From 8d250117fb267c07d27c56eed9c27715f962c83c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 20 Oct 2016 15:06:34 -0500 Subject: [PATCH 001/755] further split up resources into general (command and gui), gui, and help (as the largest resource folder, to help compilers on 32bit) --- src/CommandLine/CMakeLists.txt | 2 +- src/Desktop/CMakeLists.txt | 2 +- .../Fonts/FtglFonts/VeraBd.ttf | Bin .../Fonts/FtglFonts/VeraSe.ttf | Bin .../Fonts/LinuxLibertine/GPL.txt | 0 .../Fonts/LinuxLibertine/LICENCE.txt | 0 .../LinuxLibertine/LinLibertine_RBIah.ttf | Bin .../LinuxLibertine/LinLibertine_RBah.ttf | Bin .../LinuxLibertine/LinLibertine_RIah.ttf | Bin .../Fonts/LinuxLibertine/LinLibertine_Rah.ttf | Bin .../Fonts/LinuxLibertine/OFL-1.1.txt | 0 .../Fonts/LinuxLibertine/README | 0 .../Fonts/VeraFonts/COPYRIGHT.TXT | 0 .../Fonts/VeraFonts/README.TXT | 0 .../Fonts/VeraFonts/RELEASENOTES.TXT | 0 .../Fonts/VeraFonts/Vera.ttf | Bin .../Fonts/VeraFonts/VeraBI.ttf | Bin .../Fonts/VeraFonts/VeraBd.ttf | Bin .../Fonts/VeraFonts/VeraIt.ttf | Bin .../Fonts/VeraFonts/VeraMoBI.ttf | Bin .../Fonts/VeraFonts/VeraMoBd.ttf | Bin .../Fonts/VeraFonts/VeraMoIt.ttf | Bin .../Fonts/VeraFonts/VeraMono.ttf | Bin .../Fonts/VeraFonts/VeraSe.ttf | Bin .../Fonts/VeraFonts/VeraSeBd.ttf | Bin .../Fonts/VeraFonts/local.conf | 0 src/Resources/General/general_resources.qrc | 29 ++++++++++++++++++ .../About/hcp-logo.png | Bin .../Cursor/pen_eraser.png | Bin .../LayersPanel/colorbar.png | Bin .../LayersPanel/construction.png | Bin .../LayersPanel/wrench.png | Bin .../PaletteSettings/chain_link_icon.png | Bin .../SpecFileDialog/delete_icon.png | Bin .../SpecFileDialog/load_icon.png | Bin .../SpecFileDialog/options_icon.png | Bin .../SpecFileDialog/reload_icon.png | Bin .../{GeneralResources => Gui}/Splash/hcp.png | Bin .../Splash/startup_image.png | Bin .../Splash/twitter.png | Bin .../ToolBar/clapboard.png | Bin .../ToolBar/features_toolbox.png | Bin .../ToolBar/help.png | Bin .../ToolBar/identify.png | Bin .../ToolBar/info.png | Bin .../ToolBar/overlay_toolbox.png | Bin .../ToolBar/toolbar.png | Bin .../ToolBar/view-anterior.png | Bin .../ToolBar/view-dorsal.png | Bin .../ToolBar/view-left-lateral.png | Bin .../ToolBar/view-left-medial.png | Bin .../ToolBar/view-left.png | Bin .../ToolBar/view-plane-axial.png | Bin .../ToolBar/view-plane-coronal.png | Bin .../ToolBar/view-plane-parasagittal.png | Bin .../ToolBar/view-posterior.png | Bin .../ToolBar/view-right-lateral.png | Bin .../ToolBar/view-right-medial.png | Bin .../ToolBar/view-right.png | Bin .../ToolBar/view-ventral.png | Bin .../ToolBar/volume-crosshair-pointer.png | Bin .../gui_resources.qrc} | 26 +--------------- .../Annotations/Annotations.fld/image001.png | Bin .../Annotations/Annotations.fld/image002.png | Bin .../Annotations/Annotations.fld/image003.png | Bin .../Annotations/Annotations.fld/image004.png | Bin .../Annotations/Annotations.fld/image005.png | Bin .../Annotations/Annotations.fld/image006.png | Bin .../Annotations/Annotations.fld/image007.png | Bin .../Annotations/Annotations.fld/image008.png | Bin .../Annotations/Annotations.fld/image009.png | Bin .../Annotations/Annotations.fld/image010.png | Bin .../Annotations/Annotations.fld/image011.png | Bin .../Annotations/Annotations.fld/image012.png | Bin .../Annotations/Annotations.fld/image013.png | Bin .../Annotations/Annotations.fld/image014.png | Bin .../Annotations/Annotations.fld/image015.png | Bin .../Annotations/Annotations.fld/image016.png | Bin .../Annotations/Annotations.fld/image017.png | Bin .../Annotations/Annotations.fld/image018.png | Bin .../Annotations/Annotations.fld/image019.png | Bin .../Annotations/Annotations.fld/image020.png | Bin .../Annotations/Annotations.fld/image021.png | Bin .../Annotations/Annotations.fld/image022.png | Bin .../HelpFiles/Annotations/Annotations.html | 0 .../Features_Toolbox/Borders/Borders.html | 0 .../Borders/Borders_Attributes.png | Bin .../Borders/Borders_Selection.png | Bin .../Features_Toolbox/Borders_Attributes.png | Bin .../Features_Toolbox/Features_TB_icon.png | Bin .../Features_Toolbox/Features_Toolbox.html | 0 .../Features_Toolbox/Fibers/Fibers.html | 0 .../HelpFiles/Features_Toolbox/Foci/Foci.html | 0 .../Features_Toolbox/Foci/Foci_Attributes.png | Bin .../Features_Toolbox/Foci/Foci_Selection.png | Bin .../Features_Toolbox/Images/Images.html | 0 .../Images/Images_Selection.png | Bin .../Features_Toolbox/Labels/Labels.html | 0 .../Labels/Labels_Attributes.png | Bin .../Labels/Labels_Selection.png | Bin .../Glossary/Brainordinate/Brainordinate.html | 0 .../HelpFiles/Glossary/CIFTI/CIFTI.html | 0 .../Glossary/ConnectomeDB/ConnectomeDB.html | 0 .../ConnectomeDB/ConnectomeDB_login.png | Bin .../HelpFiles/Glossary/ConnectomeDB/Thumbs.db | Bin .../HelpFiles/Glossary/GIFTI/GIFTI.html | 0 .../Glossary/Grayordinate/Grayordinate.html | 0 .../HelpFiles/Glossary/NIFTI/NIFTI.html | 0 .../HelpFiles/Glossary/Scene/Scene.html | 0 .../Glossary/Specification_File/Spec_File.png | Bin .../Specification_File.html | 0 .../Glossary/Specification_File/Thumbs.db | Bin .../Glossary/Whiteordinate/Whiteordinate.html | 0 .../Information_Window.html | 0 .../Information_Window/Information_Window.png | Bin .../Properties/Information_Properties.png | Bin .../Properties/Properties.html | 0 .../HelpFiles/Menus/Data_Menu/Data_Menu.html | 0 .../Menus/Data_Menu/Project_Foci_Dialog.png | Bin .../HelpFiles/Menus/Data_Menu/Thumbs.db | Bin .../Menus/Develop_Menu/Develop_Menu.html | 0 .../HelpFiles/Menus/Edit_Menu/Edit_Menu.html | 0 .../HelpFiles/Menus/Edit_Menu/Edit_Menu.png | Bin .../Menus/File_Menu/._~$imation_Control.docx | Bin .../Menus/File_Menu/._~$le_Menu.docx | Bin .../Menus/File_Menu/._~$pture_Image.docx | Bin .../Animation_Control/Animation_Control.html | 0 .../Animation_Control_dialog.png | Bin .../File_Menu/Animation_Control/Thumbs.db | Bin .../Capture_Image/Capture_Image.html | 0 .../Capture_Image/Capture_Image_dialog.png | Bin .../File_Menu/Capture_Image/File_menu.png | Bin .../Menus/File_Menu/Capture_Image/Thumbs.db | Bin .../HelpFiles/Menus/File_Menu/File_Menu.html | 0 .../HelpFiles/Menus/File_Menu/File_menu.png | Bin .../File_Menu/Preferences/Preferences.html | 0 .../Preferences/Preferences_Colors.png | Bin .../File_Menu/Preferences/Preferences_ID.png | Bin .../Preferences/Preferences_Misc.png | Bin .../Preferences/Preferences_OpenGL.png | Bin .../File_Menu/Preferences/Preferences_Vol.png | Bin .../Menus/File_Menu/Preferences/Thumbs.db | Bin .../Save-Manage_Files/Gear_symbol.png | Bin .../Save-Manage_Files/Reload_symbol.png | Bin .../Save-Manage_Files/Remove_symbol.png | Bin .../Save-Manage_Files/Save-Manage_Files.html | 0 .../Save-Manage_Files_dialog.png | Bin .../File_Menu/Save-Manage_Files/Thumbs.db | Bin .../Save-Manage_Files/Upload_symbol.png | Bin .../HelpFiles/Menus/File_Menu/Thumbs.db | Bin .../Menus/Help_Menu/Bug_Report_box.png | Bin .../HelpFiles/Menus/Help_Menu/Help_Menu.html | 0 .../HelpFiles/Menus/Help_Menu/Help_Menu.png | Bin .../HelpFiles/Menus/Help_Menu/Help_Search.png | Bin .../HelpFiles/Menus/Help_Menu/Help_box.png | Bin .../HelpFiles/Menus/Help_Menu/Help_button.png | Bin .../Menus/Help_Menu/Workbench_Help.png | Bin .../Menus/Surface_Menu/Surface_Menu.html | 0 .../Menus/Surface_Menu/Surface_Properties.png | Bin .../Volume_Interaction_Surfaces.png | Bin .../HelpFiles/Menus/Thumbs.db | Bin .../Gaps_And_Margins/Gaps_And_Margins.html | 0 .../Gaps_And_Margins/Gaps_And_Margins.png | Bin .../HelpFiles/Menus/View_Menu/Thumbs.db | Bin .../Tile_Tabs_Configuration/Thumbs.db | Bin .../Tile_Tabs_Configuration.html | 0 .../Tile_Tabs_Configuration.png | Bin .../HelpFiles/Menus/View_Menu/View_Menu.html | 0 .../HelpFiles/Menus/View_Menu/View_Menu.png | Bin .../IdentifyBrainordinateDialog.png | Bin .../Menus/Window_Menu/Rename_tab.png | Bin .../HelpFiles/Menus/Window_Menu/Thumbs.db | Bin .../Menus/Window_Menu/Window_Menu.html | 0 .../Menus/Window_Menu/Window_Menu.png | Bin .../Menus/wb_view_Menu/._~$_view_Menu.docx | Bin .../HelpFiles/Menus/wb_view_Menu/Thumbs.db | Bin .../Menus/wb_view_Menu/wb_view_Menu.html | 0 .../Menus/wb_view_Menu/wb_view_Menu.png | Bin .../Mouse_Controls/Mouse_Controls.html | 0 .../Mouse_Controls/RightClick_Surface.png | Bin .../Mouse_Controls/RightClick_Volume.png | Bin .../HelpFiles/Mouse_Controls/Thumbs.db | Bin .../Open_Spec_File_Dialog/Open_Spec.png | Bin .../Open_Spec_File_Dialog.html | 0 .../HelpFiles/Open_Spec_File_Dialog/Thumbs.db | Bin .../Open_Spec_File_Dialog/gear-button.png | Bin .../Overlay_Toolbox/Charting/Charting.html | 0 .../Charting/Charting_History.png | Bin .../Charting/Charting_Loading.png | Bin .../Overlay_Toolbox/Charting/Thumbs.db | Bin .../Connectivity/Connectivity.html | 0 .../Connectivity/Connectivity.png | Bin .../Overlay_Toolbox/Layers/Add_Layer.png | Bin .../Overlay_Toolbox/Layers/Colorbar.png | Bin .../Overlay_Toolbox/Layers/Layers.html | 0 .../Layers/Overlay_Toolbox_horiz.png | Bin .../Overlay_and_Map_Settings.html | 0 .../Palette_Settings.png | Bin .../Settings_icon.png | Bin .../Overlay_Toolbox/Layers/Settings_icon.png | Bin .../Overlay_Toolbox/Overlay_Toolbox.html | 0 .../Overlay_Toolbox/Overlay_Toolbox_horiz.png | Bin .../Overlay_Toolbox/Overlay_Toolbox_vert.png | Bin .../HelpFiles/Overlay_Toolbox/Thumbs.db | Bin .../Color-Vol-Surf_Outline.png | Bin .../Vol-Surf_Outline/Tab-Vol-Surf_Outline.png | Bin .../Vol-Surf_Outline/Vol-Surf_Outline.html | 0 .../Vol-Surf_Outline/Vol-Surf_Outline.png | Bin .../Create_New_Scene.png | Bin .../Create_New_Scene_File.html | 0 .../Create_New_Scene_File/Scenes button.png | Bin .../Create_New_Scene_File/Thumbs.db | Bin .../Scenes_Window/Scenes_Window.html | 0 .../HelpFiles/Scenes_Window/Scenes_Window.png | Bin .../HelpFiles/Scenes_Window/Thumbs.db | Bin .../CiftiFileRow.png | Bin .../Indentify_Brainordinate.png | Bin .../Select_Brainordinate_Window.html | 0 .../Splash_Screen/Splash_Screen.html | 0 .../HelpFiles/Splash_Screen/Splash_screen.png | Bin .../HelpFiles/Splash_Screen/Thumbs.db | Bin .../Toolbar/All_View/All_Toolbar.png | Bin .../HelpFiles/Toolbar/All_View/All_View.html | 0 .../HelpFiles/Toolbar/All_View/All_view.png | Bin .../HelpFiles/Toolbar/All_View/Thumbs.db | Bin .../Toolbar/All_View/Volume_ID_button.png | Bin .../ChartView_dtseries_DataSeries.png | Bin .../Chart_View/ChartView_pscalar_Matrix.png | Bin .../Toolbar/Chart_View/Chart_View.html | 0 .../ChartDataSeries.png | Bin .../ChartView_DataSeries_Toolbar.png | Bin .../ChartView_dtseries_DataSeries.png | Bin .../ChartView_pscalar_Matrix.png | Bin .../Data-Time_Series_Chart_View.html | 0 .../ChartView_Matrix_Toolbar.png | Bin .../Matrix_Chart_View/Matrix_Chart_View.html | 0 .../pconn_matrix_montage.png | Bin .../pscalar_matrix_surface.png | Bin .../Toolbar/Chart_View/Montage_toolbar.png | Bin .../HelpFiles/Toolbar/Chart_View/Thumbs.db | Bin .../HelpFiles/Toolbar/Clipping/Clipping.html | 0 .../Toolbar/Clipping/Clipping_Planes.png | Bin .../HelpFiles/Toolbar/Clipping/Thumbs.db | Bin .../Custom_Orientation.html | 0 .../Custom_Orientation/Custom_Orientation.png | Bin .../Mode/Border_Drawing/Border_Drawing.html | 0 .../Border_Editing/Border_Editing.html | 0 .../Border_Editing/Border_edit.png | Bin .../Border_Editing/Edit_Border_Properties.png | Bin .../Border_Drawing/Border_Editing/Thumbs.db | Bin .../Mode/Border_Drawing/Border_drawing.png | Bin .../Border_Drawing/Create_ROI/Border_ROI.png | Bin .../Border_Drawing/Create_ROI/Create_ROI.html | 0 .../Create_ROI/Create_Region_of_Interest.png | Bin .../Mode/Border_Drawing/Create_ROI/Thumbs.db | Bin .../Toolbar/Mode/Border_Drawing/Thumbs.db | Bin .../HelpFiles/Toolbar/Mode/Border_Tools.png | Bin .../Mode/Foci_Creation/Create_Focus.png | Bin .../Mode/Foci_Creation/Foci_Creation.html | 0 .../Foci_Editing/Edit_Focus_box.png | Bin .../Foci_Editing/Foci_Editing.html | 0 .../Foci_Creation/Foci_Editing/Foci_edit.png | Bin .../Mode/Foci_Creation/Foci_Editing/Thumbs.db | Bin .../Toolbar/Mode/Foci_Creation/Foci_Tools.png | Bin .../Toolbar/Mode/Foci_Creation/Thumbs.db | Bin .../HelpFiles/Toolbar/Mode/Foci_Tools.png | Bin .../HelpFiles/Toolbar/Mode/Mode.html | 0 .../HelpFiles/Toolbar/Mode/Thumbs.db | Bin .../HelpFiles/Toolbar/Mode/Volume_Tools.png | Bin .../Toolbar/Montage_View/Montage_View.html | 0 .../Toolbar/Montage_View/Montage_toolbar.png | Bin .../HelpFiles/Toolbar/Montage_View/Thumbs.db | Bin .../Toolbar/Surface_View/SurfaceView.png | Bin .../Toolbar/Surface_View/Surface_View.html | 0 .../HelpFiles/Toolbar/Surface_View/Thumbs.db | Bin .../Toolbar/Tab_Functions/Tab_Functions.html | 0 .../Toolbar/Tab_Functions/Tab_Functions.png | Bin .../HelpFiles/Toolbar/Thumbs.db | Bin .../HelpFiles/Toolbar/Toolbar.html | 0 .../HelpFiles/Toolbar/Toolbar_icon.png | Bin .../HelpFiles/Toolbar/VolumeView.png | Bin .../HelpFiles/Toolbar/Volume_View/Thumbs.db | Bin .../Toolbar/Volume_View/VolumeView.png | Bin .../Toolbar/Volume_View/Volume_ID_button.png | Bin .../Toolbar/Volume_View/Volume_View.html | 0 .../Active_Tab/Active_Tab.html | 0 .../Workbench_Window/Active_Tab/Thumbs.db | Bin .../Active_Tab/Viewing_Tabs.png | Bin .../HelpFiles/Workbench_Window/Thumbs.db | Bin .../Workbench_Window/Tooltip/Thumbs.db | Bin .../Workbench_Window/Tooltip/Tooltip.html | 0 .../Workbench_Window/Tooltip/Tooltip.png | Bin .../Workbench_Window/Viewing_Area/Thumbs.db | Bin .../Viewing_Area/Viewing_Area.html | 0 .../Viewing_Area/WBwindow_Horiz_Labels.png | Bin .../Workbench_Window/Viewing_Tabs/Thumbs.db | Bin .../Viewing_Tabs/Viewing_Tabs.html | 0 .../Viewing_Tabs/Viewing_Tabs.png | Bin .../WBwindow_Horiz_Labels.png | Bin .../Features_TB_icon.png | Bin .../Help_button.png | Bin .../Identify_Brainordinate_Icon.png | Bin .../Identify_icon.png | Bin .../Information_icon.png | Bin .../Overlay_TB_icon.png | Bin .../Scenes_icon.png | Bin .../Thumbs.db | Bin .../Toolbar_icon.png | Bin .../Window_Elements_Hide-Show_Buttons.html | 0 .../Workbench_Window/Workbench_Window.html | 0 .../help_resources.qrc} | 3 +- .../update_resources.sh | 0 312 files changed, 34 insertions(+), 28 deletions(-) rename src/Resources/{GeneralResources => General}/Fonts/FtglFonts/VeraBd.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/FtglFonts/VeraSe.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/GPL.txt (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/LICENCE.txt (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/LinLibertine_RBah.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/LinLibertine_RIah.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/LinLibertine_Rah.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/OFL-1.1.txt (100%) rename src/Resources/{GeneralResources => General}/Fonts/LinuxLibertine/README (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/COPYRIGHT.TXT (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/README.TXT (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/RELEASENOTES.TXT (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/Vera.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraBI.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraBd.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraIt.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraMoBI.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraMoBd.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraMoIt.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraMono.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraSe.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/VeraSeBd.ttf (100%) rename src/Resources/{GeneralResources => General}/Fonts/VeraFonts/local.conf (100%) create mode 100644 src/Resources/General/general_resources.qrc rename src/Resources/{GeneralResources => Gui}/About/hcp-logo.png (100%) rename src/Resources/{GeneralResources => Gui}/Cursor/pen_eraser.png (100%) rename src/Resources/{GeneralResources => Gui}/LayersPanel/colorbar.png (100%) rename src/Resources/{GeneralResources => Gui}/LayersPanel/construction.png (100%) rename src/Resources/{GeneralResources => Gui}/LayersPanel/wrench.png (100%) rename src/Resources/{GeneralResources => Gui}/PaletteSettings/chain_link_icon.png (100%) rename src/Resources/{GeneralResources => Gui}/SpecFileDialog/delete_icon.png (100%) rename src/Resources/{GeneralResources => Gui}/SpecFileDialog/load_icon.png (100%) rename src/Resources/{GeneralResources => Gui}/SpecFileDialog/options_icon.png (100%) rename src/Resources/{GeneralResources => Gui}/SpecFileDialog/reload_icon.png (100%) rename src/Resources/{GeneralResources => Gui}/Splash/hcp.png (100%) rename src/Resources/{GeneralResources => Gui}/Splash/startup_image.png (100%) rename src/Resources/{GeneralResources => Gui}/Splash/twitter.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/clapboard.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/features_toolbox.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/help.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/identify.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/info.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/overlay_toolbox.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/toolbar.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-anterior.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-dorsal.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-left-lateral.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-left-medial.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-left.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-plane-axial.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-plane-coronal.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-plane-parasagittal.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-posterior.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-right-lateral.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-right-medial.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-right.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/view-ventral.png (100%) rename src/Resources/{GeneralResources => Gui}/ToolBar/volume-crosshair-pointer.png (100%) rename src/Resources/{GeneralResources/general_resources.qrc => Gui/gui_resources.qrc} (56%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image001.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image002.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image003.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image004.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image005.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image006.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image007.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image008.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image009.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image010.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image011.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image012.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image013.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image014.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image015.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image016.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image017.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image018.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image019.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image020.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image021.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.fld/image022.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Annotations/Annotations.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Borders/Borders.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Borders/Borders_Attributes.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Borders/Borders_Selection.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Borders_Attributes.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Features_TB_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Features_Toolbox.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Fibers/Fibers.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Foci/Foci.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Foci/Foci_Attributes.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Foci/Foci_Selection.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Images/Images.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Images/Images_Selection.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Labels/Labels.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Labels/Labels_Attributes.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Features_Toolbox/Labels/Labels_Selection.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Brainordinate/Brainordinate.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/CIFTI/CIFTI.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB_login.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/ConnectomeDB/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/GIFTI/GIFTI.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Grayordinate/Grayordinate.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/NIFTI/NIFTI.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Scene/Scene.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Specification_File/Spec_File.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Specification_File/Specification_File.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Specification_File/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Glossary/Whiteordinate/Whiteordinate.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Information_Window/Information_Window.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Information_Window/Information_Window.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Information_Window/Properties/Information_Properties.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Information_Window/Properties/Properties.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Data_Menu/Data_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Data_Menu/Project_Foci_Dialog.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Data_Menu/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Develop_Menu/Develop_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Edit_Menu/Edit_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Edit_Menu/Edit_Menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/._~$imation_Control.docx (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/._~$le_Menu.docx (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/._~$pture_Image.docx (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control_dialog.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Animation_Control/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image_dialog.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Capture_Image/File_menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Capture_Image/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/File_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/File_menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences_Colors.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences_ID.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences_Misc.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences_OpenGL.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Preferences_Vol.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Preferences/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Gear_symbol.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Reload_symbol.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Remove_symbol.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files_dialog.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Save-Manage_Files/Upload_symbol.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/File_Menu/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Bug_Report_box.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Help_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Help_Menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Help_Search.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Help_box.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Help_button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Help_Menu/Workbench_Help.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Surface_Menu/Surface_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Surface_Menu/Surface_Properties.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Surface_Menu/Volume_Interaction_Surfaces.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/View_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/View_Menu/View_Menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Window_Menu/IdentifyBrainordinateDialog.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Window_Menu/Rename_tab.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Window_Menu/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Window_Menu/Window_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/Window_Menu/Window_Menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/wb_view_Menu/._~$_view_Menu.docx (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/wb_view_Menu/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Mouse_Controls/Mouse_Controls.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Mouse_Controls/RightClick_Surface.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Mouse_Controls/RightClick_Volume.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Mouse_Controls/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Open_Spec_File_Dialog/Open_Spec.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Open_Spec_File_Dialog/Open_Spec_File_Dialog.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Open_Spec_File_Dialog/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Open_Spec_File_Dialog/gear-button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Charting/Charting.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Charting/Charting_History.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Charting/Charting_Loading.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Charting/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Add_Layer.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Colorbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Layers.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Overlay_Toolbox_horiz.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_and_Map_Settings.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Palette_Settings.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Settings_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Layers/Settings_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Overlay_Toolbox.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_horiz.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_vert.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Color-Vol-Surf_Outline.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Tab-Vol-Surf_Outline.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene_File.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Create_New_Scene_File/Scenes button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Create_New_Scene_File/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Scenes_Window.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Scenes_Window.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Scenes_Window/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Select_Brainordinate_Window/CiftiFileRow.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Select_Brainordinate_Window/Indentify_Brainordinate.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Select_Brainordinate_Window/Select_Brainordinate_Window.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Splash_Screen/Splash_Screen.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Splash_Screen/Splash_screen.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Splash_Screen/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/All_View/All_Toolbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/All_View/All_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/All_View/All_view.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/All_View/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/All_View/Volume_ID_button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Chart_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Chart_View/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Clipping/Clipping.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Clipping/Clipping_Planes.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Clipping/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Drawing.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_Editing.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_edit.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Edit_Border_Properties.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Border_drawing.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Border_ROI.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_ROI.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_Region_of_Interest.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Drawing/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Border_Tools.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Create_Focus.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Creation.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Edit_Focus_box.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_Editing.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_edit.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Tools.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Creation/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Foci_Tools.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Mode.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Mode/Volume_Tools.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Montage_View/Montage_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Montage_View/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Surface_View/SurfaceView.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Surface_View/Surface_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Surface_View/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Toolbar.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Toolbar_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/VolumeView.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Volume_View/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Volume_View/VolumeView.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Toolbar/Volume_View/Volume_View.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Active_Tab/Active_Tab.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Active_Tab/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Active_Tab/Viewing_Tabs.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Tooltip/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Tooltip/Tooltip.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Tooltip/Tooltip.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Area/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Area/Viewing_Area.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Tabs/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/WBwindow_Horiz_Labels.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Features_TB_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Help_button.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_Brainordinate_Icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Information_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Thumbs.db (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html (100%) rename src/Resources/{GuiResources => Help}/HelpFiles/Workbench_Window/Workbench_Window.html (100%) rename src/Resources/{GuiResources/gui_resources.qrc => Help/help_resources.qrc} (99%) rename src/Resources/{GuiResources => Help}/update_resources.sh (100%) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index c221625a9..328c5af0f 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -26,7 +26,7 @@ set (EXE_NAME wb_command) # # Resources # -QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/GeneralResources/general_resources.qrc) +QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/General/general_resources.qrc) # # Create the executable diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index f6afe880f..a9f2fc278 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -33,7 +33,7 @@ ENDIF (UNIX) # # Resources # -QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/GeneralResources/general_resources.qrc ../Resources/GuiResources/gui_resources.qrc) +QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/General/general_resources.qrc ../Resources/Gui/gui_resources.qrc ../Resources/Help/help_resources.qrc) # # Create the executable diff --git a/src/Resources/GeneralResources/Fonts/FtglFonts/VeraBd.ttf b/src/Resources/General/Fonts/FtglFonts/VeraBd.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/FtglFonts/VeraBd.ttf rename to src/Resources/General/Fonts/FtglFonts/VeraBd.ttf diff --git a/src/Resources/GeneralResources/Fonts/FtglFonts/VeraSe.ttf b/src/Resources/General/Fonts/FtglFonts/VeraSe.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/FtglFonts/VeraSe.ttf rename to src/Resources/General/Fonts/FtglFonts/VeraSe.ttf diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/GPL.txt b/src/Resources/General/Fonts/LinuxLibertine/GPL.txt similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/GPL.txt rename to src/Resources/General/Fonts/LinuxLibertine/GPL.txt diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/LICENCE.txt b/src/Resources/General/Fonts/LinuxLibertine/LICENCE.txt similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/LICENCE.txt rename to src/Resources/General/Fonts/LinuxLibertine/LICENCE.txt diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf b/src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf rename to src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RBah.ttf b/src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RBah.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RBah.ttf rename to src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RBah.ttf diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RIah.ttf b/src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RIah.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_RIah.ttf rename to src/Resources/General/Fonts/LinuxLibertine/LinLibertine_RIah.ttf diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_Rah.ttf b/src/Resources/General/Fonts/LinuxLibertine/LinLibertine_Rah.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/LinLibertine_Rah.ttf rename to src/Resources/General/Fonts/LinuxLibertine/LinLibertine_Rah.ttf diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/OFL-1.1.txt b/src/Resources/General/Fonts/LinuxLibertine/OFL-1.1.txt similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/OFL-1.1.txt rename to src/Resources/General/Fonts/LinuxLibertine/OFL-1.1.txt diff --git a/src/Resources/GeneralResources/Fonts/LinuxLibertine/README b/src/Resources/General/Fonts/LinuxLibertine/README similarity index 100% rename from src/Resources/GeneralResources/Fonts/LinuxLibertine/README rename to src/Resources/General/Fonts/LinuxLibertine/README diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/COPYRIGHT.TXT b/src/Resources/General/Fonts/VeraFonts/COPYRIGHT.TXT similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/COPYRIGHT.TXT rename to src/Resources/General/Fonts/VeraFonts/COPYRIGHT.TXT diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/README.TXT b/src/Resources/General/Fonts/VeraFonts/README.TXT similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/README.TXT rename to src/Resources/General/Fonts/VeraFonts/README.TXT diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/RELEASENOTES.TXT b/src/Resources/General/Fonts/VeraFonts/RELEASENOTES.TXT similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/RELEASENOTES.TXT rename to src/Resources/General/Fonts/VeraFonts/RELEASENOTES.TXT diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/Vera.ttf b/src/Resources/General/Fonts/VeraFonts/Vera.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/Vera.ttf rename to src/Resources/General/Fonts/VeraFonts/Vera.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraBI.ttf b/src/Resources/General/Fonts/VeraFonts/VeraBI.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraBI.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraBI.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraBd.ttf b/src/Resources/General/Fonts/VeraFonts/VeraBd.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraBd.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraBd.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraIt.ttf b/src/Resources/General/Fonts/VeraFonts/VeraIt.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraIt.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraIt.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoBI.ttf b/src/Resources/General/Fonts/VeraFonts/VeraMoBI.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoBI.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraMoBI.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoBd.ttf b/src/Resources/General/Fonts/VeraFonts/VeraMoBd.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoBd.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraMoBd.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoIt.ttf b/src/Resources/General/Fonts/VeraFonts/VeraMoIt.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraMoIt.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraMoIt.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraMono.ttf b/src/Resources/General/Fonts/VeraFonts/VeraMono.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraMono.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraMono.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraSe.ttf b/src/Resources/General/Fonts/VeraFonts/VeraSe.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraSe.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraSe.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/VeraSeBd.ttf b/src/Resources/General/Fonts/VeraFonts/VeraSeBd.ttf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/VeraSeBd.ttf rename to src/Resources/General/Fonts/VeraFonts/VeraSeBd.ttf diff --git a/src/Resources/GeneralResources/Fonts/VeraFonts/local.conf b/src/Resources/General/Fonts/VeraFonts/local.conf similarity index 100% rename from src/Resources/GeneralResources/Fonts/VeraFonts/local.conf rename to src/Resources/General/Fonts/VeraFonts/local.conf diff --git a/src/Resources/General/general_resources.qrc b/src/Resources/General/general_resources.qrc new file mode 100644 index 000000000..470df32a7 --- /dev/null +++ b/src/Resources/General/general_resources.qrc @@ -0,0 +1,29 @@ + + +./Fonts/FtglFonts/VeraBd.ttf +./Fonts/FtglFonts/VeraSe.ttf +./Fonts/LinuxLibertine/GPL.txt +./Fonts/LinuxLibertine/LICENCE.txt +./Fonts/LinuxLibertine/LinLibertine_Rah.ttf +./Fonts/LinuxLibertine/LinLibertine_RBah.ttf +./Fonts/LinuxLibertine/LinLibertine_RBIah.ttf +./Fonts/LinuxLibertine/LinLibertine_RIah.ttf +./Fonts/LinuxLibertine/OFL-1.1.txt +./Fonts/LinuxLibertine/README +./Fonts/VeraFonts/COPYRIGHT.TXT +./Fonts/VeraFonts/local.conf +./Fonts/VeraFonts/README.TXT +./Fonts/VeraFonts/RELEASENOTES.TXT +./Fonts/VeraFonts/Vera.ttf +./Fonts/VeraFonts/VeraBd.ttf +./Fonts/VeraFonts/VeraBI.ttf +./Fonts/VeraFonts/VeraIt.ttf +./Fonts/VeraFonts/VeraMoBd.ttf +./Fonts/VeraFonts/VeraMoBI.ttf +./Fonts/VeraFonts/VeraMoIt.ttf +./Fonts/VeraFonts/VeraMono.ttf +./Fonts/VeraFonts/VeraSe.ttf +./Fonts/VeraFonts/VeraSeBd.ttf +./general_resources.qrc + + diff --git a/src/Resources/GeneralResources/About/hcp-logo.png b/src/Resources/Gui/About/hcp-logo.png similarity index 100% rename from src/Resources/GeneralResources/About/hcp-logo.png rename to src/Resources/Gui/About/hcp-logo.png diff --git a/src/Resources/GeneralResources/Cursor/pen_eraser.png b/src/Resources/Gui/Cursor/pen_eraser.png similarity index 100% rename from src/Resources/GeneralResources/Cursor/pen_eraser.png rename to src/Resources/Gui/Cursor/pen_eraser.png diff --git a/src/Resources/GeneralResources/LayersPanel/colorbar.png b/src/Resources/Gui/LayersPanel/colorbar.png similarity index 100% rename from src/Resources/GeneralResources/LayersPanel/colorbar.png rename to src/Resources/Gui/LayersPanel/colorbar.png diff --git a/src/Resources/GeneralResources/LayersPanel/construction.png b/src/Resources/Gui/LayersPanel/construction.png similarity index 100% rename from src/Resources/GeneralResources/LayersPanel/construction.png rename to src/Resources/Gui/LayersPanel/construction.png diff --git a/src/Resources/GeneralResources/LayersPanel/wrench.png b/src/Resources/Gui/LayersPanel/wrench.png similarity index 100% rename from src/Resources/GeneralResources/LayersPanel/wrench.png rename to src/Resources/Gui/LayersPanel/wrench.png diff --git a/src/Resources/GeneralResources/PaletteSettings/chain_link_icon.png b/src/Resources/Gui/PaletteSettings/chain_link_icon.png similarity index 100% rename from src/Resources/GeneralResources/PaletteSettings/chain_link_icon.png rename to src/Resources/Gui/PaletteSettings/chain_link_icon.png diff --git a/src/Resources/GeneralResources/SpecFileDialog/delete_icon.png b/src/Resources/Gui/SpecFileDialog/delete_icon.png similarity index 100% rename from src/Resources/GeneralResources/SpecFileDialog/delete_icon.png rename to src/Resources/Gui/SpecFileDialog/delete_icon.png diff --git a/src/Resources/GeneralResources/SpecFileDialog/load_icon.png b/src/Resources/Gui/SpecFileDialog/load_icon.png similarity index 100% rename from src/Resources/GeneralResources/SpecFileDialog/load_icon.png rename to src/Resources/Gui/SpecFileDialog/load_icon.png diff --git a/src/Resources/GeneralResources/SpecFileDialog/options_icon.png b/src/Resources/Gui/SpecFileDialog/options_icon.png similarity index 100% rename from src/Resources/GeneralResources/SpecFileDialog/options_icon.png rename to src/Resources/Gui/SpecFileDialog/options_icon.png diff --git a/src/Resources/GeneralResources/SpecFileDialog/reload_icon.png b/src/Resources/Gui/SpecFileDialog/reload_icon.png similarity index 100% rename from src/Resources/GeneralResources/SpecFileDialog/reload_icon.png rename to src/Resources/Gui/SpecFileDialog/reload_icon.png diff --git a/src/Resources/GeneralResources/Splash/hcp.png b/src/Resources/Gui/Splash/hcp.png similarity index 100% rename from src/Resources/GeneralResources/Splash/hcp.png rename to src/Resources/Gui/Splash/hcp.png diff --git a/src/Resources/GeneralResources/Splash/startup_image.png b/src/Resources/Gui/Splash/startup_image.png similarity index 100% rename from src/Resources/GeneralResources/Splash/startup_image.png rename to src/Resources/Gui/Splash/startup_image.png diff --git a/src/Resources/GeneralResources/Splash/twitter.png b/src/Resources/Gui/Splash/twitter.png similarity index 100% rename from src/Resources/GeneralResources/Splash/twitter.png rename to src/Resources/Gui/Splash/twitter.png diff --git a/src/Resources/GeneralResources/ToolBar/clapboard.png b/src/Resources/Gui/ToolBar/clapboard.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/clapboard.png rename to src/Resources/Gui/ToolBar/clapboard.png diff --git a/src/Resources/GeneralResources/ToolBar/features_toolbox.png b/src/Resources/Gui/ToolBar/features_toolbox.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/features_toolbox.png rename to src/Resources/Gui/ToolBar/features_toolbox.png diff --git a/src/Resources/GeneralResources/ToolBar/help.png b/src/Resources/Gui/ToolBar/help.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/help.png rename to src/Resources/Gui/ToolBar/help.png diff --git a/src/Resources/GeneralResources/ToolBar/identify.png b/src/Resources/Gui/ToolBar/identify.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/identify.png rename to src/Resources/Gui/ToolBar/identify.png diff --git a/src/Resources/GeneralResources/ToolBar/info.png b/src/Resources/Gui/ToolBar/info.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/info.png rename to src/Resources/Gui/ToolBar/info.png diff --git a/src/Resources/GeneralResources/ToolBar/overlay_toolbox.png b/src/Resources/Gui/ToolBar/overlay_toolbox.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/overlay_toolbox.png rename to src/Resources/Gui/ToolBar/overlay_toolbox.png diff --git a/src/Resources/GeneralResources/ToolBar/toolbar.png b/src/Resources/Gui/ToolBar/toolbar.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/toolbar.png rename to src/Resources/Gui/ToolBar/toolbar.png diff --git a/src/Resources/GeneralResources/ToolBar/view-anterior.png b/src/Resources/Gui/ToolBar/view-anterior.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-anterior.png rename to src/Resources/Gui/ToolBar/view-anterior.png diff --git a/src/Resources/GeneralResources/ToolBar/view-dorsal.png b/src/Resources/Gui/ToolBar/view-dorsal.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-dorsal.png rename to src/Resources/Gui/ToolBar/view-dorsal.png diff --git a/src/Resources/GeneralResources/ToolBar/view-left-lateral.png b/src/Resources/Gui/ToolBar/view-left-lateral.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-left-lateral.png rename to src/Resources/Gui/ToolBar/view-left-lateral.png diff --git a/src/Resources/GeneralResources/ToolBar/view-left-medial.png b/src/Resources/Gui/ToolBar/view-left-medial.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-left-medial.png rename to src/Resources/Gui/ToolBar/view-left-medial.png diff --git a/src/Resources/GeneralResources/ToolBar/view-left.png b/src/Resources/Gui/ToolBar/view-left.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-left.png rename to src/Resources/Gui/ToolBar/view-left.png diff --git a/src/Resources/GeneralResources/ToolBar/view-plane-axial.png b/src/Resources/Gui/ToolBar/view-plane-axial.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-plane-axial.png rename to src/Resources/Gui/ToolBar/view-plane-axial.png diff --git a/src/Resources/GeneralResources/ToolBar/view-plane-coronal.png b/src/Resources/Gui/ToolBar/view-plane-coronal.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-plane-coronal.png rename to src/Resources/Gui/ToolBar/view-plane-coronal.png diff --git a/src/Resources/GeneralResources/ToolBar/view-plane-parasagittal.png b/src/Resources/Gui/ToolBar/view-plane-parasagittal.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-plane-parasagittal.png rename to src/Resources/Gui/ToolBar/view-plane-parasagittal.png diff --git a/src/Resources/GeneralResources/ToolBar/view-posterior.png b/src/Resources/Gui/ToolBar/view-posterior.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-posterior.png rename to src/Resources/Gui/ToolBar/view-posterior.png diff --git a/src/Resources/GeneralResources/ToolBar/view-right-lateral.png b/src/Resources/Gui/ToolBar/view-right-lateral.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-right-lateral.png rename to src/Resources/Gui/ToolBar/view-right-lateral.png diff --git a/src/Resources/GeneralResources/ToolBar/view-right-medial.png b/src/Resources/Gui/ToolBar/view-right-medial.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-right-medial.png rename to src/Resources/Gui/ToolBar/view-right-medial.png diff --git a/src/Resources/GeneralResources/ToolBar/view-right.png b/src/Resources/Gui/ToolBar/view-right.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-right.png rename to src/Resources/Gui/ToolBar/view-right.png diff --git a/src/Resources/GeneralResources/ToolBar/view-ventral.png b/src/Resources/Gui/ToolBar/view-ventral.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/view-ventral.png rename to src/Resources/Gui/ToolBar/view-ventral.png diff --git a/src/Resources/GeneralResources/ToolBar/volume-crosshair-pointer.png b/src/Resources/Gui/ToolBar/volume-crosshair-pointer.png similarity index 100% rename from src/Resources/GeneralResources/ToolBar/volume-crosshair-pointer.png rename to src/Resources/Gui/ToolBar/volume-crosshair-pointer.png diff --git a/src/Resources/GeneralResources/general_resources.qrc b/src/Resources/Gui/gui_resources.qrc similarity index 56% rename from src/Resources/GeneralResources/general_resources.qrc rename to src/Resources/Gui/gui_resources.qrc index 4e701940e..90864279a 100644 --- a/src/Resources/GeneralResources/general_resources.qrc +++ b/src/Resources/Gui/gui_resources.qrc @@ -2,31 +2,7 @@ ./About/hcp-logo.png ./Cursor/pen_eraser.png -./Fonts/FtglFonts/VeraBd.ttf -./Fonts/FtglFonts/VeraSe.ttf -./Fonts/LinuxLibertine/GPL.txt -./Fonts/LinuxLibertine/LICENCE.txt -./Fonts/LinuxLibertine/LinLibertine_Rah.ttf -./Fonts/LinuxLibertine/LinLibertine_RBah.ttf -./Fonts/LinuxLibertine/LinLibertine_RBIah.ttf -./Fonts/LinuxLibertine/LinLibertine_RIah.ttf -./Fonts/LinuxLibertine/OFL-1.1.txt -./Fonts/LinuxLibertine/README -./Fonts/VeraFonts/COPYRIGHT.TXT -./Fonts/VeraFonts/local.conf -./Fonts/VeraFonts/README.TXT -./Fonts/VeraFonts/RELEASENOTES.TXT -./Fonts/VeraFonts/Vera.ttf -./Fonts/VeraFonts/VeraBd.ttf -./Fonts/VeraFonts/VeraBI.ttf -./Fonts/VeraFonts/VeraIt.ttf -./Fonts/VeraFonts/VeraMoBd.ttf -./Fonts/VeraFonts/VeraMoBI.ttf -./Fonts/VeraFonts/VeraMoIt.ttf -./Fonts/VeraFonts/VeraMono.ttf -./Fonts/VeraFonts/VeraSe.ttf -./Fonts/VeraFonts/VeraSeBd.ttf -./general_resources.qrc +./gui_resources.qrc ./LayersPanel/colorbar.png ./LayersPanel/construction.png ./LayersPanel/wrench.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image001.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image001.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image001.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image001.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image002.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image002.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image002.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image002.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image003.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image003.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image003.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image003.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image004.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image004.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image004.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image004.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image005.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image005.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image005.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image005.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image006.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image006.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image006.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image006.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image007.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image007.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image007.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image007.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image008.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image008.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image008.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image008.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image009.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image009.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image009.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image009.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image010.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image010.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image010.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image010.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image011.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image011.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image011.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image011.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image012.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image012.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image012.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image012.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image013.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image013.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image013.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image013.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image014.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image014.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image014.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image014.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image015.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image015.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image015.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image015.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image016.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image016.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image016.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image016.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image017.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image017.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image017.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image017.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image018.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image018.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image018.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image018.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image019.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image019.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image019.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image019.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image020.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image020.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image020.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image020.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image021.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image021.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image021.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image021.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image022.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image022.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.fld/image022.png rename to src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image022.png diff --git a/src/Resources/GuiResources/HelpFiles/Annotations/Annotations.html b/src/Resources/Help/HelpFiles/Annotations/Annotations.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Annotations/Annotations.html rename to src/Resources/Help/HelpFiles/Annotations/Annotations.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders_Attributes.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders_Attributes.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders_Attributes.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders_Attributes.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders_Selection.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders_Selection.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders/Borders_Selection.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders_Selection.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders_Attributes.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders_Attributes.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Borders_Attributes.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Borders_Attributes.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Features_TB_icon.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Features_TB_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Features_TB_icon.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Features_TB_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Features_Toolbox.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Features_Toolbox.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Features_Toolbox.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Features_Toolbox.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Fibers/Fibers.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Fibers/Fibers.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Fibers/Fibers.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Fibers/Fibers.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci_Attributes.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci_Attributes.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci_Attributes.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci_Attributes.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci_Selection.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci_Selection.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Foci/Foci_Selection.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Foci/Foci_Selection.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Images/Images.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Images/Images.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Images/Images.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Images/Images.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Images/Images_Selection.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Images/Images_Selection.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Images/Images_Selection.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Images/Images_Selection.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels.html rename to src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels.html diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels_Attributes.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels_Attributes.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels_Attributes.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels_Attributes.png diff --git a/src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels_Selection.png b/src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels_Selection.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Features_Toolbox/Labels/Labels_Selection.png rename to src/Resources/Help/HelpFiles/Features_Toolbox/Labels/Labels_Selection.png diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Brainordinate/Brainordinate.html b/src/Resources/Help/HelpFiles/Glossary/Brainordinate/Brainordinate.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Brainordinate/Brainordinate.html rename to src/Resources/Help/HelpFiles/Glossary/Brainordinate/Brainordinate.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/CIFTI/CIFTI.html b/src/Resources/Help/HelpFiles/Glossary/CIFTI/CIFTI.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/CIFTI/CIFTI.html rename to src/Resources/Help/HelpFiles/Glossary/CIFTI/CIFTI.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB.html b/src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB.html rename to src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB_login.png b/src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB_login.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB_login.png rename to src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/ConnectomeDB_login.png diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/Thumbs.db b/src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/ConnectomeDB/Thumbs.db rename to src/Resources/Help/HelpFiles/Glossary/ConnectomeDB/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/GIFTI/GIFTI.html b/src/Resources/Help/HelpFiles/Glossary/GIFTI/GIFTI.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/GIFTI/GIFTI.html rename to src/Resources/Help/HelpFiles/Glossary/GIFTI/GIFTI.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Grayordinate/Grayordinate.html b/src/Resources/Help/HelpFiles/Glossary/Grayordinate/Grayordinate.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Grayordinate/Grayordinate.html rename to src/Resources/Help/HelpFiles/Glossary/Grayordinate/Grayordinate.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/NIFTI/NIFTI.html b/src/Resources/Help/HelpFiles/Glossary/NIFTI/NIFTI.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/NIFTI/NIFTI.html rename to src/Resources/Help/HelpFiles/Glossary/NIFTI/NIFTI.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Scene/Scene.html b/src/Resources/Help/HelpFiles/Glossary/Scene/Scene.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Scene/Scene.html rename to src/Resources/Help/HelpFiles/Glossary/Scene/Scene.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Spec_File.png b/src/Resources/Help/HelpFiles/Glossary/Specification_File/Spec_File.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Spec_File.png rename to src/Resources/Help/HelpFiles/Glossary/Specification_File/Spec_File.png diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Specification_File.html b/src/Resources/Help/HelpFiles/Glossary/Specification_File/Specification_File.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Specification_File.html rename to src/Resources/Help/HelpFiles/Glossary/Specification_File/Specification_File.html diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Thumbs.db b/src/Resources/Help/HelpFiles/Glossary/Specification_File/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Specification_File/Thumbs.db rename to src/Resources/Help/HelpFiles/Glossary/Specification_File/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Glossary/Whiteordinate/Whiteordinate.html b/src/Resources/Help/HelpFiles/Glossary/Whiteordinate/Whiteordinate.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Glossary/Whiteordinate/Whiteordinate.html rename to src/Resources/Help/HelpFiles/Glossary/Whiteordinate/Whiteordinate.html diff --git a/src/Resources/GuiResources/HelpFiles/Information_Window/Information_Window.html b/src/Resources/Help/HelpFiles/Information_Window/Information_Window.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Information_Window/Information_Window.html rename to src/Resources/Help/HelpFiles/Information_Window/Information_Window.html diff --git a/src/Resources/GuiResources/HelpFiles/Information_Window/Information_Window.png b/src/Resources/Help/HelpFiles/Information_Window/Information_Window.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Information_Window/Information_Window.png rename to src/Resources/Help/HelpFiles/Information_Window/Information_Window.png diff --git a/src/Resources/GuiResources/HelpFiles/Information_Window/Properties/Information_Properties.png b/src/Resources/Help/HelpFiles/Information_Window/Properties/Information_Properties.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Information_Window/Properties/Information_Properties.png rename to src/Resources/Help/HelpFiles/Information_Window/Properties/Information_Properties.png diff --git a/src/Resources/GuiResources/HelpFiles/Information_Window/Properties/Properties.html b/src/Resources/Help/HelpFiles/Information_Window/Properties/Properties.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Information_Window/Properties/Properties.html rename to src/Resources/Help/HelpFiles/Information_Window/Properties/Properties.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Data_Menu.html b/src/Resources/Help/HelpFiles/Menus/Data_Menu/Data_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Data_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Data_Menu/Data_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Project_Foci_Dialog.png b/src/Resources/Help/HelpFiles/Menus/Data_Menu/Project_Foci_Dialog.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Project_Foci_Dialog.png rename to src/Resources/Help/HelpFiles/Menus/Data_Menu/Project_Foci_Dialog.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/Data_Menu/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Data_Menu/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/Data_Menu/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Develop_Menu/Develop_Menu.html b/src/Resources/Help/HelpFiles/Menus/Develop_Menu/Develop_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Develop_Menu/Develop_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Develop_Menu/Develop_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Edit_Menu/Edit_Menu.html b/src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Edit_Menu/Edit_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Edit_Menu/Edit_Menu.png b/src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Edit_Menu/Edit_Menu.png rename to src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$imation_Control.docx b/src/Resources/Help/HelpFiles/Menus/File_Menu/._~$imation_Control.docx similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$imation_Control.docx rename to src/Resources/Help/HelpFiles/Menus/File_Menu/._~$imation_Control.docx diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$le_Menu.docx b/src/Resources/Help/HelpFiles/Menus/File_Menu/._~$le_Menu.docx similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$le_Menu.docx rename to src/Resources/Help/HelpFiles/Menus/File_Menu/._~$le_Menu.docx diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$pture_Image.docx b/src/Resources/Help/HelpFiles/Menus/File_Menu/._~$pture_Image.docx similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/._~$pture_Image.docx rename to src/Resources/Help/HelpFiles/Menus/File_Menu/._~$pture_Image.docx diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control.html b/src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control.html rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control_dialog.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control_dialog.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control_dialog.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Animation_Control_dialog.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Animation_Control/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Animation_Control/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image.html b/src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image.html rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image_dialog.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image_dialog.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image_dialog.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Capture_Image_dialog.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/File_menu.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/File_menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/File_menu.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/File_menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Capture_Image/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Capture_Image/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/File_Menu.html b/src/Resources/Help/HelpFiles/Menus/File_Menu/File_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/File_Menu.html rename to src/Resources/Help/HelpFiles/Menus/File_Menu/File_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/File_menu.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/File_menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/File_menu.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/File_menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences.html b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences.html rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Colors.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Colors.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Colors.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Colors.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_ID.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_ID.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_ID.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_ID.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Misc.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Misc.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Misc.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Misc.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_OpenGL.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_OpenGL.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_OpenGL.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_OpenGL.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Vol.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Vol.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Preferences_Vol.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Preferences_Vol.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Preferences/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Preferences/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Gear_symbol.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Gear_symbol.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Gear_symbol.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Gear_symbol.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Reload_symbol.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Reload_symbol.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Reload_symbol.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Reload_symbol.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Remove_symbol.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Remove_symbol.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Remove_symbol.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Remove_symbol.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files.html b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files.html rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files_dialog.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files_dialog.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files_dialog.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Save-Manage_Files_dialog.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Upload_symbol.png b/src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Upload_symbol.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Save-Manage_Files/Upload_symbol.png rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Save-Manage_Files/Upload_symbol.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/File_Menu/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/File_Menu/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/File_Menu/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Bug_Report_box.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Bug_Report_box.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Bug_Report_box.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Bug_Report_box.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Menu.html b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Menu.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Menu.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Search.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Search.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_Search.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_Search.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_box.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_box.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_box.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_box.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_button.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Help_button.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Help_button.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Workbench_Help.png b/src/Resources/Help/HelpFiles/Menus/Help_Menu/Workbench_Help.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Help_Menu/Workbench_Help.png rename to src/Resources/Help/HelpFiles/Menus/Help_Menu/Workbench_Help.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Surface_Menu.html b/src/Resources/Help/HelpFiles/Menus/Surface_Menu/Surface_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Surface_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Surface_Menu/Surface_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Surface_Properties.png b/src/Resources/Help/HelpFiles/Menus/Surface_Menu/Surface_Properties.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Surface_Properties.png rename to src/Resources/Help/HelpFiles/Menus/Surface_Menu/Surface_Properties.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Volume_Interaction_Surfaces.png b/src/Resources/Help/HelpFiles/Menus/Surface_Menu/Volume_Interaction_Surfaces.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Surface_Menu/Volume_Interaction_Surfaces.png rename to src/Resources/Help/HelpFiles/Menus/Surface_Menu/Volume_Interaction_Surfaces.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.html b/src/Resources/Help/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.html rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.png b/src/Resources/Help/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.png rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Gaps_And_Margins/Gaps_And_Margins.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/View_Menu/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png rename to src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/View_Menu.html b/src/Resources/Help/HelpFiles/Menus/View_Menu/View_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/View_Menu.html rename to src/Resources/Help/HelpFiles/Menus/View_Menu/View_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/View_Menu/View_Menu.png b/src/Resources/Help/HelpFiles/Menus/View_Menu/View_Menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/View_Menu/View_Menu.png rename to src/Resources/Help/HelpFiles/Menus/View_Menu/View_Menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/IdentifyBrainordinateDialog.png b/src/Resources/Help/HelpFiles/Menus/Window_Menu/IdentifyBrainordinateDialog.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/IdentifyBrainordinateDialog.png rename to src/Resources/Help/HelpFiles/Menus/Window_Menu/IdentifyBrainordinateDialog.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Rename_tab.png b/src/Resources/Help/HelpFiles/Menus/Window_Menu/Rename_tab.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Rename_tab.png rename to src/Resources/Help/HelpFiles/Menus/Window_Menu/Rename_tab.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/Window_Menu/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/Window_Menu/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Window_Menu.html b/src/Resources/Help/HelpFiles/Menus/Window_Menu/Window_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Window_Menu.html rename to src/Resources/Help/HelpFiles/Menus/Window_Menu/Window_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Window_Menu.png b/src/Resources/Help/HelpFiles/Menus/Window_Menu/Window_Menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/Window_Menu/Window_Menu.png rename to src/Resources/Help/HelpFiles/Menus/Window_Menu/Window_Menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/._~$_view_Menu.docx b/src/Resources/Help/HelpFiles/Menus/wb_view_Menu/._~$_view_Menu.docx similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/._~$_view_Menu.docx rename to src/Resources/Help/HelpFiles/Menus/wb_view_Menu/._~$_view_Menu.docx diff --git a/src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/Thumbs.db b/src/Resources/Help/HelpFiles/Menus/wb_view_Menu/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/Thumbs.db rename to src/Resources/Help/HelpFiles/Menus/wb_view_Menu/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.html b/src/Resources/Help/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.html rename to src/Resources/Help/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.html diff --git a/src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.png b/src/Resources/Help/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.png rename to src/Resources/Help/HelpFiles/Menus/wb_view_Menu/wb_view_Menu.png diff --git a/src/Resources/GuiResources/HelpFiles/Mouse_Controls/Mouse_Controls.html b/src/Resources/Help/HelpFiles/Mouse_Controls/Mouse_Controls.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Mouse_Controls/Mouse_Controls.html rename to src/Resources/Help/HelpFiles/Mouse_Controls/Mouse_Controls.html diff --git a/src/Resources/GuiResources/HelpFiles/Mouse_Controls/RightClick_Surface.png b/src/Resources/Help/HelpFiles/Mouse_Controls/RightClick_Surface.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Mouse_Controls/RightClick_Surface.png rename to src/Resources/Help/HelpFiles/Mouse_Controls/RightClick_Surface.png diff --git a/src/Resources/GuiResources/HelpFiles/Mouse_Controls/RightClick_Volume.png b/src/Resources/Help/HelpFiles/Mouse_Controls/RightClick_Volume.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Mouse_Controls/RightClick_Volume.png rename to src/Resources/Help/HelpFiles/Mouse_Controls/RightClick_Volume.png diff --git a/src/Resources/GuiResources/HelpFiles/Mouse_Controls/Thumbs.db b/src/Resources/Help/HelpFiles/Mouse_Controls/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Mouse_Controls/Thumbs.db rename to src/Resources/Help/HelpFiles/Mouse_Controls/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Open_Spec.png b/src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Open_Spec.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Open_Spec.png rename to src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Open_Spec.png diff --git a/src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Open_Spec_File_Dialog.html b/src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Open_Spec_File_Dialog.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Open_Spec_File_Dialog.html rename to src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Open_Spec_File_Dialog.html diff --git a/src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Thumbs.db b/src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/Thumbs.db rename to src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/gear-button.png b/src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/gear-button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Open_Spec_File_Dialog/gear-button.png rename to src/Resources/Help/HelpFiles/Open_Spec_File_Dialog/gear-button.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting_History.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting_History.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting_History.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting_History.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting_Loading.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting_Loading.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Charting_Loading.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Charting_Loading.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Thumbs.db b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Charting/Thumbs.db rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Charting/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Connectivity/Connectivity.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Add_Layer.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Add_Layer.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Add_Layer.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Add_Layer.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Colorbar.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Colorbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Colorbar.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Colorbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Layers.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Layers.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Layers.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Layers.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_Toolbox_horiz.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_Toolbox_horiz.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_Toolbox_horiz.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_Toolbox_horiz.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_and_Map_Settings.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_and_Map_Settings.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_and_Map_Settings.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_and_Map_Settings.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Palette_Settings.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Palette_Settings.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Palette_Settings.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Palette_Settings.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Settings_icon.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Settings_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Settings_icon.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Settings_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Settings_icon.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Settings_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Layers/Settings_icon.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Settings_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_horiz.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_horiz.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_horiz.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_horiz.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_vert.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_vert.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_vert.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Overlay_Toolbox_vert.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Thumbs.db b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Thumbs.db rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Color-Vol-Surf_Outline.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Color-Vol-Surf_Outline.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Color-Vol-Surf_Outline.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Color-Vol-Surf_Outline.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Tab-Vol-Surf_Outline.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Tab-Vol-Surf_Outline.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Tab-Vol-Surf_Outline.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Tab-Vol-Surf_Outline.png diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.html b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.html rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.html diff --git a/src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.png b/src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.png rename to src/Resources/Help/HelpFiles/Overlay_Toolbox/Vol-Surf_Outline/Vol-Surf_Outline.png diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene.png b/src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene.png rename to src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene.png diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene_File.html b/src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene_File.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene_File.html rename to src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Create_New_Scene_File.html diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Scenes button.png b/src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Scenes button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Scenes button.png rename to src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Scenes button.png diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Thumbs.db b/src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Create_New_Scene_File/Thumbs.db rename to src/Resources/Help/HelpFiles/Scenes_Window/Create_New_Scene_File/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Scenes_Window.html b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Scenes_Window.html rename to src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.html diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Scenes_Window.png b/src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Scenes_Window.png rename to src/Resources/Help/HelpFiles/Scenes_Window/Scenes_Window.png diff --git a/src/Resources/GuiResources/HelpFiles/Scenes_Window/Thumbs.db b/src/Resources/Help/HelpFiles/Scenes_Window/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Scenes_Window/Thumbs.db rename to src/Resources/Help/HelpFiles/Scenes_Window/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/CiftiFileRow.png b/src/Resources/Help/HelpFiles/Select_Brainordinate_Window/CiftiFileRow.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/CiftiFileRow.png rename to src/Resources/Help/HelpFiles/Select_Brainordinate_Window/CiftiFileRow.png diff --git a/src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/Indentify_Brainordinate.png b/src/Resources/Help/HelpFiles/Select_Brainordinate_Window/Indentify_Brainordinate.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/Indentify_Brainordinate.png rename to src/Resources/Help/HelpFiles/Select_Brainordinate_Window/Indentify_Brainordinate.png diff --git a/src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/Select_Brainordinate_Window.html b/src/Resources/Help/HelpFiles/Select_Brainordinate_Window/Select_Brainordinate_Window.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Select_Brainordinate_Window/Select_Brainordinate_Window.html rename to src/Resources/Help/HelpFiles/Select_Brainordinate_Window/Select_Brainordinate_Window.html diff --git a/src/Resources/GuiResources/HelpFiles/Splash_Screen/Splash_Screen.html b/src/Resources/Help/HelpFiles/Splash_Screen/Splash_Screen.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Splash_Screen/Splash_Screen.html rename to src/Resources/Help/HelpFiles/Splash_Screen/Splash_Screen.html diff --git a/src/Resources/GuiResources/HelpFiles/Splash_Screen/Splash_screen.png b/src/Resources/Help/HelpFiles/Splash_Screen/Splash_screen.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Splash_Screen/Splash_screen.png rename to src/Resources/Help/HelpFiles/Splash_Screen/Splash_screen.png diff --git a/src/Resources/GuiResources/HelpFiles/Splash_Screen/Thumbs.db b/src/Resources/Help/HelpFiles/Splash_Screen/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Splash_Screen/Thumbs.db rename to src/Resources/Help/HelpFiles/Splash_Screen/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_Toolbar.png b/src/Resources/Help/HelpFiles/Toolbar/All_View/All_Toolbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_Toolbar.png rename to src/Resources/Help/HelpFiles/Toolbar/All_View/All_Toolbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_View.html b/src/Resources/Help/HelpFiles/Toolbar/All_View/All_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_View.html rename to src/Resources/Help/HelpFiles/Toolbar/All_View/All_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_view.png b/src/Resources/Help/HelpFiles/Toolbar/All_View/All_view.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/All_View/All_view.png rename to src/Resources/Help/HelpFiles/Toolbar/All_View/All_view.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/All_View/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/All_View/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/All_View/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/All_View/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/All_View/Volume_ID_button.png b/src/Resources/Help/HelpFiles/Toolbar/All_View/Volume_ID_button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/All_View/Volume_ID_button.png rename to src/Resources/Help/HelpFiles/Toolbar/All_View/Volume_ID_button.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Chart_View.html b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Chart_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Chart_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Chart_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Chart_View/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Chart_View/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Chart_View/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Clipping.html b/src/Resources/Help/HelpFiles/Toolbar/Clipping/Clipping.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Clipping.html rename to src/Resources/Help/HelpFiles/Toolbar/Clipping/Clipping.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Clipping_Planes.png b/src/Resources/Help/HelpFiles/Toolbar/Clipping/Clipping_Planes.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Clipping_Planes.png rename to src/Resources/Help/HelpFiles/Toolbar/Clipping/Clipping_Planes.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Clipping/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Clipping/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Clipping/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.html b/src/Resources/Help/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.html rename to src/Resources/Help/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.png b/src/Resources/Help/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.png rename to src/Resources/Help/HelpFiles/Toolbar/Custom_Orientation/Custom_Orientation.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Drawing.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Drawing.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Drawing.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Drawing.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_Editing.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_Editing.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_Editing.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_Editing.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_edit.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_edit.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_edit.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Border_edit.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Edit_Border_Properties.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Edit_Border_Properties.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Edit_Border_Properties.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Edit_Border_Properties.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_Editing/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_drawing.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_drawing.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Border_drawing.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Border_drawing.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Border_ROI.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Border_ROI.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Border_ROI.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Border_ROI.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_ROI.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_ROI.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_ROI.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_ROI.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_Region_of_Interest.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_Region_of_Interest.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_Region_of_Interest.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Create_Region_of_Interest.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Create_ROI/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Drawing/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Drawing/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Tools.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Tools.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Border_Tools.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Border_Tools.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Create_Focus.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Create_Focus.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Create_Focus.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Create_Focus.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Creation.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Creation.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Creation.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Creation.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Edit_Focus_box.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Edit_Focus_box.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Edit_Focus_box.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Edit_Focus_box.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_Editing.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_Editing.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_Editing.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_Editing.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_edit.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_edit.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_edit.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Foci_edit.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Editing/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Tools.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Tools.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Tools.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Foci_Tools.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Creation/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Creation/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Tools.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Tools.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Foci_Tools.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Foci_Tools.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Mode.html b/src/Resources/Help/HelpFiles/Toolbar/Mode/Mode.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Mode.html rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Mode.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Mode/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Volume_Tools.png b/src/Resources/Help/HelpFiles/Toolbar/Mode/Volume_Tools.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Mode/Volume_Tools.png rename to src/Resources/Help/HelpFiles/Toolbar/Mode/Volume_Tools.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Montage_View.html b/src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Montage_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png b/src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png rename to src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Montage_View/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Montage_View/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Montage_View/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/SurfaceView.png b/src/Resources/Help/HelpFiles/Toolbar/Surface_View/SurfaceView.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/SurfaceView.png rename to src/Resources/Help/HelpFiles/Toolbar/Surface_View/SurfaceView.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/Surface_View.html b/src/Resources/Help/HelpFiles/Toolbar/Surface_View/Surface_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/Surface_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Surface_View/Surface_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Surface_View/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Surface_View/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Surface_View/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.html b/src/Resources/Help/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.html rename to src/Resources/Help/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.png b/src/Resources/Help/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.png rename to src/Resources/Help/HelpFiles/Toolbar/Tab_Functions/Tab_Functions.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Toolbar.html b/src/Resources/Help/HelpFiles/Toolbar/Toolbar.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Toolbar.html rename to src/Resources/Help/HelpFiles/Toolbar/Toolbar.html diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Toolbar_icon.png b/src/Resources/Help/HelpFiles/Toolbar/Toolbar_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Toolbar_icon.png rename to src/Resources/Help/HelpFiles/Toolbar/Toolbar_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/VolumeView.png b/src/Resources/Help/HelpFiles/Toolbar/VolumeView.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/VolumeView.png rename to src/Resources/Help/HelpFiles/Toolbar/VolumeView.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Thumbs.db b/src/Resources/Help/HelpFiles/Toolbar/Volume_View/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Thumbs.db rename to src/Resources/Help/HelpFiles/Toolbar/Volume_View/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/VolumeView.png b/src/Resources/Help/HelpFiles/Toolbar/Volume_View/VolumeView.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/VolumeView.png rename to src/Resources/Help/HelpFiles/Toolbar/Volume_View/VolumeView.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png b/src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png rename to src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png diff --git a/src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Volume_View.html b/src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_View.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Toolbar/Volume_View/Volume_View.html rename to src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_View.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Active_Tab.html b/src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Active_Tab.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Active_Tab.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Active_Tab.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Viewing_Tabs.png b/src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Viewing_Tabs.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Active_Tab/Viewing_Tabs.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Active_Tab/Viewing_Tabs.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Tooltip.html b/src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Tooltip.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Tooltip.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Tooltip.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Tooltip.png b/src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Tooltip.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Tooltip/Tooltip.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Tooltip/Tooltip.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/Viewing_Area.html b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/Viewing_Area.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/Viewing_Area.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/Viewing_Area.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.html b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.png b/src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Tabs/Viewing_Tabs.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/WBwindow_Horiz_Labels.png b/src/Resources/Help/HelpFiles/Workbench_Window/WBwindow_Horiz_Labels.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/WBwindow_Horiz_Labels.png rename to src/Resources/Help/HelpFiles/Workbench_Window/WBwindow_Horiz_Labels.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Features_TB_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Features_TB_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Features_TB_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Features_TB_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Help_button.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Help_button.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Help_button.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Help_button.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_Brainordinate_Icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_Brainordinate_Icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_Brainordinate_Icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_Brainordinate_Icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Identify_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Information_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Information_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Information_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Information_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Overlay_TB_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Scenes_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Thumbs.db b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Thumbs.db similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Thumbs.db rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Thumbs.db diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html b/src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html diff --git a/src/Resources/GuiResources/HelpFiles/Workbench_Window/Workbench_Window.html b/src/Resources/Help/HelpFiles/Workbench_Window/Workbench_Window.html similarity index 100% rename from src/Resources/GuiResources/HelpFiles/Workbench_Window/Workbench_Window.html rename to src/Resources/Help/HelpFiles/Workbench_Window/Workbench_Window.html diff --git a/src/Resources/GuiResources/gui_resources.qrc b/src/Resources/Help/help_resources.qrc similarity index 99% rename from src/Resources/GuiResources/gui_resources.qrc rename to src/Resources/Help/help_resources.qrc index ca40feb95..2aada5613 100644 --- a/src/Resources/GuiResources/gui_resources.qrc +++ b/src/Resources/Help/help_resources.qrc @@ -1,6 +1,6 @@ -./gui_resources.qrc +./help_resources.qrc ./HelpFiles/Annotations/Annotations.fld/image001.png ./HelpFiles/Annotations/Annotations.fld/image002.png ./HelpFiles/Annotations/Annotations.fld/image003.png @@ -245,5 +245,6 @@ ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Toolbar_icon.png ./HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/Window_Elements_Hide-Show_Buttons.html ./HelpFiles/Workbench_Window/Workbench_Window.html +./update_resources.sh diff --git a/src/Resources/GuiResources/update_resources.sh b/src/Resources/Help/update_resources.sh similarity index 100% rename from src/Resources/GuiResources/update_resources.sh rename to src/Resources/Help/update_resources.sh -- GitLab From eee356abf53ab8431de7368c69a8e74fd1454320 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 21 Oct 2016 20:25:15 -0500 Subject: [PATCH 002/755] fix some silliness in hostnames in preparation for new autobuild script system, pass build output through ssh to _remote scripts --- build_scripts/linux64_rh.sh | 18 +++--------------- build_scripts/linux64_rh_remote.sh | 1 + build_scripts/mac64.sh | 17 +++-------------- build_scripts/mac64_remote.sh | 1 + build_scripts/windows32_remote.sh | 2 +- build_scripts/windows64_remote.sh | 2 +- build_scripts/windows64_remote_debug.sh | 2 +- 7 files changed, 11 insertions(+), 32 deletions(-) diff --git a/build_scripts/linux64_rh.sh b/build_scripts/linux64_rh.sh index f34edea65..f6125abba 100755 --- a/build_scripts/linux64_rh.sh +++ b/build_scripts/linux64_rh.sh @@ -13,8 +13,6 @@ # File for capturing standard error # BUILD_ROOT_DIR=/home/caret/caret7_dev -ERROR_FILE=${BUILD_ROOT_DIR}/result_build_linux64_rh.txt -rm -f ${ERROR_FILE} # # If something fails, keep going @@ -24,16 +22,6 @@ set noon # # Run the build script # -echo "Starting linux64 Redhat aux script" >> ${ERROR_FILE} 2>&1 -${BUILD_ROOT_DIR}/caret7_source/build_scripts/linux64_rh_aux.sh >> ${ERROR_FILE} 2>&1 -echo "Finished linux64 Redhat script" >> ${ERROR_FILE} 2>&1 - -# -# Send output as email -# -MAIL_ERROR_FILE=${BUILD_ROOT_DIR}/mail_result_build_linux64_rh.txt -rm -f ${MAIL_ERROR_FILE} -cat ${ERROR_FILE} | mail -v -s 'Caret7 Linux 64 Redhat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu >> ${MAIL_ERROR_FILE} 2>&1 - -echo "Sent mail" - +echo "Starting linux64 Redhat aux script" +${BUILD_ROOT_DIR}/caret7_source/build_scripts/linux64_rh_aux.sh +echo "Finished linux64 Redhat script" diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh index 50b2e9981..245dcbc71 100755 --- a/build_scripts/linux64_rh_remote.sh +++ b/build_scripts/linux64_rh_remote.sh @@ -5,3 +5,4 @@ BUILD_SERVER=login1.chpc.wustl.edu #BUILD_DIR=/home/caret/caret7_dev/${BUILD} BUILD_DIR=/home/caret/caret7_dev ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 +cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/mac64.sh b/build_scripts/mac64.sh index 6e636ee76..657a6b049 100755 --- a/build_scripts/mac64.sh +++ b/build_scripts/mac64.sh @@ -13,8 +13,6 @@ # File for capturing standard error # BUILD_ROOT_DIR=/Users/caret/caret7_development/mac64 -ERROR_FILE=${BUILD_ROOT_DIR}/result_build_mac64.txt -rm -f ${ERROR_FILE} # # If something fails, keep going @@ -24,16 +22,7 @@ set noon # # Run the build script # -echo "Starting mac64 aux script" >> ${ERROR_FILE} 2>&1 -${BUILD_ROOT_DIR}/caret7_source/build_scripts/mac64_aux.sh >> ${ERROR_FILE} 2>&1 -echo "Finished mac64 aux script" >> ${ERROR_FILE} 2>&1 - -# -# Send output as email -# -MAIL_ERROR_FILE=${BUILD_ROOT_DIR}/mail_result_build_mac64.txt -rm -f ${MAIL_ERROR_FILE} -cat ${ERROR_FILE} | mail -v -s 'Caret7 Mac 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu >> ${MAIL_ERROR_FILE} 2>&1 - -echo "Sent mail" +echo "Starting mac64 aux script" +${BUILD_ROOT_DIR}/caret7_source/build_scripts/mac64_aux.sh +echo "Finished mac64 aux script" diff --git a/build_scripts/mac64_remote.sh b/build_scripts/mac64_remote.sh index 517d689ee..6cf5ef588 100755 --- a/build_scripts/mac64_remote.sh +++ b/build_scripts/mac64_remote.sh @@ -4,3 +4,4 @@ BUILD_SERVER=hippocampus.wustl.edu BUILD_DIR=/Users/caret/caret7_development/${BUILD} ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 +cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/windows32_remote.sh b/build_scripts/windows32_remote.sh index 3e8fbe4d2..69633f8e3 100755 --- a/build_scripts/windows32_remote.sh +++ b/build_scripts/windows32_remote.sh @@ -1,4 +1,4 @@ #!/bin/sh -ssh -v caret@windowsbuild 'c:\dev7\windows32\caret7_source\build_scripts\windows32.bat' > $PWD/remote_launch_windows32.txt 2>&1 +ssh -v caret@winbuild 'c:\dev7\windows32\caret7_source\build_scripts\windows32.bat' > $PWD/remote_launch_windows32.txt 2>&1 cat $PWD/remote_launch_windows32.txt | mailx -s 'Caret7 Windows 32 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/windows64_remote.sh b/build_scripts/windows64_remote.sh index 528109a23..c3ca8c493 100755 --- a/build_scripts/windows64_remote.sh +++ b/build_scripts/windows64_remote.sh @@ -1,4 +1,4 @@ #!/bin/sh -ssh -v caret@windowsbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64.bat' > remote_launch_windows64.txt 2>&1 +ssh -v caret@winbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64.bat' > remote_launch_windows64.txt 2>&1 cat remote_launch_windows64.txt | mailx -s 'Caret7 Windows 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/windows64_remote_debug.sh b/build_scripts/windows64_remote_debug.sh index 32036e65e..4918be8ab 100755 --- a/build_scripts/windows64_remote_debug.sh +++ b/build_scripts/windows64_remote_debug.sh @@ -1,4 +1,4 @@ #!/bin/sh -ssh -v caret@windowsbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64_debug.bat' > remote_launch_windows64_debug.txt 2>&1 +ssh -v caret@winbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64_debug.bat' > remote_launch_windows64_debug.txt 2>&1 cat remote_launch_windows64_debug.txt | mailx -s 'Caret7 Windows 64 DEBUG Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From f639486ef16d763d6c7185a6ac2c043c7d752f6d Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 21 Oct 2016 20:47:24 -0500 Subject: [PATCH 003/755] less verbosity in sftp --- build_scripts/linux64_rh_aux.sh | 8 ++++---- build_scripts/mac64_aux.sh | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build_scripts/linux64_rh_aux.sh b/build_scripts/linux64_rh_aux.sh index 6f285e8a0..515c33bd3 100755 --- a/build_scripts/linux64_rh_aux.sh +++ b/build_scripts/linux64_rh_aux.sh @@ -42,11 +42,11 @@ make -j2 # echo "COPYING PROGRAMS" DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 -scp -v Desktop/wb_view caret@myelin1.wustl.edu:${DIST_DIR} -scp -v CommandLine/wb_command caret@myelin1.wustl.edu:${DIST_DIR} -scp -v ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 +scp Desktop/wb_view caret@myelin1.wustl.edu:${DIST_DIR} +scp CommandLine/wb_command caret@myelin1.wustl.edu:${DIST_DIR} +scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 #put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) -scp -v ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} +scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} echo "SCRIPT COMPLETED SUCCESSFULLY" diff --git a/build_scripts/mac64_aux.sh b/build_scripts/mac64_aux.sh index a3411374e..fb8273aa9 100755 --- a/build_scripts/mac64_aux.sh +++ b/build_scripts/mac64_aux.sh @@ -102,10 +102,10 @@ macdeployqt CommandLine/wb_command.app -verbose=0 # echo "COPYING PROGRAMS" DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/macosx64_apps -scp -rv Desktop/wb_view.app caret@myelin1:${DIST_DIR} -scp -rv CommandLine/wb_command.app caret@myelin1:${DIST_DIR} -scp -v ${SRC_DIR}/CommandLine/wb_shortcuts caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_macosx64 -scp -v ${SRC_DIR}/CommandLine/bashcomplete_wb_command caret@myelin1:${DIST_DIR} +scp -r Desktop/wb_view.app caret@myelin1:${DIST_DIR} +scp -r CommandLine/wb_command.app caret@myelin1:${DIST_DIR} +scp ${SRC_DIR}/CommandLine/wb_shortcuts caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_macosx64 +scp ${SRC_DIR}/CommandLine/bashcomplete_wb_command caret@myelin1:${DIST_DIR} echo "SCRIPT COMPLETED SUCCESSFULLY" -- GitLab From a57c66f4f1e5481e10cca4af0beb121adb377f67 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 24 Oct 2016 16:02:49 -0500 Subject: [PATCH 004/755] fix help files updating script for reorganization --- src/Resources/Help/update_resources.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/Help/update_resources.sh b/src/Resources/Help/update_resources.sh index 4276cbc3a..d87434ab8 100755 --- a/src/Resources/Help/update_resources.sh +++ b/src/Resources/Help/update_resources.sh @@ -6,7 +6,7 @@ cp -r /mnt/myelin/shared/WB_Tutorial/WB_1.2_Help ./HelpFiles rm -rf OLD_HelpFiles -rcc -project -o gui_resources.qrc +rcc -project -o help_resources.qrc echo "" echo "You now need to:" -- GitLab From e9b914916d84c60fdc124624042572fdf256a8c5 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 25 Oct 2016 14:42:30 -0500 Subject: [PATCH 005/755] install completion script non-executable, per lintian --- src/CommandLine/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index 328c5af0f..46fa50413 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -80,7 +80,7 @@ ${LIBS}) INSTALL(TARGETS ${EXE_NAME} DESTINATION bin) INSTALL(PROGRAMS wb_shortcuts DESTINATION bin) -INSTALL(PROGRAMS bashcomplete_wb_command DESTINATION /usr/share/bash-completion/completions RENAME wb_command) +INSTALL(FILES bashcomplete_wb_command DESTINATION /usr/share/bash-completion/completions RENAME wb_command) # # Find Headers -- GitLab From 47ad39de370378fe1c4209a631a11fae846e69ea Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 25 Oct 2016 18:32:36 -0500 Subject: [PATCH 006/755] make bash complete show directories while completing for glob expressions --- src/CommandLine/bashcomplete_wb_command | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/bashcomplete_wb_command b/src/CommandLine/bashcomplete_wb_command index adfd1a2f1..a2df7446a 100644 --- a/src/CommandLine/bashcomplete_wb_command +++ b/src/CommandLine/bashcomplete_wb_command @@ -64,10 +64,10 @@ function _wb_command() fileglob) #bash_completion itself uses -f -X for file extension matching #using -G requires manually adding $cur before the pattern - COMPREPLY+=(`compgen -f -X "!${exereply[$((i + 1))]}" -- "$cur"`) + COMPREPLY+=(`compgen -o plusdirs -f -X "!${exereply[$((i + 1))]}" -- "$cur"`) ;; wordlist) - #for the things accepted as bool, maybe other uses - happens to function like "option" for now + #for the things accepted as bool, logging levels, maybe other uses COMPREPLY+=(`compgen -W "${exereply[$((i + 1))]}" -- "$cur"`) ;; esac -- GitLab From 19aaf41be6160c24c6810b464c41e047c2c41e1c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 27 Oct 2016 14:51:29 -0500 Subject: [PATCH 007/755] improve sanity checking in -cifti-create-label and setCiftiXML --- src/Algorithms/AlgorithmCiftiCreateLabel.cxx | 13 ++++++++++++- src/Cifti/CiftiFile.cxx | 19 ++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/Algorithms/AlgorithmCiftiCreateLabel.cxx b/src/Algorithms/AlgorithmCiftiCreateLabel.cxx index 2bb09ff74..465458115 100644 --- a/src/Algorithms/AlgorithmCiftiCreateLabel.cxx +++ b/src/Algorithms/AlgorithmCiftiCreateLabel.cxx @@ -245,6 +245,10 @@ AlgorithmCiftiCreateLabel::AlgorithmCiftiCreateLabel(ProgressObject* myProgObj, } } } + if (count == 0) + { + throw AlgorithmException("volume label file does not contain any structure names"); + } voxelLists.resize(count); vector mydims; myVolLabel->getDimensions(mydims); @@ -273,7 +277,14 @@ AlgorithmCiftiCreateLabel::AlgorithmCiftiCreateLabel(ProgressObject* myProgObj, myXML.setVolumeDimsAndSForm(ciftiVolDims, myVol->getSform()); for (map::iterator myiter = componentMap.begin(); myiter != componentMap.end(); ++myiter) { - myXML.addVolumeModelToColumns(voxelLists[myiter->second], myiter->first); + if (!voxelLists[myiter->second].empty()) + { + myXML.addVolumeModelToColumns(voxelLists[myiter->second], myiter->first); + } + } + if (myXML.getNumberOfRows() == 0) + { + throw AlgorithmException("volume label file does not label any voxels as any structure"); } } if (numMaps == -1) diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index aead6aa80..3474b78a1 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -226,9 +226,14 @@ void CiftiFile::getColumn(float* dataOut, const int64_t& index) const void CiftiFile::setCiftiXML(const CiftiXML& xml, const bool useOldMetadata) { + if (xml.getNumberOfDimensions() == 0) throw DataFileException("setCiftiXML called with 0-dimensional CiftiXML"); + vector xmlDims = xml.getDimensions(); + for (size_t i = 0; i < xmlDims.size(); ++i) + { + if (xmlDims[i] < 1) throw DataFileException("cifti xml dimensions must be greater than zero"); + } m_readingImpl.grabNew(NULL);//drop old implementation, as it is now invalid due to XML (and therefore matrix size) change m_writingImpl.grabNew(NULL); - if (xml.getNumberOfDimensions() == 0) throw DataFileException("setCiftiXML called with 0-dimensional CiftiXML"); if (useOldMetadata) { const GiftiMetaData* oldmd = m_xml.getFileMetaData(); @@ -248,11 +253,7 @@ void CiftiFile::setCiftiXML(const CiftiXML& xml, const bool useOldMetadata) } else { m_xml = xml; } - m_dims = m_xml.getDimensions(); - for (size_t i = 0; i < m_dims.size(); ++i) - { - if (m_dims[i] < 1) throw DataFileException("cifti xml dimensions must be greater than zero"); - } + m_dims = xmlDims; } void CiftiFile::setCiftiXML(const CiftiXMLOld& xml, const bool useOldMetadata) @@ -261,12 +262,12 @@ void CiftiFile::setCiftiXML(const CiftiXMLOld& xml, const bool useOldMetadata) xml.writeXML(xmlText); CiftiXML tempXML;//so that we can use the same code path tempXML.readXML(xmlText); - if (tempXML.getDimensionLength(CiftiXML::ALONG_ROW) < 1) + if (tempXML.getDimensionLength(CiftiXML::ALONG_ROW) < 0) { CiftiSeriesMap& tempMap = tempXML.getSeriesMap(CiftiXML::ALONG_ROW); tempMap.setLength(xml.getDimensionLength(CiftiXMLOld::ALONG_ROW)); } - if (tempXML.getDimensionLength(CiftiXML::ALONG_COLUMN) < 1) + if (tempXML.getDimensionLength(CiftiXML::ALONG_COLUMN) < 0) { CiftiSeriesMap& tempMap = tempXML.getSeriesMap(CiftiXML::ALONG_COLUMN); tempMap.setLength(xml.getDimensionLength(CiftiXMLOld::ALONG_COLUMN)); @@ -469,7 +470,7 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename) if (m_xml.getNumberOfDimensions() + 4 != (int)dimCheck.size()) throw DataFileException("XML does not match number of nifti dimensions in file " + filename + "'"); for (int i = 4; i < (int)dimCheck.size(); ++i) { - if (m_xml.getDimensionLength(i - 4) < 1)//CiftiXML will only let this happen with cifti-1 + if (m_xml.getDimensionLength(i - 4) < 0)//CiftiXML will only let this happen with cifti-1 { m_xml.getSeriesMap(i - 4).setLength(dimCheck[i]);//and only in a series map } else { -- GitLab From 56c4c83508ae40798e0c0d231ad817111c255e11 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Sep 2016 16:16:33 -0500 Subject: [PATCH 008/755] Edited CMakeLists.txt files to remove QT4_WRAP_UI and QT4_WRAP_CPP commands and the explicit identification of files for processing with qt's moc and uic programs. Added SET statements to set both CMAKE_AUTOMOC and CMAKE_AUTOUIC to 'ON' so that files that need to be processed by moc and uic are automatically identified. Both of these new variables are compatible with both Qt4 and Qt5 and will simplify adding support for Qt5. --- src/CMakeLists.txt | 2 +- src/Common/CMakeLists.txt | 7 +- src/GuiQt/CMakeLists.txt | 181 +------------------------------------- src/Quazip/CMakeLists.txt | 8 +- src/Qwt/CMakeLists.txt | 35 +------- 5 files changed, 7 insertions(+), 226 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 397d53048..5f5c78081 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # # Minimum required version of CMAKE # -CMAKE_MINIMUM_REQUIRED (VERSION 2.8) +CMAKE_MINIMUM_REQUIRED (VERSION 3.5) MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index b6949ed88..69f68f997 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -15,11 +15,7 @@ SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) #message("QT VERSION: " ${QT_VERSION_MAJOR} ${QT_VERSION_MINOR} ${QT_VERSION_PATCH}) -SET(MOC_INPUT_HEADER_FILES -CaretHttpManager.h -) - -QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) +SET (CMAKE_AUTOMOC ON) # # Create a library @@ -132,7 +128,6 @@ VectorOperation.h VoxelIJK.h YokingGroupEnum.h -${MOC_SOURCE_FILES} ${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx ApplicationTypeEnum.cxx AString.cxx diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 746648288..fec9ddeb4 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -17,180 +17,14 @@ SET(QT_USE_QTOPENGL TRUE) INCLUDE(${QT_USE_FILE}) # -# Headers that must be processed with QT's "moc" -# Any class that derives from a QT class and contains -# the "Q_OBJECT" macro must be listed here. +# Let CMake find files for moc and uic. # -# Also LIST each of these headers in the -# source files section so that they show -# up in development tools such as XCode. -# -SET(MOC_INPUT_HEADER_FILES -AboutWorkbenchDialog.h -AnnotationChangeCoordinateDialog.h -AnnotationColorWidget.h -AnnotationCoordinateSelectionWidget.h -AnnotationCoordinateSpaceWidget.h -AnnotationCoordinateWidget.h -AnnotationCreateDialog.h -AnnotationDeleteWidget.h -AnnotationFontWidget.h -AnnotationFormatWidget.h -AnnotationInsertNewWidget.h -AnnotationLineArrowTipsWidget.h -AnnotationMenuArrange.h -AnnotationMenuFileSelection.h -AnnotationRedoUndoWidget.h -AnnotationRotationWidget.h -AnnotationSelectionViewController.h -AnnotationPasteDialog.h -AnnotationTextAlignmentWidget.h -AnnotationTextEditorDialog.h -AnnotationTextEditorWidget.h -AnnotationTextOrientationWidget.h -AnnotationWidthHeightWidget.h -BalsaDatabaseUploadSceneFileDialog.h -BorderEditingSelectionDialog.h -BorderFileSplitDialog.h -BorderOptimizeDialog.h -BorderPropertiesEditorDialog.h -BorderSelectionViewController.h -BrainBrowserWindow.h -BrainBrowserWindowComboBox.h -BrainBrowserWindowOrientedToolBox.h -BrainBrowserWindowToolBar.h -BrainBrowserWindowToolBarChartAttributes.h -BrainBrowserWindowToolBarChartAxes.h -BrainBrowserWindowToolBarChartType.h -BrainBrowserWindowToolBarClipping.h -BrainBrowserWindowToolBarComponent.h -BrainBrowserWindowToolBarSlicePlane.h -BrainBrowserWindowToolBarSliceSelection.h -BrainBrowserWindowToolBarSurfaceMontage.h -BrainBrowserWindowToolBarTab.h -BrainBrowserWindowToolBarVolumeMontage.h -BrainOpenGLWidget.h -BugReportDialog.h -CaretColorEnumComboBox.h -CaretColorEnumMenu.h -CaretDataFileSelectionComboBox.h -CaretFileDialog.h -CaretFileDialogExtendable.h -CaretFileRemoteDialog.h -CaretMappableDataFileAndMapSelector.h -CaretMappableDataFileAndMapSelectorObject.h -ChartHistoryViewController.h -ChartLinesSelectionViewController.h -ChartMatrixParcelSelectionViewController.h -ChartMatrixSeriesSelectionViewController.h -ChartSelectionViewController.h -ChartToolBoxViewController.h -CiftiConnectivityMatrixViewController.h -CiftiParcelSelectionComboBox.h -ClippingPlanesDialog.h -ColorEditorWidget.h -CustomViewDialog.h -DataFileContentCopyMoveDialog.h -DisplayGroupAndTabItemViewController.h -DisplayGroupEnumComboBox.h -EnumComboBoxTemplate.h -FiberOrientationSelectionViewController.h -FiberSamplesOpenGLWidget.h -FociProjectionDialog.h -FociPropertiesEditorDialog.h -FociSelectionViewController.h -GapsAndMarginsDialog.h -GiftiLabelTableEditor.h -GiftiLabelTableSelectionComboBox.h -GroupAndNameHierarchyViewController.h -GuiManager.h -HelpViewerDialog.h -HyperLinkTextBrowser.h -IdentifyBrainordinateDialog.h -ImageCaptureDialog.h -ImageFileConvertToVolumeFileDialog.h -ImageSelectionViewController.h -InformationDisplayDialog.h -InformationDisplayPropertiesDialog.h -LabelSelectionViewController.h -MacApplication.h -MacDockMenu.h -MapSettingsColorBarWidget.h -MapSettingsFiberTrajectoryWidget.h -MapSettingsLabelsWidget.h -MapSettingsLayerWidget.h -MapSettingsPaletteColorMappingWidget.h -MapSettingsParcelsWidget.h -MapYokingGroupComboBox.h -MetaDataEditorDialog.h -MetaDataEditorWidget.h -MovieDialog.h -OverlaySetViewController.h -OverlaySettingsEditorDialog.h -OverlayViewController.h -PaletteColorMappingEditorDialog.h -PlotMagnifier.h -PlotPanner.h -PreferencesDialog.h -ProgressReportingDialog.h -ProgressReportingFromEvent.h -ProgressReportingWithSlots.h -RegionOfInterestCreateFromBorderDialog.h -SceneCreateReplaceDialog.h -SceneDialog.h -ScenePreviewDialog.h -SpecFileManagementDialog.h -SplashScreen.h -StructureEnumComboBox.h -StructureSurfaceSelectionControl.h -SurfacePropertiesEditorDialog.h -SurfaceSelectionViewController.h -TileTabsConfigurationDialog.h -UserInputModeAnnotationsContextMenu.h -UserInputModeAnnotationsWidget.h -UserInputModeBordersWidget.h -UserInputModeFociWidget.h -UserInputModeImageWidget.h -UserInputModeViewContextMenu.h -UserInputModeVolumeEditWidget.h -UsernamePasswordWidget.h -VolumeFileCreateDialog.h -VolumeSurfaceOutlineColorOrTabViewController.h -VolumeSurfaceOutlineSetViewController.h -VolumeSurfaceOutlineViewController.h -WuQCollapsibleWidget.h -WuQDataEntryDialog.h -WuQDialog.h -WuQDialogModal.h -WuQDialogNonModal.h -WuQDoubleSlider.h -WuQEventBlockingFilter.h -WuQGridLayoutGroup.h -WuQGroupBoxExclusiveWidget.h -WuQImageLabel.h -WuQListWidget.h -WuQMessageBox.h -WuQwtPlot.h -WuQSpecialIncrementDoubleSpinBox.h -WuQSpinBoxGroup.h -WuQSpinBoxOddValue.h -WuQTabWidget.h -WuQTimedMessageDisplay.h -WuQTreeWidget.h -WuQTrueFalseComboBox.h -#WuQWebView.h -WuQWidget.h -WuQWidgetObjectGroup.h -ZipSceneFileDialog.h -) +SET(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) # # Header files # -# If the header file is qt 'moc' file -# also list it in the section above -# named MOC_INPUT_HEADER_FILES -# SET(SOURCE_FILES AboutWorkbenchDialog.h AnnotationChangeCoordinateDialog.h @@ -594,26 +428,17 @@ WuQtUtilities.cxx ZipSceneFileDialog.cxx ) -SET(FORMS - MovieDialog.ui) - - # # Process the header files with moc producing moc_*.cpp files # - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/GuiQt) -QT4_WRAP_UI(FORMS_HEADERS ${FORMS}) -QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) # # Create the GUI library # ADD_LIBRARY(GuiQt ${SOURCE_FILES} -${MOC_SOURCE_FILES} -${FORMS_HEADERS} ) INCLUDE_DIRECTORIES( diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index f34f26958..08e34caa4 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -10,11 +10,7 @@ SET(QT_DONT_USE_QTGUI TRUE) INCLUDE(${QT_USE_FILE}) -SET(MOC_INPUT_HEADER_FILES -quazipfile.h -) - -QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) +SET(CMAKE_AUTOMOC ON) # # Prevents dll linkage errors on windows @@ -50,8 +46,6 @@ quazipnewinfo.h unzip.h zip.h -${MOC_SOURCE_FILES} - JlCompress.cpp qioapi.cpp quaadler32.cpp diff --git a/src/Qwt/CMakeLists.txt b/src/Qwt/CMakeLists.txt index bfee91248..c40c075d1 100644 --- a/src/Qwt/CMakeLists.txt +++ b/src/Qwt/CMakeLists.txt @@ -20,40 +20,8 @@ INCLUDE(${QT_USE_FILE}) add_definitions(-DQWT_NO_SVG -DQWT_NO_OPENGL) # -# Headers that must be processed with QT's "moc" -# Any class that derives from a QT class and contains -# the "Q_OBJECT" macro must be listed here. -# -# Also LIST each of these headers in the -# source files section so that they show -# up in development tools such as XCode. -# -SET(MOC_INPUT_HEADER_FILES -qwt_abstract_legend.h -qwt_dyngrid_layout.h -qwt_legend.h -qwt_legend_label.h -qwt_magnifier.h -qwt_panner.h -qwt_picker.h -qwt_plot_canvas.h -qwt_plot.h -qwt_plot_magnifier.h -qwt_plot_panner.h -qwt_plot_picker.h -qwt_plot_renderer.h -qwt_plot_zoomer.h -qwt_sampling_thread.h -qwt_scale_widget.h -qwt_text_label.h -) - # Header files # -# If the header file is qt 'moc' file -# also list it in the section above -# named MOC_INPUT_HEADER_FILES -# SET(SOURCE_FILES qwt_abstract_legend.h qwt_abstract_scale_draw.h @@ -225,14 +193,13 @@ qwt_widget_overlay.cpp # Process the header files with moc producing moc_*.cpp files # INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) +SET(CMAKE_AUTOMOC ON) # # Create the GUI library # ADD_LIBRARY(Qwt ${SOURCE_FILES} -${MOC_SOURCE_FILES} ) SET(Qwt_LIBRARIES Qwt PARENT_SCOPE) -- GitLab From 1be2bac07b079641f112b2efe973e048eff5e6f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Sep 2016 17:02:06 -0500 Subject: [PATCH 009/755] Updated all CMakeLists.txt files so that one can configure with Qt4 or Qt5. Able to build with Qt4 but more changes needed to build with Qt5. --- src/Algorithms/CMakeLists.txt | 4 ++- src/Brain/CMakeLists.txt | 4 ++- src/CMakeLists.txt | 53 ++++++++++++++++++++++++++----- src/Cifti/CMakeLists.txt | 4 ++- src/CommandLine/CMakeLists.txt | 12 +++++-- src/Commands/CMakeLists.txt | 5 ++- src/Common/CMakeLists.txt | 4 ++- src/Desktop/CMakeLists.txt | 15 +++++++-- src/Files/CMakeLists.txt | 4 ++- src/FilesBase/CMakeLists.txt | 4 ++- src/FtglFont/CMakeLists.txt | 5 ++- src/Gifti/CMakeLists.txt | 4 ++- src/GuiQt/CMakeLists.txt | 4 ++- src/Nifti/CMakeLists.txt | 4 ++- src/OSMesaDummy/CMakeLists.txt | 4 ++- src/Operations/CMakeLists.txt | 4 ++- src/OperationsBase/CMakeLists.txt | 4 ++- src/Palette/CMakeLists.txt | 4 ++- src/Quazip/CMakeLists.txt | 4 ++- src/Qwt/CMakeLists.txt | 4 ++- src/Scenes/CMakeLists.txt | 4 ++- src/Tests/CMakeLists.txt | 4 ++- src/Xml/CMakeLists.txt | 4 ++- 23 files changed, 130 insertions(+), 32 deletions(-) diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index a91f60a71..51e36a548 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create the helper library diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index c0e1d3a4c..702f9ef12 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -21,7 +21,9 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Need OpenGL diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f5c78081..82cc88d97 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -227,18 +227,55 @@ ELSE (OPENSSL_FOUND) ENDIF(OPENSSL_FOUND) # -# Must have QT 4.8 or later -# -FIND_PACKAGE(Qt4 4.8 REQUIRED) -IF(QT4_FOUND) -ELSE(QT4_FOUND) - MESSAGE(FATAL_ERROR "QT4 not found") -ENDIF(QT4_FOUND) +# Must have QT 4.8 or QT 5.6 or later +# https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) +# Modules List: http://doc.qt.io/qt-5/qtmodules.html +# +###FIND_PACKAGE(Qt5 5.6.0 CONFIG Gui Network Test Widgets Xml) +FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Core Gui Network Test Widgets Xml) +IF (Qt5_FOUND) + MESSAGE("Found Qt 5") + ##SET(moduleError "") + IF (NOT Qt5Gui_FOUND) + STRING(APPEND moduleError "Qt5 Gui module not found\n") + ENDIF() + IF (NOT Qt5Network_FOUND) + STRING(APPEND moduleError "Qt5 Network module not found\n") + ENDIF() + IF (NOT Qt5Test_FOUND) + STRING(APPEND moduleError "Qt5 Test module not found\n") + ENDIF() + IF (NOT Qt5Widgets_FOUND) + STRING(APPEND moduleError "Qt5 Widgets module not found\n") + ENDIF() + IF (NOT Qt5Xml_FOUND) + STRING(APPEND moduleError "Qt5 XML module not found\n") + ENDIF() + IF (NOT Qt5Core_FOUND) + STRING(APPEND moduleError "Qt5 Core module not found\n") + ENDIF() +# IF (NOT Qt5Crap_FOUND) +# STRING(APPEND moduleError "Qt5 Crap module not found\n") +# ENDIF() + IF (moduleError) + MESSAGE(FATAL_ERROR "Missing Modules\n" ${moduleError}) + ENDIF() + MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") +ELSE (Qt5_FOUND) + MESSAGE("Qt5 not found, looking for Qt4...") + FIND_PACKAGE(Qt4 4.8 REQUIRED) + IF(QT4_FOUND) + ELSE(QT4_FOUND) + MESSAGE(FATAL_ERROR "QT4 not found") + ENDIF(QT4_FOUND) +ENDIF (Qt5_FOUND) # # QT include files # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Try to find Qwt, utherwise use bundle diff --git a/src/Cifti/CMakeLists.txt b/src/Cifti/CMakeLists.txt index bfe3e8d33..cedfb2943 100644 --- a/src/Cifti/CMakeLists.txt +++ b/src/Cifti/CMakeLists.txt @@ -13,7 +13,9 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create GIFTI Library diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index 46fa50413..abe5b2ca5 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -16,7 +16,9 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Name of executable @@ -26,7 +28,13 @@ set (EXE_NAME wb_command) # # Resources # -QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/General/general_resources.qrc) +======= +SET (RESOURCES_QRC_FILE ../Resources/General/general_resources.qrc) +IF (Qt5_FOUND) + QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) +ELSE (Qt5_FOUND) + QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) +ENDIF (Qt5_FOUND) # # Create the executable diff --git a/src/Commands/CMakeLists.txt b/src/Commands/CMakeLists.txt index caf6e2301..859043c9a 100644 --- a/src/Commands/CMakeLists.txt +++ b/src/Commands/CMakeLists.txt @@ -11,7 +11,10 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () + # # Create the brain library diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 69f68f997..0caf32a8e 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -12,7 +12,9 @@ SET(QT_USE_QTXML TRUE) SET(QT_DONT_USE_QTGUI TRUE) SET(QT_USE_QTNETWORK TRUE) -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () #message("QT VERSION: " ${QT_VERSION_MAJOR} ${QT_VERSION_MINOR} ${QT_VERSION_PATCH}) SET (CMAKE_AUTOMOC ON) diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index a9f2fc278..8d713d48f 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -19,7 +19,10 @@ SET(QT_USE_QTNETWORK TRUE) # # QT Include directories # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () + # # Added by JWH to eliminate OpenGL linking errors in Ubuntu Linux @@ -33,7 +36,15 @@ ENDIF (UNIX) # # Resources # -QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ../Resources/General/general_resources.qrc ../Resources/Gui/gui_resources.qrc ../Resources/Help/help_resources.qrc) +SET (RESOURCES_QRC_FILE + ../Resources/General/general_resources.qrc + ../Resources/Gui/gui_resources.qrc + ../Resources/Help/help_resources.qrc) +IF (Qt5_FOUND) + QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) +ELSE (Qt5_FOUND) + QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) +ENDIF (Qt5_FOUND) # # Create the executable diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 60f36ee79..1dfea004b 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -12,7 +12,9 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Files Library diff --git a/src/FilesBase/CMakeLists.txt b/src/FilesBase/CMakeLists.txt index 4c6e06e91..51f2afb11 100644 --- a/src/FilesBase/CMakeLists.txt +++ b/src/FilesBase/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # diff --git a/src/FtglFont/CMakeLists.txt b/src/FtglFont/CMakeLists.txt index db5489251..48cd6dd0b 100644 --- a/src/FtglFont/CMakeLists.txt +++ b/src/FtglFont/CMakeLists.txt @@ -16,7 +16,10 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () + # # Need OpenGL diff --git a/src/Gifti/CMakeLists.txt b/src/Gifti/CMakeLists.txt index df85db095..c823c4f3a 100644 --- a/src/Gifti/CMakeLists.txt +++ b/src/Gifti/CMakeLists.txt @@ -12,7 +12,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create GIFTI Library diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index fec9ddeb4..38277754d 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -14,7 +14,9 @@ SET(QT_USE_QTOPENGL TRUE) # # QT include files # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Let CMake find files for moc and uic. diff --git a/src/Nifti/CMakeLists.txt b/src/Nifti/CMakeLists.txt index 198fda58f..d85e6daa0 100644 --- a/src/Nifti/CMakeLists.txt +++ b/src/Nifti/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # diff --git a/src/OSMesaDummy/CMakeLists.txt b/src/OSMesaDummy/CMakeLists.txt index 79438232b..65c7b4be7 100644 --- a/src/OSMesaDummy/CMakeLists.txt +++ b/src/OSMesaDummy/CMakeLists.txt @@ -7,7 +7,9 @@ PROJECT(OSMesaDummy) # # Need Qt for reading from resource file. # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create a library diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index 4cbebb8b0..b5d5491ec 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create the helper library diff --git a/src/OperationsBase/CMakeLists.txt b/src/OperationsBase/CMakeLists.txt index 4b8325228..aa51abfe4 100644 --- a/src/OperationsBase/CMakeLists.txt +++ b/src/OperationsBase/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create the helper library diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index c36de8162..abe44f402 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -11,7 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index 08e34caa4..319ea1014 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -8,7 +8,9 @@ PROJECT(Quazip) # SET(QT_DONT_USE_QTGUI TRUE) -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () SET(CMAKE_AUTOMOC ON) diff --git a/src/Qwt/CMakeLists.txt b/src/Qwt/CMakeLists.txt index c40c075d1..594705b8f 100644 --- a/src/Qwt/CMakeLists.txt +++ b/src/Qwt/CMakeLists.txt @@ -15,7 +15,9 @@ PROJECT (Qwt) # # QT include files # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () add_definitions(-DQWT_NO_SVG -DQWT_NO_OPENGL) diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index 7708f3fe5..b4cdca416 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -22,7 +22,9 @@ SET(QT_DONT_USE_QTGUI TRUE) # # QT include files # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create a Library diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index 6815a8f44..15d821de5 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -13,7 +13,9 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # -INCLUDE (${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # #The individual tests diff --git a/src/Xml/CMakeLists.txt b/src/Xml/CMakeLists.txt index 325f413c4..7e3dc7c86 100644 --- a/src/Xml/CMakeLists.txt +++ b/src/Xml/CMakeLists.txt @@ -13,7 +13,9 @@ SET(QT_USE_QTNETWORK TRUE) # # QT include files # -INCLUDE(${QT_USE_FILE}) +IF (QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF () # # Create a Library -- GitLab From 22cf8e8200571c6a86b0e7e3de849b5753ecb8ff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Sep 2016 10:16:49 -0500 Subject: [PATCH 010/755] QString::toAscii() is removed in Qt5 and has been replaced with String::toLatin1() as described in http://wiki.qt.io/Transition_from_Qt_4.x_to_Qt5. --- src/Common/AString.cxx | 2 +- src/Common/AString.h | 2 +- src/Common/CaretHttpManager.cxx | 4 ++-- src/Files/AnnotationFileXmlReader.cxx | 2 +- src/Files/ImageFile.cxx | 6 +++--- src/Files/StudyMetaDataLink.cxx | 2 +- src/Gifti/GiftiDataArray.cxx | 2 +- src/Gifti/GiftiFile.cxx | 2 +- src/GuiQt/AnnotationCoordinateSelectionWidget.cxx | 2 +- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 4 ++-- src/GuiQt/MovieDialog.cxx | 2 +- src/Operations/OperationProbtrackXDotConvert.cxx | 4 ++-- src/Operations/OperationVolumeCreate.cxx | 2 +- src/Operations/OperationVolumeReorient.cxx | 2 +- src/Operations/OperationVolumeSetSpace.cxx | 2 +- src/Scenes/SceneInfo.cxx | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Common/AString.cxx b/src/Common/AString.cxx index e993255b0..c28ea0dbf 100644 --- a/src/Common/AString.cxx +++ b/src/Common/AString.cxx @@ -714,7 +714,7 @@ AString::replaceHtmlSpecialCharactersWithEscapeCharacters() const const int64_t length = this->count(); for (int64_t i = 0; i < length; i++) { const QChar ch = this->at(i); - switch (ch.toAscii()) { + switch (ch.toLatin1()) { case '&': htmlString.append("&"); break; diff --git a/src/Common/AString.h b/src/Common/AString.h index 667259ea2..2b532fb33 100644 --- a/src/Common/AString.h +++ b/src/Common/AString.h @@ -56,7 +56,7 @@ namespace caret { operator std::string () {return this->toStdString(); } //char * compatibility - operator const char* () {return this->toAscii(); } + operator const char* () {return this->toLatin1(); } //double compatiblity operator double () {return this->toDouble(); } diff --git a/src/Common/CaretHttpManager.cxx b/src/Common/CaretHttpManager.cxx index eca485db2..568967b3a 100644 --- a/src/Common/CaretHttpManager.cxx +++ b/src/Common/CaretHttpManager.cxx @@ -258,7 +258,7 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret for (std::map::const_iterator headerIter = request.m_headers.begin(); headerIter != request.m_headers.end(); headerIter++) { - myRequest.setRawHeader(headerIter->first.toAscii(), headerIter->second.toAscii()); + myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); } myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postData); @@ -273,7 +273,7 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret for (std::map::const_iterator headerIter = request.m_headers.begin(); headerIter != request.m_headers.end(); headerIter++) { - myRequest.setRawHeader(headerIter->first.toAscii(), headerIter->second.toAscii()); + myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); // std::cout << "POST FILE header: " << qPrintable(headerIter->first) // << ": " << qPrintable(headerIter->second) << std::endl; } diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index 6f0a8fb7e..85ed0ed65 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -836,7 +836,7 @@ AnnotationFileXmlReader::readImageDataElement(AnnotationImage* imageAnnotation) + m_stream->errorString()); } - QByteArray imageBytes = QByteArray::fromBase64(imageChars.toAscii()); + QByteArray imageBytes = QByteArray::fromBase64(imageChars.toLatin1()); if (imageBytes.size() == numberOfBytes) { const uint8_t* imageBytesPointer = (const uint8_t*)(imageBytes.data()); imageAnnotation->setImageBytesRGBA(imageBytesPointer, diff --git a/src/Files/ImageFile.cxx b/src/Files/ImageFile.cxx index 23e117302..442e1db04 100644 --- a/src/Files/ImageFile.cxx +++ b/src/Files/ImageFile.cxx @@ -879,7 +879,7 @@ ImageFile::writeFile(const AString& filename) format = "JPEG"; } - QImageWriter writer(filename, format.toAscii()); + QImageWriter writer(filename, format.toLatin1()); if (writer.supportsOption(QImageIOHandler::Quality)) { if (format.compare("png", Qt::CaseInsensitive) == 0) { const int quality = 1; @@ -1377,7 +1377,7 @@ ImageFile::getImageInByteArray(QByteArray& byteArrayOut, } else { successFlag = m_image->save(&buffer, - format.toAscii().data()); + format.toLatin1().data()); } if ( ! successFlag) { @@ -1406,7 +1406,7 @@ ImageFile::setImageFromByteArray(const QByteArray& byteArray, } else { successFlag = m_image->loadFromData(byteArray, - format.toAscii().data()); + format.toLatin1().data()); } if ( ! successFlag) { diff --git a/src/Files/StudyMetaDataLink.cxx b/src/Files/StudyMetaDataLink.cxx index 39c124561..a310da9d8 100644 --- a/src/Files/StudyMetaDataLink.cxx +++ b/src/Files/StudyMetaDataLink.cxx @@ -325,7 +325,7 @@ StudyMetaDataLink::setLinkFromCodedText(const AString& txt) } else { std::cout << "Unrecognized StudyMetaDataLink key: " - << key.toAscii().constData() << std::endl; + << key.toLatin1().constData() << std::endl; } } } diff --git a/src/Gifti/GiftiDataArray.cxx b/src/Gifti/GiftiDataArray.cxx index 067654d98..d5fb7b1b9 100644 --- a/src/Gifti/GiftiDataArray.cxx +++ b/src/Gifti/GiftiDataArray.cxx @@ -681,7 +681,7 @@ GiftiDataArray::readFromText(const AString text, // Decode the Base64 data using VTK's algorithm // unsigned char* dataBuffer = new unsigned char[data.size()]; - //const char* textChars = text.toAscii().constData(); + //const char* textChars = text.toLatin1().constData(); const uint64_t numDecoded = Base64::decode((unsigned char*)text.toStdString().c_str(), data.size(), diff --git a/src/Gifti/GiftiFile.cxx b/src/Gifti/GiftiFile.cxx index 7a4e281f3..cb336cea9 100644 --- a/src/Gifti/GiftiFile.cxx +++ b/src/Gifti/GiftiFile.cxx @@ -994,7 +994,7 @@ GiftiFile::writeFile(const AString& filename) std::ofstream* externalBinaryOutputStream = NULL; if (encoding == GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY) { externalBinaryFileName = getFileNameNoPath() + ".data"; - externalBinaryOutputStream = new std::ofstream(externalBinaryFileName.toAscii().constData(), + externalBinaryOutputStream = new std::ofstream(externalBinaryFileName.toLatin1().constData(), std::ofstream::binary); if (externalBinaryOutputStream == NULL) { throw GiftiException("Unable to open " + externalBinaryFileName + " for output."); diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index da47d05b4..c397fcf01 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -381,7 +381,7 @@ AnnotationCoordinateSelectionWidget::createRadioButtonForSpace(const AnnotationC const QString spaceGuiName = AnnotationCoordinateSpaceEnum::toGuiName(space); const QString spaceEnumName = AnnotationCoordinateSpaceEnum::toName(space); QRadioButton* rb = new QRadioButton(spaceGuiName); - rb->setProperty(s_SPACE_PROPERTY_NAME.toAscii().constData(), + rb->setProperty(s_SPACE_PROPERTY_NAME.toLatin1().constData(), spaceEnumName); return rb; diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 6021778e0..53281bb58 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -2391,7 +2391,7 @@ MapSettingsPaletteColorMappingWidget::applyToMultipleFilesPushbuttonClicked() CaretMappableDataFile* cmdf = *iter; if (cmdf->isMappedWithPalette()) { QCheckBox* cb = ded.addCheckBox(cmdf->getFileNameNoPath()); - cb->setProperty(filePointerPropertyName.toAscii().constData(), + cb->setProperty(filePointerPropertyName.toLatin1().constData(), qVariantFromValue((void*)cmdf)); mapFileCheckBoxes.push_back(cb); @@ -2411,7 +2411,7 @@ MapSettingsPaletteColorMappingWidget::applyToMultipleFilesPushbuttonClicked() iter++) { QCheckBox* cb = *iter; if (cb->isChecked()) { - void* pointer = cb->property(filePointerPropertyName.toAscii().constData()).value(); + void* pointer = cb->property(filePointerPropertyName.toLatin1().constData()).value(); CaretMappableDataFile* cmdf = (CaretMappableDataFile*)pointer; const int32_t numMaps = cmdf->getNumberOfMaps(); diff --git a/src/GuiQt/MovieDialog.cxx b/src/GuiQt/MovieDialog.cxx index f3fe30390..2353a861f 100644 --- a/src/GuiQt/MovieDialog.cxx +++ b/src/GuiQt/MovieDialog.cxx @@ -252,7 +252,7 @@ void MovieDialog::on_recordButton_toggled(bool checked) + fileName); CaretLogFine("running " + command); - system(command.toAscii().data()); + system(command.toLatin1().data()); CaretLogFine("Finished rendering " + fileName); } diff --git a/src/Operations/OperationProbtrackXDotConvert.cxx b/src/Operations/OperationProbtrackXDotConvert.cxx index e8121695b..0be7d8534 100644 --- a/src/Operations/OperationProbtrackXDotConvert.cxx +++ b/src/Operations/OperationProbtrackXDotConvert.cxx @@ -181,7 +181,7 @@ void OperationProbtrackXDotConvert::useParameters(OperationParameters* myParams, } myXML.copyMapping(CiftiXMLOld::ALONG_COLUMN, colCiftiOpt->getCifti(1)->getCiftiXMLOld(), myDir); } - fstream dotFile(dotFileName.toAscii().constData(), fstream::in); + fstream dotFile(dotFileName.toLatin1().constData(), fstream::in); if (!dotFile.good()) { throw OperationException("error opening text file '" + dotFileName + "'"); @@ -410,7 +410,7 @@ void OperationProbtrackXDotConvert::addVoxelMapping(const VolumeFile* myLabelVol voxelLists.resize(count); inputIndices.resize(count); voxelIndexType vi, vj, vk; - fstream myTextFile(textFileName.toAscii().constData(), fstream::in); + fstream myTextFile(textFileName.toLatin1().constData(), fstream::in); if (!myTextFile.good()) { throw OperationException("error opening text file '" + textFileName + "'"); diff --git a/src/Operations/OperationVolumeCreate.cxx b/src/Operations/OperationVolumeCreate.cxx index 735371f31..9e7039950 100644 --- a/src/Operations/OperationVolumeCreate.cxx +++ b/src/Operations/OperationVolumeCreate.cxx @@ -98,7 +98,7 @@ void OperationVolumeCreate::useParameters(OperationParameters* myParams, Progres for (int i = 0; i < 3; ++i) { int dir = -1; - switch (orient[i].toAscii()) + switch (orient[i].toLatin1()) { case 'X': case 'x': diff --git a/src/Operations/OperationVolumeReorient.cxx b/src/Operations/OperationVolumeReorient.cxx index e3bfcbbee..4c55ea999 100644 --- a/src/Operations/OperationVolumeReorient.cxx +++ b/src/Operations/OperationVolumeReorient.cxx @@ -63,7 +63,7 @@ void OperationVolumeReorient::useParameters(OperationParameters* myParams, Progr VolumeSpace::OrientTypes orient[3]; for (int i = 0; i < 3; ++i) { - char id = orientString[i].toAscii(); + char id = orientString[i].toLatin1(); switch (id) { case 'L': diff --git a/src/Operations/OperationVolumeSetSpace.cxx b/src/Operations/OperationVolumeSetSpace.cxx index 3fe300d9c..1edf3ed11 100644 --- a/src/Operations/OperationVolumeSetSpace.cxx +++ b/src/Operations/OperationVolumeSetSpace.cxx @@ -91,7 +91,7 @@ void OperationVolumeSetSpace::useParameters(OperationParameters* myParams, Progr for (int i = 0; i < 3; ++i) { int dir = -1; - switch (orient[i].toAscii()) + switch (orient[i].toLatin1()) { case 'X': case 'x': diff --git a/src/Scenes/SceneInfo.cxx b/src/Scenes/SceneInfo.cxx index 24ec7a23a..a55619377 100644 --- a/src/Scenes/SceneInfo.cxx +++ b/src/Scenes/SceneInfo.cxx @@ -270,7 +270,7 @@ SceneInfo::setImageFromText(const AString& text, if ( ! text.isEmpty()) { if (encoding == SceneXmlElements::SCENE_INFO_ENCODING_BASE64_NAME) { - m_imageBytes = QByteArray::fromBase64(text.toAscii()); + m_imageBytes = QByteArray::fromBase64(text.toLatin1()); m_imageFormat = imageFormat; } else { -- GitLab From 8e3af92d9528a3d3fbeb045dbc93fc355b628176 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Sep 2016 16:48:35 -0500 Subject: [PATCH 011/755] Adding support to compile with Qt5: Now able to to configure and build with either Qt4 or Qt5. However, when trying to run with Qt5 there are some message and it aborts. --- src/Algorithms/CMakeLists.txt | 3 + src/Annotations/CMakeLists.txt | 6 ++ src/Brain/CMakeLists.txt | 5 + src/CMakeLists.txt | 22 +++-- src/Charting/CMakeLists.txt | 7 ++ src/Cifti/CMakeLists.txt | 4 + src/CommandLine/CMakeLists.txt | 18 ++++ src/CommandLine/wb_command.cxx | 2 +- src/Commands/CMakeLists.txt | 3 + src/Common/CMakeLists.txt | 5 + src/Common/CaretHttpManager.cxx | 35 +++++++ src/Desktop/CMakeLists.txt | 20 ++++ src/Desktop/desktop.cxx | 122 +++++++++++++++++++++++- src/Files/AnnotationFileXmlWriter.cxx | 4 +- src/Files/CMakeLists.txt | 5 + src/FilesBase/CMakeLists.txt | 3 + src/Gifti/CMakeLists.txt | 3 + src/GuiQt/BrainBrowserWindow.cxx | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 12 +++ src/GuiQt/CMakeLists.txt | 6 ++ src/GuiQt/CaretFileDialog.cxx | 18 ++-- src/GuiQt/CaretFileDialogExtendable.h | 6 +- src/GuiQt/HelpViewerDialog.cxx | 9 +- src/GuiQt/WuQDialog.cxx | 2 +- src/GuiQt/WuQtUtilities.cxx | 56 +++++------ src/GuiQt/WuQtUtilities.h | 2 +- src/Nifti/CMakeLists.txt | 3 + src/Operations/CMakeLists.txt | 4 + src/OperationsBase/CMakeLists.txt | 4 + src/Palette/CMakeLists.txt | 3 + src/Quazip/CMakeLists.txt | 3 + src/Qwt/CMakeLists.txt | 5 + src/Qwt/qwt_plot_renderer.cpp | 5 + src/Scenes/CMakeLists.txt | 5 + src/Scenes/SceneInfo.cxx | 2 +- src/Tests/CMakeLists.txt | 18 ++++ src/Tests/test_driver.cxx | 2 +- src/Xml/CMakeLists.txt | 5 + 38 files changed, 376 insertions(+), 63 deletions(-) diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index 51e36a548..75503cb5b 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -11,6 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 03d7f03b6..915c329e3 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -11,6 +11,12 @@ SET(QT_DONT_USE_QTGUI TRUE) # # QT include files # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + #include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Xml_INCLUDE_DIRS}) +endif() + ###INCLUDE(${QT_USE_FILE}) # diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 702f9ef12..39dd58307 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -21,6 +21,11 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Gui_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82cc88d97..a649d8a48 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -231,17 +231,27 @@ ENDIF(OPENSSL_FOUND) # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # -###FIND_PACKAGE(Qt5 5.6.0 CONFIG Gui Network Test Widgets Xml) -FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Core Gui Network Test Widgets Xml) +FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network OpenGL PrintSupport Test Widgets Xml) IF (Qt5_FOUND) MESSAGE("Found Qt 5") - ##SET(moduleError "") + IF (NOT Qt5Concurrent_FOUND) + STRING(APPEND moduleError "Qt5 Concurrentmodule not found\n") + ENDIF() + IF (NOT Qt5Core_FOUND) + STRING(APPEND moduleError "Qt5 Core module not found\n") + ENDIF() IF (NOT Qt5Gui_FOUND) STRING(APPEND moduleError "Qt5 Gui module not found\n") ENDIF() IF (NOT Qt5Network_FOUND) STRING(APPEND moduleError "Qt5 Network module not found\n") ENDIF() + IF (NOT Qt5OpenGL_FOUND) + STRING(APPEND moduleError "Qt5 OpenGL module not found\n") + ENDIF() + IF (NOT Qt5PrintSupport_FOUND) + STRING(APPEND moduleError "Qt5 Print Support module not found\n") + ENDIF() IF (NOT Qt5Test_FOUND) STRING(APPEND moduleError "Qt5 Test module not found\n") ENDIF() @@ -251,12 +261,6 @@ IF (Qt5_FOUND) IF (NOT Qt5Xml_FOUND) STRING(APPEND moduleError "Qt5 XML module not found\n") ENDIF() - IF (NOT Qt5Core_FOUND) - STRING(APPEND moduleError "Qt5 Core module not found\n") - ENDIF() -# IF (NOT Qt5Crap_FOUND) -# STRING(APPEND moduleError "Qt5 Crap module not found\n") -# ENDIF() IF (moduleError) MESSAGE(FATAL_ERROR "Missing Modules\n" ${moduleError}) ENDIF() diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 253393b35..3dd200215 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -4,6 +4,13 @@ # PROJECT(Charting) +# +# Qt include files +# +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() + # # Create a library # diff --git a/src/Cifti/CMakeLists.txt b/src/Cifti/CMakeLists.txt index cedfb2943..612ffc24c 100644 --- a/src/Cifti/CMakeLists.txt +++ b/src/Cifti/CMakeLists.txt @@ -13,6 +13,10 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index abe5b2ca5..b4eb0e975 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -16,6 +16,10 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +# include_directories(${Qt5Network_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () @@ -54,6 +58,19 @@ ELSE (APPLE) ENDIF (APPLE) +if(Qt5_FOUND) + set(QT5_LINK_LIBS + Qt5::Concurrent + Qt5::Core + Qt5::Gui + Qt5::Network +# Qt5::OpenGL +# Qt5::PrintSupport + Qt5::Test +# Qt5::Widgets + Qt5::Xml) +endif() + # # Libraries that are linked # Note: OSMESA library variables will be empty and have no effect @@ -80,6 +97,7 @@ Common ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} +${QT5_LINK_LIBS} ${OSMESA_OFFSCREEN_LIBRARY} ${OSMESA_GL_LIBRARY} ${OSMESA_GLU_LIBRARY} diff --git a/src/CommandLine/wb_command.cxx b/src/CommandLine/wb_command.cxx index 8a1864c94..9e618ffa7 100644 --- a/src/CommandLine/wb_command.cxx +++ b/src/CommandLine/wb_command.cxx @@ -18,7 +18,7 @@ */ /*LICENSE_END*/ -#include +//#include #include #include diff --git a/src/Commands/CMakeLists.txt b/src/Commands/CMakeLists.txt index 859043c9a..484b37e1f 100644 --- a/src/Commands/CMakeLists.txt +++ b/src/Commands/CMakeLists.txt @@ -11,6 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 0caf32a8e..d22bbda75 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -12,6 +12,11 @@ SET(QT_USE_QTXML TRUE) SET(QT_DONT_USE_QTGUI TRUE) SET(QT_USE_QTNETWORK TRUE) +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Xml_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Common/CaretHttpManager.cxx b/src/Common/CaretHttpManager.cxx index 568967b3a..494028235 100644 --- a/src/Common/CaretHttpManager.cxx +++ b/src/Common/CaretHttpManager.cxx @@ -24,6 +24,9 @@ #include "CaretLogger.h" #include "NetworkException.h" #include +#if QT_VERSION >= 0x050000 +#include +#endif // QT_VERSION using namespace caret; using namespace std; @@ -229,11 +232,23 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret CaretLogInfo("NO AUTH FOUND for URL " + request.m_url); } QNetworkReply* myReply = NULL; +/* + * QUrl::addQueryItem() deprecated in Qt5: http://wiki.qt.io/Transition_from_Qt_4.x_to_Qt5 + */ +#if QT_VERSION >= 0x050000 + QUrl myUrl; + QUrlQuery myUrlQuery(QUrl::fromUserInput(request.m_url)); + for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) + { + myUrlQuery.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); + } +#else // QT_VERSION QUrl myUrl = QUrl::fromUserInput(request.m_url); for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) { myUrl.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); } +#endif // QT_VERSION QNetworkAccessManager* myQNetMgr = &(myCaretMgr->m_netMgr); bool first = true; QByteArray postData; @@ -260,6 +275,9 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret headerIter++) { myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); } +#if QT_VERSION >= 0x050000 + myUrl.setQuery(myUrlQuery); +#endif // QT_VERSION myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postData); CaretLogInfo("POST ARGUMENTS URL: " + myUrl.toString()); @@ -277,6 +295,9 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret // std::cout << "POST FILE header: " << qPrintable(headerIter->first) // << ": " << qPrintable(headerIter->second) << std::endl; } +#if QT_VERSION >= 0x050000 + myUrl.setQuery(myUrlQuery); +#endif // QT_VERSION myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postUploadFile); CaretLogInfo("POST FILE URL: " + myUrl.toString()); @@ -289,8 +310,15 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret case GET: for (int32_t i = 0; i < (int32_t)request.m_arguments.size(); ++i) { +#if QT_VERSION >= 0x050000 + myUrlQuery.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); +#else // QT_VERSION myUrl.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); +#endif // QT_VERSION } +#if QT_VERSION >= 0x050000 + myUrl.setQuery(myUrlQuery); +#endif // QT_VERSION myRequest.setUrl(myUrl); CaretLogInfo("GET URL: " + myUrl.toString()); myReply = myQNetMgr->get(myRequest); @@ -298,8 +326,15 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret case HEAD: for (int32_t i = 0; i < (int32_t)request.m_arguments.size(); ++i) { +#if QT_VERSION >= 0x050000 + myUrlQuery.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); +#else // QT_VERSION myUrl.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); +#endif // QT_VERSION } +#if QT_VERSION >= 0x050000 + myUrl.setQuery(myUrlQuery); +#endif // QT_VERSION myRequest.setUrl(myUrl); CaretLogInfo("HEAD URL: " + myUrl.toString()); myReply = myQNetMgr->head(myRequest); diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 8d713d48f..2c97433f4 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -19,6 +19,12 @@ SET(QT_USE_QTNETWORK TRUE) # # QT Include directories # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5OpenGL_INCLUDE_DIRS}) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () @@ -92,6 +98,19 @@ IF (NOT APPLE) ENDIF (UNIX) ENDIF (NOT APPLE) +if(Qt5_FOUND) + set(QT5_LINK_LIBS + Qt5::Concurrent + Qt5::Core + Qt5::Gui + Qt5::Network + Qt5::OpenGL + Qt5::PrintSupport + Qt5::Test + Qt5::Widgets + Qt5::Xml) +endif() + # # Libraries that are linked # @@ -119,6 +138,7 @@ Common ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} +${QT5_LINK_LIBS} ${ZLIB_LIBRARIES} #${LIBS} ) diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index c8a185acf..5b753055c 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -57,11 +57,119 @@ static bool caretLoggerIsValid = false; using namespace caret; using namespace std; +#if QT_VERSION >= 0x050000 /** - * Handles message produced by Qt. + * Handles message produced by Qt 5 */ static void -messageHandlerForQt(QtMsgType type, const char* msg) +messageHandlerForQt5(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + const AString backtrace = SystemUtilities::getBackTrace(); + + const AString contextInfo = (" Context Info File (" + + QString(context.file) + + ") Function (" + QString(context.function) + + ") Line (" + QString::number(context.line) + + ") Version (" + QString::number(context.version) + + ") Category (" + QString(context.category) + + ")"); + const AString message = (AString(msg) + "\n" + + contextInfo + "\n" + + backtrace); + + if (caretLoggerIsValid) { + bool abortFlag = false; + bool displayedFlag = false; + switch (type) { + case QtDebugMsg: + CaretLogInfo(message); + displayedFlag = CaretLogger::getLogger()->isInfo(); + break; + case QtWarningMsg: + CaretLogWarning(message); + displayedFlag = CaretLogger::getLogger()->isWarning(); + break; + case QtCriticalMsg: + CaretLogSevere(message); + displayedFlag = CaretLogger::getLogger()->isSevere(); + break; + case QtFatalMsg: + cerr << "Qt Fatal: " << message << endl; + abortFlag = true;//fatal will cause an abort, so always display it, bypassing logger entirely + displayedFlag = true; + break; + case QtInfoMsg: + CaretLogInfo(message); + displayedFlag = CaretLogger::getLogger()->isInfo(); + break; + } + + /* + * Beep to alert user about an error!!! + */ + if (displayedFlag && (type != QtDebugMsg))//don't beep for debug + { + GuiManager::beep(); + } +#ifndef NDEBUG + if (!displayedFlag) + { + cerr << "DEBUG: Qt "; + switch (type) + { + case QtDebugMsg: + cerr << "Debug "; + break; + case QtWarningMsg: + cerr << "Warning "; + break; + case QtCriticalMsg: + cerr << "Critical "; + break; + case QtFatalMsg: + cerr << "FATAL (?!?) ";//should never happen + break; + case QtInfoMsg: + std::cerr << "Info "; + break; + } + cerr << "message hidden" << endl; + } +#endif + + if (abortFlag) { + std::abort(); + } + } + else { + switch (type) { + case QtDebugMsg: + std::cerr << "Qt Debug: " << message << std::endl; + break; + case QtWarningMsg: + std::cerr << "Qt Warning: " << message << std::endl; + break; + case QtCriticalMsg: + std::cerr << "Qt Critical: " << message << std::endl; + break; + case QtFatalMsg: + std::cerr << "Qt Fatal: " << message << std::endl; + std::abort(); + break; + case QtInfoMsg: + std::cerr << "Qt Info: " << message << std::endl; + break; + } + } +} + +#else // QT_VERSION + +/** + * Handles message produced by Qt 4. + */ +static void +messageHandlerForQt4(QtMsgType type, const char* msg) { const AString backtrace = SystemUtilities::getBackTrace(); @@ -143,6 +251,8 @@ messageHandlerForQt(QtMsgType type, const char* msg) } } +#endif // QT_VERSION + //struct for communicating stuff back to main from parseCommandLine struct ProgramState { @@ -284,7 +394,7 @@ main(int argc, char* argv[]) //change the default graphics system on mac to avoid rendering performance issues with qwtplotter #ifdef CARET_OS_MACOSX - QApplication::setGraphicsSystem("raster"); + // Qt-Deprecated: QApplication::setGraphicsSystem("raster"); MacApplication app(argc, argv); #else //CARET_OS_MACOSX QApplication app(argc, argv); @@ -325,7 +435,11 @@ main(int argc, char* argv[]) */ BrainOpenGLWidget::initializeDefaultGLFormat(); - qInstallMsgHandler(messageHandlerForQt);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created +#if QT_VERSION >= 0x050000 + qInstallMessageHandler(messageHandlerForQt5);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created +#else // QT_VERSION + qInstallMsgHandler(messageHandlerForQt4);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created +#endif // QT_VERSION /* * Log debug status */ diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index 74097ee55..48e8b1dfb 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -317,8 +317,8 @@ AnnotationFileXmlWriter::writeImage(const AnnotationImage* image) QByteArray byteArray((const char*)imageBytesRGBA, numberOfBytes); QByteArray byteArrayBase64(byteArray.toBase64()); - const QString stringBase64(QString::fromAscii(byteArrayBase64.constData(), - byteArrayBase64.size())); + const QString stringBase64(QString::fromLatin1(byteArrayBase64.constData(), + byteArrayBase64.size())); QXmlStreamAttributes attributes; getTwoDimAnnotationPropertiesAsAttributes(image, diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 1dfea004b..0ec643394 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -12,6 +12,11 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Gui_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/FilesBase/CMakeLists.txt b/src/FilesBase/CMakeLists.txt index 51f2afb11..19809c965 100644 --- a/src/FilesBase/CMakeLists.txt +++ b/src/FilesBase/CMakeLists.txt @@ -11,6 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Gifti/CMakeLists.txt b/src/Gifti/CMakeLists.txt index c823c4f3a..4c6d1f85a 100644 --- a/src/Gifti/CMakeLists.txt +++ b/src/Gifti/CMakeLists.txt @@ -12,6 +12,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 0bdbbe3c1..535744a09 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -2709,7 +2709,7 @@ BrainBrowserWindow::processDevelopExportVtkFile() "Export to VTK File", GuiManager::get()->getBrain()->getCurrentDirectory(), vtkSurfaceFileFilter); - cfd.selectFilter(vtkSurfaceFileFilter); + cfd.selectNameFilter(vtkSurfaceFileFilter); cfd.setAcceptMode(QFileDialog::AcceptSave); cfd.setFileMode(CaretFileDialog::AnyFile); if (previousVtkFileName.isEmpty() == false) { diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index c630757c6..49c94f65f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -28,7 +28,10 @@ #include #include #include +#if QT_VERSION >= 0x050000 +#else // QT_VERSION #include +#endif // QT_VERSION #include #include #include @@ -40,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -196,9 +200,17 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow * The style must remain valid until the destruction * of this instance. It cannot be declared statically. */ +#if QT_VERSION >= 0x050000 + QStyle* cleanLooksStyle = QStyleFactory::create("Cleanlooks"); + if (cleanLooksStyle != NULL) { + cleanLooksStyle->setParent(this); + this->tabBar->setStyle(cleanLooksStyle); + } +#else // QT_VERSION QCleanlooksStyle* cleanLooksStyle = new QCleanlooksStyle(); cleanLooksStyle->setParent(this); this->tabBar->setStyle(cleanLooksStyle); +#endif // QT_VERSION #endif // Q_OS_MACX QObject::connect(this->tabBar, SIGNAL(currentChanged(int)), this, SLOT(selectedTabChanged(int))); diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 38277754d..3199f8181 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -14,6 +14,12 @@ SET(QT_USE_QTOPENGL TRUE) # # QT include files # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5OpenGL_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/GuiQt/CaretFileDialog.cxx b/src/GuiQt/CaretFileDialog.cxx index 8b0d175bd..fb74a7032 100644 --- a/src/GuiQt/CaretFileDialog.cxx +++ b/src/GuiQt/CaretFileDialog.cxx @@ -179,7 +179,7 @@ void CaretFileDialog::setVisible(bool visible) { if (visible) { - fileFilterWasChanged(selectedFilter()); + fileFilterWasChanged(selectedNameFilter()); } QFileDialog::setVisible(visible); @@ -239,7 +239,7 @@ CaretFileDialog::getOpenFileNameDialog(QWidget *parent, dir, filter); if (selectedFilter != 0) { - cfd.selectFilter(*selectedFilter); + cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); @@ -288,7 +288,7 @@ CaretFileDialog::getSaveFileNameDialog(QWidget *parent, dir, filter); if (selectedFilter != 0) { - cfd.selectFilter(*selectedFilter); + cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(QFileDialog::AcceptSave); @@ -338,7 +338,7 @@ CaretFileDialog::getSaveFileNameDialog(const DataFileTypeEnum::Enum dataFileType caption, dir, DataFileTypeEnum::toQFileDialogFilter(dataFileType)); - cfd.selectFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + cfd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); cfd.setOptions(options); cfd.setAcceptMode(QFileDialog::AcceptSave); cfd.setFileMode(CaretFileDialog::AnyFile); @@ -387,8 +387,8 @@ CaretFileDialog::getChooseFileNameDialog(const DataFileTypeEnum::Enum dataFileTy QWidget *parent) { CaretFileDialog fd(parent); - fd.setFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); - fd.selectFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + //fd.setFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + fd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); fd.setAcceptMode(CaretFileDialog::AcceptSave); fd.setFileMode(CaretFileDialog::AnyFile); fd.setViewMode(CaretFileDialog::List); @@ -497,7 +497,7 @@ CaretFileDialog::getOpenFileNamesDialog(QWidget *parent, dir, filter); if (selectedFilter != 0) { - cfd.selectFilter(*selectedFilter); + cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); @@ -559,12 +559,12 @@ CaretFileDialog::restoreDialogSettings(const AString& settingsName) setDirectory(previousSettings.m_directoryName); } - QStringList dialogFilters = filters(); + QStringList dialogFilters = nameFilters(); QStringListIterator filterIter(dialogFilters); while (filterIter.hasNext()) { const AString filterName = filterIter.next(); if (filterName == previousSettings.m_fileFilterName) { - selectFilter(previousSettings.m_fileFilterName); + selectNameFilter(previousSettings.m_fileFilterName); break; } } diff --git a/src/GuiQt/CaretFileDialogExtendable.h b/src/GuiQt/CaretFileDialogExtendable.h index 704bd67a6..e7dee837b 100644 --- a/src/GuiQt/CaretFileDialogExtendable.h +++ b/src/GuiQt/CaretFileDialogExtendable.h @@ -78,7 +78,7 @@ namespace caret { QFileDialog::FileMode fileMode() const { return m_caretFileDialog->fileMode(); } - QStringList filters() const { return m_caretFileDialog->filters(); } + QStringList filters() const { return m_caretFileDialog->nameFilters(); } QStringList history() const { return m_caretFileDialog->history(); } @@ -92,7 +92,7 @@ namespace caret { QStringList nameFilters() const { return m_caretFileDialog->nameFilters(); } - void open(QObject* receiver, const char* member) { m_caretFileDialog->open(receiver, member); } + //void open(QObject* receiver, const char* member) { m_caretFileDialog->open(receiver, member); } QFileDialog::Options options() const { return m_caretFileDialog->options(); } @@ -124,7 +124,7 @@ namespace caret { void setFileMode(const QFileDialog::FileMode mode) { m_caretFileDialog->setFileMode(mode); } - void setFilter(const QString& filter) { m_caretFileDialog->setFilter(filter); } +// void setFilter(const QString& filter) { m_caretFileDialog->setNameFilter(filter); } void setHistory(const QStringList& paths) { m_caretFileDialog->setHistory(paths); } diff --git a/src/GuiQt/HelpViewerDialog.cxx b/src/GuiQt/HelpViewerDialog.cxx index 69e0f2ead..6fb357191 100644 --- a/src/GuiQt/HelpViewerDialog.cxx +++ b/src/GuiQt/HelpViewerDialog.cxx @@ -32,8 +32,13 @@ #include #include #include -#include -#include +#if QT_VERSION >= 0x050000 +#include +#include +#else // QT_VERSION +#include +#include +#endif // QT_VERSION #include #include #include diff --git a/src/GuiQt/WuQDialog.cxx b/src/GuiQt/WuQDialog.cxx index df43c2d61..5320713e5 100644 --- a/src/GuiQt/WuQDialog.cxx +++ b/src/GuiQt/WuQDialog.cxx @@ -322,7 +322,7 @@ WuQDialog::keyPressEvent(QKeyEvent* e) // Calls reject() if Escape is pressed. Simulates a button // click for the default button if Enter is pressed. Move focus // for the arrow keys. Ignore the rest. -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) { } else #endif diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index cd9c37f57..e4adbd833 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -35,7 +35,7 @@ #include #include #include -#include +//#include #include #include #include @@ -1024,33 +1024,33 @@ WuQtUtilities::getLayoutContentDescription(QLayout* layout) return s; } -/** - * Play a sound file. The sound file MUST be in the distribution's - * "resources/sounds" directory. - * - * Note that sound files, as of Qt 4.8, do not support Qt's resource - * system. - * - * @param soundFileName - * Name of sound file (with no path, just the filename). - */ -void -WuQtUtilities::playSound(const QString& soundFileName) -{ - const QString workbenchDir = SystemUtilities::getWorkbenchHome(); - const QString soundFilePath = (workbenchDir - + "/../resources/sounds/" - + soundFileName); - - if (QFile::exists(soundFilePath)) { - QSound::play(soundFilePath); - } - else { - CaretLogSevere("Sound file \"" - + soundFilePath - + "\" does not exist."); - } -} +///** +// * Play a sound file. The sound file MUST be in the distribution's +// * "resources/sounds" directory. +// * +// * Note that sound files, as of Qt 4.8, do not support Qt's resource +// * system. +// * +// * @param soundFileName +// * Name of sound file (with no path, just the filename). +// */ +//void +//WuQtUtilities::playSound(const QString& soundFileName) +//{ +// const QString workbenchDir = SystemUtilities::getWorkbenchHome(); +// const QString soundFilePath = (workbenchDir +// + "/../resources/sounds/" +// + soundFileName); +// +// if (QFile::exists(soundFilePath)) { +// QSound::play(soundFilePath); +// } +// else { +// CaretLogSevere("Sound file \"" +// + soundFilePath +// + "\" does not exist."); +// } +//} /** * Create the text for a tooltip so that long lines are diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index d5d106ceb..0b4fa57ec 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -181,7 +181,7 @@ namespace caret { static QString getLayoutContentDescription(QLayout* layout); - static void playSound(const QString& soundFileName); + //static void playSound(const QString& soundFileName); static QString createWordWrappedToolTipText(const QString& tooltipText); diff --git a/src/Nifti/CMakeLists.txt b/src/Nifti/CMakeLists.txt index d85e6daa0..285572459 100644 --- a/src/Nifti/CMakeLists.txt +++ b/src/Nifti/CMakeLists.txt @@ -11,6 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index b5d5491ec..f044f6d49 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -11,6 +11,10 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Gui_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/OperationsBase/CMakeLists.txt b/src/OperationsBase/CMakeLists.txt index aa51abfe4..61547ef8f 100644 --- a/src/OperationsBase/CMakeLists.txt +++ b/src/OperationsBase/CMakeLists.txt @@ -11,6 +11,10 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + #include_directories(${Qt5Network_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index abe44f402..ea6915154 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -11,6 +11,9 @@ SET(QT_DONT_USE_QTGUI) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index 319ea1014..1cb32ac23 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -8,6 +8,9 @@ PROJECT(Quazip) # SET(QT_DONT_USE_QTGUI TRUE) +IF(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +ENDIF() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Qwt/CMakeLists.txt b/src/Qwt/CMakeLists.txt index 594705b8f..e1b88ece1 100644 --- a/src/Qwt/CMakeLists.txt +++ b/src/Qwt/CMakeLists.txt @@ -15,6 +15,11 @@ PROJECT (Qwt) # # QT include files # +if(Qt5_FOUND) + include_directories(${Qt5Concurrent_INCLUDE_DIRS}) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Qwt/qwt_plot_renderer.cpp b/src/Qwt/qwt_plot_renderer.cpp index 3416f9806..b7bfb01cb 100644 --- a/src/Qwt/qwt_plot_renderer.cpp +++ b/src/Qwt/qwt_plot_renderer.cpp @@ -20,8 +20,13 @@ #include #include #include +#if QT_VERSION >= 0x050000 +#include +#include +#else // QT_VERSION #include #include +#endif // QT_VERSION #include #include #include diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index b4cdca416..be83e4f04 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -22,6 +22,11 @@ SET(QT_DONT_USE_QTGUI TRUE) # # QT include files # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + #include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Xml_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Scenes/SceneInfo.cxx b/src/Scenes/SceneInfo.cxx index a55619377..0846d6e40 100644 --- a/src/Scenes/SceneInfo.cxx +++ b/src/Scenes/SceneInfo.cxx @@ -233,7 +233,7 @@ SceneInfo::writeSceneInfoImage(XmlWriter& xmlWriter, if (imageBytes.length() > 0) { //QString base64String(imageBytes.toBase64()); const QByteArray base64ByteArray(imageBytes.toBase64()); - QString base64String = QString::fromAscii(base64ByteArray.constData(), + QString base64String = QString::fromLatin1(base64ByteArray.constData(), base64ByteArray.size()); XmlAttributes attributes; attributes.addAttribute(SceneXmlElements::SCENE_INFO_IMAGE_ENCODING_ATTRIBUTE, diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index 15d821de5..8f307a531 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -13,6 +13,10 @@ SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () @@ -80,6 +84,19 @@ ELSE (APPLE) ) ENDIF (APPLE) +if(Qt5_FOUND) + set(QT5_LINK_LIBS + Qt5::Concurrent + Qt5::Core + Qt5::Gui + Qt5::Network +# Qt5::OpenGL +# Qt5::PrintSupport + Qt5::Test +# Qt5::Widgets + Qt5::Xml) +endif() + # # Libraries that are linked # @@ -101,6 +118,7 @@ Palette Scenes Xml Common +${QT5_LINK_LIBS} ${QT_LIBRARIES} ${ZLIB_LIBRARIES} #${LIBS} diff --git a/src/Tests/test_driver.cxx b/src/Tests/test_driver.cxx index 8660cf91f..8fb4eb0f7 100644 --- a/src/Tests/test_driver.cxx +++ b/src/Tests/test_driver.cxx @@ -20,7 +20,7 @@ //program for running tests -#include +//#include #include #include #include diff --git a/src/Xml/CMakeLists.txt b/src/Xml/CMakeLists.txt index 7e3dc7c86..36cdc23c9 100644 --- a/src/Xml/CMakeLists.txt +++ b/src/Xml/CMakeLists.txt @@ -13,6 +13,11 @@ SET(QT_USE_QTNETWORK TRUE) # # QT include files # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) + include_directories(${Qt5Network_INCLUDE_DIRS}) + include_directories(${Qt5Xml_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () -- GitLab From d3d998b69efa3c33542efa0db3ec660cba11d2ff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Sep 2016 15:01:59 -0500 Subject: [PATCH 012/755] Continuing adding support for Qt5: Fixed crash in Progress Reporting Dialog by not unlocking the mutex in the constructor (it should be unlocked by default); added support for using either QGLWidget (used in Qt4 but deprecated and still available in Qt5) or Qt5's QOpenGLWidget; while QOpenGLWidget works it is single-buffered (graphics flash) for a yet unknown reason so using QGLWidget for now. While not much has been tested, known problems include (1) overlay toolbox being way too tall which makes graphics region way too short; (2) Qt warning message "Attempt to set a screen on a child window" related to the browser window's toolbar; (3) have been able to build on the RedHat Linux system but it will not run on our Linuxbuild computer as it does not think there is OpenGL available --- src/CMakeLists.txt | 12 ++ src/Desktop/desktop.cxx | 14 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 1 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- src/GuiQt/BrainOpenGLWidget.cxx | 136 ++++++++++++++++++ src/GuiQt/BrainOpenGLWidget.h | 9 ++ src/GuiQt/FiberSamplesOpenGLWidget.cxx | 10 +- src/GuiQt/FiberSamplesOpenGLWidget.h | 8 ++ src/GuiQt/ProgressReportingDialog.cxx | 1 + src/GuiQt/ProgressReportingDialog.h | 2 +- src/GuiQt/ProgressReportingWithSlots.cxx | 3 + src/GuiQt/QGLWidgetTextRenderer.cxx | 8 ++ src/GuiQt/QGLWidgetTextRenderer.h | 9 ++ src/GuiQt/SceneDialog.cxx | 1 + src/GuiQt/SpecFileManagementDialog.cxx | 1 - src/GuiQt/UserInputModeViewContextMenu.cxx | 3 +- 16 files changed, 214 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a649d8a48..786be833b 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -274,6 +274,18 @@ ELSE (Qt5_FOUND) ENDIF(QT4_FOUND) ENDIF (Qt5_FOUND) +if(Qt5_FOUND) + # + # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget + # + # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used + # for OpenGL. Otherwise, QGLWidget is used. + # +### add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) +endif() + + +# # # QT include files # diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 5b753055c..388bea3b6 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -392,6 +392,16 @@ main(int argc, char* argv[]) */ CaretLogFine("Running: " + caret_global_commandLine); + /* + * Setup OpenGL if using Qt 5's QOpenGLWidget. + * QOpenGLWidget's documentation indicates that + * default format must be initizlied before + * QApplication is created. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + BrainOpenGLWidget::initializeDefaultGLFormat(); +#endif + //change the default graphics system on mac to avoid rendering performance issues with qwtplotter #ifdef CARET_OS_MACOSX // Qt-Deprecated: QApplication::setGraphicsSystem("raster"); @@ -431,9 +441,11 @@ main(int argc, char* argv[]) } /* - * Setup OpenGL + * Setup OpenGL if NOT using Qt 5's QOpenGLWidget */ +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET BrainOpenGLWidget::initializeDefaultGLFormat(); +#endif #if QT_VERSION >= 0x050000 qInstallMessageHandler(messageHandlerForQt5);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index ccec6330b..215e4c671 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -208,6 +208,7 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() this); progressDialog.setCancelButton((QPushButton*)0); // no cancel button + const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 49c94f65f..beb9bec4c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -144,7 +144,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QAction* windowAspectRatioLockedAction, QAction* tabAspectRatioLockedAction, BrainBrowserWindow* parentBrainBrowserWindow) -: QToolBar(parentBrainBrowserWindow) +: QToolBar(0) //parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; this->updateCounter = 0; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index fe2cc2509..fca43915c 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -24,6 +24,9 @@ #include #include #include +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#endif #include #include @@ -96,10 +99,22 @@ using namespace caret; */ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, const int32_t windowIndex) +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +: QOpenGLWidget(parent), +#else : QGLWidget(parent), +#endif windowIndex(windowIndex), m_textRenderer(NULL) { +#if QT_VERSION >= 0x050000 +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + CaretLogWarning("wb_view built with Qt5 using QOpenGLWidget for graphics."); +#else + CaretLogWarning("wb_view built with Qt5 using deprecated QGLWidget for graphics."); +#endif +#endif + this->openGL = NULL; this->borderBeingDrawn = new Border(); @@ -146,6 +161,13 @@ m_textRenderer(NULL) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_REQUEST); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IMAGE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * Default format is set by desktop.cxx call to initializeDefaultGLFormat(). + */ + setFormat(QSurfaceFormat::defaultFormat()); +#endif } /** @@ -226,6 +248,60 @@ BrainOpenGLWidget::getOpenGLInformation() { AString info; +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + QSurfaceFormat format = this->format(); + AString swapInfo("Swap Behavior: "); + switch (format.swapBehavior()) { + case QSurfaceFormat::DefaultSwapBehavior: + swapInfo += ("DefaultSwapBehavior"); + break; + case QSurfaceFormat::SingleBuffer: + swapInfo += ("SingleBuffer"); + break; + case QSurfaceFormat::DoubleBuffer: + swapInfo += ("DoubleBuffer"); + break; + case QSurfaceFormat::TripleBuffer: + swapInfo += ("TripleBuffer"); + break; + } + + info += ("OpenGL Context:" +// "\n Accum: " + AString::fromBool(format.accum()) +// + "\n Accum size: " + AString::number(format.accumBufferSize()) + "\n Alpha: " + AString::fromBool(format.hasAlpha()) + + "\n Alpha size: " + AString::number(format.alphaBufferSize()) +// + "\n Depth: " + AString::fromBool(format.depth()) + + "\n Depth size: " + AString::number(format.depthBufferSize()) +// + "\n Direct Rendering: " + AString::fromBool(format.directRendering()) + + "\n Red size: " + AString::number(format.redBufferSize()) + + "\n Green size: " + AString::number(format.greenBufferSize()) + + "\n Blue size: " + AString::number(format.blueBufferSize()) +// + "\n Double Buffer: " + AString::fromBool(format.doubleBuffer()) +// + "\n RGBA: " + AString::fromBool(format.rgba()) +// + "\n Samples: " + AString::fromBool(format.sampleBuffers()) + + "\n Samples size: " + AString::number(format.samples()) +// + "\n Stencil: " + AString::fromBool(format.stencil()) + + "\n Stencil size: " + AString::number(format.stencilBufferSize()) + + "\n " + swapInfo + + "\n Swap Interval: " + AString::number(format.swapInterval()) + + "\n Stereo: " + AString::fromBool(format.stereo()) + + "\n Major Version: " + AString::number(format.majorVersion()) + + "\n Minor Version: " + AString::number(format.minorVersion())); + + switch (format.profile()) { + case QSurfaceFormat::NoProfile: + info += ("\nOpenGL NoProfile - OpenGL version is lower than 3.2. For 3.2 and newer this is same as CoreProfile."); + break; + case QSurfaceFormat::CoreProfile: + info += ("\nOpenGL CoreProfile - Functionality deprecated in OpenGL version 3.0 is not available."); + break; + case QSurfaceFormat::CompatibilityProfile: + info += ("\nOpenGL CompatibilityProfile - Functionality from earlier OpenGL versions is available."); + break; + } + +#else QGLFormat format = this->format(); info += ("OpenGL Context:" "\n Accum: " + AString::fromBool(format.accum()) @@ -248,6 +324,7 @@ BrainOpenGLWidget::getOpenGLInformation() + "\n Stereo: " + AString::fromBool(format.stereo()) + "\n Major Version: " + AString::number(format.majorVersion()) + "\n Minor Version: " + AString::number(format.minorVersion())); +#endif info += ("\n\n" + this->openGL->getOpenGLInformation()); @@ -298,6 +375,8 @@ BrainOpenGLWidget::createTextRenderer() } } +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +#else /* * Create a Qt text renderer */ @@ -309,6 +388,7 @@ BrainOpenGLWidget::createTextRenderer() textRendererOut = NULL; } } +#endif if (textRendererOut == NULL) { CaretLogSevere("Unable to create a text renderer for OpenGL. " @@ -476,6 +556,12 @@ BrainOpenGLWidget::paintGL() if (bbw != NULL) { EventManager::get()->sendEvent(EventBrowserWindowGraphicsRedrawn(bbw).getPointer()); } + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +// swapBuffers(); +// CaretAssert(context()); +// context()->swapBuffers(this); +#endif } /** @@ -516,7 +602,11 @@ BrainOpenGLWidget::event(QEvent* event) } } +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + return QOpenGLWidget::event(event); +#else return QGLWidget::event(event); +#endif } @@ -1298,7 +1388,11 @@ BrainOpenGLWidget::receiveEvent(Event* event) this->repaint(); } else { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + this->update(); +#else this->updateGL(); +#endif } } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) { @@ -1309,7 +1403,11 @@ BrainOpenGLWidget::receiveEvent(Event* event) if (updateOneEvent->getWindowIndex() == this->windowIndex) { updateOneEvent->setEventProcessed(); +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + this->update(); +#else this->updateGL(); +#endif } else { /* @@ -1324,7 +1422,11 @@ BrainOpenGLWidget::receiveEvent(Event* event) bool needUpdate = false; if (needUpdate) { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + this->update(); +#else this->updateGL(); +#endif } } } @@ -1451,7 +1553,11 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) * update() is a scheduled update). */ repaint(); +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + image = grabFramebuffer(); +#else image = grabFrameBuffer(); +#endif if ((captureOffsetX > 0) || (captureOffsetY > 0)) { @@ -1486,6 +1592,9 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP: { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + CaretAssertToDoFatal(); +#else /* * Note 1: QGLWidget::renderPixmap() creates a new OpenGL * Context which destroys any textures in the existing @@ -1510,6 +1619,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) image = pixmap.toImage(); textureManager->deleteAllTexturesForWindow(this->windowIndex); this->openGL->setTextRenderer(createTextRenderer()); +#endif } break; } @@ -1540,6 +1650,31 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) void BrainOpenGLWidget::initializeDefaultGLFormat() { +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + QSurfaceFormat glfmt; + //glfmt.setAccum(false); + //glfmt.setAlpha(true); + glfmt.setAlphaBufferSize(8); + glfmt.setBlueBufferSize(8); + //glfmt.setDepth(true); + glfmt.setDepthBufferSize(24); + //glfmt.setDirectRendering(true); + //glfmt.setDoubleBuffer(true); + glfmt.setGreenBufferSize(8); + //glfmt.setOverlay(false); + glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); + glfmt.setRedBufferSize(8); + glfmt.setRenderableType(QSurfaceFormat::OpenGL); + //glfmt.setSampleBuffers(false); + //glfmt.setStencil(false); + glfmt.setStereo(false); + glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + //glfmt.setRgba(true); + + glfmt.setMajorVersion(2); + glfmt.setMinorVersion(1); + QSurfaceFormat::setDefaultFormat(glfmt); +#else QGLFormat glfmt; glfmt.setAccum(false); glfmt.setAlpha(true); @@ -1558,6 +1693,7 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setGreenBufferSize(8); glfmt.setBlueBufferSize(8); QGLFormat::setDefaultFormat(glfmt); +#endif s_defaultGLFormatInitialized = true; } diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 124a5ea34..87dceec6d 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -24,7 +24,12 @@ #include "CaretOpenGLInclude.h" +#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#else #include +#endif + #include #include @@ -56,7 +61,11 @@ namespace caret { class UserInputModeAbstract; class VolumeFile; +#if WORKBENCH_USE_QT5_QOPENGL_WIDGET + class BrainOpenGLWidget : public QOpenGLWidget, public EventListenerInterface { +#else class BrainOpenGLWidget : public QGLWidget, public EventListenerInterface { +#endif Q_OBJECT public: diff --git a/src/GuiQt/FiberSamplesOpenGLWidget.cxx b/src/GuiQt/FiberSamplesOpenGLWidget.cxx index c371ecfb3..834b02ed5 100644 --- a/src/GuiQt/FiberSamplesOpenGLWidget.cxx +++ b/src/GuiQt/FiberSamplesOpenGLWidget.cxx @@ -57,7 +57,11 @@ FiberSamplesOpenGLWidget::FiberSamplesOpenGLWidget(const int32_t browserWindowIn QLabel* fiberMeanLabels[3], QLabel* fiberVarianceLabels[3], QWidget* parent) +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +: QOpenGLWidget(parent) +#else : QGLWidget(parent) +#endif { m_browserWindowIndex = browserWindowIndex; m_enabledCheckBox = enabledCheckBox; @@ -679,6 +683,10 @@ FiberSamplesOpenGLWidget::mouseMoveEvent(QMouseEvent* me) me->accept(); - updateGL(); +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + this->update(); +#else + this->updateGL(); +#endif } diff --git a/src/GuiQt/FiberSamplesOpenGLWidget.h b/src/GuiQt/FiberSamplesOpenGLWidget.h index 58aa45889..2a8daf998 100644 --- a/src/GuiQt/FiberSamplesOpenGLWidget.h +++ b/src/GuiQt/FiberSamplesOpenGLWidget.h @@ -21,7 +21,11 @@ */ /*LICENSE_END*/ +#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#else #include +#endif #include "Matrix4x4.h" @@ -33,7 +37,11 @@ namespace caret { class BrainOpenGLShapeRing; class BrainOpenGLShapeSphere; +#if WORKBENCH_USE_QT5_QOPENGL_WIDGET + class FiberSamplesOpenGLWidget : public QOpenGLWidget { +#else class FiberSamplesOpenGLWidget : public QGLWidget { +#endif Q_OBJECT public: diff --git a/src/GuiQt/ProgressReportingDialog.cxx b/src/GuiQt/ProgressReportingDialog.cxx index 7f94379b6..db0c751d6 100644 --- a/src/GuiQt/ProgressReportingDialog.cxx +++ b/src/GuiQt/ProgressReportingDialog.cxx @@ -27,6 +27,7 @@ #include #include "CaretAssert.h" +#include "CaretLogger.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "ProgressReportingFromEvent.h" diff --git a/src/GuiQt/ProgressReportingDialog.h b/src/GuiQt/ProgressReportingDialog.h index cb640adc9..b26766085 100644 --- a/src/GuiQt/ProgressReportingDialog.h +++ b/src/GuiQt/ProgressReportingDialog.h @@ -39,7 +39,7 @@ namespace caret { const AString& initialMessage, QWidget* parent, Qt::WindowFlags f = 0); - + static void runEvent(Event* event, QWidget* parent, const AString& title); diff --git a/src/GuiQt/ProgressReportingWithSlots.cxx b/src/GuiQt/ProgressReportingWithSlots.cxx index 75a899994..2a751416a 100644 --- a/src/GuiQt/ProgressReportingWithSlots.cxx +++ b/src/GuiQt/ProgressReportingWithSlots.cxx @@ -44,7 +44,10 @@ ProgressReportingWithSlots::ProgressReportingWithSlots(QObject* parent) : QObject(parent), ProgressReportingInterface() { +#if QT_VERSION >= 0x050000 +#else m_synchronizeMutex.unlock(); +#endif m_cancelled = false; } diff --git a/src/GuiQt/QGLWidgetTextRenderer.cxx b/src/GuiQt/QGLWidgetTextRenderer.cxx index 6ef5abb55..731021289 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.cxx +++ b/src/GuiQt/QGLWidgetTextRenderer.cxx @@ -19,6 +19,12 @@ */ /*LICENSE_END*/ +/* + * QOpenGLWidget does not have renderText() methods. + * renderText() methods are in deprecated QGLWidget. + */ +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET + #define __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ #include "QGLWidgetTextRenderer.h" #undef __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ @@ -1124,3 +1130,5 @@ QGLWidgetTextRenderer::FontData::~FontData() } } +#endif // not - WORKBENCH_USE_QT5_QOPENGL_WIDGET + diff --git a/src/GuiQt/QGLWidgetTextRenderer.h b/src/GuiQt/QGLWidgetTextRenderer.h index 4cddd4252..a4dfe22a3 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.h +++ b/src/GuiQt/QGLWidgetTextRenderer.h @@ -1,6 +1,12 @@ #ifndef __QGLWIDGET_TEXT_RENDERER_H__ #define __QGLWIDGET_TEXT_RENDERER_H__ +/* + * QOpenGLWidget does not have renderText() methods. + * renderText() methods are in deprecated QGLWidget. + */ +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine @@ -170,4 +176,7 @@ namespace caret { #endif // __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ } // namespace + +#endif // not - WORKBENCH_USE_QT5_QOPENGL_WIDGET + #endif //__QT_OPEN_G_L_TEXT_RENDERER_H__ diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 802829b70..1610278bd 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1347,6 +1347,7 @@ SceneDialog::showSceneButtonClicked() return; } } + ProgressReportingDialog progressDialog(("Restoring Scene " + scene->getName()), "", this); diff --git a/src/GuiQt/SpecFileManagementDialog.cxx b/src/GuiQt/SpecFileManagementDialog.cxx index fd06d7e07..4928a29ce 100644 --- a/src/GuiQt/SpecFileManagementDialog.cxx +++ b/src/GuiQt/SpecFileManagementDialog.cxx @@ -1845,7 +1845,6 @@ SpecFileManagementDialog::okButtonClickedOpenSpecFile() ProgressReportingDialog::runEvent(&readSpecFileEvent, this, m_specFile->getFileNameNoPath()); - errorMessages.appendWithNewLine(readSpecFileEvent.getErrorMessage()); updateGraphicWindowsAndUserInterface(); diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index 54e5e3f54..6728c5b03 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -813,7 +813,7 @@ UserInputModeViewContextMenu::parcelCiftiConnectivityActionSelected(QAction* act "", this); progressDialog.setValue(0); - + switch (pc->parcelType) { case ParcelConnectivity::PARCEL_TYPE_INVALID: break; @@ -956,6 +956,7 @@ UserInputModeViewContextMenu::borderCiftiConnectivitySelected() "", this); progressDialog.setValue(0); + CiftiConnectivityMatrixDataFileManager* ciftiConnMann = SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(); ciftiConnMann->loadAverageDataForSurfaceNodes(borderID->getBrain(), surface, -- GitLab From 64e824273ac8f50289d86a2ff97dad29e5b01bcc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Sep 2016 12:10:33 -0500 Subject: [PATCH 013/755] With Qt5, the main window size was incorrect when a scene was restored and was limited to a height of 640. In WuQtUtilities::moveAndSizeWindow() the method QDesktopWidget::geometry() was called to get the maximum width and height. The "geometry()" method is actually in the base class of QWidget and is probably the wrong method to call. For Qt5, QDesktopWidget::availableGeometry() is now used. It is left unchanged for Qt4 since it is working with Qt4. --- src/GuiQt/WuQtUtilities.cxx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index e4adbd833..9d8fa971b 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -389,7 +389,18 @@ WuQtUtilities::moveAndSizeWindow(QWidget* window, */ QPoint pXY(x, y); +#if QT_VERSION >= 0x050000 + const QRect availableRect = dw->availableGeometry(); +#else + /* + * Note 23 September 2016: + * Calling geometry is likely the WRONG method to call + * but since it is not causing a problem in in Qt 4.x + * we will continuing using to avoid the risk of + * breaking scenes. + */ const QRect availableRect = dw->screen()->geometry(); +#endif const int32_t screenSizeX = availableRect.width(); const int32_t screenSizeY = availableRect.height(); -- GitLab From dc2749d56389318e9b1ed5f89ee1fc3621b4fdfa Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Sep 2016 13:29:18 -0500 Subject: [PATCH 014/755] Fixed restoration of toolbox sizes when using Qt 5. --- src/GuiQt/BrainBrowserWindow.cxx | 52 +++++++++++++++++++ .../BrainBrowserWindowOrientedToolBox.cxx | 4 ++ 2 files changed, 56 insertions(+) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 535744a09..d73fbbe5c 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -4323,6 +4323,28 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, m_featuresToolBoxAction->trigger(); m_featuresToolBox->restoreFromScene(sceneAttributes, sceneClass->getClass("m_featuresToolBox")); + +#if QT_VERSION >= 0x050000 + /* + * Toolboxes were not restoring to correct size in Qt5. + * Qt5 adds a new method, QMainWindow::resizeDocks() that + * resizes a QDockWidget in one dimension. Use it to resize + * the toolbox. + */ + const SceneClass* featureToolBoxClass = sceneClass->getClass("m_featuresToolBox"); + if (featureToolBoxClass != NULL) { + const int w = featureToolBoxClass->getIntegerValue("toolboxWidth", -1); + const int h = featureToolBoxClass->getIntegerValue("toolboxHeight", -1); + if ((w > 0) + && (h > 0)) { + QList dockList; + dockList.append(m_featuresToolBox); + QList sizeList; + sizeList.append(w); + resizeDocks(dockList, sizeList, Qt::Horizontal); + } + } +#endif } /* @@ -4348,6 +4370,36 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, processShowOverlayToolBox(toolBoxVisible); m_overlayActiveToolBox->restoreFromScene(sceneAttributes, sceneClass->getClass("m_overlayActiveToolBox")); + + +#if QT_VERSION >= 0x050000 + /* + * Toolboxes were not restoring to correct size in Qt5. + * Qt5 adds a new method, QMainWindow::resizeDocks() that + * resizes a QDockWidget in one dimension. Use it to resize + * the toolbox. + */ + const SceneClass* activeToolBoxClass = sceneClass->getClass("m_overlayActiveToolBox"); + if (activeToolBoxClass != NULL) { + const int w = activeToolBoxClass->getIntegerValue("toolboxWidth", -1); + const int h = activeToolBoxClass->getIntegerValue("toolboxHeight", -1); + if ((w > 0) + && (h > 0)) { + QList dockList; + dockList.append(m_overlayActiveToolBox); + if (orientationName == "horizontal") { + QList sizeList; + sizeList.append(h); + resizeDocks(dockList, sizeList, Qt::Vertical); + } + else { + QList sizeList; + sizeList.append(w); + resizeDocks(dockList, sizeList, Qt::Horizontal); + } + } + } +#endif } } diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 95e71b491..86f2f105d 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -462,7 +462,10 @@ BrainBrowserWindowOrientedToolBox::restoreFromScene(const SceneAttributes* scene sceneClass->getClass("geometry")); } else { +#if QT_VERSION < 0x050000 /* + * Do this for Qt4 only. Qt5 restores size in BrainBrowserWindow. + * * From http://stackoverflow.com/questions/2722939/c-resize-a-docked-qt-qdockwidget-programmatically * * Set the minimum and maximum sizes and restore them later. @@ -487,6 +490,7 @@ BrainBrowserWindowOrientedToolBox::restoreFromScene(const SceneAttributes* scene this, SLOT(restoreMinimumAndMaximumSizesAfterSceneRestored())); } +#endif } } -- GitLab From 77bbc128da954003c5d1633d6a15ceaca1a112c7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Sep 2016 14:56:23 -0500 Subject: [PATCH 015/755] Fixed CaretHttpManager problem with Qt5. --- src/Common/CaretHttpManager.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Common/CaretHttpManager.cxx b/src/Common/CaretHttpManager.cxx index 494028235..593506b05 100644 --- a/src/Common/CaretHttpManager.cxx +++ b/src/Common/CaretHttpManager.cxx @@ -235,15 +235,15 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret /* * QUrl::addQueryItem() deprecated in Qt5: http://wiki.qt.io/Transition_from_Qt_4.x_to_Qt5 */ + QUrl myUrl = QUrl::fromUserInput(request.m_url); #if QT_VERSION >= 0x050000 - QUrl myUrl; QUrlQuery myUrlQuery(QUrl::fromUserInput(request.m_url)); for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) { myUrlQuery.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); } + myUrl.setQuery(myUrlQuery); #else // QT_VERSION - QUrl myUrl = QUrl::fromUserInput(request.m_url); for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) { myUrl.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); @@ -276,7 +276,7 @@ void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, Caret myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); } #if QT_VERSION >= 0x050000 - myUrl.setQuery(myUrlQuery); + //myUrl.setQuery(myUrlQuery); #endif // QT_VERSION myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postData); -- GitLab From 6e970e606ad62f48459203715448f542dedb85c3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Sep 2016 16:32:31 -0500 Subject: [PATCH 016/755] Modified CMakeLists.txt files to place statements like these (SET(QT_USE_QT TRUE) within Qt4 IF statements since they are needed only by Qt4. --- src/Brain/CMakeLists.txt | 11 +---------- src/Cifti/CMakeLists.txt | 8 ++------ src/CommandLine/CMakeLists.txt | 8 ++------ src/Desktop/CMakeLists.txt | 11 +++-------- src/Files/CMakeLists.txt | 8 ++------ src/FtglFont/CMakeLists.txt | 11 +---------- src/Gifti/CMakeLists.txt | 6 +----- src/GuiQt/CMakeLists.txt | 9 ++------- src/Nifti/CMakeLists.txt | 2 +- src/Operations/CMakeLists.txt | 6 +----- src/OperationsBase/CMakeLists.txt | 6 +----- src/Palette/CMakeLists.txt | 6 +----- src/Quazip/CMakeLists.txt | 6 +----- src/Scenes/CMakeLists.txt | 6 +----- src/Tests/CMakeLists.txt | 9 ++------- src/Xml/CMakeLists.txt | 10 +++------- 16 files changed, 25 insertions(+), 98 deletions(-) diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 39dd58307..cce1b92aa 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -8,16 +8,6 @@ PROJECT (Brain) # SET(QT_DONT_USE_QTGUI) -# -# Use OpenGL from QT -# -#SET(QT_USE_QTOPENGL TRUE) - -# -# Need network -# -SET(QT_USE_QTNETWORK TRUE) - # # Add QT for includes # @@ -27,6 +17,7 @@ if(Qt5_FOUND) include_directories(${Qt5Gui_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Cifti/CMakeLists.txt b/src/Cifti/CMakeLists.txt index 612ffc24c..3aa8c38a8 100644 --- a/src/Cifti/CMakeLists.txt +++ b/src/Cifti/CMakeLists.txt @@ -4,12 +4,6 @@ # PROJECT (Cifti) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) -SET(QT_USE_QTNETWORK TRUE) - # # Add QT for includes # @@ -18,6 +12,8 @@ if(Qt5_FOUND) include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index b4eb0e975..b5e76ae90 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -6,12 +6,6 @@ PROJECT (CommandLine) #cmake_policy(SET CMP0015 OLD) -# -# Need XML from Qt -# -#SET(QT_DONT_USE_QTGUI TRUE) -SET(QT_USE_QTXML TRUE) -SET(QT_USE_QTNETWORK TRUE) # # Add QT for includes @@ -21,6 +15,8 @@ if(Qt5_FOUND) # include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTXML TRUE) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 2c97433f4..c1f194e5b 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -8,14 +8,6 @@ PROJECT(Desktop) # set (EXE_NAME wb_view) -# -# QT Libraries -# -SET(QT_USE_QTXML TRUE) -SET(QT_USE_QTOPENGL TRUE) -SET(QT_USE_QTNETWORK TRUE) -#SET(QT_USE_QTWEBKIT TRUE) - # # QT Include directories # @@ -26,6 +18,9 @@ if(Qt5_FOUND) include_directories(${Qt5Widgets_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTXML TRUE) + SET(QT_USE_QTOPENGL TRUE) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 0ec643394..6f97aa50c 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -3,12 +3,6 @@ # PROJECT (Files) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) -SET(QT_USE_QTNETWORK TRUE) - # # Add QT for includes # @@ -18,6 +12,8 @@ if(Qt5_FOUND) include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/FtglFont/CMakeLists.txt b/src/FtglFont/CMakeLists.txt index 48cd6dd0b..76869896f 100644 --- a/src/FtglFont/CMakeLists.txt +++ b/src/FtglFont/CMakeLists.txt @@ -3,20 +3,11 @@ # PROJECT (Ftgl) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) - -# -# Use OpenGL from QT -# -#SET(QT_USE_QTOPENGL TRUE) - # # Add QT for includes # IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Gifti/CMakeLists.txt b/src/Gifti/CMakeLists.txt index 4c6d1f85a..bd246a4ea 100644 --- a/src/Gifti/CMakeLists.txt +++ b/src/Gifti/CMakeLists.txt @@ -4,11 +4,6 @@ # PROJECT (Gifti) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) - # # Add QT for includes # @@ -16,6 +11,7 @@ if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 3199f8181..888b38909 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -4,13 +4,6 @@ # PROJECT (GuiQt) -# -# Use OpenGL from QT -# -SET(QT_USE_QTNETWORK TRUE) -SET(QT_USE_QTOPENGL TRUE) -#SET(QT_USE_QTWEBKIT TRUE) - # # QT include files # @@ -21,6 +14,8 @@ if(Qt5_FOUND) include_directories(${Qt5Widgets_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTNETWORK TRUE) + SET(QT_USE_QTOPENGL TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Nifti/CMakeLists.txt b/src/Nifti/CMakeLists.txt index 285572459..3b40bf76a 100644 --- a/src/Nifti/CMakeLists.txt +++ b/src/Nifti/CMakeLists.txt @@ -6,7 +6,6 @@ project (Nifti) # # Need XML from Qt # -SET(QT_DONT_USE_QTGUI) # # Add QT for includes @@ -15,6 +14,7 @@ if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index f044f6d49..2467cca2a 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -3,11 +3,6 @@ # PROJECT (Operations) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) - # # Add QT for includes # @@ -16,6 +11,7 @@ if(Qt5_FOUND) include_directories(${Qt5Gui_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/OperationsBase/CMakeLists.txt b/src/OperationsBase/CMakeLists.txt index 61547ef8f..c2be35d51 100644 --- a/src/OperationsBase/CMakeLists.txt +++ b/src/OperationsBase/CMakeLists.txt @@ -3,11 +3,6 @@ # PROJECT (OperationsBase) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) - # # Add QT for includes # @@ -16,6 +11,7 @@ if(Qt5_FOUND) #include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index ea6915154..8c7cc803b 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -3,15 +3,11 @@ # project (Palette) -# -# Need XML from Qt -# -SET(QT_DONT_USE_QTGUI) - # # Add QT for includes # if(Qt5_FOUND) + SET(QT_DONT_USE_QTGUI) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index 1cb32ac23..36294e844 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -3,15 +3,11 @@ # PROJECT(Quazip) -# -# QT include files -# -SET(QT_DONT_USE_QTGUI TRUE) - IF(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) ENDIF() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index be83e4f04..36a0b748a 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -14,11 +14,6 @@ PROJECT (Scenes) # #ADD_DEFINITIONS(-DCARET_SCENE_DEBUG) -# -# Use XML from Qt but not GUI. -# -SET(QT_DONT_USE_QTGUI TRUE) - # # QT include files # @@ -28,6 +23,7 @@ if(Qt5_FOUND) include_directories(${Qt5Xml_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_DONT_USE_QTGUI TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index 8f307a531..d361a8ea0 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -3,13 +3,6 @@ # PROJECT (Tests) -# -# Need XML from Qt -# -# needed QImage and it is from GUI: SET(QT_DONT_USE_QTGUI TRUE) -SET(QT_USE_QTXML TRUE) -SET(QT_USE_QTNETWORK TRUE) - # # Add QT for includes # @@ -18,6 +11,8 @@ if(Qt5_FOUND) include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTXML TRUE) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () diff --git a/src/Xml/CMakeLists.txt b/src/Xml/CMakeLists.txt index 36cdc23c9..f0dfc2302 100644 --- a/src/Xml/CMakeLists.txt +++ b/src/Xml/CMakeLists.txt @@ -3,13 +3,6 @@ # PROJECT (Xml) -# -# Use XML from Qt but not GUI. -# -SET(QT_USE_QTXML TRUE) -SET(QT_DONT_USE_QTGUI TRUE) -SET(QT_USE_QTNETWORK TRUE) - # # QT include files # @@ -19,6 +12,9 @@ if(Qt5_FOUND) include_directories(${Qt5Xml_INCLUDE_DIRS}) endif() IF (QT4_FOUND) + SET(QT_USE_QTXML TRUE) + SET(QT_DONT_USE_QTGUI TRUE) + SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () -- GitLab From 4192cc1a1ce9391069dc1e13d54b19544aa116eb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Sep 2016 16:35:13 -0500 Subject: [PATCH 017/755] Fixed some compilation warnings in QwtDate::ceil() method that were actually bugs. These "add" functions were constants methods and an assignment was added to each. For example, "dt.addDays(days)" was changed to "dt = dt.addDays(days)". --- src/Qwt/qwt_date.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Qwt/qwt_date.cpp b/src/Qwt/qwt_date.cpp index fc3ac4b2d..6235426b0 100644 --- a/src/Qwt/qwt_date.cpp +++ b/src/Qwt/qwt_date.cpp @@ -322,7 +322,7 @@ QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType ) { qwtFloorTime( QwtDate::Second, dt ); if ( dt < dateTime ) - dt.addSecs( 1 ); + dt = dt.addSecs( 1 ); break; } @@ -330,7 +330,7 @@ QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType ) { qwtFloorTime( QwtDate::Minute, dt ); if ( dt < dateTime ) - dt.addSecs( 60 ); + dt = dt.addSecs( 60 ); break; } @@ -338,7 +338,7 @@ QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType ) { qwtFloorTime( QwtDate::Hour, dt ); if ( dt < dateTime ) - dt.addSecs( 3600 ); + dt = dt.addSecs( 3600 ); break; } @@ -371,7 +371,7 @@ QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType ) dateTime.date().month() ) ); if ( dt < dateTime ) - dt.addMonths( 1 ); + dt = dt.addMonths( 1 ); break; } -- GitLab From 1849b2106aea5677948fecce9e5c742c820c4fe7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 27 Sep 2016 09:33:21 -0500 Subject: [PATCH 018/755] With Qt5, the default height of the overlay toolbox at the bottom of the main window is way too tall. Qt5 added a QMainWIndow::resizeDocks() method so it is used to set the height of the overlay toolbox to a reasonable size. --- src/GuiQt/BrainBrowserWindow.cxx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index d73fbbe5c..bbfb0d551 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -246,6 +246,25 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_VIEWPORT_SIZE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); + +#if QT_VERSION >= 0x050000 + if (m_overlayHorizontalToolBox == m_overlayActiveToolBox) { + /* + * With Qt5, default height of overlay toolbox at bottom is + * way too tall. Qt 5.6 added a 'resizeDocks' method and + * it is used to initialize the height of the overlay toolbox. + */ + const int toolboxHeight = 150; + QList docks; + docks.push_back(m_overlayHorizontalToolBox); + QList dockSizes; + dockSizes.push_back(toolboxHeight); + + resizeDocks(docks, + dockSizes, + Qt::Vertical); + } +#endif } /** -- GitLab From 2f7790a764a3663e27e8b9aa63d852c4628accd4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Sep 2016 09:11:21 -0500 Subject: [PATCH 019/755] With Qt5 on Mac, the tool buttons in the browser window toolbar appear flat similar to a label. The background color is the same as the toolbar's background color and there is no border around the tool button. Added function WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton*) that uses a style sheet to lighten the tool buttons background and add a slightly darker border around the button. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 59 +++++++++++++++++-- .../BrainBrowserWindowToolBarClipping.cxx | 1 + .../BrainBrowserWindowToolBarSlicePlane.cxx | 6 ++ ...rainBrowserWindowToolBarSliceSelection.cxx | 1 + src/GuiQt/BrainBrowserWindowToolBarTab.cxx | 2 + src/GuiQt/BrainOpenGLWidget.cxx | 4 +- src/GuiQt/WuQtUtilities.cxx | 40 +++++++++++++ src/GuiQt/WuQtUtilities.h | 3 + 8 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index beb9bec4c..d1c51bd70 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -201,10 +201,16 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow * of this instance. It cannot be declared statically. */ #if QT_VERSION >= 0x050000 - QStyle* cleanLooksStyle = QStyleFactory::create("Cleanlooks"); - if (cleanLooksStyle != NULL) { - cleanLooksStyle->setParent(this); - this->tabBar->setStyle(cleanLooksStyle); + /* + * "Cleanlooks Style" removed in Qt5. Fusion style + * seems to have same effect on toolbar so that + * tabs do not get shrunk too small and so the + * scroll tabs arrows are available. + */ + QStyle* fusionStyle = QStyleFactory::create("Fusion"); + if (fusionStyle != NULL) { + fusionStyle->setParent(this); + this->tabBar->setStyle(fusionStyle); } #else // QT_VERSION QCleanlooksStyle* cleanLooksStyle = new QCleanlooksStyle(); @@ -1727,30 +1733,39 @@ BrainBrowserWindowToolBar::createOrientationWidget() this->orientationLeftOrLateralToolButton = new QToolButton(); this->orientationLeftOrLateralToolButton->setDefaultAction(this->orientationLeftOrLateralToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLeftOrLateralToolButton); this->orientationRightOrMedialToolButton = new QToolButton(); this->orientationRightOrMedialToolButton->setDefaultAction(this->orientationRightOrMedialToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationRightOrMedialToolButton); this->orientationAnteriorToolButton = new QToolButton(); this->orientationAnteriorToolButton->setDefaultAction(this->orientationAnteriorToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorToolButton); this->orientationPosteriorToolButton = new QToolButton(); this->orientationPosteriorToolButton->setDefaultAction(this->orientationPosteriorToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationPosteriorToolButton); this->orientationDorsalToolButton = new QToolButton(); this->orientationDorsalToolButton->setDefaultAction(this->orientationDorsalToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalToolButton); this->orientationVentralToolButton = new QToolButton(); this->orientationVentralToolButton->setDefaultAction(this->orientationVentralToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationVentralToolButton); this->orientationLateralMedialToolButton = new QToolButton(); this->orientationLateralMedialToolButton->setDefaultAction(this->orientationLateralMedialToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLateralMedialToolButton); this->orientationDorsalVentralToolButton = new QToolButton(); this->orientationDorsalVentralToolButton->setDefaultAction(this->orientationDorsalVentralToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalVentralToolButton); this->orientationAnteriorPosteriorToolButton = new QToolButton(); this->orientationAnteriorPosteriorToolButton->setDefaultAction(this->orientationAnteriorPosteriorToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorPosteriorToolButton); WuQtUtilities::matchWidgetWidths(this->orientationLateralMedialToolButton, this->orientationDorsalVentralToolButton, @@ -1758,11 +1773,13 @@ BrainBrowserWindowToolBar::createOrientationWidget() QToolButton* orientationResetToolButton = new QToolButton(); orientationResetToolButton->setDefaultAction(this->orientationResetToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(orientationResetToolButton); this->orientationCustomViewSelectToolButton = new QToolButton(); this->orientationCustomViewSelectToolButton->setDefaultAction(this->customViewAction); this->orientationCustomViewSelectToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationCustomViewSelectToolButton); QGridLayout* buttonGridLayout = new QGridLayout(); buttonGridLayout->setColumnStretch(3, 100); @@ -1995,6 +2012,7 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() this, SLOT(wholeBrainSurfaceLeftToolButtonTriggered(bool))); QToolButton* wholeBrainLeftSurfaceToolButton = new QToolButton(); + WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainLeftSurfaceToolButton); wholeBrainLeftSurfaceToolButton->setDefaultAction(leftSurfaceAction); /* @@ -2012,6 +2030,7 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() this, SLOT(wholeBrainSurfaceRightToolButtonTriggered(bool))); QToolButton* wholeBrainRightSurfaceToolButton = new QToolButton(); + WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainRightSurfaceToolButton); wholeBrainRightSurfaceToolButton->setDefaultAction(rightSurfaceAction); /* @@ -2029,6 +2048,7 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() this, SLOT(wholeBrainSurfaceCerebellumToolButtonTriggered(bool))); QToolButton* wholeBrainCerebellumSurfaceToolButton = new QToolButton(); + WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainCerebellumSurfaceToolButton); wholeBrainCerebellumSurfaceToolButton->setDefaultAction(cerebellumSurfaceAction); /* @@ -2227,6 +2247,32 @@ BrainBrowserWindowToolBar::createModeWidget() QToolButton* inputModeAnnotationsToolButton = new QToolButton(); inputModeAnnotationsToolButton->setDefaultAction(this->modeInputModeAnnotationsAction); + inputModeAnnotationsToolButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + inputModeAnnotationsToolButton->setAutoRaise(true); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); + +// const QPalette palette = inputModeAnnotationsToolButton->palette(); +// const QPalette::ColorRole backgroundRole = inputModeAnnotationsToolButton->backgroundRole(); +// const QBrush backgroundBrush = palette.brush(backgroundRole); +// const QColor backgroundColor = backgroundBrush.color(); +// const QColor darkerColor = backgroundColor.darker(125); +// +// const QString toolButtonStyleSheet(" QToolButton { " +// " border-style: solid; " +// " border-width: 1px; " +// " border-color: " + darkerColor.name() + "; " +// " padding-top: 1px; " +// " padding-bottom: 1px; " +// " padding-right: 3px; " +// " padding-left: 3px; " +// " }"); +// std::cout << "****** style sheet: " << toolButtonStyleSheet << std::endl; +// inputModeAnnotationsToolButton->setStyleSheet(toolButtonStyleSheet); +//// const int red = backgroundColor.red(); +//// const int green = backgroundColor.green(); +//// const int blue = backgroundColor.blue(); +//// std::cout << "******** Annotate Background Color: " << red << ", " << green << ", " << blue << std::endl; + /* * Borders */ @@ -2236,6 +2282,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeBordersAction->setCheckable(true); QToolButton* inputModeBordersToolButton = new QToolButton(); inputModeBordersToolButton->setDefaultAction(this->modeInputModeBordersAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeBordersToolButton); /* * Foci @@ -2246,6 +2293,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeFociAction->setCheckable(true); QToolButton* inputModeFociToolButton = new QToolButton(); inputModeFociToolButton->setDefaultAction(this->modeInputModeFociAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeFociToolButton); /* * Image @@ -2256,6 +2304,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeImageAction->setCheckable(true); QToolButton* inputModeImageToolButton = new QToolButton(); inputModeImageToolButton->setDefaultAction(this->modeInputModeImageAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeImageToolButton); /* * Volume Edit @@ -2266,6 +2315,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputVolumeEditAction->setCheckable(true); QToolButton* inputModeVolumeEditButton = new QToolButton(); inputModeVolumeEditButton->setDefaultAction(this->modeInputVolumeEditAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeVolumeEditButton); /* * View Mode @@ -2290,6 +2340,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeViewAction->setCheckable(true); QToolButton* inputModeViewToolButton = new QToolButton(); inputModeViewToolButton->setDefaultAction(this->modeInputModeViewAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeViewToolButton); WuQtUtilities::matchWidgetWidths(inputModeAnnotationsToolButton, inputModeBordersToolButton, diff --git a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx index 5036749ca..8cdd370db 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx @@ -82,6 +82,7 @@ m_parentToolBar(parentToolBar) setupToolButton->setText("Setup"); QObject::connect(setupToolButton, SIGNAL(clicked()), this, SLOT(setupClippingPushButtonClicked())); + WuQtUtilities::setToolButtonStyleForQt5Mac(setupToolButton); QGridLayout* gridLayout = new QGridLayout(this); gridLayout->setHorizontalSpacing(6); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx index 7633265c5..c58fd33e8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx @@ -117,18 +117,23 @@ m_parentToolBar(parentToolBar) QToolButton* volumePlaneParasagittalToolButton = new QToolButton(); volumePlaneParasagittalToolButton->setDefaultAction(m_volumePlaneParasagittalToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneParasagittalToolButton); QToolButton* volumePlaneCoronalToolButton = new QToolButton(); volumePlaneCoronalToolButton->setDefaultAction(m_volumePlaneCoronalToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneCoronalToolButton); QToolButton* volumePlaneAxialToolButton = new QToolButton(); volumePlaneAxialToolButton->setDefaultAction(m_volumePlaneAxialToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAxialToolButton); QToolButton* volumePlaneAllToolButton = new QToolButton(); volumePlaneAllToolButton->setDefaultAction(m_volumePlaneAllToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAllToolButton); QToolButton* volumePlaneResetToolButton = new QToolButton(); volumePlaneResetToolButton->setDefaultAction(m_volumePlaneResetToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneResetToolButton); WuQtUtilities::matchWidgetHeights(volumePlaneParasagittalToolButton, volumePlaneCoronalToolButton, @@ -143,6 +148,7 @@ m_parentToolBar(parentToolBar) slicePlaneCustomToolButton->setDefaultAction(m_parentToolBar->customViewAction); slicePlaneCustomToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + WuQtUtilities::setToolButtonStyleForQt5Mac(slicePlaneCustomToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 69ddde3be..788188845 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -73,6 +73,7 @@ m_parentToolBar(parentToolBar) SLOT(volumeIndicesOriginActionTriggered())); QToolButton* volumeIndicesOriginToolButton = new QToolButton; volumeIndicesOriginToolButton->setDefaultAction(volumeIndicesOriginToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIndicesOriginToolButton); QLabel* parasagittalLabel = new QLabel("P:"); QLabel* coronalLabel = new QLabel("C:"); diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx index 21bf0268f..c8e3ff31d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx @@ -83,9 +83,11 @@ m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) QToolButton* windowAspectRatioLockedToolButton = new QToolButton(); windowAspectRatioLockedToolButton->setDefaultAction(windowAspectRatioLockedAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(windowAspectRatioLockedToolButton); QToolButton* tabAspectRatioLockedToolButton = new QToolButton(); tabAspectRatioLockedToolButton->setDefaultAction(tabAspectRatioLockedAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(tabAspectRatioLockedToolButton); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index fca43915c..3cb6102ba 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -82,7 +82,7 @@ #include "UserInputModeImage.h" #include "UserInputModeView.h" #include "UserInputModeVolumeEdit.h" - +#include "WuQMessageBox.h" using namespace caret; @@ -1593,7 +1593,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP: { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - CaretAssertToDoFatal(); + WuQMessageBox::errorOk(this, "Render PixMap not implemented with Qt5"); #else /* * Note 1: QGLWidget::renderPixmap() creates a new OpenGL diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 9d8fa971b..1d438358f 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -39,6 +39,7 @@ #include #include #include +#include #include "CaretAssert.h" #include "CaretLogger.h" @@ -1390,5 +1391,44 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, return painter; } +/** + * With Qt5, a toolbutton placed into a toolbar uses the + * background of the toolbar with no morder and appears + * similar to a label. Use a stylesheet so that + * the button appears similar to Qt4. + */ +void +WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) +{ +#ifdef CARET_OS_MACOSX +#if QT_VERSION >= 0x050000 + const QPalette palette = toolButton->palette(); + const QPalette::ColorRole backgroundRole = toolButton->backgroundRole(); + const QBrush backgroundBrush = palette.brush(backgroundRole); + const QColor backgroundColor = backgroundBrush.color(); + const QColor lighterColor = backgroundColor.lighter(100); + const QColor darkerColor = backgroundColor.darker(125); + + /* + * Use a stylesheet to: + * (1) Make the background of the button lighter + * (2) Add a border around the button that is slightly + * darker than the background. + */ + const QString toolButtonStyleSheet(" QToolButton { " + " background: " + lighterColor.name() + "; " + " border-style: solid; " + " border-width: 1px; " + " border-color: " + darkerColor.name() + "; " + " padding-top: 1px; " + " padding-bottom: 1px; " + " padding-right: 3px; " + " padding-left: 3px; " + " }"); + toolButton->setStyleSheet(toolButtonStyleSheet); +#endif +#endif +} + diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index 0b4fa57ec..cbbca0191 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -41,6 +41,7 @@ class QPixmap; class QPushButton; class QString; class QTableWidget; +class QToolButton; class QWidget; namespace caret { @@ -192,6 +193,8 @@ namespace caret { static Qt::CheckState boolToCheckState(const bool value); + static void setToolButtonStyleForQt5Mac(QToolButton* toolButton); + private: WuQtUtilities(); ~WuQtUtilities(); -- GitLab From 7db897d28ceae9122ebdd182a6095d86688f6ca5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Sep 2016 15:11:47 -0500 Subject: [PATCH 020/755] Fixed invalid OpenGL operation error caused by calls to glReadPixels(GL_BACK). With Qt5 QOpenGLWidget, OpenGL commands are draw into offscreen frame buffers so that is probably why the GL_FRONT and GL_BACK buffers do not exist.. Thus, do not call glReadPixels(). Identification operations continue to successfully complete. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 43 ++++++++++++++++++++++---- src/CMakeLists.txt | 2 +- src/GuiQt/BrainOpenGLWidget.cxx | 11 ++----- src/GuiQt/BrainOpenGLWidget.h | 4 +-- src/GuiQt/FiberSamplesOpenGLWidget.h | 4 +-- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 0c6c98833..1e5bc45e5 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5654,9 +5654,19 @@ BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum:: */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - // Figure out item was picked using color in color buffer - // + /* + * Determine item picked by examination of color in back buffer + * + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else glReadBuffer(GL_BACK); +#endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -5725,9 +5735,19 @@ BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum:: */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - // Figure out item was picked using color in color buffer - // + /* + * Determine item picked by examination of color in back buffer + * + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else glReadBuffer(GL_BACK); +#endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -5800,9 +5820,19 @@ BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum:: */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - // Figure out item was picked using color in color buffer - // + /* + * Determine item picked by examination of color in back buffer + * + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else glReadBuffer(GL_BACK); +#endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -7531,6 +7561,7 @@ BrainOpenGLFixedPipeline::getStateOfOpenGL() const s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_COLOR_MATERIAL", GL_COLOR_MATERIAL)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CULL_FACE", GL_CULL_FACE)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_DEPTH_TEST", GL_DEPTH_TEST)); + s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_DOUBLEBUFFER", GL_DOUBLEBUFFER)); s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_LIGHT_MODEL_LOCAL_VIEWER", GL_LIGHT_MODEL_LOCAL_VIEWER)); s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_LIGHT_MODEL_TWO_SIDE", GL_LIGHT_MODEL_TWO_SIDE)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHTING", GL_LIGHTING)); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 786be833b..13dcd36a3 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -281,7 +281,7 @@ if(Qt5_FOUND) # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used # for OpenGL. Otherwise, QGLWidget is used. # -### add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) + add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) endif() diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 3cb6102ba..274a744cb 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -266,7 +266,7 @@ BrainOpenGLWidget::getOpenGLInformation() break; } - info += ("OpenGL Context:" + info += ("QOpenGLWidget Context:" // "\n Accum: " + AString::fromBool(format.accum()) // + "\n Accum size: " + AString::number(format.accumBufferSize()) "\n Alpha: " + AString::fromBool(format.hasAlpha()) @@ -303,7 +303,7 @@ BrainOpenGLWidget::getOpenGLInformation() #else QGLFormat format = this->format(); - info += ("OpenGL Context:" + info += ("QGLWidget Context:" "\n Accum: " + AString::fromBool(format.accum()) + "\n Accum size: " + AString::number(format.accumBufferSize()) + "\n Alpha: " + AString::fromBool(format.alpha()) @@ -376,6 +376,7 @@ BrainOpenGLWidget::createTextRenderer() } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* No Qt Text Renderer in QOpenGLWidget */ #else /* * Create a Qt text renderer @@ -556,12 +557,6 @@ BrainOpenGLWidget::paintGL() if (bbw != NULL) { EventManager::get()->sendEvent(EventBrowserWindowGraphicsRedrawn(bbw).getPointer()); } - -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -// swapBuffers(); -// CaretAssert(context()); -// context()->swapBuffers(this); -#endif } /** diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 87dceec6d..84a33eccd 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -24,7 +24,7 @@ #include "CaretOpenGLInclude.h" -#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else #include @@ -61,7 +61,7 @@ namespace caret { class UserInputModeAbstract; class VolumeFile; -#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET class BrainOpenGLWidget : public QOpenGLWidget, public EventListenerInterface { #else class BrainOpenGLWidget : public QGLWidget, public EventListenerInterface { diff --git a/src/GuiQt/FiberSamplesOpenGLWidget.h b/src/GuiQt/FiberSamplesOpenGLWidget.h index 2a8daf998..51e880465 100644 --- a/src/GuiQt/FiberSamplesOpenGLWidget.h +++ b/src/GuiQt/FiberSamplesOpenGLWidget.h @@ -21,7 +21,7 @@ */ /*LICENSE_END*/ -#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else #include @@ -37,7 +37,7 @@ namespace caret { class BrainOpenGLShapeRing; class BrainOpenGLShapeSphere; -#if WORKBENCH_USE_QT5_QOPENGL_WIDGET +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET class FiberSamplesOpenGLWidget : public QOpenGLWidget { #else class FiberSamplesOpenGLWidget : public QGLWidget { -- GitLab From a5497402c150ddb6916dce86bc21ed49ecc169e4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 30 Sep 2016 09:28:05 -0500 Subject: [PATCH 021/755] Added catchable CMAKE variables for enabling Qt5 and using Qt5's QOpenGLWidget (and not include Qt's OpenGL module) instead of the deprecated QGLWidget. --- src/Brain/BrainOpenGLFixedPipeline.h | 4 - src/CMakeLists.txt | 131 ++++++++++++++++----------- src/Desktop/CMakeLists.txt | 10 +- src/Desktop/desktop.cxx | 8 +- src/GuiQt/BrainOpenGLWidget.cxx | 2 +- src/GuiQt/BrainOpenGLWidget.h | 1 + 6 files changed, 93 insertions(+), 63 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index f27ea2f08..2401a11c2 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -40,10 +40,6 @@ #include "VolumeSliceViewPlaneEnum.h" #include "WholeBrainVoxelDrawingMode.h" - -class QGLWidget; -class QImage; - namespace caret { class AnnotationText; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 13dcd36a3..685cf4385 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,9 @@ MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") #TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options +set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries") +set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "If Qt 5.x is used, use QOpenGLWidget instead of deprecated QGLWidget") + # # Setting the compiler MUST be done before the PROJECT # statement or else an infinite loop will occur indicating @@ -85,6 +88,7 @@ SET(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "cause all build commands to be displ # # Allow support for C11X compiler +# May not need these, use CMAKE_CXX_STANDARD:UNINITIALIZED=11 # SET (WORKBENCH_C11X FALSE) ##SET (WORKBENCH_C11X TRUE) @@ -231,66 +235,83 @@ ENDIF(OPENSSL_FOUND) # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # -FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network OpenGL PrintSupport Test Widgets Xml) -IF (Qt5_FOUND) - MESSAGE("Found Qt 5") - IF (NOT Qt5Concurrent_FOUND) - STRING(APPEND moduleError "Qt5 Concurrentmodule not found\n") - ENDIF() - IF (NOT Qt5Core_FOUND) - STRING(APPEND moduleError "Qt5 Core module not found\n") - ENDIF() - IF (NOT Qt5Gui_FOUND) - STRING(APPEND moduleError "Qt5 Gui module not found\n") - ENDIF() - IF (NOT Qt5Network_FOUND) - STRING(APPEND moduleError "Qt5 Network module not found\n") - ENDIF() - IF (NOT Qt5OpenGL_FOUND) - STRING(APPEND moduleError "Qt5 OpenGL module not found\n") - ENDIF() - IF (NOT Qt5PrintSupport_FOUND) - STRING(APPEND moduleError "Qt5 Print Support module not found\n") - ENDIF() - IF (NOT Qt5Test_FOUND) - STRING(APPEND moduleError "Qt5 Test module not found\n") - ENDIF() - IF (NOT Qt5Widgets_FOUND) - STRING(APPEND moduleError "Qt5 Widgets module not found\n") - ENDIF() - IF (NOT Qt5Xml_FOUND) - STRING(APPEND moduleError "Qt5 XML module not found\n") - ENDIF() - IF (moduleError) - MESSAGE(FATAL_ERROR "Missing Modules\n" ${moduleError}) - ENDIF() - MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") -ELSE (Qt5_FOUND) - MESSAGE("Qt5 not found, looking for Qt4...") +IF (WORKBENCH_USE_QT5) + message("WORKBENCH_USE_QT5 defined") +ELSE () + message("WORKBENCH_USE_QT5 NOT defined") +ENDIF () + +IF (WORKBENCH_USE_QT5) + + # + # The OpenGL module is deprecated in Qt5 and + # is needed only if QGLWidget is used for + # the OpenGL graphics. + # + IF (NOT WORKBENCH_USE_QT5_QOPENGL_WIDGET) + SET(WB_QT_OPENGL_MODULE "OpenGL") + ENDIF () + + #FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network OpenGL PrintSupport Test Widgets Xml) + FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) + IF (Qt5_FOUND) + MESSAGE("Found Qt 5") + IF (NOT Qt5Concurrent_FOUND) + STRING(APPEND moduleError "Qt5 Concurrentmodule not found\n") + ENDIF() + IF (NOT Qt5Core_FOUND) + STRING(APPEND moduleError "Qt5 Core module not found\n") + ENDIF() + IF (NOT Qt5Gui_FOUND) + STRING(APPEND moduleError "Qt5 Gui module not found\n") + ENDIF() + IF (NOT Qt5Network_FOUND) + STRING(APPEND moduleError "Qt5 Network module not found\n") + ENDIF() + IF (NOT WORKBENCH_USE_QT5_QOPENGL_WIDGET) + IF (NOT Qt5OpenGL_FOUND) + STRING(APPEND moduleError "Qt5 OpenGL module not found\n") + ENDIF() + ENDIF () + IF (NOT Qt5PrintSupport_FOUND) + STRING(APPEND moduleError "Qt5 Print Support module not found\n") + ENDIF() + IF (NOT Qt5Test_FOUND) + STRING(APPEND moduleError "Qt5 Test module not found\n") + ENDIF() + IF (NOT Qt5Widgets_FOUND) + STRING(APPEND moduleError "Qt5 Widgets module not found\n") + ENDIF() + IF (NOT Qt5Xml_FOUND) + STRING(APPEND moduleError "Qt5 XML module not found\n") + ENDIF() + IF (moduleError) + MESSAGE(FATAL_ERROR "Missing Modules\n" ${moduleError}) + ENDIF() + + IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) + # + # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget + # + # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used + # for OpenGL. Otherwise, QGLWidget is used. + # + MESSAGE("Configuring to use QOpenGLWidget instead of deprecated QGLWidget") + add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) + ELSE () + MESSAGE("Configuring to use deprecated QGLWidget instead of new QOpenGLWidget") + ENDIF () + ELSE () + MESSAGE(FATAL_ERROR "Qt5 was required but not found") + ENDIF () +ELSE () FIND_PACKAGE(Qt4 4.8 REQUIRED) IF(QT4_FOUND) + INCLUDE(${QT_USE_FILE}) ELSE(QT4_FOUND) MESSAGE(FATAL_ERROR "QT4 not found") ENDIF(QT4_FOUND) -ENDIF (Qt5_FOUND) - -if(Qt5_FOUND) - # - # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget - # - # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used - # for OpenGL. Otherwise, QGLWidget is used. - # - add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) -endif() - - -# -# -# QT include files -# -IF (QT4_FOUND) - INCLUDE(${QT_USE_FILE}) + MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") ENDIF () # diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index c1f194e5b..c9a3ca4df 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -14,7 +14,9 @@ set (EXE_NAME wb_view) if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) - include_directories(${Qt5OpenGL_INCLUDE_DIRS}) + if(Qt5OpenGL_FOUND) + include_directories(${Qt5OpenGL_INCLUDE_DIRS}) + endif() include_directories(${Qt5Widgets_INCLUDE_DIRS}) endif() IF (QT4_FOUND) @@ -93,18 +95,22 @@ IF (NOT APPLE) ENDIF (UNIX) ENDIF (NOT APPLE) +if(Qt5OpenGL_FOUND) + set(QT5_OPENGL_LIB_NAME Qt5::OpenGL) +endif() if(Qt5_FOUND) set(QT5_LINK_LIBS Qt5::Concurrent Qt5::Core Qt5::Gui Qt5::Network - Qt5::OpenGL + ${QT5_OPENGL_LIB_NAME} Qt5::PrintSupport Qt5::Test Qt5::Widgets Qt5::Xml) endif() +message("*** QT5_LINK_LIBS: ${QT5_LINK_LIBS}") # # Libraries that are linked diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 388bea3b6..463d598cd 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -22,7 +22,9 @@ #include #include #include +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include +#endif #include #include #include @@ -428,6 +430,7 @@ main(int argc, char* argv[]) /* * Make sure OpenGL is available. */ +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET if (QGLFormat::hasOpenGL() == false) { QString msg = "This computer does not support OpenGL (3D graphics system).\n" "You will need to install OpenGL to run Workbench.\n" @@ -439,6 +442,7 @@ main(int argc, char* argv[]) return -1; } +#endif /* * Setup OpenGL if NOT using Qt 5's QOpenGLWidget @@ -642,13 +646,15 @@ main(int argc, char* argv[]) myState.sceneNameOrNumber); } +#ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET if (QGLPixelBuffer::hasOpenGLPbuffers()) { CaretLogConfig("OpenGL PBuffers are supported"); } else { CaretLogConfig("OpenGL PBuffers are NOT supported"); } - +#endif + /* * Log local (language, country) */ diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 274a744cb..76b62c496 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -234,7 +234,7 @@ BrainOpenGLWidget::initializeGL() CaretLogConfig(getOpenGLInformation()); if (s_defaultGLFormatInitialized == false) { - CaretLogSevere("PROGRAM ERROR: The default QGLFormat has not been set.\n" + CaretLogSevere("PROGRAM ERROR: The default OpenGL has not been set.\n" "Need to call BrainOpenGLWidget::initializeDefaultGLFormat() prior to " "instantiating an instance of this class."); } diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 84a33eccd..b3b7ce3ac 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -38,6 +38,7 @@ #include "EventListenerInterface.h" class QMouseEvent; +class QWidget; namespace caret { -- GitLab From 27fb94cf9ded0ee0fe7b3eee427504879bb3fc1a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 3 Oct 2016 14:33:44 -0500 Subject: [PATCH 022/755] Added usage of WuQtUtilities::setToolButtonStyleForQt5Mac() to tool buttons in the Annotate, Border, Foci, Image, View, and Volume toolbars. Also added to tool buttons on right edge of the toolbar. Updated WuQtUtilities::setToolButtonStyleForQt5Mac() to add a "checked" color to on/off tool buttons and a "pressed" color to tool buttons that are clicked. --- src/GuiQt/AnnotationColorWidget.cxx | 2 + src/GuiQt/AnnotationCoordinateWidget.cxx | 1 + src/GuiQt/AnnotationDeleteWidget.cxx | 1 + src/GuiQt/AnnotationFontWidget.cxx | 4 + src/GuiQt/AnnotationFormatWidget.cxx | 1 + src/GuiQt/AnnotationInsertNewWidget.cxx | 86 ++++++++++++------- src/GuiQt/AnnotationInsertNewWidget.h | 6 +- src/GuiQt/AnnotationLineArrowTipsWidget.cxx | 2 + src/GuiQt/AnnotationRedoUndoWidget.cxx | 2 + src/GuiQt/AnnotationTextAlignmentWidget.cxx | 2 + src/GuiQt/AnnotationTextOrientationWidget.cxx | 1 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 10 ++- src/GuiQt/UserInputModeBordersWidget.cxx | 11 +++ src/GuiQt/UserInputModeFociWidget.cxx | 4 + src/GuiQt/UserInputModeImageWidget.cxx | 5 +- src/GuiQt/UserInputModeVolumeEditWidget.cxx | 8 ++ src/GuiQt/WuQtUtilities.cxx | 64 +++++++++++--- 17 files changed, 165 insertions(+), 45 deletions(-) diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index f95c592f3..c9a926151 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -107,6 +107,7 @@ m_browserWindowIndex(browserWindowIndex) m_backgroundToolButton = new QToolButton(); m_backgroundToolButton->setDefaultAction(m_backgroundColorAction); m_backgroundToolButton->setIconSize(toolButtonSize); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_backgroundToolButton); /* * Widget/object group for background widgets @@ -134,6 +135,7 @@ m_browserWindowIndex(browserWindowIndex) m_lineToolButton = new QToolButton(); m_lineToolButton->setDefaultAction(m_lineColorAction); m_lineToolButton->setIconSize(toolButtonSize); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_lineToolButton); /* * Line thickness diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 360c45c30..adc97d60d 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -175,6 +175,7 @@ m_browserWindowIndex(browserWindowIndex) this, SLOT(setCoordinateActionTriggered())); setCoordinateToolButton->setDefaultAction(setCoordinateAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(setCoordinateToolButton); } m_surfaceWidget = new QWidget(); diff --git a/src/GuiQt/AnnotationDeleteWidget.cxx b/src/GuiQt/AnnotationDeleteWidget.cxx index e82d39410..1f5f9f63c 100644 --- a/src/GuiQt/AnnotationDeleteWidget.cxx +++ b/src/GuiQt/AnnotationDeleteWidget.cxx @@ -136,6 +136,7 @@ AnnotationDeleteWidget::createDeleteToolButton() toolButton->setIconSize(pixmap.size()); toolButton->setDefaultAction(m_deleteToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index e07e3f585..d12454407 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -136,6 +136,7 @@ m_browserWindowIndex(browserWindowIndex) m_textColorToolButton = new QToolButton(); m_textColorToolButton->setDefaultAction(m_textColorAction); m_textColorToolButton->setIconSize(toolButtonSize); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_textColorToolButton); QToolButton* boldFontToolButton = NULL; QToolButton* italicFontToolButton = NULL; @@ -155,6 +156,7 @@ m_browserWindowIndex(browserWindowIndex) m_boldFontAction->setCheckable(true); boldFontToolButton = new QToolButton(); boldFontToolButton->setDefaultAction(m_boldFontAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(boldFontToolButton); /* * Change the bold toolbutton's font to bold. @@ -171,6 +173,7 @@ m_browserWindowIndex(browserWindowIndex) m_italicFontAction->setCheckable(true); italicFontToolButton = new QToolButton(); italicFontToolButton->setDefaultAction(m_italicFontAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(italicFontToolButton); /* * Change the italic toolbutton's font to italic. @@ -187,6 +190,7 @@ m_browserWindowIndex(browserWindowIndex) m_underlineFontAction->setCheckable(true); underlineFontToolButton = new QToolButton(); underlineFontToolButton->setDefaultAction(m_underlineFontAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(underlineFontToolButton); /* * Change the underline toolbutton's font to underline. diff --git a/src/GuiQt/AnnotationFormatWidget.cxx b/src/GuiQt/AnnotationFormatWidget.cxx index 3e200f4d5..908a5cd06 100644 --- a/src/GuiQt/AnnotationFormatWidget.cxx +++ b/src/GuiQt/AnnotationFormatWidget.cxx @@ -98,6 +98,7 @@ AnnotationFormatWidget::createArrangeMenuToolButton() QToolButton* arrangeToolButton = new QToolButton(); arrangeToolButton->setDefaultAction(arrangeAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(arrangeToolButton); return arrangeToolButton; } diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index 294825881..cdfeb212a 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -72,16 +72,37 @@ AnnotationInsertNewWidget::AnnotationInsertNewWidget(const int32_t browserWindow : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { - QToolButton* shapeBoxToolButton = createShapeToolButton(AnnotationTypeEnum::BOX); - QToolButton* shapeImageToolButton = createShapeToolButton(AnnotationTypeEnum::IMAGE); - QToolButton* shapeLineToolButton = createShapeToolButton(AnnotationTypeEnum::LINE); - QToolButton* shapeOvalToolButton = createShapeToolButton(AnnotationTypeEnum::OVAL); - QToolButton* shapeTextToolButton = createShapeToolButton(AnnotationTypeEnum::TEXT); + /* + * Shape buttons + */ + m_shapeActionGroup = new QActionGroup(this); + QToolButton* shapeBoxToolButton = createShapeToolButton(AnnotationTypeEnum::BOX, + m_shapeActionGroup); + QToolButton* shapeImageToolButton = createShapeToolButton(AnnotationTypeEnum::IMAGE, + m_shapeActionGroup); + QToolButton* shapeLineToolButton = createShapeToolButton(AnnotationTypeEnum::LINE, + m_shapeActionGroup); + QToolButton* shapeOvalToolButton = createShapeToolButton(AnnotationTypeEnum::OVAL, + m_shapeActionGroup); + QToolButton* shapeTextToolButton = createShapeToolButton(AnnotationTypeEnum::TEXT, + m_shapeActionGroup); + QObject::connect(m_shapeActionGroup, SIGNAL(triggered(QAction*)), + this, SLOT(spaceOrShapeActionTriggered())); - QToolButton* tabSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::TAB); - QToolButton* stereotaxicSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::STEREOTAXIC); - QToolButton* surfaceSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SURFACE); - QToolButton* windowSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::WINDOW); + /* + * Space buttons + */ + m_spaceActionGroup = new QActionGroup(this); + QToolButton* tabSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::TAB, + m_spaceActionGroup); + QToolButton* stereotaxicSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::STEREOTAXIC, + m_spaceActionGroup); + QToolButton* surfaceSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SURFACE, + m_spaceActionGroup); + QToolButton* windowSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::WINDOW, + m_spaceActionGroup); + QObject::connect(m_spaceActionGroup, SIGNAL(triggered(QAction*)), + this, SLOT(spaceOrShapeActionTriggered())); const bool smallButtonsFlag = false; if (smallButtonsFlag) { @@ -100,26 +121,8 @@ m_browserWindowIndex(browserWindowIndex) windowSpaceToolButton->setMaximumSize(mw, mh); } - m_spaceActionGroup = new QActionGroup(this); - m_spaceActionGroup->addAction(tabSpaceToolButton->defaultAction()); - m_spaceActionGroup->addAction(stereotaxicSpaceToolButton->defaultAction()); - m_spaceActionGroup->addAction(surfaceSpaceToolButton->defaultAction()); - m_spaceActionGroup->addAction(windowSpaceToolButton->defaultAction()); - QObject::connect(m_spaceActionGroup, SIGNAL(triggered(QAction*)), - this, SLOT(spaceOrShapeActionTriggered())); - - m_shapeActionGroup = new QActionGroup(this); - m_shapeActionGroup->addAction(shapeBoxToolButton->defaultAction()); - m_shapeActionGroup->addAction(shapeImageToolButton->defaultAction()); - m_shapeActionGroup->addAction(shapeLineToolButton->defaultAction()); - m_shapeActionGroup->addAction(shapeOvalToolButton->defaultAction()); - m_shapeActionGroup->addAction(shapeTextToolButton->defaultAction()); - QObject::connect(m_shapeActionGroup, SIGNAL(triggered(QAction*)), - this, SLOT(spaceOrShapeActionTriggered())); - QToolButton* fileSelectionToolButton = createFileSelectionToolButton(); - QLabel* fileLabel = new QLabel("File"); QLabel* spaceLabel = new QLabel("Space"); QLabel* typeLabel = new QLabel("Type"); @@ -286,6 +289,7 @@ AnnotationInsertNewWidget::createFileSelectionToolButton() QToolButton* fileSelectionToolButton = new QToolButton(); fileSelectionToolButton->setDefaultAction(m_fileSelectionToolButtonAction); fileSelectionToolButton->setFixedWidth(fileSelectionToolButton->sizeHint().width()); + WuQtUtilities::setToolButtonStyleForQt5Mac(fileSelectionToolButton); return fileSelectionToolButton; } @@ -295,9 +299,12 @@ AnnotationInsertNewWidget::createFileSelectionToolButton() * * @param annotationType * The annotation type. + * @param actionGroup + * Action group to which button is added to make button exclusive. */ QToolButton* -AnnotationInsertNewWidget::createShapeToolButton(const AnnotationTypeEnum::Enum annotationType) +AnnotationInsertNewWidget::createShapeToolButton(const AnnotationTypeEnum::Enum annotationType, + QActionGroup* actionGroup) { const QString typeGuiName = AnnotationTypeEnum::toGuiName(annotationType); QToolButton* toolButton = new QToolButton(); @@ -317,6 +324,13 @@ AnnotationInsertNewWidget::createShapeToolButton(const AnnotationTypeEnum::Enum toolButton->setDefaultAction(action); + /* + * Must set style AFTER button is added to action group + * so that checked property is enabled for button + */ + actionGroup->addAction(action); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); + return toolButton; } @@ -470,9 +484,12 @@ AnnotationInsertNewWidget::createShapePixmap(const QWidget* widget, * * @param annotationSpace * The annotation space + * @param actionGroup + * Action group to which button is added to make button exclusive. */ QToolButton* -AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace) +AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace, + QActionGroup* actionGroup) { switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::PIXELS: @@ -504,11 +521,18 @@ AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpace action->setData((int)AnnotationCoordinateSpaceEnum::toIntegerCode(annotationSpace)); action->setToolTip(AnnotationCoordinateSpaceEnum::toToolTip(annotationSpace)); - toolButton->setDefaultAction(action); - action->setCheckable(true); action->setChecked(false); + toolButton->setDefaultAction(action); + + /* + * Must set style AFTER button is added to action group + * so that checked property is enabled for button + */ + actionGroup->addAction(action); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); + return toolButton; } diff --git a/src/GuiQt/AnnotationInsertNewWidget.h b/src/GuiQt/AnnotationInsertNewWidget.h index 5b3ff7967..e70989639 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.h +++ b/src/GuiQt/AnnotationInsertNewWidget.h @@ -58,9 +58,11 @@ namespace caret { AnnotationInsertNewWidget& operator=(const AnnotationInsertNewWidget&); - QToolButton* createShapeToolButton(const AnnotationTypeEnum::Enum annotationType); + QToolButton* createShapeToolButton(const AnnotationTypeEnum::Enum annotationType, + QActionGroup* actionGroup); - QToolButton* createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace); + QToolButton* createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace, + QActionGroup* actionGroup); QPixmap createShapePixmap(const QWidget* widget, const AnnotationTypeEnum::Enum annotationType); diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index ab187b9cb..5af9f8583 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -68,6 +68,7 @@ m_browserWindowIndex(browserWindowIndex) m_endArrowToolButton->setFixedSize(toolButtonSize); QObject::connect(m_endArrowToolButton, SIGNAL(clicked(bool)), this, SLOT(endArrowTipActionToggled())); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_endArrowToolButton); m_startArrowToolButton = new QToolButton(); m_startArrowToolButton->setArrowType(Qt::UpArrow); @@ -76,6 +77,7 @@ m_browserWindowIndex(browserWindowIndex) m_startArrowToolButton->setFixedSize(toolButtonSize); QObject::connect(m_startArrowToolButton, SIGNAL(clicked(bool)), this, SLOT(startArrowTipActionToggled())); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_startArrowToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); diff --git a/src/GuiQt/AnnotationRedoUndoWidget.cxx b/src/GuiQt/AnnotationRedoUndoWidget.cxx index 5801bed6a..3b7519b67 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.cxx +++ b/src/GuiQt/AnnotationRedoUndoWidget.cxx @@ -65,6 +65,7 @@ m_browserWindowIndex(browserWindowIndex) SLOT(redoActionTriggered())); QToolButton* redoToolButton = new QToolButton(); redoToolButton->setDefaultAction(m_redoAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(redoToolButton); m_undoAction = WuQtUtilities::createAction("Undo", "Undo ToolTip", @@ -73,6 +74,7 @@ m_browserWindowIndex(browserWindowIndex) SLOT(undoActionTriggered())); QToolButton* undoToolButton = new QToolButton(); undoToolButton->setDefaultAction(m_undoAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.cxx b/src/GuiQt/AnnotationTextAlignmentWidget.cxx index 70d472bef..32e7ce5cc 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.cxx +++ b/src/GuiQt/AnnotationTextAlignmentWidget.cxx @@ -379,6 +379,7 @@ AnnotationTextAlignmentWidget::createHorizontalAlignmentToolButton(const Annotat action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } @@ -418,6 +419,7 @@ AnnotationTextAlignmentWidget::createVerticalAlignmentToolButton(const Annotatio action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index 3d4ae3ea8..e78f55d85 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -228,6 +228,7 @@ AnnotationTextOrientationWidget::createOrientationToolButton(const AnnotationTex action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index d1c51bd70..8fb47425b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -144,7 +144,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QAction* windowAspectRatioLockedAction, QAction* tabAspectRatioLockedAction, BrainBrowserWindow* parentBrainBrowserWindow) -: QToolBar(0) //parentBrainBrowserWindow) +: QToolBar(parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; this->updateCounter = 0; @@ -299,6 +299,14 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow overlayToolBoxToolButton, layersToolBoxToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(helpDialogToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(informationDialogToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(identifyDialogToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(sceneDialogToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolBarToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(overlayToolBoxToolButton); + WuQtUtilities::setToolButtonStyleForQt5Mac(layersToolBoxToolButton); + /* * Tab bar and controls at far right side of toolbar */ diff --git a/src/GuiQt/UserInputModeBordersWidget.cxx b/src/GuiQt/UserInputModeBordersWidget.cxx index 52fff6731..c9f718fa5 100644 --- a/src/GuiQt/UserInputModeBordersWidget.cxx +++ b/src/GuiQt/UserInputModeBordersWidget.cxx @@ -284,6 +284,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() drawAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_CREATE)); QToolButton* drawToolButton = new QToolButton(); drawToolButton->setDefaultAction(drawAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(drawToolButton); /* * Erase @@ -301,6 +302,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() eraseAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_ERASE)); QToolButton* eraseToolButton = new QToolButton(); eraseToolButton->setDefaultAction(eraseAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(eraseToolButton); /* * Extend @@ -322,6 +324,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() extendAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_EXTEND)); QToolButton* extendToolButton = new QToolButton(); extendToolButton->setDefaultAction(extendAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(extendToolButton); /* * Replace @@ -343,6 +346,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() replaceAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_REPLACE)); QToolButton* replaceToolButton = new QToolButton(); replaceToolButton->setDefaultAction(replaceAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(replaceToolButton); /* * Optimize @@ -357,6 +361,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() optimizeAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_OPTIMIZE)); QToolButton* optimizeToolButton = new QToolButton(); optimizeToolButton->setDefaultAction(optimizeAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(optimizeToolButton); /* * Finish @@ -371,6 +376,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() SLOT(drawFinishButtonClicked())); QToolButton* finishToolButton = new QToolButton(); finishToolButton->setDefaultAction(finishAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(finishToolButton); /* * Undo @@ -388,6 +394,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() undoToolButton->setAutoRepeat(true); undoToolButton->setAutoRepeatDelay(500); // 500ms = 1/2 second undoToolButton->setAutoRepeatInterval(100); // 100ms = 1/10 second + WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QAction* undoFinishAction = WuQtUtilities::createAction("Undo Finish", @@ -398,6 +405,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() SLOT(drawUndoLastEditButtonClicked())); m_undoFinishToolButton = new QToolButton(); m_undoFinishToolButton->setDefaultAction(undoFinishAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_undoFinishToolButton); /* * Reset @@ -409,6 +417,7 @@ UserInputModeBordersWidget::createDrawOperationWidget() SLOT(drawResetButtonClicked())); QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(resetAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); this->drawOperationActionGroup = new QActionGroup(this); this->drawOperationActionGroup->addAction(drawAction); @@ -988,6 +997,7 @@ UserInputModeBordersWidget::createEditOperationWidget() deleteAction->setData(static_cast(UserInputModeBorders::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); const AString propertiesToolTipText = ("A dialog for editing a border's properties is displayed by " "clicking any point in a border." @@ -999,6 +1009,7 @@ UserInputModeBordersWidget::createEditOperationWidget() propertiesAction->setData(static_cast(UserInputModeBorders::EDIT_OPERATION_PROPERTIES)); QToolButton* propertiesToolButton = new QToolButton(); propertiesToolButton->setDefaultAction(propertiesAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(propertiesToolButton); this->editOperationActionGroup = new QActionGroup(this); this->editOperationActionGroup->addAction(deleteAction); diff --git a/src/GuiQt/UserInputModeFociWidget.cxx b/src/GuiQt/UserInputModeFociWidget.cxx index 1782b84c1..82da5b06a 100644 --- a/src/GuiQt/UserInputModeFociWidget.cxx +++ b/src/GuiQt/UserInputModeFociWidget.cxx @@ -233,6 +233,7 @@ UserInputModeFociWidget::createCreateOperationWidget() SLOT(createNewFocusActionTriggered())); QToolButton* newFocusToolButton = new QToolButton(); newFocusToolButton->setDefaultAction(newFocusAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(newFocusToolButton); const AString lastIDToolTipText = ("Press this button to display a dialog for creating a new focus " "with the focus' coordinates set to the stereotaxic location of the " @@ -246,6 +247,7 @@ UserInputModeFociWidget::createCreateOperationWidget() SLOT(createLastIdentificationFocusActionTriggered())); QToolButton* lastIdFocusToolButton = new QToolButton(); lastIdFocusToolButton->setDefaultAction(lastIdFocusAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(lastIdFocusToolButton); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); @@ -391,6 +393,7 @@ UserInputModeFociWidget::createEditOperationWidget() deleteAction->setData(static_cast(UserInputModeFoci::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); const AString propertiesToolTipText = ("Click the mouse over a focus to display a dialog " "for editing the focus' properties." @@ -402,6 +405,7 @@ UserInputModeFociWidget::createEditOperationWidget() propertiesAction->setData(static_cast(UserInputModeFoci::EDIT_OPERATION_PROPERTIES)); QToolButton* propertiesToolButton = new QToolButton(); propertiesToolButton->setDefaultAction(propertiesAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(propertiesToolButton); m_editOperationActionGroup = new QActionGroup(this); m_editOperationActionGroup->addAction(deleteAction); diff --git a/src/GuiQt/UserInputModeImageWidget.cxx b/src/GuiQt/UserInputModeImageWidget.cxx index 69a2895e9..7a1690aa5 100644 --- a/src/GuiQt/UserInputModeImageWidget.cxx +++ b/src/GuiQt/UserInputModeImageWidget.cxx @@ -169,6 +169,7 @@ UserInputModeImageWidget::createEditOperationWidget() addAction->setData(static_cast(UserInputModeImage::EDIT_OPERATION_ADD)); QToolButton* addToolButton = new QToolButton(); addToolButton->setDefaultAction(addAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(addToolButton); /* * Delete button @@ -182,6 +183,7 @@ UserInputModeImageWidget::createEditOperationWidget() deleteAction->setData(static_cast(UserInputModeImage::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); /* * Action group to make add/delete actions mutually exclusive @@ -205,6 +207,7 @@ UserInputModeImageWidget::createEditOperationWidget() convertAction->setCheckable(false); m_convertToolButton = new QToolButton(); m_convertToolButton->setDefaultAction(convertAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_convertToolButton); /* * Delete all button @@ -218,7 +221,7 @@ UserInputModeImageWidget::createEditOperationWidget() deleteAllAction->setCheckable(false); m_deleteAllToolButton = new QToolButton(); m_deleteAllToolButton->setDefaultAction(deleteAllAction); - + WuQtUtilities::setToolButtonStyleForQt5Mac(m_deleteAllToolButton); QWidget* widget = new QWidget(); diff --git a/src/GuiQt/UserInputModeVolumeEditWidget.cxx b/src/GuiQt/UserInputModeVolumeEditWidget.cxx index 104ecc83a..cf2a18e7d 100644 --- a/src/GuiQt/UserInputModeVolumeEditWidget.cxx +++ b/src/GuiQt/UserInputModeVolumeEditWidget.cxx @@ -236,6 +236,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() "Create a new volume file that will become the top-most overlay", this, this, SLOT(newFileActionTriggered()))); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_newFileToolButton); m_addMapsToolButton = new QToolButton(); m_addMapsToolButton->setDefaultAction(WuQtUtilities::createAction("Add", @@ -243,6 +244,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() "First new map will become the top-most overlay."), this, this, SLOT(addMapsActionTriggered()))); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_addMapsToolButton); m_lockAction = WuQtUtilities::createAction("Lock", "Lock/unlock volume file to disallow/allow editing", @@ -251,6 +253,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() m_lockAction->setCheckable(true); QToolButton* lockFileToolButton = new QToolButton(); lockFileToolButton->setDefaultAction(m_lockAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(lockFileToolButton); QLabel* editLabel = new QLabel("Edit:"); @@ -260,6 +263,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() "Undo the last volume edit", this, this, SLOT(undoActionTriggered()))); + WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QToolButton* redoToolButton = new QToolButton(); @@ -267,6 +271,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() "Redo (or is it undo) the last undo", this, this, SLOT(redoActionTriggered()))); + WuQtUtilities::setToolButtonStyleForQt5Mac(redoToolButton); QToolButton* resetToolButton = new QToolButton(); @@ -274,6 +279,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() "Reset all edting of the volume", this, this, SLOT(resetActionTriggered()))); + WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); QLabel* brushSizeLabel = new QLabel("Brush Size:"); const int MIN_BRUSH_SIZE = 1; @@ -313,6 +319,7 @@ UserInputModeVolumeEditWidget::createSelectionToolBar() this, SLOT(labelValueActionTriggered())); m_voxelLabelValueToolButton = new QToolButton(); m_voxelLabelValueToolButton->setDefaultAction(m_voxelLabelValueAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_voxelLabelValueToolButton); const int SPACE = 10; QWidget* widget = new QWidget(); @@ -386,6 +393,7 @@ UserInputModeVolumeEditWidget::createModeToolBar() QToolButton* toolButton = new QToolButton(); toolButton->setDefaultAction(action); + WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); layout->addWidget(toolButton); } diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 1d438358f..ec311ceb2 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1402,12 +1402,25 @@ WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) { #ifdef CARET_OS_MACOSX #if QT_VERSION >= 0x050000 + bool hasMenuFlag = false; + bool hasCheckableFlag = false; + QAction* action = toolButton->defaultAction(); + if (action != NULL) { + if (action->menu() != NULL) { + hasMenuFlag = true; + } + if (action->isCheckable()) { + hasCheckableFlag = true; + } + } + const QPalette palette = toolButton->palette(); const QPalette::ColorRole backgroundRole = toolButton->backgroundRole(); const QBrush backgroundBrush = palette.brush(backgroundRole); const QColor backgroundColor = backgroundBrush.color(); const QColor lighterColor = backgroundColor.lighter(100); const QColor darkerColor = backgroundColor.darker(125); + const QColor slightlyDarkerColor = backgroundColor.darker(115); /* * Use a stylesheet to: @@ -1415,17 +1428,48 @@ WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) * (2) Add a border around the button that is slightly * darker than the background. */ - const QString toolButtonStyleSheet(" QToolButton { " - " background: " + lighterColor.name() + "; " - " border-style: solid; " - " border-width: 1px; " - " border-color: " + darkerColor.name() + "; " - " padding-top: 1px; " - " padding-bottom: 1px; " - " padding-right: 3px; " - " padding-left: 3px; " - " }"); + QString toolButtonStyleSheet(" QToolButton { " + " background: " + lighterColor.name() + "; "); + if (hasMenuFlag) { +// toolButtonStyleSheet.append(" border-style: solid; " +// " border-width: 1px; " +// " border-color: " + darkerColor.name() + "; " +// " padding-top: 6px; " +// " padding-bottom: 6px; " +// " padding-right: 4px; " +// " padding-left: 3px; "); + } + else { + toolButtonStyleSheet.append(" border-style: solid; " + " border-width: 1px; " + " border-color: " + darkerColor.name() + "; " + " padding-top: 2px; " + " padding-bottom: 2px; " + " padding-right: 3px; " + " padding-left: 3px; "); + } + toolButtonStyleSheet.append(" } "); + + if (hasCheckableFlag) { + /* + * Background color when button is "checked" + */ + toolButtonStyleSheet.append(" QToolButton:checked { " + " background-color: " + slightlyDarkerColor.name() + "; " + " } "); + } + else { + /* + * Background color when button is "pressed" + */ + toolButtonStyleSheet.append(" QToolButton:pressed { " + " background-color: " + slightlyDarkerColor.name() + "; " + " } "); + } + toolButton->setStyleSheet(toolButtonStyleSheet); + + //std::cout << qPrintable(toolButton->text() + " " + toolButtonStyleSheet + "\n\n"); #endif #endif } -- GitLab From 63ddb73f9d4049a925923ef14f3d9f46c911ff42 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 4 Oct 2016 14:29:03 -0500 Subject: [PATCH 023/755] When using Qt 5's QOpenGLWidget (a replacement for QGLWidget), flashing and transparent/strange graphics were seen after an identification operation and in particular, after annotation identification. Identification is performed by encoding color information into the OpenGL color buffer. Apparently, this color information remains displayed after an identification operation. Now, after an identification operation is performed, a call is made to QOpenGLWidget::repaint() to redraw the graphics region. This seems to update the frame buffer into which QOpenGLWidget draws into and thus corrects the problem with strange looking graphics after an identification operation. --- src/GuiQt/BrainOpenGLWidget.cxx | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 76b62c496..8c61fe19e 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1083,6 +1083,21 @@ BrainOpenGLWidget::performIdentification(const int x, y, applySelectionBackgroundFiltering); } + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation) so + * there is no "back" or "front buffer". Since + * identification is encoded in the framebuffer, + * it is necessary to repaint (udpates graphics + * immediately) to redraw the models. Otherwise, + * the graphics flash with strange looking drawing. + */ + this->repaint(); + this->doneCurrent(); +#endif + return idManager; } @@ -1128,6 +1143,20 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, y, true); } + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation) so + * there is no "back" or "front buffer". Since + * identification is encoded in the framebuffer, + * it is necessary to repaint (udpates graphics + * immediately) to redraw the models. Otherwise, + * the graphics flash with strange looking drawing. + */ + this->repaint(); + this->doneCurrent(); +#endif return annotationID; } @@ -1176,6 +1205,21 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi y, true); } + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation) so + * there is no "back" or "front buffer". Since + * identification is encoded in the framebuffer, + * it is necessary to repaint (udpates graphics + * immediately) to redraw the models. Otherwise, + * the graphics flash with strange looking drawing. + */ + this->repaint(); + this->doneCurrent(); +#endif + return idManager; } @@ -1214,6 +1258,20 @@ BrainOpenGLWidget::performProjection(const int x, y, projectionOut); } + +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* + * Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation) so + * there is no "back" or "front buffer". Since + * identification is encoded in the framebuffer, + * it is necessary to repaint (udpates graphics + * immediately) to redraw the models. Otherwise, + * the graphics flash with strange looking drawing. + */ + this->repaint(); + this->doneCurrent(); +#endif } /** -- GitLab From 363abb053a803d3f0a0cae22c959bf2ca7fea747 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Oct 2016 15:17:25 -0500 Subject: [PATCH 024/755] Added cached variable WORKBENCH_QT5_DEPRECATED_FATAL_ERROR to src/CMakeLists.txt. When WORKBENCH_QT5_DEPRECATED_FATAL_ERROR is TRUE, a compiler definition (WORKBENCH_REPLACE_QT_DEPRECATED) is used with #ifdef/#else/#endif in the source code to allow usage of methods that replace the obsolete functions. Examples include using std::sort() in place of qSort() and QDateTime::setOffsetFromUtc() in place of QDateTime::setUtcOffset(). --- src/CMakeLists.txt | 9 +++++++++ src/GuiQt/BrainOpenGLWidget.cxx | 5 +++++ src/Quazip/quazipdir.cpp | 5 +++++ src/Qwt/qwt_clipper.cpp | 5 +++++ src/Qwt/qwt_date.cpp | 4 ++++ src/Qwt/qwt_date_scale_draw.cpp | 4 ++++ src/Qwt/qwt_date_scale_engine.cpp | 15 +++++++++++++++ src/Qwt/qwt_plot_dict.cpp | 13 +++++++++++-- src/Qwt/qwt_plot_spectrogram.cpp | 8 +++++++- 9 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 685cf4385..f0d628353 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,7 @@ MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") #TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options +set (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR FALSE CACHE BOOL "If TRUE, produce fatal compiler error for Qt 5 deprecated functionality") set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries") set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "If Qt 5.x is used, use QOpenGLWidget instead of deprecated QGLWidget") @@ -301,6 +302,14 @@ IF (WORKBENCH_USE_QT5) ELSE () MESSAGE("Configuring to use deprecated QGLWidget instead of new QOpenGLWidget") ENDIF () + + IF (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR) + # Causes Qt to remove declarations for deprecated functionality + add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700) + # Enable usage of replacements for Qt deprecated functionality in Workbench source code + add_definitions(-DWORKBENCH_REPLACE_QT_DEPRECATED) + ENDIF () + ELSE () MESSAGE(FATAL_ERROR "Qt5 was required but not found") ENDIF () diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 8c61fe19e..6b4cee881 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -341,11 +341,16 @@ BrainOpenGLWidget::getOpenGLInformation() #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS int32_t numVertexBuffers = 0; +#ifdef GL_VERSION_2_0 + /* + * Note: glIsBuffer() was added to OpenGL 2.0 + */ for (GLuint iBuff = 1; iBuff < 1000; iBuff++) { if (glIsBuffer(iBuff)) { numVertexBuffers++; } } +#endif // GL_VERSION_2_0 info += ("\nAt least " + AString::number(numVertexBuffers) + " vertex buffers are allocated"); diff --git a/src/Quazip/quazipdir.cpp b/src/Quazip/quazipdir.cpp index d75075e27..ba215da80 100644 --- a/src/Quazip/quazipdir.cpp +++ b/src/Quazip/quazipdir.cpp @@ -1,3 +1,4 @@ +#include #include "quazipdir.h" #include @@ -356,7 +357,11 @@ bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, == Qt::CaseInsensitive) srt |= QDir::IgnoreCase; QuaZipDirComparator lessThan(srt); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + std::sort(list.begin(), list.end(), lessThan); +#else qSort(list.begin(), list.end(), lessThan); +#endif } QuaZipDir_convertInfoList(list, result); return true; diff --git a/src/Qwt/qwt_clipper.cpp b/src/Qwt/qwt_clipper.cpp index 51614aa37..c826e7fb4 100644 --- a/src/Qwt/qwt_clipper.cpp +++ b/src/Qwt/qwt_clipper.cpp @@ -7,6 +7,7 @@ * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ +#include #include "qwt_clipper.h" #include "qwt_point_polar.h" #include @@ -351,7 +352,11 @@ QVector QwtCircleClipper::clipCircle( QList angles; for ( int i = 0; i < points.size(); i++ ) angles += toAngle( pos, points[i] ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + std::sort(angles.begin(), angles.end()); +#else qSort( angles ); +#endif const int in = d_rect.contains( qwtPolar2Pos( pos, radius, angles[0] + ( angles[1] - angles[0] ) / 2 ) ); diff --git a/src/Qwt/qwt_date.cpp b/src/Qwt/qwt_date.cpp index 6235426b0..3bb0f8526 100644 --- a/src/Qwt/qwt_date.cpp +++ b/src/Qwt/qwt_date.cpp @@ -614,7 +614,11 @@ int QwtDate::utcOffset( const QDateTime &dateTime ) } case Qt::OffsetFromUTC: { +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + seconds = dateTime.offsetFromUtc(); +#else seconds = dateTime.utcOffset(); +#endif } default: { diff --git a/src/Qwt/qwt_date_scale_draw.cpp b/src/Qwt/qwt_date_scale_draw.cpp index cebde7b30..4ef95e632 100644 --- a/src/Qwt/qwt_date_scale_draw.cpp +++ b/src/Qwt/qwt_date_scale_draw.cpp @@ -271,7 +271,11 @@ QDateTime QwtDateScaleDraw::toDateTime( double value ) const if ( d_data->timeSpec == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + dt.setOffsetFromUtc( d_data->utcOffset ); +#else dt.setUtcOffset( d_data->utcOffset ); +#endif } return dt; diff --git a/src/Qwt/qwt_date_scale_engine.cpp b/src/Qwt/qwt_date_scale_engine.cpp index 0c368a94c..c16534c00 100644 --- a/src/Qwt/qwt_date_scale_engine.cpp +++ b/src/Qwt/qwt_date_scale_engine.cpp @@ -1117,7 +1117,12 @@ QDateTime QwtDateScaleEngine::alignDate( if ( dateTime.timeSpec() == Qt::OffsetFromUTC ) { + dt = dt.addSecs( d_data->utcOffset ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + dt.setOffsetFromUtc( 0 ); +#else dt.setUtcOffset( 0 ); +#endif } switch( intervalType ) @@ -1275,7 +1280,12 @@ QDateTime QwtDateScaleEngine::alignDate( if ( dateTime.timeSpec() == Qt::OffsetFromUTC ) { + dt = dt.addSecs( d_data->utcOffset ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + dt.setOffsetFromUtc( dateTime.offsetFromUtc() ); +#else dt.setUtcOffset( dateTime.utcOffset() ); +#endif } return dt; @@ -1303,7 +1313,12 @@ QDateTime QwtDateScaleEngine::toDateTime( double value ) const if ( d_data->timeSpec == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); + dt = dt.addSecs( d_data->utcOffset ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + dt.setOffsetFromUtc( d_data->utcOffset ); +#else dt.setUtcOffset( d_data->utcOffset ); +#endif } return dt; diff --git a/src/Qwt/qwt_plot_dict.cpp b/src/Qwt/qwt_plot_dict.cpp index 17c61ed47..4e2e08a77 100644 --- a/src/Qwt/qwt_plot_dict.cpp +++ b/src/Qwt/qwt_plot_dict.cpp @@ -7,6 +7,7 @@ * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ +#include #include "qwt_plot_dict.h" class QwtPlotDict::PrivateData @@ -22,7 +23,11 @@ public: return; QList::iterator it = - qUpperBound( begin(), end(), item, LessZThan() ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + std::upper_bound( begin(), end(), item, LessZThan() ); +#else + qUpperBound( begin(), end(), item, LessZThan() ); +#endif insert( it, item ); } @@ -32,7 +37,11 @@ public: return; QList::iterator it = - qLowerBound( begin(), end(), item, LessZThan() ); +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + std::lower_bound( begin(), end(), item, LessZThan() ); +#else + qLowerBound( begin(), end(), item, LessZThan() ); +#endif for ( ; it != end(); ++it ) { diff --git a/src/Qwt/qwt_plot_spectrogram.cpp b/src/Qwt/qwt_plot_spectrogram.cpp index e7a9fecc7..bab844c75 100644 --- a/src/Qwt/qwt_plot_spectrogram.cpp +++ b/src/Qwt/qwt_plot_spectrogram.cpp @@ -7,6 +7,8 @@ * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ +#include + #include "qwt_plot_spectrogram.h" #include "qwt_painter.h" #include "qwt_interval.h" @@ -286,8 +288,12 @@ bool QwtPlotSpectrogram::testConrecFlag( void QwtPlotSpectrogram::setContourLevels( const QList &levels ) { d_data->contourLevels = levels; +#ifdef WORKBENCH_REPLACE_QT_DEPRECATED + std::sort(d_data->contourLevels.begin(), d_data->contourLevels.end()); +#else qSort( d_data->contourLevels ); - +#endif + legendChanged(); itemChanged(); } -- GitLab From b3adc7281e17b447f39213d3a3d5c25a1871ce03 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 7 Oct 2016 15:25:10 -0500 Subject: [PATCH 025/755] Updated documentation of CMakeLists.txt's WORKBENCH_USE_QT5 to indicate that it must be passed as a command line parameter to cmake. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0d628353..b2c0c5340 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") #TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options set (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR FALSE CACHE BOOL "If TRUE, produce fatal compiler error for Qt 5 deprecated functionality") -set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries") +set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries. Must be passed as an argument to CMake: cmake -DWORKBENCH_USE_QT5=TRUE ") set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "If Qt 5.x is used, use QOpenGLWidget instead of deprecated QGLWidget") # -- GitLab From b5e05274c25c842b358df0b5961a2eccdad619f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 13 Oct 2016 12:36:29 -0500 Subject: [PATCH 026/755] Set minimum OpenGL version to 2.1 --- src/GuiQt/BrainOpenGLWidget.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 6b4cee881..e021aa050 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1742,6 +1742,8 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setDirectRendering(true); glfmt.setDoubleBuffer(true); glfmt.setOverlay(false); + glfmt.setProfile(QGLFormat::CompatibilityProfile); + glfmt.setVersion(2, 1); glfmt.setSampleBuffers(false); glfmt.setStencil(false); glfmt.setStereo(false); -- GitLab From 80981773ecaabc1b6bc0adcf9d0e93ae52ca4eaf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 13 Oct 2016 12:40:48 -0500 Subject: [PATCH 027/755] Added a test scenes ("Test All...") button to the Scene Dialog. When pressed, all scenes in the current scene file are displayed and images of the graphics region are captured. Next, a dialog is displayed that shows, on the left, the preview image from the scene and on the right, a image of the graphics region from display of the scene. If the images do not match, there may be a problem with the scene. --- src/GuiQt/SceneCreateReplaceDialog.cxx | 98 +++++ src/GuiQt/SceneCreateReplaceDialog.h | 3 + src/GuiQt/SceneDialog.cxx | 489 ++++++++++++++++++++----- src/GuiQt/SceneDialog.h | 20 +- src/GuiQt/WuQDialogNonModal.cxx | 13 + src/GuiQt/WuQDialogNonModal.h | 4 +- src/GuiQt/WuQtUtilities.cxx | 51 +++ src/GuiQt/WuQtUtilities.h | 4 + 8 files changed, 585 insertions(+), 97 deletions(-) diff --git a/src/GuiQt/SceneCreateReplaceDialog.cxx b/src/GuiQt/SceneCreateReplaceDialog.cxx index dc9b3efea..cccc57339 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.cxx +++ b/src/GuiQt/SceneCreateReplaceDialog.cxx @@ -424,6 +424,104 @@ SceneCreateReplaceDialog::addImageToScene(Scene* scene) } } +/** + * Create an image for the loaded scene. + * + * @param imageOut + * Output image of the scene. + * @param errorMessageOut + * Contains error information if image was not created. + * @return + * True if output image is valid, else false. + */ +bool +SceneCreateReplaceDialog::createSceneImage(QImage& imageOut, + AString& errorMessageOut) +{ + bool validImageFlag = false; + imageOut = QImage(); + errorMessageOut.clear(); + + uint8_t backgroundColor[3] = { 0, 0, 0 }; + bool backgroundColorValid = false; + + /* + * Capture an image of each window + */ + std::vector imageFiles; + std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); + for (std::vector::iterator iter = windows.begin(); + iter != windows.end(); + iter++) { + BrainBrowserWindow* bbw = *iter; + const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); + + EventImageCapture imageCaptureEvent(browserWindowIndex); + EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); + + if (imageCaptureEvent.getEventProcessCount() > 0) { + if (imageCaptureEvent.isError()) { + errorMessageOut.appendWithNewLine(imageCaptureEvent.getErrorMessage()); + } + else { + imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); + if ( ! backgroundColorValid) { + imageCaptureEvent.getBackgroundColor(backgroundColor); + backgroundColorValid = true; + } + } + } + } + + /* + * Assemble images of each window into a single image + * and add it to the scene. Use one image per row + * since the images are limited in horizontal space + * when shown in the listing of scenes. + */ + if ( ! imageFiles.empty()) { + try { + const int32_t numImagesPerRow = 1; + ImageFile compositeImageFile; + compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, + numImagesPerRow, + backgroundColor); + + if (backgroundColorValid) { + const int marginSize = 5; + compositeImageFile.cropImageRemoveBackground(marginSize, + backgroundColor); + } + + const int MAXIMUM_IMAGE_WIDTH = 1024; + compositeImageFile.resizeToMaximumWidth(MAXIMUM_IMAGE_WIDTH); + + const AString PREFERRED_IMAGE_FORMAT = "png"; + + QByteArray byteArray; + compositeImageFile.getImageInByteArray(byteArray, + PREFERRED_IMAGE_FORMAT); + + imageOut = *compositeImageFile.getAsQImage(); + validImageFlag = true; + } + catch (const DataFileException& dfe) { + errorMessageOut.appendWithNewLine("Even though image failed, scene was created."); + } + } + + /* + * Free memory from the image files. + */ + for (std::vector::iterator iter = imageFiles.begin(); + iter != imageFiles.end(); + iter++) { + delete *iter; + } + + return validImageFlag; +} + /** * @return Widget containing the scene options widgets. */ diff --git a/src/GuiQt/SceneCreateReplaceDialog.h b/src/GuiQt/SceneCreateReplaceDialog.h index 7ae6f8517..3a7e46877 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.h +++ b/src/GuiQt/SceneCreateReplaceDialog.h @@ -50,6 +50,9 @@ namespace caret { SceneFile* sceneFile, Scene* sceneToReplace); + static bool createSceneImage(QImage& imageOut, + AString& errorMessageOut); + virtual ~SceneCreateReplaceDialog(); private: diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 1610278bd..3539db64a 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -104,6 +104,17 @@ SceneDialog::SceneDialog(QWidget* parent) { m_selectedSceneClassInfoIndex = -1; + m_testAllScenesDescription = ("This operation may be slow as it requires displaying all scenes. " + "\n" + "Each scene is displayed and an image of the graphic(s) regions is generated " + "from the scene. After all scenes have been loaded, a dialog is " + "displayed that shows a scene's preview image on the left and " + "on the right, the image created by loading the scene. If the " + "two images do not match, it indicates a problem with the scene. " + "Possible problems include data files missing, data files that " + "have changed, or a change to the software."); + m_testAllScenesDescription = WuQtUtilities::createWordWrappedToolTipText(m_testAllScenesDescription); + /* * No apply buton */ @@ -362,18 +373,21 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) const bool validFile = (getSelectedSceneFile() != NULL); - bool validScene = false; + bool validScene = false; + bool haveScenes = false; if (validFile) { const Scene* scene = getSelectedScene(); if (scene != NULL) { validScene = true; } + haveScenes = (sceneFile->getNumberOfScenes() > 0); } enableSceneMoveUpAndDownButtons(); m_addNewScenePushButton->setEnabled(validFile); m_deleteScenePushButton->setEnabled(validScene); + m_testScenesPushButton->setEnabled(haveScenes); m_insertNewScenePushButton->setEnabled(validScene); m_replaceScenePushButton->setEnabled(validScene); m_showScenePushButton->setEnabled(validScene); @@ -691,6 +705,248 @@ SceneDialog::insertSceneButtonClicked() } } +/** + * Get the image from the scene info. + * + * @param sceneInfo + * The scene info. + * @return + * Point to image that caller must delete. Will be NULL + * if image is not valid. + */ +QImage* +SceneDialog::getQImageFromSceneInfo(const SceneInfo* sceneInfo) const +{ + QImage* imageOut = NULL; + + QByteArray imageByteArray; + AString imageBytesFormat; + sceneInfo->getImageBytes(imageByteArray, + imageBytesFormat); + + ImageFile imageFile; + imageFile.setImageFromByteArray(imageByteArray, + imageBytesFormat); + const QImage* image = imageFile.getAsQImage(); + if (image != NULL) { + if (image->isNull()) { + CaretLogSevere("Preview image is invalid (isNull)"); + } + else { + imageOut = new QImage(*image); + } + } + + return imageOut; +} + +/** + * Test all scenes by loading them and then + * displaying images that are stored with the + * scene and new image of the displayed scene. + */ +void +SceneDialog::testScenesPushButtonClicked() +{ + SceneFile* sceneFile = getSelectedSceneFile(); + if (sceneFile == NULL) { + WuQMessageBox::errorOk(m_testScenesPushButton, "No scene file is loaded."); + return; + } + + std::vector sceneNames; + std::vector sceneErrors; + std::vector sceneImages; + std::vector newImages; + + const int32_t numScenes = sceneFile->getNumberOfScenes(); + if (numScenes == 0) { + WuQMessageBox::errorOk(m_testScenesPushButton, "Selected scene file contains no scenes."); + return; + } + + if ( ! WuQMessageBox::warningOkCancel(m_testScenesPushButton, + "Test All Scenes", + m_testAllScenesDescription)) { + return; + } + + AString username; + AString password; + + /* + * Check to see if any scenes need a login/password. + * Same login/password is used for all scenes. + */ + for (int32_t i = 0; i < numScenes; i++) { + const Scene* scene = sceneFile->getSceneAtIndex(i); + if (scene != NULL) { + if (scene->hasFilesWithRemotePaths()) { + const QString msg("This scene contains files that are on the network. " + "If accessing the files requires a username and " + "password, enter it here. Otherwise, remove any " + "text from the username and password fields."); + + + if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, + "Username and Password", + msg, + username, + password)) { + CaretDataFile::setFileReadingUsernameAndPassword(username, + password); + break; + } + } + } + } + + showWaitCursor(); + + const int IMAGE_DISPLAY_WIDTH = 500; + for (int32_t i = 0; i < numScenes; i++) { + Scene* origScene = sceneFile->getSceneAtIndex(i); + if (origScene != NULL) { + if (origScene->hasFilesWithRemotePaths()) { + CaretDataFile::setFileReadingUsernameAndPassword(username, + password); + } + + AString errorMessage; + const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); + if (successFlag) { + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + QImage image; + AString imageErrorMessage; + const bool validImage = SceneCreateReplaceDialog::createSceneImage(image, + imageErrorMessage); + if (validImage) { + newImages.push_back(image.scaledToWidth(IMAGE_DISPLAY_WIDTH)); + } + else { + newImages.push_back(QImage()); + } + } + else { + newImages.push_back(QImage()); + } + + + + sceneNames.push_back(origScene->getName()); + const QImage* imageFromScene = getQImageFromSceneInfo(origScene->getSceneInfo()); + if (imageFromScene != NULL) { + sceneImages.push_back(imageFromScene->scaledToWidth(IMAGE_DISPLAY_WIDTH)); + delete imageFromScene; + } + else { + sceneImages.push_back(QImage()); + } + + sceneErrors.push_back(errorMessage); + + } + } + + CaretAssert(sceneNames.size() == sceneErrors.size()); + CaretAssert(sceneNames.size() == sceneImages.size()); + CaretAssert(sceneNames.size() == sceneErrors.size()); + CaretAssert(sceneNames.size() == newImages.size()); + + showNormalCursor(); + + const int32_t numValidScenes = static_cast(sceneNames.size()); + if (numValidScenes <= 0) { + WuQMessageBox::errorOk(m_testScenesPushButton, + "No scenes were loaded."); + return; + } + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 100); + + for (int32_t i = 0; i < numValidScenes; i++) { + int row = gridLayout->rowCount(); + if (i > 0) { + gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), + row, 0, 1, 4); + row = gridLayout->rowCount(); + } + + gridLayout->addWidget(new QLabel("Scene Name: " + sceneNames[i]), + row, 0, 1, 2, Qt::AlignLeft); + + row = gridLayout->rowCount(); + + if ( ! sceneErrors[i].isEmpty()) { + QLabel* errorLabel = new QLabel("Scene Errors: " + sceneErrors[i]); + errorLabel->setWordWrap(true); + gridLayout->addWidget(errorLabel, + row, 0, 1, 2, Qt::AlignLeft); + + row = gridLayout->rowCount(); + } + + const QSizePolicy::Policy imageSizePolicy = QSizePolicy::Preferred; + + QLabel* sceneImageLabel = new QLabel("Image Invalid"); + if ( ! sceneImages[i].isNull()) { + sceneImageLabel->clear(); + sceneImageLabel->setPixmap(QPixmap::fromImage(sceneImages[i])); + sceneImageLabel->setSizePolicy(imageSizePolicy, + imageSizePolicy); + } + gridLayout->addWidget(sceneImageLabel, + row, 0); + + QLabel* newImageLabel = new QLabel("Image Invalid"); + if ( ! newImages[i].isNull()) { + newImageLabel->clear(); + newImageLabel->setPixmap(QPixmap::fromImage(newImages[i])); + newImageLabel->setSizePolicy(imageSizePolicy, + imageSizePolicy); + } + gridLayout->addWidget(newImageLabel, + row, 1); + } + + const int numRows = gridLayout->rowCount(); + for (int32_t i = 0; i < numRows; i++) { + gridLayout->setRowStretch(i, 0); + } + + QWidget* dialogWidget = new QWidget(); + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addLayout(gridLayout); + dialogLayout->addStretch(); + + WuQDialogNonModal* dialog = new WuQDialogNonModal("Scene Comparisons", + m_testScenesPushButton); + dialog->setDeleteWhenClosed(true); + dialog->setApplyButtonText(""); + dialog->setCentralWidget(dialogWidget, + WuQDialogNonModal::SCROLL_AREA_ALWAYS); + dialog->show(); + WuQtUtilities::limitWindowSizePercentageOfMaximum(dialog, + 100.0, + 100.0); + + const int dialogWidth = (IMAGE_DISPLAY_WIDTH * 2) + 50; + const int dialogHeight = (IMAGE_DISPLAY_WIDTH * 2.5); + WuQtUtilities::resizeWindow(dialog, + dialogWidth, + dialogHeight); + + dialog->show(); +} + + /** * Move the selected scene up. */ @@ -749,88 +1005,88 @@ SceneDialog::replaceSceneButtonClicked() } } -/** - * Add an image to the scene. - * - * @param scene - * Scene to which image is added. - */ -void -SceneDialog::addImageToScene(Scene* scene) -{ - AString errorMessage; - - CaretAssert(scene); - - uint8_t backgroundColor[3] = { 0, 0, 0 }; - bool backgroundColorValid = false; - - /* - * Capture an image of each window - */ - std::vector imageFiles; - std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); - for (std::vector::iterator iter = windows.begin(); - iter != windows.end(); - iter++) { - BrainBrowserWindow* bbw = *iter; - const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); - - EventImageCapture imageCaptureEvent(browserWindowIndex); - EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); - - if (imageCaptureEvent.getEventProcessCount() > 0) { - if (imageCaptureEvent.isError()) { - errorMessage.appendWithNewLine(imageCaptureEvent.getErrorMessage()); - } - else { - imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); - if ( ! backgroundColorValid) { - imageCaptureEvent.getBackgroundColor(backgroundColor); - backgroundColorValid = true; - } - } - } - } - - /* - * Assemble images of each window into a single image - * and add it to the scene. Use one image per row - * since the images are limited in horizontal space - * when shown in the listing of scenes. - */ - if ( ! imageFiles.empty()) { - try { - const int32_t numImagesPerRow = 1; - ImageFile compositeImageFile; - compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, - numImagesPerRow, - backgroundColor); - - compositeImageFile.resizeToMaximumWidth(512); - - QByteArray byteArray; - compositeImageFile.getImageInByteArray(byteArray, - SceneDialog::PREFERRED_IMAGE_FORMAT); - - scene->getSceneInfo()->setImageBytes(byteArray, - SceneDialog::PREFERRED_IMAGE_FORMAT); - } - catch (const DataFileException& dfe) { - WuQMessageBox::errorOk(m_addNewScenePushButton, - dfe.whatString()); - } - } - - /* - * Free memory from the image files. - */ - for (std::vector::iterator iter = imageFiles.begin(); - iter != imageFiles.end(); - iter++) { - delete *iter; - } -} +///** +// * Add an image to the scene. +// * +// * @param scene +// * Scene to which image is added. +// */ +//void +//SceneDialog::addImageToScene(Scene* scene) +//{ +// AString errorMessage; +// +// CaretAssert(scene); +// +// uint8_t backgroundColor[3] = { 0, 0, 0 }; +// bool backgroundColorValid = false; +// +// /* +// * Capture an image of each window +// */ +// std::vector imageFiles; +// std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); +// for (std::vector::iterator iter = windows.begin(); +// iter != windows.end(); +// iter++) { +// BrainBrowserWindow* bbw = *iter; +// const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); +// +// EventImageCapture imageCaptureEvent(browserWindowIndex); +// EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); +// +// if (imageCaptureEvent.getEventProcessCount() > 0) { +// if (imageCaptureEvent.isError()) { +// errorMessage.appendWithNewLine(imageCaptureEvent.getErrorMessage()); +// } +// else { +// imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); +// if ( ! backgroundColorValid) { +// imageCaptureEvent.getBackgroundColor(backgroundColor); +// backgroundColorValid = true; +// } +// } +// } +// } +// +// /* +// * Assemble images of each window into a single image +// * and add it to the scene. Use one image per row +// * since the images are limited in horizontal space +// * when shown in the listing of scenes. +// */ +// if ( ! imageFiles.empty()) { +// try { +// const int32_t numImagesPerRow = 1; +// ImageFile compositeImageFile; +// compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, +// numImagesPerRow, +// backgroundColor); +// +// compositeImageFile.resizeToMaximumWidth(512); +// +// QByteArray byteArray; +// compositeImageFile.getImageInByteArray(byteArray, +// SceneDialog::PREFERRED_IMAGE_FORMAT); +// +// scene->getSceneInfo()->setImageBytes(byteArray, +// SceneDialog::PREFERRED_IMAGE_FORMAT); +// } +// catch (const DataFileException& dfe) { +// WuQMessageBox::errorOk(m_addNewScenePushButton, +// dfe.whatString()); +// } +// } +// +// /* +// * Free memory from the image files. +// */ +// for (std::vector::iterator iter = imageFiles.begin(); +// iter != imageFiles.end(); +// iter++) { +// delete *iter; +// } +//} /** * Check to see if there are modified files. If there are @@ -928,6 +1184,14 @@ SceneDialog::createMainPage() QObject::connect(m_deleteScenePushButton, SIGNAL(clicked()), this, SLOT(deleteSceneButtonClicked())); + /* + * Test all scenes + */ + m_testScenesPushButton = new QPushButton("Test All..."); + m_testScenesPushButton->setToolTip(m_testAllScenesDescription); + QObject::connect(m_testScenesPushButton, SIGNAL(clicked()), + this, SLOT(testScenesPushButtonClicked())); + /* * Move scene up button */ @@ -988,6 +1252,8 @@ SceneDialog::createMainPage() sceneButtonLayout->addWidget(m_insertNewScenePushButton); sceneButtonLayout->addWidget(m_replaceScenePushButton); sceneButtonLayout->addStretch(); + sceneButtonLayout->addWidget(m_testScenesPushButton); + sceneButtonLayout->addSpacing(20); sceneButtonLayout->addWidget(m_moveSceneUpPushButton); sceneButtonLayout->addWidget(m_moveSceneDownPushButton); sceneButtonLayout->addSpacing(20); @@ -1353,7 +1619,7 @@ SceneDialog::showSceneButtonClicked() this); progressDialog.setValue(0); - displayScenePrivate(sceneFile, + displayScenePrivateWithErrorMessageDialog(sceneFile, scene, false); } @@ -1471,7 +1737,7 @@ bool SceneDialog::displayScene(SceneFile* sceneFile, Scene* scene) { - const bool isSuccessful = displayScenePrivate(sceneFile, + const bool isSuccessful = displayScenePrivateWithErrorMessageDialog(sceneFile, scene, true); loadSceneFileComboBox(sceneFile); @@ -1482,27 +1748,67 @@ SceneDialog::displayScene(SceneFile* sceneFile, /** * Display the given scene from the given scene file. + * If the scene fails to load, an error message is displayed + * in a dialog. + * * @param sceneFile * Scene file. * @param scene * Scene that is displayed. + * param showWaitCursor + * Show a wait cursor while loading scene * @return * true if scene was displayed without error, else false. */ bool -SceneDialog::displayScenePrivate(SceneFile* sceneFile, - Scene* scene, - const bool showWaitCursor) +SceneDialog::displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, + Scene* scene, + const bool showWaitCursor) +{ + AString errorMessage; + + const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, + scene, + showWaitCursor, + errorMessage); + if ( ! successFlag) { + WuQMessageBox::errorOk(this, + errorMessage); + } + + return successFlag; +} + +/** + * Display the given scene from the given scene file. + * @param sceneFile + * Scene file. + * @param scene + * Scene that is displayed. + * param showWaitCursor + * Show a wait cursor while loading scene + * @param errorMessageOut + * Contains error information if scene fails to load. + * @return + * true if scene was displayed without error, else false. + */ +bool +SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, + Scene* scene, + const bool showWaitCursor, + AString& errorMessageOut) { CaretAssert(sceneFile); CaretAssert(scene); + errorMessageOut.clear(); + const AString sceneFileName = sceneFile->getFileName(); const SceneClass* guiManagerClass = scene->getClassWithName("guiManager"); if (guiManagerClass->getName() != "guiManager") { - WuQMessageBox::errorOk(this,"Top level scene class should be guiManager but it is: " - + guiManagerClass->getName()); + errorMessageOut = ("Top level scene class should be guiManager but it is: " + + guiManagerClass->getName()); return false; } @@ -1546,8 +1852,7 @@ SceneDialog::displayScenePrivate(SceneFile* sceneFile, } } else { - WuQMessageBox::errorOk(this, - sceneErrorMessage); + errorMessageOut = sceneErrorMessage; return false; } diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index b86778206..43df9a291 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -104,6 +104,8 @@ namespace caret { void browseBaseDirectoryPushButtonClicked(); + void testScenesPushButtonClicked(); + public: // ADD_NEW_METHODS_HERE @@ -129,9 +131,14 @@ namespace caret { QWidget* createSceneFileWidget(); - bool displayScenePrivate(SceneFile* sceneFile, - Scene* scene, - const bool showWaitCursor); + bool displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, + Scene* scene, + const bool showWaitCursor); + + bool displayScenePrivateWithErrorMessage(SceneFile* sceneFile, + Scene* scene, + const bool showWaitCursor, + AString& errorMessageOut); bool checkForModifiedFiles(const bool creatingSceneFlag); @@ -139,6 +146,9 @@ namespace caret { void loadSceneFileMetaDataWidgets(); + + QImage* getQImageFromSceneInfo(const SceneInfo* sceneInfo) const; + // ADD_NEW_MEMBERS_HERE QComboBox* m_sceneFileSelectionComboBox; @@ -153,6 +163,8 @@ namespace caret { QPushButton* m_deleteScenePushButton; + QPushButton* m_testScenesPushButton; + QPushButton* m_moveSceneUpPushButton; QPushButton* m_moveSceneDownPushButton; @@ -187,6 +199,8 @@ namespace caret { WuQWidgetObjectGroup* m_sceneFileButtonsGroup; + AString m_testAllScenesDescription; + static const AString PREFERRED_IMAGE_FORMAT; static bool s_informUserAboutScenesOnExitFlag; diff --git a/src/GuiQt/WuQDialogNonModal.cxx b/src/GuiQt/WuQDialogNonModal.cxx index 4887ebe3a..fc1b8b648 100644 --- a/src/GuiQt/WuQDialogNonModal.cxx +++ b/src/GuiQt/WuQDialogNonModal.cxx @@ -79,6 +79,19 @@ WuQDialogNonModal::~WuQDialogNonModal() } +/** + * May be called requesting the dialog to update its content + * Subclasses should override. + */ +void +WuQDialogNonModal::updateDialog() +{ +#ifdef DEBUG + QString text(getObjectName() + " should override updateDialog"); + CaretLogWarning(text); +#endif +} + /** * Gets called when the dialog is closing. * Overriden so that position of dialog diff --git a/src/GuiQt/WuQDialogNonModal.h b/src/GuiQt/WuQDialogNonModal.h index c380ccfaa..55548bcac 100644 --- a/src/GuiQt/WuQDialogNonModal.h +++ b/src/GuiQt/WuQDialogNonModal.h @@ -39,8 +39,8 @@ namespace caret { void setCloseButtonText(const AString& text); - /** May be called requesting the dialog to update its content */ - virtual void updateDialog() = 0; + virtual void updateDialog(); + //virtual void updateDialog() = 0; void setSaveWindowPositionForNextTime(const bool saveIt); diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index ec311ceb2..89edd9c0e 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -527,6 +527,57 @@ WuQtUtilities::resizeWindow(QWidget* window, } } +/** + * Limit a window's size to a percentage of the maximum size. + * + * @param window + * Window that is resized. + * @param widthMaximumPercentage + * Maximum width percentage [0, 100] + * @param heightMaximumPercentage + * Maximum height percentage [0, 100] + */ +void +WuQtUtilities::limitWindowSizePercentageOfMaximum(QWidget* window, + const float widthMaximumPercentage, + const float heightMaximumPercentage) +{ + AString message; + if ((widthMaximumPercentage < 0.0) + || (widthMaximumPercentage > 100.0)) { + message.appendWithNewLine("Percentage width must range [0, 100]: value -> " + + AString::number(widthMaximumPercentage)); + } + if ((heightMaximumPercentage < 0.0) + || (heightMaximumPercentage > 100.0)) { + message.appendWithNewLine("Percentage height must range [0, 100]: value -> " + + AString::number(heightMaximumPercentage)); + } + + if ( ! message.isEmpty()) { + CaretLogSevere(message); + return; + } + + QDesktopWidget* dw = QApplication::desktop(); + QPoint pXY(window->x(), + window->y()); + const int32_t nearestScreen = dw->screenNumber(pXY); + if (nearestScreen >= 0) { + const QRect screenRect = dw->availableGeometry(nearestScreen); + const int32_t screenWidth = screenRect.width(); + const int32_t screenHeight = screenRect.height(); + + const float maxWidth = ((widthMaximumPercentage / 100.0) * screenWidth); + const float maxHeight = ((heightMaximumPercentage / 100.0) * screenHeight); + + window->setMaximumSize(maxWidth, + maxHeight); + window->adjustSize(); + } +} + + /** * Table widget has a default size of 640 x 480. * Estimate the size of the dialog with the table fully expanded. diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index cbbca0191..4214b5557 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -134,6 +134,10 @@ namespace caret { const int32_t width, const int32_t height); + static void limitWindowSizePercentageOfMaximum(QWidget* window, + const float widthMaximumPercentage, + const float heightMaximumPercentage); + static int getMaximumWidgetHeight(QWidget* w1, QWidget* w2, QWidget* w3 = 0, -- GitLab From ba3e6884ac0e4a5512d9e85497aa295ddc355660 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 17 Oct 2016 09:58:45 -0500 Subject: [PATCH 028/755] Changed query for testing OpenGL support so that it works with both QGLWidget and QOpenGLWidget. --- src/Desktop/desktop.cxx | 25 ++++++++++++++++++++----- src/GuiQt/BrainBrowserWindow.cxx | 9 ++++++++- src/GuiQt/BrainBrowserWindow.h | 2 ++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 463d598cd..f3eb28096 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -430,14 +430,21 @@ main(int argc, char* argv[]) /* * Make sure OpenGL is available. */ + const QString noOpenGLMessage("OpenGL (3D Graphics System) is not available. " + "This may be caused by missing or outdated OpenGL libraries." + +#ifdef CARET_OS_LINUX + "On Linux, this may be caused by a missing plugin " + "library /xcbglintegrations/libqxcb-glx-integration.so." +#endif + ); + + #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET if (QGLFormat::hasOpenGL() == false) { - QString msg = "This computer does not support OpenGL (3D graphics system).\n" - "You will need to install OpenGL to run Workbench.\n" - "Please see your system administrator."; app.processEvents(); WuQMessageBox::errorOk(NULL, - msg); + noOpenGLMessage); app.processEvents(); return -1; @@ -594,8 +601,16 @@ main(int argc, char* argv[]) EventManager::get()->sendEvent(newBrowserWindow.getPointer()); splashScreen.close(); - BrainBrowserWindow* myWindow = GuiManager::get()->getBrowserWindowByWindowIndex(0); + BrainBrowserWindow* myWindow = GuiManager::get()->getBrowserWindowByWindowIndex(0); + if ( ! myWindow->hasValidOpenGL()) { + app.processEvents(); + WuQMessageBox::errorOk(NULL, + noOpenGLMessage); + app.processEvents(); + + return -1; + } if ((myState.windowSizeXY[0] > 0) && (myState.windowSizeXY[1] > 0)) { diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index bbfb0d551..4424dc914 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -4505,6 +4505,13 @@ BrainBrowserWindow::getDescriptionOfContent(PlainTextStringBuilder& descriptionO descriptionOut.popIndentation(); } - +/** + * @return Has valid OpenGL. + */ +bool +BrainBrowserWindow::hasValidOpenGL() +{ + return m_openGLWidget->isValid(); +} diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index fcc5e2c43..b6a96311d 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -146,6 +146,8 @@ namespace caret { void setAspectRatio(const float aspectRatio); + bool hasValidOpenGL(); + protected: void closeEvent(QCloseEvent* event); void keyPressEvent(QKeyEvent* event); -- GitLab From 5e40fdb3aef39d1b662166c09580ce4329d7f194 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 18 Oct 2016 09:23:08 -0500 Subject: [PATCH 029/755] Added list of header files containing 'Q_OBJECT' that need to be processed with MOC to the CMakeLists.txt files. Will allow timing comparison with CMAKE_AUTOMOC. --- src/Common/CMakeLists.txt | 22 ++++- src/GuiQt/CMakeLists.txt | 190 +++++++++++++++++++++++++++++++++++++- src/Quazip/CMakeLists.txt | 22 ++++- src/Qwt/CMakeLists.txt | 41 +++++++- 4 files changed, 267 insertions(+), 8 deletions(-) diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index d22bbda75..72e02a5de 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -22,7 +22,25 @@ IF (QT4_FOUND) ENDIF () #message("QT VERSION: " ${QT_VERSION_MAJOR} ${QT_VERSION_MINOR} ${QT_VERSION_PATCH}) -SET (CMAKE_AUTOMOC ON) +# +# With AUTOMOC, do not need to specify files +# that contain Q_OBJECT macro for Qt to process with 'moc' +# (meta-object compiler). +# +IF(WORKBENCH_USE_CMAKE_AUTOMOC) + SET(CMAKE_AUTOMOC ON) +ELSE() + SET(MOC_INPUT_HEADER_FILES + CaretHttpManager.h + ) + + IF(Qt5_FOUND) + QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF() + IF (QT4_FOUND) + QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF () +ENDIF() # # Create a library @@ -135,6 +153,8 @@ VectorOperation.h VoxelIJK.h YokingGroupEnum.h +${MOC_SOURCE_FILES} + ${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx ApplicationTypeEnum.cxx AString.cxx diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 888b38909..9d446af4d 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -22,12 +22,192 @@ ENDIF () # # Let CMake find files for moc and uic. # -SET(CMAKE_AUTOMOC ON) -SET(CMAKE_AUTOUIC ON) + +# +# With AUTOMOC, do not need to specify files +# that contain Q_OBJECT macro for Qt to process with 'moc' +# (meta-object compiler). +# +IF(WORKBENCH_USE_CMAKE_AUTOMOC) + SET(CMAKE_AUTOMOC ON) + SET(CMAKE_AUTOUIC ON) +ELSE() + SET(FORMS + MovieDialog.ui + ) + + SET(MOC_INPUT_HEADER_FILES + AboutWorkbenchDialog.h + AnnotationChangeCoordinateDialog.h + AnnotationColorWidget.h + AnnotationCoordinateSelectionWidget.h + AnnotationCoordinateSpaceWidget.h + AnnotationCoordinateWidget.h + AnnotationCreateDialog.h + AnnotationDeleteWidget.h + AnnotationFontWidget.h + AnnotationFormatWidget.h + AnnotationInsertNewWidget.h + AnnotationLineArrowTipsWidget.h + AnnotationMenuArrange.h + AnnotationMenuFileSelection.h + AnnotationRedoUndoWidget.h + AnnotationRotationWidget.h + AnnotationSelectionViewController.h + AnnotationPasteDialog.h + AnnotationTextAlignmentWidget.h + AnnotationTextEditorDialog.h + AnnotationTextEditorWidget.h + AnnotationTextOrientationWidget.h + AnnotationWidthHeightWidget.h + BalsaDatabaseUploadSceneFileDialog.h + BorderEditingSelectionDialog.h + BorderFileSplitDialog.h + BorderOptimizeDialog.h + BorderPropertiesEditorDialog.h + BorderSelectionViewController.h + BrainBrowserWindow.h + BrainBrowserWindowComboBox.h + BrainBrowserWindowOrientedToolBox.h + BrainBrowserWindowToolBar.h + BrainBrowserWindowToolBarChartAttributes.h + BrainBrowserWindowToolBarChartAxes.h + BrainBrowserWindowToolBarChartType.h + BrainBrowserWindowToolBarClipping.h + BrainBrowserWindowToolBarComponent.h + BrainBrowserWindowToolBarSlicePlane.h + BrainBrowserWindowToolBarSliceSelection.h + BrainBrowserWindowToolBarSurfaceMontage.h + BrainBrowserWindowToolBarTab.h + BrainBrowserWindowToolBarVolumeMontage.h + BrainOpenGLWidget.h + BugReportDialog.h + CaretColorEnumComboBox.h + CaretColorEnumMenu.h + CaretDataFileSelectionComboBox.h + CaretFileDialog.h + CaretFileDialogExtendable.h + CaretFileRemoteDialog.h + CaretMappableDataFileAndMapSelector.h + CaretMappableDataFileAndMapSelectorObject.h + ChartHistoryViewController.h + ChartLinesSelectionViewController.h + ChartMatrixParcelSelectionViewController.h + ChartMatrixSeriesSelectionViewController.h + ChartSelectionViewController.h + ChartToolBoxViewController.h + CiftiConnectivityMatrixViewController.h + CiftiParcelSelectionComboBox.h + ClippingPlanesDialog.h + ColorEditorWidget.h + CustomViewDialog.h + DataFileContentCopyMoveDialog.h + DisplayGroupAndTabItemViewController.h + DisplayGroupEnumComboBox.h + EnumComboBoxTemplate.h + FiberOrientationSelectionViewController.h + FiberSamplesOpenGLWidget.h + FociProjectionDialog.h + FociPropertiesEditorDialog.h + FociSelectionViewController.h + GapsAndMarginsDialog.h + GiftiLabelTableEditor.h + GiftiLabelTableSelectionComboBox.h + GroupAndNameHierarchyViewController.h + GuiManager.h + HelpViewerDialog.h + HyperLinkTextBrowser.h + IdentifyBrainordinateDialog.h + ImageCaptureDialog.h + ImageFileConvertToVolumeFileDialog.h + ImageSelectionViewController.h + InformationDisplayDialog.h + InformationDisplayPropertiesDialog.h + LabelSelectionViewController.h + MacApplication.h + MacDockMenu.h + MapSettingsColorBarWidget.h + MapSettingsFiberTrajectoryWidget.h + MapSettingsLabelsWidget.h + MapSettingsLayerWidget.h + MapSettingsPaletteColorMappingWidget.h + MapSettingsParcelsWidget.h + MapYokingGroupComboBox.h + MetaDataEditorDialog.h + MetaDataEditorWidget.h + MovieDialog.h + OverlaySetViewController.h + OverlaySettingsEditorDialog.h + OverlayViewController.h + PaletteColorMappingEditorDialog.h + PlotMagnifier.h + PlotPanner.h + PreferencesDialog.h + ProgressReportingDialog.h + ProgressReportingFromEvent.h + ProgressReportingWithSlots.h + RegionOfInterestCreateFromBorderDialog.h + SceneCreateReplaceDialog.h + SceneDialog.h + ScenePreviewDialog.h + SpecFileManagementDialog.h + SplashScreen.h + StructureEnumComboBox.h + StructureSurfaceSelectionControl.h + SurfacePropertiesEditorDialog.h + SurfaceSelectionViewController.h + TileTabsConfigurationDialog.h + UserInputModeAnnotationsContextMenu.h + UserInputModeAnnotationsWidget.h + UserInputModeBordersWidget.h + UserInputModeFociWidget.h + UserInputModeImageWidget.h + UserInputModeViewContextMenu.h + UserInputModeVolumeEditWidget.h + UsernamePasswordWidget.h + VolumeFileCreateDialog.h + VolumeSurfaceOutlineColorOrTabViewController.h + VolumeSurfaceOutlineSetViewController.h + VolumeSurfaceOutlineViewController.h + WuQCollapsibleWidget.h + WuQDataEntryDialog.h + WuQDialog.h + WuQDialogModal.h + WuQDialogNonModal.h + WuQDoubleSlider.h + WuQEventBlockingFilter.h + WuQGridLayoutGroup.h + WuQGroupBoxExclusiveWidget.h + WuQImageLabel.h + WuQListWidget.h + WuQMessageBox.h + WuQwtPlot.h + WuQSpecialIncrementDoubleSpinBox.h + WuQSpinBoxGroup.h + WuQSpinBoxOddValue.h + WuQTabWidget.h + WuQTimedMessageDisplay.h + WuQTreeWidget.h + WuQTrueFalseComboBox.h + #WuQWebView.h + WuQWidget.h + WuQWidgetObjectGroup.h + ZipSceneFileDialog.h + ) + + IF(Qt5_FOUND) + QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + QT5_WRAP_UI(FORMS_HEADERS ${FORMS}) + ENDIF() + IF (QT4_FOUND) + QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + QT4_WRAP_UI(FORMS_HEADERS ${FORMS}) + ENDIF () +ENDIF() # # Header files -# +# SET(SOURCE_FILES AboutWorkbenchDialog.h AnnotationChangeCoordinateDialog.h @@ -441,7 +621,9 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} # Create the GUI library # ADD_LIBRARY(GuiQt -${SOURCE_FILES} + ${FORMS_HEADERS} + ${MOC_SOURCE_FILES} + ${SOURCE_FILES} ) INCLUDE_DIRECTORIES( diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index 36294e844..42d341e90 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -11,7 +11,25 @@ IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () -SET(CMAKE_AUTOMOC ON) +# +# With AUTOMOC, do not need to specify files +# that contain Q_OBJECT macro for Qt to process with 'moc' +# (meta-object compiler). +# +IF(WORKBENCH_USE_CMAKE_AUTOMOC) + SET(CMAKE_AUTOMOC ON) +ELSE() + SET(MOC_INPUT_HEADER_FILES + quazipfile.h + ) + + IF(Qt5_FOUND) + QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF() + IF (QT4_FOUND) + QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF () +ENDIF() # # Prevents dll linkage errors on windows @@ -47,6 +65,8 @@ quazipnewinfo.h unzip.h zip.h +${MOC_SOURCE_FILES} + JlCompress.cpp qioapi.cpp quaadler32.cpp diff --git a/src/Qwt/CMakeLists.txt b/src/Qwt/CMakeLists.txt index e1b88ece1..1afd7c2e3 100644 --- a/src/Qwt/CMakeLists.txt +++ b/src/Qwt/CMakeLists.txt @@ -26,6 +26,43 @@ ENDIF () add_definitions(-DQWT_NO_SVG -DQWT_NO_OPENGL) +# +# With AUTOMOC, do not need to specify files +# that contain Q_OBJECT macro for Qt to process with 'moc' +# (meta-object compiler). +# +IF(WORKBENCH_USE_CMAKE_AUTOMOC) + SET(CMAKE_AUTOMOC ON) +ELSE() + SET(MOC_INPUT_HEADER_FILES + qwt_abstract_legend.h + qwt_dyngrid_layout.h + qwt_legend.h + qwt_legend_label.h + qwt_magnifier.h + qwt_panner.h + qwt_picker.h + qwt_plot_canvas.h + qwt_plot.h + qwt_plot_magnifier.h + qwt_plot_panner.h + qwt_plot_picker.h + qwt_plot_renderer.h + qwt_plot_zoomer.h + qwt_sampling_thread.h + qwt_scale_widget.h + qwt_text_label.h + ) + + IF(Qt5_FOUND) + QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF() + IF (QT4_FOUND) + QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) + ENDIF () +ENDIF() + + # # Header files # @@ -200,13 +237,13 @@ qwt_widget_overlay.cpp # Process the header files with moc producing moc_*.cpp files # INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -SET(CMAKE_AUTOMOC ON) # # Create the GUI library # ADD_LIBRARY(Qwt -${SOURCE_FILES} + ${SOURCE_FILES} + ${MOC_SOURCE_FILES} ) SET(Qwt_LIBRARIES Qwt PARENT_SCOPE) -- GitLab From a0bb38928154c310feb95398b15d05da090bf47e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 19 Oct 2016 11:48:45 -0500 Subject: [PATCH 030/755] Fixed some compilation warnings. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- src/Scenes/SceneString.cxx | 8 +++++--- src/Scenes/SceneStringArray.cxx | 8 +++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 1e5bc45e5..577ae83dd 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2107,7 +2107,7 @@ BrainOpenGLFixedPipeline::drawSurfaceTriangles(Surface* surface, * Determine position in triangle using barycentric coordinates */ double displayXYZ[3] = { - this->mouseX, + this->mouseX, this->mouseY, 0.0 }; diff --git a/src/Scenes/SceneString.cxx b/src/Scenes/SceneString.cxx index 402526bf2..92132ada2 100644 --- a/src/Scenes/SceneString.cxx +++ b/src/Scenes/SceneString.cxx @@ -148,12 +148,14 @@ SceneString::unsignedByteValue() const return 0; } + /* + * Note since "i" is unsigned there is no need + * to compare with std::numeric_limits::min() + * since it is zero. + */ if (i > std::numeric_limits::max()) { return std::numeric_limits::max(); } - else if (i < std::numeric_limits::min()) { - return std::numeric_limits::min(); - } const uint8_t b = static_cast(i); return b; diff --git a/src/Scenes/SceneStringArray.cxx b/src/Scenes/SceneStringArray.cxx index 2f0eabcf3..c5e4a0d63 100644 --- a/src/Scenes/SceneStringArray.cxx +++ b/src/Scenes/SceneStringArray.cxx @@ -204,12 +204,14 @@ SceneStringArray::unsignedByteValue(const int32_t arrayIndex) const return 0; } + /* + * Note since "i" is unsigned there is no need + * to compare with std::numeric_limits::min() + * since it is zero. + */ if (i > std::numeric_limits::max()) { return std::numeric_limits::max(); } - else if (i < std::numeric_limits::min()) { - return std::numeric_limits::min(); - } const uint8_t b = static_cast(i); return b; -- GitLab From 760ac6a6b8996bc65cb02bb00c2da120dcf11a25 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 24 Oct 2016 12:14:21 -0500 Subject: [PATCH 031/755] Merged changes for adding Qt5 support. --- src/CommandLine/CMakeLists.txt | 1 - src/Desktop/CMakeLists.txt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index b5e76ae90..6b4d24a0d 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -28,7 +28,6 @@ set (EXE_NAME wb_command) # # Resources # -======= SET (RESOURCES_QRC_FILE ../Resources/General/general_resources.qrc) IF (Qt5_FOUND) QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index c9a3ca4df..f3fad9a13 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -109,8 +109,9 @@ if(Qt5_FOUND) Qt5::Test Qt5::Widgets Qt5::Xml) + + message("*** QT5_LINK_LIBS: ${QT5_LINK_LIBS}") endif() -message("*** QT5_LINK_LIBS: ${QT5_LINK_LIBS}") # # Libraries that are linked -- GitLab From 8410c6d5642113f0c7c90d878646c35e77bf9773 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 25 Oct 2016 12:22:23 -0500 Subject: [PATCH 032/755] Fixed drawing of CIFTI files on orthogonal volume slices in ALL view. Coloring had not been implemented which resulted in unitialized data being used for the coloring. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 9 +- src/Files/CiftiMappableDataFile.cxx | 189 ++++++++++++++++++-- 2 files changed, 178 insertions(+), 20 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 3725a1062..7d4918422 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -4737,6 +4737,10 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxels(const float sliceNormal const int32_t mapIndex, const uint8_t sliceOpacity) { + if (validVoxelCount <= 0) { + return; + } + /* * There are two ways to draw the voxels. * @@ -4773,9 +4777,10 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxels(const float sliceNormal const int64_t totalVertexBytes = ((numberOfColumns + 1) * (numberOfRows + 1) * bytesPerVertex); - const int64_t singleQuadBytes = (validVoxelCount * bytesPerVertex * 4); + const int64_t numberOfVoxels = numberOfColumns * numberOfRows; + const int64_t singleQuadBytes = (numberOfVoxels * bytesPerVertex * 4); const int64_t indexQuadBytes = (totalVertexBytes - + (16 * validVoxelCount)); + + (16 * numberOfVoxels)); bool drawWithQuadIndicesFlag = false; if (indexQuadBytes < singleQuadBytes) { diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 336d25d20..51f41cc4b 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -2689,17 +2689,134 @@ CiftiMappableDataFile::getVoxelColorsForSliceInMap(const PaletteFile* paletteFil * Number of voxels with alpha greater than zero */ int64_t -CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t /*mapIndex*/, - const int64_t[] /*firstVoxelIJK[3]*/, - const int64_t[] /*rowStepIJK[3]*/, - const int64_t[] /*columnStepIJK[3]*/, - const int64_t /*numberOfRows*/, - const int64_t /*numberOfColumns*/, - const DisplayGroupEnum::Enum /*displayGroup*/, - const int32_t /*tabIndex*/, - uint8_t* /*rgbaOut*/) const +CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, + const int64_t firstVoxelIJK[3], + const int64_t rowStepIJK[3], + const int64_t columnStepIJK[3], + const int64_t numberOfRows, + const int64_t numberOfColumns, + const DisplayGroupEnum::Enum displayGroup, + const int32_t tabIndex, + uint8_t* rgbaOut) const { - return 0; + CaretAssertVectorIndex(m_mapContent, + mapIndex); + + if (isMapColoringValid(mapIndex) == false) { + CiftiMappableDataFile* nonConstThis = const_cast(this); + nonConstThis->updateScalarColoringForMap(mapIndex, + NULL); + } + + const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); + + + /* + * RGBA size will be zero if no data has been loaded for a CIFTI + * matrix type file (user clicking brainordinate). + */ + if (mapRgbaCount <= 0) { + return 0; + } + + const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; + + CaretAssert(m_voxelIndicesToOffset); + + /* + * Data values are only needed when a label volume + * is being drawn so that we can determine if the + * label is displayed. + */ + std::vector dataValues; + const GiftiLabelTable* labelTable = (isMappedWithLabelTable() + ? getMapLabelTable(mapIndex) + : NULL); + if (isMappedWithLabelTable()) { + CaretAssert(labelTable); + getMapData(mapIndex, + dataValues); + } + + int64_t rowIJK[3] = { firstVoxelIJK[0], firstVoxelIJK[1], firstVoxelIJK[2] }; + uint8_t rgba[4] = { 0, 0, 0, 0 }; + int64_t rgbaOutIndex4 = 0; + + int64_t validVoxelCount = 0; + + for (int32_t iRow = 0; iRow < numberOfRows; iRow++) { + int64_t ijk[3] = { rowIJK[0], rowIJK[1], rowIJK[2] }; + + for (int32_t iCol = 0; iCol < numberOfColumns; iCol++) { + rgba[3] = 0; + + const int64_t dataOffset = m_voxelIndicesToOffset->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); + if (dataOffset >= 0) { + const int64_t dataOffset4 = dataOffset * 4; + CaretAssert(dataOffset4 < mapRgbaCount); + + rgba[0] = mapRGBA[dataOffset4]; + rgba[1] = mapRGBA[dataOffset4+1]; + rgba[2] = mapRGBA[dataOffset4+2]; + + /* + * A negative value for alpha indicates "do not draw". + * Since unsigned bytes do not have negative values, + * change the value to zero (which indicates "transparent"). + */ + float alpha = mapRGBA[dataOffset4+3]; + if (alpha < 0.0) { + alpha = 0.0; + } + + if (alpha > 0.0) { + if (labelTable != NULL) { + /* + * For label data, verify that the label is displayed. + * If NOT displayed, zero out the alpha value to + * prevent display of the data. + */ + CaretAssertVectorIndex(dataValues, dataOffset); + const int32_t dataValue = dataValues[dataOffset]; + const GiftiLabel* label = labelTable->getLabel(dataValue); + if (label != NULL) { + const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); + CaretAssert(item); + if (item->isSelected(displayGroup, tabIndex) == false) { + alpha = 0.0; + } + } + } + + } + + if (alpha > 0.0) { + ++validVoxelCount; + } + rgba[3] = (alpha * 255.0); + } + + rgbaOut[rgbaOutIndex4] = rgba[0]; + rgbaOut[rgbaOutIndex4+1] = rgba[1]; + rgbaOut[rgbaOutIndex4+2] = rgba[2]; + rgbaOut[rgbaOutIndex4+3] = rgba[3]; + rgbaOutIndex4 += 4; + + if (rgba[3] > 0) { + validVoxelCount++; + } + + ijk[0] += columnStepIJK[0]; + ijk[1] += columnStepIJK[1]; + ijk[2] += columnStepIJK[2]; + } + + rowIJK[0] += rowStepIJK[0]; + rowIJK[1] += rowStepIJK[1]; + rowIJK[2] += rowStepIJK[2]; + } + + return validVoxelCount; } /** @@ -6683,7 +6800,8 @@ CiftiMappableDataFile::MapContent::updateHistogramLimitedValues(const std::vecto * @param data * Data contained in the map. * @param paletteFile - * File containing the palettes. + * File containing the palettes. If NULL, the find palette + * event is used to find the palette. * @param fastStatistics * Fast statistics used for palette coloring. While map content contains * a fast statistics member, it is calculated on the data within the map. @@ -6722,10 +6840,45 @@ CiftiMappableDataFile::MapContent::updateColoring(const std::vector& data data.size(), &m_rgba[0]); } - else if (paletteFile != NULL) { + else { CaretAssert(m_paletteColorMapping); const AString paletteName = m_paletteColorMapping->getSelectedPaletteName(); - const Palette* palette = paletteFile->getPaletteByName(paletteName); + + /* + * First, look for palette in palette file but only + * if the palette file is valid + */ + Palette* paletteFromFile = NULL; + if (paletteFile != NULL) { + paletteFromFile = paletteFile->getPaletteByName(paletteName); + if (paletteFromFile == NULL) { + CaretLogSevere("No palette named " + + paletteName + + " found in " + + paletteFile->getFileNameNoPath() + + "."); + } + } + + /* + * If palette was not found in palette file, + * find palette using event. + */ + Palette* paletteFromEvent = NULL; + if (paletteFromFile == NULL) { + EventPaletteGetByName eventPaletteGetName(paletteName); + EventManager::get()->sendEvent(eventPaletteGetName.getPointer()); + paletteFromEvent = eventPaletteGetName.getPalette(); + if (paletteFromEvent == NULL) { + CaretLogSevere("No palette named " + + paletteName + + " found using EventPaletteGetByName."); + } + } + + Palette* palette = ((paletteFromFile != NULL) + ? paletteFromFile + : paletteFromEvent); if ((palette != NULL) && (fastStatistics != NULL)) { NodeAndVoxelColoring::colorScalarsWithPalette(fastStatistics, @@ -6742,11 +6895,11 @@ CiftiMappableDataFile::MapContent::updateColoring(const std::vector& data 0); } } - else { - const AString msg("NULL palette for coloring scalar data."); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - } +// else { +// const AString msg("NULL palette for coloring scalar data."); +// CaretAssertMessage(0, msg); +// CaretLogSevere(msg); +// } m_rgbaValid = true; } -- GitLab From c84c39321d1bb4f60f42e0f9029f508151530b58 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 31 Oct 2016 10:24:42 -0500 Subject: [PATCH 033/755] Update Mac64 build script to use newer version of cmake. --- build_scripts/mac64_aux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_scripts/mac64_aux.sh b/build_scripts/mac64_aux.sh index fb8273aa9..e1f7ff383 100755 --- a/build_scripts/mac64_aux.sh +++ b/build_scripts/mac64_aux.sh @@ -81,7 +81,7 @@ export OPENMP_LIB_DIR echo "BUILDING SOURCE" mkdir -p ${BUILD_DIR} cd ${BUILD_DIR} -/usr/local/cmake-3.3.1/bin/cmake \ +/usr/local/cmake-3.6.2/bin/cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=${CC_COMPILER} \ -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ -- GitLab From c97433afe46e6b666a02823c4966147337e42df0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 31 Oct 2016 11:05:39 -0500 Subject: [PATCH 034/755] The mac64_remote.sh script had its email subject corrected to 'Caret7 Mac 64 Build Result' (previously was 'Caret7 Linux645 Build Result '). --- build_scripts/mac64_remote.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_scripts/mac64_remote.sh b/build_scripts/mac64_remote.sh index 6cf5ef588..592bca120 100755 --- a/build_scripts/mac64_remote.sh +++ b/build_scripts/mac64_remote.sh @@ -4,4 +4,4 @@ BUILD_SERVER=hippocampus.wustl.edu BUILD_DIR=/Users/caret/caret7_development/${BUILD} ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu +cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Mac 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From e8955aaa4a4e0ed94eee411ed14ed97265fe2a57 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 1 Nov 2016 22:10:21 +0000 Subject: [PATCH 035/755] fixes to build on ubuntu 14.04 cmake and qt5 versions --- src/Algorithms/CMakeLists.txt | 2 ++ src/Annotations/CMakeLists.txt | 2 ++ src/Brain/CMakeLists.txt | 2 ++ src/CMakeLists.txt | 8 ++++++-- src/Charting/CMakeLists.txt | 2 ++ src/Cifti/CMakeLists.txt | 2 ++ src/Commands/CMakeLists.txt | 2 ++ src/Common/CMakeLists.txt | 7 +++++-- src/Desktop/desktop.cxx | 6 ++++++ src/Files/CMakeLists.txt | 1 + src/FilesBase/CMakeLists.txt | 2 ++ src/Gifti/CMakeLists.txt | 2 ++ src/GuiQt/BrainBrowserWindow.cxx | 8 ++++---- src/GuiQt/CMakeLists.txt | 2 ++ src/Nifti/CMakeLists.txt | 2 ++ src/OSMesaDummy/CMakeLists.txt | 2 ++ src/Operations/CMakeLists.txt | 2 ++ src/OperationsBase/CMakeLists.txt | 2 ++ src/Palette/CMakeLists.txt | 2 ++ src/Quazip/CMakeLists.txt | 2 ++ src/Qwt/CMakeLists.txt | 2 ++ src/Scenes/CMakeLists.txt | 4 ++++ src/Tests/CMakeLists.txt | 1 + src/Xml/CMakeLists.txt | 2 ++ src/kloewe/cpuinfo/CMakeLists.txt | 3 +++ src/kloewe/dot/CMakeLists.txt | 4 ++-- 26 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index 75503cb5b..9e57eecc2 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -251,6 +251,8 @@ AlgorithmVolumeWarpfieldResample.cxx OverlapLogicEnum.cxx ) +TARGET_LINK_LIBRARIES(Algorithms ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 915c329e3..5d4e5c1b7 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -107,6 +107,8 @@ EventAnnotationGroupGetWithKey.cxx EventAnnotationGrouping.cxx ) +TARGET_LINK_LIBRARIES(Annotations ${CARET_QT5_LINK}) + # # Find headers # diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index cce1b92aa..9517452cd 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -327,6 +327,8 @@ WholeBrainSurfaceSettings.cxx WholeBrainVoxelDrawingMode.cxx ) +TARGET_LINK_LIBRARIES(Brain ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2c0c5340..c93a5bc34 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # # Minimum required version of CMAKE # -CMAKE_MINIMUM_REQUIRED (VERSION 3.5) +CMAKE_MINIMUM_REQUIRED (VERSION 2.8.12) MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") @@ -242,6 +242,7 @@ ELSE () message("WORKBENCH_USE_QT5 NOT defined") ENDIF () +SET(CARET_QT5_LINK "") IF (WORKBENCH_USE_QT5) # @@ -254,7 +255,7 @@ IF (WORKBENCH_USE_QT5) ENDIF () #FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network OpenGL PrintSupport Test Widgets Xml) - FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) + FIND_PACKAGE(Qt5 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) IF (Qt5_FOUND) MESSAGE("Found Qt 5") IF (NOT Qt5Concurrent_FOUND) @@ -310,6 +311,9 @@ IF (WORKBENCH_USE_QT5) add_definitions(-DWORKBENCH_REPLACE_QT_DEPRECATED) ENDIF () + #small hack to get the qt5 compile flag requirements into libraries + SET(CARET_QT5_LINK "Qt5::Core") + ELSE () MESSAGE(FATAL_ERROR "Qt5 was required but not found") ENDIF () diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 3dd200215..783166936 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -60,6 +60,8 @@ ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx ) +TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) + # # Include directories # diff --git a/src/Cifti/CMakeLists.txt b/src/Cifti/CMakeLists.txt index 3aa8c38a8..add65dfe6 100644 --- a/src/Cifti/CMakeLists.txt +++ b/src/Cifti/CMakeLists.txt @@ -54,6 +54,8 @@ CiftiSeriesMap.cxx CiftiVersion.cxx ) +TARGET_LINK_LIBRARIES(Cifti ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Commands/CMakeLists.txt b/src/Commands/CMakeLists.txt index 484b37e1f..bee897a8d 100644 --- a/src/Commands/CMakeLists.txt +++ b/src/Commands/CMakeLists.txt @@ -50,6 +50,8 @@ CommandParser.cxx CommandUnitTest.cxx ) +TARGET_LINK_LIBRARIES(Commands ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 72e02a5de..8cad9dd5f 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -283,5 +283,8 @@ ENDIF(EXISTS ${GIT_REPOSITORY}) # Conditionally link the dot library to use the SIMD-based dot product implementation # IF (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) - TARGET_LINK_LIBRARIES(Common dot) -ENDIF() + TARGET_LINK_LIBRARIES(Common dot ${CARET_QT5_LINK}) +ELSE (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) + TARGET_LINK_LIBRARIES(Common ${CARET_QT5_LINK}) +ENDIF (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) + diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index f3eb28096..f2e662672 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -100,10 +100,12 @@ messageHandlerForQt5(QtMsgType type, const QMessageLogContext& context, const QS abortFlag = true;//fatal will cause an abort, so always display it, bypassing logger entirely displayedFlag = true; break; +#if QT_VERSION >= 0x050500 case QtInfoMsg: CaretLogInfo(message); displayedFlag = CaretLogger::getLogger()->isInfo(); break; +#endif } /* @@ -131,9 +133,11 @@ messageHandlerForQt5(QtMsgType type, const QMessageLogContext& context, const QS case QtFatalMsg: cerr << "FATAL (?!?) ";//should never happen break; +#if QT_VERSION >= 0x050500 case QtInfoMsg: std::cerr << "Info "; break; +#endif } cerr << "message hidden" << endl; } @@ -158,9 +162,11 @@ messageHandlerForQt5(QtMsgType type, const QMessageLogContext& context, const QS std::cerr << "Qt Fatal: " << message << std::endl; std::abort(); break; +#if QT_VERSION >= 0x050500 case QtInfoMsg: std::cerr << "Qt Info: " << message << std::endl; break; +#endif } } } diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 6f97aa50c..6547df948 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -261,6 +261,7 @@ XmlStreamReaderHelper.cxx XmlStreamWriterHelper.cxx ) +TARGET_LINK_LIBRARIES(Files ${CARET_QT5_LINK}) # # Find Headers diff --git a/src/FilesBase/CMakeLists.txt b/src/FilesBase/CMakeLists.txt index 19809c965..d23a04fa1 100644 --- a/src/FilesBase/CMakeLists.txt +++ b/src/FilesBase/CMakeLists.txt @@ -49,6 +49,8 @@ VolumeSliceViewPlaneEnum.cxx VolumeSpace.cxx ) +TARGET_LINK_LIBRARIES(FilesBase ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Gifti/CMakeLists.txt b/src/Gifti/CMakeLists.txt index bd246a4ea..04a024b61 100644 --- a/src/Gifti/CMakeLists.txt +++ b/src/Gifti/CMakeLists.txt @@ -40,6 +40,8 @@ GiftiLabelTableSaxReader.cxx GiftiMetaDataSaxReader.cxx ) +TARGET_LINK_LIBRARIES(Gifti ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 4424dc914..e9082e291 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -247,7 +247,7 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050600 if (m_overlayHorizontalToolBox == m_overlayActiveToolBox) { /* * With Qt5, default height of overlay toolbox at bottom is @@ -4343,10 +4343,10 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, m_featuresToolBox->restoreFromScene(sceneAttributes, sceneClass->getClass("m_featuresToolBox")); -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050600 /* * Toolboxes were not restoring to correct size in Qt5. - * Qt5 adds a new method, QMainWindow::resizeDocks() that + * Qt5.6 adds a new method, QMainWindow::resizeDocks() that * resizes a QDockWidget in one dimension. Use it to resize * the toolbox. */ @@ -4391,7 +4391,7 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, sceneClass->getClass("m_overlayActiveToolBox")); -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050600 /* * Toolboxes were not restoring to correct size in Qt5. * Qt5 adds a new method, QMainWindow::resizeDocks() that diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 9d446af4d..0d9097ecd 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -626,6 +626,8 @@ ADD_LIBRARY(GuiQt ${SOURCE_FILES} ) +TARGET_LINK_LIBRARIES(GuiQt ${CARET_QT5_LINK}) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/GuiQt ${Qwt_INCLUDE_DIRS} diff --git a/src/Nifti/CMakeLists.txt b/src/Nifti/CMakeLists.txt index 3b40bf76a..3001f57ab 100644 --- a/src/Nifti/CMakeLists.txt +++ b/src/Nifti/CMakeLists.txt @@ -34,6 +34,8 @@ NiftiHeader.cxx NiftiIO.cxx ) +TARGET_LINK_LIBRARIES(Nifti ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/OSMesaDummy/CMakeLists.txt b/src/OSMesaDummy/CMakeLists.txt index 65c7b4be7..fdfeddb75 100644 --- a/src/OSMesaDummy/CMakeLists.txt +++ b/src/OSMesaDummy/CMakeLists.txt @@ -19,6 +19,8 @@ OSMesaDummy.h OSMesaDummy.c ) +TARGET_LINK_LIBRARIES(OSMesaDummy ${CARET_QT5_LINK}) + # # Include directories # diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index 2467cca2a..d40c4f28f 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -196,6 +196,8 @@ OperationZipSceneFile.cxx OperationZipSpecFile.cxx ) +TARGET_LINK_LIBRARIES(Operations ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/OperationsBase/CMakeLists.txt b/src/OperationsBase/CMakeLists.txt index c2be35d51..98b57cd04 100644 --- a/src/OperationsBase/CMakeLists.txt +++ b/src/OperationsBase/CMakeLists.txt @@ -28,6 +28,8 @@ OperationParameters.cxx OperationParametersEnum.cxx ) +TARGET_LINK_LIBRARIES(OperationsBase ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index 8c7cc803b..67b9cd68b 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -39,6 +39,8 @@ PaletteScalarAndColor.cxx PaletteThresholdRangeModeEnum.cxx ) +TARGET_LINK_LIBRARIES(Palette ${CARET_QT5_LINK}) + # # Find Headers # diff --git a/src/Quazip/CMakeLists.txt b/src/Quazip/CMakeLists.txt index 42d341e90..e457f71eb 100644 --- a/src/Quazip/CMakeLists.txt +++ b/src/Quazip/CMakeLists.txt @@ -82,5 +82,7 @@ unzip.c zip.c ) +TARGET_LINK_LIBRARIES(Quazip ${CARET_QT5_LINK}) + SET(QUAZIP_LIBRARIES Quazip PARENT_SCOPE) SET(QUAZIP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) diff --git a/src/Qwt/CMakeLists.txt b/src/Qwt/CMakeLists.txt index 1afd7c2e3..2d0ec18c2 100644 --- a/src/Qwt/CMakeLists.txt +++ b/src/Qwt/CMakeLists.txt @@ -246,5 +246,7 @@ ADD_LIBRARY(Qwt ${MOC_SOURCE_FILES} ) +TARGET_LINK_LIBRARIES(Qwt ${CARET_QT5_LINK}) + SET(Qwt_LIBRARIES Qwt PARENT_SCOPE) SET(Qwt_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index 36a0b748a..d0cbcad38 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -17,10 +17,12 @@ PROJECT (Scenes) # # QT include files # +SET(CARET_QT_LINK_MODULES "") if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) #include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Xml_INCLUDE_DIRS}) + SET(CARET_QT_LINK_MODULES "Qt5::Core") endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI TRUE) @@ -101,6 +103,8 @@ SceneUnsignedByteArray.cxx SceneWriterXml.cxx ) +TARGET_LINK_LIBRARIES(Scenes ${CARET_QT5_LINK}) + # # Find headers # diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index d361a8ea0..7aa8b45ff 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -59,6 +59,7 @@ VolumeFileTest.cxx XnatTest.cxx ) +TARGET_LINK_LIBRARIES(Tests ${CARET_QT5_LINK}) # # Create the test1 executable diff --git a/src/Xml/CMakeLists.txt b/src/Xml/CMakeLists.txt index f0dfc2302..a75c1bbba 100644 --- a/src/Xml/CMakeLists.txt +++ b/src/Xml/CMakeLists.txt @@ -48,3 +48,5 @@ ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) +TARGET_LINK_LIBRARIES(Xml ${CARET_QT5_LINK}) + diff --git a/src/kloewe/cpuinfo/CMakeLists.txt b/src/kloewe/cpuinfo/CMakeLists.txt index e17c05ddc..96e8df669 100644 --- a/src/kloewe/cpuinfo/CMakeLists.txt +++ b/src/kloewe/cpuinfo/CMakeLists.txt @@ -12,3 +12,6 @@ add_compile_options(-std=c99 -Wall -Wextra -Wno-unused-parameter -Wconversion -W add_definitions(-DNDEBUG) add_library(cpuinfo src/cpuinfo.c) + +TARGET_LINK_LIBRARIES(cpuinfo ${CARET_QT5_LINK}) + diff --git a/src/kloewe/dot/CMakeLists.txt b/src/kloewe/dot/CMakeLists.txt index 704cb2f2e..5e5725a10 100644 --- a/src/kloewe/dot/CMakeLists.txt +++ b/src/kloewe/dot/CMakeLists.txt @@ -25,9 +25,9 @@ add_library(dot_sse2 src/dot_sse2.c) add_library(dot_avx src/dot_avx.c) if(DOT_USEFMA) add_library(dot_avxfma src/dot_avx.c) - target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma cpuinfo) + target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma cpuinfo ${CARET_QT5_LINK}) else() - target_link_libraries(dot dot_naive dot_sse2 dot_avx cpuinfo) + target_link_libraries(dot dot_naive dot_sse2 dot_avx cpuinfo ${CARET_QT5_LINK}) endif() if(CMAKE_VERSION VERSION_LESS "2.8.12") -- GitLab From 549a3499cdce4c6e4460d92d3b6f74b26fe06692 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 1 Nov 2016 17:14:59 -0500 Subject: [PATCH 036/755] revert cmake version statement to qt4 value --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c93a5bc34..f64845f64 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # # Minimum required version of CMAKE # -CMAKE_MINIMUM_REQUIRED (VERSION 2.8.12) +CMAKE_MINIMUM_REQUIRED (VERSION 2.8) MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") -- GitLab From ce1bff3565cffcc20a228e7684104dae6b400b57 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 4 Nov 2016 15:34:08 -0500 Subject: [PATCH 037/755] update readme with qt5 support, use GNUInstallDirs for install targets --- README | 6 +++--- src/CommandLine/CMakeLists.txt | 8 +++++--- src/Desktop/CMakeLists.txt | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README b/README index 5004461e1..4cc78409f 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -Connectome Workbench requires QT4 to compile. Recommended is the latest 4.8.x release. The following configure options were used on linux for our builds: +Connectome Workbench requires QT4 or QT5 to compile. Recommended is the latest 4.8.x release, or 5.6 or later. For QT4, try the following configure options: --system-zlib -webkit -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -nomake demos -nomake examples -no-qt3support -no-dbus -opensource -exceptions -stl -no-multimedia -no-phonon -no-audio-backend -openssl +-system-zlib -no-webkit -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -nomake demos -nomake examples -no-qt3support -no-dbus -opensource -exceptions -stl -no-multimedia -no-phonon -no-audio-backend -openssl -Optionally, it can use OSMesa, which allows the -show-scene command to work. Use it by setting OSMESA_DIR as an environment variable, such that $OSMESA_DIR/include/GL/osmesa.h exists, before running cmake. +It is highly recommended to compile with OSMesa, which allow the -show-scene command and the "render pixmap" image capture method to work. Use it by setting OSMESA_DIR as an environment variable, such that $OSMESA_DIR/include/GL/osmesa.h exists, before running cmake. It is compiled using cmake, on linux do: diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index 6b4d24a0d..b29237f3f 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -99,9 +99,11 @@ ${OSMESA_GLU_LIBRARY} ${ZLIB_LIBRARIES} ${LIBS}) -INSTALL(TARGETS ${EXE_NAME} DESTINATION bin) -INSTALL(PROGRAMS wb_shortcuts DESTINATION bin) -INSTALL(FILES bashcomplete_wb_command DESTINATION /usr/share/bash-completion/completions RENAME wb_command) +INCLUDE(GNUInstallDirs) + +INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) +INSTALL(PROGRAMS wb_shortcuts DESTINATION ${CMAKE_INSTALL_BINDIR}) +INSTALL(FILES bashcomplete_wb_command DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions RENAME wb_command) # # Find Headers diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index f3fad9a13..0dd20bf2b 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -145,7 +145,9 @@ ${ZLIB_LIBRARIES} #${LIBS} ) -INSTALL(TARGETS ${EXE_NAME} DESTINATION bin) +INCLUDE(GNUInstallDirs) + +INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) IF(WIN32) TARGET_LINK_LIBRARIES(${EXE_NAME} -- GitLab From f0a14e9dd5ad5aa851aeacb6923e2f48112d1e86 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 2 Nov 2016 14:25:07 -0500 Subject: [PATCH 038/755] Added a README_BUGS.txt file to the top level source directory. At this time, it contains a workaround for bug QT-54666 which causes the CMake error 'No known features for CXX compiler'. --- README_BUGS.txt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 README_BUGS.txt diff --git a/README_BUGS.txt b/README_BUGS.txt new file mode 100644 index 000000000..1a89ff6e5 --- /dev/null +++ b/README_BUGS.txt @@ -0,0 +1,26 @@ + +********************************************************************************** + + +CMake Error in Tests/CMakeLists.txt: + No known features for CXX compiler + + "Clang" + + version 4.0.0. + +--------------------------------------------------------------------------------- + +CMake does not recognize the compiler and it fails to find the compiler's +features. We have seen this problem with Clang 4.0.0 and Qt 5.7.0 on +Mac OS X. It is a documented Qt bug. + +Qt Bug 5466: https://bugreports.qt.io/browse/QTBUG-54666 + +The solution with Qt 5.7.0 is: + (1) Edit /lib/cmake/Qt5Core/Qt5CoreConfigExtras.cmake + (2) Comment out the line "set_property(TARGET Qt5::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)" by placing a "#" at the beginning of the line. + +********************************************************************************** + + -- GitLab From abca2c5004fb28d1733e33eef7edca324337210c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 7 Nov 2016 16:35:10 -0600 Subject: [PATCH 039/755] =?UTF-8?q?Resolve=20WB-649=20Restoring=20from=20S?= =?UTF-8?q?cene=20Does=20Not=20Fully=20Restore=20Overlay=20Toolbox=20in=20?= =?UTF-8?q?Left=20Mode.=20=20By=20default,=20a=20combo=20box=E2=80=99s=20s?= =?UTF-8?q?ize=20is=20set=20the=20first=20time=20it=20is=20displayed.=20?= =?UTF-8?q?=20Thus,=20if=20the=20toolbox=20was=20narrow=20when=20first=20d?= =?UTF-8?q?isplayed,=20the=20combo=20box=20size=20(width)=20is=20set=20at?= =?UTF-8?q?=20that=20time.=20=20The=20combo=20box=20width=20policy=20has?= =?UTF-8?q?=20been=20changed=20to=20allow=20the=20width=20of=20the=20combo?= =?UTF-8?q?=20box=20to=20adjust=20in=20width=20as=20needed.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/GuiQt/OverlayViewController.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GuiQt/OverlayViewController.cxx b/src/GuiQt/OverlayViewController.cxx index 22e813395..54e1e0cba 100644 --- a/src/GuiQt/OverlayViewController.cxx +++ b/src/GuiQt/OverlayViewController.cxx @@ -95,6 +95,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, minComboBoxWidth = 50; maxComboBoxWidth = 100000; } + const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContents; /* * Enabled Check Box @@ -114,6 +115,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, QObject::connect(this->fileComboBox, SIGNAL(activated(int)), this, SLOT(fileComboBoxSelected(int))); this->fileComboBox->setToolTip("Selects file for this overlay"); + this->fileComboBox->setSizeAdjustPolicy(comboSizePolicy); /* * Map Index Spin Box @@ -132,6 +134,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, QObject::connect(this->mapNameComboBox, SIGNAL(activated(int)), this, SLOT(mapNameComboBoxSelected(int))); this->mapNameComboBox->setToolTip("Select map by its name"); + this->mapNameComboBox->setSizeAdjustPolicy(comboSizePolicy); /* * Opacity double spin box -- GitLab From df82b95b2503cc7fb954223a023eb7d90cb95cee Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 8 Nov 2016 08:14:55 -0600 Subject: [PATCH 040/755] For overlay toolbox, stretch factor for grid layout was missing for a column. --- src/GuiQt/OverlaySetViewController.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GuiQt/OverlaySetViewController.cxx b/src/GuiQt/OverlaySetViewController.cxx index 3d1bbf618..b7bdb49b2 100644 --- a/src/GuiQt/OverlaySetViewController.cxx +++ b/src/GuiQt/OverlaySetViewController.cxx @@ -81,6 +81,7 @@ OverlaySetViewController::OverlaySetViewController(const Qt::Orientation orienta gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 100); gridLayout->setColumnStretch(6, 0); + gridLayout->setColumnStretch(7, 0); gridLayout->setColumnStretch(8, 100); QLabel* onLabel = new QLabel("On"); -- GitLab From 163439885aa2555ad00c435d464aa7a67a5a8b3d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 9 Nov 2016 14:36:58 -0600 Subject: [PATCH 041/755] Modified src/CMakeLists.txt so that the paths to ZLIB are not hardcoded on Windows and instead set the variable 'ZLIB_ROOT' used by the FindZLIB module in CMake. Modified the (older) build scripts for windows so that they set ZLIB_ROOT as a parameter to the 'cmake' command. In addition, the variable WORKBENCH_FREETYPE_DIR has been added to specify the path to the FreeType root directory. If this variable is present, it is used by CMake to set the environment variable FREETYPE_DIR used in the CMake module FindFreeType. Lastly, added CMake Policy CMP0020 to CMakeLists.txt for Windows only to eliminate many warnings produced by newer versions of CMake. --- build_scripts/windows32/build.bat | 13 ++++++++++++- build_scripts/windows64/build.bat | 10 +++++++--- src/CMakeLists.txt | 20 +++++++++++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/build_scripts/windows32/build.bat b/build_scripts/windows32/build.bat index d14768f56..614ead338 100755 --- a/build_scripts/windows32/build.bat +++ b/build_scripts/windows32/build.bat @@ -6,7 +6,18 @@ REM rd /q/s %DIR%\caret7_source\build md %DIR%\caret7_source\build cd /d %DIR%\caret7_source\build REMcmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src -cmake -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev32\install\FreeType-2.4.8\include\freetype2 -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev32\install\FreeType-2.4.8\include -DFREETYPE_LIBRARY=C:\dev32\install\FreeType-2.4.8\lib\freetype.lib -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src + +cmake ^ + -DWORKBENCH_FREETYPE_DIR=C:\dev32\install\FreeType-2.4.8\lib ^ + -DZLIB_ROOT=C:\dev32\install\zlib ^ + -G "NMake Makefiles JOM" ^ + -DCMAKE_BUILD_TYPE=Release ^ + ../src + jom -j8 cd /d %OLD_DIR% set OLD_DIR= + +#JWH -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev32\install\FreeType-2.4.8\include\freetype2 +#JWH -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev32\install\FreeType-2.4.8\include +#JWH -DFREETYPE_LIBRARY=C:\dev32\install\FreeType-2.4.8\lib\freetype.lib diff --git a/build_scripts/windows64/build.bat b/build_scripts/windows64/build.bat index 546f32f32..6b654183d 100755 --- a/build_scripts/windows64/build.bat +++ b/build_scripts/windows64/build.bat @@ -5,9 +5,8 @@ set OLD_DIR=%CD% md %DIR%\caret7_source\build cd /d %DIR%\caret7_source\build cmake ^ - -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev64\install\FreeType-2.4.8\include\freetype2 ^ - -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev64\install\FreeType-2.4.8\include ^ - -DFREETYPE_LIBRARY=C:\dev64\install\FreeType-2.4.8\lib\freetype.lib ^ + -DWORKBENCH_FREETYPE_DIR=C:\dev64\install\FreeType-2.4.8 ^ + -DZLIB_ROOT=C:\dev64\install\zlib ^ -G "NMake Makefiles JOM" ^ -DCMAKE_BUILD_TYPE=Release ^ ../src @@ -15,3 +14,8 @@ cmake ^ jom -j8 cd /d %OLD_DIR% set OLD_DIR= + + +REM JWH -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev64\install\FreeType-2.4.8\include\freetype2 +REM JWH -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev64\install\FreeType-2.4.8\include +REM JWH -DFREETYPE_LIBRARY=C:\dev64\install\FreeType-2.4.8\lib\freetype.lib diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f64845f64..6ef9a7307 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,11 @@ ELSEIF(UNIX) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ELSEIF(WIN32) ADD_DEFINITIONS(-DCARET_OS_WINDOWS) + # Policy CMP0020 is related to Qt + # https://cmake.org/cmake/help/v3.5/policy/CMP0020.html + if(POLICY CMP0020) + cmake_policy(SET CMP0020 NEW) + endif() IF(MSVC) ADD_DEFINITIONS(-DCARET_OS_WINDOWS_MSVC) IF(CMAKE_CL_64) @@ -39,9 +44,9 @@ ELSEIF(WIN32) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) ##SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -we4061") - SET( ZLIB_INCLUDE_DIR "C:\\dev64\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") +#JWH SET( ZLIB_INCLUDE_DIR "C:\\dev64\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") # SET( ZLIB_LIBRARY "C:\\dev64\\install\\zlib\\lib\\zlib.lib" CACHE STRING "zlib library (binary)") - SET(ZLIB_LIBRARY optimized "C:\\dev64\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev64\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") +#JWH SET(ZLIB_LIBRARY optimized "C:\\dev64\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev64\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") SET( OPENSSL_ROOT_DIR "c:\\dev64\\install\\openssl-1.0.1t" CACHE_STRING "open ssl root directory") ELSE() @@ -412,7 +417,12 @@ FIND_PACKAGE(ZLIB) IF ( ZLIB_FOUND ) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) ELSE (ZLIB_FOUND) - MESSAGE(FATAL_ERROR "ZLIB was not found") + MESSAGE(FATAL_ERROR "ZLIB was not found. It may be necessary to define " + "the variable ZLIB_ROOT when running cmake so that " + "the FindZLIB module is able to find ZLIB.\n" + " cmake -DZLIB_ROOT= \n" + "See HINTS at " + "https://cmake.org/cmake/help/v3.5/module/FindZLIB.html") ENDIF (ZLIB_FOUND) # @@ -440,6 +450,10 @@ ENDIF (QUAZIP_FOUND) # SET(FTGL_FONT_MODULE_FOR_LINKING "") +IF (DEFINED WORKBENCH_FREETYPE_DIR) + # FindFreeType looks for environment variable FREETYPE_DIR as a hint + SET(ENV{FREETYPE_DIR} ${WORKBENCH_FREETYPE_DIR}) +ENDIF () FIND_PACKAGE(Freetype) IF (FREETYPE_FOUND) MESSAGE("FreeType library found") -- GitLab From 2ab897b78e3db22770a14bf00f4686fbbce25adb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 10 Nov 2016 08:58:06 -0600 Subject: [PATCH 042/755] Mesa is now defined by WORKBENCH_MESA_DIR when running CMake (environment variable OSMESA_DIR no longer used). --- build_scripts/mac64_aux.sh | 1 + src/CMakeLists.txt | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/build_scripts/mac64_aux.sh b/build_scripts/mac64_aux.sh index e1f7ff383..6c6bf82ef 100755 --- a/build_scripts/mac64_aux.sh +++ b/build_scripts/mac64_aux.sh @@ -85,6 +85,7 @@ cd ${BUILD_DIR} -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=${CC_COMPILER} \ -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ + -DWORKBENCH_MESA_DIR=/opt/caret64_sdk/install/Mesa-7.8.2 \ -DCMAKE_VERBOSE_MAKEFILE=FALSE \ ${SRC_DIR} make -j2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6ef9a7307..0726d27a6 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,7 +15,7 @@ MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") set (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR FALSE CACHE BOOL "If TRUE, produce fatal compiler error for Qt 5 deprecated functionality") set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries. Must be passed as an argument to CMake: cmake -DWORKBENCH_USE_QT5=TRUE ") set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "If Qt 5.x is used, use QOpenGLWidget instead of deprecated QGLWidget") - +set (WORKBENCH_MESA_DIR "" CACHE PATH "Path to the Mesa root directory that contains the 'include' and 'lib' directories. Mesa is optional and used by wb_command's -show-scene operation.") # # Setting the compiler MUST be done before the PROJECT # statement or else an infinite loop will occur indicating @@ -517,26 +517,26 @@ SET(OSMESA_GL_LIBRARY "") SET(OSMESA_GLU_LIBRARY "") SET(OSMESA_INCLUDE_DIRECTORY "") -MESSAGE("OSMESA_DIR: $ENV{OSMESA_DIR}") -IF (EXISTS $ENV{OSMESA_DIR}) - IF (EXISTS $ENV{OSMESA_DIR}/include/GL/osmesa.h) +MESSAGE("OSMESA_DIR: ${WORKBENCH_MESA_DIR}") +IF (EXISTS ${WORKBENCH_MESA_DIR}) + IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) MESSAGE("Have Mesa Include Directory") FIND_LIBRARY(OSMESA_LIBRARY_FOUND NAMES OSMesa - HINTS $ENV{OSMESA_DIR}/lib) + HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GL_LIBRARY_FOUND NAMES GL - HINTS $ENV{OSMESA_DIR}/lib) + HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GLU_LIBRARY_FOUND NAMES GLU - HINTS $ENV{OSMESA_DIR}/lib) + HINTS ${WORKBENCH_MESA_DIR}/lib) MESSAGE("OSMesa lib: " ${OSMESA_LIBRARY}) IF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_DEFINITION -DHAVE_OSMESA) SET(OSMESA_OFFSCREEN_LIBRARY ${OSMESA_LIBRARY_FOUND}) SET(OSMESA_GL_LIBRARY ${OSMESA_GL_LIBRARY_FOUND}) SET(OSMESA_GLU_LIBRARY ${OSMESA_GLU_LIBRARY_FOUND}) - SET(OSMESA_INCLUDE_DIRECTORY $ENV{OSMESA_DIR}/include) + SET(OSMESA_INCLUDE_DIRECTORY ${WORKBENCH_MESA_DIR}/include) SET(OSMESA_FOUND TRUE) MESSAGE("Offscreen Mesa Library was found") @@ -546,8 +546,8 @@ IF (EXISTS $ENV{OSMESA_DIR}) MESSAGE(" Libraries: ${OSMESA_GL_LIBRARY}") MESSAGE(" Libraries: ${OSMESA_GLU_LIBRARY}") ENDIF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) - ENDIF (EXISTS $ENV{OSMESA_DIR}/include/GL/osmesa.h) -ENDIF (EXISTS $ENV{OSMESA_DIR}) + ENDIF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) +ENDIF (EXISTS ${WORKBENCH_MESA_DIR}) #============================================================================= MESSAGE("") -- GitLab From 492ff30498dc8be6c698a9b7fad50d9d38ea36eb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 10 Nov 2016 12:14:56 -0600 Subject: [PATCH 043/755] Continuing cleanup of CMakeLists.txt including removing older, commented out code. --- src/CMakeLists.txt | 128 +++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 81 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0726d27a6..65ed5b507 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,44 +40,32 @@ ELSEIF(WIN32) IF(MSVC) ADD_DEFINITIONS(-DCARET_OS_WINDOWS_MSVC) IF(CMAKE_CL_64) -## SET(CMAKE_GENERATOR_TOOLSET "v120_CTP_Nov2012" CACHE STRING "Platform Toolset" FORCE) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) - ##SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -we4061") -#JWH SET( ZLIB_INCLUDE_DIR "C:\\dev64\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") -# SET( ZLIB_LIBRARY "C:\\dev64\\install\\zlib\\lib\\zlib.lib" CACHE STRING "zlib library (binary)") -#JWH SET(ZLIB_LIBRARY optimized "C:\\dev64\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev64\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") - SET( OPENSSL_ROOT_DIR "c:\\dev64\\install\\openssl-1.0.1t" CACHE_STRING "open ssl root directory") - +#JWH SET( OPENSSL_ROOT_DIR "c:\\dev64\\install\\openssl-1.0.1t" CACHE_STRING "open ssl root directory") ELSE() -## SET(CMAKE_GENERATOR_TOOLSET "v120_CTP_Nov2012" CACHE STRING "Platform Toolset" FORCE) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) - ##SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -we4061") - SET( ZLIB_INCLUDE_DIR "C:\\dev32\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") -# SET( ZLIB_LIBRARY "C:\\dev32\\install\\zlib\\lib\\zlib.lib" CACHE STRING "zlib library (binary)") - SET(ZLIB_LIBRARY optimized "C:\\dev32\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev32\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") - SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") +#JWH SET( ZLIB_INCLUDE_DIR "C:\\dev32\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") +#JWH SET(ZLIB_LIBRARY optimized "C:\\dev32\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev32\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") +#JWH SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") ENDIF(CMAKE_CL_64) ELSE(MSVC) - SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") - FIND_PATH(ZLIB_INCLUDE_DIR zlib.h - C:\\dev32\\install\\zlib\\include - C:\\zlib_software\\zlib-1.2.5-install\\include - $ENV{ZLIB_INC_DIR}) - FIND_PATH(ZLIB_LIBRARY libzlib.a - C:\\zlib_software\\zlib-1.2.5-install\\lib) - IF (NOT ZLIB_FOUND) - FIND_PATH(ZLIB_LIBRARY zlib.lib - C:\\dev32\\install\\zlib\\lib) - ENDIF(NOT ZLIB_FOUND) - IF (NOT ZLIB_FOUND) - FIND_PATH(ZLIB_LIBRARY libz.a - $ENV{ZLIB_LIB_DIR}) - ENDIF(NOT ZLIB_FOUND) - - ### SET( ZLIB_INCLUDE_DIR "C:\\dev32\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") - ### SET( ZLIB_LIBRARY "C:\\dev32\\install\\zlib\\lib\\zlib.lib" CACHE STRING "zlib library (binary)") +#JWH SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") +#JWH FIND_PATH(ZLIB_INCLUDE_DIR zlib.h +#JWH C:\\dev32\\install\\zlib\\include +#JWH C:\\zlib_software\\zlib-1.2.5-install\\include +#JWH $ENV{ZLIB_INC_DIR}) +#JWH FIND_PATH(ZLIB_LIBRARY libzlib.a +#JWH C:\\zlib_software\\zlib-1.2.5-install\\lib) +#JWH IF (NOT ZLIB_FOUND) +#JWH FIND_PATH(ZLIB_LIBRARY zlib.lib +#JWH C:\\dev32\\install\\zlib\\lib) +#JWH ENDIF(NOT ZLIB_FOUND) +#JWH IF (NOT ZLIB_FOUND) +#JWH FIND_PATH(ZLIB_LIBRARY libz.a +#JWH $ENV{ZLIB_LIB_DIR}) +#JWH ENDIF(NOT ZLIB_FOUND) ENDIF(MSVC) ELSE(APPLE) MESSAGE(FATAL_ERROR "Unrecognized operating system " ${CMAKE_SYSTEM_NAME}) @@ -156,41 +144,29 @@ ENDIF (CLANG_FLAG) # statements that do not handle all of the enumerated types # are treated as an error. Also, all warnings. # -###IF (CMAKE_COMPILER_IS_GNUCXX) IF (NOT MSVC) -## SET(CMAKE_CXX_FLAGS "-W -Wall -Werror=return-type -Werror=switch ${CMAKE_CXX_FLAGS}" CACHE STRING "c++ compiler specific options") -## SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Werror=return-type -Werror=switch -std=c++0x") -##SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") -if (CMAKE_COMPILER_IS_GNUCC) - execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) - list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) - list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) - message("gcc major minor version numbers are: " ${GCC_MAJOR},${GCC_MINOR}) - if(${GCC_VERSION} VERSION_LESS "4.2") - #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall" CACHE STRING "c++ compiler specific options") - ADD_DEFINITIONS(-W -Wall) - else() - #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Werror=return-type -Werror=switch" CACHE STRING "c++ compiler specific options") - ADD_DEFINITIONS(-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNU_11X_FLAGS}") - endif() - - if (${GCC_VERSION} VERSION_LESS "4.9") - # there is no greater than or equal in CMake - else() - ADD_DEFINITIONS(-Wno-narrowing -Wno-unused-local-typedefs) + if (CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION) + string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) + list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) + list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) + message("gcc major minor version numbers are: " ${GCC_MAJOR},${GCC_MINOR}) + if(${GCC_VERSION} VERSION_LESS "4.2") + #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall" CACHE STRING "c++ compiler specific options") + ADD_DEFINITIONS(-W -Wall) + else() + #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Werror=return-type -Werror=switch" CACHE STRING "c++ compiler specific options") + ADD_DEFINITIONS(-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNU_11X_FLAGS}") + endif() + + if (${GCC_VERSION} VERSION_LESS "4.9") + # there is no greater than or equal in CMake + else() + ADD_DEFINITIONS(-Wno-narrowing -Wno-unused-local-typedefs) + endif() endif() - -# execute_process(COMMAND uname -n OUTPUT_VARIABLE MACHINE_NAME) -# message("MACHINE_NAME: ${MACHINE_NAME}") -# if (${MACHINE_NAME} MATCHES "linuxbuild") -# message("is linuxbuild") -# SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-E" ${CMAKE_EXE_LINKER_FLAGS}) -# endif() - -endif() ENDIF (NOT MSVC) # @@ -233,7 +209,9 @@ IF(OPENSSL_FOUND) MESSAGE("OpenSSL include=${OPENSSL_INCLUDE_DIR}") MESSAGE("OpenSSL libraries=${OPENSSL_LIBRARIES}") ELSE (OPENSSL_FOUND) - MESSAGE("OpenSSL NOT FOUND") + MESSAGE("OpenSSL NOT FOUND. You may need to define OPENSSL_ROOT_DIR when running CMake.") + MESSAGE(" cmake -DOPENSSL_ROOT_DIR= \n") + MESSAGE("See: https://cmake.org/cmake/help/v3.5/module/FindOpenSSL.html") ENDIF(OPENSSL_FOUND) # @@ -259,7 +237,6 @@ IF (WORKBENCH_USE_QT5) SET(WB_QT_OPENGL_MODULE "OpenGL") ENDIF () - #FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Concurrent Core Gui Network OpenGL PrintSupport Test Widgets Xml) FIND_PACKAGE(Qt5 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) IF (Qt5_FOUND) MESSAGE("Found Qt 5") @@ -478,21 +455,10 @@ ELSE (FREETYPE_FOUND) SET (FREETYPE_LIBRARY "") SET (FREETYPE_LIBRARIES "") MESSAGE("FreeType library NOT found") - MESSAGE(" The environment variable FREETYPE_DIR can be set to the") - MESSAGE(" directory containing FreeType include and lib.") - MESSAGE("") - MESSAGE(" ") - MESSAGE(" On Windows (and possibly other systems) it may be necessary to set") - MESSAGE(" DFREETYPE_INCLUDE_DIR_freetype2") - MESSAGE(" /FreeType-X.Y.Z/include/freetype2") - MESSAGE(" DFREETYPE_INCLUDE_DIR_ft2build") - MESSAGE(" /FreeType-X.Y.Z/include") - MESSAGE(" DFREETYPE_LIBRARY") - MESSAGE(" /FreeType-X.Y.Z/lib/freetype.lib") - MESSAGE(" ") - MESSAGE(" These variable can be set when running cmake. For example:") - MESSAGE(" cmake -DFREETYPE_INCLUDE_DIR_freetype2=/FreeType-X.Y.Z/include/freetype2") - MESSAGE(" ") + MESSAGE(" Define the PATH to FreeType when running CMake") + MESSAGE(" -DWORKBENCH_FREETYPE_DIR=") + MESSAGE(" Where is the directory containing FreeType's") + MESSAGE(" 'include' and 'lib' directories.") ENDIF (FREETYPE_FOUND) # -- GitLab From 199a848149157fce0ebcdef6031ed10ae4453193 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 10 Nov 2016 14:52:14 -0600 Subject: [PATCH 044/755] Continued cleanup of CMakeLists.txt including removing more hardcoded paths and some obsolete setting of flags for C++11. Qt5 handles settings flags for C++11. In addition, print values of all variables starting with 'WORKBENCH' at the end. --- src/CMakeLists.txt | 78 ++++++++++------------------------------------ 1 file changed, 16 insertions(+), 62 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65ed5b507..328a1136f 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,78 +42,26 @@ ELSEIF(WIN32) IF(CMAKE_CL_64) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) -#JWH SET( OPENSSL_ROOT_DIR "c:\\dev64\\install\\openssl-1.0.1t" CACHE_STRING "open ssl root directory") ELSE() ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) -#JWH SET( ZLIB_INCLUDE_DIR "C:\\dev32\\install\\zlib\\include" CACHE STRING "zlib include directory (headers)") -#JWH SET(ZLIB_LIBRARY optimized "C:\\dev32\\install\\zlib\\lib\\zlib.lib" debug "C:\\dev32\\install\\zlib\\lib\\zlibd.lib" CACHE STRING "zlib library (binary)") -#JWH SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") ENDIF(CMAKE_CL_64) ELSE(MSVC) -#JWH SET( OPENSSL_ROOT_DIR "c:\\dev32\\install\\openssl" CACHE_STRING "open ssl root directory") -#JWH FIND_PATH(ZLIB_INCLUDE_DIR zlib.h -#JWH C:\\dev32\\install\\zlib\\include -#JWH C:\\zlib_software\\zlib-1.2.5-install\\include -#JWH $ENV{ZLIB_INC_DIR}) -#JWH FIND_PATH(ZLIB_LIBRARY libzlib.a -#JWH C:\\zlib_software\\zlib-1.2.5-install\\lib) -#JWH IF (NOT ZLIB_FOUND) -#JWH FIND_PATH(ZLIB_LIBRARY zlib.lib -#JWH C:\\dev32\\install\\zlib\\lib) -#JWH ENDIF(NOT ZLIB_FOUND) -#JWH IF (NOT ZLIB_FOUND) -#JWH FIND_PATH(ZLIB_LIBRARY libz.a -#JWH $ENV{ZLIB_LIB_DIR}) -#JWH ENDIF(NOT ZLIB_FOUND) ENDIF(MSVC) ELSE(APPLE) MESSAGE(FATAL_ERROR "Unrecognized operating system " ${CMAKE_SYSTEM_NAME}) ENDIF(APPLE) - - -#cmake_policy(SET CMP0015 OLD) - # # Shows compilation command when true # SET(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "cause all build commands to be displayed") -# -# Allow support for C11X compiler -# May not need these, use CMAKE_CXX_STANDARD:UNINITIALIZED=11 -# -SET (WORKBENCH_C11X FALSE) -##SET (WORKBENCH_C11X TRUE) -IF ("$ENV{WORKBENCH_CONFIGURE_C11X}" STREQUAL "YES") - SET (WORKBENCH_C11X TRUE) - MESSAGE("Configuring Workbench build with C11X enabled.") -ENDIF ("$ENV{WORKBENCH_CONFIGURE_C11X}" STREQUAL "YES") - - -# -# Set flags for C11 compiler -# Only set for C++ compiler -# C11x options are not recognized by C compiler -# -SET (CLANG_11X_FLAGS "") -SET (GNU_11X_FLAGS "") -SET (INTEL_11X_FLAGS "") -IF (WORKBENCH_C11X) - ADD_DEFINITIONS("-DWORKBENCH_HAVE_C11X") - SET (CLANG_11X_FLAGS "-std=c++11 -stdlib=libstdc++ -Wno-error=c++11-narrowing") - ####SET (CLANG_11X_FLAGS "-std=c++11 -stdlib=libc++ -Wno-error=c++11-narrowing") - SET (GNU_11X_FLAGS "-std=c++11 -Wno-error=c++11-narrowing") - SET (INTEL_11X_FLAGS "-std=c++11 -Wno-error=c++11-narrowing") -ENDIF (WORKBENCH_C11X) - # # Intel compiler # IF (${CMAKE_CXX_COMPILER} MATCHES "^.*icpc$") ADD_DEFINITIONS("-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${INTEL_11X_FLAGS}") ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*icpc$") # @@ -129,13 +77,6 @@ ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang2\\+\\+.*") IF (CLANG_FLAG) MESSAGE("USING CLANG COMPILER ${CMAKE_CXX_COMPILER}") ADD_DEFINITIONS("-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter -Wno-deprecated-declarations") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_11X_FLAGS}") - ##SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_11X_FLAGS} -W -Wall -Werror=return-type -Werror=switch -Wunused-parameter") - ##SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_11X_FLAGS} -W -Wall -Werror=return-type -Werror=switch -Wunused-parameter" CACHE STRING "C++ compiler options" FORCE) - - IF (WORKBENCH_C11X) - ####set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -std=c++11 -stdlib=libc++") - ENDIF (WORKBENCH_C11X) ENDIF (CLANG_FLAG) @@ -153,12 +94,9 @@ IF (NOT MSVC) list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) message("gcc major minor version numbers are: " ${GCC_MAJOR},${GCC_MINOR}) if(${GCC_VERSION} VERSION_LESS "4.2") - #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall" CACHE STRING "c++ compiler specific options") ADD_DEFINITIONS(-W -Wall) else() - #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Werror=return-type -Werror=switch" CACHE STRING "c++ compiler specific options") ADD_DEFINITIONS(-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNU_11X_FLAGS}") endif() if (${GCC_VERSION} VERSION_LESS "4.9") @@ -284,6 +222,7 @@ IF (WORKBENCH_USE_QT5) add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ELSE () MESSAGE("Configuring to use deprecated QGLWidget instead of new QOpenGLWidget") + remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ENDIF () IF (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR) @@ -372,6 +311,8 @@ IF (OPENMP_FOUND) SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel") ADD_DEFINITIONS("-static-intel") ENDIF() + MESSAGE("OpenMP was Found") + MESSAGE(" OpenMP_CXX_FLAGS: ${OpenMP_CXX_FLAGS}") ELSE (OPENMP_FOUND) MESSAGE(WARNING "OpenMP was not found") @@ -565,3 +506,16 @@ ENDIF() #CTest tests # ENABLE_TESTING() + + + +# +# Print values of Workbench Variables +# +get_cmake_property( allVars VARIABLES ) +foreach( var in ${allVars} ) + string(FIND ${var} "WORKBENCH" workbenchOffset) + if(${workbenchOffset} EQUAL 0) + message(STATUS " ${var}=${${var}}" ) + endif() +endforeach() -- GitLab From 092c5faf7afd2d96dc3f40084b34120893f70563 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 11 Nov 2016 15:33:10 -0600 Subject: [PATCH 045/755] Fixed improperly commented out code in build_scripts/windows32/build.bat --- build_scripts/windows32/build.bat | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build_scripts/windows32/build.bat b/build_scripts/windows32/build.bat index 614ead338..9cd97333b 100755 --- a/build_scripts/windows32/build.bat +++ b/build_scripts/windows32/build.bat @@ -7,6 +7,11 @@ md %DIR%\caret7_source\build cd /d %DIR%\caret7_source\build REMcmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src +REM -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev32\install\FreeType-2.4.8\include\freetype2 +REM -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev32\install\FreeType-2.4.8\include +REM -DFREETYPE_LIBRARY=C:\dev32\install\FreeType-2.4.8\lib\freetype.lib + + cmake ^ -DWORKBENCH_FREETYPE_DIR=C:\dev32\install\FreeType-2.4.8\lib ^ -DZLIB_ROOT=C:\dev32\install\zlib ^ @@ -18,6 +23,3 @@ jom -j8 cd /d %OLD_DIR% set OLD_DIR= -#JWH -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev32\install\FreeType-2.4.8\include\freetype2 -#JWH -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev32\install\FreeType-2.4.8\include -#JWH -DFREETYPE_LIBRARY=C:\dev32\install\FreeType-2.4.8\lib\freetype.lib -- GitLab From 3482ef9a324d11c5347b12330ec6606bb035f02b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 11 Nov 2016 15:33:31 -0600 Subject: [PATCH 046/755] Updated src/CMakeLists.txt file to output a summary at the end. --- src/CMakeLists.txt | 100 ++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 328a1136f..42976d751 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,11 +5,6 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.8) MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") -# -# -# -#message(INFORMATION "\nTo get the correct version of QT, qmake must be in the PATH\n") - #TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options set (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR FALSE CACHE BOOL "If TRUE, produce fatal compiler error for Qt 5 deprecated functionality") @@ -134,18 +129,14 @@ if (CMAKE_COMPILER_IS_GNUCC) endif() endif() -# -# will set name of XCode project: -# disabled at this time -# -##PROJECT(BorderOptProject C CXX) - +SET(OPENSSL_RESULT "Not Found") FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) MESSAGE("OpenSSL version=${OPENSSL_VERSION}") MESSAGE("OpenSSL include=${OPENSSL_INCLUDE_DIR}") MESSAGE("OpenSSL libraries=${OPENSSL_LIBRARIES}") + SET(OPENSSL_RESULT "${OPENSSL_VERSION} ${OPENSSL_LIBRARIES}") ELSE (OPENSSL_FOUND) MESSAGE("OpenSSL NOT FOUND. You may need to define OPENSSL_ROOT_DIR when running CMake.") MESSAGE(" cmake -DOPENSSL_ROOT_DIR= \n") @@ -157,15 +148,9 @@ ENDIF(OPENSSL_FOUND) # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # -IF (WORKBENCH_USE_QT5) - message("WORKBENCH_USE_QT5 defined") -ELSE () - message("WORKBENCH_USE_QT5 NOT defined") -ENDIF () - +SET(QT_RESULT "Not Found") SET(CARET_QT5_LINK "") IF (WORKBENCH_USE_QT5) - # # The OpenGL module is deprecated in Qt5 and # is needed only if QGLWidget is used for @@ -218,10 +203,8 @@ IF (WORKBENCH_USE_QT5) # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used # for OpenGL. Otherwise, QGLWidget is used. # - MESSAGE("Configuring to use QOpenGLWidget instead of deprecated QGLWidget") add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ELSE () - MESSAGE("Configuring to use deprecated QGLWidget instead of new QOpenGLWidget") remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ENDIF () @@ -235,6 +218,7 @@ IF (WORKBENCH_USE_QT5) #small hack to get the qt5 compile flag requirements into libraries SET(CARET_QT5_LINK "Qt5::Core") + SET(QT_RESULT "${Qt5_VERSION}") ELSE () MESSAGE(FATAL_ERROR "Qt5 was required but not found") ENDIF () @@ -242,15 +226,17 @@ ELSE () FIND_PACKAGE(Qt4 4.8 REQUIRED) IF(QT4_FOUND) INCLUDE(${QT_USE_FILE}) + MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") + SET(QT_RESULT "${QTVERSION}") ELSE(QT4_FOUND) MESSAGE(FATAL_ERROR "QT4 not found") ENDIF(QT4_FOUND) - MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") ENDIF () # # Try to find Qwt, utherwise use bundle # +SET(QWT_RESULT "Not Found") IF (NOT WIN32) PKG_CHECK_MODULES(Qwt qwt) ENDIF (NOT WIN32) @@ -258,8 +244,10 @@ IF (Qwt_FOUND) MESSAGE("Qwt library found") MESSAGE(" INCLUDES ${Qwt_INCLUDE_DIRS}") MESSAGE(" LIBS ${Qwt_LIBRARIES}") + SET(QWT_RESULT "Using Qwt Library ${Qwt_LIBRARIES}") ELSE (Qwt_FOUND) MESSAGE("Qwt library not found, using bundled") + SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) # @@ -298,6 +286,7 @@ ENDIF (NOT OPENMP_FOUND) # # If OpenMP is found, may need to set compiler and linker flags # +SET(OPENMP_RESULT "Not Found") IF (OPENMP_FOUND) # add definitions will add the flag to the linker and resource compilers, which don't understand the openmp option SET(CMAKE_CXX_FLAGS "${OpenMP_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") @@ -313,6 +302,7 @@ IF (OPENMP_FOUND) ENDIF() MESSAGE("OpenMP was Found") MESSAGE(" OpenMP_CXX_FLAGS: ${OpenMP_CXX_FLAGS}") + SET(OPENMP_RESULT "Yes") ELSE (OPENMP_FOUND) MESSAGE(WARNING "OpenMP was not found") @@ -331,9 +321,11 @@ MESSAGE("\nC++ flags ${CMAKE_CXX_FLAGS}\n") # # MUST have ZLIB # +SET(ZLIB_RESULT "Not Found") FIND_PACKAGE(ZLIB) IF ( ZLIB_FOUND ) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) + SET(ZLIB_RESULT ${ZLIB_VERSION_STRING}) ELSE (ZLIB_FOUND) MESSAGE(FATAL_ERROR "ZLIB was not found. It may be necessary to define " "the variable ZLIB_ROOT when running cmake so that " @@ -346,11 +338,13 @@ ENDIF (ZLIB_FOUND) # # Try to find QuaZip, otherwise use bundled # -FIND_PACKAGE(QuaZip) +SET(QUAZIP_RESULT "Not Found") +FIND_PACKAGE(QuaZip QUIET) IF (QUAZIP_FOUND) MESSAGE("QuaZip library found") MESSAGE(" INCLUDES ${QUAZIP_INCLUDE_DIRS}") MESSAGE(" LIBS ${QUAZIP_LIBRARIES}") + SET(QUAZIP_RESULT "Using QuaZip Library ${QUAZIP_LIBRARIES}") ELSE (QUAZIP_FOUND) MESSAGE("QuaZip library not found, using bundled") # @@ -360,14 +354,16 @@ ELSE (QUAZIP_FOUND) IF(MSVC) ADD_DEFINITIONS(-DQUAZIP_STATIC) ENDIF(MSVC) - ENDIF(WIN32) + ENDIF(WIN32) + SET(QUAZIP_RESULT "In Workbench Source Code") ENDIF (QUAZIP_FOUND) # # Find FreeType # +SET(FREETYPE_RESULT "Not Found") +SET(FTGL_RESULT "Must have FreeType to use FTGL") SET(FTGL_FONT_MODULE_FOR_LINKING "") - IF (DEFINED WORKBENCH_FREETYPE_DIR) # FindFreeType looks for environment variable FREETYPE_DIR as a hint SET(ENV{FREETYPE_DIR} ${WORKBENCH_FREETYPE_DIR}) @@ -387,11 +383,14 @@ IF (FREETYPE_FOUND) MESSAGE("FTGL library found") MESSAGE(" INCLUDES ${FTGL_INCLUDE_DIRS}") MESSAGE(" LIBS ${FTGL_LIBRARIES}") + SET(FTGL_RESULT "Using FTGL Library ${FTGL_LIBRARIES}") ELSE (FTGL_FOUND) MESSAGE("FTGL library not found, using bundled") + SET(FTGL_RESULT "In Workbench Source Code") ENDIF (FTGL_FOUND) ADD_DEFINITIONS(-DHAVE_FREETYPE) + SET(FREETYPE_RESULT "${FREETYPE_VERSION_STRING} ${FREETYPE_LIBRARIES}") ELSE (FREETYPE_FOUND) SET (FREETYPE_LIBRARY "") SET (FREETYPE_LIBRARIES "") @@ -424,6 +423,7 @@ SET(OSMESA_GL_LIBRARY "") SET(OSMESA_GLU_LIBRARY "") SET(OSMESA_INCLUDE_DIRECTORY "") +SET(OSMESA_RESULT "Not found") MESSAGE("OSMESA_DIR: ${WORKBENCH_MESA_DIR}") IF (EXISTS ${WORKBENCH_MESA_DIR}) IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) @@ -452,6 +452,8 @@ IF (EXISTS ${WORKBENCH_MESA_DIR}) MESSAGE(" Libraries: ${OSMESA_OFFSCREEN_LIBRARY}") MESSAGE(" Libraries: ${OSMESA_GL_LIBRARY}") MESSAGE(" Libraries: ${OSMESA_GLU_LIBRARY}") + + SET(OSMESA_RESULT ${OSMESA_OFFSCREEN_LIBRARY}) ENDIF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}) @@ -507,15 +509,57 @@ ENDIF() # ENABLE_TESTING() - - # -# Print values of Workbench Variables +# This is for help with finding variables created +# by "Find" type commands +# To use, set DEBUG_VARIABLE_PREFIX to the prefix +# of variables that are sought. For example, +# set to "Q" to find all variables beginning +# with "Q". Or, set to "OSMESA" to find print +# all OSMESA variables. +SET(DEBUG_VARIABLE_PREFIX "") +IF(NOT (DEBUG_VARIABLE_PREFIX STREQUAL "")) + get_cmake_property( debugAllVars VARIABLES ) + foreach( debugVar in ${debugAllVars} ) + string(FIND ${debugVar} ${DEBUG_VARIABLE_PREFIX} debugOffset) + if(${debugOffset} EQUAL 0) + message(${MSG_TYPE} ${MSG_INDENT} "${debugVar}=${${debugVar}}" ) + endif() + endforeach() +ENDIF() + # +# Print Summary +# +SET(MSG_TYPE "") +SET(MSG_INDENT " ") +MESSAGE(${MSG_TYPE} "************* SUMMARY FROM RUNNING CMake ********************") +FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") +MESSAGE(${MSG_TYPE} "TOOLS:") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") +MESSAGE(${MSG_TYPE} "WORKBENCH VARIABLES:") get_cmake_property( allVars VARIABLES ) foreach( var in ${allVars} ) string(FIND ${var} "WORKBENCH" workbenchOffset) if(${workbenchOffset} EQUAL 0) - message(STATUS " ${var}=${${var}}" ) + message(${MSG_TYPE} ${MSG_INDENT} "${var}=${${var}}" ) endif() endforeach() + +MESSAGE(${MSG_TYPE} "PACKAGES:") +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) +MESSAGE(${MSG_TYPE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) + +MESSAGE(${MSG_TYPE} "************* END SUMMARY FROM RUNNING CMake *****************") -- GitLab From 1c51c19e82af21321c41f1d337a4cb2c62557e31 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 14 Nov 2016 12:51:51 -0600 Subject: [PATCH 047/755] Finished cleanup of CMakeLists.txt files to remove excess output and print a summary at the end. --- src/Brain/CMakeLists.txt | 2 +- src/CMakeLists.txt | 320 ++++++++++++++++++++------------- src/CommandLine/CMakeLists.txt | 4 +- src/Desktop/CMakeLists.txt | 7 +- src/FtglFont/CMakeLists.txt | 2 +- 5 files changed, 202 insertions(+), 133 deletions(-) diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 9517452cd..38f80ef3b 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -43,7 +43,7 @@ IF (OPENGL_FOUND) # INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) ELSE (OPENGL_FOUND) - MESSAGE(FATAL_ERROR "OpenGL Libraries were not found") + MESSAGE(SEND_ERROR "OpenGL Libraries were not found") ENDIF (OPENGL_FOUND) # diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42976d751..229f2eb6d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,22 +3,51 @@ # CMAKE_MINIMUM_REQUIRED (VERSION 2.8) -MESSAGE("\nCMake Version: ${CMAKE_VERSION}\n") +# +# Set to true for verbose output when debugging this file +# +SET(WB_CMAKE_VERBOSE_OUTPUT_FLAG FALSE) + +########################################################################################## +# +# A function to get all user defined variables with a specified prefix +# From https://cmake.org/Wiki/CMake/Tutorials/SettingVariableGroups +# +function (getListOfVarsStartingWith _prefix _varResult) + get_cmake_property(_vars CACHE_VARIABLES) + string (REGEX MATCHALL "(^|;)${_prefix}[A-Za-z0-9_]*" _matchedVars "${_vars}") + set (${_varResult} ${_matchedVars} PARENT_SCOPE) +endfunction() + -#TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options +########################################################################################## +# +# Workbench CACHE variables +# TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options +# +set (WORKBENCH_QT5_DISABLE_DEPRECATED FALSE CACHE BOOL + "If TRUE, use of Qt 5 deprecated functionality will cause compiler error") +set (WORKBENCH_USE_CMAKE_AUTOMOC FALSE CACHE BOOL + "If TRUE, use CMAKE_AUTOMOC command for generating 'moc' files") +set (WORKBENCH_USE_QT5 FALSE CACHE BOOL + "If TRUE, require Qt5, else Qt4.Specify as argument to cmake: -DWORKBENCH_USE_QT5=TRUE") +set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL + "With Qt5, QOpenGLWidget instead of deprecated QGLWidget") +set (WORKBENCH_MESA_DIR "" CACHE PATH + "Directory containing Mesa's 'include' and 'lib' directories. Mesa is optional and used by wb_command's -show-scene operation.") -set (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR FALSE CACHE BOOL "If TRUE, produce fatal compiler error for Qt 5 deprecated functionality") -set (WORKBENCH_USE_QT5 FALSE CACHE BOOL "Enable search for Qt 5.x libraries. Must be passed as an argument to CMake: cmake -DWORKBENCH_USE_QT5=TRUE ") -set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "If Qt 5.x is used, use QOpenGLWidget instead of deprecated QGLWidget") -set (WORKBENCH_MESA_DIR "" CACHE PATH "Path to the Mesa root directory that contains the 'include' and 'lib' directories. Mesa is optional and used by wb_command's -show-scene operation.") +# +# Shows compilation command when true +# Should we be setting this (JWH 14 Nov 2016) ???? +# +SET(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "cause all build commands to be displayed") + +########################################################################################## # # Setting the compiler MUST be done before the PROJECT # statement or else an infinite loop will occur indicating # that the compiler has been redefined. # - - - IF(APPLE) ADD_DEFINITIONS(-DCARET_OS_MACOSX) ELSEIF(UNIX) @@ -34,24 +63,17 @@ ELSEIF(WIN32) endif() IF(MSVC) ADD_DEFINITIONS(-DCARET_OS_WINDOWS_MSVC) - IF(CMAKE_CL_64) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) + IF(CMAKE_CL_64) ELSE() - ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) - SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) ENDIF(CMAKE_CL_64) ELSE(MSVC) ENDIF(MSVC) ELSE(APPLE) - MESSAGE(FATAL_ERROR "Unrecognized operating system " ${CMAKE_SYSTEM_NAME}) + MESSAGE(SEND_ERROR "Unrecognized operating system " ${CMAKE_SYSTEM_NAME}) ENDIF(APPLE) -# -# Shows compilation command when true -# -SET(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "cause all build commands to be displayed") - # # Intel compiler # @@ -70,7 +92,6 @@ IF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang2\\+\\+.*") SET(CLANG_FLAG TRUE) ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang2\\+\\+.*") IF (CLANG_FLAG) - MESSAGE("USING CLANG COMPILER ${CMAKE_CXX_COMPILER}") ADD_DEFINITIONS("-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter -Wno-deprecated-declarations") ENDIF (CLANG_FLAG) @@ -102,11 +123,13 @@ IF (NOT MSVC) endif() ENDIF (NOT MSVC) +########################################################################################## # # If GNU compiler, use SIMD-based dot computation, if possible # -if (CMAKE_COMPILER_IS_GNUCC) - +SET(SIMD_RESULT "Search for SIMD disabled for compiler on this system.") +if (CMAKE_COMPILER_IS_GNUCC + OR CLANG_FLAG) # # Define flag to avoid trying to compile SIMD stuff (coded for x86 only) # @@ -117,32 +140,47 @@ if (CMAKE_COMPILER_IS_GNUCC) # IF (WORKBENCH_USE_SIMD) TRY_COMPILE(CPUINFO_COMPILES ${CMAKE_CURRENT_BINARY_DIR}/cpuinfo_compile_test ${CMAKE_CURRENT_SOURCE_DIR}/kloewe/cpuinfo cpuinfo) - MESSAGE("CPUINFO_COMPILES: ${CPUINFO_COMPILES}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("SIMD CPUINFO_COMPILES: ${CPUINFO_COMPILES}") + ENDIF() + + # + # Add the necessary definition and include directory to enable the + # SIMD-based dot product implementations + # + IF (CPUINFO_COMPILES) + ADD_DEFINITIONS(-DCARET_DOTFCN) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/kloewe/dot/src) + SET(SIMD_RESULT "Enabled") + ELSE() + SET(SIMD_RESULT "Failed when compiling with SIMD") + ENDIF() + ELSE (WORKBENCH_USE_SIMD) + SET(SIMD_RESULT "Search for SIMD disabled, WORKBENCH_USE_SIMD=FALSE") ENDIF (WORKBENCH_USE_SIMD) - - # - # Add the necessary definition and include directory to enable the SIMD-based dot product implementations - # - if (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) - ADD_DEFINITIONS(-DCARET_DOTFCN) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/kloewe/dot/src) - endif() endif() +########################################################################################## +# +# OpenSSL +# SET(OPENSSL_RESULT "Not Found") FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - MESSAGE("OpenSSL version=${OPENSSL_VERSION}") - MESSAGE("OpenSSL include=${OPENSSL_INCLUDE_DIR}") - MESSAGE("OpenSSL libraries=${OPENSSL_LIBRARIES}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("OpenSSL version=${OPENSSL_VERSION}") + MESSAGE("OpenSSL include=${OPENSSL_INCLUDE_DIR}") + MESSAGE("OpenSSL libraries=${OPENSSL_LIBRARIES}") + ENDIF() SET(OPENSSL_RESULT "${OPENSSL_VERSION} ${OPENSSL_LIBRARIES}") ELSE (OPENSSL_FOUND) - MESSAGE("OpenSSL NOT FOUND. You may need to define OPENSSL_ROOT_DIR when running CMake.") + MESSAGE("OpenSSL NOT FOUND. May need to define OPENSSL_ROOT_DIR when running CMake.") MESSAGE(" cmake -DOPENSSL_ROOT_DIR= \n") MESSAGE("See: https://cmake.org/cmake/help/v3.5/module/FindOpenSSL.html") ENDIF(OPENSSL_FOUND) +########################################################################################## # # Must have QT 4.8 or QT 5.6 or later # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) @@ -162,7 +200,6 @@ IF (WORKBENCH_USE_QT5) FIND_PACKAGE(Qt5 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) IF (Qt5_FOUND) - MESSAGE("Found Qt 5") IF (NOT Qt5Concurrent_FOUND) STRING(APPEND moduleError "Qt5 Concurrentmodule not found\n") ENDIF() @@ -193,7 +230,7 @@ IF (WORKBENCH_USE_QT5) STRING(APPEND moduleError "Qt5 XML module not found\n") ENDIF() IF (moduleError) - MESSAGE(FATAL_ERROR "Missing Modules\n" ${moduleError}) + MESSAGE(SEND_ERROR "Missing Qt5 Modules\n" ${moduleError}) ENDIF() IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) @@ -208,7 +245,7 @@ IF (WORKBENCH_USE_QT5) remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ENDIF () - IF (WORKBENCH_QT5_DEPRECATED_FATAL_ERROR) + IF (WORKBENCH_QT5_DISABLE_DEPRECATED) # Causes Qt to remove declarations for deprecated functionality add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700) # Enable usage of replacements for Qt deprecated functionality in Workbench source code @@ -220,36 +257,41 @@ IF (WORKBENCH_USE_QT5) SET(QT_RESULT "${Qt5_VERSION}") ELSE () - MESSAGE(FATAL_ERROR "Qt5 was required but not found") + MESSAGE(SEND_ERROR "Qt5 was required but not found") ENDIF () ELSE () FIND_PACKAGE(Qt4 4.8 REQUIRED) IF(QT4_FOUND) INCLUDE(${QT_USE_FILE}) - MESSAGE("QT_USE_FILE: ${QT_USE_FILE}") SET(QT_RESULT "${QTVERSION}") ELSE(QT4_FOUND) - MESSAGE(FATAL_ERROR "QT4 not found") + MESSAGE(SEND_ERROR "QT4 not found") ENDIF(QT4_FOUND) ENDIF () +########################################################################################## # -# Try to find Qwt, utherwise use bundle +# Try to find Qwt, otherwise use bundle # SET(QWT_RESULT "Not Found") IF (NOT WIN32) PKG_CHECK_MODULES(Qwt qwt) ENDIF (NOT WIN32) IF (Qwt_FOUND) - MESSAGE("Qwt library found") - MESSAGE(" INCLUDES ${Qwt_INCLUDE_DIRS}") - MESSAGE(" LIBS ${Qwt_LIBRARIES}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("Qwt library found") + MESSAGE(" INCLUDES ${Qwt_INCLUDE_DIRS}") + MESSAGE(" LIBS ${Qwt_LIBRARIES}") + ENDIF() SET(QWT_RESULT "Using Qwt Library ${Qwt_LIBRARIES}") ELSE (Qwt_FOUND) - MESSAGE("Qwt library not found, using bundled") + IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("Qwt library not found, using bundled") + ENDIF() SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) +########################################################################################## # # The Find OpenMP package may not work on all systems and the user may # furnish the paths to the OpenMP files by using environment variables. @@ -300,8 +342,10 @@ IF (OPENMP_FOUND) SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel") ADD_DEFINITIONS("-static-intel") ENDIF() - MESSAGE("OpenMP was Found") - MESSAGE(" OpenMP_CXX_FLAGS: ${OpenMP_CXX_FLAGS}") + IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("OpenMP was Found") + MESSAGE(" OpenMP_CXX_FLAGS: ${OpenMP_CXX_FLAGS}") + ENDIF() SET(OPENMP_RESULT "Yes") ELSE (OPENMP_FOUND) MESSAGE(WARNING "OpenMP was not found") @@ -316,8 +360,7 @@ ELSE (OPENMP_FOUND) ENDIF (CLANG_FLAG) ENDIF(OPENMP_FOUND) -MESSAGE("\nC++ flags ${CMAKE_CXX_FLAGS}\n") - +########################################################################################## # # MUST have ZLIB # @@ -327,7 +370,7 @@ IF ( ZLIB_FOUND ) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) SET(ZLIB_RESULT ${ZLIB_VERSION_STRING}) ELSE (ZLIB_FOUND) - MESSAGE(FATAL_ERROR "ZLIB was not found. It may be necessary to define " + MESSAGE(SEND_ERROR "ZLIB was not found. It may be necessary to define " "the variable ZLIB_ROOT when running cmake so that " "the FindZLIB module is able to find ZLIB.\n" " cmake -DZLIB_ROOT= \n" @@ -335,18 +378,23 @@ ELSE (ZLIB_FOUND) "https://cmake.org/cmake/help/v3.5/module/FindZLIB.html") ENDIF (ZLIB_FOUND) +########################################################################################## # # Try to find QuaZip, otherwise use bundled # SET(QUAZIP_RESULT "Not Found") FIND_PACKAGE(QuaZip QUIET) IF (QUAZIP_FOUND) - MESSAGE("QuaZip library found") - MESSAGE(" INCLUDES ${QUAZIP_INCLUDE_DIRS}") - MESSAGE(" LIBS ${QUAZIP_LIBRARIES}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("QuaZip library found") + MESSAGE(" INCLUDES ${QUAZIP_INCLUDE_DIRS}") + MESSAGE(" LIBS ${QUAZIP_LIBRARIES}") + ENDIF() SET(QUAZIP_RESULT "Using QuaZip Library ${QUAZIP_LIBRARIES}") ELSE (QUAZIP_FOUND) - MESSAGE("QuaZip library not found, using bundled") + IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("QuaZip library not found, using bundled") + ENDIF() # # Quazip needs this defined here for static linking on windows # @@ -358,6 +406,7 @@ ELSE (QUAZIP_FOUND) SET(QUAZIP_RESULT "In Workbench Source Code") ENDIF (QUAZIP_FOUND) +########################################################################################## # # Find FreeType # @@ -370,22 +419,28 @@ IF (DEFINED WORKBENCH_FREETYPE_DIR) ENDIF () FIND_PACKAGE(Freetype) IF (FREETYPE_FOUND) - MESSAGE("FreeType library found") - MESSAGE(" INCLUDES ${FREETYPE_INCLUDE_DIRS}") - MESSAGE(" INCLUDES_FT2_BUILD ${FREETYPE_INCLUDE_DIR_ft2build}") - MESSAGE(" INCLUDES_FT2 ${FREETYPE_INCLUDE_DIR_freetype2}") - MESSAGE(" LIBS ${FREETYPE_LIBRARIES}") - + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("FreeType library found") + MESSAGE(" INCLUDES ${FREETYPE_INCLUDE_DIRS}") + MESSAGE(" INCLUDES_FT2_BUILD ${FREETYPE_INCLUDE_DIR_ft2build}") + MESSAGE(" INCLUDES_FT2 ${FREETYPE_INCLUDE_DIR_freetype2}") + MESSAGE(" LIBS ${FREETYPE_LIBRARIES}") + ENDIF() + IF (NOT WIN32) PKG_CHECK_MODULES(FTGL ftgl) ENDIF (NOT WIN32) IF (FTGL_FOUND) - MESSAGE("FTGL library found") - MESSAGE(" INCLUDES ${FTGL_INCLUDE_DIRS}") - MESSAGE(" LIBS ${FTGL_LIBRARIES}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("FTGL library found") + MESSAGE(" INCLUDES ${FTGL_INCLUDE_DIRS}") + MESSAGE(" LIBS ${FTGL_LIBRARIES}") + ENDIF() SET(FTGL_RESULT "Using FTGL Library ${FTGL_LIBRARIES}") ELSE (FTGL_FOUND) - MESSAGE("FTGL library not found, using bundled") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("FTGL library not found, using bundled") + ENDIF() SET(FTGL_RESULT "In Workbench Source Code") ENDIF (FTGL_FOUND) @@ -401,6 +456,7 @@ ELSE (FREETYPE_FOUND) MESSAGE(" 'include' and 'lib' directories.") ENDIF (FREETYPE_FOUND) +########################################################################################## # # Fixes issue with XCode and newer version of CMake. # It prevents the ZERO_CHECK dependency from running @@ -410,11 +466,12 @@ ENDIF (FREETYPE_FOUND) IF (APPLE) SET (CMAKE_SUPPRESS_REGENERATION TRUE) ENDIF (APPLE) -#============================================================================= + +########################################################################################## # -# Test for offscreen mesa (optional library) -# If found, set some variables. Since, Mesa is only used for -# command line +# Test for offscreen MESA (optional library) +# Mesa is used by wb_command's -show-scene. +# If Mesa is not found, the "-show-scene" command will not be available. # SET(OSMESA_FOUND FALSE) SET(OSMESA_DEFINITION "") @@ -424,10 +481,11 @@ SET(OSMESA_GLU_LIBRARY "") SET(OSMESA_INCLUDE_DIRECTORY "") SET(OSMESA_RESULT "Not found") -MESSAGE("OSMESA_DIR: ${WORKBENCH_MESA_DIR}") IF (EXISTS ${WORKBENCH_MESA_DIR}) IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) - MESSAGE("Have Mesa Include Directory") + IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("Have Mesa Include Directory") + ENDIF() FIND_LIBRARY(OSMESA_LIBRARY_FOUND NAMES OSMesa HINTS ${WORKBENCH_MESA_DIR}/lib) @@ -437,7 +495,9 @@ IF (EXISTS ${WORKBENCH_MESA_DIR}) FIND_LIBRARY(OSMESA_GLU_LIBRARY_FOUND NAMES GLU HINTS ${WORKBENCH_MESA_DIR}/lib) - MESSAGE("OSMesa lib: " ${OSMESA_LIBRARY}) + IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("OSMesa lib: " ${OSMESA_LIBRARY_FOUND}) + ENDIF() IF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_DEFINITION -DHAVE_OSMESA) SET(OSMESA_OFFSCREEN_LIBRARY ${OSMESA_LIBRARY_FOUND}) @@ -446,26 +506,21 @@ IF (EXISTS ${WORKBENCH_MESA_DIR}) SET(OSMESA_INCLUDE_DIRECTORY ${WORKBENCH_MESA_DIR}/include) SET(OSMESA_FOUND TRUE) - MESSAGE("Offscreen Mesa Library was found") - MESSAGE(" Definition: ${OSMESA_DEFINITION}") - MESSAGE(" Include: ${OSMESA_INCLUDE_DIRECTORY}") - MESSAGE(" Libraries: ${OSMESA_OFFSCREEN_LIBRARY}") - MESSAGE(" Libraries: ${OSMESA_GL_LIBRARY}") - MESSAGE(" Libraries: ${OSMESA_GLU_LIBRARY}") + IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + MESSAGE("Offscreen Mesa Library was found") + MESSAGE(" Definition: ${OSMESA_DEFINITION}") + MESSAGE(" Include: ${OSMESA_INCLUDE_DIRECTORY}") + MESSAGE(" Libraries: ${OSMESA_OFFSCREEN_LIBRARY}") + MESSAGE(" Libraries: ${OSMESA_GL_LIBRARY}") + MESSAGE(" Libraries: ${OSMESA_GLU_LIBRARY}") + ENDIF() SET(OSMESA_RESULT ${OSMESA_OFFSCREEN_LIBRARY}) ENDIF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}) -#============================================================================= -MESSAGE("") -MESSAGE("Compiler: ${CMAKE_CXX_COMPILER}") -MESSAGE("Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") -MESSAGE("") -#============================================================================= - - +########################################################################################## # # All subdirectories that will be configured for building # @@ -504,62 +559,75 @@ if (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) ADD_SUBDIRECTORY ( kloewe/dot ) ENDIF() +########################################################################################## # -#CTest tests +# CTest tests # ENABLE_TESTING() +########################################################################################## +# +# DEBUGGING ONLY +# +# Some find modules do not always document all of their variables. +# If you know the prefix for the find module's variables, +# this code can be used to print the variables by setting +# DEBUG_VARIABLE_PREFIX to the prefix. +# For example, set to "Q" to find all variables beginning from Qt +# or to "OSMESA" to print all OSMESA variables. # -# This is for help with finding variables created -# by "Find" type commands -# To use, set DEBUG_VARIABLE_PREFIX to the prefix -# of variables that are sought. For example, -# set to "Q" to find all variables beginning -# with "Q". Or, set to "OSMESA" to find print -# all OSMESA variables. SET(DEBUG_VARIABLE_PREFIX "") IF(NOT (DEBUG_VARIABLE_PREFIX STREQUAL "")) - get_cmake_property( debugAllVars VARIABLES ) - foreach( debugVar in ${debugAllVars} ) - string(FIND ${debugVar} ${DEBUG_VARIABLE_PREFIX} debugOffset) - if(${debugOffset} EQUAL 0) + getListOfVarsStartingWith(${DEBUG_VARIABLE_PREFIX} allVars) + foreach( debugVar IN LISTS allVars ) message(${MSG_TYPE} ${MSG_INDENT} "${debugVar}=${${debugVar}}" ) - endif() endforeach() ENDIF() +########################################################################################## # # Print Summary # -SET(MSG_TYPE "") +SET(MSG_MODE "") #Optional SET(MSG_INDENT " ") -MESSAGE(${MSG_TYPE} "************* SUMMARY FROM RUNNING CMake ********************") +MESSAGE(${MSG_MODE} "************* SUMMARY FROM RUNNING CMake ********************") FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") -MESSAGE(${MSG_TYPE} "TOOLS:") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") -MESSAGE(${MSG_TYPE} "WORKBENCH VARIABLES:") -get_cmake_property( allVars VARIABLES ) -foreach( var in ${allVars} ) - string(FIND ${var} "WORKBENCH" workbenchOffset) - if(${workbenchOffset} EQUAL 0) - message(${MSG_TYPE} ${MSG_INDENT} "${var}=${${var}}" ) - endif() + +cmake_host_system_information(RESULT hostName QUERY "FQDN") +cmake_host_system_information(RESULT hostCores QUERY "NUMBER_OF_LOGICAL_CORES") +MESSAGE(${MSG_MODE} "HOST:") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "Name: ${hostName}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "Number of cores: ${hostCores}") +MESSAGE(${MSG_MODE} "TOOLS:") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Build Type: ${CMAKE_BUILD_TYPE}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") + +MESSAGE(${MSG_MODE} "WORKBENCH VARIABLES:") +getListOfVarsStartingWith("WORKBENCH" allVars) +foreach( var IN LISTS allVars ) + get_property(docString CACHE ${var} PROPERTY HELPSTRING) + message(${MSG_MODE} ${MSG_INDENT} "${var}=${${var}}" ) + + STRING(REPLACE "" "\n${MSG_INDENT}${MSG_INDENT}" docPrint ${docString}) + message(${MSG_MODE} ${MSG_INDENT} ${MSG_INDENT} ${docPrint}) endforeach() -MESSAGE(${MSG_TYPE} "PACKAGES:") -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) -MESSAGE(${MSG_TYPE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) - -MESSAGE(${MSG_TYPE} "************* END SUMMARY FROM RUNNING CMake *****************") +MESSAGE(${MSG_MODE} "PACKAGES:") +MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "SIMD: " ${SIMD_RESULT}) +MESSAGE(${MSG_MODE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) + +MESSAGE(${MSG_MODE} "************* END SUMMARY FROM RUNNING CMake *****************") + diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index b29237f3f..604751f38 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -32,7 +32,9 @@ SET (RESOURCES_QRC_FILE ../Resources/General/general_resources.qrc) IF (Qt5_FOUND) QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ELSE (Qt5_FOUND) - QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) + IF (QT4_FOUND) + QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) + ENDIF() ENDIF (Qt5_FOUND) # diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 0dd20bf2b..78f763f0f 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -46,7 +46,9 @@ SET (RESOURCES_QRC_FILE IF (Qt5_FOUND) QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ELSE (Qt5_FOUND) - QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) + IF (QT4_FOUND) + QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) + ENDIF() ENDIF (Qt5_FOUND) # @@ -109,8 +111,6 @@ if(Qt5_FOUND) Qt5::Test Qt5::Widgets Qt5::Xml) - - message("*** QT5_LINK_LIBS: ${QT5_LINK_LIBS}") endif() # @@ -215,7 +215,6 @@ ${CMAKE_SOURCE_DIR}/Common # Apple needs framework # IF (APPLE) - MESSAGE("EXE: " ${CMAKE_BUILD_DIR} " " ${EXE_NAME}) ADD_CUSTOM_COMMAND( TARGET ${EXE_NAME} POST_BUILD diff --git a/src/FtglFont/CMakeLists.txt b/src/FtglFont/CMakeLists.txt index 76869896f..e6dad49fd 100644 --- a/src/FtglFont/CMakeLists.txt +++ b/src/FtglFont/CMakeLists.txt @@ -34,7 +34,7 @@ IF (OPENGL_FOUND) # INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) ELSE (OPENGL_FOUND) - MESSAGE(FATAL_ERROR "OpenGL Libraries were not found") + MESSAGE(SEND_ERROR "OpenGL Libraries were not found") ENDIF (OPENGL_FOUND) # -- GitLab From 9172e3098c2c05f018a3358a0b8129491a3097c2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 14 Nov 2016 16:03:58 -0600 Subject: [PATCH 048/755] Removed fatal error from text in CMakeLists.txt to so that older build scripts do not see 'fatal' or 'error' and think the build has failed. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 229f2eb6d..ce24d4b14 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,7 @@ endfunction() # TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options # set (WORKBENCH_QT5_DISABLE_DEPRECATED FALSE CACHE BOOL - "If TRUE, use of Qt 5 deprecated functionality will cause compiler error") + "If TRUE, use of Qt 5 deprecated functionality will cause compiler to fail") set (WORKBENCH_USE_CMAKE_AUTOMOC FALSE CACHE BOOL "If TRUE, use CMAKE_AUTOMOC command for generating 'moc' files") set (WORKBENCH_USE_QT5 FALSE CACHE BOOL -- GitLab From 8051a2f8952c85846031e46d5a671bfd3c3730bf Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 14 Nov 2016 16:07:47 -0600 Subject: [PATCH 049/755] fix bug in completion parser, remove unnecessary host information from cmake --- src/CMakeLists.txt | 5 ----- src/Commands/CommandParser.cxx | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce24d4b14..d2e5d9a03 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -593,11 +593,6 @@ SET(MSG_INDENT " ") MESSAGE(${MSG_MODE} "************* SUMMARY FROM RUNNING CMake ********************") FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") -cmake_host_system_information(RESULT hostName QUERY "FQDN") -cmake_host_system_information(RESULT hostCores QUERY "NUMBER_OF_LOGICAL_CORES") -MESSAGE(${MSG_MODE} "HOST:") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "Name: ${hostName}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "Number of cores: ${hostCores}") MESSAGE(${MSG_MODE} "TOOLS:") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Build Type: ${CMAKE_BUILD_TYPE}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") diff --git a/src/Commands/CommandParser.cxx b/src/Commands/CommandParser.cxx index 36efddabb..2ebc24cc5 100644 --- a/src/Commands/CommandParser.cxx +++ b/src/Commands/CommandParser.cxx @@ -666,7 +666,7 @@ CommandParser::CompletionInfo CommandParser::completionComponent(ParameterCompon if (parameters.hasNext()) { //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER - AString rawArg = parameters.nextString(myComponent->m_paramList[i]->m_shortName); + AString rawArg = parameters.nextString(myComponent->m_outputList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') { -- GitLab From 1386baeb4713e21ed60ef3c454ec015240c654c2 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 14 Nov 2016 16:50:47 -0600 Subject: [PATCH 050/755] simplify cmakelists by removing duplicate messages, remove nonworking set for verbose, making wb_cmake_verbose control summary message, change qt5 find statement to simply "required" instead of a lot of conditionals to check for each module --- src/CMakeLists.txt | 229 +++++++++++++-------------------------------- 1 file changed, 64 insertions(+), 165 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2e5d9a03..644c697d1 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,7 +6,7 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.8) # # Set to true for verbose output when debugging this file # -SET(WB_CMAKE_VERBOSE_OUTPUT_FLAG FALSE) +SET(WB_CMAKE_VERBOSE_OUTPUT_FLAG TRUE) ########################################################################################## # @@ -36,12 +36,6 @@ set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL set (WORKBENCH_MESA_DIR "" CACHE PATH "Directory containing Mesa's 'include' and 'lib' directories. Mesa is optional and used by wb_command's -show-scene operation.") -# -# Shows compilation command when true -# Should we be setting this (JWH 14 Nov 2016) ???? -# -SET(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "cause all build commands to be displayed") - ########################################################################################## # # Setting the compiler MUST be done before the PROJECT @@ -140,9 +134,6 @@ if (CMAKE_COMPILER_IS_GNUCC # IF (WORKBENCH_USE_SIMD) TRY_COMPILE(CPUINFO_COMPILES ${CMAKE_CURRENT_BINARY_DIR}/cpuinfo_compile_test ${CMAKE_CURRENT_SOURCE_DIR}/kloewe/cpuinfo cpuinfo) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("SIMD CPUINFO_COMPILES: ${CPUINFO_COMPILES}") - ENDIF() # # Add the necessary definition and include directory to enable the @@ -168,11 +159,6 @@ SET(OPENSSL_RESULT "Not Found") FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("OpenSSL version=${OPENSSL_VERSION}") - MESSAGE("OpenSSL include=${OPENSSL_INCLUDE_DIR}") - MESSAGE("OpenSSL libraries=${OPENSSL_LIBRARIES}") - ENDIF() SET(OPENSSL_RESULT "${OPENSSL_VERSION} ${OPENSSL_LIBRARIES}") ELSE (OPENSSL_FOUND) MESSAGE("OpenSSL NOT FOUND. May need to define OPENSSL_ROOT_DIR when running CMake.") @@ -182,7 +168,7 @@ ENDIF(OPENSSL_FOUND) ########################################################################################## # -# Must have QT 4.8 or QT 5.6 or later +# Must have QT 4.8 or QT 5, recommended 5.6 or later # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # @@ -198,67 +184,30 @@ IF (WORKBENCH_USE_QT5) SET(WB_QT_OPENGL_MODULE "OpenGL") ENDIF () - FIND_PACKAGE(Qt5 COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) - IF (Qt5_FOUND) - IF (NOT Qt5Concurrent_FOUND) - STRING(APPEND moduleError "Qt5 Concurrentmodule not found\n") - ENDIF() - IF (NOT Qt5Core_FOUND) - STRING(APPEND moduleError "Qt5 Core module not found\n") - ENDIF() - IF (NOT Qt5Gui_FOUND) - STRING(APPEND moduleError "Qt5 Gui module not found\n") - ENDIF() - IF (NOT Qt5Network_FOUND) - STRING(APPEND moduleError "Qt5 Network module not found\n") - ENDIF() - IF (NOT WORKBENCH_USE_QT5_QOPENGL_WIDGET) - IF (NOT Qt5OpenGL_FOUND) - STRING(APPEND moduleError "Qt5 OpenGL module not found\n") - ENDIF() - ENDIF () - IF (NOT Qt5PrintSupport_FOUND) - STRING(APPEND moduleError "Qt5 Print Support module not found\n") - ENDIF() - IF (NOT Qt5Test_FOUND) - STRING(APPEND moduleError "Qt5 Test module not found\n") - ENDIF() - IF (NOT Qt5Widgets_FOUND) - STRING(APPEND moduleError "Qt5 Widgets module not found\n") - ENDIF() - IF (NOT Qt5Xml_FOUND) - STRING(APPEND moduleError "Qt5 XML module not found\n") - ENDIF() - IF (moduleError) - MESSAGE(SEND_ERROR "Missing Qt5 Modules\n" ${moduleError}) - ENDIF() - - IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) - # - # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget - # - # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used - # for OpenGL. Otherwise, QGLWidget is used. - # - add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) - ELSE () - remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) - ENDIF () - - IF (WORKBENCH_QT5_DISABLE_DEPRECATED) - # Causes Qt to remove declarations for deprecated functionality - add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700) - # Enable usage of replacements for Qt deprecated functionality in Workbench source code - add_definitions(-DWORKBENCH_REPLACE_QT_DEPRECATED) - ENDIF () - - #small hack to get the qt5 compile flag requirements into libraries - SET(CARET_QT5_LINK "Qt5::Core") - - SET(QT_RESULT "${Qt5_VERSION}") - ELSE () - MESSAGE(SEND_ERROR "Qt5 was required but not found") - ENDIF () + FIND_PACKAGE(Qt5 REQUIRED COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml) + IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) + # + # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget + # + # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used + # for OpenGL. Otherwise, QGLWidget is used. + # + add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) + ELSE (WORKBENCH_USE_QT5_QOPENGL_WIDGET) + remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) + ENDIF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) + + IF (WORKBENCH_QT5_DISABLE_DEPRECATED) + # Causes Qt to remove declarations for deprecated functionality + add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700) + # Enable usage of replacements for Qt deprecated functionality in Workbench source code + add_definitions(-DWORKBENCH_REPLACE_QT_DEPRECATED) + ENDIF (WORKBENCH_QT5_DISABLE_DEPRECATED) + + #small hack to get the qt5 compile flag requirements into libraries + SET(CARET_QT5_LINK "Qt5::Core") + + SET(QT_RESULT "${Qt5_VERSION}") ELSE () FIND_PACKAGE(Qt4 4.8 REQUIRED) IF(QT4_FOUND) @@ -278,16 +227,8 @@ IF (NOT WIN32) PKG_CHECK_MODULES(Qwt qwt) ENDIF (NOT WIN32) IF (Qwt_FOUND) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("Qwt library found") - MESSAGE(" INCLUDES ${Qwt_INCLUDE_DIRS}") - MESSAGE(" LIBS ${Qwt_LIBRARIES}") - ENDIF() SET(QWT_RESULT "Using Qwt Library ${Qwt_LIBRARIES}") ELSE (Qwt_FOUND) - IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("Qwt library not found, using bundled") - ENDIF() SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) @@ -342,10 +283,6 @@ IF (OPENMP_FOUND) SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel") ADD_DEFINITIONS("-static-intel") ENDIF() - IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("OpenMP was Found") - MESSAGE(" OpenMP_CXX_FLAGS: ${OpenMP_CXX_FLAGS}") - ENDIF() SET(OPENMP_RESULT "Yes") ELSE (OPENMP_FOUND) MESSAGE(WARNING "OpenMP was not found") @@ -385,16 +322,8 @@ ENDIF (ZLIB_FOUND) SET(QUAZIP_RESULT "Not Found") FIND_PACKAGE(QuaZip QUIET) IF (QUAZIP_FOUND) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("QuaZip library found") - MESSAGE(" INCLUDES ${QUAZIP_INCLUDE_DIRS}") - MESSAGE(" LIBS ${QUAZIP_LIBRARIES}") - ENDIF() SET(QUAZIP_RESULT "Using QuaZip Library ${QUAZIP_LIBRARIES}") ELSE (QUAZIP_FOUND) - IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("QuaZip library not found, using bundled") - ENDIF() # # Quazip needs this defined here for static linking on windows # @@ -419,28 +348,12 @@ IF (DEFINED WORKBENCH_FREETYPE_DIR) ENDIF () FIND_PACKAGE(Freetype) IF (FREETYPE_FOUND) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("FreeType library found") - MESSAGE(" INCLUDES ${FREETYPE_INCLUDE_DIRS}") - MESSAGE(" INCLUDES_FT2_BUILD ${FREETYPE_INCLUDE_DIR_ft2build}") - MESSAGE(" INCLUDES_FT2 ${FREETYPE_INCLUDE_DIR_freetype2}") - MESSAGE(" LIBS ${FREETYPE_LIBRARIES}") - ENDIF() - IF (NOT WIN32) PKG_CHECK_MODULES(FTGL ftgl) ENDIF (NOT WIN32) IF (FTGL_FOUND) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("FTGL library found") - MESSAGE(" INCLUDES ${FTGL_INCLUDE_DIRS}") - MESSAGE(" LIBS ${FTGL_LIBRARIES}") - ENDIF() SET(FTGL_RESULT "Using FTGL Library ${FTGL_LIBRARIES}") ELSE (FTGL_FOUND) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("FTGL library not found, using bundled") - ENDIF() SET(FTGL_RESULT "In Workbench Source Code") ENDIF (FTGL_FOUND) @@ -483,9 +396,6 @@ SET(OSMESA_INCLUDE_DIRECTORY "") SET(OSMESA_RESULT "Not found") IF (EXISTS ${WORKBENCH_MESA_DIR}) IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) - IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("Have Mesa Include Directory") - ENDIF() FIND_LIBRARY(OSMESA_LIBRARY_FOUND NAMES OSMesa HINTS ${WORKBENCH_MESA_DIR}/lib) @@ -495,9 +405,6 @@ IF (EXISTS ${WORKBENCH_MESA_DIR}) FIND_LIBRARY(OSMESA_GLU_LIBRARY_FOUND NAMES GLU HINTS ${WORKBENCH_MESA_DIR}/lib) - IF (WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("OSMesa lib: " ${OSMESA_LIBRARY_FOUND}) - ENDIF() IF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_DEFINITION -DHAVE_OSMESA) SET(OSMESA_OFFSCREEN_LIBRARY ${OSMESA_LIBRARY_FOUND}) @@ -506,15 +413,6 @@ IF (EXISTS ${WORKBENCH_MESA_DIR}) SET(OSMESA_INCLUDE_DIRECTORY ${WORKBENCH_MESA_DIR}/include) SET(OSMESA_FOUND TRUE) - IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) - MESSAGE("Offscreen Mesa Library was found") - MESSAGE(" Definition: ${OSMESA_DEFINITION}") - MESSAGE(" Include: ${OSMESA_INCLUDE_DIRECTORY}") - MESSAGE(" Libraries: ${OSMESA_OFFSCREEN_LIBRARY}") - MESSAGE(" Libraries: ${OSMESA_GL_LIBRARY}") - MESSAGE(" Libraries: ${OSMESA_GLU_LIBRARY}") - ENDIF() - SET(OSMESA_RESULT ${OSMESA_OFFSCREEN_LIBRARY}) ENDIF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) @@ -588,41 +486,42 @@ ENDIF() # # Print Summary # -SET(MSG_MODE "") #Optional -SET(MSG_INDENT " ") -MESSAGE(${MSG_MODE} "************* SUMMARY FROM RUNNING CMake ********************") -FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") - -MESSAGE(${MSG_MODE} "TOOLS:") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Build Type: ${CMAKE_BUILD_TYPE}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") - -MESSAGE(${MSG_MODE} "WORKBENCH VARIABLES:") -getListOfVarsStartingWith("WORKBENCH" allVars) -foreach( var IN LISTS allVars ) - get_property(docString CACHE ${var} PROPERTY HELPSTRING) - message(${MSG_MODE} ${MSG_INDENT} "${var}=${${var}}" ) - - STRING(REPLACE "" "\n${MSG_INDENT}${MSG_INDENT}" docPrint ${docString}) - message(${MSG_MODE} ${MSG_INDENT} ${MSG_INDENT} ${docPrint}) -endforeach() - -MESSAGE(${MSG_MODE} "PACKAGES:") -MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "SIMD: " ${SIMD_RESULT}) -MESSAGE(${MSG_MODE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) - -MESSAGE(${MSG_MODE} "************* END SUMMARY FROM RUNNING CMake *****************") +IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) + SET(MSG_MODE "") #Optional + SET(MSG_INDENT " ") + MESSAGE(${MSG_MODE} "************* SUMMARY FROM RUNNING CMake ********************") + FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") + + MESSAGE(${MSG_MODE} "TOOLS:") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Build Type: ${CMAKE_BUILD_TYPE}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") + + MESSAGE(${MSG_MODE} "WORKBENCH VARIABLES:") + getListOfVarsStartingWith("WORKBENCH" allVars) + foreach( var IN LISTS allVars ) + get_property(docString CACHE ${var} PROPERTY HELPSTRING) + message(${MSG_MODE} ${MSG_INDENT} "${var}=${${var}}" ) + + STRING(REPLACE "" "\n${MSG_INDENT}${MSG_INDENT}" docPrint ${docString}) + message(${MSG_MODE} ${MSG_INDENT} ${MSG_INDENT} ${docPrint}) + endforeach() + MESSAGE(${MSG_MODE} "PACKAGES:") + MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "SIMD: " ${SIMD_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) + + MESSAGE(${MSG_MODE} "************* END SUMMARY FROM RUNNING CMake *****************") +ENDIF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) -- GitLab From f31dacdf49cb915b486ee5ed27ecd52105a0c20f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 16 Nov 2016 15:29:37 -0600 Subject: [PATCH 051/755] On Windows systems, include 'windows.h' instead of 'unistd.h'. --- src/Common/SystemUtilities.cxx | 4 ++++ src/GuiQt/MovieDialog.cxx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Common/SystemUtilities.cxx b/src/Common/SystemUtilities.cxx index 13b164272..a467f0afc 100644 --- a/src/Common/SystemUtilities.cxx +++ b/src/Common/SystemUtilities.cxx @@ -21,7 +21,11 @@ #include #include #include +#ifdef CARET_OS_WINDOWS +#include +#else #include +#endif #include #include diff --git a/src/GuiQt/MovieDialog.cxx b/src/GuiQt/MovieDialog.cxx index 2353a861f..cd96c9906 100644 --- a/src/GuiQt/MovieDialog.cxx +++ b/src/GuiQt/MovieDialog.cxx @@ -20,7 +20,11 @@ #include #include +#ifdef CARET_OS_WINDOWS +#include +#else #include +#endif #include "MovieDialog.h" #include "ui_MovieDialog.h" -- GitLab From 3cb922b3a4cedcd0c36f59f4d83b2b7de3977a91 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 17 Nov 2016 09:45:30 -0600 Subject: [PATCH 052/755] Disable counting of vertex buffers in OpenGL information until new windows build is fixed so that it finds the correct OpenGL libraries (need 2.0 or later but getting 1.1) --- src/GuiQt/BrainOpenGLWidget.cxx | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index e021aa050..3c043d74a 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -339,22 +339,25 @@ BrainOpenGLWidget::getOpenGLInformation() + AString::number(numDisplayLists) + " display lists are allocated in first OpenGL context."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS -#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS - int32_t numVertexBuffers = 0; -#ifdef GL_VERSION_2_0 - /* - * Note: glIsBuffer() was added to OpenGL 2.0 - */ - for (GLuint iBuff = 1; iBuff < 1000; iBuff++) { - if (glIsBuffer(iBuff)) { - numVertexBuffers++; - } - } -#endif // GL_VERSION_2_0 - info += ("\nAt least " - + AString::number(numVertexBuffers) - + " vertex buffers are allocated"); -#endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS + +// Disable check of vertex buffers until OpenGL +// version is fixed on windows (finds 1.1) +//#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS +// int32_t numVertexBuffers = 0; +//#ifdef GL_VERSION_2_0 +// /* +// * Note: glIsBuffer() was added to OpenGL 2.0 +// */ +// for (GLuint iBuff = 1; iBuff < 1000; iBuff++) { +// if (glIsBuffer(iBuff)) { +// numVertexBuffers++; +// } +// } +//#endif // GL_VERSION_2_0 +// info += ("\nAt least " +// + AString::number(numVertexBuffers) +// + " vertex buffers are allocated"); +//#endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS info += "\n"; return info; -- GitLab From 2d6a38d842489dfd4b5b8906cfee1a38328f5394 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 7 Dec 2016 17:34:39 -0600 Subject: [PATCH 053/755] new cifti and gifti label probability commands --- .../AlgorithmCiftiLabelProbability.cxx | 154 ++++++++++++++++++ .../AlgorithmCiftiLabelProbability.h | 80 +++++++++ src/Algorithms/AlgorithmLabelProbability.cxx | 127 +++++++++++++++ src/Algorithms/AlgorithmLabelProbability.h | 46 ++++++ .../AlgorithmVolumeLabelProbability.cxx | 2 +- src/Algorithms/CMakeLists.txt | 4 + src/Commands/CommandOperationManager.cxx | 4 + 7 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 src/Algorithms/AlgorithmCiftiLabelProbability.cxx create mode 100644 src/Algorithms/AlgorithmCiftiLabelProbability.h create mode 100644 src/Algorithms/AlgorithmLabelProbability.cxx create mode 100644 src/Algorithms/AlgorithmLabelProbability.h diff --git a/src/Algorithms/AlgorithmCiftiLabelProbability.cxx b/src/Algorithms/AlgorithmCiftiLabelProbability.cxx new file mode 100644 index 000000000..29918120c --- /dev/null +++ b/src/Algorithms/AlgorithmCiftiLabelProbability.cxx @@ -0,0 +1,154 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AlgorithmCiftiLabelProbability.h" +#include "AlgorithmException.h" + +#include "CiftiFile.h" + +#include +#include +#include + +using namespace caret; +using namespace std; + +AString AlgorithmCiftiLabelProbability::getCommandSwitch() +{ + return "-cifti-label-probability"; +} + +AString AlgorithmCiftiLabelProbability::getShortDescription() +{ + return "FIND FREQUENCY OF CIFTI LABELS"; +} + +OperationParameters* AlgorithmCiftiLabelProbability::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + + ret->addCiftiParameter(1, "label-maps", "cifti dlabel file containing individual label maps from many subjects"); + + ret->addCiftiOutputParameter(2, "probability-dscalar-out", "the relative frequencies of each label at each vertex/voxel"); + + ret->createOptionalParameter(3, "-exclude-unlabeled", "don't make a probability map of the unlabeled key"); + + ret->setHelpText( + AString("This command outputs a set of soft ROIs, one for each label in the input, ") + + "where the value is how many of the input maps had that label at that vertex/voxel, divided by the number of input maps." + ); + return ret; +} + +void AlgorithmCiftiLabelProbability::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + const CiftiFile* inputLabel = myParams->getCifti(1); + CiftiFile* outputCifti = myParams->getOutputCifti(2); + bool excludeUnlabeled = myParams->getOptionalParameter(3)->m_present; + AlgorithmCiftiLabelProbability(myProgObj, inputLabel, outputCifti, excludeUnlabeled); +} + +AlgorithmCiftiLabelProbability::AlgorithmCiftiLabelProbability(ProgressObject* myProgObj, const CiftiFile* inputLabel, CiftiFile* outputCifti, const bool& excludeUnlabeled) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + const CiftiXML& inputXML = inputLabel->getCiftiXML(); + if (inputXML.getNumberOfDimensions() != 2 || + inputXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS || + inputXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) + { + throw AlgorithmException("input cifti file does not have the mapping types of a dlabel file"); + } + const CiftiLabelsMap& inputLabelMap = inputXML.getLabelsMap(CiftiXML::ALONG_ROW); + int64_t numInMaps = inputLabelMap.getLength(); + vector > keyToOutMapLookup(numInMaps);//we match labels by name, not by key - since cifti files are more memory efficient than volume files, do it the fast way + map nameToOutMap; + for (int64_t m = 0; m < numInMaps; ++m) + { + const GiftiLabelTable* mapTable = inputLabelMap.getMapLabelTable(m); + set mapKeys = mapTable->getKeys(); + int32_t unlabeledKey = -1;//don't request it from the table if we aren't going to skip it, because requesting it can add it to the table + if (excludeUnlabeled) + { + unlabeledKey = mapTable->getUnassignedLabelKey(); + } + for (set::iterator iter = mapKeys.begin(); iter != mapKeys.end(); ++iter)//order by key value + { + if (excludeUnlabeled && *iter == unlabeledKey) continue;//skip to next key + const AString thisName = mapTable->getLabelName(*iter); + map::iterator search = nameToOutMap.find(thisName); + int outMap = -1; + if (search == nameToOutMap.end()) + { + outMap = nameToOutMap.size();//sequential integers starting from 0 + nameToOutMap[thisName] = outMap; + } else { + outMap = search->second; + } + keyToOutMapLookup[m][*iter] = outMap; + } + }//for simplicity, do the actual processing in a second loop + int64_t numOutMaps = nameToOutMap.size(), colSize = inputXML.getDimensionLength(CiftiXML::ALONG_COLUMN); + vector > counts(numOutMaps, vector(colSize, 0)); + for (int64_t row = 0; row < colSize; ++row) + { + vector scratchRow(numInMaps); + inputLabel->getRow(scratchRow.data(), row); + for (int64_t m = 0; m < numInMaps; ++m) + { + int thiskey = (int)floor(scratchRow[m] + 0.5f); + map::iterator search = keyToOutMapLookup[m].find(thiskey); + if (search != keyToOutMapLookup[m].end()) + { + ++counts[search->second][row]; + } + } + } + CiftiXML outXML; + outXML.setNumberOfDimensions(2); + outXML.setMap(CiftiXML::ALONG_COLUMN, inputXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN)); + CiftiScalarsMap outRowMap; + outRowMap.setLength(numOutMaps); + for (map::iterator iter = nameToOutMap.begin(); iter != nameToOutMap.end(); ++iter) + { + outRowMap.setMapName(iter->second, iter->first); + } + outXML.setMap(CiftiXML::ALONG_ROW, outRowMap); + outputCifti->setCiftiXML(outXML); + for (int64_t row = 0; row < colSize; ++row) + { + vector scratchRow(numOutMaps); + for (int64_t m = 0; m < numOutMaps; ++m) + { + scratchRow[m] = ((float)counts[m][row]) / numInMaps; + } + outputCifti->setRow(scratchRow.data(), row); + } +} + +float AlgorithmCiftiLabelProbability::getAlgorithmInternalWeight() +{ + return 1.0f;//override this if needed, if the progress bar isn't smooth +} + +float AlgorithmCiftiLabelProbability::getSubAlgorithmWeight() +{ + //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm + return 0.0f; +} diff --git a/src/Algorithms/AlgorithmCiftiLabelProbability.h b/src/Algorithms/AlgorithmCiftiLabelProbability.h new file mode 100644 index 000000000..a9d6fc5a4 --- /dev/null +++ b/src/Algorithms/AlgorithmCiftiLabelProbability.h @@ -0,0 +1,80 @@ +#ifndef __ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ +#define __ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +/* +file->save as... and enter what you will name the class, plus .h + +find and replace these strings in plain text mode (not "whole word only"): + +AlgorithmCiftiLabelProbability : algorithm name, in CamelCase, with initial capital, same as what you saved the header file to +ALGORITHM_CIFTI_LABEL_PROBABILITY : uppercase of algorithm name, with underscore between words, used in #ifdef guards + +next, make AlgorithmCiftiLabelProbability.cxx from AlgorithmTemplate.cxx.txt via one of the following (depending on working directory): + +cat AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > AlgorithmCiftiLabelProbability.cxx +cat Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > Algorithms/AlgorithmCiftiLabelProbability.cxx +cat src/Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > src/Algorithms/AlgorithmCiftiLabelProbability.cxx + +or manually copy and replace + +next, implement its functions - the algorithm work goes in the CONSTRUCTOR + +add these into Algorithms/CMakeLists.txt: + +AlgorithmCiftiLabelProbability.h +AlgorithmCiftiLabelProbability.cxx + +place the following lines into Commands/CommandOperationManager.cxx: + +#include "AlgorithmCiftiLabelProbability.h" + //near the top + + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelProbability())); + //in CommandOperationManager() + +finally, remove this block comment +*/ + +#include "AbstractAlgorithm.h" + +namespace caret { + + class AlgorithmCiftiLabelProbability : public AbstractAlgorithm + { + AlgorithmCiftiLabelProbability(); + protected: + static float getSubAlgorithmWeight(); + static float getAlgorithmInternalWeight(); + public: + AlgorithmCiftiLabelProbability(ProgressObject* myProgObj, const CiftiFile* inputLabel, CiftiFile* outputCifti, const bool& excludeUnlabeled = false); + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoAlgorithmCiftiLabelProbability; + +} + +#endif //__ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ diff --git a/src/Algorithms/AlgorithmLabelProbability.cxx b/src/Algorithms/AlgorithmLabelProbability.cxx new file mode 100644 index 000000000..5780f4d8a --- /dev/null +++ b/src/Algorithms/AlgorithmLabelProbability.cxx @@ -0,0 +1,127 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AlgorithmLabelProbability.h" +#include "AlgorithmException.h" + +#include "GiftiLabelTable.h" +#include "LabelFile.h" +#include "MetricFile.h" + +#include +#include + +using namespace caret; +using namespace std; + +AString AlgorithmLabelProbability::getCommandSwitch() +{ + return "-label-probability"; +} + +AString AlgorithmLabelProbability::getShortDescription() +{ + return "FIND FREQUENCY OF SURFACE LABELS"; +} + +OperationParameters* AlgorithmLabelProbability::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + + ret->addLabelParameter(1, "label-maps", "label file containing individual label maps from many subjects"); + + ret->addMetricOutputParameter(2, "probability-metric-out", "the relative frequencies of each label at each vertex"); + + ret->createOptionalParameter(3, "-exclude-unlabeled", "don't make a probability map of the unlabeled key"); + + ret->setHelpText( + AString("This command outputs a set of soft ROIs, one for each label in the input, ") + + "where the value is how many of the input maps had that label at that vertex, divided by the number of input maps." + ); + return ret; +} + +void AlgorithmLabelProbability::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + const LabelFile* inputLabel = myParams->getLabel(1); + MetricFile* outputMetric = myParams->getOutputMetric(2); + bool excludeUnlabeled = myParams->getOptionalParameter(3)->m_present; + AlgorithmLabelProbability(myProgObj, inputLabel, outputMetric, excludeUnlabeled); +} + +AlgorithmLabelProbability::AlgorithmLabelProbability(ProgressObject* myProgObj, const LabelFile* inputLabel, MetricFile* outputMetric, const bool& excludeUnlabeled) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + int numNodes = inputLabel->getNumberOfNodes(); + int numInMaps = inputLabel->getNumberOfMaps();//note: label files have only one label table that covers the entire file, and should never have duplicate names + map keyToOutMapLookup; + vector outMapNames; + const GiftiLabelTable* fileTable = inputLabel->getLabelTable(); + set keys = fileTable->getKeys(); + int32_t unlabeledKey = -1;//don't request it from label table if we aren't going to exclude it, as that could create the unassigned key + if (excludeUnlabeled) + { + unlabeledKey = fileTable->getUnassignedLabelKey(); + } + for (set::iterator iter = keys.begin(); iter != keys.end(); ++iter) + { + if (excludeUnlabeled && *iter == unlabeledKey) continue; + int newOutMap = (int)keyToOutMapLookup.size();//get size before [] allocates a new member + keyToOutMapLookup[*iter] = newOutMap; + outMapNames.push_back(fileTable->getLabelName(*iter)); + } + int numOutMaps = keyToOutMapLookup.size(); + vector > counts(numOutMaps, vector(numNodes, 0)); + for (int m = 0; m < numInMaps; ++m) + { + const int32_t* data = inputLabel->getLabelKeyPointerForColumn(m); + for (int i = 0; i < numNodes; ++i) + { + map::iterator search = keyToOutMapLookup.find(data[i]); + if (search != keyToOutMapLookup.end()) + { + ++counts[search->second][i]; + } + } + } + vector scratch(numNodes); + outputMetric->setNumberOfNodesAndColumns(numNodes, numOutMaps); + outputMetric->setStructure(inputLabel->getStructure()); + for (int m = 0; m < numOutMaps; ++m) + { + outputMetric->setMapName(m, outMapNames[m]); + for (int i = 0; i < numNodes; ++i) + { + scratch[i] = ((float)counts[m][i]) / numInMaps; + } + outputMetric->setValuesForColumn(m, scratch.data()); + } +} + +float AlgorithmLabelProbability::getAlgorithmInternalWeight() +{ + return 1.0f;//override this if needed, if the progress bar isn't smooth +} + +float AlgorithmLabelProbability::getSubAlgorithmWeight() +{ + //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm + return 0.0f; +} diff --git a/src/Algorithms/AlgorithmLabelProbability.h b/src/Algorithms/AlgorithmLabelProbability.h new file mode 100644 index 000000000..8eb479a52 --- /dev/null +++ b/src/Algorithms/AlgorithmLabelProbability.h @@ -0,0 +1,46 @@ +#ifndef __ALGORITHM_LABEL_PROBABILITY_H__ +#define __ALGORITHM_LABEL_PROBABILITY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AbstractAlgorithm.h" + +namespace caret { + + class AlgorithmLabelProbability : public AbstractAlgorithm + { + AlgorithmLabelProbability(); + protected: + static float getSubAlgorithmWeight(); + static float getAlgorithmInternalWeight(); + public: + AlgorithmLabelProbability(ProgressObject* myProgObj, const LabelFile* inputLabel, MetricFile* outputMetric, const bool& excludeUnlabeled = false); + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoAlgorithmLabelProbability; + +} + +#endif //__ALGORITHM_LABEL_PROBABILITY_H__ diff --git a/src/Algorithms/AlgorithmVolumeLabelProbability.cxx b/src/Algorithms/AlgorithmVolumeLabelProbability.cxx index 6a2206c5a..459d86403 100644 --- a/src/Algorithms/AlgorithmVolumeLabelProbability.cxx +++ b/src/Algorithms/AlgorithmVolumeLabelProbability.cxx @@ -38,7 +38,7 @@ AString AlgorithmVolumeLabelProbability::getCommandSwitch() AString AlgorithmVolumeLabelProbability::getShortDescription() { - return "FIND FREQUENCY OF LABELS"; + return "FIND FREQUENCY OF VOLUME LABELS"; } OperationParameters* AlgorithmVolumeLabelProbability::getParameters() diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index 9e57eecc2..c1ff6495b 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -42,6 +42,7 @@ AlgorithmCiftiFalseCorrelation.h AlgorithmCiftiFindClusters.h AlgorithmCiftiGradient.h AlgorithmCiftiLabelAdjacency.h +AlgorithmCiftiLabelProbability.h AlgorithmCiftiLabelToBorder.h AlgorithmCiftiLabelToROI.h AlgorithmCiftiMergeDense.h @@ -69,6 +70,7 @@ AlgorithmGiftiLabelToROI.h AlgorithmLabelDilate.h AlgorithmLabelErode.h AlgorithmLabelModifyKeys.h +AlgorithmLabelProbability.h AlgorithmLabelResample.h AlgorithmLabelToBorder.h AlgorithmLabelToVolumeMapping.h @@ -156,6 +158,7 @@ AlgorithmCiftiFalseCorrelation.cxx AlgorithmCiftiFindClusters.cxx AlgorithmCiftiGradient.cxx AlgorithmCiftiLabelAdjacency.cxx +AlgorithmCiftiLabelProbability.cxx AlgorithmCiftiLabelToBorder.cxx AlgorithmCiftiLabelToROI.cxx AlgorithmCiftiMergeDense.cxx @@ -183,6 +186,7 @@ AlgorithmGiftiLabelToROI.cxx AlgorithmLabelDilate.cxx AlgorithmLabelErode.cxx AlgorithmLabelModifyKeys.cxx +AlgorithmLabelProbability.cxx AlgorithmLabelResample.cxx AlgorithmLabelToBorder.cxx AlgorithmLabelToVolumeMapping.cxx diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 6f1057028..d92b22eb4 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -43,6 +43,7 @@ #include "AlgorithmCiftiFindClusters.h" #include "AlgorithmCiftiGradient.h" #include "AlgorithmCiftiLabelAdjacency.h" +#include "AlgorithmCiftiLabelProbability.h" #include "AlgorithmCiftiLabelToBorder.h" #include "AlgorithmCiftiLabelToROI.h" #include "AlgorithmCiftiMergeDense.h" @@ -68,6 +69,7 @@ #include "AlgorithmLabelDilate.h" #include "AlgorithmLabelErode.h" #include "AlgorithmLabelModifyKeys.h" +#include "AlgorithmLabelProbability.h" #include "AlgorithmLabelResample.h" #include "AlgorithmLabelToBorder.h" #include "AlgorithmLabelToVolumeMapping.h" @@ -297,6 +299,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelAdjacency())); + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiMergeDense())); @@ -323,6 +326,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelDilate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelErode())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelModifyKeys())); + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelToVolumeMapping())); -- GitLab From 4643ff57c0e61262d4a0df8e9a44cdf6f026d99a Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 7 Dec 2016 17:42:37 -0600 Subject: [PATCH 054/755] improve error message for failure to open output files, update comment in bash completion --- src/CommandLine/bashcomplete_wb_command | 2 +- src/Common/CaretBinaryFile.cxx | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/bashcomplete_wb_command b/src/CommandLine/bashcomplete_wb_command index a2df7446a..99ff8b35d 100644 --- a/src/CommandLine/bashcomplete_wb_command +++ b/src/CommandLine/bashcomplete_wb_command @@ -21,7 +21,7 @@ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#put this file in (or link to it from) /etc/bash_completion.d or copy contents to ~/.bash_completion +#put this file in (or link to it from) /etc/bash_completion.d or /usr/share/bash-completion/completions or copy contents to ~/.bash_completion function _wb_command() { diff --git a/src/Common/CaretBinaryFile.cxx b/src/Common/CaretBinaryFile.cxx index fdc8d6c20..123dcae2d 100644 --- a/src/Common/CaretBinaryFile.cxx +++ b/src/Common/CaretBinaryFile.cxx @@ -298,7 +298,12 @@ void QFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& o case QFile::ResourceError://on linux at least, it never gives another code besides the unhelpful OpenError throw DataFileException("failed to open file '" + filename + "', too many open files"); default: - throw DataFileException("failed to open file '" + filename + "'"); + if (opmode & CaretBinaryFile::WRITE) + { + throw DataFileException("failed to open file '" + filename + "' for writing"); + } else { + throw DataFileException("failed to open file '" + filename + "'"); + } } } } -- GitLab From 093e2ced93789c1abd9e4bb1ddf451a8cb7da699 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 5 Dec 2016 14:24:04 -0600 Subject: [PATCH 055/755] Fixed a bug noticed on Mac with Qt5. On either Palette Editor Dilog or Overlay and Map Settings Dialog, selection of a Palette combo box resulted in containing no selected palette. Problem was that the focus in event, used to ensure valid data on the dialog, was being issued during the pop-up of the combo box resulting in no selected palette. Solution was to ignore focus events when the reason is Qt::PopupFocusReason. --- src/GuiQt/OverlaySettingsEditorDialog.cxx | 10 +++++++++- src/GuiQt/PaletteColorMappingEditorDialog.cxx | 11 ++++++++++- src/GuiQt/WuQDialog.cxx | 10 +++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/OverlaySettingsEditorDialog.cxx b/src/GuiQt/OverlaySettingsEditorDialog.cxx index e86650cc8..95a3fbcf0 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.cxx +++ b/src/GuiQt/OverlaySettingsEditorDialog.cxx @@ -201,8 +201,16 @@ OverlaySettingsEditorDialog::createMapFileAndNameSection() * The focus event. */ void -OverlaySettingsEditorDialog::focusInEvent(QFocusEvent* /*event*/) +OverlaySettingsEditorDialog::focusInEvent(QFocusEvent* event) { + if (event->reason() == Qt::PopupFocusReason) { + /* + * This occurs when a combo box is popped up Mac, + * causes a problem, and can be ignored. + */ + return; + } + updateDialog(); } diff --git a/src/GuiQt/PaletteColorMappingEditorDialog.cxx b/src/GuiQt/PaletteColorMappingEditorDialog.cxx index cf377fd64..ae604328c 100644 --- a/src/GuiQt/PaletteColorMappingEditorDialog.cxx +++ b/src/GuiQt/PaletteColorMappingEditorDialog.cxx @@ -19,6 +19,7 @@ */ /*LICENSE_END*/ +#include #include #include #include @@ -133,8 +134,16 @@ PaletteColorMappingEditorDialog::receiveEvent(Event* event) * The focus event. */ void -PaletteColorMappingEditorDialog::focusInEvent(QFocusEvent* /*event*/) +PaletteColorMappingEditorDialog::focusInEvent(QFocusEvent* event) { + if (event->reason() == Qt::PopupFocusReason) { + /* + * This occurs when a combo box is popped up Mac, + * causes a problem, and can be ignored. + */ + return; + } + updateDialog(); } diff --git a/src/GuiQt/WuQDialog.cxx b/src/GuiQt/WuQDialog.cxx index 5320713e5..287ea51f1 100644 --- a/src/GuiQt/WuQDialog.cxx +++ b/src/GuiQt/WuQDialog.cxx @@ -549,8 +549,16 @@ WuQDialog::helpButtonClicked() * The focus event. */ void -WuQDialog::focusInEvent(QFocusEvent* /*event*/) +WuQDialog::focusInEvent(QFocusEvent* event) { + if (event->reason() == Qt::PopupFocusReason) { + /* + * This occurs when a combo box is popped up Mac, + * causes a problem, and can be ignored. + */ + return; + } + focusGained(); } -- GitLab From 661380244e6d979b8d1507c21dff748b6698d732 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Dec 2016 10:37:04 -0600 Subject: [PATCH 056/755] In BrainOpenGLWidget with Qt5, a warning message indicated which Qt widget was used for OpenGL (QGLWidget or QOpenGLWidget. This information has been moved to the OpenGL information available from the About wb_view dialog. --- src/GuiQt/BrainOpenGLWidget.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 3c043d74a..e898d24b1 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -107,14 +107,6 @@ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, windowIndex(windowIndex), m_textRenderer(NULL) { -#if QT_VERSION >= 0x050000 -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - CaretLogWarning("wb_view built with Qt5 using QOpenGLWidget for graphics."); -#else - CaretLogWarning("wb_view built with Qt5 using deprecated QGLWidget for graphics."); -#endif -#endif - this->openGL = NULL; this->borderBeingDrawn = new Border(); @@ -247,6 +239,14 @@ QString BrainOpenGLWidget::getOpenGLInformation() { AString info; +#if QT_VERSION >= 0x050000 +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + info += ("Rendering with Qt5 QOpenGLWidget.\n"); +#else + info += ("Rendering with Qt5 QGLWidget (deprecated).\n"); +#endif + info += ("\n"); +#endif #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QSurfaceFormat format = this->format(); -- GitLab From 23f3d5cb2a9d384dad1ce1862549224f9a3875fd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 8 Dec 2016 12:36:31 -0600 Subject: [PATCH 057/755] Updating RedHat build scripts from old supercomputer (login1) to new supercomputer (login01 for building, dtn01 for copying executables). On the new supercomputer file transfers will fail on login01 and dtn01 is setup for file transfers (dtn01 should not be used for building. However, due to firewall issues, we cannot copy from a supercomputer node to outside the supercomputer but we initiating the copy on one of our nodes from the dtn01 will work. Copying has been moved to the linux64_rh_remote.sh script after checking that the build was successful. --- build_scripts/linux64_rh.sh | 3 +++ build_scripts/linux64_rh_aux.sh | 10 +++++++++ build_scripts/linux64_rh_remote.sh | 36 +++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/build_scripts/linux64_rh.sh b/build_scripts/linux64_rh.sh index f6125abba..d4f6fc161 100755 --- a/build_scripts/linux64_rh.sh +++ b/build_scripts/linux64_rh.sh @@ -24,4 +24,7 @@ set noon # echo "Starting linux64 Redhat aux script" ${BUILD_ROOT_DIR}/caret7_source/build_scripts/linux64_rh_aux.sh +resultFlag=$? echo "Finished linux64 Redhat script" + +exit $resultFlag diff --git a/build_scripts/linux64_rh_aux.sh b/build_scripts/linux64_rh_aux.sh index 515c33bd3..d93f5ad65 100755 --- a/build_scripts/linux64_rh_aux.sh +++ b/build_scripts/linux64_rh_aux.sh @@ -37,6 +37,16 @@ echo "BUILDING SOURCE" cd ${BUILD_DIR} make -j2 +# +# Exit with result of running 'make' +# Cannot scp does not work when run on cluster system to outside cluster +# +exit $? + + + + + # # Copy to distribution directory # diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh index 245dcbc71..3fcfa6b70 100755 --- a/build_scripts/linux64_rh_remote.sh +++ b/build_scripts/linux64_rh_remote.sh @@ -1,8 +1,38 @@ #!/bin/sh BUILD=linux64_rh -BUILD_SERVER=login1.chpc.wustl.edu +BUILD_SERVER=login01.chpc.wustl.edu +COPY_SERVER=dtn01.chpc.wustl.edu -#BUILD_DIR=/home/caret/caret7_dev/${BUILD} BUILD_DIR=/home/caret/caret7_dev + ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu +buildResult=$? + +if [ ! $result ]; then + echo "Build was successful, now copying to distribution directory" + + # + # Copy to distribution directory + # Copy from 'dtn01 (copying will hang on login01) + # + echo "COPYING PROGRAMS" + COPY_FROM_DIR=caret@${COPY_SERVER}:${BUILD_DIR}/build + DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 + scp ${COPY_FROM_DIR}/Desktop/wb_view ${DIST_DIR} > $PWD/remote_launch_${BUILD}.txt 2>&1 + scp ${COPY_FROM_DIR}/CommandLine/wb_command ${DIST_DIR} > $PWD/remote_launch_${BUILD}.txt 2>&1 + + # + # Need to be changed + # + #scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 + #put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) + #scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} + +echo "SCRIPT COMPLETED SUCCESSFULLY" +else + echo "Build failed" +fi + +#cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu + + -- GitLab From 430f232ae6b9cdbff1d9df823dd19610eb6d9ac3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 8 Dec 2016 14:30:19 -0600 Subject: [PATCH 058/755] Add RedHat to email subject for RedHat build (was changed in myelin build directory but change had not been committed. --- build_scripts/linux64_rh_remote.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh index 3fcfa6b70..c5c41256b 100755 --- a/build_scripts/linux64_rh_remote.sh +++ b/build_scripts/linux64_rh_remote.sh @@ -33,6 +33,6 @@ else echo "Build failed" fi -#cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu +#cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From 1e254c7b3725ba52f8cccd8687f2b9928e797dcb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 8 Dec 2016 15:02:36 -0600 Subject: [PATCH 059/755] Updated for RedHat build script including email fix --- build_scripts/linux64_rh_aux.sh | 14 +++++++------- build_scripts/linux64_rh_remote.sh | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build_scripts/linux64_rh_aux.sh b/build_scripts/linux64_rh_aux.sh index d93f5ad65..887370b78 100755 --- a/build_scripts/linux64_rh_aux.sh +++ b/build_scripts/linux64_rh_aux.sh @@ -50,13 +50,13 @@ exit $? # # Copy to distribution directory # -echo "COPYING PROGRAMS" -DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 -scp Desktop/wb_view caret@myelin1.wustl.edu:${DIST_DIR} -scp CommandLine/wb_command caret@myelin1.wustl.edu:${DIST_DIR} -scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 -#put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) -scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} +#echo "COPYING PROGRAMS" +#DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 +#scp Desktop/wb_view caret@myelin1.wustl.edu:${DIST_DIR} +#scp CommandLine/wb_command caret@myelin1.wustl.edu:${DIST_DIR} +#scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 +##put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) +#scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} echo "SCRIPT COMPLETED SUCCESSFULLY" diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh index c5c41256b..6924e662b 100755 --- a/build_scripts/linux64_rh_remote.sh +++ b/build_scripts/linux64_rh_remote.sh @@ -33,6 +33,6 @@ else echo "Build failed" fi -#cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu +cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From 7d5fb46b4fa4501c87dfec9e87bae7a01e7a87ca Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 8 Dec 2016 15:23:24 -0600 Subject: [PATCH 060/755] Redhat remote build script was replacing the build result file when copying executables instead of appending to the build log file. --- build_scripts/linux64_rh_remote.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh index 6924e662b..aa58e0258 100755 --- a/build_scripts/linux64_rh_remote.sh +++ b/build_scripts/linux64_rh_remote.sh @@ -18,8 +18,8 @@ if [ ! $result ]; then echo "COPYING PROGRAMS" COPY_FROM_DIR=caret@${COPY_SERVER}:${BUILD_DIR}/build DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 - scp ${COPY_FROM_DIR}/Desktop/wb_view ${DIST_DIR} > $PWD/remote_launch_${BUILD}.txt 2>&1 - scp ${COPY_FROM_DIR}/CommandLine/wb_command ${DIST_DIR} > $PWD/remote_launch_${BUILD}.txt 2>&1 + scp ${COPY_FROM_DIR}/Desktop/wb_view ${DIST_DIR} >> $PWD/remote_launch_${BUILD}.txt 2>&1 + scp ${COPY_FROM_DIR}/CommandLine/wb_command ${DIST_DIR} >> $PWD/remote_launch_${BUILD}.txt 2>&1 # # Need to be changed @@ -28,11 +28,11 @@ if [ ! $result ]; then #put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) #scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} -echo "SCRIPT COMPLETED SUCCESSFULLY" + echo "SCRIPT COMPLETED SUCCESSFULLY" else echo "Build failed" fi -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu +cat $PWD/remote_launch_${BUILD}.txt | mailx -v -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From 50f0e35948464f316c6ce885415f378e9d8e921b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Dec 2016 09:51:18 -0600 Subject: [PATCH 061/755] Outline around Chart Attributes 'Reset' button was missing on Mac. --- src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index 5cd60d51a..e11d9e4a6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -351,6 +351,7 @@ EventListenerInterface() SLOT(resetButtonClicked())); QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(resetButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); WuQtUtilities::matchWidgetWidths(m_cellHeightSpinBox, m_cellWidthSpinBox); -- GitLab From 1012300cdf57472de57a6b4e3961a456179dc555 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Dec 2016 15:55:25 -0600 Subject: [PATCH 062/755] Correct spelling of 'Attributes' on Map Settings Dialog's Fiber Trajectory page. --- src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx b/src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx index 6740b90d9..6d730e458 100644 --- a/src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx +++ b/src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx @@ -100,7 +100,7 @@ MapSettingsFiberTrajectoryWidget::createAttributesWidget() m_colorSelectionComboBox = WuQFactory::newComboBoxSignalInt(this, SLOT(processAttributesChanges())); - QGroupBox* attributesGroupBox = new QGroupBox("Attribues"); + QGroupBox* attributesGroupBox = new QGroupBox("Attributes"); QGridLayout* attributesGridLayout = new QGridLayout(attributesGroupBox); int row = 0; attributesGridLayout->addWidget(colorLabel, row, 0); -- GitLab From c2e3bec94c55dc16e8ee77b1cf676c66292008e9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Dec 2016 16:31:48 -0600 Subject: [PATCH 063/755] Fixed missing border around Toobar->Mode->Annotation button when using Qt5. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 3 +- src/GuiQt/WuQtUtilities.cxx | 43 +++++++++++++++++-------- src/GuiQt/WuQtUtilities.h | 2 ++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 8fb47425b..337727bee 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -2257,7 +2257,8 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeAnnotationsToolButton->setToolButtonStyle(Qt::ToolButtonTextOnly); inputModeAnnotationsToolButton->setAutoRaise(true); - WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); + WuQtUtilities::addBorderToToolButtonForQt5(inputModeAnnotationsToolButton); + //WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); // const QPalette palette = inputModeAnnotationsToolButton->palette(); // const QPalette::ColorRole backgroundRole = inputModeAnnotationsToolButton->backgroundRole(); diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 89edd9c0e..2f353ae00 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1443,15 +1443,15 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, } /** - * With Qt5, a toolbutton placed into a toolbar uses the - * background of the toolbar with no morder and appears - * similar to a label. Use a stylesheet so that - * the button appears similar to Qt4. + * With Qt5, an occasional toolbutton is missing its border. + * Use a stylesheet to add a border to the toolbutton. + * + * @param toolButton + * toolButton ToolButton that needs style updated. */ void -WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) +WuQtUtilities::addBorderToToolButtonForQt5(QToolButton* toolButton) { -#ifdef CARET_OS_MACOSX #if QT_VERSION >= 0x050000 bool hasMenuFlag = false; bool hasCheckableFlag = false; @@ -1482,13 +1482,13 @@ WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) QString toolButtonStyleSheet(" QToolButton { " " background: " + lighterColor.name() + "; "); if (hasMenuFlag) { -// toolButtonStyleSheet.append(" border-style: solid; " -// " border-width: 1px; " -// " border-color: " + darkerColor.name() + "; " -// " padding-top: 6px; " -// " padding-bottom: 6px; " -// " padding-right: 4px; " -// " padding-left: 3px; "); + // toolButtonStyleSheet.append(" border-style: solid; " + // " border-width: 1px; " + // " border-color: " + darkerColor.name() + "; " + // " padding-top: 6px; " + // " padding-bottom: 6px; " + // " padding-right: 4px; " + // " padding-left: 3px; "); } else { toolButtonStyleSheet.append(" border-style: solid; " @@ -1522,6 +1522,23 @@ WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) //std::cout << qPrintable(toolButton->text() + " " + toolButtonStyleSheet + "\n\n"); #endif +} + + +/** + * With Qt5, a toolbutton placed into a toolbar uses the + * background of the toolbar with no border and appears + * similar to a label. Use a stylesheet so that + * the button appears similar to Qt4. + * + * @param toolButton + * toolButton ToolButton that needs style updated. + */ +void +WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) +{ +#ifdef CARET_OS_MACOSX + addBorderToToolButtonForQt5(toolButton); #endif } diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index 4214b5557..f2f403181 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -197,6 +197,8 @@ namespace caret { static Qt::CheckState boolToCheckState(const bool value); + static void addBorderToToolButtonForQt5(QToolButton* toolButton); + static void setToolButtonStyleForQt5Mac(QToolButton* toolButton); private: -- GitLab From a14ea60859bcf168b0f2d3d665847b3bc75e96bc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Dec 2016 10:09:28 -0600 Subject: [PATCH 064/755] With Qt5, missing border around 'Annotation' button in toolbar was caused by setting the button's toolbutton style and has been removed. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 30 ++----------------------- src/GuiQt/WuQtUtilities.cxx | 28 +++++++---------------- src/GuiQt/WuQtUtilities.h | 2 -- 3 files changed, 10 insertions(+), 50 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 337727bee..6d663aa6b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -2254,33 +2254,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeAnnotationsAction->setCheckable(true); QToolButton* inputModeAnnotationsToolButton = new QToolButton(); inputModeAnnotationsToolButton->setDefaultAction(this->modeInputModeAnnotationsAction); - - inputModeAnnotationsToolButton->setToolButtonStyle(Qt::ToolButtonTextOnly); - inputModeAnnotationsToolButton->setAutoRaise(true); - WuQtUtilities::addBorderToToolButtonForQt5(inputModeAnnotationsToolButton); - //WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); - -// const QPalette palette = inputModeAnnotationsToolButton->palette(); -// const QPalette::ColorRole backgroundRole = inputModeAnnotationsToolButton->backgroundRole(); -// const QBrush backgroundBrush = palette.brush(backgroundRole); -// const QColor backgroundColor = backgroundBrush.color(); -// const QColor darkerColor = backgroundColor.darker(125); -// -// const QString toolButtonStyleSheet(" QToolButton { " -// " border-style: solid; " -// " border-width: 1px; " -// " border-color: " + darkerColor.name() + "; " -// " padding-top: 1px; " -// " padding-bottom: 1px; " -// " padding-right: 3px; " -// " padding-left: 3px; " -// " }"); -// std::cout << "****** style sheet: " << toolButtonStyleSheet << std::endl; -// inputModeAnnotationsToolButton->setStyleSheet(toolButtonStyleSheet); -//// const int red = backgroundColor.red(); -//// const int green = backgroundColor.green(); -//// const int blue = backgroundColor.blue(); -//// std::cout << "******** Annotate Background Color: " << red << ", " << green << ", " << blue << std::endl; + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); /* * Borders @@ -2429,7 +2403,7 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) UserInputModeAbstract::UserInputMode inputMode = UserInputModeAbstract::INVALID; if (action == this->modeInputModeAnnotationsAction) { - inputMode = UserInputModeAbstract::ANNOTATIONS; + inputMode = UserInputModeAbstract::ANNOTATIONS; } else if (action == this->modeInputModeBordersAction) { inputMode = UserInputModeAbstract::BORDERS; diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 2f353ae00..41f0023c3 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1443,16 +1443,21 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, } /** - * With Qt5, an occasional toolbutton is missing its border. - * Use a stylesheet to add a border to the toolbutton. + * With Qt5, a toolbutton placed into a toolbar uses the + * background of the toolbar with no border and appears + * similar to a label. Use a stylesheet so that + * the button appears similar to Qt4. * * @param toolButton * toolButton ToolButton that needs style updated. */ void -WuQtUtilities::addBorderToToolButtonForQt5(QToolButton* toolButton) +WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) { +#ifdef CARET_OS_MACOSX #if QT_VERSION >= 0x050000 + CaretAssert(toolButton); + bool hasMenuFlag = false; bool hasCheckableFlag = false; QAction* action = toolButton->defaultAction(); @@ -1522,23 +1527,6 @@ WuQtUtilities::addBorderToToolButtonForQt5(QToolButton* toolButton) //std::cout << qPrintable(toolButton->text() + " " + toolButtonStyleSheet + "\n\n"); #endif -} - - -/** - * With Qt5, a toolbutton placed into a toolbar uses the - * background of the toolbar with no border and appears - * similar to a label. Use a stylesheet so that - * the button appears similar to Qt4. - * - * @param toolButton - * toolButton ToolButton that needs style updated. - */ -void -WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) -{ -#ifdef CARET_OS_MACOSX - addBorderToToolButtonForQt5(toolButton); #endif } diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index f2f403181..4214b5557 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -197,8 +197,6 @@ namespace caret { static Qt::CheckState boolToCheckState(const bool value); - static void addBorderToToolButtonForQt5(QToolButton* toolButton); - static void setToolButtonStyleForQt5Mac(QToolButton* toolButton); private: -- GitLab From cdae8224b38d5ae41a96379adfc6bcc757b783a3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Dec 2016 10:38:38 -0600 Subject: [PATCH 065/755] In annotation toolbar, increased height of text orientation buttons so that the vertically oriented 'ab' text is not clipped and fully visible. --- src/GuiQt/AnnotationTextOrientationWidget.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index e78f55d85..70012bdd3 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -255,7 +255,7 @@ AnnotationTextOrientationWidget::createHorizontalAlignmentPixmap(const QWidget* * the foreground color around the pixmap's perimeter. */ float width = 24.0; - float height = 24.0; + float height = 30.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, @@ -270,7 +270,7 @@ AnnotationTextOrientationWidget::createHorizontalAlignmentPixmap(const QWidget* break; case AnnotationTextOrientationEnum::STACKED: painter->drawText(pixmap.rect(), - (Qt::AlignHCenter | Qt::AlignTop), + (Qt::AlignCenter), "a\nb"); break; } -- GitLab From d9949a47b37b3afdae49f6d8a849e16395e3872a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Dec 2016 12:13:48 -0600 Subject: [PATCH 066/755] The name of the application 'Connectome Workbench' was set in two places, GuiManager and ApplicationInformation. The name has been removed from GuiManager. --- src/GuiQt/BrainBrowserWindow.cxx | 4 +--- src/GuiQt/GuiManager.cxx | 11 ----------- src/GuiQt/GuiManager.h | 13 ------------- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index e9082e291..a157290ec 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -140,13 +140,11 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, m_defaultTileTabsConfiguration->setName("All Tabs (Default)"); m_selectedTileTabsConfigurationUniqueIdentifier = m_defaultTileTabsConfiguration->getUniqueIdentifier(); - GuiManager* guiManager = GuiManager::get(); - setAttribute(Qt::WA_DeleteOnClose); m_browserWindowIndex = browserWindowIndex; - setWindowTitle(guiManager->applicationName() + setWindowTitle(ApplicationInformation().getName() + " " + AString::number(m_browserWindowIndex + 1)); setObjectName(windowTitle()); diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 6fa8fb34a..e341468a2 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -152,8 +152,6 @@ GuiManager::GuiManager(QObject* parent) void GuiManager::initializeGuiManager() { - this->nameOfApplication = "Connectome Workbench"; - //this->brainOpenGL = NULL; this->allowBrowserWindowsToCloseWithoutConfirmation = false; m_bugReportDialog = NULL; @@ -1120,15 +1118,6 @@ void GuiManager::processTileWindows() CaretLogFine(windowInfo); } -/** - * @return Name of the application. - */ -QString -GuiManager::applicationName() const -{ - return this->nameOfApplication; -} - /** * Receive events from the event manager. * diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index a7d9a74df..1dc7604c8 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -104,9 +104,6 @@ namespace caret { void processShowSaveManageFilesDialog(BrainBrowserWindow* browserWindow); - QString applicationName() const; - - //BrainOpenGL* getBrainOpenGL(); BrowserTabContent* getBrowserTabContentForBrowserWindow(const int32_t browserWindowIndex, const bool allowInvalidBrowserWindowIndex); @@ -225,10 +222,6 @@ namespace caret { void showHideHelpDialog(const bool status, BrainBrowserWindow* parentBrainBrowserWindow); -// void processShowHelpViewerDialog(BrainBrowserWindow* browserWindow, -// const AString& helpPageName); - - void addNonModalDialog(QWidget* dialog); void addParentLessNonModalDialog(QWidget* dialog); @@ -243,15 +236,9 @@ namespace caret { */ std::vector m_brainBrowserWindows; - /** Name of application */ - QString nameOfApplication; - /** Skips confirmation of browser window closing when all tabs are moved to one window */ bool allowBrowserWindowsToCloseWithoutConfirmation; - /* Performs OpenGL drawing commands */ - //BrainOpenGL* brainOpenGL; - /* Editor for overlay settings. */ std::set m_overlaySettingsEditors; -- GitLab From 914d0438f5ab280acc9c8bae8ede6a23e4b733c2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 14 Dec 2016 11:40:28 -0600 Subject: [PATCH 067/755] Implementation of WB-649 (Restoring from Scenes Does Not Fully Restore Overlay ToolBox in Left Mode) is causing performance problems noticed when switching the selected tab. Calling QComboBox::setSizeAdjustPolicy(QComboBox::AdjustToContents) appears to adjust the size of the combo box any time an item is inserted (found using Mac's Instruments Time Profiler) which is making updates very slow. For now, the combo box size adjust policy has been changed to its default, QComboBox::AdjustToContentsOnFirstShow. --- src/GuiQt/OverlayViewController.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/OverlayViewController.cxx b/src/GuiQt/OverlayViewController.cxx index 54e1e0cba..1fea6c380 100644 --- a/src/GuiQt/OverlayViewController.cxx +++ b/src/GuiQt/OverlayViewController.cxx @@ -95,7 +95,7 @@ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, minComboBoxWidth = 50; maxComboBoxWidth = 100000; } - const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContents; + const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; /* * Enabled Check Box -- GitLab From ea06af1a516437ebbfbfe69123c5752c40e5e8a0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 14 Dec 2016 12:25:25 -0600 Subject: [PATCH 068/755] Re-resolve WB-649 (Restoring from Scenes Does Not Fully Restore Overlay ToolBox in Left Mode): Changed layout that contains overlay so that the layout allows the contents to expand. This fixes the problem without causing any performance issues. --- src/GuiQt/OverlaySetViewController.cxx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/GuiQt/OverlaySetViewController.cxx b/src/GuiQt/OverlaySetViewController.cxx index b7bdb49b2..fb090d8ee 100644 --- a/src/GuiQt/OverlaySetViewController.cxx +++ b/src/GuiQt/OverlaySetViewController.cxx @@ -136,15 +136,24 @@ OverlaySetViewController::OverlaySetViewController(const Qt::Orientation orienta verticalLayout->addStretch(); } else { - QVBoxLayout* verticalLayout = new QVBoxLayout(); + /* + * Resolve WB-649 + */ + QVBoxLayout* verticalLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); verticalLayout->addWidget(gridWidget); verticalLayout->addStretch(); - QHBoxLayout* horizontalLayout = new QHBoxLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(horizontalLayout, 1, 1); - horizontalLayout->addLayout(verticalLayout); - horizontalLayout->addStretch(); + +// QVBoxLayout* verticalLayout = new QVBoxLayout(); +// WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); +// verticalLayout->addWidget(gridWidget); +// verticalLayout->addStretch(); +// +// QHBoxLayout* horizontalLayout = new QHBoxLayout(this); +// WuQtUtilities::setLayoutSpacingAndMargins(horizontalLayout, 1, 1); +// horizontalLayout->addLayout(verticalLayout); +// horizontalLayout->addStretch(); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); -- GitLab From 23a5f9e02bd93a112d37ac1c7f40966b589c5cf3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Dec 2016 15:27:06 -0600 Subject: [PATCH 069/755] Added WorkbenchSpecialVersionEnum. At this time, it is used to identify a special version of Workbench for use with scenes from the first implementation of charting. The text "(first charting version)" appears in the Main Window titlebar, the Splash window, and the About wb_view dialog. This "first charting version" of Workbench has been created and executables are located in "/mnt/myelin/distribution/caret7_distribution/first_charting_workbench". The special version has been turned off in the code since the executables have been created. --- src/Common/ApplicationInformation.cxx.in | 40 ++- src/Common/ApplicationInformation.h | 9 + src/Common/CMakeLists.txt | 2 + src/Common/WorkbenchSpecialVersionEnum.cxx | 373 +++++++++++++++++++++ src/Common/WorkbenchSpecialVersionEnum.h | 104 ++++++ src/GuiQt/AboutWorkbenchDialog.cxx | 2 +- src/GuiQt/SceneDialog.cxx | 59 ++++ src/GuiQt/SceneDialog.h | 6 +- src/GuiQt/SplashScreen.cxx | 11 +- 9 files changed, 598 insertions(+), 8 deletions(-) create mode 100644 src/Common/WorkbenchSpecialVersionEnum.cxx create mode 100644 src/Common/WorkbenchSpecialVersionEnum.h diff --git a/src/Common/ApplicationInformation.cxx.in b/src/Common/ApplicationInformation.cxx.in index 294721872..135fac342 100644 --- a/src/Common/ApplicationInformation.cxx.in +++ b/src/Common/ApplicationInformation.cxx.in @@ -45,7 +45,23 @@ using namespace caret; ApplicationInformation::ApplicationInformation() : CaretObject() { - this->name = "Connectome Workbench"; + this->workbenchSpecialVersion = WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO; + //this->workbenchSpecialVersion = WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING; + + this->name = "Connectome Workbench"; + this->nameForGuiLabel = this->name; + switch (this->workbenchSpecialVersion) { + case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO: + /* use default naming */ + break; + case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING: + this->name = "Connectome Workbench (First Charting Version)"; + this->nameForGuiLabel = ("" + "Connectome Workbench
" + "(First Charting Version)" + ""); + break; + } this->version = "1.2.3"; this->commit = "Commit: @COMMIT@"; this->commitDate = "Commit Date: @COMMIT_DATE@"; @@ -94,6 +110,16 @@ ApplicationInformation::getName() const return this->name; } +/** + * @return Name of the application formatted + * specifically for use in a GUI QLabel. + */ +AString +ApplicationInformation::getNameForGuiLabel() const +{ + return this->nameForGuiLabel; +} + /** * @return Version of application. */ @@ -195,6 +221,18 @@ ApplicationInformation::getSummaryInformationInString(const AString& separator) return infoOut; } +/** + * @return The Workbench Special Version + * + * Used for versions of Workbench that may or may + * not be released and contains special functionality. + */ +WorkbenchSpecialVersionEnum::Enum +ApplicationInformation::getWorkbenchSpecialVersion() const +{ + return this->workbenchSpecialVersion; +} + /** * @return The type of application. */ diff --git a/src/Common/ApplicationInformation.h b/src/Common/ApplicationInformation.h index 62eb4d605..93a1e72b3 100644 --- a/src/Common/ApplicationInformation.h +++ b/src/Common/ApplicationInformation.h @@ -23,6 +23,7 @@ #include "ApplicationTypeEnum.h" #include "CaretObject.h" +#include "WorkbenchSpecialVersionEnum.h" namespace caret { @@ -35,6 +36,8 @@ namespace caret { AString getName() const; + AString getNameForGuiLabel() const; + AString getVersion() const; AString getCommit() const; @@ -47,6 +50,8 @@ namespace caret { AString getCompiledWithDebugStatus() const; + WorkbenchSpecialVersionEnum::Enum getWorkbenchSpecialVersion() const; + static ApplicationTypeEnum::Enum getApplicationType(); static void setApplicationType(const ApplicationTypeEnum::Enum applicationType); @@ -58,6 +63,8 @@ namespace caret { AString name; + AString nameForGuiLabel; + AString version; AString commit; @@ -70,6 +77,8 @@ namespace caret { AString compiledWithOpenMP; + WorkbenchSpecialVersionEnum::Enum workbenchSpecialVersion; + static ApplicationTypeEnum::Enum s_applicationType; }; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 8cad9dd5f..8537fb8d3 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -151,6 +151,7 @@ TriStateSelectionStatusEnum.h Vector3D.h VectorOperation.h VoxelIJK.h +WorkbenchSpecialVersionEnum.h YokingGroupEnum.h ${MOC_SOURCE_FILES} @@ -241,6 +242,7 @@ TileTabsConfiguration.cxx TriStateSelectionStatusEnum.cxx Vector3D.cxx VectorOperation.cxx +WorkbenchSpecialVersionEnum.cxx YokingGroupEnum.cxx ) diff --git a/src/Common/WorkbenchSpecialVersionEnum.cxx b/src/Common/WorkbenchSpecialVersionEnum.cxx new file mode 100644 index 000000000..779b04f3b --- /dev/null +++ b/src/Common/WorkbenchSpecialVersionEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ +#include "WorkbenchSpecialVersionEnum.h" +#undef __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::WorkbenchSpecialVersionEnum + * \brief Identifies versions of Workbench with special functionality. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_workbenchSpecialVersionEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void workbenchSpecialVersionEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "WorkbenchSpecialVersionEnum.h" + * + * Instatiate: + * m_workbenchSpecialVersionEnumComboBox = new EnumComboBoxTemplate(this); + * m_workbenchSpecialVersionEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_workbenchSpecialVersionEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(workbenchSpecialVersionEnumComboBoxItemActivated())); + * + * Update the selection: + * m_workbenchSpecialVersionEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const WorkbenchSpecialVersionEnum::Enum VARIABLE = m_workbenchSpecialVersionEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +WorkbenchSpecialVersionEnum::WorkbenchSpecialVersionEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +WorkbenchSpecialVersionEnum::~WorkbenchSpecialVersionEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +WorkbenchSpecialVersionEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(WorkbenchSpecialVersionEnum(WORKBENCH_SPECIAL_VERSION_NO, + "WORKBENCH_SPECIAL_VERSION_NO", + "Workbench Special Version No")); + + enumData.push_back(WorkbenchSpecialVersionEnum(WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING, + "WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING", + "Old Charting")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const WorkbenchSpecialVersionEnum* +WorkbenchSpecialVersionEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const WorkbenchSpecialVersionEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WorkbenchSpecialVersionEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WorkbenchSpecialVersionEnum::Enum +WorkbenchSpecialVersionEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WorkbenchSpecialVersionEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +WorkbenchSpecialVersionEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +WorkbenchSpecialVersionEnum::Enum +WorkbenchSpecialVersionEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WorkbenchSpecialVersionEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +WorkbenchSpecialVersionEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +WorkbenchSpecialVersionEnum::Enum +WorkbenchSpecialVersionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const WorkbenchSpecialVersionEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +WorkbenchSpecialVersionEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WorkbenchSpecialVersionEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(WorkbenchSpecialVersionEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +WorkbenchSpecialVersionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(WorkbenchSpecialVersionEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/WorkbenchSpecialVersionEnum.h b/src/Common/WorkbenchSpecialVersionEnum.h new file mode 100644 index 000000000..5e85bf3c8 --- /dev/null +++ b/src/Common/WorkbenchSpecialVersionEnum.h @@ -0,0 +1,104 @@ +#ifndef __WORKBENCH_SPECIAL_VERSION_ENUM_H__ +#define __WORKBENCH_SPECIAL_VERSION_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class WorkbenchSpecialVersionEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Not a special version */ + WORKBENCH_SPECIAL_VERSION_NO, + /** First Implementation of Charting */ + WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING + }; + + + ~WorkbenchSpecialVersionEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + WorkbenchSpecialVersionEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const WorkbenchSpecialVersionEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ +std::vector WorkbenchSpecialVersionEnum::enumData; +bool WorkbenchSpecialVersionEnum::initializedFlag = false; +int32_t WorkbenchSpecialVersionEnum::integerCodeCounter = 0; +#endif // __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ + +} // namespace +#endif //__WORKBENCH_SPECIAL_VERSION_ENUM_H__ diff --git a/src/GuiQt/AboutWorkbenchDialog.cxx b/src/GuiQt/AboutWorkbenchDialog.cxx index f8114ecbc..0070f86d3 100644 --- a/src/GuiQt/AboutWorkbenchDialog.cxx +++ b/src/GuiQt/AboutWorkbenchDialog.cxx @@ -70,7 +70,7 @@ AboutWorkbenchDialog::AboutWorkbenchDialog(BrainOpenGLWidget* openGLParentWidget imageLabel->setAlignment(Qt::AlignCenter); } - QLabel* workbenchLabel = new QLabel(appInfo.getName()); + QLabel* workbenchLabel = new QLabel(appInfo.getNameForGuiLabel()); QFont workbenchFont = workbenchLabel->font(); workbenchFont.setBold(true); workbenchFont.setPointSize(32); diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 3539db64a..9338f1e66 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -40,6 +40,7 @@ #include "SceneDialog.h" #undef __SCENE_DIALOG_DECLARE__ +#include "ApplicationInformation.h" #include "BalsaDatabaseUploadSceneFileDialog.h" #include "Brain.h" #include "BrainBrowserWindow.h" @@ -479,6 +480,10 @@ SceneDialog::highlightScene(const Scene* scene) void SceneDialog::newSceneFileButtonClicked() { + if ( ! displayNewSceneWarning()) { + return; + } + /* * Let user choose a different path/name */ @@ -663,6 +668,10 @@ SceneDialog::browseBaseDirectoryPushButtonClicked() void SceneDialog::addNewSceneButtonClicked() { + if ( ! displayNewSceneWarning()) { + return; + } + if ( ! checkForModifiedFiles(true)) { return; } @@ -685,6 +694,10 @@ SceneDialog::addNewSceneButtonClicked() void SceneDialog::insertSceneButtonClicked() { + if ( ! displayNewSceneWarning()) { + return; + } + if ( ! checkForModifiedFiles(true)) { return; } @@ -985,6 +998,10 @@ SceneDialog::moveSceneDownButtonClicked() void SceneDialog::replaceSceneButtonClicked() { + if ( ! displayNewSceneWarning()) { + return; + } + if ( ! checkForModifiedFiles(true)) { return; } @@ -1933,6 +1950,48 @@ SceneDialog::isInformUserAboutScenesOnExit() return s_informUserAboutScenesOnExitFlag; } +/** + * Under some circumstances, the user may be warned + * when creating a new scene or scene file. + * + * @return + * True if scene or scene file should be created, else false. + */ +bool +SceneDialog::displayNewSceneWarning() +{ + if (s_warnUserWhenCreatingSceneFlag) { + s_warnUserWhenCreatingSceneFlag = false; + + ApplicationInformation appInfo; + switch (appInfo.getWorkbenchSpecialVersion()) { + case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO: + break; + case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING: + { + const QString text("This is a special version of Workbench that correctly " + "displays scene files containing the first implementation " + "of matrix and line charting. Charting is undergoing a " + "redesign and any scenes created with this special version " + "of Workbench will not display correctly in newer, official " + "releases of Workbench."); + + if (WuQMessageBox::warningOkCancel(this, + "Do you want to continue?", + text)) { + return true; + } + else { + return false; + } + } + break; + } + } + + return true; +} + /* ======================================================================== */ diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index 43df9a291..e06c5b705 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -142,11 +142,12 @@ namespace caret { bool checkForModifiedFiles(const bool creatingSceneFlag); + bool displayNewSceneWarning(); + void enableSceneMoveUpAndDownButtons(); void loadSceneFileMetaDataWidgets(); - QImage* getQImageFromSceneInfo(const SceneInfo* sceneInfo) const; // ADD_NEW_MEMBERS_HERE @@ -204,6 +205,8 @@ namespace caret { static const AString PREFERRED_IMAGE_FORMAT; static bool s_informUserAboutScenesOnExitFlag; + + static bool s_warnUserWhenCreatingSceneFlag; }; class SceneClassInfoWidget : public QGroupBox { @@ -277,6 +280,7 @@ namespace caret { #ifdef __SCENE_DIALOG_DECLARE__ const AString SceneDialog::PREFERRED_IMAGE_FORMAT = "jpg"; bool SceneDialog::s_informUserAboutScenesOnExitFlag = true; + bool SceneDialog::s_warnUserWhenCreatingSceneFlag = true; #endif // __SCENE_DIALOG_DECLARE__ } // namespace diff --git a/src/GuiQt/SplashScreen.cxx b/src/GuiQt/SplashScreen.cxx index ffa807eea..9de4fcfd9 100644 --- a/src/GuiQt/SplashScreen.cxx +++ b/src/GuiQt/SplashScreen.cxx @@ -82,14 +82,15 @@ SplashScreen::SplashScreen(QWidget* parent) " font: 20px bold " "}"); - QLabel* workbenchLabel = new QLabel("" - "Connectome
" - "Workbench" - ""); + ApplicationInformation appInfo; + QLabel* workbenchLabel = new QLabel(appInfo.getNameForGuiLabel()); +// QLabel* workbenchLabel = new QLabel("" +// "Connectome
" +// "Workbench" +// ""); workbenchLabel->setStyleSheet(labelStyle); workbenchLabel->setAlignment(Qt::AlignCenter); - ApplicationInformation appInfo; QLabel* versionLabel = new QLabel("Version: " + appInfo.getVersion()); versionLabel->setAlignment(Qt::AlignCenter); -- GitLab From b32d278b6a398801777e3857a64136b0f1dd6ba8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Dec 2016 09:37:22 -0600 Subject: [PATCH 070/755] Resolve WB-654 (tile tabs stretch factors should not have a lower limit of 1): The lower limit has been changed from 1.0 to 0.1. A lower limit of 0.1 was used (instead of 0 or 0.01) to keep single steps (up/down arrow presses) in 0.1 increments (1.0, 0.9, 0.8, ... 0.1, 0.2, ..., 1.0). Otherwise step values going up would have been 0.01, 0.11, 0.21, 0.31, ... 1.01. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index a9817355c..e59a808db 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -219,7 +219,7 @@ TileTabsConfigurationDialog::createEditConfigurationWidget() Qt::AlignHCenter); row++; - const float stretchMinimumValue = 1.0; + const float stretchMinimumValue = 0.1; const float stretchMaximumValue = 10000000.0; const float stretchStep = 0.1; const float stretchDigitsRightOfDecimal = 2; -- GitLab From ffdd2fc6b8e4df19136271ff23c0c44a7b7cb0f3 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 22 Dec 2016 18:00:02 -0600 Subject: [PATCH 071/755] avoid crashes when resampling to an unusual volume space with less than 3 dimensions --- src/Algorithms/AlgorithmVolumeAffineResample.cxx | 4 +++- src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Algorithms/AlgorithmVolumeAffineResample.cxx b/src/Algorithms/AlgorithmVolumeAffineResample.cxx index 6beb6e996..62ea42180 100644 --- a/src/Algorithms/AlgorithmVolumeAffineResample.cxx +++ b/src/Algorithms/AlgorithmVolumeAffineResample.cxx @@ -95,7 +95,9 @@ void AlgorithmVolumeAffineResample::useParameters(OperationParameters* myParams, FloatMatrix affMat = FloatMatrix(myAffine.getMatrix()); NiftiIO refSpaceIO; refSpaceIO.openRead(refSpaceName); - AlgorithmVolumeAffineResample(myProgObj, inVol, affMat, refSpaceIO.getDimensions().data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); + vector refDims = refSpaceIO.getDimensions(); + if (refDims.size() < 3) refDims.resize(3, 1); + AlgorithmVolumeAffineResample(myProgObj, inVol, affMat, refDims.data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); } AlgorithmVolumeAffineResample::AlgorithmVolumeAffineResample(ProgressObject* myProgObj, const VolumeFile* inVol, const FloatMatrix& myAffine, diff --git a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx index eb57e7563..6c9e0da06 100644 --- a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx +++ b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx @@ -93,7 +93,9 @@ void AlgorithmVolumeWarpfieldResample::useParameters(OperationParameters* myPara } NiftiIO refSpaceIO; refSpaceIO.openRead(refSpaceName); - AlgorithmVolumeWarpfieldResample(myProgObj, inVol, myWarpfield.getWarpfield(), refSpaceIO.getDimensions().data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); + vector refDims = refSpaceIO.getDimensions(); + if (refDims.size() < 3) refDims.resize(3, 1); + AlgorithmVolumeWarpfieldResample(myProgObj, inVol, myWarpfield.getWarpfield(), refDims.data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); } AlgorithmVolumeWarpfieldResample::AlgorithmVolumeWarpfieldResample(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* warpfield, -- GitLab From acbca6ec4043c4b02b41b49ead114fcfdfd12c15 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 29 Dec 2016 20:07:48 -0600 Subject: [PATCH 072/755] add suggestion to "too many open files" error --- src/Common/CaretBinaryFile.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/CaretBinaryFile.cxx b/src/Common/CaretBinaryFile.cxx index 123dcae2d..85a73ad8a 100644 --- a/src/Common/CaretBinaryFile.cxx +++ b/src/Common/CaretBinaryFile.cxx @@ -296,7 +296,7 @@ void QFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& o switch (m_file.error()) { case QFile::ResourceError://on linux at least, it never gives another code besides the unhelpful OpenError - throw DataFileException("failed to open file '" + filename + "', too many open files"); + throw DataFileException("failed to open file '" + filename + "', too many open files, try 'ulimit -n 4096'"); default: if (opmode & CaretBinaryFile::WRITE) { -- GitLab From 0efeb8e9ec93cf75a96b8ed45de60ab5f8a87ecc Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 4 Jan 2017 20:38:13 -0600 Subject: [PATCH 073/755] add strain-based distortion computation --- src/Algorithms/AlgorithmSurfaceDistortion.cxx | 99 +++++++++++++++++-- src/Algorithms/AlgorithmSurfaceDistortion.h | 3 +- 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.cxx b/src/Algorithms/AlgorithmSurfaceDistortion.cxx index ad8dbb4c9..fef69f19f 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.cxx +++ b/src/Algorithms/AlgorithmSurfaceDistortion.cxx @@ -22,6 +22,7 @@ #include "AlgorithmException.h" #include "AlgorithmMetricSmoothing.h" +#include "FloatMatrix.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" @@ -60,6 +61,8 @@ OperationParameters* AlgorithmSurfaceDistortion::getParameters() ret->createOptionalParameter(6, "-edge-method", "calculate distortion of edge lengths rather than areas"); + ret->createOptionalParameter(7, "-strain-method", "calculate distortion by the local affines between triangles"); + ret->setHelpText( AString("This command, when not using -caret5-method or -edge-method, is equivalent to using -surface-vertex-areas on each surface, ") + "smoothing both output metrics with the GEO_GAUSS_EQUAL method on the surface they came from if -smooth is specified, and then using the formula " + @@ -67,7 +70,9 @@ OperationParameters* AlgorithmSurfaceDistortion::getParameters() "When using -caret5-method, it uses the surface distortion method from caret5, which takes the base 2 log of the ratio of tile areas, " + "then averages those results at each vertex, and then smooths the result on the reference surface.\n\n" + "When using -edge-method, the -smooth option is ignored, and the output at each vertex is the average of 'abs(ln(refEdge/distortEdge)/ln(2))' over all edges " + - "connected to the vertex." + "connected to the vertex.\n\n" + + "When using -strain-method, the -smooth option is ignored. The output is two columns, the first is the area distortion ratio, and the second is anisotropic strain. " + + "These are calculated by an affine transform between matching triangles, and then averaged across the triangles of a vertex." ); return ret; } @@ -84,20 +89,29 @@ void AlgorithmSurfaceDistortion::useParameters(OperationParameters* myParams, Pr smooth = (float)smoothOpt->getDouble(1); if (smooth <= 0.0f) throw AlgorithmException("smoothing kernel must be positive if specified"); } + int methodCount = 0; bool caret5method = myParams->getOptionalParameter(5)->m_present; + if (caret5method) ++methodCount; bool edgeMethod = myParams->getOptionalParameter(6)->m_present; - if (caret5method && edgeMethod) throw AlgorithmException("you may not specify both -caret5-method and -edge-method"); - AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod); + if (edgeMethod) ++methodCount; + bool strainMethod = myParams->getOptionalParameter(7)->m_present; + if (strainMethod) ++methodCount; + if (methodCount > 1) throw AlgorithmException("you may not specify more than one of -caret5-method, -edge-method, or -strain-method"); + AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod, strainMethod); } AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, - MetricFile* myMetricOut, const float& smooth, const bool& caret5method, const bool& edgeMethod) : AbstractAlgorithm(myProgObj) + MetricFile* myMetricOut, const float& smooth, const bool& caret5method, const bool& edgeMethod, const bool& strainMethod) : AbstractAlgorithm(myProgObj) { - if (caret5method && edgeMethod) throw AlgorithmException("you may not use both caret5 and edge method flags"); - ProgressObject* smoothRef = NULL, *smoothDistort = NULL, *caret5Smooth = NULL;//uncomment these if you use another algorithm inside here + int methodCount = 0; + if (caret5method) ++methodCount; + if (edgeMethod) ++methodCount; + if (strainMethod) ++methodCount; + if (methodCount > 1) throw AlgorithmException("you may not use multiple method flags"); + ProgressObject* smoothRef = NULL, *smoothDistort = NULL, *caret5Smooth = NULL; if (myProgObj != NULL) { - if (smooth > 0.0f && !edgeMethod) + if (smooth > 0.0f && !edgeMethod && !strainMethod) { if (caret5method) { @@ -111,7 +125,9 @@ AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj LevelProgress myProgress(myProgObj); if (!referenceSurf->hasNodeCorrespondence(*distortedSurf)) throw AlgorithmException("input surfaces must have node correspondence"); int numNodes = referenceSurf->getNumberOfNodes(); - myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); + int numOutCols = 1; + if (strainMethod) numOutCols = 2; + myMetricOut->setNumberOfNodesAndColumns(numNodes, numOutCols); myMetricOut->setStructure(referenceSurf->getStructure()); if (caret5method) { @@ -198,6 +214,73 @@ AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj } myMetricOut->setValue(i, 0, accum / numNeigh); } + } else if (strainMethod) { + myMetricOut->setColumnName(0, "area ratio (J)"); + myMetricOut->setColumnName(1, "elongation ratio (R)"); + int numTris = referenceSurf->getNumberOfTriangles(); + vector affines(numTris); + for (int i = 0; i < numTris; ++i) + { + const int32_t* thisTri = referenceSurf->getTriangle(i); + Vector3D allCoords[2][3]; + for (int j = 0; j < 3; ++j) + { + allCoords[0][j] = referenceSurf->getCoordinate(thisTri[j]); + allCoords[1][j] = distortedSurf->getCoordinate(thisTri[j]); + } + float allCoords2D[2][3][2];//ref/dist, vert, x/y + for (int k = 0; k < 2; ++k) + { + Vector3D iHat = (allCoords[k][1] - allCoords[k][0]).normal();//we don't need the triangle normal, so make the 2D basis without cross products + Vector3D jHat = allCoords[k][2] - allCoords[k][0]; + jHat = (jHat - iHat * iHat.dot(jHat)).normal(); + for (int j = 0; j < 3; ++j) + { + Vector3D tempCoord = allCoords[k][j] - allCoords[k][0];//use a triangle vertex as the origin to make the numbers smaller, less rounding error + allCoords2D[k][j][0] = iHat.dot(tempCoord); + allCoords2D[k][j][1] = jHat.dot(tempCoord); + } + } + affines[i].resize(2, 2, true); + FloatMatrix solver(3, 4);//3 equations, 3 unknowns + for (int k = 0; k < 2; ++k) + { + for (int j = 0; j < 3; ++j) + { + solver[j][0] = allCoords2D[0][j][0];//x + solver[j][1] = allCoords2D[0][j][1];//y + solver[j][2] = 1; + solver[j][3] = allCoords2D[1][j][k];//x' or y' + } + FloatMatrix solved = solver.reducedRowEchelon(); + affines[i][k][0] = solved[0][3];//x coef + affines[i][k][1] = solved[1][3];//y coef + } + } + int numNodes = referenceSurf->getNumberOfNodes(); + CaretPointer myTopoHelp = referenceSurf->getTopologyHelper(); + for (int i = 0; i < numNodes; ++i) + { + const vector& myTiles = myTopoHelp->getNodeTiles(i); + double accumJ = 0.0, accumR = 0.0; + for (int j = 0; j < (int)myTiles.size(); ++j) + { + FloatMatrix tempMat = affines[myTiles[j]] * affines[myTiles[j]].transpose(); + float thisJ = sqrt(tempMat[0][0] * tempMat[1][1] - tempMat[0][1] * tempMat[1][0]);//written-out determinant for 2x2, because FloatMatrix doesn't currently have a generic determinant function + float I1_st = (tempMat[0][0] + tempMat[1][1]) / thisJ;//2D formula + float thisR; + if (I1_st <= 2) + { + thisR = 1.0; + } else { + thisR = 0.5 * (I1_st + sqrt(I1_st * I1_st - 4));//convert I1* to (major strain) / (minor strain) + } + accumJ += thisJ;//not sure which areas to weight by, so for now do a straight average, relying on smoothness inherent in the measures + accumR += thisR;//could maybe do some fancy interpolation of the affines in 3D sphere space + } + myMetricOut->setValue(i, 0, accumJ / myTiles.size()); + myMetricOut->setValue(i, 1, accumR / myTiles.size()); + } } else { myMetricOut->setColumnName(0, "area distortion"); MetricFile refAreas, distortAreas; diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.h b/src/Algorithms/AlgorithmSurfaceDistortion.h index b50b5a604..e8c340a1e 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.h +++ b/src/Algorithms/AlgorithmSurfaceDistortion.h @@ -33,7 +33,8 @@ namespace caret { static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, - MetricFile* myMetricOut, const float& smooth = -1.0f, const bool& caret5method = false, const bool& edgeMethod = false); + MetricFile* myMetricOut, const float& smooth = -1.0f, + const bool& caret5method = false, const bool& edgeMethod = false, const bool& strainMethod = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); -- GitLab From 8cf35d68eb1489651fed92ea251a5f3f7694ce51 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 5 Jan 2017 16:30:49 -0600 Subject: [PATCH 074/755] remove most of the old autobuild scripts --- build_scripts/linux32_remote.sh | 7 - build_scripts/linux64_remote.sh | 8 -- build_scripts/linux64_rh.sh | 30 ----- build_scripts/linux64_rh_aux.sh | 62 --------- build_scripts/linux64_rh_remote.sh | 38 ------ build_scripts/mac32.sh | 39 ------ build_scripts/mac32_aux.sh | 79 ----------- build_scripts/mac32_remote.sh | 6 - build_scripts/mac64.sh | 28 ---- build_scripts/mac64_aux.sh | 112 ---------------- build_scripts/mac64_noodle.sh | 35 ----- build_scripts/mac64_noodle_aux.sh | 126 ------------------ build_scripts/mac64_noodle_remote.sh | 6 - build_scripts/mac64_remote.sh | 7 - build_scripts/windows64.bat | 37 ----- build_scripts/windows64/README.txt | 3 - build_scripts/windows64/build.bat | 21 --- build_scripts/windows64/build_debug.bat | 11 -- build_scripts/windows64/c7env64.bat | 7 - build_scripts/windows64/c7env64.vbs | 21 --- build_scripts/windows64/env.bat | 21 --- build_scripts/windows64/launchcmdvs.bat | 3 - build_scripts/windows64/launchqtcreatorvs.bat | 3 - build_scripts/windows64/launchvs.bat | 3 - build_scripts/windows64/setup_env.bat | 2 - build_scripts/windows6411/README.txt | 3 - build_scripts/windows6411/build.bat | 11 -- build_scripts/windows6411/c7env64.bat | 4 - build_scripts/windows6411/c7env64.vbs | 21 --- build_scripts/windows6411/ctp.bat | 2 - build_scripts/windows6411/env.bat | 20 --- build_scripts/windows6411/launchcmdvs.bat | 3 - .../windows6411/launchqtcreatorvs.bat | 3 - build_scripts/windows6411/launchvs.bat | 3 - build_scripts/windows6411/setup_env.bat | 2 - build_scripts/windows6412/README.txt | 3 - build_scripts/windows6412/build.bat | 11 -- build_scripts/windows6412/c7env64.bat | 4 - build_scripts/windows6412/c7env64.vbs | 21 --- build_scripts/windows6412/ctp.bat | 2 - build_scripts/windows6412/env.bat | 20 --- build_scripts/windows6412/launchcmdvs.bat | 3 - .../windows6412/launchqtcreatorvs.bat | 3 - build_scripts/windows6412/launchvs.bat | 3 - build_scripts/windows6412/setup_env.bat | 2 - build_scripts/windows64_debug.bat | 35 ----- build_scripts/windows64_remote.sh | 4 - build_scripts/windows64_remote_debug.sh | 4 - 48 files changed, 902 deletions(-) delete mode 100755 build_scripts/linux32_remote.sh delete mode 100755 build_scripts/linux64_remote.sh delete mode 100755 build_scripts/linux64_rh.sh delete mode 100755 build_scripts/linux64_rh_aux.sh delete mode 100755 build_scripts/linux64_rh_remote.sh delete mode 100755 build_scripts/mac32.sh delete mode 100755 build_scripts/mac32_aux.sh delete mode 100755 build_scripts/mac32_remote.sh delete mode 100755 build_scripts/mac64.sh delete mode 100755 build_scripts/mac64_aux.sh delete mode 100755 build_scripts/mac64_noodle.sh delete mode 100755 build_scripts/mac64_noodle_aux.sh delete mode 100755 build_scripts/mac64_noodle_remote.sh delete mode 100755 build_scripts/mac64_remote.sh delete mode 100755 build_scripts/windows64.bat delete mode 100644 build_scripts/windows64/README.txt delete mode 100755 build_scripts/windows64/build.bat delete mode 100755 build_scripts/windows64/build_debug.bat delete mode 100755 build_scripts/windows64/c7env64.bat delete mode 100755 build_scripts/windows64/c7env64.vbs delete mode 100755 build_scripts/windows64/env.bat delete mode 100755 build_scripts/windows64/launchcmdvs.bat delete mode 100755 build_scripts/windows64/launchqtcreatorvs.bat delete mode 100755 build_scripts/windows64/launchvs.bat delete mode 100755 build_scripts/windows64/setup_env.bat delete mode 100644 build_scripts/windows6411/README.txt delete mode 100755 build_scripts/windows6411/build.bat delete mode 100755 build_scripts/windows6411/c7env64.bat delete mode 100755 build_scripts/windows6411/c7env64.vbs delete mode 100755 build_scripts/windows6411/ctp.bat delete mode 100755 build_scripts/windows6411/env.bat delete mode 100755 build_scripts/windows6411/launchcmdvs.bat delete mode 100755 build_scripts/windows6411/launchqtcreatorvs.bat delete mode 100755 build_scripts/windows6411/launchvs.bat delete mode 100755 build_scripts/windows6411/setup_env.bat delete mode 100755 build_scripts/windows6412/README.txt delete mode 100755 build_scripts/windows6412/build.bat delete mode 100755 build_scripts/windows6412/c7env64.bat delete mode 100755 build_scripts/windows6412/c7env64.vbs delete mode 100755 build_scripts/windows6412/ctp.bat delete mode 100755 build_scripts/windows6412/env.bat delete mode 100755 build_scripts/windows6412/launchcmdvs.bat delete mode 100755 build_scripts/windows6412/launchqtcreatorvs.bat delete mode 100755 build_scripts/windows6412/launchvs.bat delete mode 100755 build_scripts/windows6412/setup_env.bat delete mode 100755 build_scripts/windows64_debug.bat delete mode 100755 build_scripts/windows64_remote.sh delete mode 100755 build_scripts/windows64_remote_debug.sh diff --git a/build_scripts/linux32_remote.sh b/build_scripts/linux32_remote.sh deleted file mode 100755 index e70349d2a..000000000 --- a/build_scripts/linux32_remote.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -BUILD=linux32 -BUILD_SERVER=linuxbuild - -BUILD_DIR=/home/caret/${BUILD}/caret7_dev -ssh -v caret@${BUILD_SERVER} "/bin/bash -c \"cd ${BUILD_DIR};./build32.sh caret\"" > $PWD/remote_launch_${BUILD}.txt 2>&1 -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 32 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/linux64_remote.sh b/build_scripts/linux64_remote.sh deleted file mode 100755 index 001cc26b8..000000000 --- a/build_scripts/linux64_remote.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -BUILD=linux64 -BUILD_SERVER=linuxbuild - -BUILD_DIR=/home/caret/${BUILD}/caret7_dev -ssh -v caret@${BUILD_SERVER} "/bin/bash -c \"cd ${BUILD_DIR};./build64.sh caret\"" > $PWD/remote_launch_${BUILD}.txt 2>&1 -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Linux 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu - diff --git a/build_scripts/linux64_rh.sh b/build_scripts/linux64_rh.sh deleted file mode 100755 index d4f6fc161..000000000 --- a/build_scripts/linux64_rh.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# -# This file is executed by myelin1. -# -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# - -# -# File for capturing standard error -# -BUILD_ROOT_DIR=/home/caret/caret7_dev - -# -# If something fails, keep going -# -set noon - -# -# Run the build script -# -echo "Starting linux64 Redhat aux script" -${BUILD_ROOT_DIR}/caret7_source/build_scripts/linux64_rh_aux.sh -resultFlag=$? -echo "Finished linux64 Redhat script" - -exit $resultFlag diff --git a/build_scripts/linux64_rh_aux.sh b/build_scripts/linux64_rh_aux.sh deleted file mode 100755 index 887370b78..000000000 --- a/build_scripts/linux64_rh_aux.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -# -# This file is executed on the redhat build machine -# -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# -# Based off Tim Coalson's "buildbot" script -# - -BUILD_ROOT_DIR=/home/caret/caret7_dev -GIT_ROOT_DIR=${BUILD_ROOT_DIR}/caret7_source -BUILD_DIR=${BUILD_ROOT_DIR}/build -cd ${BUILD_ROOT_DIR} -echo "BUILD_DIR: ${BUILD_DIR}" - -# -# Go into git checkout directory -# -cd ${GIT_ROOT_DIR} - - -# -# Update source from repository -# -echo "UPDATING SOURCE FROM GIT REPOSITORY" -git fetch -git reset --hard origin/master - -# -# Build, assume the build directory is already set up as desired -# -echo "BUILDING SOURCE" -cd ${BUILD_DIR} -make -j2 - -# -# Exit with result of running 'make' -# Cannot scp does not work when run on cluster system to outside cluster -# -exit $? - - - - - -# -# Copy to distribution directory -# -#echo "COPYING PROGRAMS" -#DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 -#scp Desktop/wb_view caret@myelin1.wustl.edu:${DIST_DIR} -#scp CommandLine/wb_command caret@myelin1.wustl.edu:${DIST_DIR} -#scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 -##put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) -#scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} - -echo "SCRIPT COMPLETED SUCCESSFULLY" - diff --git a/build_scripts/linux64_rh_remote.sh b/build_scripts/linux64_rh_remote.sh deleted file mode 100755 index aa58e0258..000000000 --- a/build_scripts/linux64_rh_remote.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -BUILD=linux64_rh -BUILD_SERVER=login01.chpc.wustl.edu -COPY_SERVER=dtn01.chpc.wustl.edu - -BUILD_DIR=/home/caret/caret7_dev - -ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 -buildResult=$? - -if [ ! $result ]; then - echo "Build was successful, now copying to distribution directory" - - # - # Copy to distribution directory - # Copy from 'dtn01 (copying will hang on login01) - # - echo "COPYING PROGRAMS" - COPY_FROM_DIR=caret@${COPY_SERVER}:${BUILD_DIR}/build - DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/exe_rh_linux64 - scp ${COPY_FROM_DIR}/Desktop/wb_view ${DIST_DIR} >> $PWD/remote_launch_${BUILD}.txt 2>&1 - scp ${COPY_FROM_DIR}/CommandLine/wb_command ${DIST_DIR} >> $PWD/remote_launch_${BUILD}.txt 2>&1 - - # - # Need to be changed - # - #scp ${GIT_ROOT_DIR}/src/CommandLine/wb_shortcuts caret@myelin1.wustl.edu:/mainpool/storage/distribution/caret7_distribution/workbench/bin_rh_linux64 - #put the completion into the exe directory, because it isn't useful to run it directly (and would make wb_comm behave worse) - #scp ${GIT_ROOT_DIR}/src/CommandLine/bashcomplete_wb_command caret@myelin1.wustl.edu:${DIST_DIR} - - echo "SCRIPT COMPLETED SUCCESSFULLY" -else - echo "Build failed" -fi - -cat $PWD/remote_launch_${BUILD}.txt | mailx -v -s 'Caret7 Linux 64 RedHat Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu - - diff --git a/build_scripts/mac32.sh b/build_scripts/mac32.sh deleted file mode 100755 index 64eb448e8..000000000 --- a/build_scripts/mac32.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -# -# This file is executed by (via "launchd") -# /System/Library/LaunchDaemons/edu.wustl.caret.build.mac32.plist -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# - -# -# File for capturing standard error -# -BUILD_ROOT_DIR=/Users/caret/caret7_development/mac32 -ERROR_FILE=${BUILD_ROOT_DIR}/result_build_mac32.txt -rm -f ${ERROR_FILE} - -# -# If something fails, keep going -# -set noon - -# -# Run the build script -# -echo "Starting mac32 aux script" >> ${ERROR_FILE} 2>&1 -${BUILD_ROOT_DIR}/caret7_source/build_scripts/mac32_aux.sh >> ${ERROR_FILE} 2>&1 -echo "Finished mac32 aux script" >> ${ERROR_FILE} 2>&1 - -# -# Send output as email -# -MAIL_ERROR_FILE=${BUILD_ROOT_DIR}/mail_result_build_mac32.txt -rm -f ${MAIL_ERROR_FILE} -cat ${ERROR_FILE} | mail -v -s 'Caret7 Mac 32 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu >> ${MAIL_ERROR_FILE} 2>&1 - -echo "Sent mail" - diff --git a/build_scripts/mac32_aux.sh b/build_scripts/mac32_aux.sh deleted file mode 100755 index 58f7829a0..000000000 --- a/build_scripts/mac32_aux.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh - -# -# This file is executed by (via "launchd") -# /System/Library/LaunchDaemons/edu.wustl.caret.build.mac32.plist -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# -# Based off Tim Coalson's "buildbot" script -# - -# -# Go to correct directory -# -BUILD_ROOT_DIR=/Users/caret/caret7_development/mac32 -GIT_ROOT_DIR=${BUILD_ROOT_DIR}/caret7_source -SRC_DIR=${GIT_ROOT_DIR}/src -BUILD_DIR=${BUILD_ROOT_DIR}/build -cd ${BUILD_ROOT_DIR} -echo "BUILD_DIR: ${BUILD_DIR}" - -# -# Use Qt SDK -# -QTDIR=/Users/caret/QtSDK/Desktop/Qt/474/gcc -export QTDIR -echo "QTDIR: ${QTDIR}" - -PATH=${QTDIR}/bin:${PATH} -export PATH -QMAKE_PROG=`which qmake` -echo "QMAKE: ${QMAKE_PROG}" - -# -# Go into git checkout directory -# -cd ${GIT_ROOT_DIR} - - -# -# Update source from repository -# -echo "UPDATING SOURCE FROM GIT REPOSITORY" -git reset --hard HEAD -git pull -u - -# -# Configure and build as release. -# Build twice so that if the build fails, the second build will -# contain just the output that shows the errors. -# Catch output and echo to screen. -# -echo "BUILDING SOURCE" -mkdir -p ${BUILD_DIR} -cd ${BUILD_DIR} -cmake ${SRC_DIR} -make -j2 -make -j2 - -# -# Run 'macdeployqt' on the App so that frameworks are copied -# -echo "RUNNING MACDEPLOYQT" -macdeployqt Desktop/wb_view.app - -# -# Copy to distribution directory -# -echo "COPYING PROGRAMS" -DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/macosx32_apps -scp -rv Desktop/wb_view.app caret@myelin1:${DIST_DIR} -scp -v CommandLine/wb_command caret@myelin1:${DIST_DIR} -scp -v ${SRC_DIR}/CommandLine/wb_shortcuts caret@myelin1:${DIST_DIR} -scp -v ${SRC_DIR}/CommandLine/bashcomplete_wb_command caret@myelin1:${DIST_DIR} - -echo "SCRIPT COMPLETED SUCCESSFULLY" - diff --git a/build_scripts/mac32_remote.sh b/build_scripts/mac32_remote.sh deleted file mode 100755 index 1c351b468..000000000 --- a/build_scripts/mac32_remote.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -BUILD=mac32 -BUILD_SERVER=hippocampus.wustl.edu - -BUILD_DIR=/Users/caret/caret7_development/${BUILD} -ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 diff --git a/build_scripts/mac64.sh b/build_scripts/mac64.sh deleted file mode 100755 index 657a6b049..000000000 --- a/build_scripts/mac64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# -# This file is executed by (via "launchd") -# /System/Library/LaunchDaemons/edu.wustl.caret.build.mac64.plist -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# - -# -# File for capturing standard error -# -BUILD_ROOT_DIR=/Users/caret/caret7_development/mac64 - -# -# If something fails, keep going -# -set noon - -# -# Run the build script -# -echo "Starting mac64 aux script" -${BUILD_ROOT_DIR}/caret7_source/build_scripts/mac64_aux.sh -echo "Finished mac64 aux script" - diff --git a/build_scripts/mac64_aux.sh b/build_scripts/mac64_aux.sh deleted file mode 100755 index 6c6bf82ef..000000000 --- a/build_scripts/mac64_aux.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh - -# -# This file is executed by (via "launchd") -# /System/Library/LaunchDaemons/edu.wustl.caret.build.mac64.plist -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# -# Based off Tim Coalson's "buildbot" script -# - -# -# Go to correct directory -# -BUILD_ROOT_DIR=/Users/caret/caret7_development/mac64 -GIT_ROOT_DIR=${BUILD_ROOT_DIR}/caret7_source -SRC_DIR=${GIT_ROOT_DIR}/src -BUILD_DIR=${BUILD_ROOT_DIR}/build -cd ${BUILD_ROOT_DIR} -echo "BUILD_DIR: ${BUILD_DIR}" - -# -# Setup Environment -# - -# -# Use Qt SDK -# -#QTDIR=/Users/caret/QtSDK/Desktop/Qt/474/gcc -# has SSL linked -QTDIR=/opt/caret64_sdk/install/qt-4.8.3 -export QTDIR -echo "QTDIR: ${QTDIR}" - -PATH=${QTDIR}/bin:${PATH} -export PATH -QMAKE_PROG=`which qmake` -echo "QMAKE: ${QMAKE_PROG}" - -# -# Go into git checkout directory -# -cd ${GIT_ROOT_DIR} - - -# -# Update source from repository -# -echo "UPDATING SOURCE FROM GIT REPOSITORY" -git reset --hard HEAD -git pull -u - -# -# Configure and build as release. -# Build twice so that if the build fails, the second build will -# contain just the output that shows the errors. -# Catch output and echo to screen. -# -#CC_COMPILER=/usr/local/clang-llvm/clang+llvm-3.2-x86_64-apple-darwin11/bin/clang -#CXX_COMPILER=/usr/local/clang-llvm/clang+llvm-3.2-x86_64-apple-darwin11/bin/clang++ -#CC_COMPILER=/usr/bin/gcc -#CXX_COMPILER=/usr/bin/g++ -#CC_COMPILER=/usr/local/gcc-4.9.3/bin/gcc -#CXX_COMPILER=/usr/local/gcc-4.9.3/bin/g++ - -# -# Clang compiler with OpenMP -# -CC_COMPILER=/usr/local/clang-openmp-opt/llvm/build/Release/bin/clang2 -CXX_COMPILER=/usr/local/clang-openmp-opt/llvm/build/Release/bin/clang2++ -OPENMP_COMPILE_OPTION=-fopenmp -export OPENMP_COMPILE_OPTION -OPENMP_HEADER_DIR=/usr/local/clang-openmp-opt/llvm/build/Release/include -export OPENMP_HEADER_DIR -OPENMP_LIB_DIR=/usr/local/clang-openmp-opt/llvm/build/Release/lib -export OPENMP_LIB_DIR - - -echo "BUILDING SOURCE" -mkdir -p ${BUILD_DIR} -cd ${BUILD_DIR} -/usr/local/cmake-3.6.2/bin/cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER=${CC_COMPILER} \ - -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ - -DWORKBENCH_MESA_DIR=/opt/caret64_sdk/install/Mesa-7.8.2 \ - -DCMAKE_VERBOSE_MAKEFILE=FALSE \ - ${SRC_DIR} -make -j2 -make -j2 - -# -# Run 'macdeployqt' on the Apps so that frameworks are copied -# -echo "RUNNING MACDEPLOYQT" -macdeployqt Desktop/wb_view.app -verbose=0 -macdeployqt CommandLine/wb_command.app -verbose=0 - -# -# Copy to distribution directory -# -echo "COPYING PROGRAMS" -DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/macosx64_apps -scp -r Desktop/wb_view.app caret@myelin1:${DIST_DIR} -scp -r CommandLine/wb_command.app caret@myelin1:${DIST_DIR} -scp ${SRC_DIR}/CommandLine/wb_shortcuts caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_macosx64 -scp ${SRC_DIR}/CommandLine/bashcomplete_wb_command caret@myelin1:${DIST_DIR} - -echo "SCRIPT COMPLETED SUCCESSFULLY" - diff --git a/build_scripts/mac64_noodle.sh b/build_scripts/mac64_noodle.sh deleted file mode 100755 index 0d5ec1a47..000000000 --- a/build_scripts/mac64_noodle.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -# -# -# - -# -# File for capturing standard error -# -BUILD_ROOT_DIR=/Users/caret/caret7_autobuild -ERROR_FILE=${BUILD_ROOT_DIR}/result_build_mac64_noodle.txt -rm -f ${ERROR_FILE} - -# -# If something fails, keep going -# -set noon - -# -# Run the build script -# -echo "Starting mac64 noodle aux script" >> ${ERROR_FILE} 2>&1 -${BUILD_ROOT_DIR}/caret7_source/build_scripts/mac64_noodle_aux.sh >> ${ERROR_FILE} 2>&1 -echo "Finished mac64 noodle aux script" >> ${ERROR_FILE} 2>&1 - -# -# Send output as email -# -MAIL_ERROR_FILE=${BUILD_ROOT_DIR}/mail_result_build_mac64_noodle.txt -rm -f ${MAIL_ERROR_FILE} -#cat ${ERROR_FILE} | mail -v -s 'Caret7 Mac 64 Noodle Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu >> ${MAIL_ERROR_FILE} 2>&1 -cat ${ERROR_FILE} | mail -v -s 'Caret7 Mac 64 Noodle Build Result' john@brainvis.wustl.edu >> ${MAIL_ERROR_FILE} 2>&1 - -echo "Sent mail" - diff --git a/build_scripts/mac64_noodle_aux.sh b/build_scripts/mac64_noodle_aux.sh deleted file mode 100755 index 78059f0b6..000000000 --- a/build_scripts/mac64_noodle_aux.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/sh - -# -# (1) Update source code from repository -# (2) Build Caret programs -# (3) Copy executables into the distribution -# -# Based off Tim Coalson's "buildbot" script -# - -# -# Go to correct directory -# -BUILD_ROOT_DIR=/Users/caret/caret7_autobuild -GIT_ROOT_DIR=${BUILD_ROOT_DIR}/caret7_source -SRC_DIR=${GIT_ROOT_DIR}/src -BUILD_SCRIPT_DIR=${GIT_ROOT_DIR}/build_scripts -#BUILD_SCRIPT_DIR=/Users/caret/develop_build_script -BUILD_DIR=${BUILD_ROOT_DIR}/build -cd ${BUILD_ROOT_DIR} -echo "BUILD_DIR: ${BUILD_DIR}" - -# -# Setup Environment -# - -# -# Use Qt SDK -# -QTDIR=/opt/caret64_sdk/install/qt-4.8.7/bin/qmake -export QTDIR -echo "QTDIR: ${QTDIR}" - -PATH=${QTDIR}/bin:${PATH} -export PATH -QMAKE_PROG=`which qmake` -echo "QMAKE: ${QMAKE_PROG}" - -# -# Go into git checkout directory -# -cd ${GIT_ROOT_DIR} - - -# -# Update source from repository -# -echo "UPDATING SOURCE FROM GIT REPOSITORY" -git reset --hard HEAD -git pull -u - - -# -# Clang compiler -# -# OpenMP is added to compiler and environment -# variables must be set so compiler finds OpenMP. -# -CC_COMPILER=/opt/local/bin/clang-mp-3.7 -CXX_COMPILER=/opt/local/bin/clang++-mp-3.7 -OPENMP_COMPILE_OPTION="-fopenmp -D_OPENMP" -export OPENMP_COMPILE_OPTION -OPENMP_HEADER_DIR=/opt/local/include/libomp -export OPENMP_HEADER_DIR -OPENMP_LIB_DIR=/opt/local/lib/libomp -export OPENMP_LIB_DIR - -# -# Mesa Library for Offscreen OpenGL -# -OSMESA_DIR=/opt/caret64_sdk/install/Mesa-7.8.2 - -# -# CMake executable path -# -CMAKE_EXE=/opt/caret64_sdk/install/cmake-3.5.2/bin/cmake - -# -# Configure with CMake -# -echo "BUILDING SOURCE" -mkdir -p ${BUILD_DIR} -cd ${BUILD_DIR} -${CMAKE_EXE} \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER=${CC_COMPILER} \ - -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ - -DCMAKE_VERBOSE_MAKEFILE=FALSE \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \ - -DCMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk" \ - ${SRC_DIR} - -# -# Run Make to build. -# It is run twice so that errors will be at end of log file -# -make -j2 -make -j - -# -# Run 'macdeployqt' on the Apps so that Qt frameworks are copied -# -echo "RUNNING MACDEPLOYQT" -macdeployqt Desktop/wb_view.app -verbose=0 -macdeployqt CommandLine/wb_command.app -verbose=0 - -# -# Need to copy OpenMP library to wb_view and wb_command -# -${BUILD_SCRIPT_DIR}/mac64_copy_library_to_workbench.sh \ - ${OPENMP_LIB_DIR}/libomp.dylib \ - ${BUILD_DIR}/Desktop/wb_view.app/Contents/MacOS/wb_view -${BUILD_SCRIPT_DIR}/mac64_copy_library_to_workbench.sh \ - ${OPENMP_LIB_DIR}/libomp.dylib \ - ${BUILD_DIR}/CommandLine/wb_command.app/Contents/MacOS/wb_command - -# -# Copy to distribution directory -# -echo "COPYING PROGRAMS" -DIST_DIR=/mainpool/storage/distribution/caret7_distribution/workbench/macosx64_noodle_apps -scp -r Desktop/wb_view.app caret@myelin1:${DIST_DIR} -scp -r CommandLine/wb_command.app caret@myelin1:${DIST_DIR} - -echo "SCRIPT COMPLETED SUCCESSFULLY" - diff --git a/build_scripts/mac64_noodle_remote.sh b/build_scripts/mac64_noodle_remote.sh deleted file mode 100755 index 4ec2af81b..000000000 --- a/build_scripts/mac64_noodle_remote.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -BUILD=mac64_noodle -BUILD_SERVER=noodle.wustl.edu - -BUILD_DIR=/Users/caret/caret7_autobuild -ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 diff --git a/build_scripts/mac64_remote.sh b/build_scripts/mac64_remote.sh deleted file mode 100755 index 592bca120..000000000 --- a/build_scripts/mac64_remote.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -BUILD=mac64 -BUILD_SERVER=hippocampus.wustl.edu - -BUILD_DIR=/Users/caret/caret7_development/${BUILD} -ssh -v caret@${BUILD_SERVER} ${BUILD_DIR}/caret7_source/build_scripts/${BUILD}.sh $1 > $PWD/remote_launch_${BUILD}.txt 2>&1 -cat $PWD/remote_launch_${BUILD}.txt | mailx -s 'Caret7 Mac 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/windows64.bat b/build_scripts/windows64.bat deleted file mode 100755 index 7bd771721..000000000 --- a/build_scripts/windows64.bat +++ /dev/null @@ -1,37 +0,0 @@ -@echo=off -set CMD=c:\Windows\system32\cmd.exe -REM -REM Go to correct directory -REM -set BUILD_DIR=c:\dev7\windows64 -cd %BUILD_DIR% - -REM -REM Go into source directory -REM -cd caret7_source - -echo "Caret7 Windows64 Build Result" - -REM -REM Grab the latest Sources -REM -c:\cygwin\bin\git.exe reset --hard HEAD -c:\cygwin\bin\git.exe fetch -c:\cygwin\bin\git.exe reset --hard origin/master - -REM -REM Build caret -REM -cd build_scripts/windows64 -%CMD% /c build.bat -cd .. -cd .. -set DIST_DIR=caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_windows64 - -echo "Copying Files" -c:\cygwin\bin\scp build/Desktop/wb_view.exe %DIST_DIR% -c:\cygwin\bin\scp build/CommandLine/wb_command.exe %DIST_DIR% -c:\cygwin\bin\scp src/CommandLine/wb_shortcuts %DIST_DIR% -c:\cygwin\bin\scp src/CommandLine/bashcomplete_wb_command %DIST_DIR% -echo "Finished Copying Files" diff --git a/build_scripts/windows64/README.txt b/build_scripts/windows64/README.txt deleted file mode 100644 index 6d8910cad..000000000 --- a/build_scripts/windows64/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -setup_env.bat -sets up the build environment -build.bat -sets up environment, runs cmake, and builds the release version of caret -c7env64.bat - sets up environment diff --git a/build_scripts/windows64/build.bat b/build_scripts/windows64/build.bat deleted file mode 100755 index 6b654183d..000000000 --- a/build_scripts/windows64/build.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -if [%MACHINE%]==[] call setup_env.bat - -set OLD_DIR=%CD% -md %DIR%\caret7_source\build -cd /d %DIR%\caret7_source\build -cmake ^ - -DWORKBENCH_FREETYPE_DIR=C:\dev64\install\FreeType-2.4.8 ^ - -DZLIB_ROOT=C:\dev64\install\zlib ^ - -G "NMake Makefiles JOM" ^ - -DCMAKE_BUILD_TYPE=Release ^ - ../src - -jom -j8 -cd /d %OLD_DIR% -set OLD_DIR= - - -REM JWH -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev64\install\FreeType-2.4.8\include\freetype2 -REM JWH -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev64\install\FreeType-2.4.8\include -REM JWH -DFREETYPE_LIBRARY=C:\dev64\install\FreeType-2.4.8\lib\freetype.lib diff --git a/build_scripts/windows64/build_debug.bat b/build_scripts/windows64/build_debug.bat deleted file mode 100755 index b53f4294b..000000000 --- a/build_scripts/windows64/build_debug.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -if [%MACHINE%]==[] call setup_env.bat - -set OLD_DIR=%CD% -REM rd /q/s %DIR%\caret7_source\build_debug -md %DIR%\caret7_source\build_debug -cd /d %DIR%\caret7_source\build_debug -cmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Debug ../src -jom -j8 -cd /d %OLD_DIR% -set OLD_DIR= diff --git a/build_scripts/windows64/c7env64.bat b/build_scripts/windows64/c7env64.bat deleted file mode 100755 index af814c251..000000000 --- a/build_scripts/windows64/c7env64.bat +++ /dev/null @@ -1,7 +0,0 @@ -REM set PATH=C:\dev64\install\Qt481\bin;C:\Qt\qtcreator-2.4.1\bin;%PATH% -REM set QTDIR=C:\dev64\install\Qt481 -set QTDIR=C:\dev64\install\qt-4.8.7 -set PATH=%QTDIR%\bin;C:\Qt\qtcreator-2.4.1\bin;%PATH% -set ZLIB_LIB_DIR=C:\dev64\install\zlib\lib -set ZLIB_INC_DIR=C:\dev64\install\zlib\include -set FREETYPE_DIR=C:\dev64\install\FreeType-2.4.8 diff --git a/build_scripts/windows64/c7env64.vbs b/build_scripts/windows64/c7env64.vbs deleted file mode 100755 index 646bd92da..000000000 --- a/build_scripts/windows64/c7env64.vbs +++ /dev/null @@ -1,21 +0,0 @@ -Set objShell = WScript.CreateObject("WScript.Shell") -Set colUsrEnvVars = objShell.Environment("USER") - -QtPath = "C:\dev64\install\Qt\bin" - -Path = colUsrEnvVars("OLDPATH") - -If Len(Path) = 0 Then - colUsrEnvVars("OLDPATH") = colUsrEnvVars("PATH") - 'objShell.ExpandEnvironmentStrings("%PATH%") - WScript.Echo colUsrEnvVars("OLDPATH") - Path = colUsrEnvVars("OLDPATH") -End If - -NewPath = (QtPath & ";" & Path) -colUsrEnvVars("PATH") = (NewPath) - -colUsrEnvVars("QTDIR") = "C:\dev64\install\Qt" - -colUsrEnvVars("ZLIB_LIB_DIR") = "C:\dev64\install\zlib\lib" -colUsrEnvVars("ZLIB_INC_DIR") = "C:\dev64\install\zlib\include" \ No newline at end of file diff --git a/build_scripts/windows64/env.bat b/build_scripts/windows64/env.bat deleted file mode 100755 index 3aee5c106..000000000 --- a/build_scripts/windows64/env.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -rem isn't batch awesome, no else statments... -IF [%1]==[] ( - set DIR "." -) -IF NOT [%1]==[] ( -set DIR=%1 -) -IF [%2]==[] ( - set MACHINE X86 -) -IF NOT [%2]==[] ( -set MACHINE=%2 -) - -IF NOT [%INITVS%]==[%MACHINE%] ( - echo "Setting %MACHINE% bit compiler variables" - set INITVS=%MACHINE% - call "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %MACHINE% - CD %DIR% -) \ No newline at end of file diff --git a/build_scripts/windows64/launchcmdvs.bat b/build_scripts/windows64/launchcmdvs.bat deleted file mode 100755 index dcf238c30..000000000 --- a/build_scripts/windows64/launchcmdvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev\git\caret7_source" x64 -cmd.exe diff --git a/build_scripts/windows64/launchqtcreatorvs.bat b/build_scripts/windows64/launchqtcreatorvs.bat deleted file mode 100755 index f10593a95..000000000 --- a/build_scripts/windows64/launchqtcreatorvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev\git\caret7_source" x64 -C:\Qt\qtcreator-2.7.1\bin\qtcreator.exe diff --git a/build_scripts/windows64/launchvs.bat b/build_scripts/windows64/launchvs.bat deleted file mode 100755 index b948bf0f8..000000000 --- a/build_scripts/windows64/launchvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" x64 -devenv.exe diff --git a/build_scripts/windows64/setup_env.bat b/build_scripts/windows64/setup_env.bat deleted file mode 100755 index 7c2061860..000000000 --- a/build_scripts/windows64/setup_env.bat +++ /dev/null @@ -1,2 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" AMD64 \ No newline at end of file diff --git a/build_scripts/windows6411/README.txt b/build_scripts/windows6411/README.txt deleted file mode 100644 index 6d8910cad..000000000 --- a/build_scripts/windows6411/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -setup_env.bat -sets up the build environment -build.bat -sets up environment, runs cmake, and builds the release version of caret -c7env64.bat - sets up environment diff --git a/build_scripts/windows6411/build.bat b/build_scripts/windows6411/build.bat deleted file mode 100755 index f0d100316..000000000 --- a/build_scripts/windows6411/build.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -if [%MACHINE%]==[] call setup_env.bat - -set OLD_DIR=%CD% -REM rd /q/s %DIR%\caret7_source\build -md %DIR%\caret7_source\build -cd /d %DIR%\caret7_source\build -cmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src -jom -j8 -cd /d %OLD_DIR% -set OLD_DIR= \ No newline at end of file diff --git a/build_scripts/windows6411/c7env64.bat b/build_scripts/windows6411/c7env64.bat deleted file mode 100755 index be2ce6303..000000000 --- a/build_scripts/windows6411/c7env64.bat +++ /dev/null @@ -1,4 +0,0 @@ -set PATH=C:\dev6411\install\Qt482\bin;C:\Qt\qtcreator-2.4.1\bin;%PATH% -set QTDIR=C:\dev6411\install\Qt482 -set ZLIB_LIB_DIR=C:\dev6411\install\zlib\lib -set ZLIB_INC_DIR=C:\dev6411\install\zlib\include \ No newline at end of file diff --git a/build_scripts/windows6411/c7env64.vbs b/build_scripts/windows6411/c7env64.vbs deleted file mode 100755 index 9f22dfbf5..000000000 --- a/build_scripts/windows6411/c7env64.vbs +++ /dev/null @@ -1,21 +0,0 @@ -Set objShell = WScript.CreateObject("WScript.Shell") -Set colUsrEnvVars = objShell.Environment("USER") - -QtPath = "C:\dev6411\install\Qt\bin" - -Path = colUsrEnvVars("OLDPATH") - -If Len(Path) = 0 Then - colUsrEnvVars("OLDPATH") = colUsrEnvVars("PATH") - 'objShell.ExpandEnvironmentStrings("%PATH%") - WScript.Echo colUsrEnvVars("OLDPATH") - Path = colUsrEnvVars("OLDPATH") -End If - -NewPath = (QtPath & ";" & Path) -colUsrEnvVars("PATH") = (NewPath) - -colUsrEnvVars("QTDIR") = "C:\dev6411\install\Qt" - -colUsrEnvVars("ZLIB_LIB_DIR") = "C:\dev6411\install\zlib\lib" -colUsrEnvVars("ZLIB_INC_DIR") = "C:\dev6411\install\zlib\include" \ No newline at end of file diff --git a/build_scripts/windows6411/ctp.bat b/build_scripts/windows6411/ctp.bat deleted file mode 100755 index 91a0c79f2..000000000 --- a/build_scripts/windows6411/ctp.bat +++ /dev/null @@ -1,2 +0,0 @@ -set PATH=c:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2012 CTP\bin;%PATH% -set INCLUDE=c:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2012 CTP\include;%INCLUDE% \ No newline at end of file diff --git a/build_scripts/windows6411/env.bat b/build_scripts/windows6411/env.bat deleted file mode 100755 index 1f68351a4..000000000 --- a/build_scripts/windows6411/env.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -rem isn't batch awesome, no else statments... -IF [%1]==[] ( - set DIR "." -) -IF NOT [%1]==[] ( -set DIR=%1 -) -IF [%2]==[] ( - set MACHINE X86 -) -IF NOT [%2]==[] ( -set MACHINE=%2 -) - -IF NOT [%INITVS%]==[%MACHINE%] ( - echo "Setting %MACHINE% bit compiler variables" - set INITVS=%MACHINE% - call "c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" %MACHINE% -) \ No newline at end of file diff --git a/build_scripts/windows6411/launchcmdvs.bat b/build_scripts/windows6411/launchcmdvs.bat deleted file mode 100755 index dcf238c30..000000000 --- a/build_scripts/windows6411/launchcmdvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev\git\caret7_source" x64 -cmd.exe diff --git a/build_scripts/windows6411/launchqtcreatorvs.bat b/build_scripts/windows6411/launchqtcreatorvs.bat deleted file mode 100755 index c74912741..000000000 --- a/build_scripts/windows6411/launchqtcreatorvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env32.bat -call env.bat "c:\dev7\windows32" x64 -qtcreator.exe diff --git a/build_scripts/windows6411/launchvs.bat b/build_scripts/windows6411/launchvs.bat deleted file mode 100755 index b948bf0f8..000000000 --- a/build_scripts/windows6411/launchvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" x64 -devenv.exe diff --git a/build_scripts/windows6411/setup_env.bat b/build_scripts/windows6411/setup_env.bat deleted file mode 100755 index 7c2061860..000000000 --- a/build_scripts/windows6411/setup_env.bat +++ /dev/null @@ -1,2 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" AMD64 \ No newline at end of file diff --git a/build_scripts/windows6412/README.txt b/build_scripts/windows6412/README.txt deleted file mode 100755 index 6d8910cad..000000000 --- a/build_scripts/windows6412/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -setup_env.bat -sets up the build environment -build.bat -sets up environment, runs cmake, and builds the release version of caret -c7env64.bat - sets up environment diff --git a/build_scripts/windows6412/build.bat b/build_scripts/windows6412/build.bat deleted file mode 100755 index f0d100316..000000000 --- a/build_scripts/windows6412/build.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -if [%MACHINE%]==[] call setup_env.bat - -set OLD_DIR=%CD% -REM rd /q/s %DIR%\caret7_source\build -md %DIR%\caret7_source\build -cd /d %DIR%\caret7_source\build -cmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src -jom -j8 -cd /d %OLD_DIR% -set OLD_DIR= \ No newline at end of file diff --git a/build_scripts/windows6412/c7env64.bat b/build_scripts/windows6412/c7env64.bat deleted file mode 100755 index aafc2c3f3..000000000 --- a/build_scripts/windows6412/c7env64.bat +++ /dev/null @@ -1,4 +0,0 @@ -set PATH=C:\dev6412\install\Qt486\bin;C:\Qt\qtcreator-2.4.1\bin;%PATH% -set QTDIR=C:\dev6412\install\Qt486 -set ZLIB_LIB_DIR=C:\dev6412\install\zlib\lib -set ZLIB_INC_DIR=C:\dev6412\install\zlib\include \ No newline at end of file diff --git a/build_scripts/windows6412/c7env64.vbs b/build_scripts/windows6412/c7env64.vbs deleted file mode 100755 index 9f22dfbf5..000000000 --- a/build_scripts/windows6412/c7env64.vbs +++ /dev/null @@ -1,21 +0,0 @@ -Set objShell = WScript.CreateObject("WScript.Shell") -Set colUsrEnvVars = objShell.Environment("USER") - -QtPath = "C:\dev6411\install\Qt\bin" - -Path = colUsrEnvVars("OLDPATH") - -If Len(Path) = 0 Then - colUsrEnvVars("OLDPATH") = colUsrEnvVars("PATH") - 'objShell.ExpandEnvironmentStrings("%PATH%") - WScript.Echo colUsrEnvVars("OLDPATH") - Path = colUsrEnvVars("OLDPATH") -End If - -NewPath = (QtPath & ";" & Path) -colUsrEnvVars("PATH") = (NewPath) - -colUsrEnvVars("QTDIR") = "C:\dev6411\install\Qt" - -colUsrEnvVars("ZLIB_LIB_DIR") = "C:\dev6411\install\zlib\lib" -colUsrEnvVars("ZLIB_INC_DIR") = "C:\dev6411\install\zlib\include" \ No newline at end of file diff --git a/build_scripts/windows6412/ctp.bat b/build_scripts/windows6412/ctp.bat deleted file mode 100755 index 91a0c79f2..000000000 --- a/build_scripts/windows6412/ctp.bat +++ /dev/null @@ -1,2 +0,0 @@ -set PATH=c:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2012 CTP\bin;%PATH% -set INCLUDE=c:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2012 CTP\include;%INCLUDE% \ No newline at end of file diff --git a/build_scripts/windows6412/env.bat b/build_scripts/windows6412/env.bat deleted file mode 100755 index 234241d25..000000000 --- a/build_scripts/windows6412/env.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -rem isn't batch awesome, no else statments... -IF [%1]==[] ( - set DIR "." -) -IF NOT [%1]==[] ( -set DIR=%1 -) -IF [%2]==[] ( - set MACHINE X86 -) -IF NOT [%2]==[] ( -set MACHINE=%2 -) - -IF NOT [%INITVS%]==[%MACHINE%] ( - echo "Setting %MACHINE% bit compiler variables" - set INITVS=%MACHINE% - call "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %MACHINE% -) \ No newline at end of file diff --git a/build_scripts/windows6412/launchcmdvs.bat b/build_scripts/windows6412/launchcmdvs.bat deleted file mode 100755 index dcf238c30..000000000 --- a/build_scripts/windows6412/launchcmdvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev\git\caret7_source" x64 -cmd.exe diff --git a/build_scripts/windows6412/launchqtcreatorvs.bat b/build_scripts/windows6412/launchqtcreatorvs.bat deleted file mode 100755 index c74912741..000000000 --- a/build_scripts/windows6412/launchqtcreatorvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env32.bat -call env.bat "c:\dev7\windows32" x64 -qtcreator.exe diff --git a/build_scripts/windows6412/launchvs.bat b/build_scripts/windows6412/launchvs.bat deleted file mode 100755 index b948bf0f8..000000000 --- a/build_scripts/windows6412/launchvs.bat +++ /dev/null @@ -1,3 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" x64 -devenv.exe diff --git a/build_scripts/windows6412/setup_env.bat b/build_scripts/windows6412/setup_env.bat deleted file mode 100755 index 7c2061860..000000000 --- a/build_scripts/windows6412/setup_env.bat +++ /dev/null @@ -1,2 +0,0 @@ -call c7env64.bat -call env.bat "c:\dev7\windows64" AMD64 \ No newline at end of file diff --git a/build_scripts/windows64_debug.bat b/build_scripts/windows64_debug.bat deleted file mode 100755 index c7227d92f..000000000 --- a/build_scripts/windows64_debug.bat +++ /dev/null @@ -1,35 +0,0 @@ -@echo=off -set CMD=c:\Windows\system32\cmd.exe -REM -REM Go to correct directory -REM -set BUILD_DIR=c:\dev7\windows64 -cd %BUILD_DIR% - -REM -REM Go into source directory -REM -cd caret7_source - -echo "Caret7 Windows64 DEBUG Build Result" - -REM -REM Grab the latest Sources -REM -c:\cygwin\bin\git.exe reset --hard HEAD -c:\cygwin\bin\git.exe fetch -c:\cygwin\bin\git.exe reset --hard origin/master - -REM -REM Build caret -REM -cd build_scripts/windows64 -%CMD% /c build_debug.bat -cd .. -cd .. -set DIST_DIR=caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_windows64 - -REM echo "Copying Files" -REM c:\cygwin\bin\scp build/Desktop/workbench.exe %DIST_DIR% -REM c:\cygwin\bin\scp build/CommandLine/wb_command.exe %DIST_DIR% -REM echo "Finished Copying Files" diff --git a/build_scripts/windows64_remote.sh b/build_scripts/windows64_remote.sh deleted file mode 100755 index c3ca8c493..000000000 --- a/build_scripts/windows64_remote.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -ssh -v caret@winbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64.bat' > remote_launch_windows64.txt 2>&1 -cat remote_launch_windows64.txt | mailx -s 'Caret7 Windows 64 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu diff --git a/build_scripts/windows64_remote_debug.sh b/build_scripts/windows64_remote_debug.sh deleted file mode 100755 index 4918be8ab..000000000 --- a/build_scripts/windows64_remote_debug.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -ssh -v caret@winbuild 'c:\dev7\windows64\caret7_source\build_scripts\windows64_debug.bat' > remote_launch_windows64_debug.txt 2>&1 -cat remote_launch_windows64_debug.txt | mailx -s 'Caret7 Windows 64 DEBUG Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu -- GitLab From 4e5843fcf240e94888001d66161d9c3d1920c9bc Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 5 Jan 2017 19:13:23 -0600 Subject: [PATCH 075/755] make volume and metric math copy map names from the first file that they use all the maps from --- src/Operations/OperationMetricMath.cxx | 10 ++++++++-- src/Operations/OperationVolumeMath.cxx | 9 ++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Operations/OperationMetricMath.cxx b/src/Operations/OperationMetricMath.cxx index 0957b9139..6b0aac59d 100644 --- a/src/Operations/OperationMetricMath.cxx +++ b/src/Operations/OperationMetricMath.cxx @@ -91,10 +91,11 @@ void OperationMetricMath::useParameters(OperationParameters* myParams, ProgressO } int numInputs = myVarOpts.size(); int numVars = myVarNames.size(); - vector varMetrics(numVars, (MetricFile*)NULL); + vector varMetrics(numVars, NULL); vector metricColumns(numVars, -1); if (numInputs == 0 && numVars == 0) throw OperationException("you must specify at least one input metric (-var), even if the expression doesn't use a variable"); - int numNodes; + const MetricFile* namefile = NULL; + int numNodes = -1; StructureEnum::Enum myStructure; int numColumns = -1; for (int i = 0; i < numInputs; ++i) @@ -137,6 +138,10 @@ void OperationMetricMath::useParameters(OperationParameters* myParams, ProgressO if (numColumns == -1)//then this is the first one that doesn't use -repeat { numColumns = thisColumns; + if (useColumn == -1) + { + namefile = thisMetric;//if it also doesn't use -column, take map names from it + } } else { if (numColumns != thisColumns) { @@ -182,6 +187,7 @@ void OperationMetricMath::useParameters(OperationParameters* myParams, ProgressO myMetricOut->setStructure(myStructure); for (int j = 0; j < numColumns; ++j) { + if (namefile != NULL) myMetricOut->setMapName(j, namefile->getMapName(j)); for (int v = 0; v < numVars; ++v) { if (metricColumns[v] == -1) diff --git a/src/Operations/OperationVolumeMath.cxx b/src/Operations/OperationVolumeMath.cxx index 21daf49ef..5533a4769 100644 --- a/src/Operations/OperationVolumeMath.cxx +++ b/src/Operations/OperationVolumeMath.cxx @@ -91,10 +91,10 @@ void OperationVolumeMath::useParameters(OperationParameters* myParams, ProgressO } int numInputs = myVarOpts.size(); int numVars = myVarNames.size(); - vector varVolumes(numVars, (VolumeFile*)NULL); + vector varVolumes(numVars, NULL); vector varSubvolumes(numVars, -1); if (numInputs == 0 && numVars == 0) throw OperationException("you must specify at least one input volume (-var), even if the expression doesn't use a variable"); - VolumeFile* first; + VolumeFile* first = NULL, *namefile = NULL; VolumeSpace mySpace; vector outDims; int numSubvols = -1; @@ -143,8 +143,10 @@ void OperationVolumeMath::useParameters(OperationParameters* myParams, ProgressO { numSubvols = thisSubvols; outDims = thisVolume->getOriginalDimensions(); - if (useSubvolume != -1) + if (useSubvolume == -1) { + namefile = thisVolume;//if it also doesn't use -subvolume, take map names from it + } else { outDims.resize(3);//change to output only one subvolume in the simplest way } } else { @@ -192,6 +194,7 @@ void OperationVolumeMath::useParameters(OperationParameters* myParams, ProgressO myVolOut->reinitialize(outDims, first->getSform());//DO NOT take volume type from first volume, because we don't check for or copy label tables, nor do we want to for (int s = 0; s < numSubvols; ++s) { + if (namefile != NULL) myVolOut->setMapName(s, namefile->getMapName(s)); for (int v = 0; v < numVars; ++v) { if (varSubvolumes[v] == -1) -- GitLab From 51368fd40d5d010fbc6b114edacb0be7fb139c7c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 5 Jan 2017 23:21:11 -0600 Subject: [PATCH 076/755] add thin column and partial-volume options to mapping between volume and surface --- .../AlgorithmLabelToVolumeMapping.cxx | 35 +++- .../AlgorithmLabelToVolumeMapping.h | 3 +- .../AlgorithmMetricToVolumeMapping.cxx | 28 ++- .../AlgorithmMetricToVolumeMapping.h | 3 +- .../AlgorithmVolumeLabelToSurfaceMapping.cxx | 186 +++++++++--------- .../AlgorithmVolumeLabelToSurfaceMapping.h | 3 +- .../AlgorithmVolumeToSurfaceMapping.cxx | 13 +- .../AlgorithmVolumeToSurfaceMapping.h | 6 +- src/Files/RibbonMappingHelper.cxx | 53 +++-- src/Files/RibbonMappingHelper.h | 3 +- 10 files changed, 205 insertions(+), 128 deletions(-) diff --git a/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx b/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx index 6310921dd..8c704f642 100644 --- a/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx +++ b/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx @@ -63,12 +63,14 @@ OperationParameters* AlgorithmLabelToVolumeMapping::getParameters() ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* ribbonSubdivOpt = ribbonOpt->createOptionalParameter(3, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdivOpt->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); + ribbonOpt->createOptionalParameter(4, "-greedy", "also put labels in voxels with less than 50% partial volume (legacy behavior)"); + ribbonOpt->createOptionalParameter(5, "-thick-columns", "use overlapping columns (legacy method)"); ret->setHelpText( AString("Maps labels from a gifti label file into a volume file. ") + "You must specify exactly one mapping method option. " + "The -nearest-vertex method uses the label from the vertex closest to the voxel center. " + - "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse, with popularity logic to decide on a label to use. " + "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse, with popularity logic to decide on a label to use." ); return ret; } @@ -101,6 +103,7 @@ void AlgorithmLabelToVolumeMapping::useParameters(OperationParameters* myParams, } SurfaceFile* innerSurf = NULL, *outerSurf = NULL; int subDivs = 3; + bool greedy = false, thick = false; OptionalParameter* ribbonOpt = myParams->getOptionalParameter(6); if (ribbonOpt->m_present) { @@ -121,6 +124,8 @@ void AlgorithmLabelToVolumeMapping::useParameters(OperationParameters* myParams, throw AlgorithmException("invalid number of subdivisions specified"); } } + greedy = ribbonOpt->getOptionalParameter(4)->m_present; + thick = ribbonOpt->getOptionalParameter(5)->m_present; } if (!haveMethod) { @@ -132,7 +137,7 @@ void AlgorithmLabelToVolumeMapping::useParameters(OperationParameters* myParams, AlgorithmLabelToVolumeMapping(myProgObj, myLabel, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, nearDist); break; case RIBBON: - AlgorithmLabelToVolumeMapping(myProgObj, myLabel, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs); + AlgorithmLabelToVolumeMapping(myProgObj, myLabel, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs, greedy, thick); break; case INVALID: CaretAssert(0); @@ -190,7 +195,8 @@ AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myP } AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, - VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs) : AbstractAlgorithm(myProgObj) + VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs, + const bool& greedy, const bool& thickColumn) : AbstractAlgorithm(myProgObj) { int numNodes = mySurf->getNumberOfNodes(); if (myLabel->getNumberOfNodes() != numNodes) @@ -229,10 +235,12 @@ AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myP const int32_t* colData = myLabel->getLabelKeyPointerForColumn(m); for (map > >::const_iterator iter = reverseWeights.begin(); iter != reverseWeights.end(); ++iter) { + double totalWeight = 0.0; map totals; const vector >& vertWeightsRef = iter->second; for (int i = 0; i < (int)vertWeightsRef.size(); ++i) { + totalWeight += vertWeightsRef[i].second; map::iterator iter2 = totals.find(colData[vertWeightsRef[i].first]); if (iter2 == totals.end()) {//because floats don't initialize to 0 @@ -243,12 +251,25 @@ AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myP } float bestWeight = -1.0f; int32_t bestLabel = unlabeledVal; - for (map::iterator iter2 = totals.begin(); iter2 != totals.end(); ++iter2) + bool skipLoop = false; + if (!greedy) { - if (iter2->second > bestWeight) + if (thickColumn) { - bestWeight = iter2->second; - bestLabel = iter2->first; + skipLoop = (totalWeight < 1.5);//slight hack: the thick column method basically counts every triangle three times + } else { + skipLoop = (totalWeight < 0.5); + } + } + if (!skipLoop) + { + for (map::iterator iter2 = totals.begin(); iter2 != totals.end(); ++iter2) + { + if (iter2->second > bestWeight) + { + bestWeight = iter2->second; + bestLabel = iter2->first; + } } } scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = bestLabel; diff --git a/src/Algorithms/AlgorithmLabelToVolumeMapping.h b/src/Algorithms/AlgorithmLabelToVolumeMapping.h index 651a49220..e4770e566 100644 --- a/src/Algorithms/AlgorithmLabelToVolumeMapping.h +++ b/src/Algorithms/AlgorithmLabelToVolumeMapping.h @@ -37,7 +37,8 @@ namespace caret { AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const float& nearDist); AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, - VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs = 3); + VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const int& subDivs = 3, const bool& greedy = false, const bool& thick = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmMetricToVolumeMapping.cxx b/src/Algorithms/AlgorithmMetricToVolumeMapping.cxx index 309739ff8..4edd1925a 100644 --- a/src/Algorithms/AlgorithmMetricToVolumeMapping.cxx +++ b/src/Algorithms/AlgorithmMetricToVolumeMapping.cxx @@ -65,12 +65,15 @@ OperationParameters* AlgorithmMetricToVolumeMapping::getParameters() ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* ribbonSubdivOpt = ribbonOpt->createOptionalParameter(3, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdivOpt->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); + ribbonOpt->createOptionalParameter(4, "-greedy", "instead of antialiasing partial-volumed voxels, put full metric values (legacy behavior)"); + ribbonOpt->createOptionalParameter(5, "-thick-columns", "use overlapping columns (legacy method)"); ret->setHelpText( AString("Maps values from a metric file into a volume file. ") + "You must specify exactly one mapping method option. " + "The -nearest-vertex method uses the value from the vertex closest to the voxel center (useful for integer values). " + - "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse. " + "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse. " + + "Mapping to lower resolutions than the mesh may require a larger -voxel-subdiv value in order to have all of the surface data participate." ); return ret; } @@ -103,6 +106,7 @@ void AlgorithmMetricToVolumeMapping::useParameters(OperationParameters* myParams } SurfaceFile* innerSurf = NULL, *outerSurf = NULL; int subDivs = 3; + bool greedy = false, thick = false; OptionalParameter* ribbonOpt = myParams->getOptionalParameter(6); if (ribbonOpt->m_present) { @@ -123,6 +127,8 @@ void AlgorithmMetricToVolumeMapping::useParameters(OperationParameters* myParams throw AlgorithmException("invalid number of subdivisions specified"); } } + greedy = ribbonOpt->getOptionalParameter(4)->m_present; + thick = ribbonOpt->getOptionalParameter(5)->m_present; } if (!haveMethod) { @@ -134,7 +140,7 @@ void AlgorithmMetricToVolumeMapping::useParameters(OperationParameters* myParams AlgorithmMetricToVolumeMapping(myProgObj, myMetric, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, nearDist); break; case RIBBON: - AlgorithmMetricToVolumeMapping(myProgObj, myMetric, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs); + AlgorithmMetricToVolumeMapping(myProgObj, myMetric, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs, greedy, thick); break; case INVALID: CaretAssert(0); @@ -191,7 +197,8 @@ AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* m } AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, - VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs) : AbstractAlgorithm(myProgObj) + VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs, + const bool& greedy, const bool& thickColumn) : AbstractAlgorithm(myProgObj) { int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) @@ -212,7 +219,7 @@ AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* m int numCols = myMetric->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols); vector > forwardWeights; - RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs); + RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs, !thickColumn); map > > reverseWeights; for (int i = 0; i < numNodes; ++i) { @@ -236,7 +243,18 @@ AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* m accum += colData[iter->second[i].first] * iter->second[i].second; } CaretAssert(totalWeight > 0.0);//ribbon mapping should never add weights of 0 to lists - scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = accum / totalWeight; + if (greedy) + { + scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = accum / totalWeight; + } else { + float denom = 1.0f;//thin weights are intended to be space filling without overlapping + if (thickColumn) denom = 3.0f;//a bit of a hack - ideally, in thick mode every fully covered voxel should have weights sum to 3 + if (totalWeight > denom) + { + denom = totalWeight;//however, the surface contours occasionally occasionally turn the polyhedrons partly inside out, so voxels can sum to more than they theoretically should + } + scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = accum / denom; + } } myVolOut->setFrame(scratchFrame.data(), m); myVolOut->setMapName(m, myMetric->getMapName(m)); diff --git a/src/Algorithms/AlgorithmMetricToVolumeMapping.h b/src/Algorithms/AlgorithmMetricToVolumeMapping.h index d1c909716..35bd3d343 100644 --- a/src/Algorithms/AlgorithmMetricToVolumeMapping.h +++ b/src/Algorithms/AlgorithmMetricToVolumeMapping.h @@ -39,7 +39,8 @@ namespace caret { VolumeFile* myVolOut, const float& nearDist); ///ribbon constrained AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, - VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs = 3); + VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const int& subDivs = 3, const bool& greedy = false, const bool& thick = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); diff --git a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx index bbe644186..4d933bef7 100644 --- a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx @@ -59,12 +59,21 @@ OperationParameters* AlgorithmVolumeLabelToSurfaceMapping::getParameters() roiVol->addVolumeParameter(1, "roi-volume", "the volume file"); OptionalParameter* ribbonSubdiv = ribbonOpt->createOptionalParameter(4, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdiv->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); + ribbonOpt->createOptionalParameter(5, "-thin-columns", "use non-overlapping polyhedra"); OptionalParameter* subvolumeSelect = ret->createOptionalParameter(5, "-subvol-select", "select a single subvolume to map"); subvolumeSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( - AString("Map label volume data to a surface. If -ribbon-constrained is not specified, uses the enclosing voxel method.") + AString("Map label volume data to a surface. If -ribbon-constrained is not specified, uses the enclosing voxel method.") + + "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for a popularity comparison. " + + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + + "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " + "The volume ROI is useful to exclude partial volume effects of voxels the surfaces pass through, and will cause the mapping to ignore " + + "voxels that don't have a positive value in the mask. The subdivision number specifies how it approximates the amount of the volume the polyhedron " + + "intersects, by splitting each voxel into NxNxN pieces, and checking whether the center of each piece is inside the polyhedron. If you have very large " + + "voxels, consider increasing this if you get unexpected unlabeled vertices in your output." ); return ret; } @@ -105,7 +114,8 @@ void AlgorithmVolumeLabelToSurfaceMapping::useParameters(OperationParameters* my throw AlgorithmException("invalid number of subdivisions specified"); } } - AlgorithmVolumeLabelToSurfaceMapping(myProgObj, myVolume, mySurface, myLabelOut, innerSurf, outerSurf, myRoiVol, subdivisions, mySubVol); + bool thinColumns = ribbonOpt->getOptionalParameter(5)->m_present; + AlgorithmVolumeLabelToSurfaceMapping(myProgObj, myVolume, mySurface, myLabelOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, mySubVol); } else { AlgorithmVolumeLabelToSurfaceMapping(myProgObj, myVolume, mySurface, myLabelOut, mySubVol); } @@ -119,6 +129,7 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr { throw AlgorithmException("input volume must be a label volume"); } + if (myVolume->getNumberOfComponents() != 1) throw AlgorithmException("label volumes must not have multiple components per map"); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) @@ -128,9 +139,9 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr int64_t numColumns; if (mySubVol == -1) { - numColumns = myVolDims[3] * myVolDims[4]; + numColumns = myVolDims[3]; } else { - numColumns = myVolDims[4]; + numColumns = 1; } int64_t numNodes = mySurface->getNumberOfNodes(); myLabelOut->setNumberOfNodesAndColumns(numNodes, numColumns); @@ -141,7 +152,7 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr GiftiLabelTable cumulativeTable = *(myVolume->getMapLabelTable(0));//so we don't run into append issues with the "???" label that gets made by GiftiLabelTable's constructor for (int64_t i = 0; i < myVolDims[3]; ++i) { - map frameRemap; + map frameRemap; if (i > 0) { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(i); @@ -151,29 +162,21 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr } frameRemap = cumulativeTable.append(*tempTable); } - for (int64_t j = 0; j < myVolDims[4]; ++j) + AString mapName = myVolume->getMapName(i); + myLabelOut->setColumnName(i, mapName); +#pragma omp CARET_PARFOR + for (int64_t node = 0; node < numNodes; ++node) { - AString mapName = myVolume->getMapName(i); - if (myVolDims[4] != 1) + int32_t tempKey = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, i) + 0.5f); + map::iterator iter = frameRemap.find(tempKey); + if (iter != frameRemap.end()) { - mapName += " component " + AString::number(j); + myArray[node] = iter->second; + } else { + myArray[node] = tempKey;//for simplicity, assume all values in the volume file are in the label table } - int64_t thisCol = i * myVolDims[4] + j; - myLabelOut->setColumnName(thisCol, mapName); -#pragma omp CARET_PARFOR - for (int64_t node = 0; node < numNodes; ++node) - { - int32_t tempKey = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, i, j) + 0.5f); - map::iterator iter = frameRemap.find(tempKey); - if (iter != frameRemap.end()) - { - myArray[node] = iter->second; - } else { - myArray[node] = tempKey;//for simplicity, assume all values in the volume file are in the label table - } - } - myLabelOut->setLabelKeysForColumn(thisCol, myArray.data()); } + myLabelOut->setLabelKeysForColumn(i, myArray.data()); } *(myLabelOut->getLabelTable()) = cumulativeTable; } else { @@ -183,27 +186,19 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr throw AlgorithmException("specified subvolume is missing a label table"); } *(myLabelOut->getLabelTable()) = *tempTable; - for (int64_t j = 0; j < myVolDims[4]; ++j) - { - AString mapName = myVolume->getMapName(mySubVol); - if (myVolDims[4] != 1) - { - mapName += " component " + AString::number(j); - } - int64_t thisCol = j; - myLabelOut->setColumnName(thisCol, mapName); + myLabelOut->setColumnName(0, myVolume->getMapName(mySubVol)); #pragma omp CARET_PARFOR - for (int64_t node = 0; node < numNodes; ++node) - {//for simplicity, assume all values in the volume file are in the label table - myArray[node] = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, mySubVol, j) + 0.5f); - } - myLabelOut->setLabelKeysForColumn(thisCol, myArray.data()); + for (int64_t node = 0; node < numNodes; ++node) + {//for simplicity, assume all values in the volume file are in the label table + myArray[node] = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, mySubVol) + 0.5f); } + myLabelOut->setLabelKeysForColumn(0, myArray.data()); } } AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, - const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* myRoiVol, const int32_t& subdivisions, + const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const VolumeFile* myRoiVol, const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); @@ -211,6 +206,7 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr { throw AlgorithmException("input volume must be a label volume"); } + if (myVolume->getNumberOfComponents() != 1) throw AlgorithmException("label volumes must not have multiple components per map"); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) @@ -220,9 +216,9 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr int64_t numColumns; if (mySubVol == -1) { - numColumns = myVolDims[3] * myVolDims[4]; + numColumns = myVolDims[3]; } else { - numColumns = myVolDims[4]; + numColumns = 1; } int64_t numNodes = mySurface->getNumberOfNodes(); myLabelOut->setNumberOfNodesAndColumns(numNodes, numColumns); @@ -231,14 +227,14 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr vector > myWeights; const float* roiFrame = NULL; if (myRoiVol != NULL) roiFrame = myRoiVol->getFrame(); - RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions); + RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); if (mySubVol == -1) { GiftiLabelTable cumulativeTable = *(myVolume->getMapLabelTable(0));//so we don't run into append issues with the "???" label that gets made by GiftiLabelTable's constructor int32_t unlabeledKey = cumulativeTable.getUnassignedLabelKey();//but, assume the first table has one, because we may need it for (int64_t i = 0; i < myVolDims[3]; ++i) { - map frameRemap; + map frameRemap; if (i > 0) { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(i); @@ -248,76 +244,82 @@ AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(Progr } frameRemap = cumulativeTable.append(*tempTable); } - for (int64_t j = 0; j < myVolDims[4]; ++j) + myLabelOut->setColumnName(i, myVolume->getMapName(i)); +#pragma omp CARET_PARFOR + for (int64_t node = 0; node < numNodes; ++node) { - AString mapName = myVolume->getMapName(i); - if (myVolDims[4] != 1) + const vector& weightRef = myWeights[node]; + map totals; + for (int v = 0; v < (int)weightRef.size(); ++v) { - mapName += " component " + AString::number(j); + int32_t voxKey = (int32_t)floor(myVolume->getValue(weightRef[v].ijk, i) + 0.5f); + map::iterator iter = totals.find(voxKey); + if (iter == totals.end()) + {//floats don't initialize to 0 + totals[voxKey] = weightRef[v].weight; + } else { + totals[voxKey] += weightRef[v].weight; + } } - int64_t thisCol = i * myVolDims[4] + j; - myLabelOut->setColumnName(thisCol, mapName); -#pragma omp CARET_PARFOR - for (int64_t node = 0; node < numNodes; ++node) + int32_t tempKey = unlabeledKey; + float bestSum = -1.0f; + for (map::iterator iter = totals.begin(); iter != totals.end(); ++iter) { - const vector& weightRef = myWeights[node]; - map totals; - for (int v = 0; v < (int)weightRef.size(); ++v) - { - int32_t voxKey = (int32_t)floor(myVolume->getValue(weightRef[v].ijk, i, j) + 0.5f); - map::iterator iter = totals.find(voxKey); - if (iter == totals.end()) - {//floats don't initialize to 0 - totals[voxKey] = weightRef[v].weight; - } else { - totals[voxKey] += weightRef[v].weight; - } - } - int32_t tempKey = unlabeledKey; - float bestSum = -1.0f; - for (map::iterator iter = totals.begin(); iter != totals.end(); ++iter) - { - if (iter->second > bestSum) - { - tempKey = iter->first; - bestSum = iter->second; - } - } - map::iterator iter = frameRemap.find(tempKey); - if (iter != frameRemap.end()) + if (iter->second > bestSum) { - myArray[node] = iter->second; - } else { - myArray[node] = tempKey;//for simplicity, assume all values in the frame are in the label table + tempKey = iter->first; + bestSum = iter->second; } } - myLabelOut->setLabelKeysForColumn(thisCol, myArray.data()); + map::iterator iter = frameRemap.find(tempKey); + if (iter != frameRemap.end()) + { + myArray[node] = iter->second; + } else { + myArray[node] = tempKey;//for simplicity, assume all values in the frame are in the label table + } } + myLabelOut->setLabelKeysForColumn(i, myArray.data()); } *(myLabelOut->getLabelTable()) = cumulativeTable; } else { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(mySubVol); + int unlabeledKey = tempTable->getUnassignedLabelKey(); if (tempTable == NULL) { throw AlgorithmException("specified subvolume is missing a label table"); } *(myLabelOut->getLabelTable()) = *tempTable; - for (int64_t j = 0; j < myVolDims[4]; ++j) - { - AString mapName = myVolume->getMapName(mySubVol); - if (myVolDims[4] != 1) + myLabelOut->setColumnName(0, myVolume->getMapName(mySubVol)); +#pragma omp CARET_PARFOR + for (int64_t node = 0; node < numNodes; ++node) + {//for simplicity, assume all values in the volume file are in the label table + const vector& weightRef = myWeights[node]; + map totals; + for (int v = 0; v < (int)weightRef.size(); ++v) { - mapName += " component " + AString::number(j); + int32_t voxKey = (int32_t)floor(myVolume->getValue(weightRef[v].ijk, mySubVol) + 0.5f); + map::iterator iter = totals.find(voxKey); + if (iter == totals.end()) + {//floats don't initialize to 0 + totals[voxKey] = weightRef[v].weight; + } else { + totals[voxKey] += weightRef[v].weight; + } } - int64_t thisCol = j; - myLabelOut->setColumnName(thisCol, mapName); -#pragma omp CARET_PARFOR - for (int64_t node = 0; node < numNodes; ++node) - {//for simplicity, assume all values in the volume file are in the label table - myArray[node] = 0;//TODO + int32_t tempKey = unlabeledKey; + float bestSum = -1.0f; + for (map::iterator iter = totals.begin(); iter != totals.end(); ++iter) + { + if (iter->second > bestSum) + { + tempKey = iter->first; + bestSum = iter->second; + } } - myLabelOut->setLabelKeysForColumn(thisCol, myArray.data()); + myArray[node] = tempKey;//for simplicity, assume all values in the frame are in the label table } + myLabelOut->setLabelKeysForColumn(0, myArray.data()); } } diff --git a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.h b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.h index 425c5ba8c..17a79a7e7 100644 --- a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.h +++ b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.h @@ -35,7 +35,8 @@ namespace caret { AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, const int64_t& mySubVol = -1); AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, - const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* myRoiVol = NULL, const int32_t& subdivisions = 3, + const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const VolumeFile* myRoiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, const int64_t& mySubVol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx index de9fd9a60..4d945c417 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx @@ -68,6 +68,7 @@ OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() roiVol->addVolumeParameter(1, "roi-volume", "the volume file"); OptionalParameter* ribbonSubdiv = ribbonOpt->createOptionalParameter(4, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdiv->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); + ribbonOpt->createOptionalParameter(7, "-thin-columns", "use non-overlapping polyhedra"); OptionalParameter* ribbonWeights = ribbonOpt->createOptionalParameter(5, "-output-weights", "write the voxel weights for a vertex to a volume file"); ribbonWeights->addIntegerParameter(1, "vertex", "the vertex number to get the voxel weights for, 0-based"); ribbonWeights->addVolumeOutputParameter(2, "weights-out", "volume to write the weights to"); @@ -87,6 +88,8 @@ OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() "linear interpolation based on the voxels immediately on each side of the vertex's position.\n\n" + "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for sampling. " + + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + + "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " "The volume ROI is useful to exclude partial volume effects of voxels the surfaces pass through, and will cause the mapping to ignore " + "voxels that don't have a positive value in the mask. The subdivision number specifies how it approximates the amount of the volume the polyhedron " + "intersects, by splitting each voxel into NxNxN pieces, and checking whether the center of each piece is inside the polyhedron. If you have very large " + @@ -196,6 +199,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam throw AlgorithmException("invalid number of subdivisions specified"); } } + bool thinColumns = ribbonOpt->getOptionalParameter(7); int weightsOutVertex = -1; VolumeFile* weightsOut = NULL; OptionalParameter* ribbonWeights = ribbonOpt->getOptionalParameter(5); @@ -204,7 +208,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam weightsOutVertex = (int)ribbonWeights->getInteger(1); weightsOut = ribbonWeights->getOutputVolume(2); } - AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, mySubVol, weightsOutVertex, weightsOut); + AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, mySubVol, weightsOutVertex, weightsOut); OptionalParameter* ribbonWeightsText = ribbonOpt->getOptionalParameter(6); if (ribbonWeightsText->m_present) {//do this after the algorithm, to let it do the error condition checking @@ -213,7 +217,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam vector > myWeights; const float* roiFrame = NULL; if (myRoiVol != NULL) roiFrame = myRoiVol->getFrame(); - RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions); + RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); for (int i = 0; i < (int)myWeights.size(); ++i) { outFile << i << ", " << myWeights[i].size(); @@ -340,7 +344,8 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* //ribbon mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol, - const int32_t& subdivisions, const int64_t& mySubVol, const int& weightsOutVertex, VolumeFile* weightsOut) : AbstractAlgorithm(myProgObj) + const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, + const int& weightsOutVertex, VolumeFile* weightsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myVolDims; @@ -377,7 +382,7 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* vector > myWeights; const float* roiFrame = NULL; if (roiVol != NULL) roiFrame = roiVol->getFrame(); - RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions); + RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); if (weightsOut != NULL) { weightsOut->setValueAllVoxels(0.0f); diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h index bb4a6c1d8..85eb25109 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h @@ -50,8 +50,10 @@ namespace caret { AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile::InterpType& myMethod, const int64_t& mySubVol = -1); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, - const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol = NULL, const int32_t& subdivisions = 3, - const int64_t& mySubVol = -1, const int& weightsOutVertex = -1, VolumeFile* weightsOut = NULL); + const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const VolumeFile* roiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, + const int64_t& mySubVol = -1, + const int& weightsOutVertex = -1, VolumeFile* weightsOut = NULL); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol = -1); static OperationParameters* getParameters(); diff --git a/src/Files/RibbonMappingHelper.cxx b/src/Files/RibbonMappingHelper.cxx index a01a4c26e..316b4a478 100644 --- a/src/Files/RibbonMappingHelper.cxx +++ b/src/Files/RibbonMappingHelper.cxx @@ -84,18 +84,43 @@ namespace { std::vector m_tris; std::vector m_quads; - PolyInfo(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t node);//surfaces MUST be in node correspondence, otherwise SEVERE strangeness, possible crashes + PolyInfo(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t node, const bool& thinColumn = false);//surfaces MUST be in node correspondence, otherwise SEVERE strangeness, possible crashes PolyInfo() {}; int isInside(const float* xyz);//0 for no, 2 for yes, 1 for if only half the triangulations (between the two triangulations of one of the quad faces) private: - void addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t root, const int32_t node2, const int32_t node3);//adds the tri for each surface, plus the quad + void addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t* myTri, const int rootIndex, const bool& thinColumn);//adds the tri for each surface, plus the quad }; - void PolyInfo::addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t root, const int32_t node2, const int32_t node3) - { - m_tris.push_back(TriInfo(innerSurf->getCoordinate(root), innerSurf->getCoordinate(node2), innerSurf->getCoordinate(node3))); - m_tris.push_back(TriInfo(outerSurf->getCoordinate(root), outerSurf->getCoordinate(node2), outerSurf->getCoordinate(node3))); - m_quads.push_back(QuadInfo(innerSurf->getCoordinate(node2), innerSurf->getCoordinate(node3), outerSurf->getCoordinate(node3), outerSurf->getCoordinate(node2))); + void PolyInfo::addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t* myTri, const int rootIndex, const bool& thinColumn) + {//tries to orient normals consistently with respect to inside/outside, but it doesn't currently matter + int root = myTri[rootIndex], node2 = myTri[(rootIndex + 1) % 3], node3 = myTri[(rootIndex + 2) % 3]; + if (thinColumn) + { + Vector3D innerRoot = innerSurf->getCoordinate(root), inner2 = innerSurf->getCoordinate(node2), inner3 = innerSurf->getCoordinate(node3); + Vector3D outerRoot = outerSurf->getCoordinate(root), outer2 = outerSurf->getCoordinate(node2), outer3 = outerSurf->getCoordinate(node3); + //use an ordering trick of the 3 vertices so that the summing order is always 01, 12, or 20 - doesn't actually matter (at least on x86), but hey + Vector3D innerEdge2 = (innerRoot + inner2) / 2, innerEdge3 = (inner3 + innerRoot) / 2; + Vector3D outerEdge2 = (outerRoot + outer2) / 2, outerEdge3 = (outer3 + outerRoot) / 2; + //for consistency in floating point rounding, we need to generate the sum of the 3 coordinates in the same order regardless of rootIndex + //so, use the original triangle definition and 0, 1, 2 order + //this doesn't matter for edges because there only 2 coordinates are added together + Vector3D innerCenter = (Vector3D(innerSurf->getCoordinate(myTri[0])) + + Vector3D(innerSurf->getCoordinate(myTri[1])) + + Vector3D(innerSurf->getCoordinate(myTri[2]))) / 3; + Vector3D outerCenter = (Vector3D(outerSurf->getCoordinate(myTri[0])) + + Vector3D(outerSurf->getCoordinate(myTri[1])) + + Vector3D(outerSurf->getCoordinate(myTri[2]))) / 3; + m_tris.push_back(TriInfo(innerRoot, innerEdge3, innerCenter)); + m_tris.push_back(TriInfo(innerRoot, innerCenter, innerEdge2)); + m_tris.push_back(TriInfo(outerRoot, outerEdge2, outerCenter)); + m_tris.push_back(TriInfo(outerRoot, outerCenter, outerEdge3)); + m_quads.push_back(QuadInfo(innerEdge2, innerCenter, outerCenter, outerEdge2)); + m_quads.push_back(QuadInfo(innerCenter, innerEdge3, outerEdge3, outerCenter)); + } else { + m_tris.push_back(TriInfo(innerSurf->getCoordinate(root), innerSurf->getCoordinate(node3), innerSurf->getCoordinate(node2))); + m_tris.push_back(TriInfo(outerSurf->getCoordinate(root), outerSurf->getCoordinate(node2), outerSurf->getCoordinate(node3))); + m_quads.push_back(QuadInfo(innerSurf->getCoordinate(node2), innerSurf->getCoordinate(node3), outerSurf->getCoordinate(node3), outerSurf->getCoordinate(node2))); + } } int PolyInfo::isInside(const float* xyz) @@ -117,7 +142,7 @@ namespace return 0; } - PolyInfo::PolyInfo(const caret::SurfaceFile* innerSurf, const caret::SurfaceFile* outerSurf, const int32_t node) + PolyInfo::PolyInfo(const caret::SurfaceFile* innerSurf, const caret::SurfaceFile* outerSurf, const int32_t node, const bool& thinColumn) { CaretPointer myTopoHelp = innerSurf->getTopologyHelper(); int numTiles; @@ -127,13 +152,13 @@ namespace const int32_t* myTri = innerSurf->getTriangle(myTiles[i]); if (myTri[0] == node) { - addTri(innerSurf, outerSurf, myTri[0], myTri[1], myTri[2]); + addTri(innerSurf, outerSurf, myTri, 0, thinColumn); } else { if (myTri[1] == node) { - addTri(innerSurf, outerSurf, myTri[1], myTri[2], myTri[0]); + addTri(innerSurf, outerSurf, myTri, 1, thinColumn); } else { - addTri(innerSurf, outerSurf, myTri[2], myTri[0], myTri[1]); + addTri(innerSurf, outerSurf, myTri, 2, thinColumn); } } } @@ -213,7 +238,7 @@ namespace } float computeVoxelFraction(const VolumeSpace& myVolSpace, const int64_t* ijk, PolyInfo& myPoly, const int divisions, - const Vector3D& ivec, const Vector3D& jvec, const Vector3D& kvec) + const Vector3D& ivec, const Vector3D& jvec, const Vector3D& kvec) { Vector3D myLowCorner; myVolSpace.indexToSpace(ijk[0] - 0.5f, ijk[1] - 0.5f, ijk[2] - 0.5f, myLowCorner); @@ -241,7 +266,7 @@ namespace } void RibbonMappingHelper::computeWeightsRibbon(vector >& myWeightsOut, const VolumeSpace& myVolSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, - const float* roiFrame, const int& numDivisions) + const float* roiFrame, const int& numDivisions, const bool& thinColumn) { if (!innerSurf->hasNodeCorrespondence(*outerSurf)) { @@ -269,7 +294,7 @@ void RibbonMappingHelper::computeWeightsRibbon(vector >& myW myWeightsOut[node].reserve(maxVoxelCount); float tempf; int64_t node3 = node * 3; - PolyInfo myPoly(innerSurf, outerSurf, node);//build the polygon + PolyInfo myPoly(innerSurf, outerSurf, node, thinColumn);//build the polygon Vector3D minIndex, maxIndex, tempvec; myVolSpace.spaceToIndex(innerCoords + node3, minIndex);//find the bounding box in VOLUME INDEX SPACE, starting with the center nodes maxIndex = minIndex; diff --git a/src/Files/RibbonMappingHelper.h b/src/Files/RibbonMappingHelper.h index c69288db7..5ca5fd247 100644 --- a/src/Files/RibbonMappingHelper.h +++ b/src/Files/RibbonMappingHelper.h @@ -50,7 +50,8 @@ namespace caret public: ///compute per-vertex ribbon mapping weights - surfaces must have vertex correspondence, or an exception is thrown static void computeWeightsRibbon(std::vector >& myWeightsOut, const VolumeSpace& myVolSpace, - const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame = NULL, const int& numDivisions = 3); + const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const float* roiFrame = NULL, const int& numDivisions = 3, const bool& thinColumn = false); }; } -- GitLab From 8971462efb3afdfc91cba382263fb76b8592e17f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 6 Jan 2017 11:51:36 -0600 Subject: [PATCH 077/755] After upgrade to Qt5, when capturing an image with Render Pixmap, borders were drawn with the wrong color. The problem was unrelated to scene capture and only occurred when borders were drawn using a 'standard color'. The problem was traced to an unitialized alpha value when obtaining the RGBA color components for a standard caret color. --- src/Annotations/Annotation.cxx | 4 +- src/Annotations/AnnotationColorBar.cxx | 2 +- src/Annotations/AnnotationText.cxx | 2 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 4 +- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 2 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 2 +- src/Brain/SurfaceNodeColoring.cxx | 2 +- src/Common/CaretColorEnum.cxx | 38 ++++++++++--------- src/Common/CaretColorEnum.h | 8 ++-- src/Files/NodeAndVoxelColoring.cxx | 4 +- src/GuiQt/AnnotationColorWidget.cxx | 4 +- src/GuiQt/AnnotationFontWidget.cxx | 2 +- src/GuiQt/CaretColorEnumMenu.cxx | 2 +- src/GuiQt/WuQtUtilities.cxx | 2 +- 14 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 4d03e9aea..5191ed201 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -808,7 +808,7 @@ Annotation::getLineColorRGBA(float rgbaOut[4]) const case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: - CaretColorEnum::toRGBFloat(m_colorLine, + CaretColorEnum::toRGBAFloat(m_colorLine, rgbaOut); rgbaOut[3] = 1.0; break; @@ -894,7 +894,7 @@ Annotation::getBackgroundColorRGBA(float rgbaOut[4]) const case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: - CaretColorEnum::toRGBFloat(m_colorBackground, + CaretColorEnum::toRGBAFloat(m_colorBackground, rgbaOut); rgbaOut[3] = 1.0; break; diff --git a/src/Annotations/AnnotationColorBar.cxx b/src/Annotations/AnnotationColorBar.cxx index 2a9244f7f..34384c63b 100644 --- a/src/Annotations/AnnotationColorBar.cxx +++ b/src/Annotations/AnnotationColorBar.cxx @@ -295,7 +295,7 @@ AnnotationColorBar::getTextColorRGBA(float rgbaOut[4]) const case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: - CaretColorEnum::toRGBFloat(m_colorText, + CaretColorEnum::toRGBAFloat(m_colorText, rgbaOut); rgbaOut[3] = 1.0; break; diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index aa5cbaead..fbb4dec35 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -541,7 +541,7 @@ AnnotationText::getTextColorRGBA(float rgbaOut[4]) const case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: - CaretColorEnum::toRGBFloat(m_colorText, + CaretColorEnum::toRGBAFloat(m_colorText, rgbaOut); rgbaOut[3] = 1.0; break; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 577ae83dd..e9ddf6add 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -3040,7 +3040,7 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, this->windowTabIndex); float caretColorRGBA[4]; - CaretColorEnum::toRGBFloat(caretColor, caretColorRGBA); + CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); const bool isPasteOntoSurface = fociDisplayProperties->isPasteOntoSurface(displayGroup, this->windowTabIndex); @@ -3266,7 +3266,7 @@ BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) const CaretColorEnum::Enum caretColor = borderDisplayProperties->getStandardColorType(displayGroup, this->windowTabIndex); float caretColorRGBA[4]; - CaretColorEnum::toRGBFloat(caretColor, caretColorRGBA); + CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); const bool isContralateralEnabled = borderDisplayProperties->isContralateralDisplayed(displayGroup, this->windowTabIndex); const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index ab74c319f..3b14aa207 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -2858,7 +2858,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceFoci(const Plane& plane) const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); float caretColorRGBA[4]; - CaretColorEnum::toRGBFloat(caretColor, caretColorRGBA); + CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); bool drawAsSpheres = false; switch (fociDisplayProperties->getDrawingType(displayGroup, diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 7d4918422..030079125 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3690,7 +3690,7 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceFoci(const Plane& plane) const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); float caretColorRGBA[4]; - CaretColorEnum::toRGBFloat(caretColor, caretColorRGBA); + CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); if (fociDisplayProperties->isDisplayed(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { diff --git a/src/Brain/SurfaceNodeColoring.cxx b/src/Brain/SurfaceNodeColoring.cxx index 1996f510e..8ee163372 100644 --- a/src/Brain/SurfaceNodeColoring.cxx +++ b/src/Brain/SurfaceNodeColoring.cxx @@ -689,7 +689,7 @@ SurfaceNodeColoring::assignLabelTableColors(const GiftiLabelTable* labelTable, float outlineRGBA[4]; - CaretColorEnum::toRGBFloat(outlineColor, outlineRGBA); + CaretColorEnum::toRGBAFloat(outlineColor, outlineRGBA); outlineRGBA[3] = 1.0; /* diff --git a/src/Common/CaretColorEnum.cxx b/src/Common/CaretColorEnum.cxx index ace88b77e..e28a0de1d 100644 --- a/src/Common/CaretColorEnum.cxx +++ b/src/Common/CaretColorEnum.cxx @@ -321,41 +321,43 @@ CaretColorEnum::toRGB(Enum enumValue) } /** - * Get the RGB components (ranging zero to one) of the enumerated type. + * Get the RGBA components (ranging zero to one) of the enumerated type. * @param enumValue * Enumerated value. - * @param rgbOut - * Output with RGB components [0.0, 1.0] + * @param rgbaOut + * Output with RGB components [0.0, 1.0] and Alpha=1.0 */ void -CaretColorEnum::toRGBFloat(Enum enumValue, - float rgbOut[3]) +CaretColorEnum::toRGBAFloat(Enum enumValue, + float rgbaOut[4]) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); - rgbOut[0] = enumInstance->rgb[0]; - rgbOut[1] = enumInstance->rgb[1]; - rgbOut[2] = enumInstance->rgb[2]; + rgbaOut[0] = enumInstance->rgb[0]; + rgbaOut[1] = enumInstance->rgb[1]; + rgbaOut[2] = enumInstance->rgb[2]; + rgbaOut[3] = 1.0; } /** - * Get the RGB components (ranging zero to one) of the enumerated type. + * Get the RGBA components (ranging zero to one) of the enumerated type. * @param enumValue * Enumerated value. - * @param rgbOut - * Output with RGB components [0.0, 1.0] + * @param rgbaOut + * Output with RGB components [0, 255] and Alpha=255 */ void -CaretColorEnum::toRGBByte(Enum enumValue, - uint8_t rgbOut[3]) +CaretColorEnum::toRGBAByte(Enum enumValue, + uint8_t rgbaOut[4]) { - float rgbFloat[3]; - toRGBFloat(enumValue, rgbFloat); + float rgbaFloat[3]; + toRGBAFloat(enumValue, rgbaFloat); - rgbOut[0] = static_cast(rgbFloat[0] * 255.0); - rgbOut[1] = static_cast(rgbFloat[1] * 255.0); - rgbOut[2] = static_cast(rgbFloat[2] * 255.0); + rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); + rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); + rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); + rgbaOut[3] = 255; } diff --git a/src/Common/CaretColorEnum.h b/src/Common/CaretColorEnum.h index c814de5f0..d001ffb01 100644 --- a/src/Common/CaretColorEnum.h +++ b/src/Common/CaretColorEnum.h @@ -106,11 +106,11 @@ public: static const float* toRGB(Enum enumValue); - static void toRGBFloat(Enum enumValue, - float rgbOut[3]); + static void toRGBAFloat(Enum enumValue, + float rgbaOut[4]); - static void toRGBByte(Enum enumValue, - uint8_t rgbOut[3]); + static void toRGBAByte(Enum enumValue, + uint8_t rgbaOut[4]); private: CaretColorEnum(const Enum enumValue, diff --git a/src/Files/NodeAndVoxelColoring.cxx b/src/Files/NodeAndVoxelColoring.cxx index 510f17ff9..5318bccf9 100644 --- a/src/Files/NodeAndVoxelColoring.cxx +++ b/src/Files/NodeAndVoxelColoring.cxx @@ -874,8 +874,8 @@ NodeAndVoxelColoring::convertSliceColoringToOutlineMode(uint8_t* rgbaInOut, } uint8_t outlineRGBA[4]; - CaretColorEnum::toRGBByte(labelOutlineColor, - outlineRGBA); + CaretColorEnum::toRGBAByte(labelOutlineColor, + outlineRGBA); outlineRGBA[3] = 255; /* diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index c9a926151..80f2b8b02 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -311,7 +311,7 @@ AnnotationColorWidget::updateBackgroundColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; - CaretColorEnum::toRGBFloat(colorEnum, rgba); + CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; const int32_t numAnnotations = static_cast(m_annotations.size()); @@ -390,7 +390,7 @@ AnnotationColorWidget::updateLineColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; - CaretColorEnum::toRGBFloat(colorEnum, rgba); + CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; const int32_t numAnnotations = static_cast(m_annotations.size()); diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index d12454407..ff65131e9 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -484,7 +484,7 @@ AnnotationFontWidget::updateTextColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; - CaretColorEnum::toRGBFloat(colorEnum, rgba); + CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; bool colorButtonValidFlag = false; diff --git a/src/GuiQt/CaretColorEnumMenu.cxx b/src/GuiQt/CaretColorEnumMenu.cxx index 947ccd93b..b43648714 100644 --- a/src/GuiQt/CaretColorEnumMenu.cxx +++ b/src/GuiQt/CaretColorEnumMenu.cxx @@ -88,7 +88,7 @@ CaretColorEnumMenu::initializeCaretColorEnumMenu(const int64_t caretColorOptions * Create an icon with the color. */ float rgba[4]; - CaretColorEnum::toRGBFloat(colorEnum, rgba); + CaretColorEnum::toRGBAFloat(colorEnum, rgba); if (colorEnum == CaretColorEnum::NONE) { rgba[3] = 0.0; } diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 41f0023c3..f6c3a95cf 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1261,7 +1261,7 @@ WuQtUtilities::createCaretColorEnumPixmap(const QWidget* widget, case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: - CaretColorEnum::toRGBFloat(caretColor, + CaretColorEnum::toRGBAFloat(caretColor, colorRGBA); colorRGBA[3] = 1.0; validColorFlag = true; -- GitLab From 3eda87cf2b14a38d68e7555e58e77dff877fa1cc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 6 Jan 2017 14:41:42 -0600 Subject: [PATCH 078/755] Fixed missing outline around QToolButtons (on Mac) for Border and Foci Edit/Create dialogs. --- src/GuiQt/BorderPropertiesEditorDialog.cxx | 3 +++ src/GuiQt/FociPropertiesEditorDialog.cxx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/GuiQt/BorderPropertiesEditorDialog.cxx b/src/GuiQt/BorderPropertiesEditorDialog.cxx index 7f7ccd211..ad510d106 100644 --- a/src/GuiQt/BorderPropertiesEditorDialog.cxx +++ b/src/GuiQt/BorderPropertiesEditorDialog.cxx @@ -172,6 +172,7 @@ BorderPropertiesEditorDialog::BorderPropertiesEditorDialog(const QString& title, SLOT(newBorderFileButtonClicked())); QToolButton* newFileToolButton = new QToolButton(); newFileToolButton->setDefaultAction(newFileAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(newFileToolButton); /* * Completer for name @@ -192,6 +193,7 @@ BorderPropertiesEditorDialog::BorderPropertiesEditorDialog(const QString& title, SLOT(displayNameEditor())); QToolButton* displayNameColorEditorToolButton = new QToolButton(); displayNameColorEditorToolButton->setDefaultAction(displayNameColorEditorAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(displayNameColorEditorToolButton); /* * Class @@ -209,6 +211,7 @@ BorderPropertiesEditorDialog::BorderPropertiesEditorDialog(const QString& title, SLOT(displayClassEditor())); QToolButton* displayClassEditorToolButton = new QToolButton(); displayClassEditorToolButton->setDefaultAction(displayClassEditorAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(displayClassEditorToolButton); /* * Closed diff --git a/src/GuiQt/FociPropertiesEditorDialog.cxx b/src/GuiQt/FociPropertiesEditorDialog.cxx index 4a4534434..bb9f7cb3a 100644 --- a/src/GuiQt/FociPropertiesEditorDialog.cxx +++ b/src/GuiQt/FociPropertiesEditorDialog.cxx @@ -203,6 +203,7 @@ FociPropertiesEditorDialog::FociPropertiesEditorDialog(const QString& title, SLOT(newFociFileButtonClicked())); QToolButton* newFileToolButton = new QToolButton(); newFileToolButton->setDefaultAction(newFileAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(newFileToolButton); /* * Completer for name @@ -223,6 +224,7 @@ FociPropertiesEditorDialog::FociPropertiesEditorDialog(const QString& title, SLOT(displayNameEditor())); QToolButton* displayNameColorEditorToolButton = new QToolButton(); displayNameColorEditorToolButton->setDefaultAction(displayNameColorEditorAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(displayNameColorEditorToolButton); /* * Class @@ -240,6 +242,7 @@ FociPropertiesEditorDialog::FociPropertiesEditorDialog(const QString& title, SLOT(displayClassEditor())); QToolButton* displayClassEditorToolButton = new QToolButton(); displayClassEditorToolButton->setDefaultAction(displayClassEditorAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(displayClassEditorToolButton); /* * Coordinates -- GitLab From f593504285830d32bbea52254dc94b2d26d205e5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 26 Jan 2017 10:05:02 -0600 Subject: [PATCH 079/755] Resolve WB-655: Default Threshold Range to "File" on Overlay/Map Settings Editor -> Palette Tab. --- .../MapSettingsPaletteColorMappingWidget.cxx | 4 ++-- src/GuiQt/WuQDoubleSlider.cxx | 21 ++++++++++++++++++- src/GuiQt/WuQDoubleSlider.h | 4 ++++ src/Palette/PaletteColorMapping.cxx | 3 ++- src/Palette/PaletteColorMappingSaxReader.cxx | 11 +++++++++- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 53281bb58..2b07e2f99 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -703,8 +703,8 @@ MapSettingsPaletteColorMappingWidget::createThresholdSection() this->thresholdAdjustmentWidgetGroup->add(this->thresholdLinkCheckBox); this->thresholdAdjustmentWidgetGroup->add(thresholdLowLabel); this->thresholdAdjustmentWidgetGroup->add(thresholdHighLabel); - this->thresholdAdjustmentWidgetGroup->add(this->thresholdLowSlider); - this->thresholdAdjustmentWidgetGroup->add(this->thresholdHighSlider); + this->thresholdAdjustmentWidgetGroup->add(this->thresholdLowSlider->getWidget()); + this->thresholdAdjustmentWidgetGroup->add(this->thresholdHighSlider->getWidget()); this->thresholdAdjustmentWidgetGroup->add(this->thresholdLowSpinBox); this->thresholdAdjustmentWidgetGroup->add(this->thresholdHighSpinBox); this->thresholdAdjustmentWidgetGroup->add(this->thresholdShowInsideRadioButton); diff --git a/src/GuiQt/WuQDoubleSlider.cxx b/src/GuiQt/WuQDoubleSlider.cxx index 58111a1d1..43f9adff9 100644 --- a/src/GuiQt/WuQDoubleSlider.cxx +++ b/src/GuiQt/WuQDoubleSlider.cxx @@ -114,6 +114,25 @@ WuQDoubleSlider::setRange(double minValue, double maxValue) this->updateSlider(); } +/** + * @return The minimum value of the slider. + */ +double +WuQDoubleSlider::minimumValue() const +{ + return this->minimum;; +} + +/** + * @return The maximum value of the slider. + */ +double +WuQDoubleSlider::maximumValue() const +{ + return this->maximum;; +} + + /** * @return The value of the slider. */ @@ -158,7 +177,7 @@ WuQDoubleSlider::updateSlider() const double parametricValue = (this->sliderValue - this->minimum) / dRange; const int dSlider = this->slider->maximum() - this->slider->minimum(); - const int qSliderValue = static_cast(dSlider * parametricValue) + this->minimum; + const int qSliderValue = static_cast(dSlider * parametricValue);;// + this->minimum; this->slider->blockSignals(true); this->slider->setValue(qSliderValue); this->slider->blockSignals(false); diff --git a/src/GuiQt/WuQDoubleSlider.h b/src/GuiQt/WuQDoubleSlider.h index 1ceffccfb..a4fb0ec6e 100644 --- a/src/GuiQt/WuQDoubleSlider.h +++ b/src/GuiQt/WuQDoubleSlider.h @@ -41,6 +41,10 @@ namespace caret { void setRange(double minValue, double maxValue); + double minimumValue() const; + + double maximumValue() const; + double value() const; signals: diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index c96ce04cc..6f103ea0f 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -222,7 +222,8 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->thresholdMappedAverageAreaMaximum = 1.0f; this->thresholdDataName = ""; this->thresholdShowFailureInGreen = false; - this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP; + //this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP; + this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; this->numericFormatMode = NumericFormatModeEnum::AUTO; this->precisionDigits = 2; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index ded2e4b1b..3369f6db7 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -289,7 +289,16 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, this->paletteColorMapping->setThresholdNegMinPosMaxLinked(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING) { - /* Top level tag, nothing to do */ + /* WB- + * We want to default the range mode to 'FILE'. While we do that in the constructor + * for PaletteColorMapping, most files contain PaletteColorMapping in the XML for + * each map and when the file is read, the default values are replaced. So, + * to avoid breaking older scenes, only change the range mode from 'MAP' to 'FILE' + * if thresholding is off when reading palette color mapping from XML. + */ + if (this->paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { + this->paletteColorMapping->setThresholdRangeMode(PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE); + } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE) { bool isValid = false; -- GitLab From b7e4ede4e36e36a171fd76febf227c17c4f86f73 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 31 Jan 2017 22:04:33 -0600 Subject: [PATCH 080/755] fix some help text, remove instruction comment --- .../AlgorithmCiftiLabelProbability.h | 34 ------------------- src/Algorithms/AlgorithmSurfaceDistortion.cxx | 2 +- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/src/Algorithms/AlgorithmCiftiLabelProbability.h b/src/Algorithms/AlgorithmCiftiLabelProbability.h index a9d6fc5a4..6e47c1bb0 100644 --- a/src/Algorithms/AlgorithmCiftiLabelProbability.h +++ b/src/Algorithms/AlgorithmCiftiLabelProbability.h @@ -21,40 +21,6 @@ */ /*LICENSE_END*/ -/* -file->save as... and enter what you will name the class, plus .h - -find and replace these strings in plain text mode (not "whole word only"): - -AlgorithmCiftiLabelProbability : algorithm name, in CamelCase, with initial capital, same as what you saved the header file to -ALGORITHM_CIFTI_LABEL_PROBABILITY : uppercase of algorithm name, with underscore between words, used in #ifdef guards - -next, make AlgorithmCiftiLabelProbability.cxx from AlgorithmTemplate.cxx.txt via one of the following (depending on working directory): - -cat AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > AlgorithmCiftiLabelProbability.cxx -cat Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > Algorithms/AlgorithmCiftiLabelProbability.cxx -cat src/Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmCiftiLabelProbability/g' > src/Algorithms/AlgorithmCiftiLabelProbability.cxx - -or manually copy and replace - -next, implement its functions - the algorithm work goes in the CONSTRUCTOR - -add these into Algorithms/CMakeLists.txt: - -AlgorithmCiftiLabelProbability.h -AlgorithmCiftiLabelProbability.cxx - -place the following lines into Commands/CommandOperationManager.cxx: - -#include "AlgorithmCiftiLabelProbability.h" - //near the top - - this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelProbability())); - //in CommandOperationManager() - -finally, remove this block comment -*/ - #include "AbstractAlgorithm.h" namespace caret { diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.cxx b/src/Algorithms/AlgorithmSurfaceDistortion.cxx index fef69f19f..9dd5620a4 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.cxx +++ b/src/Algorithms/AlgorithmSurfaceDistortion.cxx @@ -64,7 +64,7 @@ OperationParameters* AlgorithmSurfaceDistortion::getParameters() ret->createOptionalParameter(7, "-strain-method", "calculate distortion by the local affines between triangles"); ret->setHelpText( - AString("This command, when not using -caret5-method or -edge-method, is equivalent to using -surface-vertex-areas on each surface, ") + + AString("This command, when not using -caret5-method, -edge-method, or -strain-method, is equivalent to using -surface-vertex-areas on each surface, ") + "smoothing both output metrics with the GEO_GAUSS_EQUAL method on the surface they came from if -smooth is specified, and then using the formula " + "'ln(distorted/reference)/ln(2)' on the smoothed results.\n\n" + "When using -caret5-method, it uses the surface distortion method from caret5, which takes the base 2 log of the ratio of tile areas, " + -- GitLab From 469b4abb0ae207b45d11fd32bb658787ae7a2a47 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 31 Jan 2017 23:06:24 -0600 Subject: [PATCH 081/755] check for truncated uncompressed nifti files (cifti) --- src/Common/CaretBinaryFile.cxx | 8 ++++++++ src/Common/CaretBinaryFile.h | 2 ++ src/Nifti/NiftiIO.cxx | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/Common/CaretBinaryFile.cxx b/src/Common/CaretBinaryFile.cxx index 85a73ad8a..d97b1fa82 100644 --- a/src/Common/CaretBinaryFile.cxx +++ b/src/Common/CaretBinaryFile.cxx @@ -52,6 +52,7 @@ namespace caret void close(); void seek(const int64_t& position); int64_t pos(); + int64_t size() { return -1; } void read(void* dataOut, const int64_t& count, int64_t* numRead); void write(const void* dataIn, const int64_t& count); ~ZFileImpl(); @@ -69,6 +70,7 @@ namespace caret void close(); void seek(const int64_t& position); int64_t pos(); + int64_t size() { return m_file.size(); } void read(void* dataOut, const int64_t& count, int64_t* numRead); void write(const void* dataIn, const int64_t& count); }; @@ -147,6 +149,12 @@ int64_t CaretBinaryFile::pos() return m_impl->pos(); } +int64_t CaretBinaryFile::size() +{ + if (m_curMode == NONE) throw DataFileException("file is not open, can't report size"); + return m_impl->size(); +} + void CaretBinaryFile::write(const void* dataIn, const int64_t& count) { CaretAssert(count >= 0);//not sure about allowing 0 diff --git a/src/Common/CaretBinaryFile.h b/src/Common/CaretBinaryFile.h index b2396f33d..db774dd6c 100644 --- a/src/Common/CaretBinaryFile.h +++ b/src/Common/CaretBinaryFile.h @@ -55,6 +55,7 @@ namespace caret { int64_t pos(); void read(void* dataOut, const int64_t& count, int64_t* numRead = NULL);//throw if numRead is NULL and (error or end of file reached early) void write(const void* dataIn, const int64_t& count);//failure to complete write is always an exception + int64_t size();//may return -1 if size cannot be determined efficiently class ImplInterface { protected: @@ -65,6 +66,7 @@ namespace caret { const QString& getFilename() const { return m_fileName; } virtual void seek(const int64_t& position) = 0; virtual int64_t pos() = 0; + virtual int64_t size() = 0; virtual void read(void* dataOut, const int64_t& count, int64_t* numRead) = 0; virtual void write(const void* dataIn, const int64_t& count) = 0; virtual ~ImplInterface(); diff --git a/src/Nifti/NiftiIO.cxx b/src/Nifti/NiftiIO.cxx index edf496b7b..267d763d4 100644 --- a/src/Nifti/NiftiIO.cxx +++ b/src/Nifti/NiftiIO.cxx @@ -34,6 +34,16 @@ void NiftiIO::openRead(const QString& filename) throw DataFileException("file uses the binary datatype, which is unsupported: " + filename); } m_dims = m_header.getDimensions(); + int64_t filesize = m_file.size();//returns -1 if it can't efficiently determine size + int64_t elemCount = getNumComponents(); + for (int i = 0; i < (int)m_dims.size(); ++i) + { + elemCount *= m_dims[i]; + } + if (filesize >= 0 && filesize < m_header.getDataOffset() + numBytesPerElem() * elemCount) + { + throw DataFileException("nifti file is truncated: " + filename); + } } void NiftiIO::writeNew(const QString& filename, const NiftiHeader& header, const int& version, const bool& withRead, const bool& swapEndian) -- GitLab From 16b12cd7e02892a3ab671e71b039a2414a66439e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 6 Feb 2017 22:44:55 -0600 Subject: [PATCH 082/755] add ability to set writing datatype and scaling range to cifti --- src/Cifti/CiftiFile.cxx | 38 +++++++++-- src/Cifti/CiftiFile.h | 14 +++- src/Nifti/NiftiHeader.cxx | 138 +++++++++++++++++++++++++++++++++++++- src/Nifti/NiftiHeader.h | 2 + src/Nifti/NiftiIO.cxx | 28 +------- src/Nifti/NiftiIO.h | 25 +++++-- 6 files changed, 206 insertions(+), 39 deletions(-) diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index 3474b78a1..a316b8bde 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -42,7 +42,8 @@ namespace CiftiXML m_xml;//because we need to parse it to set up the dimensions anyway public: CiftiOnDiskImpl(const QString& filename);//read-only - CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian);//make new empty file with read/write + CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian, + const int16_t& datatype, const bool& rescale, const double& minval, const double& maxval);//make new empty file with read/write void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead) const; void getColumn(float* dataOut, const int64_t& index) const; const CiftiXML& getCiftiXML() const { return m_xml; } @@ -108,6 +109,7 @@ CiftiFile::WriteImplInterface::~WriteImplInterface() CiftiFile::CiftiFile(const QString& fileName) { m_endianPref = NATIVE; + setWritingDataTypeNoScaling();//default argument is float32 openFile(fileName); } @@ -157,6 +159,24 @@ void CiftiFile::setWritingFile(const QString& fileName, const CiftiVersion& writ m_endianPref = endian; } +void CiftiFile::setWritingDataTypeNoScaling(const int16_t& type) +{ + m_writingDataType = type;//could do some validation here + m_doWriteScaling = false; + m_minScalingVal = -1.0; + m_maxScalingVal = 1.0; + m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing +} + +void CiftiFile::setWritingDataTypeAndScaling(const int16_t& type, const double& minval, const double& maxval) +{ + m_writingDataType = type;//could do some validation here + m_doWriteScaling = true; + m_minScalingVal = minval; + m_maxScalingVal = maxval; + m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing +} + void CiftiFile::writeFile(const QString& fileName, const CiftiVersion& writingVersion, const ENDIAN& endian) { if (m_readingImpl == NULL || m_dims.empty()) throw DataFileException("writeFile called on uninitialized CiftiFile"); @@ -174,7 +194,8 @@ void CiftiFile::writeFile(const QString& fileName, const CiftiVersion& writingVe m_readingImpl = tempMemory;//we are about to make the old reading impl very unhappy, replace it so that if we get an error while writing, we hang onto the memory version m_writingImpl.grabNew(NULL);//and make it re-magic the writing implementation again if data is set } - CaretPointer tempWrite(new CiftiOnDiskImpl(myInfo.getAbsoluteFilePath(), m_xml, writingVersion, writeSwapped)); + CaretPointer tempWrite(new CiftiOnDiskImpl(myInfo.getAbsoluteFilePath(), m_xml, writingVersion, writeSwapped, + m_writingDataType, m_doWriteScaling, m_minScalingVal, m_maxScalingVal)); copyImplData(m_readingImpl, tempWrite, m_dims); if (collision)//if we rewrote the file, we need the handle to the new file, and to dump the temporary in-memory version { @@ -352,7 +373,8 @@ void CiftiFile::verifyWriteImpl() } } } - m_writingImpl.grabNew(new CiftiOnDiskImpl(m_writingFile, m_xml, m_onDiskVersion, shouldSwap(m_endianPref)));//this constructor makes new file for writing + m_writingImpl.grabNew(new CiftiOnDiskImpl(m_writingFile, m_xml, m_onDiskVersion, shouldSwap(m_endianPref), + m_writingDataType, m_doWriteScaling, m_minScalingVal, m_maxScalingVal));//this constructor makes new file for writing if (m_readingImpl != NULL) { copyImplData(m_readingImpl, m_writingImpl, m_dims); @@ -570,11 +592,17 @@ namespace } } -CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian) +CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian, + const int16_t& datatype, const bool& rescale, const double& minval, const double& maxval) {//starts writing new file warnForBadExtension(filename, xml); NiftiHeader outHeader; - outHeader.setDataType(NIFTI_TYPE_FLOAT32);//actually redundant currently, default is float32 + if (rescale) + { + outHeader.setDataTypeAndScaleRange(datatype, minval, maxval); + } else { + outHeader.setDataType(datatype); + } char intentName[16]; int32_t intentCode = xml.getIntentInfo(version, intentName); outHeader.setIntent(intentCode, intentName); diff --git a/src/Cifti/CiftiFile.h b/src/Cifti/CiftiFile.h index 3afe3f472..194cea333 100644 --- a/src/Cifti/CiftiFile.h +++ b/src/Cifti/CiftiFile.h @@ -26,6 +26,7 @@ #include "CiftiXML.h" #include "CiftiXMLOld.h" #include "MultiDimIterator.h" +#include "nifti1.h" #include @@ -45,7 +46,11 @@ namespace caret BIG }; - CiftiFile() { m_endianPref = NATIVE; } + CiftiFile() + { + m_endianPref = NATIVE; + setWritingDataTypeNoScaling();//default argument is float32 + } explicit CiftiFile(const QString &fileName);//calls openFile void openFile(const QString& fileName);//starts on-disk reading void openURL(const QString& url, const QString& user, const QString& pass);//open from XNAT @@ -69,6 +74,10 @@ namespace caret void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index);//for 2D only, will be slow if on disk! + ///data type and scaling options - should be set before setRow, etc, to avoid rewriting of file + void setWritingDataTypeNoScaling(const int16_t& type = NIFTI_TYPE_FLOAT32); + void setWritingDataTypeAndScaling(const int16_t& type, const double& minval, const double& maxval); + void getRow(float* dataOut, const int64_t& index, const bool& tolerateShortRead) const;//backwards compatibility for old CiftiFile/CiftiInterface void getRow(float* dataOut, const int64_t& index) const; int64_t getNumberOfRows() const; @@ -100,6 +109,9 @@ namespace caret //CiftiXML m_xml;//uncomment when we drop CiftiInterface CiftiVersion m_onDiskVersion; ENDIAN m_endianPref; + bool m_doWriteScaling; + int16_t m_writingDataType; + double m_minScalingVal, m_maxScalingVal; void verifyWriteImpl(); static void copyImplData(const ReadImplInterface* from, WriteImplInterface* to, const std::vector& dims); diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index f1ef7633a..11cb780bc 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -30,6 +30,7 @@ #include #include #include +#include "stdint.h" using namespace std; using namespace caret; @@ -474,6 +475,141 @@ void NiftiHeader::setDataScaling(const double& mult, const double& offset) m_header.scl_inter = offset; } +namespace +{ + template + struct Scaling + { + double mult, offset; + Scaling(const double& minval, const double& maxval) + { + std::numeric_limits mylimits; + double mymin = mylimits.min(); + if (!mylimits.is_integer) mymin = -mylimits.max();//again, c++11 can use lowest() instead of these lines + mult = (maxval - minval) / ((double)mylimits.max() - mymin);//multiplying is the first step of decoding (after byteswap), so start with the range + offset = minval - mymin * mult;//offset is added after multiplying the encoded value by mult + } + }; +} + +void NiftiHeader::setDataTypeAndScaleRange(const int16_t& type, const double& minval, const double& maxval) +{ + setDataType(type); + switch (type) + { + case NIFTI_TYPE_RGB24: + clearDataScaling();//RGB ignores scaling fields + break; + case DT_BINARY://currently not supported in read/write functions anyway + setDataScaling(maxval - minval, minval);//make the two possible decoded values equal to the min and max + break; + case NIFTI_TYPE_INT8: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_UINT8: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_INT16: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_UINT16: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_INT32: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_UINT32: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_INT64: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_UINT64: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_FLOAT32: + case NIFTI_TYPE_COMPLEX64: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_FLOAT64: + case NIFTI_TYPE_COMPLEX128: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + case NIFTI_TYPE_FLOAT128: + case NIFTI_TYPE_COMPLEX256: + { + Scaling myscale(minval, maxval); + setDataScaling(myscale.mult, myscale.offset); + break; + } + default: + CaretAssert(0); + throw CaretException("internal error, report what you did to the developers"); + } +} + +int NiftiHeader::getNumComponents() const +{ + switch (getDataType()) + { + case NIFTI_TYPE_RGB24: + return 3; + break; + case NIFTI_TYPE_COMPLEX64: + case NIFTI_TYPE_COMPLEX128: + case NIFTI_TYPE_COMPLEX256: + return 2; + break; + case DT_BINARY: + case NIFTI_TYPE_INT8: + case NIFTI_TYPE_UINT8: + case NIFTI_TYPE_INT16: + case NIFTI_TYPE_UINT16: + case NIFTI_TYPE_INT32: + case NIFTI_TYPE_UINT32: + case NIFTI_TYPE_FLOAT32: + case NIFTI_TYPE_INT64: + case NIFTI_TYPE_UINT64: + case NIFTI_TYPE_FLOAT64: + case NIFTI_TYPE_FLOAT128: + return 1; + break; + default: + CaretAssert(0); + throw CaretException("internal error, report what you did to the developers"); + } +} + void NiftiHeader::read(CaretBinaryFile& inFile) { nifti_1_header buffer1; @@ -658,7 +794,7 @@ int NiftiHeader::typeToNumBits(const int64_t& type) return 256; break; default: - throw DataFileException("incorrect datatype code"); + throw DataFileException("incorrect nifti datatype code"); } } diff --git a/src/Nifti/NiftiHeader.h b/src/Nifti/NiftiHeader.h index 228bdec18..874139ac1 100644 --- a/src/Nifti/NiftiHeader.h +++ b/src/Nifti/NiftiHeader.h @@ -60,6 +60,7 @@ namespace caret int32_t getIntentCode() const { return m_header.intent_code; } const char* getIntentName() const { return m_header.intent_name; }//NOTE: 16 BYTES, MAY NOT HAVE A NULL TERMINATOR bool getDataScaling(double& mult, double& offset) const;//returns false if scaling not needed + int getNumComponents() const; QString toString() const; void setDimensions(const std::vector& dimsIn); @@ -68,6 +69,7 @@ namespace caret void setDataType(const int16_t& type); void clearDataScaling(); void setDataScaling(const double& mult, const double& offset); + void setDataTypeAndScaleRange(const int16_t& type, const double& minval, const double& maxval); ///get the FSL "scale" space std::vector > getFSLSpace() const; diff --git a/src/Nifti/NiftiIO.cxx b/src/Nifti/NiftiIO.cxx index 267d763d4..0d422f755 100644 --- a/src/Nifti/NiftiIO.cxx +++ b/src/Nifti/NiftiIO.cxx @@ -71,33 +71,7 @@ void NiftiIO::close() int NiftiIO::getNumComponents() const { - switch (m_header.getDataType()) - { - case NIFTI_TYPE_RGB24: - return 3; - break; - case NIFTI_TYPE_COMPLEX64: - case NIFTI_TYPE_COMPLEX128: - case NIFTI_TYPE_COMPLEX256: - return 2; - break; - case NIFTI_TYPE_INT8: - case NIFTI_TYPE_UINT8: - case NIFTI_TYPE_INT16: - case NIFTI_TYPE_UINT16: - case NIFTI_TYPE_INT32: - case NIFTI_TYPE_UINT32: - case NIFTI_TYPE_FLOAT32: - case NIFTI_TYPE_INT64: - case NIFTI_TYPE_UINT64: - case NIFTI_TYPE_FLOAT64: - case NIFTI_TYPE_FLOAT128: - return 1; - break; - default: - CaretAssert(0); - throw DataFileException("internal error, report what you did to the developers"); - } + return m_header.getNumComponents(); } int NiftiIO::numBytesPerElem() diff --git a/src/Nifti/NiftiIO.h b/src/Nifti/NiftiIO.h index cca7ddacf..3392bf949 100644 --- a/src/Nifti/NiftiIO.h +++ b/src/Nifti/NiftiIO.h @@ -49,6 +49,8 @@ namespace caret void convertRead(TO* out, FROM* in, const int64_t& count);//for reading from file template void convertWrite(TO* out, const FROM* in, const int64_t& count);//for writing to file + template + static TO clamp(const FROM& in);//deal with integer cast being undefined when converting from outside range public: void openRead(const QString& filename); void writeNew(const QString& filename, const NiftiHeader& header, const int& version = 1, const bool& withRead = false, const bool& swapEndian = false); @@ -223,12 +225,12 @@ namespace caret { for (int64_t i = 0; i < count; ++i) { - out[i] = (TO)floor(0.5 + offset + mult * (long double)in[i]);//we don't always need that much precision, but it will still be faster than hard drives + out[i] = clamp(floor(0.5l + offset + mult * (long double)in[i]));//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { - out[i] = (TO)floor(0.5 + in[i]); + out[i] = clamp(floor(0.5 + in[i])); } } } else { @@ -253,17 +255,17 @@ namespace caret double mult, offset; bool doScale = m_header.getDataScaling(mult, offset); if (std::numeric_limits::is_integer)//do round to nearest when integer output type - { + {//TODO: what about NaN? if (doScale) { for (int64_t i = 0; i < count; ++i) { - out[i] = (TO)floor(0.5 + ((long double)in[i] - offset) / mult);//we don't always need that much precision, but it will still be faster than hard drives + out[i] = clamp(floor(0.5l + ((long double)in[i] - offset) / mult));//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { - out[i] = (TO)floor(0.5 + in[i]); + out[i] = clamp(floor(0.5 + in[i])); } } } else { @@ -283,6 +285,19 @@ namespace caret if (m_header.isSwapped()) ByteSwapping::swapArray(out, count); } + template + TO NiftiIO::clamp(const FROM& in) + { + std::numeric_limits mylimits; + if (mylimits.max() < in) return mylimits.max(); + if (mylimits.is_integer)//c++11 can use lowest() instead of this mess + { + if (mylimits.min() > in) return mylimits.min(); + } else { + if (-mylimits.max() > in) return -mylimits.max(); + } + return (TO)in; + } } #endif //__NIFTI_IO_H__ -- GitLab From 7a5b22bcbf1d8f2f7c61ad0251f87834892c27c2 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 6 Feb 2017 23:05:03 -0600 Subject: [PATCH 083/755] fix incorrect behavior of label to volume with thin, ungreedy setting --- src/Algorithms/AlgorithmLabelToVolumeMapping.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx b/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx index 8c704f642..e3f7aa348 100644 --- a/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx +++ b/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx @@ -217,7 +217,7 @@ AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myP int numCols = myLabel->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols, 1, SubvolumeAttributes::LABEL); vector > forwardWeights; - RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs); + RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs, !thickColumn); map > > reverseWeights; for (int i = 0; i < numNodes; ++i) { -- GitLab From e08400cf791061a9917b9cfff3ae4522dc6c57f0 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 9 Feb 2017 23:06:44 -0600 Subject: [PATCH 084/755] add global option to control datatype and scaling of cifti, move global options to another help page --- build_scripts/commandhtml.sh | 20 ++-- src/Cifti/CiftiFile.cxx | 4 + src/Commands/CommandOperation.cxx | 8 ++ src/Commands/CommandOperation.h | 6 + src/Commands/CommandOperationManager.cxx | 139 +++++++++++++++++++---- src/Commands/CommandOperationManager.h | 2 + src/Commands/CommandParser.cxx | 26 +++++ src/Commands/CommandParser.h | 9 +- src/Nifti/NiftiHeader.cxx | 6 + 9 files changed, 189 insertions(+), 31 deletions(-) diff --git a/build_scripts/commandhtml.sh b/build_scripts/commandhtml.sh index 1680b1aeb..2eb5c0f18 100755 --- a/build_scripts/commandhtml.sh +++ b/build_scripts/commandhtml.sh @@ -39,6 +39,10 @@ echo -n "$initialText" | head -n $((infoLine + 1)) >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -arguments-help >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" +#-global-options +echo -n '' >> "$outDir/$startPage" +echo "$initialText" | grep -- -global-options >> "$outDir/$startPage" +echo -n '' >> "$outDir/$startPage" #-cifti-help echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -cifti-help >> "$outDir/$startPage" @@ -64,16 +68,20 @@ echo -n '' >> "$outDir/$startPage" #remainder of help info allCommandsLine=`echo "$initialText" | grep -n -- -all-commands-help | cut -f1 -d:` echo "$initialText" | tail -n +$((allCommandsLine+2)) >> "$outDir/$startPage" -#end page +#end main page echo '' >> "$outDir/$startPage" echo '' >> "$outDir/$startPage" #-arguments-help page make_basic_command_page "-arguments-help" +#-arguments-help page +make_basic_command_page "-global-options" #-cifti-help page make_basic_command_page "-cifti-help" #-cifti-help page make_basic_command_page "-gifti-help" +#-all-commands-help page +make_basic_command_page "-all-commands-help" #-list-commands page, and its subpages outPage="$outDir/`command_to_page_name -list-commands`" @@ -90,6 +98,9 @@ do make_basic_command_page "$thisCommand" echo ''"${lines[$i]}"'' >> "$outPage" done +#end -list-commands page +echo '' >> "$outPage" +echo '' >> "$outPage" #-list-deprecated-commands page, and its subpages outPage="$outDir/`command_to_page_name -list-deprecated-commands`" @@ -106,11 +117,6 @@ do make_basic_command_page "$thisCommand" echo ''"${lines[$i]}"'' >> "$outPage" done - -#end main page +#end -list-deprecated-commands page echo '' >> "$outPage" echo '' >> "$outPage" - -#-all-commands-help page -make_basic_command_page "-all-commands-help" - diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index a316b8bde..56f736038 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -603,6 +603,10 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, c } else { outHeader.setDataType(datatype); } + if (outHeader.getNumComponents() != 1) + { + throw DataFileException("cifti cannot be written with multi-component nifti datatypes (i.e., complex, RGB)"); + } char intentName[16]; int32_t intentCode = xml.getIntentInfo(version, intentName); outHeader.setIntent(intentCode, intentName); diff --git a/src/Commands/CommandOperation.cxx b/src/Commands/CommandOperation.cxx index 081883e04..548c966de 100644 --- a/src/Commands/CommandOperation.cxx +++ b/src/Commands/CommandOperation.cxx @@ -73,6 +73,14 @@ void CommandOperation::disableProvenance() { } +void CommandOperation::setCiftiOutputDTypeAndScale(const int16_t&, const double&, const double&) +{ +} + +void CommandOperation::setCiftiOutputDTypeNoScale(const int16_t&) +{ +} + AString CommandOperation::doCompletion(ProgramParameters&, const bool&) { return ""; diff --git a/src/Commands/CommandOperation.h b/src/Commands/CommandOperation.h index ce8c8d953..0d54ef435 100644 --- a/src/Commands/CommandOperation.h +++ b/src/Commands/CommandOperation.h @@ -27,6 +27,8 @@ #include "ProgramParametersException.h" #include "AString.h" +#include "nifti1.h" + namespace caret { class ProgramParameters; @@ -39,6 +41,10 @@ namespace caret { void execute(ProgramParameters& parameters, const bool& preventProvenance); + virtual void setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal); + + virtual void setCiftiOutputDTypeNoScale(const int16_t& dtype); + virtual AString doCompletion(ProgramParameters& parameters, const bool& useExtGlob); protected: diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index d92b22eb4..24e0b6818 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -243,6 +243,7 @@ #include "StructureEnum.h" #include +#include using namespace caret; using namespace std; @@ -513,6 +514,32 @@ CommandOperationManager::~CommandOperationManager() this->deprecatedOperations.clear(); } +namespace +{ + //quick hack to convert type argument to internal integer + int16_t stringToCiftiType(const AString& input) + { + map nameToCode; + nameToCode["INT8"] = NIFTI_TYPE_INT8; + nameToCode["UINT8"] = NIFTI_TYPE_UINT8; + nameToCode["INT16"] = NIFTI_TYPE_INT16; + nameToCode["UINT16"] = NIFTI_TYPE_UINT16; + nameToCode["INT32"] = NIFTI_TYPE_INT32; + nameToCode["UINT32"] = NIFTI_TYPE_UINT32; + nameToCode["INT64"] = NIFTI_TYPE_INT64; + nameToCode["UINT64"] = NIFTI_TYPE_UINT64; + nameToCode["FLOAT32"] = NIFTI_TYPE_FLOAT32; + nameToCode["FLOAT64"] = NIFTI_TYPE_FLOAT64; + nameToCode["FLOAT128"] = NIFTI_TYPE_FLOAT128; + map::iterator iter = nameToCode.find(input); + if (iter == nameToCode.end()) + { + throw CommandException("Unrecognized cifti datatype: '" + input + "'"); + } + return iter->second; + } +} + /** * Run a command. * @@ -544,6 +571,22 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) CaretLogWarning("SIMD type '" + DotSIMDEnum::toName(impl) + "' not supported (could be cpu, compiler, or build options), using '" + DotSIMDEnum::toName(retval) + "'"); } } + int16_t ciftiDType = NIFTI_TYPE_FLOAT32; + bool ciftiScale = false; + double ciftiMin = -1.0, ciftiMax = -1.0; + if (getGlobalOption(parameters, "-cifti-output-datatype", 1, globalOptionArgs)) + { + ciftiDType = stringToCiftiType(globalOptionArgs[0]); + } + if (getGlobalOption(parameters, "-cifti-output-range", 2, globalOptionArgs)) + { + ciftiScale = true; + bool valid = false; + ciftiMin = globalOptionArgs[0].toDouble(&valid); + if (!valid) throw CommandException("non-numeric option to -cifti-output-range: '" + globalOptionArgs[0] + "'"); + ciftiMax = globalOptionArgs[1].toDouble(&valid); + if (!valid) throw CommandException("non-numeric option to -cifti-output-range: '" + globalOptionArgs[1] + "'"); + } const uint64_t numberOfCommands = this->commandOperations.size(); const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); @@ -561,6 +604,8 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) printHelpInfo(); } else if (commandSwitch == "-arguments-help") { printArgumentsHelp("wb_command"); + } else if (commandSwitch == "-global-options") { + printGlobalOptions(); } else if (commandSwitch == "-cifti-help") { printCiftiHelp("wb_command"); } else if (commandSwitch == "-gifti-help") { @@ -609,6 +654,12 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) { cout << operation->getHelpInformation("wb_command") << endl; } else { + if (ciftiScale) + { + operation->setCiftiOutputDTypeAndScale(ciftiDType, ciftiMin, ciftiMax); + } else { + operation->setCiftiOutputDTypeNoScale(ciftiDType); + } operation->execute(parameters, preventProvenance); } } @@ -645,7 +696,17 @@ AString CommandOperationManager::doCompletion(ProgramParameters& parameters, con } return ret; } - ret = "wordlist -disable-provenance\\ -logging\\ -simd";//we could prevent suggesting an already-provided global option, but that would be a bit surprising + OptionInfo ciftiDTypeInfo = parseGlobalOption(parameters, "-cifti-output-datatype", 1, globalOptionArgs, true); + if (ciftiDTypeInfo.specified && !ciftiDTypeInfo.complete) + { + return "wordlist INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 FLOAT32 FLOAT64 FLOAT128"; + } + OptionInfo ciftiRangeInfo = parseGlobalOption(parameters, "-cifti-output-range", 2, globalOptionArgs, true); + if (ciftiRangeInfo.specified && !ciftiRangeInfo.complete) + {//can't tab complete a literal number + return ""; + } + ret = "wordlist -disable-provenance\\ -logging\\ -simd\\ -cifti-output-datatype\\ -cifti-output-range";//we could prevent suggesting an already-provided global option, but that would be a bit surprising const uint64_t numberOfCommands = this->commandOperations.size(); const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); if (!parameters.hasNext()) @@ -897,6 +958,7 @@ void CommandOperationManager::printHelpInfo() cout << endl << "Information options:" << endl; cout << " -help show this help info" << endl; cout << " -arguments-help explain the format of subcommand help info" << endl; + cout << " -global-options display options that can be added to any command" << endl; cout << " -cifti-help explain the cifti file format and related terms" << endl; cout << " -gifti-help explain the gifti file format (metric, surface)" << endl; cout << " -version show extended version information" << endl; @@ -904,27 +966,6 @@ void CommandOperationManager::printHelpInfo() cout << " -list-deprecated-commands list deprecated subcommands" << endl; cout << " -all-commands-help show all processing subcommands and their help" << endl; cout << " info - VERY LONG" << endl; - cout << endl << "Global options (can be added to any command):" << endl; - cout << " -disable-provenance don't generate provenance info in output files" << endl; - cout << " -logging set the logging level, valid values are:" << endl; - vector logLevels; - LogLevelEnum::getAllEnums(logLevels); - for (vector::iterator iter = logLevels.begin(); - iter != logLevels.end(); - iter++) { - cout << " " << LogLevelEnum::toName(*iter) << endl; - } - cout << endl;//add a line after the logging types for readability - //guide for wrap, assuming 80 columns: | - cout << " -simd set the SIMD implementation to use (currently" << endl; - cout << " used only for correlation, default AUTO which" << endl; - cout << " selects fastest supported), valid values are:" << endl; - vector simdTypes = DotSIMDEnum::getAllEnums(); - for (vector::iterator iter = simdTypes.begin(); - iter != simdTypes.end(); - iter++) { - cout << " " << DotSIMDEnum::toName(*iter) << endl; - } cout << endl; cout << "To get the help information of a processing subcommand, run it without any" << endl; cout << " additional arguments." << endl; @@ -995,6 +1036,60 @@ void CommandOperationManager::printArgumentsHelp(const AString& programName) cout << endl; } +void CommandOperationManager::printGlobalOptions() +{ + cout << "Global options (can be added to any command):" << endl; + cout << endl; + //guide for wrap, assuming 80 columns: | + cout << " -disable-provenance don't generate provenance info in output" << endl; + cout << " files" << endl; + cout << endl; + cout << " -cifti-output-datatype write cifti output with the given" << endl; + cout << " datatype (default FLOAT32), note that" << endl; + cout << " numeric precision is only float32," << endl; + cout << " valid values are:" << endl; + cout << " INT8" << endl; + cout << " UINT8" << endl; + cout << " INT16" << endl; + cout << " UINT16" << endl; + cout << " INT32" << endl; + cout << " UINT32" << endl; + cout << " INT64" << endl; + cout << " UINT64" << endl; + cout << " FLOAT32" << endl; + cout << " FLOAT64" << endl; + cout << " FLOAT128" << endl; + cout << endl; + //guide for wrap, assuming 80 columns: | + cout << " -cifti-output-range write cifti output with scaling and offset" << endl; + cout << " header fields such that and " << endl; + cout << " are the most extreme values that can be" << endl; + cout << " represented, mostly useful with integer" << endl; + cout << " output datatypes (see above)" << endl; + cout << endl; + cout << " -logging set the logging level, valid values are:" << endl; + vector logLevels; + LogLevelEnum::getAllEnums(logLevels); + for (vector::iterator iter = logLevels.begin(); + iter != logLevels.end(); + iter++) { + cout << " " << LogLevelEnum::toName(*iter) << endl; + } + cout << endl;//add a line after the logging types for readability + //guide for wrap, assuming 80 columns: | + cout << " -simd set the SIMD implementation to use" << endl; + cout << " (currently used only for correlation," << endl; + cout << " default AUTO which selects fastest" << endl; + cout << " supported), valid values are:" << endl; + vector simdTypes = DotSIMDEnum::getAllEnums(); + for (vector::iterator iter = simdTypes.begin(); + iter != simdTypes.end(); + iter++) { + cout << " " << DotSIMDEnum::toName(*iter) << endl; + } + cout << endl; +} + void CommandOperationManager::printCiftiHelp(const AString& /*programName*/) { //guide for wrap, assuming 80 columns: | diff --git a/src/Commands/CommandOperationManager.h b/src/Commands/CommandOperationManager.h index d6588294a..d89ff78ea 100644 --- a/src/Commands/CommandOperationManager.h +++ b/src/Commands/CommandOperationManager.h @@ -67,6 +67,8 @@ namespace caret { void printArgumentsHelp(const AString& programName); + void printGlobalOptions(); + void printCiftiHelp(const AString& programName); void printGiftiHelp(const AString& programName); diff --git a/src/Commands/CommandParser.cxx b/src/Commands/CommandParser.cxx index 2ebc24cc5..f1135ad2b 100644 --- a/src/Commands/CommandParser.cxx +++ b/src/Commands/CommandParser.cxx @@ -55,6 +55,10 @@ CommandParser::CommandParser(AutoOperationInterface* myAutoOper) : OperationParserInterface(myAutoOper) { m_doProvenance = true; + m_ciftiScale = false; + m_ciftiDType = NIFTI_TYPE_FLOAT32; + m_ciftiMax = -1.0;//these values won't get used, but don't leave them uninitialized + m_ciftiMin = -1.0; } void CommandParser::disableProvenance() @@ -62,6 +66,22 @@ void CommandParser::disableProvenance() m_doProvenance = false; } +void CommandParser::setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal) +{ + m_ciftiDType = dtype; + m_ciftiMin = minVal; + m_ciftiMax = maxVal; + m_ciftiScale = true; +} + +void CommandParser::setCiftiOutputDTypeNoScale(const int16_t& dtype) +{ + m_ciftiDType = dtype; + m_ciftiMax = -1.0;//for sanity, don't keep any previous value around + m_ciftiMin = -1.0; + m_ciftiScale = false; +} + void CommandParser::executeOperation(ProgramParameters& parameters) { CaretPointer myAlgParams(m_autoOper->getParameters());//could be an autopointer, but this is safer @@ -946,6 +966,12 @@ void CommandParser::makeOnDiskOutputs(const vector& outAssociation) myCiftiParam->m_parameter.grabNew(new CiftiFile()); myCiftiParam->m_parameter->setWritingFile(outAssociation[i].m_fileName); } + if (m_ciftiScale) + { + myCiftiParam->m_parameter->setWritingDataTypeAndScaling(m_ciftiDType, m_ciftiMin, m_ciftiMax); + } else { + myCiftiParam->m_parameter->setWritingDataTypeNoScaling(m_ciftiDType); + } break; } default: diff --git a/src/Commands/CommandParser.h b/src/Commands/CommandParser.h index 0a46d7d63..9924a9c54 100644 --- a/src/Commands/CommandParser.h +++ b/src/Commands/CommandParser.h @@ -27,6 +27,7 @@ #include "ProgramParameters.h" #include "CommandException.h" #include "ProgramParametersException.h" + #include #include @@ -36,7 +37,9 @@ namespace caret { { int m_minIndent, m_maxIndent, m_indentIncrement, m_maxWidth; AString m_provenance, m_parentProvenance, m_workingDir; - bool m_doProvenance; + bool m_doProvenance, m_ciftiScale; + double m_ciftiMin, m_ciftiMax; + int16_t m_ciftiDType; const static AString PROVENANCE_NAME, PARENT_PROVENANCE_NAME, PROGRAM_PROVENANCE_NAME, CWD_PROVENANCE_NAME;//TODO: put this elsewhere? std::map m_inputCiftiNames; struct OutputAssoc @@ -55,7 +58,7 @@ namespace caret { void parseRemainingOptions(ParameterComponent* myAlgParams, ProgramParameters& parameters, std::vector& outAssociation, bool debug); void provenanceBeforeOperation(const std::vector& outAssociation); void provenanceAfterOperation(const std::vector& outAssociation); - void makeOnDiskOutputs(const std::vector& outAssociation);//ensures on-disk inputs aren't used as on-disk outputs, converting outputs to in-memory when needed + void makeOnDiskOutputs(const std::vector& outAssociation);//ensures on-disk inputs aren't used as on-disk outputs, keeping outputs in-memory when needed void writeOutput(const std::vector& outAssociation); AString getIndentString(int desired); void addHelpComponent(AString& info, ParameterComponent* myComponent, int curIndent); @@ -71,6 +74,8 @@ namespace caret { public: CommandParser(AutoOperationInterface* myAutoOper); void disableProvenance(); + void setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal); + void setCiftiOutputDTypeNoScale(const int16_t& dtype); void executeOperation(ProgramParameters& parameters); void showParsedOperation(ProgramParameters& parameters); AString doCompletion(ProgramParameters& parameters, const bool& useExtGlob); diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index 11cb780bc..90db97cea 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -869,6 +869,12 @@ void NiftiHeader::swapHeaderBytes(nifti_2_header& header) void NiftiHeader::write(CaretBinaryFile& outFile, const int& version, const bool& swapEndian) { if (!canWriteVersion(version)) throw DataFileException("unable to write NIfTI version " + QString::number(version) + " for file " + outFile.getFilename()); + double junk1, junk2; + int16_t datatype = getDataType(); + if (getDataScaling(junk1, junk2) && ((datatype & 0x70) > 0 || datatype >= 1536)) + {//that hacky expression is to detect 16, 32, 64, 1536, 1792, and 2048 + CaretLogWarning("writing nifti file with scaling factor and floating point datatype"); + } const char padding[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int64_t voxOffset; if (version == 2) -- GitLab From d44638ebd1218ffda03e108859c20ba9ea2d2878 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 10 Feb 2017 15:05:55 -0600 Subject: [PATCH 085/755] fix readme compilation instructions --- README | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README b/README index 4cc78409f..7984b23b5 100644 --- a/README +++ b/README @@ -8,11 +8,13 @@ It is compiled using cmake, on linux do: mkdir build cd build -cmake ../workbench/src -D CMAKE_BUILD_TYPE=Release +cmake -D CMAKE_BUILD_TYPE=Release ../workbench/src make For other OSes, see http://www.cmake.org/cmake/help/runningcmake.html +Also note the -j flag of "make" (like "make -j4") can be used to speed up the build by compiling multiple source files at the same time. + This produces 3 executables, 2 of which are useful to the end user (Desktop/wb_view, CommandLine/wb_command), and one for running internal tests (Tests/test_driver). To run the (few) tests available: -- GitLab From ff4b2e3ef6edd0d47ca511ba9cbaacd0797c428e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 13 Feb 2017 16:04:22 -0600 Subject: [PATCH 086/755] clarify cifti output datatype help info --- src/Commands/CommandOperationManager.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 24e0b6818..688ab90a7 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -1046,7 +1046,7 @@ void CommandOperationManager::printGlobalOptions() cout << endl; cout << " -cifti-output-datatype write cifti output with the given" << endl; cout << " datatype (default FLOAT32), note that" << endl; - cout << " numeric precision is only float32," << endl; + cout << " calculation precision is only float32," << endl; cout << " valid values are:" << endl; cout << " INT8" << endl; cout << " UINT8" << endl; -- GitLab From a6e75f5eb601f25240d71df848018a8a0c9111d9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 16 Feb 2017 15:20:22 -0600 Subject: [PATCH 087/755] Resolve WB-659: Palette color mapping is incorrect with interpolation and 'none' color. When interpolating colors and the data values was less than the 'none' color and above the next color, interpolation was using the 'none' color which produced incorect coloring as it used the RGB values assigned to the none color. Logic has been corrected, in this case to apply no coloring in this situation. Palettes affected are PSYCH, ROY-BIG, clear_brain, fidl, raich4_clrmid, raich6_clrmid, HSB8_clrmid, and POS_NEG. By the way the problem was noticed when using the PSYCH palette and shades of blue were seen for positive values. --- src/Palette/Palette.cxx | 74 +++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/Palette/Palette.cxx b/src/Palette/Palette.cxx index 37fa2b951..c1da33796 100644 --- a/src/Palette/Palette.cxx +++ b/src/Palette/Palette.cxx @@ -462,32 +462,62 @@ Palette::getPaletteColor( } if (paletteIndex >= 0) { const PaletteScalarAndColor* psac = this->getScalarAndColor(paletteIndex); - psac->getColor(rgbaOut); - if (interpolateColorFlag && - (paletteIndex < (numScalarColors - 1))) { - const PaletteScalarAndColor* psacBelow = this->getScalarAndColor(paletteIndex + 1); - float totalDiff = psac->getScalar() - psacBelow->getScalar(); - if (totalDiff != 0.0) { - float offset = scalar - psacBelow->getScalar(); - float percentAbove = offset / totalDiff; - float percentBelow = 1.0f - percentAbove; - if ( ! psacBelow->isNoneColor()) { - const float* rgbaAbove = psac->getColor(); - const float* rgbaBelow = psacBelow->getColor(); - - rgbaOut[0] = (percentAbove * rgbaAbove[0] - + percentBelow * rgbaBelow[0]); - rgbaOut[1] = (percentAbove * rgbaAbove[1] - + percentBelow * rgbaBelow[1]); - rgbaOut[2] = (percentAbove * rgbaAbove[2] - + percentBelow * rgbaBelow[2]); + if (psac->isNoneColor()) { + rgbaOut[3] = 0.0; + } + else { + psac->getColor(rgbaOut); // color assigned here + if (interpolateColorFlag && + (paletteIndex < (numScalarColors - 1))) { + const PaletteScalarAndColor* psacBelow = this->getScalarAndColor(paletteIndex + 1); + float totalDiff = psac->getScalar() - psacBelow->getScalar(); + if (totalDiff != 0.0) { + float offset = scalar - psacBelow->getScalar(); + float percentAbove = offset / totalDiff; + float percentBelow = 1.0f - percentAbove; + if ( ! psacBelow->isNoneColor()) { + const float* rgbaAbove = psac->getColor(); + const float* rgbaBelow = psacBelow->getColor(); + + rgbaOut[0] = (percentAbove * rgbaAbove[0] + + percentBelow * rgbaBelow[0]); + rgbaOut[1] = (percentAbove * rgbaAbove[1] + + percentBelow * rgbaBelow[1]); + rgbaOut[2] = (percentAbove * rgbaAbove[2] + + percentBelow * rgbaBelow[2]); + } } } } - else if (psac->isNoneColor()) { - rgbaOut[3] = 0.0f; - } } +// if (paletteIndex >= 0) { +// const PaletteScalarAndColor* psac = this->getScalarAndColor(paletteIndex); +// psac->getColor(rgbaOut); +// if (interpolateColorFlag && +// (paletteIndex < (numScalarColors - 1))) { +// const PaletteScalarAndColor* psacBelow = this->getScalarAndColor(paletteIndex + 1); +// float totalDiff = psac->getScalar() - psacBelow->getScalar(); +// if (totalDiff != 0.0) { +// float offset = scalar - psacBelow->getScalar(); +// float percentAbove = offset / totalDiff; +// float percentBelow = 1.0f - percentAbove; +// if ( ! psacBelow->isNoneColor()) { +// const float* rgbaAbove = psac->getColor(); +// const float* rgbaBelow = psacBelow->getColor(); +// +// rgbaOut[0] = (percentAbove * rgbaAbove[0] +// + percentBelow * rgbaBelow[0]); +// rgbaOut[1] = (percentAbove * rgbaAbove[1] +// + percentBelow * rgbaBelow[1]); +// rgbaOut[2] = (percentAbove * rgbaAbove[2] +// + percentBelow * rgbaBelow[2]); +// } +// } +// } +// else if (psac->isNoneColor()) { +// rgbaOut[3] = 0.0f; +// } +// } } } -- GitLab From 953ad76e61898080fa6cf0c1a9fc89cde36eac5a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 16 Feb 2017 16:19:49 -0600 Subject: [PATCH 088/755] Removed code that was commented out of Palette.cxx earlier today. --- src/Palette/Palette.cxx | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/src/Palette/Palette.cxx b/src/Palette/Palette.cxx index c1da33796..5b725a4c8 100644 --- a/src/Palette/Palette.cxx +++ b/src/Palette/Palette.cxx @@ -446,18 +446,6 @@ Palette::getPaletteColor( } } } - - // if (paletteIndex != binaryPaletteIndex) { - // std::cout << "FAILED palette indices correct=" - // << paletteIndex << " binary-index=" << binaryPaletteIndex << std::endl; - // } - -// /* -// * Always interpolate if there are only two colors -// */ -// if (numScalarColors == 2) { -// interpolateColorFlag = true; -// } } } if (paletteIndex >= 0) { @@ -490,34 +478,6 @@ Palette::getPaletteColor( } } } -// if (paletteIndex >= 0) { -// const PaletteScalarAndColor* psac = this->getScalarAndColor(paletteIndex); -// psac->getColor(rgbaOut); -// if (interpolateColorFlag && -// (paletteIndex < (numScalarColors - 1))) { -// const PaletteScalarAndColor* psacBelow = this->getScalarAndColor(paletteIndex + 1); -// float totalDiff = psac->getScalar() - psacBelow->getScalar(); -// if (totalDiff != 0.0) { -// float offset = scalar - psacBelow->getScalar(); -// float percentAbove = offset / totalDiff; -// float percentBelow = 1.0f - percentAbove; -// if ( ! psacBelow->isNoneColor()) { -// const float* rgbaAbove = psac->getColor(); -// const float* rgbaBelow = psacBelow->getColor(); -// -// rgbaOut[0] = (percentAbove * rgbaAbove[0] -// + percentBelow * rgbaBelow[0]); -// rgbaOut[1] = (percentAbove * rgbaAbove[1] -// + percentBelow * rgbaBelow[1]); -// rgbaOut[2] = (percentAbove * rgbaAbove[2] -// + percentBelow * rgbaBelow[2]); -// } -// } -// } -// else if (psac->isNoneColor()) { -// rgbaOut[3] = 0.0f; -// } -// } } } -- GitLab From 88bd24804e3848bd188a30287c3eaef4cf411093 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 16 Feb 2017 18:05:06 -0600 Subject: [PATCH 089/755] add corrected areas option to geodesic rois --- .../OperationSurfaceGeodesicROIs.cxx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Operations/OperationSurfaceGeodesicROIs.cxx b/src/Operations/OperationSurfaceGeodesicROIs.cxx index ac74a5ca4..ad5d30169 100644 --- a/src/Operations/OperationSurfaceGeodesicROIs.cxx +++ b/src/Operations/OperationSurfaceGeodesicROIs.cxx @@ -62,6 +62,9 @@ OperationParameters* OperationSurfaceGeodesicROIs::getParameters() OptionalParameter* namesOpt = ret->createOptionalParameter(7, "-names", "name the columns from text file"); namesOpt->addStringParameter(1, "name-list-file", "a text file containing column names, one per line"); + OptionalParameter* corrAreaOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); + corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); + ret->setHelpText( AString("For each vertex in the list file, a column in the output metric is created, and an ROI around that vertex is drawn in that column. ") + "Each metric column will have zeros outside the geodesic distance spacified by , and by default will have a value of 1.0 inside it. " + @@ -144,6 +147,16 @@ void OperationSurfaceGeodesicROIs::useParameters(OperationParameters* myParams, ++i; } } + MetricFile* corrAreas = NULL; + OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(8); + if (corrAreaOpt->m_present) + { + corrAreas = corrAreaOpt->getMetric(1); + if (corrAreas->getNumberOfNodes() != numNodes) + { + throw OperationException("corrected areas metric does not match surface in number of vertices"); + } + } myMetricOut->setNumberOfNodesAndColumns(numNodes, (int)nodelist.size()); myMetricOut->setStructure(mySurf->getStructure()); float invneg2sigmasqr = -0.5f / (sigma * sigma); @@ -161,12 +174,20 @@ void OperationSurfaceGeodesicROIs::useParameters(OperationParameters* myParams, ", " + AString::number(myCoord[2], 'f', 1) + ")"); } } + CaretPointer myhelp; + CaretPointer mygeobase; + if (corrAreas == NULL) + { + myhelp = mySurf->getGeodesicHelper(); + } else { + mygeobase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); + myhelp.grabNew(new GeodesicHelper(mygeobase)); + } switch (overlapType) { case 1://ALLOW for (int i = 0; i < (int)nodelist.size(); ++i) { - CaretPointer myhelp = mySurf->getGeodesicHelper(); vector roinodes; vector dists; myhelp->getNodesToGeoDist(nodelist[i], limit, roinodes, dists); @@ -199,7 +220,6 @@ void OperationSurfaceGeodesicROIs::useParameters(OperationParameters* myParams, vector bestDists(numNodes, -1.0f); for (int i = 0; i < (int)nodelist.size(); ++i) { - CaretPointer myhelp = mySurf->getGeodesicHelper(); vector roinodes; vector dists; myhelp->getNodesToGeoDist(nodelist[i], limit, roinodes, dists); -- GitLab From 1df3c0fb6de9ec072ef7dc0984eb6e9e26af68ad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 20 Feb 2017 17:14:00 -0600 Subject: [PATCH 090/755] Resolve WB-660 color bars dont' match: Fixed color bar processing in PaletteColorMapping.cxx --- src/Palette/PaletteColorMapping.cxx | 451 +++++++++++++++++++++------- 1 file changed, 349 insertions(+), 102 deletions(-) diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 6f103ea0f..25bd96c64 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -443,16 +443,13 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, /* * Types of values for display */ - const bool isPositiveOnly = (this->displayPositiveDataFlag && ( ! this->displayNegativeDataFlag)); - const bool isNegativeOnly = (( ! this->displayPositiveDataFlag) && this->displayNegativeDataFlag); - - float xMinimum = -1.0; - float xMaximum = 1.0; - if (isPositiveOnly) { - xMinimum = 0.0; + float xMinimum = 0.0; + float xMaximum = 0.0; + if (this->displayPositiveDataFlag) { + xMaximum = 1.0; } - else if (isNegativeOnly) { - xMaximum = 0.0; + if (this->displayNegativeDataFlag) { + xMinimum = -1.0; } /* @@ -463,119 +460,100 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, interpolateColor = true; } + float zeroRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; + /* - * Draw the colorbar starting with the color assigned - * to the negative end of the palette. - * Colorbar scalars range from -1 to 1. + * Palettes start with most positive scalar value that in on right side of palette */ - const int iStart = palette->getNumberOfScalarsAndColors() - 1; - const int iEnd = 1; - const int iStep = -1; - for (int i = iStart; i >= iEnd; i += iStep) { - /* - * palette data for 'left' side of a color in the palette. - */ - const PaletteScalarAndColor* sc = palette->getScalarAndColor(i); - float scalar = sc->getScalar(); - float rgba[4]; - sc->getColor(rgba); - - /* - * palette data for 'right' side of a color in the palette. - */ - const PaletteScalarAndColor* nextSC = palette->getScalarAndColor(i - 1); - float nextScalar = nextSC->getScalar(); - float nextRGBA[4]; - nextSC->getColor(nextRGBA); - const bool isNoneColorFlag = nextSC->isNoneColor(); - - /* - * Exclude negative regions if not displayed. - */ - if ( ! this->displayNegativeDataFlag) { - if (nextScalar < 0.0) { - continue; - } - else if (scalar < 0.0) { - scalar = 0.0; - } + const int32_t numberOfColors = palette->getNumberOfScalarsAndColors(); + const bool interpolationOnFlag = interpolateColor; + const int32_t lastColorIndex = numberOfColors - 1; + for (int32_t index = 0; index < numberOfColors; index++) { + const PaletteScalarAndColor* rightSideScalarColor = palette->getScalarAndColor(index); + if (rightSideScalarColor->isNoneColor()) { + /* + * No drawing for "none" color; skip to next color + */ + continue; } /* - * Exclude positive regions if not displayed. + * Add vertices for right side of quad */ - if ( ! this->displayPositiveDataFlag) { - if (scalar > 0.0) { - continue; - } - else if (nextScalar > 0.0) { - nextScalar = 0.0; - } + float rightSideScalar = rightSideScalarColor->getScalar(); + if (index == 0) { + rightSideScalar = xMaximum; // First color extends to right side } + float rightSideRGBA[4]; + rightSideScalarColor->getColor(rightSideRGBA); + + //addXyRgba(quadsXYZ, quadsRGBA, rightSideScalar, -halfHeight, rightSideRGBA); + //addXyRgba(quadsXYZ, quadsRGBA, rightSideScalar, halfHeight, rightSideRGBA); /* - * Normally, the first entry has a scalar value of -1. - * If it does not, use the first color draw from - * -1 to the first scalar value. + * Default left side of palette subsection to far left side + * and same color as right side of palette subsection */ - if (i == iStart) { - if ( ! sc->isNoneColor()) { - if (scalar > -1.0) { - const float xStart = -1.0; - const float xEnd = scalar; - - colorBar->addSection(xStart, - xEnd, - rgba, - rgba); - } - } - } + float leftSideScalar = xMinimum; + float leftSideRGBA[4] = { rightSideRGBA[0], rightSideRGBA[1], rightSideRGBA[2], rightSideRGBA[3] }; /* - * If the 'next' color is none, drawing - * is skipped to let the background show - * throw the 'none' region of the palette. + * Determine the next scalar and color index for left side of quad + * Left side color is same color as right if: + * # At last color in palette + * # Next color is "none" + * # Interpolation is OFF */ - if ( ! isNoneColorFlag) { + int32_t nextIndex = index + 1; + if (nextIndex <= lastColorIndex) { /* - * left and right region of an entry in the palette + * Set scalar value for left side of subsection of palette */ - const float xStart = scalar; - const float xEnd = nextScalar; + const PaletteScalarAndColor* leftSideScalarColor = palette->getScalarAndColor(nextIndex); + leftSideScalar = leftSideScalarColor->getScalar(); - /* - * Unless interpolating, use the 'next' color. - */ - float* startRGBA = nextRGBA; - float* endRGBA = nextRGBA; - if (interpolateColor) { - startRGBA = rgba; + if (palette->getScalarAndColor(nextIndex)->isNoneColor()) { + /* + * No interpolation if left side of subsection is "none" color + */ } - - /* - * Draw the region in the palette. - */ - colorBar->addSection(xStart, - xEnd, - startRGBA, - endRGBA); - + else if (interpolationOnFlag) { + /* + * Set color for left side of subsection of palette + */ + leftSideScalarColor->getColor(leftSideRGBA); + } + } + + if ((rightSideScalar >= 0.0) + && (leftSideScalar <= 0.0)) { /* - * The last scalar value is normally 1.0. If the last - * scalar is less than 1.0, then fill in the rest of - * the palette from the last scalar to 1.0. + * Used for special case when zero is one but both + * negative and postive are off */ - if (i == iEnd) { - if (nextScalar < 1.0) { - const float xStart = nextScalar; - const float xEnd = 1.0; - colorBar->addSection(xStart, - xEnd, - nextRGBA, - nextRGBA); + const float diff = rightSideScalar - leftSideScalar; + if (diff > 0.0) { + const float rightWeight = rightSideScalar; + const float leftWeight = -leftSideScalar; + for (int32_t m = 0; m < 4; m++) { + zeroRGBA[m] = ((leftSideRGBA[m] * leftWeight) + + (rightSideRGBA[m] * rightWeight)); } } + else { + for (int32_t m = 0; m < 4; m++) { + zeroRGBA[m] = rightSideRGBA[m]; + } + } + } + + /* + * Add a section to the color bar + */ + leftSideScalar = MathFunctions::limitRange(leftSideScalar, xMinimum, xMaximum); + rightSideScalar = MathFunctions::limitRange(rightSideScalar, xMinimum, xMaximum); + if (rightSideScalar > leftSideScalar) { + colorBar->addSection(leftSideScalar, rightSideScalar, leftSideRGBA, rightSideRGBA); } } @@ -638,7 +616,20 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, if ( ! this->displayZeroDataFlag) { colorBar->addSection(0.0, 0.0, backgroundRGBA, backgroundRGBA); } - + + /* + * If only zero is displayed + */ + if (this->displayZeroDataFlag + && ( ! this->displayPositiveDataFlag) + && ( ! this->displayNegativeDataFlag)) { + if (zeroRGBA[3] > 0.0) { + colorBar->addSection(-1.0, 0.0, backgroundRGBA, backgroundRGBA); + colorBar->addSection( 0.0, 0.0, zeroRGBA, zeroRGBA); + colorBar->addSection( 1.0, 0.0, backgroundRGBA, backgroundRGBA); + } + } + /** * Add numeric text to the color bar. */ @@ -646,6 +637,241 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, colorBar); } +///** +// * Setup an annotation color bar with its color sections. +// * +// * @param statistics +// * Statistics of data for colorbar. +// * @param colorBar +// * The annotation colorbar that has its color sections set. +// */ +//void +//PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, +// AnnotationColorBar* colorBar) +//{ +// CaretAssert(statistics); +// CaretAssert(colorBar); +// +// colorBar->clearSections(); +// +// const AString paletteName = getSelectedPaletteName(); +// EventPaletteGetByName paletteEvent(paletteName); +// EventManager::get()->sendEvent(paletteEvent.getPointer()); +// const Palette* palette = paletteEvent.getPalette(); +// if (palette == NULL) { +// CaretLogSevere("Unable to find palette named \"" +// + paletteName +// + "\""); +// return; +// } +// +// +// /* +// * Types of values for display +// */ +// const bool isPositiveOnly = (this->displayPositiveDataFlag && ( ! this->displayNegativeDataFlag)); +// const bool isNegativeOnly = (( ! this->displayPositiveDataFlag) && this->displayNegativeDataFlag); +// +// float xMinimum = -1.0; +// float xMaximum = 1.0; +// if (isPositiveOnly) { +// xMinimum = 0.0; +// } +// else if (isNegativeOnly) { +// xMaximum = 0.0; +// } +// +// /* +// * Always interpolate if the palette has only two colors +// */ +// bool interpolateColor = this->interpolatePaletteFlag; +// if (palette->getNumberOfScalarsAndColors() <= 2) { +// interpolateColor = true; +// } +// +// /* +// * Draw the colorbar starting with the color assigned +// * to the negative end of the palette. +// * Colorbar scalars range from -1 to 1. +// */ +// const int iStart = palette->getNumberOfScalarsAndColors() - 1; +// const int iEnd = 1; +// const int iStep = -1; +// for (int i = iStart; i >= iEnd; i += iStep) { +// /* +// * palette data for 'left' side of a color in the palette. +// */ +// const PaletteScalarAndColor* sc = palette->getScalarAndColor(i); +// float scalar = sc->getScalar(); +// float rgba[4]; +// sc->getColor(rgba); +// +// /* +// * palette data for 'right' side of a color in the palette. +// */ +// const PaletteScalarAndColor* nextSC = palette->getScalarAndColor(i - 1); +// float nextScalar = nextSC->getScalar(); +// float nextRGBA[4]; +// nextSC->getColor(nextRGBA); +// const bool isNoneColorFlag = nextSC->isNoneColor(); +// +// /* +// * Exclude negative regions if not displayed. +// */ +// if ( ! this->displayNegativeDataFlag) { +// if (nextScalar < 0.0) { +// continue; +// } +// else if (scalar < 0.0) { +// scalar = 0.0; +// } +// } +// +// /* +// * Exclude positive regions if not displayed. +// */ +// if ( ! this->displayPositiveDataFlag) { +// if (scalar > 0.0) { +// continue; +// } +// else if (nextScalar > 0.0) { +// nextScalar = 0.0; +// } +// } +// +// /* +// * Normally, the first entry has a scalar value of -1. +// * If it does not, use the first color draw from +// * -1 to the first scalar value. +// */ +// if (i == iStart) { +// if ( ! sc->isNoneColor()) { +// if (scalar > -1.0) { +// const float xStart = -1.0; +// const float xEnd = scalar; +// +// colorBar->addSection(xStart, +// xEnd, +// rgba, +// rgba); +// } +// } +// } +// +// /* +// * If the 'next' color is none, drawing +// * is skipped to let the background show +// * throw the 'none' region of the palette. +// */ +// if ( ! isNoneColorFlag) { +// /* +// * left and right region of an entry in the palette +// */ +// const float xStart = scalar; +// const float xEnd = nextScalar; +// +// /* +// * Unless interpolating, use the 'next' color. +// */ +// float* startRGBA = nextRGBA; +// float* endRGBA = nextRGBA; +// if (interpolateColor) { +// startRGBA = rgba; +// } +// +// /* +// * Draw the region in the palette. +// */ +// colorBar->addSection(xStart, +// xEnd, +// startRGBA, +// endRGBA); +// +// /* +// * The last scalar value is normally 1.0. If the last +// * scalar is less than 1.0, then fill in the rest of +// * the palette from the last scalar to 1.0. +// */ +// if (i == iEnd) { +// if (nextScalar < 1.0) { +// const float xStart = nextScalar; +// const float xEnd = 1.0; +// colorBar->addSection(xStart, +// xEnd, +// nextRGBA, +// nextRGBA); +// } +// } +// } +// } +// +// float backgroundRGBA[4]; +// colorBar->getBackgroundColorRGBA(backgroundRGBA); +// +// /* +// * Draw over thresholded regions with background color +// */ +// if (this->thresholdType != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { +// const float minMaxThresholds[2] = { +// getThresholdMinimum(thresholdType), +// getThresholdMaximum(thresholdType) +// }; +// float normalizedThresholds[2]; +// +// mapDataToPaletteNormalizedValues(statistics, +// minMaxThresholds, +// normalizedThresholds, +// 2); +// +// switch (this->thresholdTest) { +// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: +// if (normalizedThresholds[0] >= xMinimum) { +// colorBar->addSection(xMinimum, +// normalizedThresholds[0], +// backgroundRGBA, +// backgroundRGBA); +// } +// if (normalizedThresholds[1] < xMaximum) { +// colorBar->addSection(normalizedThresholds[1], +// xMaximum, +// backgroundRGBA, +// backgroundRGBA); +// } +// break; +// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: +// { +// const float xMin = MathFunctions::limitRange(normalizedThresholds[0], +// xMinimum, +// xMaximum); +// const float xMax = MathFunctions::limitRange(normalizedThresholds[1], +// xMinimum, +// xMaximum); +// if (xMin < xMax) { +// colorBar->addSection(normalizedThresholds[0], +// normalizedThresholds[1], +// backgroundRGBA, +// backgroundRGBA); +// } +// } +// break; +// } +// } +// +// /* +// * If zeros are not displayed, draw a line in the +// * background color at zero in the palette. +// */ +// if ( ! this->displayZeroDataFlag) { +// colorBar->addSection(0.0, 0.0, backgroundRGBA, backgroundRGBA); +// } +// +// /** +// * Add numeric text to the color bar. +// */ +// setupAnnotationColorBarNumericText(statistics, +// colorBar); +//} + /** * Get auto scale percentage negative maximum. * @return Its value. @@ -2020,6 +2246,27 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic // zeroValueText)); } + /* + * When zero only + */ + if (isDisplayZeroDataFlag()) { + if (( ! negativeDataDisplayedFlag) + && ( ! positiveDataDisplayedFlag)) { + colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, + "", + AnnotationTextAlignHorizontalEnum::CENTER, + true)); + colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, + "0.0", + AnnotationTextAlignHorizontalEnum::CENTER, + true)); + colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(1.0, + "", + AnnotationTextAlignHorizontalEnum::CENTER, + true)); + } + } + /* * Add the positive values text */ -- GitLab From eeb6ed1a8d1cdd450116788c5a3765f303f9372f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Feb 2017 09:52:07 -0600 Subject: [PATCH 091/755] Removed old, unused color bar drawing code. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 858 ------------------------- src/Brain/BrainOpenGLFixedPipeline.h | 7 - 2 files changed, 865 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index e9ddf6add..ce4b54e53 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -878,8 +878,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, if(model != NULL) { CaretAssert((this->windowTabIndex >= 0) && (this->windowTabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); - bool modelAllowsPalettes = true; - ModelChart* modelChart = dynamic_cast(model); ModelSurface* surfaceModel = dynamic_cast(model); ModelSurfaceMontage* surfaceMontageModel = dynamic_cast(model); @@ -887,7 +885,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, ModelWholeBrain* wholeBrainModel = dynamic_cast(model); if (modelChart != NULL) { drawChartData(browserTabContent, modelChart, viewport); - modelAllowsPalettes = true; } else if (surfaceModel != NULL) { m_mirroredClippingEnabled = true; @@ -908,7 +905,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, wholeBrainModel, viewport); } else { - modelAllowsPalettes = false; CaretAssertMessage(0, "Unknown type of model for drawing"); } @@ -916,9 +912,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, int viewport[4]; viewportContent->getModelViewport(viewport); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - if (modelAllowsPalettes) { - this->drawAllPalettes(model->getBrain()); - } BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, @@ -6690,857 +6683,6 @@ BrainOpenGLFixedPipeline::drawTextAtModelCoords(const float modelXYZ[3], } } -/** - * Draw the palettes showing how scalars are mapped - * to colors. - * @param brain - * Brain containing model being drawn. - * @param viewport - * Viewport for the model. - */ -void -BrainOpenGLFixedPipeline::drawAllPalettes(Brain* brain) -{ - const bool useTheNewestPaletteDrawingFlag = true; - if (useTheNewestPaletteDrawingFlag) { - return; - } - - /* - * Turn off depth testing - */ - glDisable(GL_DEPTH_TEST); - - - /* - * Save the projection matrix, model matrix, and viewport. - */ - glMatrixMode(GL_PROJECTION); - GLfloat savedProjectionMatrix[16]; - glGetFloatv(GL_PROJECTION_MATRIX, - savedProjectionMatrix); - glMatrixMode(GL_MODELVIEW); - GLfloat savedModelviewMatrix[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, - savedModelviewMatrix); - GLint savedViewport[4]; - glGetIntegerv(GL_VIEWPORT, - savedViewport); - - CaretAssert(brain); - - /* - * Check for a 'selection' type mode - */ - bool selectFlag = false; - switch (this->mode) { - case MODE_DRAWING: - break; - case MODE_IDENTIFICATION: - selectFlag = true; - break; - case MODE_PROJECTION: - return; - break; - } - if (selectFlag) { - return; - } - - this->disableLighting(); - - PaletteFile* paletteFile = brain->getPaletteFile(); - CaretAssert(paletteFile); - - std::vector mapFiles; - std::vector mapIndices; - this->browserTabContent->getDisplayedPaletteMapFiles(mapFiles, - mapIndices); - - /* - * Each map file has a palette drawn to represent the - * datas mapping to colors. - */ - const int32_t numMapFiles = static_cast(mapFiles.size()); - for (int32_t i = 0; i < numMapFiles; i++) { - const int mapIndex = mapIndices[i]; - const PaletteColorMapping* pcm = mapFiles[i]->getMapPaletteColorMapping(mapIndex); - if (pcm != NULL) { - const AString paletteName = pcm->getSelectedPaletteName(); - const Palette* palette = paletteFile->getPaletteByName(paletteName); - if (palette != NULL) { - FastStatistics* statistics = NULL; - switch (mapFiles[i]->getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(mapFiles[i]->getFileFastStatistics()); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(mapFiles[i]->getMapFastStatistics(mapIndex)); - break; - } - if (statistics != NULL) { - this->drawPalette(palette, - pcm, - statistics, - i); - } - } - else { - CaretLogWarning("Palette named " - + paletteName - + " not found in palette file."); - } - } - } - - /* - * Restore the projection matrix, model matrix, and viewport. - */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(savedProjectionMatrix); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(savedModelviewMatrix); - glViewport(savedViewport[0], - savedViewport[1], - savedViewport[2], - savedViewport[3]); -} - -///** -// * Draw a palette. -// * @param palette -// * Palette that is drawn. -// * @param paletteColorMapping -// * Controls mapping of data to colors. -// * @param statistics -// * Statistics describing the data that is mapped to the palette. -// * @param paletteDrawingIndex -// * Counts number of palettes being drawn for the Y-position -// */ -//void -//BrainOpenGLFixedPipeline::drawPalette(const Palette* palette, -// const PaletteColorMapping* paletteColorMapping, -// const FastStatistics* statistics, -// const int paletteDrawingIndex) -//{ -// /* -// * Save viewport. -// */ -// GLint modelViewport[4]; -// glGetIntegerv(GL_VIEWPORT, modelViewport); -// -// /* -// * Create a viewport for drawing the palettes in the -// * lower left corner of the window. Try to use -// * 25% of the display's width. -// */ -// const GLint colorbarViewportWidth = std::max(static_cast(modelViewport[2] * 0.25), -// (GLint)120); -// const GLint colorbarViewportHeight = 35; -// const GLint colorbarViewportX = modelViewport[0] + 10; -// const GLint colorbarVerticalSpacing = 10; -// GLint colorbarViewportY = (modelViewport[1] -// + colorbarVerticalSpacing -// + (paletteDrawingIndex * colorbarViewportHeight)); -// -// glViewport(colorbarViewportX, -// colorbarViewportY, -// colorbarViewportWidth, -// colorbarViewportHeight); -// -// CaretLogFine("Palette " + palette->getName() + " Viewport: (" -// + AString::number(colorbarViewportX) + ", " -// + AString::number(colorbarViewportY) + ", " -// + AString::number(colorbarViewportWidth) + ", " -// + AString::number(colorbarViewportHeight) -// + ")\n Model Viewport: " -// + AString::fromNumbers(modelViewport, 4, ", ")); -// /* -// * Types of values for display -// */ -// const bool isPositiveDisplayed = paletteColorMapping->isDisplayPositiveDataFlag(); -// const bool isNegativeDisplayed = paletteColorMapping->isDisplayNegativeDataFlag(); -// const bool isZeroDisplayed = paletteColorMapping->isDisplayZeroDataFlag(); -// const bool isPositiveOnly = (isPositiveDisplayed && (isNegativeDisplayed == false)); -// const bool isNegativeOnly = ((isPositiveDisplayed == false) && isNegativeDisplayed); -// -// /* -// * Create an orthographic projection that ranges in X: -// * (-1, 1) If negative and positive displayed -// * (-1, 0) If positive is NOT displayed -// * (0, 1) If negative is NOT displayed -// */ -// const GLdouble halfHeight = static_cast(colorbarViewportHeight / 2); -// const GLdouble orthoHeight = halfHeight; -// GLdouble orthoLeft = -1.0; -// GLdouble orthoRight = 1.0; -// if (isPositiveOnly) { -// orthoLeft = 0.0; -// } -// else if (isNegativeOnly) { -// orthoRight = 0.0; -// } -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// glOrtho(orthoLeft, orthoRight, -// -orthoHeight, orthoHeight, -// -1.0, 1.0); -// -// glMatrixMode (GL_MODELVIEW); -// glLoadIdentity(); -// -// /* -// * A little extra so viewport gets filled -// */ -// const GLdouble orthoLeftWithExtra = orthoLeft - 0.10; -// const GLdouble orthoRightWithExtra = orthoRight + 0.10; -// -// /* -// * Fill the palette viewport with the background color -// * Add a little to left and right so viewport is filled (excess will get clipped) -// */ -// glColor3fv(m_backgroundColorFloat); -// glRectf(orthoLeftWithExtra, -orthoHeight, orthoRightWithExtra, orthoHeight); -// -// /* -// * Always interpolate if the palette has only two colors -// */ -// bool interpolateColor = paletteColorMapping->isInterpolatePaletteFlag(); -// if (palette->getNumberOfScalarsAndColors() <= 2) { -// interpolateColor = true; -// } -// -// /* -// * Draw the colorbar starting with the color assigned -// * to the negative end of the palette. -// * Colorbar scalars range from -1 to 1. -// */ -// const int iStart = palette->getNumberOfScalarsAndColors() - 1; -// const int iEnd = 1; -// const int iStep = -1; -// for (int i = iStart; i >= iEnd; i += iStep) { -// /* -// * palette data for 'left' side of a color in the palette. -// */ -// const PaletteScalarAndColor* sc = palette->getScalarAndColor(i); -// float scalar = sc->getScalar(); -// float rgba[4]; -// sc->getColor(rgba); -// -// /* -// * palette data for 'right' side of a color in the palette. -// */ -// const PaletteScalarAndColor* nextSC = palette->getScalarAndColor(i - 1); -// float nextScalar = nextSC->getScalar(); -// float nextRGBA[4]; -// nextSC->getColor(nextRGBA); -// const bool isNoneColorFlag = nextSC->isNoneColor(); -// -// /* -// * Exclude negative regions if not displayed. -// */ -// if (isNegativeDisplayed == false) { -// if (nextScalar < 0.0) { -// continue; -// } -// else if (scalar < 0.0) { -// scalar = 0.0; -// } -// } -// -// /* -// * Exclude positive regions if not displayed. -// */ -// if (isPositiveDisplayed == false) { -// if (scalar > 0.0) { -// continue; -// } -// else if (nextScalar > 0.0) { -// nextScalar = 0.0; -// } -// } -// -// /* -// * Normally, the first entry has a scalar value of -1. -// * If it does not, use the first color draw from -// * -1 to the first scalar value. -// */ -// if (i == iStart) { -// if (sc->isNoneColor() == false) { -// if (scalar > -1.0) { -// const float xStart = -1.0; -// const float xEnd = scalar; -// glColor3fv(rgba); -// glBegin(GL_POLYGON); -// glVertex3f(xStart, 0.0, 0.0); -// glVertex3f(xStart, -halfHeight, 0.0); -// glVertex3f(xEnd, -halfHeight, 0.0); -// glVertex3f(xEnd, 0.0, 0.0); -// glEnd(); -// } -// } -// } -// -// /* -// * If the 'next' color is none, drawing -// * is skipped to let the background show -// * throw the 'none' region of the palette. -// */ -// if (isNoneColorFlag == false) { -// /* -// * left and right region of an entry in the palette -// */ -// const float xStart = scalar; -// const float xEnd = nextScalar; -// -// /* -// * Unless interpolating, use the 'next' color. -// */ -// float* startRGBA = nextRGBA; -// float* endRGBA = nextRGBA; -// if (interpolateColor) { -// startRGBA = rgba; -// } -// -// /* -// * Draw the region in the palette. -// */ -// glBegin(GL_POLYGON); -// glColor3fv(startRGBA); -// glVertex3f(xStart, 0.0, 0.0); -// glVertex3f(xStart, -halfHeight, 0.0); -// glColor3fv(endRGBA); -// glVertex3f(xEnd, -halfHeight, 0.0); -// glVertex3f(xEnd, 0.0, 0.0); -// glEnd(); -// -// /* -// * The last scalar value is normally 1.0. If the last -// * scalar is less than 1.0, then fill in the rest of -// * the palette from the last scalar to 1.0. -// */ -// if (i == iEnd) { -// if (nextScalar < 1.0) { -// const float xStart = nextScalar; -// const float xEnd = 1.0; -// glColor3fv(nextRGBA); -// glBegin(GL_POLYGON); -// glVertex3f(xStart, 0.0, 0.0); -// glVertex3f(xStart, -halfHeight, 0.0); -// glVertex3f(xEnd, -halfHeight, 0.0); -// glVertex3f(xEnd, 0.0, 0.0); -// glEnd(); -// } -// } -// } -// } -// -// /* -// * Draw over thresholded regions with background color -// */ -// const PaletteThresholdTypeEnum::Enum thresholdType = paletteColorMapping->getThresholdType(); -// if (thresholdType != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { -// const float minMaxThresholds[2] = { -// paletteColorMapping->getThresholdMinimum(thresholdType), -// paletteColorMapping->getThresholdMaximum(thresholdType) -// }; -// float normalizedThresholds[2]; -// -// paletteColorMapping->mapDataToPaletteNormalizedValues(statistics, -// minMaxThresholds, -// normalizedThresholds, -// 2); -// -// switch (paletteColorMapping->getThresholdTest()) { -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: -// glColor3fv(m_backgroundColorFloat); -// glRectf(orthoLeftWithExtra, -orthoHeight, normalizedThresholds[0], orthoHeight); -// glRectf(normalizedThresholds[1], -orthoHeight, orthoRightWithExtra, orthoHeight); -// break; -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: -// glColor3fv(m_backgroundColorFloat); -// glRectf(normalizedThresholds[0], -orthoHeight, normalizedThresholds[1], orthoHeight); -// break; -// } -// } -// -// /* -// * If zeros are not displayed, draw a line in the -// * background color at zero in the palette. -// */ -// if (isZeroDisplayed == false) { -// this->setLineWidth(1.0); -// glColor3fv(m_backgroundColorFloat); -// glBegin(GL_LINES); -// glVertex2f(0.0, -halfHeight); -// glVertex2f(0.0, 0.0); -// glEnd(); -// } -// -// AString textLeft; -// AString textCenter; -// AString textRight; -// const bool useNewFormattingFlag = true; -// if (useNewFormattingFlag) { -// /* -// * NEW FORMATTING !!!!! -// */ -// paletteColorMapping->getPaletteColorBarScaleText(statistics, -// textLeft, -// textCenter, -// textRight); -// -// std::vector > normalizedPositionAndText; -// paletteColorMapping->getPaletteColorBarScaleText(statistics, -// normalizedPositionAndText); -// } -// else { -// float minMax[4] = { -1.0, 0.0, 0.0, 1.0 }; -// switch (paletteColorMapping->getScaleMode()) { -// case PaletteScaleModeEnum::MODE_AUTO_SCALE: -// { -// float dummy; -// statistics->getNonzeroRanges(minMax[0], dummy, dummy, minMax[3]); -// } -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: -// { -// const float maxPct = paletteColorMapping->getAutoScaleAbsolutePercentageMaximum(); -// const float minPct = paletteColorMapping->getAutoScaleAbsolutePercentageMinimum(); -// -// minMax[0] = -statistics->getApproxAbsolutePercentile(maxPct); -// minMax[1] = -statistics->getApproxAbsolutePercentile(minPct); -// minMax[2] = statistics->getApproxAbsolutePercentile(minPct); -// minMax[3] = statistics->getApproxAbsolutePercentile(maxPct); -// } -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: -// { -// const float negMaxPct = paletteColorMapping->getAutoScalePercentageNegativeMaximum(); -// const float negMinPct = paletteColorMapping->getAutoScalePercentageNegativeMinimum(); -// const float posMinPct = paletteColorMapping->getAutoScalePercentagePositiveMinimum(); -// const float posMaxPct = paletteColorMapping->getAutoScalePercentagePositiveMaximum(); -// -// minMax[0] = statistics->getApproxNegativePercentile(negMaxPct); -// minMax[1] = statistics->getApproxNegativePercentile(negMinPct); -// minMax[2] = statistics->getApproxPositivePercentile(posMinPct); -// minMax[3] = statistics->getApproxPositivePercentile(posMaxPct); -// } -// break; -// case PaletteScaleModeEnum::MODE_USER_SCALE: -// minMax[0] = paletteColorMapping->getUserScaleNegativeMaximum(); -// minMax[1] = paletteColorMapping->getUserScaleNegativeMinimum(); -// minMax[2] = paletteColorMapping->getUserScalePositiveMinimum(); -// minMax[3] = paletteColorMapping->getUserScalePositiveMaximum(); -// break; -// } -// textLeft = AString::number(minMax[0], 'f', 1); -// AString textCenterNeg = AString::number(minMax[1], 'f', 1); -// if (textCenterNeg == "-0.0") { -// textCenterNeg = "0.0"; -// } -// AString textCenterPos = AString::number(minMax[2], 'f', 1); -// textCenter = textCenterPos; -// if (isNegativeDisplayed && isPositiveDisplayed) { -// if (textCenterNeg != textCenterPos) { -// textCenter = textCenterNeg + "/" + textCenterPos; -// } -// } -// else if (isNegativeDisplayed) { -// textCenter = textCenterNeg; -// } -// else if (isPositiveDisplayed) { -// textCenter = textCenterPos; -// } -// textRight = AString::number(minMax[3], 'f', 1); -// } -// -// /* -// * Reset to the models viewport for drawing text. -// */ -// glViewport(modelViewport[0], -// modelViewport[1], -// modelViewport[2], -// modelViewport[3]); -// -// /* -// * Account for margin around colorbar when calculating text locations -// */ -// int textCenterX = colorbarViewportX - modelViewport[0] + (colorbarViewportWidth / 2); -// const int textLeftX = colorbarViewportX - modelViewport[0]; -// const int textRightX = (colorbarViewportX - modelViewport[0] + colorbarViewportWidth); -// if (isPositiveOnly) { -// textCenterX = textLeftX; -// } -// else if (isNegativeOnly) { -// textCenterX = textRightX; -// } -// -// const int textY = 2 + colorbarViewportY - modelViewport[1] + (colorbarViewportHeight / 2); -// if (isNegativeDisplayed) { -// AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE12); -// annotationText.setTextColor(CaretColorEnum::CUSTOM); -// annotationText.setCustomLineColor(m_foregroundColorFloat); -// annotationText.setText(textLeft); -// this->drawTextAtViewportCoords(textLeftX, -// textY, -// annotationText); -// } -// -// if (isNegativeDisplayed -// || isZeroDisplayed -// || isPositiveDisplayed) { -// -// AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// if (isNegativeOnly) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// } -// else if (isPositiveOnly) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// } -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE12); -// annotationText.setTextColor(CaretColorEnum::CUSTOM); -// annotationText.setCustomLineColor(m_foregroundColorFloat); -// annotationText.setText(textCenter); -// this->drawTextAtViewportCoords(textCenterX, -// textY, -// annotationText); -// } -// -// if (isPositiveDisplayed) { -// AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE12); -// annotationText.setTextColor(CaretColorEnum::CUSTOM); -// annotationText.setCustomLineColor(m_foregroundColorFloat); -// annotationText.setText(textRight); -// this->drawTextAtViewportCoords(textRightX, -// textY, -// annotationText); -// } -// -// return; -//} - -/** - * Draw a palette. - * @param palette - * Palette that is drawn. - * @param paletteColorMapping - * Controls mapping of data to colors. - * @param statistics - * Statistics describing the data that is mapped to the palette. - * @param paletteDrawingIndex - * Counts number of palettes being drawn for the Y-position - */ -void -BrainOpenGLFixedPipeline::drawPalette(const Palette* palette, - const PaletteColorMapping* paletteColorMapping, - const FastStatistics* statistics, - const int paletteDrawingIndex) -{ - /* - * Save viewport. - */ - GLint modelViewport[4]; - glGetIntegerv(GL_VIEWPORT, modelViewport); - - /* - * Create a viewport for drawing the palettes in the - * lower left corner of the window. Try to use - * 25% of the display's width. - */ - const GLint colorbarViewportWidth = std::max(static_cast(modelViewport[2] * 0.25), - (GLint)120); - const GLint colorbarViewportHeight = 35; - const GLint colorbarViewportX = modelViewport[0] + 10; - const GLint colorbarVerticalSpacing = 10; - GLint colorbarViewportY = (modelViewport[1] - + colorbarVerticalSpacing - + (paletteDrawingIndex * colorbarViewportHeight)); - - glViewport(colorbarViewportX, - colorbarViewportY, - colorbarViewportWidth, - colorbarViewportHeight); - - CaretLogFine("Palette " + palette->getName() + " Viewport: (" - + AString::number(colorbarViewportX) + ", " - + AString::number(colorbarViewportY) + ", " - + AString::number(colorbarViewportWidth) + ", " - + AString::number(colorbarViewportHeight) - + ")\n Model Viewport: " - + AString::fromNumbers(modelViewport, 4, ", ")); - /* - * Types of values for display - */ - const bool isPositiveDisplayed = paletteColorMapping->isDisplayPositiveDataFlag(); - const bool isNegativeDisplayed = paletteColorMapping->isDisplayNegativeDataFlag(); - const bool isZeroDisplayed = paletteColorMapping->isDisplayZeroDataFlag(); - const bool isPositiveOnly = (isPositiveDisplayed && (isNegativeDisplayed == false)); - const bool isNegativeOnly = ((isPositiveDisplayed == false) && isNegativeDisplayed); - - /* - * Create an orthographic projection that ranges in X: - * (-1, 1) If negative and positive displayed - * (-1, 0) If positive is NOT displayed - * (0, 1) If negative is NOT displayed - */ - const GLdouble halfHeight = static_cast(colorbarViewportHeight / 2); - const GLdouble orthoHeight = halfHeight; - GLdouble orthoLeft = -1.0; - GLdouble orthoRight = 1.0; - if (isPositiveOnly) { - orthoLeft = 0.0; - } - else if (isNegativeOnly) { - orthoRight = 0.0; - } - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(orthoLeft, orthoRight, - -orthoHeight, orthoHeight, - -1.0, 1.0); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity(); - - /* - * A little extra so viewport gets filled - */ - const GLdouble orthoLeftWithExtra = orthoLeft - 0.10; - const GLdouble orthoRightWithExtra = orthoRight + 0.10; - - /* - * Fill the palette viewport with the background color - * Add a little to left and right so viewport is filled (excess will get clipped) - */ - glColor3fv(m_backgroundColorFloat); - glRectf(orthoLeftWithExtra, -orthoHeight, orthoRightWithExtra, orthoHeight); - - /* - * Always interpolate if the palette has only two colors - */ - bool interpolateColor = paletteColorMapping->isInterpolatePaletteFlag(); - if (palette->getNumberOfScalarsAndColors() <= 2) { - interpolateColor = true; - } - - /* - * Draw the colorbar starting with the color assigned - * to the negative end of the palette. - * Colorbar scalars range from -1 to 1. - */ - const int iStart = palette->getNumberOfScalarsAndColors() - 1; - const int iEnd = 1; - const int iStep = -1; - for (int i = iStart; i >= iEnd; i += iStep) { - /* - * palette data for 'left' side of a color in the palette. - */ - const PaletteScalarAndColor* sc = palette->getScalarAndColor(i); - float scalar = sc->getScalar(); - float rgba[4]; - sc->getColor(rgba); - - /* - * palette data for 'right' side of a color in the palette. - */ - const PaletteScalarAndColor* nextSC = palette->getScalarAndColor(i - 1); - float nextScalar = nextSC->getScalar(); - float nextRGBA[4]; - nextSC->getColor(nextRGBA); - const bool isNoneColorFlag = nextSC->isNoneColor(); - - /* - * Exclude negative regions if not displayed. - */ - if (isNegativeDisplayed == false) { - if (nextScalar < 0.0) { - continue; - } - else if (scalar < 0.0) { - scalar = 0.0; - } - } - - /* - * Exclude positive regions if not displayed. - */ - if (isPositiveDisplayed == false) { - if (scalar > 0.0) { - continue; - } - else if (nextScalar > 0.0) { - nextScalar = 0.0; - } - } - - /* - * Normally, the first entry has a scalar value of -1. - * If it does not, use the first color draw from - * -1 to the first scalar value. - */ - if (i == iStart) { - if (sc->isNoneColor() == false) { - if (scalar > -1.0) { - const float xStart = -1.0; - const float xEnd = scalar; - glColor3fv(rgba); - glBegin(GL_POLYGON); - glVertex3f(xStart, 0.0, 0.0); - glVertex3f(xStart, -halfHeight, 0.0); - glVertex3f(xEnd, -halfHeight, 0.0); - glVertex3f(xEnd, 0.0, 0.0); - glEnd(); - } - } - } - - /* - * If the 'next' color is none, drawing - * is skipped to let the background show - * throw the 'none' region of the palette. - */ - if (isNoneColorFlag == false) { - /* - * left and right region of an entry in the palette - */ - const float xStart = scalar; - const float xEnd = nextScalar; - - /* - * Unless interpolating, use the 'next' color. - */ - float* startRGBA = nextRGBA; - float* endRGBA = nextRGBA; - if (interpolateColor) { - startRGBA = rgba; - } - - /* - * Draw the region in the palette. - */ - glBegin(GL_POLYGON); - glColor3fv(startRGBA); - glVertex3f(xStart, 0.0, 0.0); - glVertex3f(xStart, -halfHeight, 0.0); - glColor3fv(endRGBA); - glVertex3f(xEnd, -halfHeight, 0.0); - glVertex3f(xEnd, 0.0, 0.0); - glEnd(); - - /* - * The last scalar value is normally 1.0. If the last - * scalar is less than 1.0, then fill in the rest of - * the palette from the last scalar to 1.0. - */ - if (i == iEnd) { - if (nextScalar < 1.0) { - const float xStart = nextScalar; - const float xEnd = 1.0; - glColor3fv(nextRGBA); - glBegin(GL_POLYGON); - glVertex3f(xStart, 0.0, 0.0); - glVertex3f(xStart, -halfHeight, 0.0); - glVertex3f(xEnd, -halfHeight, 0.0); - glVertex3f(xEnd, 0.0, 0.0); - glEnd(); - } - } - } - } - - /* - * Draw over thresholded regions with background color - */ - const PaletteThresholdTypeEnum::Enum thresholdType = paletteColorMapping->getThresholdType(); - if (thresholdType != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { - const float minMaxThresholds[2] = { - paletteColorMapping->getThresholdMinimum(thresholdType), - paletteColorMapping->getThresholdMaximum(thresholdType) - }; - float normalizedThresholds[2]; - - paletteColorMapping->mapDataToPaletteNormalizedValues(statistics, - minMaxThresholds, - normalizedThresholds, - 2); - - switch (paletteColorMapping->getThresholdTest()) { - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: - glColor3fv(m_backgroundColorFloat); - glRectf(orthoLeftWithExtra, -orthoHeight, normalizedThresholds[0], orthoHeight); - glRectf(normalizedThresholds[1], -orthoHeight, orthoRightWithExtra, orthoHeight); - break; - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: - glColor3fv(m_backgroundColorFloat); - glRectf(normalizedThresholds[0], -orthoHeight, normalizedThresholds[1], orthoHeight); - break; - } - } - - /* - * If zeros are not displayed, draw a line in the - * background color at zero in the palette. - */ - if (isZeroDisplayed == false) { - this->setLineWidth(1.0); - glColor3fv(m_backgroundColorFloat); - glBegin(GL_LINES); - glVertex2f(0.0, -halfHeight); - glVertex2f(0.0, 0.0); - glEnd(); - } - - /* - * Reset to the models viewport for drawing text. - */ - glViewport(modelViewport[0], - modelViewport[1], - modelViewport[2], - modelViewport[3]); - - /* - * Get the numeric text values for display above the color bar - */ - std::vector > normalizedPositionAndText; - paletteColorMapping->getPaletteColorBarScaleText(statistics, - normalizedPositionAndText); - - const int textViewportY = 2 + colorbarViewportY - modelViewport[1] + (colorbarViewportHeight / 2); - const int32_t numericTextCount = static_cast(normalizedPositionAndText.size()); - for (int32_t iText = 0; iText < numericTextCount; iText++) { - CaretAssertVectorIndex(normalizedPositionAndText, iText); - - const float textNormalizedX = normalizedPositionAndText[iText].first; - const float textViewportX = ((colorbarViewportX - modelViewport[0]) - + static_cast(textNormalizedX * colorbarViewportWidth)); - - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - if (iText == 0) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - } - else if (iText == (numericTextCount - 1)) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - } - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE14); - annotationText.setTextColor(CaretColorEnum::CUSTOM); - annotationText.setCustomTextColor(m_foregroundColorFloat); - annotationText.setText(normalizedPositionAndText[iText].second); - this->drawTextAtViewportCoords(textViewportX, - textViewportY, - annotationText); - } -} /** * @return A string containing the state of OpenGL (depth testing, lighting, etc.) diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 2401a11c2..75c6a9c4c 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -453,13 +453,6 @@ namespace caret { // const int32_t tabViewport[4]); void drawTabAnnotations(BrainOpenGLViewportContent* tabContent); - void drawAllPalettes(Brain* brain); - - void drawPalette(const Palette* palette, - const PaletteColorMapping* paletteColorMapping, - const FastStatistics* statistics, - const int paletteDrawingIndex); - void drawBackgroundImage(BrainOpenGLViewportContent* vpContent); void drawImage(BrainOpenGLViewportContent* vpContent, -- GitLab From fa942cb9d03260cd5f1c2c58fec33b9c688c69e2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Feb 2017 12:56:08 -0600 Subject: [PATCH 092/755] When a dynconn file is selected in an Overlay, disable the Overlay's Contruction Menu items 'Reload Selected File' and 'Copy Path and Filename to Clipboard' since the a dynconn file cannot be reloaded (need to reload its parent dtseries file) and since the filename of the dynconn file is not valid. --- src/GuiQt/OverlayViewController.cxx | 13 +++++++++---- src/GuiQt/OverlayViewController.h | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/GuiQt/OverlayViewController.cxx b/src/GuiQt/OverlayViewController.cxx index 1fea6c380..e626d8843 100644 --- a/src/GuiQt/OverlayViewController.cxx +++ b/src/GuiQt/OverlayViewController.cxx @@ -841,9 +841,9 @@ OverlayViewController::createConstructionMenu(QWidget* parent) menu->addSeparator(); - menu->addAction("Copy Path and File Name to Clipboard", - this, - SLOT(menuCopyFileNameToClipBoard())); + m_copyPathAndFileNameToClipboardAction = menu->addAction("Copy Path and File Name to Clipboard", + this, + SLOT(menuCopyFileNameToClipBoard())); menu->addAction("Copy Map Name to Clipboard", this, @@ -864,7 +864,7 @@ OverlayViewController::menuConstructionAboutToShow() int32_t mapIndex = -1; this->overlay->getSelectionData(caretDataFile, mapIndex); - + QString menuText = "Reload Selected File"; if (caretDataFile != NULL) { if (caretDataFile->isModified()) { @@ -876,7 +876,12 @@ OverlayViewController::menuConstructionAboutToShow() } menuText += suffix; } + + const bool notDynConnFileFlag = (caretDataFile->getDataFileType() != DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC); + m_constructionReloadFileAction->setEnabled(notDynConnFileFlag); + m_copyPathAndFileNameToClipboardAction->setEnabled(notDynConnFileFlag); } + m_constructionReloadFileAction->setText(menuText); } } diff --git a/src/GuiQt/OverlayViewController.h b/src/GuiQt/OverlayViewController.h index aa8da6944..d68b2c54f 100644 --- a/src/GuiQt/OverlayViewController.h +++ b/src/GuiQt/OverlayViewController.h @@ -148,6 +148,8 @@ namespace caret { QAction* m_constructionReloadFileAction; + QAction* m_copyPathAndFileNameToClipboardAction; + WuQGridLayoutGroup* gridLayoutGroup; friend class OverlaySetViewController; -- GitLab From 6d3fa454c240da72f37d11be87b4f6f376a4ed8d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Feb 2017 15:03:28 -0600 Subject: [PATCH 093/755] Resolve WB-661 Open dialog file filter not functioning on Mac: Changed the CaretFileDialog so that it uses Qt's file dialog (instead of a native dialog) since the proxy file filter only works with a Qt file dialog. The proxy file filter is needed to hide files that do not match the selected file filter and to prevent CIFTI files from being listed when the file filter is set to volume files. --- src/GuiQt/CaretFileDialog.cxx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/GuiQt/CaretFileDialog.cxx b/src/GuiQt/CaretFileDialog.cxx index fb74a7032..6a9f78787 100644 --- a/src/GuiQt/CaretFileDialog.cxx +++ b/src/GuiQt/CaretFileDialog.cxx @@ -147,10 +147,19 @@ void CaretFileDialog::initializeCaretFileDialog() { /* - * Create a proxy model that hides files that do not match the file filter. - * On Macs, Qt shows files that do not match the file filter as disabled - * but we don't want them displayed. The dialog will take ownership of - * the proxy model so it does not need to be deleted by this instance. + * We MUST use a non-native dialog. + * Otherwise, the file filter proxy model + * will not work. + */ + setOption(QFileDialog::DontUseNativeDialog); + + /* + * Create a proxy model for filtering the data files. + * The proxy is used to limit the displayed files to + * only those with the proper file extension. In addition, + * since CIFTI and NIFTI files end in ".nii", filtering is + * performed so that CIFTI files are not displayed when + * the user selectes Volume files. */ m_filterFilesProxyModel = new FilterFilesProxyModel(); this->setProxyModel(m_filterFilesProxyModel); -- GitLab From 3f84ed20ae243ab734ddc2f5a869f645084897ea Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Feb 2017 15:37:23 -0600 Subject: [PATCH 094/755] Fixed crash when volume tab was selected. CaretColorEnum::toRGBAByte() was improperly sizing an array and going beyond the array's bounds. --- src/Common/CaretColorEnum.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/CaretColorEnum.cxx b/src/Common/CaretColorEnum.cxx index e28a0de1d..3b6efb7e5 100644 --- a/src/Common/CaretColorEnum.cxx +++ b/src/Common/CaretColorEnum.cxx @@ -351,7 +351,7 @@ void CaretColorEnum::toRGBAByte(Enum enumValue, uint8_t rgbaOut[4]) { - float rgbaFloat[3]; + float rgbaFloat[4]; toRGBAFloat(enumValue, rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); -- GitLab From 91afc68b0b3c06f69d8dd4bdf39ce4a53c07cffa Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 21 Feb 2017 15:55:42 -0600 Subject: [PATCH 095/755] reorder palettes and introduce 2 new palettes without "none" --- src/Files/PaletteFile.cxx | 932 ++++++++++++++++++++------------------ 1 file changed, 495 insertions(+), 437 deletions(-) diff --git a/src/Files/PaletteFile.cxx b/src/Files/PaletteFile.cxx index e6c8622cb..f996fc40b 100644 --- a/src/Files/PaletteFile.cxx +++ b/src/Files/PaletteFile.cxx @@ -400,64 +400,7 @@ PaletteFile::addDefaultPalettes() this->addColor("_black", 0x00, 0x00, 0x00 ); this->addColor("_orange", 0xff, 0x69, 0x00 ); - //---------------------------------------------------------------------- - // Psych palette - // - if (this->getPaletteByName("PSYCH") == NULL) { - this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); - this->addColor("_poran-red", 0xff, 0x44, 0x00 ); - this->addColor("_pblue", 0x00, 0x44, 0xff ); - this->addColor("_pltblue1", 0x00, 0x69, 0xff ); - this->addColor("_pltblue2", 0x00, 0x99, 0xff ); - this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); - - Palette psych; - psych.setName("PSYCH"); - //psych.setPositiveOnly(false); - - psych.addScalarAndColor(1.00f, "_yellow"); - psych.addScalarAndColor(0.75f, "_pyell-oran"); - psych.addScalarAndColor(0.50f, "_orange"); - psych.addScalarAndColor(0.25f, "_poran-red"); - psych.addScalarAndColor(0.05f, "none"); - psych.addScalarAndColor(-0.05f, "_pblue"); - psych.addScalarAndColor(-0.25f, "_pltblue1"); - psych.addScalarAndColor(-0.50f, "_pltblue2"); - psych.addScalarAndColor(-0.75f, "_pbluecyan"); - - addPalette(psych); - } - //---------------------------------------------------------------------- - // Psych no-none palette - // - if (this->getPaletteByName("PSYCH-NO-NONE") == NULL) { - this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); - this->addColor("_poran-red", 0xff, 0x44, 0x00 ); - this->addColor("_pblue", 0x00, 0x44, 0xff ); - this->addColor("_pltblue1", 0x00, 0x69, 0xff ); - this->addColor("_pltblue2", 0x00, 0x99, 0xff ); - this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); - - Palette psychNoNone; - psychNoNone.setName("PSYCH-NO-NONE"); - //psychNoNone.setPositiveOnly(false); - - psychNoNone.addScalarAndColor(1.00f, "_yellow"); - psychNoNone.addScalarAndColor(0.75f, "_pyell-oran"); - psychNoNone.addScalarAndColor(0.50f, "_orange"); - psychNoNone.addScalarAndColor(0.25f, "_poran-red"); - psychNoNone.addScalarAndColor(0.0f, "_pblue"); - psychNoNone.addScalarAndColor(-0.25f, "_pltblue1"); - psychNoNone.addScalarAndColor(-0.50f, "_pltblue2"); - psychNoNone.addScalarAndColor(-0.75f, "_pbluecyan"); - - addPalette(psychNoNone); - } - - //---------------------------------------------------------------------- - // ROY-BIG palette - // - if (this->getPaletteByName("ROY-BIG") == NULL) { + if (this->getPaletteByName(Palette::ROY_BIG_BL_PALETTE_NAME) == NULL) { this->addColor("_RGB_255_255_0", 255, 255, 0 ); //#ffff00 this->addColor("_RGB_255_200_0", 255, 200, 0 ); //#ffc800 this->addColor("_RGB_255_120_0", 255, 120, 0 ); //#ff7800 @@ -475,31 +418,6 @@ PaletteFile::addDefaultPalettes() this->addColor("_RGB_0_255_0", 0, 255, 0 ); //#00ff00 this->addColor("_RGB_0_255_255", 0, 255, 255 ); //#00ffff - Palette royBig; - royBig.setName("ROY-BIG"); - - royBig.addScalarAndColor(1.00f, "_RGB_255_255_0"); - royBig.addScalarAndColor(0.875f, "_RGB_255_200_0"); - royBig.addScalarAndColor(0.750f, "_RGB_255_120_0"); - royBig.addScalarAndColor(0.625f, "_RGB_255_0_0"); - royBig.addScalarAndColor(0.500f, "_RGB_200_0_0"); - royBig.addScalarAndColor(0.375f, "_RGB_150_0_0"); - royBig.addScalarAndColor(0.250f, "_RGB_100_0_0"); - royBig.addScalarAndColor(0.125f, "_RGB_60_0_0"); - royBig.addScalarAndColor(0.000f, "none"); - royBig.addScalarAndColor(-0.125f, "_RGB_0_0_80"); - royBig.addScalarAndColor(-0.250f, "_RGB_0_0_170"); - royBig.addScalarAndColor(-0.375f, "_RGB_75_0_125"); - royBig.addScalarAndColor(-0.500f, "_RGB_125_0_160"); - royBig.addScalarAndColor(-0.625f, "_RGB_75_125_0"); - royBig.addScalarAndColor(-0.750f, "_RGB_0_200_0"); - royBig.addScalarAndColor(-0.875f, "_RGB_0_255_0"); - royBig.addScalarAndColor(-0.990f, "_RGB_0_255_255"); - royBig.addScalarAndColor(-1.00f, "_RGB_0_255_255"); - - addPalette(royBig); - - Palette royBigBL; royBigBL.setName(Palette::ROY_BIG_BL_PALETTE_NAME); @@ -525,48 +443,6 @@ PaletteFile::addDefaultPalettes() addPalette(royBigBL); } - //---------------------------------------------------------------------- - // Orange-Yellow palette - // - if (this->getPaletteByName("Orange-Yellow") == NULL) { - this->addColor("_oy1", 0, 0, 0 ); - this->addColor("_oy2", 130, 2, 0 ); - this->addColor("_oy3", 254, 130, 2 ); - this->addColor("_oy4", 254, 254, 126 ); - this->addColor("_oy5", 254, 254, 254 ); - - Palette orangeYellow; - orangeYellow.setName("Orange-Yellow"); - orangeYellow.addScalarAndColor( 1.0f, "_oy5"); - orangeYellow.addScalarAndColor( 0.5f, "_oy4"); - orangeYellow.addScalarAndColor( 0.0f, "_oy3"); - orangeYellow.addScalarAndColor(-0.5f, "_oy2"); - orangeYellow.addScalarAndColor(-1.0f, "_oy1"); - addPalette(orangeYellow); - } - - // - // Create a palette with just white and black designed to be used - // with the interpolate option - // - if (this->getPaletteByName(Palette::GRAY_INTERP_PALETTE_NAME) == NULL) { - this->addColor("_white_gray_interp", 255, 255, 255 ); - this->addColor("_black_gray_interp", 0, 0, 0 ); - - - Palette palGrayPositiveInterp; - palGrayPositiveInterp.setName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); - palGrayPositiveInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); - palGrayPositiveInterp.addScalarAndColor(0.0f, "_black_gray_interp"); - addPalette(palGrayPositiveInterp); - - Palette palGrayInterp; - palGrayInterp.setName(Palette::GRAY_INTERP_PALETTE_NAME); - palGrayInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); - palGrayInterp.addScalarAndColor(-1.0f, "_black_gray_interp"); - addPalette(palGrayInterp); - } - //------------------------------------------------------------------------ // // Palette by David Van Essen @@ -600,31 +476,6 @@ PaletteFile::addDefaultPalettes() int blue_videen7[3] = { 0x7f, 0x7f, 0xcc }; this->addColor("_blue_videen7", blue_videen7); - if (this->getPaletteByName("clear_brain") == NULL) { - Palette clearBrain; - clearBrain.setName("clear_brain"); - clearBrain.addScalarAndColor(1.0f , "_red"); - clearBrain.addScalarAndColor(0.9f , "_orange"); - clearBrain.addScalarAndColor(0.8f , "_oran-yell"); - clearBrain.addScalarAndColor(0.7f , "_yellow"); - clearBrain.addScalarAndColor(0.6f , "_limegreen"); - clearBrain.addScalarAndColor(0.5f , "_green"); - clearBrain.addScalarAndColor(0.4f , "_blue_videen7"); - clearBrain.addScalarAndColor(0.3f , "_blue_videen9"); - clearBrain.addScalarAndColor(0.2f , "_blue_videen11"); - clearBrain.addScalarAndColor(0.1f , "_purple2"); - clearBrain.addScalarAndColor(0.0f , "none"); - clearBrain.addScalarAndColor(-0.1f , "_cyan"); - clearBrain.addScalarAndColor(-0.2f , "_green"); - clearBrain.addScalarAndColor(-0.3f , "_limegreen"); - clearBrain.addScalarAndColor(-0.4f , "_violet"); - clearBrain.addScalarAndColor(-0.5f , "_hotpink"); - clearBrain.addScalarAndColor(-0.6f , "_white"); - clearBrain.addScalarAndColor(-0.7f , "_gry-dd"); - clearBrain.addScalarAndColor(-0.8f , "_gry-bb"); - clearBrain.addScalarAndColor(-0.9f , "_black"); - addPalette(clearBrain); - } if (this->getPaletteByName("videen_style") == NULL) { Palette videenStyle; videenStyle.setName("videen_style"); @@ -651,289 +502,64 @@ PaletteFile::addDefaultPalettes() addPalette(videenStyle); } - if (this->getPaletteByName("fidl") == NULL) { - int Bright_Yellow[3] = { 0xee, 0xee, 0x55 }; - this->addColor("_Bright_Yellow", Bright_Yellow); - int Mustard[3] = { 0xdd, 0xdd, 0x66 }; - this->addColor("_Mustard", Mustard); - int Brown_Mustard[3] = { 0xdd, 0x99, 0x00 }; - this->addColor("_Brown_Mustard", Brown_Mustard); - int Bright_Red[3] = { 0xff, 0x00, 0x00 }; - this->addColor("_Bright_Red", Bright_Red); - int Fire_Engine_Red[3] = { 0xdd, 0x00, 0x00 }; - this->addColor("_Fire_Engine_Red", Fire_Engine_Red); - int Brick[3] = { 0xbb, 0x00, 0x00 }; - this->addColor("_Brick", Brick); - int Beet[3] = { 0x99, 0x00, 0x00 }; - this->addColor("_Beet", Beet); - int Beaujolais[3] = { 0x77, 0x00, 0x00 }; - this->addColor("_Beaujolais", Beaujolais); - int Burgundy[3] = { 0x55, 0x00, 0x00 }; - this->addColor("_Burgundy", Burgundy); - int Thrombin[3] = { 0x11, 0x00, 0x00 }; - this->addColor("_Thrombin", Thrombin); - int Deep_Green[3] = { 0x00, 0x11, 0x00 }; - this->addColor("_Deep_Green", Deep_Green); - int British_Racing_Green[3] = { 0x00, 0x55, 0x00 }; - this->addColor("_British_Racing_Green", British_Racing_Green); - int Kelp[3] = { 0x00, 0x77, 0x00 }; - this->addColor("_Kelp", Kelp); - int Lime[3] = { 0x00, 0x99, 0x00 }; - this->addColor("_Lime", Lime); - int Mint[3] = { 0x00, 0xbb, 0x00 }; - this->addColor("_Mint", Mint); - int Brussell_Sprout[3] = { 0x00, 0xdd, 0x00 }; - this->addColor("_Brussell_Sprout", Brussell_Sprout); - int Bright_Green[3] = { 0x00, 0xff, 0x00 }; - this->addColor("_Bright_Green", Bright_Green); - int Periwinkle[3] = { 0x66, 0x66, 0xbb }; - this->addColor("_Periwinkle", Periwinkle); - int Azure[3] = { 0x88, 0x88, 0xee }; - this->addColor("_Azure", Azure); - int Turquoise[3] = { 0x00, 0xcc, 0xcc }; - this->addColor("_Turquoise", Turquoise); + // + // Create a palette with just white and black designed to be used + // with the interpolate option + // + if (this->getPaletteByName(Palette::GRAY_INTERP_PALETTE_NAME) == NULL) { + this->addColor("_white_gray_interp", 255, 255, 255 ); + this->addColor("_black_gray_interp", 0, 0, 0 ); + - Palette fidl; - fidl.setName("fidl"); - fidl.addScalarAndColor(1.0f, "_Bright_Yellow"); - fidl.addScalarAndColor(0.9f, "_Mustard"); - fidl.addScalarAndColor(0.8f, "_Brown_Mustard"); - fidl.addScalarAndColor(0.7f, "_Bright_Red"); - fidl.addScalarAndColor(0.6f, "_Fire_Engine_Red"); - fidl.addScalarAndColor(0.5f, "_Brick"); - fidl.addScalarAndColor(0.4f, "_Beet"); - fidl.addScalarAndColor(0.3f, "_Beaujolais"); - fidl.addScalarAndColor(0.2f, "_Burgundy"); - fidl.addScalarAndColor(0.1f, "_Thrombin"); - fidl.addScalarAndColor(0.0f, "none"); - fidl.addScalarAndColor(-0.1f, "_Deep_Green"); - fidl.addScalarAndColor(-0.2f, "_British_Racing_Green"); - fidl.addScalarAndColor(-0.3f, "_Kelp"); - fidl.addScalarAndColor(-0.4f, "_Lime"); - fidl.addScalarAndColor(-0.5f, "_Mint"); - fidl.addScalarAndColor(-0.6f, "_Brussell_Sprout"); - fidl.addScalarAndColor(-0.7f, "_Bright_Green"); - fidl.addScalarAndColor(-0.8f, "_Periwinkle"); - fidl.addScalarAndColor(-0.9f, "_Azure"); - fidl.addScalarAndColor(-1.0f, "_Turquoise"); - addPalette(fidl); + Palette palGrayPositiveInterp; + palGrayPositiveInterp.setName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); + palGrayPositiveInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); + palGrayPositiveInterp.addScalarAndColor(0.0f, "_black_gray_interp"); + addPalette(palGrayPositiveInterp); + + Palette palGrayInterp; + palGrayInterp.setName(Palette::GRAY_INTERP_PALETTE_NAME); + palGrayInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); + palGrayInterp.addScalarAndColor(-1.0f, "_black_gray_interp"); + addPalette(palGrayInterp); + } + + //---------------------------------------------------------------------- + // fixed Psych palette + // + if (this->getPaletteByName("PSYCH-FIXED") == NULL) { + this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); + this->addColor("_poran-red", 0xff, 0x44, 0x00 ); + this->addColor("_pred", 0xff, 0x00, 0x00 ); + this->addColor("_pblue", 0x00, 0x44, 0xff ); + this->addColor("_pltblue1", 0x00, 0x69, 0xff ); + this->addColor("_pltblue2", 0x00, 0x99, 0xff ); + this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); + this->addColor("_pcyan", 0x00, 0xff, 0xff ); + + Palette psychFixed; + psychFixed.setName("PSYCH-FIXED"); + //psych.setPositiveOnly(false); + + psychFixed.addScalarAndColor(1.00f, "_yellow"); + psychFixed.addScalarAndColor(0.75f, "_pyell-oran"); + psychFixed.addScalarAndColor(0.50f, "_orange"); + psychFixed.addScalarAndColor(0.25f, "_poran-red"); + psychFixed.addScalarAndColor(0.00001f, "_pred");//0.00001f is a special range reserved by data normalization for zero values, see PaletteColorMapping.cxx:1590 + psychFixed.addScalarAndColor(0.0000099f, "_black"); + psychFixed.addScalarAndColor(-0.0000099f, "_black"); + psychFixed.addScalarAndColor(-0.00001f, "_pblue"); + psychFixed.addScalarAndColor(-0.25f, "_pltblue1"); + psychFixed.addScalarAndColor(-0.50f, "_pltblue2"); + psychFixed.addScalarAndColor(-0.75f, "_pbluecyan"); + psychFixed.addScalarAndColor(-1.0f, "_pcyan"); + + addPalette(psychFixed); } //------------------------------------------------------------------------ // - // Colors by Russ H. - // - int _rbgyr20_10[3] = { 0x00, 0xff, 0x00 }; - this->addColor("_rbgyr20_10", _rbgyr20_10); - int _rbgyr20_15[3] = { 0xff, 0xff, 0x00 }; - this->addColor("_rbgyr20_15", _rbgyr20_15); - int _rbgyr20_20[3] = { 0xff, 0x00, 0x00 }; - this->addColor("_rbgyr20_20", _rbgyr20_20); - - int _rbgyr20_21[3] = { 0x9d, 0x22, 0xc1 }; - this->addColor("_rbgyr20_21", _rbgyr20_21); - int _rbgyr20_22[3] = { 0x81, 0x06, 0xa5 }; - this->addColor("_rbgyr20_22", _rbgyr20_22); - int _rbgyr20_23[3] = { 0xff, 0xec, 0x00 }; - this->addColor("_rbgyr20_23", _rbgyr20_23); - int _rbgyr20_24[3] = { 0xff, 0xd6, 0x00 }; - this->addColor("_rbgyr20_24", _rbgyr20_24); - int _rbgyr20_25[3] = { 0xff, 0xbc, 0x00 }; - this->addColor("_rbgyr20_25", _rbgyr20_25); - int _rbgyr20_26[3] = { 0xff, 0x9c, 0x00 }; - this->addColor("_rbgyr20_26", _rbgyr20_26); - int _rbgyr20_27[3] = { 0xff, 0x7c, 0x00 }; - this->addColor("_rbgyr20_27", _rbgyr20_27); - int _rbgyr20_28[3] = { 0xff, 0x5c, 0x00 }; - this->addColor("_rbgyr20_28", _rbgyr20_28); - int _rbgyr20_29[3] = { 0xff, 0x3d, 0x00 }; - this->addColor("_rbgyr20_29", _rbgyr20_29); - int _rbgyr20_30[3] = { 0xff, 0x23, 0x00 }; - this->addColor("_rbgyr20_30", _rbgyr20_30); - int _rbgyr20_31[3] = { 0x00, 0xed, 0x12 }; - this->addColor("_rbgyr20_31", _rbgyr20_31); - int _rbgyr20_32[3] = { 0x00, 0xd5, 0x2a }; - this->addColor("_rbgyr20_32", _rbgyr20_32); - int _rbgyr20_33[3] = { 0x00, 0xb9, 0x46 }; - this->addColor("_rbgyr20_33", _rbgyr20_33); - int _rbgyr20_34[3] = { 0x00, 0x9b, 0x64 }; - this->addColor("_rbgyr20_34", _rbgyr20_34); - int _rbgyr20_35[3] = { 0x00, 0x7b, 0x84 }; - this->addColor("_rbgyr20_35", _rbgyr20_35); - int _rbgyr20_36[3] = { 0x00, 0x5b, 0xa4 }; - this->addColor("_rbgyr20_36", _rbgyr20_36); - int _rbgyr20_37[3] = { 0x00, 0x44, 0xbb }; - this->addColor("_rbgyr20_37", _rbgyr20_37); - int _rbgyr20_38[3] = { 0x00, 0x24, 0xdb }; - this->addColor("_rbgyr20_38", _rbgyr20_38); - int _rbgyr20_39[3] = { 0x00, 0x00, 0xff }; - this->addColor("_rbgyr20_39", _rbgyr20_39); - - int _rbgyr20_40[3] = { 0xff, 0xf1, 0x00 }; - this->addColor("_rbgyr20_40", _rbgyr20_40); - int _rbgyr20_41[3] = { 0xff, 0xdc, 0x00 }; - this->addColor("_rbgyr20_41", _rbgyr20_41); - int _rbgyr20_42[3] = { 0xff, 0xcb, 0x00 }; - this->addColor("_rbgyr20_42", _rbgyr20_42); - int _rbgyr20_43[3] = { 0xff, 0xc2, 0x00 }; - this->addColor("_rbgyr20_43", _rbgyr20_43); - int _rbgyr20_44[3] = { 0xff, 0xae, 0x00 }; - this->addColor("_rbgyr20_44", _rbgyr20_44); - int _rbgyr20_45[3] = { 0xff, 0x9f, 0x00 }; - this->addColor("_rbgyr20_45", _rbgyr20_45); - int _rbgyr20_46[3] = { 0xff, 0x86, 0x00 }; - this->addColor("_rbgyr20_46", _rbgyr20_46); - int _rbgyr20_47[3] = { 0xff, 0x59, 0x00 }; - this->addColor("_rbgyr20_47", _rbgyr20_47); - int _rbgyr20_48[3] = { 0x00, 0xff, 0x2d }; - this->addColor("_rbgyr20_48", _rbgyr20_48); - int _rbgyr20_49[3] = { 0x00, 0xff, 0x65 }; - this->addColor("_rbgyr20_49", _rbgyr20_49); - int _rbgyr20_50[3] = { 0x00, 0xff, 0xa5 }; - this->addColor("_rbgyr20_50", _rbgyr20_50); - int _rbgyr20_51[3] = { 0x00, 0xff, 0xdd }; - this->addColor("_rbgyr20_51", _rbgyr20_51); - int _rbgyr20_52[3] = { 0x00, 0xff, 0xff }; - this->addColor("_rbgyr20_52", _rbgyr20_52); - int _rbgyr20_53[3] = { 0x00, 0xe9, 0xff }; - this->addColor("_rbgyr20_53", _rbgyr20_53); - int _rbgyr20_54[3] = { 0x00, 0xad, 0xff }; - this->addColor("_rbgyr20_54", _rbgyr20_54); - int _rbgyr20_55[3] = { 0x00, 0x69, 0xff }; - this->addColor("_rbgyr20_55", _rbgyr20_55); - int _rbgyr20_56[3] = { 0xff, 0x00, 0xb9 }; - this->addColor("_rbgyr20_56", _rbgyr20_56); - int _rbgyr20_57[3] = { 0xff, 0x00, 0x63 }; - this->addColor("_rbgyr20_57", _rbgyr20_57); - int _rbgyr20_58[3] = { 0xff, 0x05, 0x00 }; - this->addColor("_rbgyr20_58", _rbgyr20_58); - int _rbgyr20_59[3] = { 0xff, 0x32, 0x00 }; - this->addColor("_rbgyr20_59", _rbgyr20_59); - int _rbgyr20_60[3] = { 0xff, 0x70, 0x00 }; - this->addColor("_rbgyr20_60", _rbgyr20_60); - int _rbgyr20_61[3] = { 0xff, 0xa4, 0x00 }; - this->addColor("_rbgyr20_61", _rbgyr20_61); - int _rbgyr20_62[3] = { 0xff, 0xba, 0x00 }; - this->addColor("_rbgyr20_62", _rbgyr20_62); - int _rbgyr20_63[3] = { 0xff, 0xd3, 0x00 }; - this->addColor("_rbgyr20_63", _rbgyr20_63); - int _rbgyr20_64[3] = { 0x42, 0x21, 0xdb }; - this->addColor("_rbgyr20_64", _rbgyr20_64); - int _rbgyr20_65[3] = { 0x10, 0x08, 0xf6 }; - this->addColor("_rbgyr20_65", _rbgyr20_65); - int _rbgyr20_66[3] = { 0x00, 0x13, 0xff }; - this->addColor("_rbgyr20_66", _rbgyr20_66); - int _rbgyr20_67[3] = { 0x00, 0x5b, 0xff }; - this->addColor("_rbgyr20_67", _rbgyr20_67); - int _rbgyr20_68[3] = { 0x00, 0xb3, 0xff }; - this->addColor("_rbgyr20_68", _rbgyr20_68); - int _rbgyr20_69[3] = { 0x00, 0xfc, 0xff }; - this->addColor("_rbgyr20_69", _rbgyr20_69); - int _rbgyr20_70[3] = { 0x00, 0xff, 0xcd }; - this->addColor("_rbgyr20_70", _rbgyr20_70); - int _rbgyr20_71[3] = { 0x00, 0xff, 0x74 }; - this->addColor("_rbgyr20_71", _rbgyr20_71); - int _rbgyr20_72[3] = { 0xff, 0x00, 0xf9 }; - this->addColor("_rbgyr20_72", _rbgyr20_72); - int _rbgyr20_73[3] = { 0x62, 0x31, 0xc9 }; - this->addColor("_rbgyr20_73", _rbgyr20_73); - - //------------------------------------------------------------------------ - // - // Palette by Russ H. - // - if (this->getPaletteByName("raich4_clrmid") == NULL) { - Palette r4; - r4.setName("raich4_clrmid"); - r4.addScalarAndColor(1.000000f, "_rbgyr20_20"); - r4.addScalarAndColor(0.900000f, "_rbgyr20_30"); - r4.addScalarAndColor(0.800000f, "_rbgyr20_29"); - r4.addScalarAndColor(0.700000f, "_rbgyr20_28"); - r4.addScalarAndColor(0.600000f, "_rbgyr20_27"); - r4.addScalarAndColor(0.500000f, "_rbgyr20_26"); - r4.addScalarAndColor(0.400000f, "_rbgyr20_25"); - r4.addScalarAndColor(0.300000f, "_rbgyr20_24"); - r4.addScalarAndColor(0.200000f, "_rbgyr20_23"); - r4.addScalarAndColor(0.100000f, "_rbgyr20_15"); - r4.addScalarAndColor(0.000000f, "none"); - r4.addScalarAndColor(-0.100000f, "_rbgyr20_10"); - r4.addScalarAndColor(-0.200000f, "_rbgyr20_31"); - r4.addScalarAndColor(-0.300000f, "_rbgyr20_32"); - r4.addScalarAndColor(-0.400000f, "_rbgyr20_33"); - r4.addScalarAndColor(-0.500000f, "_rbgyr20_34"); - r4.addScalarAndColor(-0.600000f, "_rbgyr20_35"); - r4.addScalarAndColor(-0.700000f, "_rbgyr20_36"); - r4.addScalarAndColor(-0.800000f, "_rbgyr20_37"); - r4.addScalarAndColor(-0.900000f, "_rbgyr20_38"); - r4.addScalarAndColor(-1.000000f, "_rbgyr20_39"); - addPalette(r4); - } - - //------------------------------------------------------------------------ - // - // Palette by Russ H. - // - if (this->getPaletteByName("raich6_clrmid") == NULL) { - Palette r6; - r6.setName("raich6_clrmid"); - r6.addScalarAndColor(1.000000f, "_rbgyr20_20"); - r6.addScalarAndColor(0.900000f, "_rbgyr20_47"); - r6.addScalarAndColor(0.800000f, "_rbgyr20_46"); - r6.addScalarAndColor(0.700000f, "_rbgyr20_45"); - r6.addScalarAndColor(0.600000f, "_rbgyr20_44"); - r6.addScalarAndColor(0.500000f, "_rbgyr20_43"); - r6.addScalarAndColor(0.400000f, "_rbgyr20_42"); - r6.addScalarAndColor(0.300000f, "_rbgyr20_41"); - r6.addScalarAndColor(0.200000f, "_rbgyr20_40"); - r6.addScalarAndColor(0.100000f, "_rbgyr20_15"); - r6.addScalarAndColor(0.000000f, "none"); - r6.addScalarAndColor(-0.100000f, "_rbgyr20_10"); - r6.addScalarAndColor(-0.200000f, "_rbgyr20_48"); - r6.addScalarAndColor(-0.300000f, "_rbgyr20_49"); - r6.addScalarAndColor(-0.400000f, "_rbgyr20_50"); - r6.addScalarAndColor(-0.500000f, "_rbgyr20_51"); - r6.addScalarAndColor(-0.600000f, "_rbgyr20_52"); - r6.addScalarAndColor(-0.700000f, "_rbgyr20_53"); - r6.addScalarAndColor(-0.800000f, "_rbgyr20_54"); - r6.addScalarAndColor(-0.900000f, "_rbgyr20_55"); - r6.addScalarAndColor(-1.000000f, "_rbgyr20_39"); - addPalette(r6); - } - - //------------------------------------------------------------------------ - // - // Palette by Russ H. - // - if (this->getPaletteByName("HSB8_clrmid") == NULL) { - Palette hsb8; - hsb8.setName("HSB8_clrmid"); - hsb8.addScalarAndColor(1.000000f, "_rbgyr20_15"); - hsb8.addScalarAndColor(0.900000f, "_rbgyr20_63"); - hsb8.addScalarAndColor(0.800000f, "_rbgyr20_62"); - hsb8.addScalarAndColor(0.700000f, "_rbgyr20_61"); - hsb8.addScalarAndColor(0.600000f, "_rbgyr20_60"); - hsb8.addScalarAndColor(0.500000f, "_rbgyr20_59"); - hsb8.addScalarAndColor(0.400000f, "_rbgyr20_58"); - hsb8.addScalarAndColor(0.300000f, "_rbgyr20_57"); - hsb8.addScalarAndColor(0.200000f, "_rbgyr20_56"); - hsb8.addScalarAndColor(0.100000f, "_rbgyr20_72"); - hsb8.addScalarAndColor(0.000000f, "none"); - hsb8.addScalarAndColor(-0.100000f, "_rbgyr20_73"); - hsb8.addScalarAndColor(-0.200000f, "_rbgyr20_64"); - hsb8.addScalarAndColor(-0.300000f, "_rbgyr20_65"); - hsb8.addScalarAndColor(-0.400000f, "_rbgyr20_66"); - hsb8.addScalarAndColor(-0.500000f, "_rbgyr20_67"); - hsb8.addScalarAndColor(-0.600000f, "_rbgyr20_68"); - hsb8.addScalarAndColor(-0.700000f, "_rbgyr20_69"); - hsb8.addScalarAndColor(-0.800000f, "_rbgyr20_70"); - hsb8.addScalarAndColor(-0.900000f, "_rbgyr20_71"); - hsb8.addScalarAndColor(-1.000000f, "_rbgyr20_10"); - addPalette(hsb8); - } - - //------------------------------------------------------------------------ - // - // Palette by Jon Wieser @ mcw + // Palette by Jon Wieser @ mcw // int rbgyr20_01[3] = { 0xCC, 0x10, 0x33 }; this->addColor("_rbgyr20_01", rbgyr20_01); @@ -1026,21 +652,45 @@ PaletteFile::addDefaultPalettes() pal3.addScalarAndColor(0.0f, "none"); addPalette(pal3); } + //---------------------------------------------------------------------- - // Positive/Negative palette + // Orange-Yellow palette // - if (this->getPaletteByName("POS_NEG") == NULL) { + if (this->getPaletteByName("Orange-Yellow") == NULL) { + this->addColor("_oy1", 0, 0, 0 ); + this->addColor("_oy2", 130, 2, 0 ); + this->addColor("_oy3", 254, 130, 2 ); + this->addColor("_oy4", 254, 254, 126 ); + this->addColor("_oy5", 254, 254, 254 ); + + Palette orangeYellow; + orangeYellow.setName("Orange-Yellow"); + orangeYellow.addScalarAndColor( 1.0f, "_oy5"); + orangeYellow.addScalarAndColor( 0.5f, "_oy4"); + orangeYellow.addScalarAndColor( 0.0f, "_oy3"); + orangeYellow.addScalarAndColor(-0.5f, "_oy2"); + orangeYellow.addScalarAndColor(-1.0f, "_oy1"); + addPalette(orangeYellow); + } + + //---------------------------------------------------------------------- + // Positive/Negative/Zero palette + // + if (this->getPaletteByName("POS_NEG_ZERO") == NULL) { this->addColor("pos_neg_blue", 0x00, 0x00, 0xff ); this->addColor("pos_neg_red", 0xff, 0x00, 0x00 ); - Palette posNeg; - posNeg.setName("POS_NEG"); + Palette posNegZero; + posNegZero.setName("POS_NEG_ZERO"); - posNeg.addScalarAndColor(1.00f, "pos_neg_red"); - posNeg.addScalarAndColor(0.0001f, "none"); - posNeg.addScalarAndColor(-0.0001f, "pos_neg_blue"); + posNegZero.addScalarAndColor(1.0f, "pos_neg_red"); + posNegZero.addScalarAndColor(0.00001f, "pos_neg_red"); + posNegZero.addScalarAndColor(0.0000099f, "_black"); + posNegZero.addScalarAndColor(-0.0000099f, "_black"); + posNegZero.addScalarAndColor(-0.00001f, "pos_neg_blue"); + posNegZero.addScalarAndColor(-1.0f, "pos_neg_blue"); - addPalette(posNeg); + addPalette(posNegZero); } if (this->getPaletteByName("red-yellow") == NULL) { @@ -1206,8 +856,416 @@ PaletteFile::addDefaultPalettes() addPalette(JET256); } + + //TSC: palettes that use "none" or are broken (psych no none) start here - exception: rbgyr20p, to keep it close to rbgyr20 + //---------------------------------------------------------------------- + // Psych palette + // + if (this->getPaletteByName("PSYCH") == NULL) { + this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); + this->addColor("_poran-red", 0xff, 0x44, 0x00 ); + this->addColor("_pblue", 0x00, 0x44, 0xff ); + this->addColor("_pltblue1", 0x00, 0x69, 0xff ); + this->addColor("_pltblue2", 0x00, 0x99, 0xff ); + this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); + + Palette psych; + psych.setName("PSYCH"); + //psych.setPositiveOnly(false); + + psych.addScalarAndColor(1.00f, "_yellow"); + psych.addScalarAndColor(0.75f, "_pyell-oran"); + psych.addScalarAndColor(0.50f, "_orange"); + psych.addScalarAndColor(0.25f, "_poran-red"); + psych.addScalarAndColor(0.05f, "none"); + psych.addScalarAndColor(-0.05f, "_pblue"); + psych.addScalarAndColor(-0.25f, "_pltblue1"); + psych.addScalarAndColor(-0.50f, "_pltblue2"); + psych.addScalarAndColor(-0.75f, "_pbluecyan"); + + addPalette(psych); + } + //---------------------------------------------------------------------- + // Psych no-none palette + // + if (this->getPaletteByName("PSYCH-NO-NONE") == NULL) { + this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); + this->addColor("_poran-red", 0xff, 0x44, 0x00 ); + this->addColor("_pblue", 0x00, 0x44, 0xff ); + this->addColor("_pltblue1", 0x00, 0x69, 0xff ); + this->addColor("_pltblue2", 0x00, 0x99, 0xff ); + this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); + + Palette psychNoNone; + psychNoNone.setName("PSYCH-NO-NONE"); + //psychNoNone.setPositiveOnly(false); + + psychNoNone.addScalarAndColor(1.00f, "_yellow"); + psychNoNone.addScalarAndColor(0.75f, "_pyell-oran"); + psychNoNone.addScalarAndColor(0.50f, "_orange"); + psychNoNone.addScalarAndColor(0.25f, "_poran-red"); + psychNoNone.addScalarAndColor(0.0f, "_pblue"); + psychNoNone.addScalarAndColor(-0.25f, "_pltblue1"); + psychNoNone.addScalarAndColor(-0.50f, "_pltblue2"); + psychNoNone.addScalarAndColor(-0.75f, "_pbluecyan"); + + addPalette(psychNoNone); + } + + //---------------------------------------------------------------------- + // ROY-BIG palette + // + if (this->getPaletteByName("ROY-BIG") == NULL) { + Palette royBig; + royBig.setName("ROY-BIG"); + + royBig.addScalarAndColor(1.00f, "_RGB_255_255_0"); + royBig.addScalarAndColor(0.875f, "_RGB_255_200_0"); + royBig.addScalarAndColor(0.750f, "_RGB_255_120_0"); + royBig.addScalarAndColor(0.625f, "_RGB_255_0_0"); + royBig.addScalarAndColor(0.500f, "_RGB_200_0_0"); + royBig.addScalarAndColor(0.375f, "_RGB_150_0_0"); + royBig.addScalarAndColor(0.250f, "_RGB_100_0_0"); + royBig.addScalarAndColor(0.125f, "_RGB_60_0_0"); + royBig.addScalarAndColor(0.000f, "none"); + royBig.addScalarAndColor(-0.125f, "_RGB_0_0_80"); + royBig.addScalarAndColor(-0.250f, "_RGB_0_0_170"); + royBig.addScalarAndColor(-0.375f, "_RGB_75_0_125"); + royBig.addScalarAndColor(-0.500f, "_RGB_125_0_160"); + royBig.addScalarAndColor(-0.625f, "_RGB_75_125_0"); + royBig.addScalarAndColor(-0.750f, "_RGB_0_200_0"); + royBig.addScalarAndColor(-0.875f, "_RGB_0_255_0"); + royBig.addScalarAndColor(-0.990f, "_RGB_0_255_255"); + royBig.addScalarAndColor(-1.00f, "_RGB_0_255_255"); + + addPalette(royBig); + } + + if (this->getPaletteByName("clear_brain") == NULL) { + Palette clearBrain; + clearBrain.setName("clear_brain"); + clearBrain.addScalarAndColor(1.0f , "_red"); + clearBrain.addScalarAndColor(0.9f , "_orange"); + clearBrain.addScalarAndColor(0.8f , "_oran-yell"); + clearBrain.addScalarAndColor(0.7f , "_yellow"); + clearBrain.addScalarAndColor(0.6f , "_limegreen"); + clearBrain.addScalarAndColor(0.5f , "_green"); + clearBrain.addScalarAndColor(0.4f , "_blue_videen7"); + clearBrain.addScalarAndColor(0.3f , "_blue_videen9"); + clearBrain.addScalarAndColor(0.2f , "_blue_videen11"); + clearBrain.addScalarAndColor(0.1f , "_purple2"); + clearBrain.addScalarAndColor(0.0f , "none"); + clearBrain.addScalarAndColor(-0.1f , "_cyan"); + clearBrain.addScalarAndColor(-0.2f , "_green"); + clearBrain.addScalarAndColor(-0.3f , "_limegreen"); + clearBrain.addScalarAndColor(-0.4f , "_violet"); + clearBrain.addScalarAndColor(-0.5f , "_hotpink"); + clearBrain.addScalarAndColor(-0.6f , "_white"); + clearBrain.addScalarAndColor(-0.7f , "_gry-dd"); + clearBrain.addScalarAndColor(-0.8f , "_gry-bb"); + clearBrain.addScalarAndColor(-0.9f , "_black"); + addPalette(clearBrain); + } + + if (this->getPaletteByName("fidl") == NULL) { + int Bright_Yellow[3] = { 0xee, 0xee, 0x55 }; + this->addColor("_Bright_Yellow", Bright_Yellow); + int Mustard[3] = { 0xdd, 0xdd, 0x66 }; + this->addColor("_Mustard", Mustard); + int Brown_Mustard[3] = { 0xdd, 0x99, 0x00 }; + this->addColor("_Brown_Mustard", Brown_Mustard); + int Bright_Red[3] = { 0xff, 0x00, 0x00 }; + this->addColor("_Bright_Red", Bright_Red); + int Fire_Engine_Red[3] = { 0xdd, 0x00, 0x00 }; + this->addColor("_Fire_Engine_Red", Fire_Engine_Red); + int Brick[3] = { 0xbb, 0x00, 0x00 }; + this->addColor("_Brick", Brick); + int Beet[3] = { 0x99, 0x00, 0x00 }; + this->addColor("_Beet", Beet); + int Beaujolais[3] = { 0x77, 0x00, 0x00 }; + this->addColor("_Beaujolais", Beaujolais); + int Burgundy[3] = { 0x55, 0x00, 0x00 }; + this->addColor("_Burgundy", Burgundy); + int Thrombin[3] = { 0x11, 0x00, 0x00 }; + this->addColor("_Thrombin", Thrombin); + int Deep_Green[3] = { 0x00, 0x11, 0x00 }; + this->addColor("_Deep_Green", Deep_Green); + int British_Racing_Green[3] = { 0x00, 0x55, 0x00 }; + this->addColor("_British_Racing_Green", British_Racing_Green); + int Kelp[3] = { 0x00, 0x77, 0x00 }; + this->addColor("_Kelp", Kelp); + int Lime[3] = { 0x00, 0x99, 0x00 }; + this->addColor("_Lime", Lime); + int Mint[3] = { 0x00, 0xbb, 0x00 }; + this->addColor("_Mint", Mint); + int Brussell_Sprout[3] = { 0x00, 0xdd, 0x00 }; + this->addColor("_Brussell_Sprout", Brussell_Sprout); + int Bright_Green[3] = { 0x00, 0xff, 0x00 }; + this->addColor("_Bright_Green", Bright_Green); + int Periwinkle[3] = { 0x66, 0x66, 0xbb }; + this->addColor("_Periwinkle", Periwinkle); + int Azure[3] = { 0x88, 0x88, 0xee }; + this->addColor("_Azure", Azure); + int Turquoise[3] = { 0x00, 0xcc, 0xcc }; + this->addColor("_Turquoise", Turquoise); + + Palette fidl; + fidl.setName("fidl"); + fidl.addScalarAndColor(1.0f, "_Bright_Yellow"); + fidl.addScalarAndColor(0.9f, "_Mustard"); + fidl.addScalarAndColor(0.8f, "_Brown_Mustard"); + fidl.addScalarAndColor(0.7f, "_Bright_Red"); + fidl.addScalarAndColor(0.6f, "_Fire_Engine_Red"); + fidl.addScalarAndColor(0.5f, "_Brick"); + fidl.addScalarAndColor(0.4f, "_Beet"); + fidl.addScalarAndColor(0.3f, "_Beaujolais"); + fidl.addScalarAndColor(0.2f, "_Burgundy"); + fidl.addScalarAndColor(0.1f, "_Thrombin"); + fidl.addScalarAndColor(0.0f, "none"); + fidl.addScalarAndColor(-0.1f, "_Deep_Green"); + fidl.addScalarAndColor(-0.2f, "_British_Racing_Green"); + fidl.addScalarAndColor(-0.3f, "_Kelp"); + fidl.addScalarAndColor(-0.4f, "_Lime"); + fidl.addScalarAndColor(-0.5f, "_Mint"); + fidl.addScalarAndColor(-0.6f, "_Brussell_Sprout"); + fidl.addScalarAndColor(-0.7f, "_Bright_Green"); + fidl.addScalarAndColor(-0.8f, "_Periwinkle"); + fidl.addScalarAndColor(-0.9f, "_Azure"); + fidl.addScalarAndColor(-1.0f, "_Turquoise"); + addPalette(fidl); + } + + //------------------------------------------------------------------------ + // + // Colors by Russ H. + // + int _rbgyr20_10[3] = { 0x00, 0xff, 0x00 }; + this->addColor("_rbgyr20_10", _rbgyr20_10); + int _rbgyr20_15[3] = { 0xff, 0xff, 0x00 }; + this->addColor("_rbgyr20_15", _rbgyr20_15); + int _rbgyr20_20[3] = { 0xff, 0x00, 0x00 }; + this->addColor("_rbgyr20_20", _rbgyr20_20); + + int _rbgyr20_21[3] = { 0x9d, 0x22, 0xc1 }; + this->addColor("_rbgyr20_21", _rbgyr20_21); + int _rbgyr20_22[3] = { 0x81, 0x06, 0xa5 }; + this->addColor("_rbgyr20_22", _rbgyr20_22); + int _rbgyr20_23[3] = { 0xff, 0xec, 0x00 }; + this->addColor("_rbgyr20_23", _rbgyr20_23); + int _rbgyr20_24[3] = { 0xff, 0xd6, 0x00 }; + this->addColor("_rbgyr20_24", _rbgyr20_24); + int _rbgyr20_25[3] = { 0xff, 0xbc, 0x00 }; + this->addColor("_rbgyr20_25", _rbgyr20_25); + int _rbgyr20_26[3] = { 0xff, 0x9c, 0x00 }; + this->addColor("_rbgyr20_26", _rbgyr20_26); + int _rbgyr20_27[3] = { 0xff, 0x7c, 0x00 }; + this->addColor("_rbgyr20_27", _rbgyr20_27); + int _rbgyr20_28[3] = { 0xff, 0x5c, 0x00 }; + this->addColor("_rbgyr20_28", _rbgyr20_28); + int _rbgyr20_29[3] = { 0xff, 0x3d, 0x00 }; + this->addColor("_rbgyr20_29", _rbgyr20_29); + int _rbgyr20_30[3] = { 0xff, 0x23, 0x00 }; + this->addColor("_rbgyr20_30", _rbgyr20_30); + int _rbgyr20_31[3] = { 0x00, 0xed, 0x12 }; + this->addColor("_rbgyr20_31", _rbgyr20_31); + int _rbgyr20_32[3] = { 0x00, 0xd5, 0x2a }; + this->addColor("_rbgyr20_32", _rbgyr20_32); + int _rbgyr20_33[3] = { 0x00, 0xb9, 0x46 }; + this->addColor("_rbgyr20_33", _rbgyr20_33); + int _rbgyr20_34[3] = { 0x00, 0x9b, 0x64 }; + this->addColor("_rbgyr20_34", _rbgyr20_34); + int _rbgyr20_35[3] = { 0x00, 0x7b, 0x84 }; + this->addColor("_rbgyr20_35", _rbgyr20_35); + int _rbgyr20_36[3] = { 0x00, 0x5b, 0xa4 }; + this->addColor("_rbgyr20_36", _rbgyr20_36); + int _rbgyr20_37[3] = { 0x00, 0x44, 0xbb }; + this->addColor("_rbgyr20_37", _rbgyr20_37); + int _rbgyr20_38[3] = { 0x00, 0x24, 0xdb }; + this->addColor("_rbgyr20_38", _rbgyr20_38); + int _rbgyr20_39[3] = { 0x00, 0x00, 0xff }; + this->addColor("_rbgyr20_39", _rbgyr20_39); + + int _rbgyr20_40[3] = { 0xff, 0xf1, 0x00 }; + this->addColor("_rbgyr20_40", _rbgyr20_40); + int _rbgyr20_41[3] = { 0xff, 0xdc, 0x00 }; + this->addColor("_rbgyr20_41", _rbgyr20_41); + int _rbgyr20_42[3] = { 0xff, 0xcb, 0x00 }; + this->addColor("_rbgyr20_42", _rbgyr20_42); + int _rbgyr20_43[3] = { 0xff, 0xc2, 0x00 }; + this->addColor("_rbgyr20_43", _rbgyr20_43); + int _rbgyr20_44[3] = { 0xff, 0xae, 0x00 }; + this->addColor("_rbgyr20_44", _rbgyr20_44); + int _rbgyr20_45[3] = { 0xff, 0x9f, 0x00 }; + this->addColor("_rbgyr20_45", _rbgyr20_45); + int _rbgyr20_46[3] = { 0xff, 0x86, 0x00 }; + this->addColor("_rbgyr20_46", _rbgyr20_46); + int _rbgyr20_47[3] = { 0xff, 0x59, 0x00 }; + this->addColor("_rbgyr20_47", _rbgyr20_47); + int _rbgyr20_48[3] = { 0x00, 0xff, 0x2d }; + this->addColor("_rbgyr20_48", _rbgyr20_48); + int _rbgyr20_49[3] = { 0x00, 0xff, 0x65 }; + this->addColor("_rbgyr20_49", _rbgyr20_49); + int _rbgyr20_50[3] = { 0x00, 0xff, 0xa5 }; + this->addColor("_rbgyr20_50", _rbgyr20_50); + int _rbgyr20_51[3] = { 0x00, 0xff, 0xdd }; + this->addColor("_rbgyr20_51", _rbgyr20_51); + int _rbgyr20_52[3] = { 0x00, 0xff, 0xff }; + this->addColor("_rbgyr20_52", _rbgyr20_52); + int _rbgyr20_53[3] = { 0x00, 0xe9, 0xff }; + this->addColor("_rbgyr20_53", _rbgyr20_53); + int _rbgyr20_54[3] = { 0x00, 0xad, 0xff }; + this->addColor("_rbgyr20_54", _rbgyr20_54); + int _rbgyr20_55[3] = { 0x00, 0x69, 0xff }; + this->addColor("_rbgyr20_55", _rbgyr20_55); + int _rbgyr20_56[3] = { 0xff, 0x00, 0xb9 }; + this->addColor("_rbgyr20_56", _rbgyr20_56); + int _rbgyr20_57[3] = { 0xff, 0x00, 0x63 }; + this->addColor("_rbgyr20_57", _rbgyr20_57); + int _rbgyr20_58[3] = { 0xff, 0x05, 0x00 }; + this->addColor("_rbgyr20_58", _rbgyr20_58); + int _rbgyr20_59[3] = { 0xff, 0x32, 0x00 }; + this->addColor("_rbgyr20_59", _rbgyr20_59); + int _rbgyr20_60[3] = { 0xff, 0x70, 0x00 }; + this->addColor("_rbgyr20_60", _rbgyr20_60); + int _rbgyr20_61[3] = { 0xff, 0xa4, 0x00 }; + this->addColor("_rbgyr20_61", _rbgyr20_61); + int _rbgyr20_62[3] = { 0xff, 0xba, 0x00 }; + this->addColor("_rbgyr20_62", _rbgyr20_62); + int _rbgyr20_63[3] = { 0xff, 0xd3, 0x00 }; + this->addColor("_rbgyr20_63", _rbgyr20_63); + int _rbgyr20_64[3] = { 0x42, 0x21, 0xdb }; + this->addColor("_rbgyr20_64", _rbgyr20_64); + int _rbgyr20_65[3] = { 0x10, 0x08, 0xf6 }; + this->addColor("_rbgyr20_65", _rbgyr20_65); + int _rbgyr20_66[3] = { 0x00, 0x13, 0xff }; + this->addColor("_rbgyr20_66", _rbgyr20_66); + int _rbgyr20_67[3] = { 0x00, 0x5b, 0xff }; + this->addColor("_rbgyr20_67", _rbgyr20_67); + int _rbgyr20_68[3] = { 0x00, 0xb3, 0xff }; + this->addColor("_rbgyr20_68", _rbgyr20_68); + int _rbgyr20_69[3] = { 0x00, 0xfc, 0xff }; + this->addColor("_rbgyr20_69", _rbgyr20_69); + int _rbgyr20_70[3] = { 0x00, 0xff, 0xcd }; + this->addColor("_rbgyr20_70", _rbgyr20_70); + int _rbgyr20_71[3] = { 0x00, 0xff, 0x74 }; + this->addColor("_rbgyr20_71", _rbgyr20_71); + int _rbgyr20_72[3] = { 0xff, 0x00, 0xf9 }; + this->addColor("_rbgyr20_72", _rbgyr20_72); + int _rbgyr20_73[3] = { 0x62, 0x31, 0xc9 }; + this->addColor("_rbgyr20_73", _rbgyr20_73); + + //------------------------------------------------------------------------ + // + // Palette by Russ H. + // + if (this->getPaletteByName("raich4_clrmid") == NULL) { + Palette r4; + r4.setName("raich4_clrmid"); + r4.addScalarAndColor(1.000000f, "_rbgyr20_20"); + r4.addScalarAndColor(0.900000f, "_rbgyr20_30"); + r4.addScalarAndColor(0.800000f, "_rbgyr20_29"); + r4.addScalarAndColor(0.700000f, "_rbgyr20_28"); + r4.addScalarAndColor(0.600000f, "_rbgyr20_27"); + r4.addScalarAndColor(0.500000f, "_rbgyr20_26"); + r4.addScalarAndColor(0.400000f, "_rbgyr20_25"); + r4.addScalarAndColor(0.300000f, "_rbgyr20_24"); + r4.addScalarAndColor(0.200000f, "_rbgyr20_23"); + r4.addScalarAndColor(0.100000f, "_rbgyr20_15"); + r4.addScalarAndColor(0.000000f, "none"); + r4.addScalarAndColor(-0.100000f, "_rbgyr20_10"); + r4.addScalarAndColor(-0.200000f, "_rbgyr20_31"); + r4.addScalarAndColor(-0.300000f, "_rbgyr20_32"); + r4.addScalarAndColor(-0.400000f, "_rbgyr20_33"); + r4.addScalarAndColor(-0.500000f, "_rbgyr20_34"); + r4.addScalarAndColor(-0.600000f, "_rbgyr20_35"); + r4.addScalarAndColor(-0.700000f, "_rbgyr20_36"); + r4.addScalarAndColor(-0.800000f, "_rbgyr20_37"); + r4.addScalarAndColor(-0.900000f, "_rbgyr20_38"); + r4.addScalarAndColor(-1.000000f, "_rbgyr20_39"); + addPalette(r4); + } + + //------------------------------------------------------------------------ + // + // Palette by Russ H. + // + if (this->getPaletteByName("raich6_clrmid") == NULL) { + Palette r6; + r6.setName("raich6_clrmid"); + r6.addScalarAndColor(1.000000f, "_rbgyr20_20"); + r6.addScalarAndColor(0.900000f, "_rbgyr20_47"); + r6.addScalarAndColor(0.800000f, "_rbgyr20_46"); + r6.addScalarAndColor(0.700000f, "_rbgyr20_45"); + r6.addScalarAndColor(0.600000f, "_rbgyr20_44"); + r6.addScalarAndColor(0.500000f, "_rbgyr20_43"); + r6.addScalarAndColor(0.400000f, "_rbgyr20_42"); + r6.addScalarAndColor(0.300000f, "_rbgyr20_41"); + r6.addScalarAndColor(0.200000f, "_rbgyr20_40"); + r6.addScalarAndColor(0.100000f, "_rbgyr20_15"); + r6.addScalarAndColor(0.000000f, "none"); + r6.addScalarAndColor(-0.100000f, "_rbgyr20_10"); + r6.addScalarAndColor(-0.200000f, "_rbgyr20_48"); + r6.addScalarAndColor(-0.300000f, "_rbgyr20_49"); + r6.addScalarAndColor(-0.400000f, "_rbgyr20_50"); + r6.addScalarAndColor(-0.500000f, "_rbgyr20_51"); + r6.addScalarAndColor(-0.600000f, "_rbgyr20_52"); + r6.addScalarAndColor(-0.700000f, "_rbgyr20_53"); + r6.addScalarAndColor(-0.800000f, "_rbgyr20_54"); + r6.addScalarAndColor(-0.900000f, "_rbgyr20_55"); + r6.addScalarAndColor(-1.000000f, "_rbgyr20_39"); + addPalette(r6); + } + + //------------------------------------------------------------------------ + // + // Palette by Russ H. + // + if (this->getPaletteByName("HSB8_clrmid") == NULL) { + Palette hsb8; + hsb8.setName("HSB8_clrmid"); + hsb8.addScalarAndColor(1.000000f, "_rbgyr20_15"); + hsb8.addScalarAndColor(0.900000f, "_rbgyr20_63"); + hsb8.addScalarAndColor(0.800000f, "_rbgyr20_62"); + hsb8.addScalarAndColor(0.700000f, "_rbgyr20_61"); + hsb8.addScalarAndColor(0.600000f, "_rbgyr20_60"); + hsb8.addScalarAndColor(0.500000f, "_rbgyr20_59"); + hsb8.addScalarAndColor(0.400000f, "_rbgyr20_58"); + hsb8.addScalarAndColor(0.300000f, "_rbgyr20_57"); + hsb8.addScalarAndColor(0.200000f, "_rbgyr20_56"); + hsb8.addScalarAndColor(0.100000f, "_rbgyr20_72"); + hsb8.addScalarAndColor(0.000000f, "none"); + hsb8.addScalarAndColor(-0.100000f, "_rbgyr20_73"); + hsb8.addScalarAndColor(-0.200000f, "_rbgyr20_64"); + hsb8.addScalarAndColor(-0.300000f, "_rbgyr20_65"); + hsb8.addScalarAndColor(-0.400000f, "_rbgyr20_66"); + hsb8.addScalarAndColor(-0.500000f, "_rbgyr20_67"); + hsb8.addScalarAndColor(-0.600000f, "_rbgyr20_68"); + hsb8.addScalarAndColor(-0.700000f, "_rbgyr20_69"); + hsb8.addScalarAndColor(-0.800000f, "_rbgyr20_70"); + hsb8.addScalarAndColor(-0.900000f, "_rbgyr20_71"); + hsb8.addScalarAndColor(-1.000000f, "_rbgyr20_10"); + addPalette(hsb8); + } + + //---------------------------------------------------------------------- + // Positive/Negative palette + // + if (this->getPaletteByName("POS_NEG") == NULL) { + this->addColor("pos_neg_blue", 0x00, 0x00, 0xff ); + this->addColor("pos_neg_red", 0xff, 0x00, 0x00 ); + + Palette posNeg; + posNeg.setName("POS_NEG"); + + posNeg.addScalarAndColor(1.00f, "pos_neg_red"); + posNeg.addScalarAndColor(0.0001f, "none"); + posNeg.addScalarAndColor(-0.0001f, "pos_neg_blue"); + + addPalette(posNeg); + } + if (modifiedStatus == false) { - this->clearModified(); + this->clearModified();//this clears modified status on all members, to match our status } } -- GitLab From 04f7d747c2c9ee34acb7f43e2344c9e63e30f2bf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Feb 2017 12:12:33 -0600 Subject: [PATCH 096/755] Probably resolve WB-657: Better support of volume files with oblique sform: If an oblique volume is selected as the underlay, the viewing orientation will switch to oblique and orthogonal is removed from the menu. In addtion, when a slice index was changed while viewing an oblique volume, the slices changed to dramatically different values. Now, incrementing or decrementing the slice indices will adjust the corresponding coordinate by the size of voxel. --- ...rainBrowserWindowToolBarSliceSelection.cxx | 141 ++++++++++++++++-- .../BrainBrowserWindowToolBarSliceSelection.h | 10 +- src/GuiQt/OverlayViewController.cxx | 3 +- 3 files changed, 136 insertions(+), 18 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 788188845..d91e88365 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -210,6 +210,7 @@ m_parentToolBar(parentToolBar) m_volumeIndicesWidgetGroup->add(m_volumeIndicesXcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesYcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesZcoordSpinBox); + m_volumeIndicesWidgetGroup->add(m_volumeSliceProjectionTypeEnumComboBox->getWidget()); m_volumeIndicesWidgetGroup->add(m_volumeIdentificationUpdatesSlicesAction); } @@ -255,6 +256,40 @@ BrainBrowserWindowToolBarSliceSelection::updateContent(BrowserTabContent* browse } if (vf != NULL) { + /* + * Test selected file to see if it is an oblique volume file (not a CIFTI file) + */ + bool obliqueVolumeFlag = false; + VolumeFile* volumeFile = dynamic_cast(vf); + if (volumeFile != NULL) { + if ( ! volumeFile->isPlumb()) { + obliqueVolumeFlag = true; + } + } + + /* + * Update slice projection type for allowed projection types + */ + std::vector validSliceProjections; + validSliceProjections.push_back(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); + if ( ! obliqueVolumeFlag) { + validSliceProjections.push_back(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL); + } + m_volumeSliceProjectionTypeEnumComboBox->setupWithItems(validSliceProjections); + + /* + * If volume is oblique, change its projection type to oblique + */ + switch (browserTabContent->getSliceProjectionType()) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + if (obliqueVolumeFlag) { + browserTabContent->setSliceProjectionType(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); + } + break; + } + m_volumeIndicesAxialCheckBox->setChecked(browserTabContent->isSliceAxialEnabled()); m_volumeIndicesCoronalCheckBox->setChecked(browserTabContent->isSliceCoronalEnabled()); m_volumeIndicesParasagittalCheckBox->setChecked(browserTabContent->isSliceParasagittalEnabled()); @@ -432,29 +467,42 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialCheckBoxStateChanged( /** * Called when volume indices parasagittal spin box value is changed. + * + * @param sliceIndex + * New index of slice. */ void -BrainBrowserWindowToolBarSliceSelection::volumeIndicesParasagittalSpinBoxValueChanged(int /*i*/) +BrainBrowserWindowToolBarSliceSelection::volumeIndicesParasagittalSpinBoxValueChanged(int sliceIndex) { - this->readVolumeSliceIndicesAndUpdateSliceCoordinates(); + this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::PARASAGITTAL, + sliceIndex); } /** * Called when volume indices coronal spin box value is changed. + * + * @param sliceIndex + * New index of slice. */ void -BrainBrowserWindowToolBarSliceSelection::volumeIndicesCoronalSpinBoxValueChanged(int /*i*/) +BrainBrowserWindowToolBarSliceSelection::volumeIndicesCoronalSpinBoxValueChanged(int sliceIndex) { - this->readVolumeSliceIndicesAndUpdateSliceCoordinates(); + this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::CORONAL, + sliceIndex); } /** * Called when volume indices axial spin box value is changed. + * + * @param sliceIndex + * New index of slice. */ void -BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialSpinBoxValueChanged(int /*i*/) +BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialSpinBoxValueChanged(int sliceIndex) { - this->readVolumeSliceIndicesAndUpdateSliceCoordinates(); + + this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::AXIAL, + sliceIndex); } /** @@ -492,9 +540,15 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesZcoordSpinBoxValueChanged( /** * Read the slice indices and update the slice coordinates. + * + * @param viewPlane + * View plane whose slice index was changed + * @param sliceIndex + * New slice index. */ void -BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoordinates() +BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoordinates(const VolumeSliceViewPlaneEnum::Enum viewPlane, + const int64_t sliceIndex) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); @@ -515,12 +569,73 @@ BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoo } if (underlayVolumeFile != NULL) { - const int64_t parasagittalSlice = m_volumeIndicesParasagittalSpinBox->value(); - const int64_t coronalSlice = m_volumeIndicesCoronalSpinBox->value(); - const int64_t axialSlice = m_volumeIndicesAxialSpinBox->value(); - btc->setSliceIndexAxial(underlayVolumeFile, axialSlice); - btc->setSliceIndexCoronal(underlayVolumeFile, coronalSlice); - btc->setSliceIndexParasagittal(underlayVolumeFile, parasagittalSlice); + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = m_volumeSliceProjectionTypeEnumComboBox->getSelectedItem(); + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + float sx(1.0), sy(1.0), sz(1.0); + underlayVolumeFile->getVoxelSpacing(sx, sy, sz); + + switch (viewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + { + const int32_t diff = sliceIndex - btc->getSliceIndexAxial(underlayVolumeFile); + if (diff > 0) { + btc->setSliceCoordinateAxial(btc->getSliceCoordinateAxial() + sz); + } + else { + btc->setSliceCoordinateAxial(btc->getSliceCoordinateAxial() - sz); + } + } + break; + case VolumeSliceViewPlaneEnum::CORONAL: + { + const int32_t diff = sliceIndex - btc->getSliceIndexCoronal(underlayVolumeFile); + if (diff > 0) { + btc->setSliceCoordinateCoronal(btc->getSliceCoordinateCoronal() + sy); + } + else { + btc->setSliceCoordinateCoronal(btc->getSliceCoordinateCoronal() - sy); + } + } + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + { + const int32_t diff = sliceIndex - btc->getSliceIndexParasagittal(underlayVolumeFile); + if (diff > 0) { + btc->setSliceCoordinateParasagittal(btc->getSliceCoordinateParasagittal() + sx); + } + else { + btc->setSliceCoordinateParasagittal(btc->getSliceCoordinateParasagittal() - sx); + } + } + break; + } + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + switch (viewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + CaretAssert(0); + break; + case VolumeSliceViewPlaneEnum::AXIAL: + btc->setSliceIndexAxial(underlayVolumeFile, + sliceIndex); + break; + case VolumeSliceViewPlaneEnum::CORONAL: + btc->setSliceIndexCoronal(underlayVolumeFile, + sliceIndex); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + btc->setSliceIndexParasagittal(underlayVolumeFile, + sliceIndex); + break; + } + break; + } } this->updateSliceIndicesAndCoordinatesRanges(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h index 472d4dd92..9d436bba3 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h @@ -23,6 +23,7 @@ #include "BrainBrowserWindowToolBarComponent.h" +#include "VolumeSliceViewPlaneEnum.h" class QAction; class QCheckBox; @@ -52,9 +53,9 @@ namespace caret { void volumeIndicesParasagittalCheckBoxStateChanged(int state); void volumeIndicesCoronalCheckBoxStateChanged(int state); void volumeIndicesAxialCheckBoxStateChanged(int state); - void volumeIndicesParasagittalSpinBoxValueChanged(int i); - void volumeIndicesCoronalSpinBoxValueChanged(int i); - void volumeIndicesAxialSpinBoxValueChanged(int i); + void volumeIndicesParasagittalSpinBoxValueChanged(int sliceIndex); + void volumeIndicesCoronalSpinBoxValueChanged(int sliceIndex); + void volumeIndicesAxialSpinBoxValueChanged(int sliceIndex); void volumeIndicesXcoordSpinBoxValueChanged(double d); void volumeIndicesYcoordSpinBoxValueChanged(double d); void volumeIndicesZcoordSpinBoxValueChanged(double d); @@ -67,7 +68,8 @@ namespace caret { BrainBrowserWindowToolBarSliceSelection& operator=(const BrainBrowserWindowToolBarSliceSelection&); void readVolumeSliceCoordinatesAndUpdateSliceIndices(); - void readVolumeSliceIndicesAndUpdateSliceCoordinates(); + void readVolumeSliceIndicesAndUpdateSliceCoordinates(const VolumeSliceViewPlaneEnum::Enum viewPlane, + const int64_t sliceIndex); void updateSliceIndicesAndCoordinatesRanges(); BrainBrowserWindowToolBar* m_parentToolBar; diff --git a/src/GuiQt/OverlayViewController.cxx b/src/GuiQt/OverlayViewController.cxx index e626d8843..1c6747bcb 100644 --- a/src/GuiQt/OverlayViewController.cxx +++ b/src/GuiQt/OverlayViewController.cxx @@ -366,7 +366,6 @@ OverlayViewController::fileComboBoxSelected(int indx) updateOverlaySettingsEditor(); updateViewController(this->overlay); - updateGraphicsWindow(); if (file != NULL) { if (file->isVolumeMappable()) { @@ -376,6 +375,8 @@ OverlayViewController::fileComboBoxSelected(int indx) EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(browserWindowIndex).addToolBar().getPointer()); } } + + updateGraphicsWindow(); } /** -- GitLab From 8f42f35b3b29e2b0bc54f94f909af07a90c97cb4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Feb 2017 15:20:25 -0600 Subject: [PATCH 097/755] Data normalization selection on Map Settings dialog was not saved to data files. It is a file property and is now stored in file metadata. However, at this time VolumeFile does not support file metadata. --- src/Files/CaretMappableDataFile.cxx | 49 ++++++++++++++++++++---- src/Files/CaretMappableDataFile.h | 3 +- src/Files/CiftiFiberTrajectoryFile.cxx | 2 +- src/Files/CiftiFiberTrajectoryFile.h | 2 +- src/Files/CiftiMappableDataFile.cxx | 9 +++-- src/Files/CiftiMappableDataFile.h | 2 +- src/Files/GiftiTypeFile.cxx | 2 +- src/Files/GiftiTypeFile.h | 2 +- src/Files/VolumeFile.cxx | 2 +- src/Files/VolumeFile.h | 2 +- src/FilesBase/GiftiMetaDataXmlElements.h | 3 ++ 11 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 869f8128b..cf95ca2ee 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -32,6 +32,7 @@ #include "FastStatistics.h" #include "FileInformation.h" #include "GiftiLabelTable.h" +#include "GiftiMetaDataXmlElements.h" #include "Histogram.h" #include "LabelDrawingProperties.h" #include "PaletteColorMapping.h" @@ -52,8 +53,6 @@ CaretMappableDataFile::CaretMappableDataFile(const DataFileTypeEnum::Enum dataFi : CaretDataFile(dataFileType) { m_labelDrawingProperties.grabNew(new LabelDrawingProperties()); - - m_paletteNormalizationMode = PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; } /** @@ -98,7 +97,7 @@ CaretMappableDataFile::operator=(const CaretMappableDataFile& cmdf) void CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& cmdf) { - m_paletteNormalizationMode = cmdf.m_paletteNormalizationMode; + setPaletteNormalizationMode(cmdf.getPaletteNormalizationMode()); } // note: method is documented in header file @@ -303,7 +302,7 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute if (isMappedWithPalette()) { sceneClass->addEnumeratedType("m_paletteNormalizationMode", - m_paletteNormalizationMode); + getPaletteNormalizationMode()); if (sceneAttributes->isModifiedPaletteSettingsSavedToScene()) { std::vector pcmClassVector; @@ -380,8 +379,8 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr getPaletteNormalizationModesSupported(paletteNormalizationModes); if ( ! paletteNormalizationModes.empty()) { const PaletteNormalizationModeEnum::Enum defValue = paletteNormalizationModes[0]; - m_paletteNormalizationMode = sceneClass->getEnumeratedTypeValue("m_paletteNormalizationMode", - defValue); + setPaletteNormalizationMode(sceneClass->getEnumeratedTypeValue("m_paletteNormalizationMode", + defValue)); } const int32_t numMaps = getNumberOfMaps(); @@ -983,7 +982,33 @@ CaretMappableDataFile::getLabelDrawingProperties() const PaletteNormalizationModeEnum::Enum CaretMappableDataFile::getPaletteNormalizationMode() const { - return m_paletteNormalizationMode; + /* + * As of 24 feb 2017, volume file has never supported file metadata + */ + if (getDataFileType() == DataFileTypeEnum::VOLUME) { + return PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; + } + + PaletteNormalizationModeEnum::Enum modeValue = PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; + + const AString textValue = getFileMetaData()->get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); + bool validFlag = false; + modeValue = PaletteNormalizationModeEnum::fromName(textValue, &validFlag); + + if ( ! validFlag) { + std::vector validModes; + getPaletteNormalizationModesSupported(validModes); + + if ( ! validModes.empty()) { + CaretAssertVectorIndex(validModes, 0); + modeValue = validModes[0]; + } + else { + modeValue = PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; + } + } + + return modeValue; } /** @@ -995,7 +1020,15 @@ CaretMappableDataFile::getPaletteNormalizationMode() const void CaretMappableDataFile::setPaletteNormalizationMode(const PaletteNormalizationModeEnum::Enum mode) { - m_paletteNormalizationMode = mode; + /* + * As of 24 feb 2017, volume file has never supported file metadata + */ + if (getDataFileType() == DataFileTypeEnum::VOLUME) { + return; + } + + getFileMetaData()->set(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE, + PaletteNormalizationModeEnum::toName(mode)); } /** diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 039e3d8ab..f507152bd 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -371,7 +371,7 @@ namespace caret { * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ - virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) = 0; + virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const = 0; /** * @return The palette normalization mode for the file. @@ -464,7 +464,6 @@ namespace caret { CaretPointer m_labelDrawingProperties; - PaletteNormalizationModeEnum::Enum m_paletteNormalizationMode; }; #ifdef __CARET_MAPPABLE_DATA_FILE_DECLARE__ diff --git a/src/Files/CiftiFiberTrajectoryFile.cxx b/src/Files/CiftiFiberTrajectoryFile.cxx index c89dc1af8..59b2d5188 100644 --- a/src/Files/CiftiFiberTrajectoryFile.cxx +++ b/src/Files/CiftiFiberTrajectoryFile.cxx @@ -731,7 +731,7 @@ CiftiFiberTrajectoryFile::getMapLabelTable(const int32_t /*mapIndex*/) const * vector is assumed to be the default mode. */ void -CiftiFiberTrajectoryFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) +CiftiFiberTrajectoryFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); } diff --git a/src/Files/CiftiFiberTrajectoryFile.h b/src/Files/CiftiFiberTrajectoryFile.h index fad155832..607cc8ce9 100644 --- a/src/Files/CiftiFiberTrajectoryFile.h +++ b/src/Files/CiftiFiberTrajectoryFile.h @@ -108,7 +108,7 @@ namespace caret { virtual const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const; - virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut); + virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual void updateScalarColoringForMap(const int32_t mapIndex, const PaletteFile* paletteFile); diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 51f41cc4b..2ccf37d48 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -243,9 +243,10 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi * Note: The first palette normalization mode is assumed to * be the default mode. The method called is in a parent class. */ - if ( ! m_paletteNormalizationModesSupported.empty()) { - setPaletteNormalizationMode(m_paletteNormalizationModesSupported[0]); - } + CaretAssertToDoWarning(); +// if ( ! m_paletteNormalizationModesSupported.empty()) { +// setPaletteNormalizationMode(m_paletteNormalizationModesSupported[0]); +// } CaretAssert(m_dataReadingAccessMethod != DATA_ACCESS_METHOD_INVALID); CaretAssert(m_dataMappingAccessMethod != DATA_ACCESS_METHOD_INVALID); @@ -1941,7 +1942,7 @@ CiftiMappableDataFile::getMapLabelTable(const int32_t mapIndex) const * vector is assumed to be the default mode. */ void -CiftiMappableDataFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) +CiftiMappableDataFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut = m_paletteNormalizationModesSupported; } diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 1177db8d9..b89767a02 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -208,7 +208,7 @@ namespace caret { const float mostNegativeValueInclusive, const bool includeZeroValues); - virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut); + virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual int64_t getDataSizeUncompressedInBytes() const; diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 570b3a974..87dd314cf 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -744,7 +744,7 @@ GiftiTypeFile::isMappedWithPalette() const * vector is assumed to be the default mode. */ void -GiftiTypeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) +GiftiTypeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); diff --git a/src/Files/GiftiTypeFile.h b/src/Files/GiftiTypeFile.h index 854d3ca39..52e3b652f 100644 --- a/src/Files/GiftiTypeFile.h +++ b/src/Files/GiftiTypeFile.h @@ -146,7 +146,7 @@ namespace caret { virtual bool isMappedWithPalette() const; - virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut); + virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 0ff7e6ba3..fd19cb908 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -1131,7 +1131,7 @@ VolumeFile::isMappedWithPalette() const * vector is assumed to be the default mode. */ void -VolumeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) +VolumeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index e5e968f98..3bafc9ace 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -259,7 +259,7 @@ namespace caret { bool isMappedWithPalette() const; - virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut); + virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); diff --git a/src/FilesBase/GiftiMetaDataXmlElements.h b/src/FilesBase/GiftiMetaDataXmlElements.h index c2a51ac11..cbe4d01b6 100644 --- a/src/FilesBase/GiftiMetaDataXmlElements.h +++ b/src/FilesBase/GiftiMetaDataXmlElements.h @@ -205,6 +205,9 @@ namespace GiftiMetaDataXmlElements { /**name of palette color mapping stored in metadata */ static const AString METADATA_NAME_PALETTE_COLOR_MAPPING = "PaletteColorMapping"; + + /** name of palette normalization mode */ + static const AString METADATA_PALETTE_NORMALIZATION_MODE = "PaletteNormalizationMode"; } // namespace -- GitLab From 4bd42cb9ea2309acbf0784c64f0f96bf1daa06b7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Feb 2017 16:12:46 -0600 Subject: [PATCH 098/755] Removed initialization of palette normalization mode from CiftiMappableDataFile as it is now initialized in CaretMappableDataFile. --- src/Files/CiftiMappableDataFile.cxx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 2ccf37d48..71fc6d0db 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -239,15 +239,6 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi break; } - /* - * Note: The first palette normalization mode is assumed to - * be the default mode. The method called is in a parent class. - */ - CaretAssertToDoWarning(); -// if ( ! m_paletteNormalizationModesSupported.empty()) { -// setPaletteNormalizationMode(m_paletteNormalizationModesSupported[0]); -// } - CaretAssert(m_dataReadingAccessMethod != DATA_ACCESS_METHOD_INVALID); CaretAssert(m_dataMappingAccessMethod != DATA_ACCESS_METHOD_INVALID); CaretAssert(m_colorMappingMethod != COLOR_MAPPING_METHOD_INVALID); -- GitLab From 656189818aa69743ce9a9b21f71218d51247b38a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Feb 2017 16:17:39 -0600 Subject: [PATCH 099/755] Changed PaletteColorMappingSaxReader so that it no longer throws an exception if an unrecognized palette color mapping element is encountered. Instead a warning message is printed about the unrecognized element so that parsing can continue. This problem was encountered when new palette color mapping elements were added but the data file was read with an older version of wb_view. --- src/Palette/PaletteColorMappingSaxReader.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 3369f6db7..92c39b340 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -336,10 +336,10 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, else { std::ostringstream str; str - << "Unrecognized palette color mapping element \"" + << "Unrecognized (perhaps new) palette color mapping element \"" << qName.toStdString() << "\"."; - throw XmlSaxParserException(AString::fromStdString(str.str())); + warning(XmlSaxParserException(AString::fromStdString(str.str()))); } break; } -- GitLab From 2020fa47c884de18841c9f860789131e5671854b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Feb 2017 16:23:56 -0600 Subject: [PATCH 100/755] PaletteColorMapping::decodeFromStringXML() was leaking memory when the SAX parser threw an exception (delete was outside catch). This has been corrected by using a CaretPointer. --- src/Palette/PaletteColorMapping.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 25bd96c64..4872e42b7 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -387,7 +387,7 @@ PaletteColorMapping::decodeFromStringXML(const AString& xml) { PaletteColorMappingSaxReader saxReader(this); - XmlSaxParser* parser = XmlSaxParser::createXmlParser(); + CaretPointer parser(XmlSaxParser::createXmlParser()); try { parser->parseString(xml, &saxReader); } @@ -408,7 +408,6 @@ PaletteColorMapping::decodeFromStringXML(const AString& xml) << e.whatString().toStdString(); throw XmlException(AString::fromStdString(str.str())); } - delete parser; } /** -- GitLab From cb849e0d89d48fe9a9278313d3699ac87ae72760 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 2 Mar 2017 09:34:20 -0600 Subject: [PATCH 101/755] Resolve WB-666: If a spec file and a data file were specified as arguments when running wb_view from the command line, the files were loaded two times (spec file dialog appears, hit ok, files load, spec file dialog appears again...). --- src/Desktop/desktop.cxx | 228 ++++++++++++---------------------------- 1 file changed, 70 insertions(+), 158 deletions(-) diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index f2e662672..244dfa35d 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -265,12 +265,14 @@ messageHandlerForQt4(QtMsgType type, const char* msg) struct ProgramState { vector fileList; - int specLoadType; int windowSizeXY[2]; int windowPosXY[2]; int graphicsSizeXY[2]; bool showSplash; + AString specFileNameLoadWithDialog; + AString specFileNameLoadAll; + AString sceneFileName; AString sceneNameOrNumber; @@ -278,89 +280,6 @@ struct ProgramState }; -/* -// maximum mumber of lines the output console should have - -static const WORD MAX_CONSOLE_LINES = 500; -#include -#include -#include -#include -#include -#include - -void RedirectIOToConsole() -{ - - int hConHandle; - - long lStdHandle; - - CONSOLE_SCREEN_BUFFER_INFO coninfo; - - FILE *fp; - - // allocate a console for this app - - AllocConsole(); - - // set the screen buffer to be big enough to let us scroll text - - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - - &coninfo); - - coninfo.dwSize.Y = MAX_CONSOLE_LINES; - - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), - - coninfo.dwSize); - - // redirect unbuffered STDOUT to the console - - lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); - - hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); - - fp = _fdopen( hConHandle, "w" ); - - *stdout = *fp; - - setvbuf( stdout, NULL, _IONBF, 0 ); - - // redirect unbuffered STDIN to the console - - lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); - - hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); - - fp = _fdopen( hConHandle, "r" ); - - *stdin = *fp; - - setvbuf( stdin, NULL, _IONBF, 0 ); - - // redirect unbuffered STDERR to the console - - lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); - - hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); - - fp = _fdopen( hConHandle, "w" ); - - *stderr = *fp; - - setvbuf( stderr, NULL, _IONBF, 0 ); - - // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog - - // point to console as well - - ios::sync_with_stdio(); - -}*/ -//#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") - //declare the functions associated with command line void printHelp(const AString& progName); void parseCommandLine(const AString& progName, ProgramParameters* myParams, ProgramState& myState); @@ -368,8 +287,6 @@ int main(int argc, char* argv[]) { srand(time(NULL)); - //MS Windows code to allocate a new console, will have a preference to set this up - //RedirectIOToConsole(); int result; { /* @@ -447,7 +364,7 @@ main(int argc, char* argv[]) #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET - if (QGLFormat::hasOpenGL() == false) { + if ( ! QGLFormat::hasOpenGL()) { app.processEvents(); WuQMessageBox::errorOk(NULL, noOpenGLMessage); @@ -474,30 +391,6 @@ main(int argc, char* argv[]) */ CaretLogConfig(applicationInformation.getCompiledWithDebugStatus()); - //sanity check command line - bool haveSpec = false; - bool haveFiles = false; - for (int i = 0; i < (int)myState.fileList.size(); ++i) - { - if (myState.fileList[i].endsWith(".spec")) - { - if (haveSpec) - { - cerr << "error, cannot load multiple spec files at this time" << endl; - return -1; - } - haveSpec = true; - } else { - haveFiles = true; - } - } - //if error to have both data and spec files - /*if (haveFiles && haveSpec) - { - cerr << "error, cannot specify both spec files and data files on the command line" << endl; - return -1; - }//*/ - /* * Enabled the desired splash screen based upon user preferences * and command line options. Do not show selection splash screen @@ -505,14 +398,8 @@ main(int argc, char* argv[]) */ CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); bool showSelectionSplashScreen = preferences->isSplashScreenEnabled(); - if (myState.fileList.empty() == false) { - showSelectionSplashScreen = false; - } - if (myState.sceneFileName.isEmpty() == false) { - showSelectionSplashScreen = false; - } bool showImageSplashScreen = (! showSelectionSplashScreen); - if (myState.showSplash == false) { + if ( ! myState.showSplash) { showSelectionSplashScreen = false; showImageSplashScreen = false; } @@ -550,20 +437,16 @@ main(int argc, char* argv[]) /* * Now that events have processed, see if there was a request for - * a data file to open + * a data file to open. */ const AString dataFileNameFromOS = GuiManager::get()->getNameOfDataFileToOpenAfterStartup(); - if (dataFileNameFromOS.isEmpty() == false) { - myState.fileList.push_back(dataFileNameFromOS); + if ( ! dataFileNameFromOS.isEmpty()) { showSelectionSplashScreen = false; if (dataFileNameFromOS.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { - haveSpec = true; - haveFiles = false; - myState.specLoadType = 0; + myState.specFileNameLoadWithDialog = dataFileNameFromOS; } else { - haveSpec = false; - haveFiles = true; + myState.fileList.push_back(dataFileNameFromOS); } } @@ -582,15 +465,11 @@ main(int argc, char* argv[]) const QString dataFileName = splashScreen.getSelectedDataFileName(); if ( ! dataFileName.isEmpty()) { myState.fileList.clear(); - myState.fileList.push_back(dataFileName); - if (dataFileName.endsWith(DataFileTypeEnum::SPECIFICATION)) { - myState.specLoadType = 0; // which means use BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE; - haveSpec = true; - haveFiles = false; + if (dataFileName.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { + myState.specFileNameLoadWithDialog = dataFileName; } else { - haveSpec = false; - haveFiles = true; + myState.fileList.push_back(dataFileName); } } } @@ -642,27 +521,21 @@ main(int argc, char* argv[]) myWindow->setGraphicsWidgetFixedSize(myState.graphicsSizeXY[0], myState.graphicsSizeXY[1]); } - //use command line - if (haveFiles) - { - myWindow->loadFilesFromCommandLine(myState.fileList, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG);//second parameter unused in this case + if ( ! myState.specFileNameLoadAll.isEmpty()) { + myWindow->loadFilesFromCommandLine({ myState.specFileNameLoadAll }, + BrainBrowserWindow::LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE); } - if (haveSpec) - { - switch (myState.specLoadType) - { - case 0://dialog - myWindow->loadFilesFromCommandLine(myState.fileList, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE); - break; - case 1://load all - myWindow->loadFilesFromCommandLine(myState.fileList, BrainBrowserWindow::LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE); - break; - default: - CaretAssert(false); - } + else if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { + myWindow->loadFilesFromCommandLine({ myState.specFileNameLoadWithDialog }, + BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE); } - if (myState.sceneFileName.isEmpty() == false) { + if (! myState.fileList.empty()) { + myWindow->loadFilesFromCommandLine(myState.fileList, + BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG); + } + + if ( ! myState.sceneFileName.isEmpty()) { myWindow->loadSceneFromCommandLine(myState.sceneFileName, myState.sceneNameOrNumber); } @@ -812,10 +685,6 @@ void printHelp(const AString& progName) iter++) { cout << " " << qPrintable(LogLevelEnum::toName(*iter)) << endl; } -// foreach (LogLevelEnum::Enum level , logLevels) { -// for (LogLevelEnum::Enum level : logLevels) { -// cout << " " << qPrintable(LogLevelEnum::toName(level)) << endl; -// } cout << endl @@ -860,6 +729,8 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog { bool hasFatalError = false; + const AString moreThanOneSpecFileErrorMessage("More than one spec file is NOT allowed in options"); + try { while (myParams->hasNext()) { @@ -911,7 +782,16 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog hasFatalError = true; } } else if (thisParam == "-spec-load-all") { - myState.specLoadType = 1; + if ( ! myState.specFileNameLoadAll.isEmpty()) { + cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; + } + else if (myParams->hasNext()) { + myState.specFileNameLoadAll = myParams->nextString("Spec File Name"); + } + else { + cerr << "Missing spec file name for \"-spec\" option" << endl; + hasFatalError = true; + } } else if (thisParam == "-graphics-size") { if (myParams->hasNext()) { myState.graphicsSizeXY[0] = myParams->nextInt("Graphics Size X"); @@ -978,7 +858,18 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog hasFatalError = true; } } else { - myState.fileList.push_back(thisParam); + if (thisParam.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { + if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { + cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; + hasFatalError = true; + } + else { + myState.specFileNameLoadWithDialog = thisParam; + } + } + else { + myState.fileList.push_back(thisParam); + } } } } @@ -987,16 +878,37 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog hasFatalError = true; } + if ( ( ! myState.specFileNameLoadWithDialog.isEmpty()) + && ( ! myState.specFileNameLoadAll.isEmpty())) { + cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; + hasFatalError = true; + } + if (hasFatalError) { exit(-1); } + + /* + * If any files are listed, disable splash screen + */ + if ( ! myState.fileList.empty()) { + myState.showSplash = false; + } + if ( ! myState.sceneFileName.isEmpty()) { + myState.showSplash = false; + } + if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { + myState.showSplash = false; + } + if ( ! myState.specFileNameLoadAll.isEmpty()) { + myState.showSplash = false; + } } ProgramState::ProgramState() { sceneFileName = ""; sceneNameOrNumber = ""; - specLoadType = 0;//0: use spec window, 1: all windowSizeXY[0] = -1; windowSizeXY[1] = -1; windowPosXY[0] = -1; -- GitLab From b054c724fc0962ba74f6d656ebf663c9906d08d6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 3 Mar 2017 15:40:50 -0600 Subject: [PATCH 102/755] Added file and map metadata for VolumeFile. It is needed to store the data normalization selection as part of WB-664 in the file metadata. --- src/Files/CaretVolumeExtension.cxx | 87 +++++++++++++++++++++++++++++- src/Files/CaretVolumeExtension.h | 13 ++++- src/Files/VolumeFile.cxx | 66 ++++++++++++++++++----- src/Files/VolumeFile.h | 5 +- src/FilesBase/GiftiMetaData.cxx | 10 ++++ src/FilesBase/GiftiMetaData.h | 2 + 6 files changed, 165 insertions(+), 18 deletions(-) diff --git a/src/Files/CaretVolumeExtension.cxx b/src/Files/CaretVolumeExtension.cxx index 07394d7c3..3621e16ed 100644 --- a/src/Files/CaretVolumeExtension.cxx +++ b/src/Files/CaretVolumeExtension.cxx @@ -20,6 +20,8 @@ #include "CaretVolumeExtension.h" #include "XmlSaxParser.h" +#include "GiftiMetaData.h" +#include "GiftiMetaDataSaxReader.h" #include "GiftiXmlElements.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" @@ -46,6 +48,7 @@ CaretVolumeExtension::clear() { m_comment.clear(); m_date.clear(); m_attributes.clear(); + m_metadata.grabNew(NULL); } void CaretVolumeExtension::readFromXmlString(const AString& s) @@ -75,6 +78,11 @@ void CaretVolumeExtension::writeAsXML(XmlWriter& xmlWriter) { m_attributes[i]->writeAsXML(xmlWriter, i); } + if (m_metadata != NULL) { // write metadata only if it is not empty + if ( ! m_metadata->isEmpty()) { + m_metadata->writeAsXML(xmlWriter); + } + } xmlWriter.writeEndElement();//just to make it clean xmlWriter.writeEndDocument();//so, this just flushes } @@ -114,6 +122,11 @@ void SubvolumeAttributes::writeAsXML(XmlWriter& xmlWriter, int index) typeString = "Unknown"; } xmlWriter.writeElementCData(CARET_VOL_EXT_VI_TYPE, typeString); + if (m_metadata != NULL) { // write metadata only if it is not empty + if ( ! m_metadata->isEmpty()) { + m_metadata->writeAsXML(xmlWriter); + } + } xmlWriter.writeEndElement(); } @@ -144,6 +157,14 @@ void CaretVolumeExtensionXMLReader::characters(const char* ch) CaretAssert(m_paletteReader != NULL); m_paletteReader->characters(ch); break; + case ROOT_META_DATA: + case VI_META_DATA: + CaretAssert(m_metadataReader); + m_metadataReader->characters(ch); + break; + case IGNORING_INVALID_ELEMENT: + m_ignoringInvalidElementContent.append(AString(ch).trimmed()); + break; default: m_charDataStack.back() += ch; } @@ -217,6 +238,18 @@ void CaretVolumeExtensionXMLReader::endElement(const AString& namespaceURI, cons popState = false; } break; + case ROOT_META_DATA: + case VI_META_DATA: + CaretAssert(m_metadataReader); + m_metadataReader->endElement(namespaceURI, localName, qualifiedName); + if (qualifiedName == GiftiXmlElements::TAG_METADATA) { + m_metadataReader->endDocument(); + m_metadataReader.grabNew(NULL); + } + else { + popState = false; + } + break; case VOLUME_TYPE: CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); if (elemCharData == "Anatomy") @@ -236,6 +269,24 @@ void CaretVolumeExtensionXMLReader::endElement(const AString& namespaceURI, cons m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::UNKNOWN; } break; + case IGNORING_INVALID_ELEMENT: + if (qualifiedName == m_ignoringInvalidElementName) { + /* finished parsing of invalid element */ + warning(XmlSaxParserException("Unrecognized content discarded (attributes/whitespace removed): <" + + qualifiedName + + ">" + + m_ignoringInvalidElementContent + + "")); + m_ignoringInvalidElementName = ""; + m_ignoringInvalidElementContent = ""; + } + else { + m_ignoringInvalidElementContent.append(""); + popState = false; + } + break; } if (popState) { @@ -300,6 +351,12 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri m_toFill->m_attributes.resize(m_viIndex + 1);//don't worry, CaretPointer copy is relatively cheap } m_toFill->m_attributes[m_viIndex].grabNew(new SubvolumeAttributes()); + } else if (qName == GiftiXmlElements::TAG_METADATA) { + nextState = ROOT_META_DATA; + m_toFill->m_metadata.grabNew(new GiftiMetaData); + m_metadataReader.grabNew(new GiftiMetaDataSaxReader(m_toFill->m_metadata)); + m_metadataReader->startDocument(); + m_metadataReader->startElement(uri, localName, qName, atts); }//anything else gets caught in INVALID below break; case VOLUME_INFORMATION: @@ -324,6 +381,13 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri m_paletteReader.grabNew(new PaletteColorMappingSaxReader(m_toFill->m_attributes[m_viIndex]->m_palette)); m_paletteReader->startDocument(); m_paletteReader->startElement(uri, localName, qName, atts); + } else if (qName == GiftiXmlElements::TAG_METADATA) { + nextState = VI_META_DATA; + CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); + m_toFill->m_attributes[m_viIndex]->m_metadata.grabNew(new GiftiMetaData); + m_metadataReader.grabNew(new GiftiMetaDataSaxReader(m_toFill->m_attributes[m_viIndex]->m_metadata)); + m_metadataReader->startDocument(); + m_metadataReader->startElement(uri, localName, qName, atts); } else if (qName == CARET_VOL_EXT_VI_TYPE) { nextState = VOLUME_TYPE; } @@ -341,13 +405,34 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri CaretAssert(m_paletteReader != NULL); m_paletteReader->startElement(uri, localName, qName, atts); break; + case ROOT_META_DATA: + case VI_META_DATA: + addState = false; + CaretAssert(m_metadataReader); + m_metadataReader->startElement(uri, localName, qName, atts); + break; + case IGNORING_INVALID_ELEMENT: + addState = false; + m_ignoringInvalidElementContent.append("<" + qName + ">"); + break; } } if (addState) { if (nextState == INVALID) { - throw XmlSaxParserException(AString("CaretVolumeExtension encountered an unexpected element: ") + invalidInfo); + /* + * If the invalid element name is not empty, + * then we are processing child elements of the + * invalid element. + */ + if (m_ignoringInvalidElementName.isEmpty()) { + m_ignoringInvalidElementName = qName; + nextState = IGNORING_INVALID_ELEMENT; + } +// else { +// throw XmlSaxParserException(AString("CaretVolumeExtension encountered an unexpected element: ") + invalidInfo); +// } } m_stateStack.push_back(nextState); m_charDataStack.push_back(AString()); diff --git a/src/Files/CaretVolumeExtension.h b/src/Files/CaretVolumeExtension.h index 3ac8c33d6..c0b795ef4 100644 --- a/src/Files/CaretVolumeExtension.h +++ b/src/Files/CaretVolumeExtension.h @@ -29,9 +29,12 @@ #include "XmlSaxParserHandlerInterface.h" #include "PaletteColorMappingSaxReader.h" #include "GiftiLabelTableSaxReader.h" +#include "GiftiMetaDataSaxReader.h" + namespace caret { + class GiftiMetaData; struct StudyMetadataLinkSet { @@ -53,6 +56,7 @@ namespace caret AString m_comment; AString m_guiLabel; CaretPointer m_labelTable; + CaretPointer m_metadata; StudyMetadataLinkSet m_studyMetadata; CaretPointer m_palette; VolumeType m_type; @@ -62,6 +66,7 @@ namespace caret struct CaretVolumeExtension { + mutable CaretPointer m_metadata; AString m_comment; AString m_date;//TODO: make a class to handle ISO-8601 dates std::vector > m_attributes; @@ -84,7 +89,10 @@ namespace caret LABEL_TABLE, STUDY_META_DATA_LINK_SET, PALETTE_COLOR_MAPPING, - VOLUME_TYPE + VOLUME_TYPE, + ROOT_META_DATA, + VI_META_DATA, + IGNORING_INVALID_ELEMENT }; std::vector m_stateStack; CaretVolumeExtension* m_toFill; @@ -92,6 +100,9 @@ namespace caret int m_viIndex; CaretPointer m_paletteReader; CaretPointer m_labelReader; + CaretPointer m_metadataReader; + AString m_ignoringInvalidElementName; + AString m_ignoringInvalidElementContent; CaretVolumeExtensionXMLReader();//disallow default construction CaretVolumeExtensionXMLReader(const CaretVolumeExtensionXMLReader&);//disallow copy CaretVolumeExtensionXMLReader& operator=(const CaretVolumeExtensionXMLReader&);//disallow assignment diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index fd19cb908..ecf208bce 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -645,7 +645,7 @@ void VolumeFile::validateMembers() } } - setPaletteNormalizationMode(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); + //setPaletteNormalizationMode(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_singleSliceFlag = false; if ((dimensions[0] == 1) @@ -697,6 +697,8 @@ VolumeFile::clearModified() CaretMappableDataFile::clearModified(); clearModifiedVolumeBase(); + getFileMetaData()->clearModified(); + const int32_t numMaps = getNumberOfMaps(); if (isMappedWithPalette()) { @@ -710,6 +712,10 @@ VolumeFile::clearModified() getMapLabelTable(i)->clearModified(); } } + + for (int32_t i = 0; i < numMaps; i++) { + getMapMetaData(i)->clearModified(); + } } /** @@ -727,6 +733,10 @@ VolumeFile::isModifiedExcludingPaletteColorMapping() const return true; } + if (getFileMetaData()->isModified()) { + return true; + } + const int32_t numMaps = getNumberOfMaps(); if (isMappedWithLabelTable()) { for (int32_t i = 0; i < numMaps; i++) { @@ -735,6 +745,11 @@ VolumeFile::isModifiedExcludingPaletteColorMapping() const } } } + for (int32_t i = 0; i < numMaps; i++) { + if (getMapMetaData(i)->isModified()) { + return true; + } + } return false; } @@ -797,22 +812,22 @@ VolumeFile::setMapName(const int32_t mapIndex, const GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) const { - CaretAssertVectorIndex(m_brickAttributes, mapIndex); - if (m_brickAttributes[mapIndex].m_metadata == NULL) + CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); + if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) { - m_brickAttributes[mapIndex].m_metadata.grabNew(new GiftiMetaData()); + m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); } - return m_brickAttributes[mapIndex].m_metadata; + return m_caretVolExt.m_attributes[mapIndex]->m_metadata; } GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) { - CaretAssertVectorIndex(m_brickAttributes, mapIndex); - if (m_brickAttributes[mapIndex].m_metadata == NULL) + CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); + if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) { - m_brickAttributes[mapIndex].m_metadata.grabNew(new GiftiMetaData()); + m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); } - return m_brickAttributes[mapIndex].m_metadata; + return m_caretVolExt.m_attributes[mapIndex]->m_metadata; } void VolumeFile::checkStatisticsValid() @@ -1050,6 +1065,31 @@ VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, return m_fileHistorgramLimitedValues; } +/** + * @return Pointer to file's metadata. + */ +GiftiMetaData* +VolumeFile::getFileMetaData() +{ + if (m_caretVolExt.m_metadata == NULL) { + m_caretVolExt.m_metadata.grabNew(new GiftiMetaData); + } + return m_caretVolExt.m_metadata; +} + +/** + * @return Pointer to file's metadata. + */ +const GiftiMetaData* +VolumeFile::getFileMetaData() const +{ + if (m_caretVolExt.m_metadata == NULL) { + m_caretVolExt.m_metadata.grabNew(new GiftiMetaData); + } + return m_caretVolExt.m_metadata; +} + + /** * Get all data for a volume file. If the file is very * large this method may take a large amount of time! @@ -1262,12 +1302,12 @@ VolumeFile::isMappedWithRGBA() const AString VolumeFile::getMapUniqueID(const int32_t mapIndex) const { - CaretAssertVectorIndex(m_brickAttributes, mapIndex); - if (m_brickAttributes[mapIndex].m_metadata == NULL) + CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); + if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) { - m_brickAttributes[mapIndex].m_metadata.grabNew(new GiftiMetaData()); + m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); } - return m_brickAttributes[mapIndex].m_metadata->getUniqueID(); + return m_caretVolExt.m_attributes[mapIndex]->m_metadata->getUniqueID(); } /** diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index 3bafc9ace..03752548a 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -68,7 +68,6 @@ namespace caret { float m_histogramLimitedValuesLeastNegativeValueInclusive; float m_histogramLimitedValuesMostNegativeValueInclusive; bool m_histogramLimitedValuesIncludeZeroValues; - CaretPointer m_metadata;//NOTE: does not get saved currently! }; mutable std::vector m_brickAttributes;//because statistics and metadata construct lazily @@ -209,12 +208,12 @@ namespace caret { /** * @return Get access to the file's metadata. */ - GiftiMetaData* getFileMetaData() { return NULL; }//doesn't seem to be a spot for generic metadata in the nifti caret extension + GiftiMetaData* getFileMetaData(); /** * @return Get access to unmodifiable file's metadata. */ - const GiftiMetaData* getFileMetaData() const { return NULL; } + const GiftiMetaData* getFileMetaData() const; bool isSurfaceMappable() const { return false; } diff --git a/src/FilesBase/GiftiMetaData.cxx b/src/FilesBase/GiftiMetaData.cxx index 1364ebbe9..aff711a87 100644 --- a/src/FilesBase/GiftiMetaData.cxx +++ b/src/FilesBase/GiftiMetaData.cxx @@ -677,3 +677,13 @@ GiftiMetaData::isModified() const return this->modifiedFlag; } +/** + * Is the metadata empty (no metadata)? + */ +bool +GiftiMetaData::isEmpty() const +{ + return this->metadata.empty(); +} + + diff --git a/src/FilesBase/GiftiMetaData.h b/src/FilesBase/GiftiMetaData.h index 619d33e67..589c9bc7a 100644 --- a/src/FilesBase/GiftiMetaData.h +++ b/src/FilesBase/GiftiMetaData.h @@ -129,6 +129,8 @@ public: void resetUniqueIdentifier(); + bool isEmpty() const; + private: void readEntry(QXmlStreamReader& xml); -- GitLab From ac0b2cbae02a3775ff779ee91ee89b518e202964 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 3 Mar 2017 15:42:09 -0600 Subject: [PATCH 103/755] Resolve WB-664 Data normalization selection should be saved in file: The data normalization is file property and its status is saved in the file's metadata. This data normalization is no longer saved to the scene but if found in an older scene, the value will be applied. --- src/Files/CaretMappableDataFile.cxx | 42 ++++++++++++++++------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index cf95ca2ee..97bd7d4fe 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -301,8 +301,12 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute "m_labelDrawingProperties")); if (isMappedWithPalette()) { - sceneClass->addEnumeratedType("m_paletteNormalizationMode", - getPaletteNormalizationMode()); + /* + * 03 March 2017 + * Note: Palette (m_paletteNormalizationMode) normalization is no + * longer added to scenes since the palette normalization is a file + * property stored in the file's metadata. + */ if (sceneAttributes->isModifiedPaletteSettingsSavedToScene()) { std::vector pcmClassVector; @@ -375,12 +379,26 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr sceneClass->getClass("m_labelDrawingProperties")); if (isMappedWithPalette()) { + /* + * Palette normalization was no longer saved to scenes after + * palette normalization was saved in mappable files's metadata. + */ std::vector paletteNormalizationModes; getPaletteNormalizationModesSupported(paletteNormalizationModes); if ( ! paletteNormalizationModes.empty()) { - const PaletteNormalizationModeEnum::Enum defValue = paletteNormalizationModes[0]; - setPaletteNormalizationMode(sceneClass->getEnumeratedTypeValue("m_paletteNormalizationMode", - defValue)); + const AString paletteNormStringValue = sceneClass->getEnumeratedTypeValueAsString("m_paletteNormalizationMode"); + if ( ! paletteNormStringValue.isEmpty()) { + bool validFlag = false; + const PaletteNormalizationModeEnum::Enum palNormValue = PaletteNormalizationModeEnum::fromName(paletteNormStringValue, + &validFlag); + if (validFlag) { + if (std::find(paletteNormalizationModes.begin(), + paletteNormalizationModes.end(), + palNormValue) != paletteNormalizationModes.end()) { + setPaletteNormalizationMode(palNormValue); + } + } + } } const int32_t numMaps = getNumberOfMaps(); @@ -982,13 +1000,6 @@ CaretMappableDataFile::getLabelDrawingProperties() const PaletteNormalizationModeEnum::Enum CaretMappableDataFile::getPaletteNormalizationMode() const { - /* - * As of 24 feb 2017, volume file has never supported file metadata - */ - if (getDataFileType() == DataFileTypeEnum::VOLUME) { - return PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; - } - PaletteNormalizationModeEnum::Enum modeValue = PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; const AString textValue = getFileMetaData()->get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); @@ -1020,13 +1031,6 @@ CaretMappableDataFile::getPaletteNormalizationMode() const void CaretMappableDataFile::setPaletteNormalizationMode(const PaletteNormalizationModeEnum::Enum mode) { - /* - * As of 24 feb 2017, volume file has never supported file metadata - */ - if (getDataFileType() == DataFileTypeEnum::VOLUME) { - return; - } - getFileMetaData()->set(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE, PaletteNormalizationModeEnum::toName(mode)); } -- GitLab From 5910fb6043ba40d2f6cc7285a5664835e8c3d66a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 6 Mar 2017 11:31:26 -0600 Subject: [PATCH 104/755] Fixed XmlWriter's writeStartElement method with attributes so that it does not add a space between the element name and '>' if there are no attributes. --- src/Xml/XmlWriter.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Xml/XmlWriter.cxx b/src/Xml/XmlWriter.cxx index 04bb76ead..6a71a4fc6 100644 --- a/src/Xml/XmlWriter.cxx +++ b/src/Xml/XmlWriter.cxx @@ -320,13 +320,18 @@ XmlWriter::writeStartElement(const AString& localName) { void XmlWriter::writeStartElement(const AString& localName, const XmlAttributes& attributes) { + int32_t numAtts = attributes.getNumberOfAttributes(); + if (numAtts <= 0) { + writeStartElement(localName); + return; + } + this->writeIndentation(); this->writeTextToOutputStream("<" + localName + " "); int32_t attIndentSpaces = localName.length() + 2; AString attIndentString(attIndentSpaces, ' '); - int32_t numAtts = attributes.getNumberOfAttributes(); for (int32_t i = 0; i < numAtts; i++) { if (i > 0) { this->writeIndentation(); -- GitLab From 64bfd0b74a4bbbb2d09af387e35afa6e90a7a02d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 6 Mar 2017 14:29:38 -0600 Subject: [PATCH 105/755] Moved code out of CaretVolumeExtension for handling unexpected XML elements while parsing into its own class (XmlUnexpectedElementSaxParser) so that it can be used by other SAX parsers. --- src/Files/CaretVolumeExtension.cxx | 54 +++---- src/Files/CaretVolumeExtension.h | 6 +- src/Xml/CMakeLists.txt | 10 +- src/Xml/XmlUnexpectedElementSaxParser.cxx | 172 ++++++++++++++++++++++ src/Xml/XmlUnexpectedElementSaxParser.h | 94 ++++++++++++ 5 files changed, 302 insertions(+), 34 deletions(-) create mode 100644 src/Xml/XmlUnexpectedElementSaxParser.cxx create mode 100644 src/Xml/XmlUnexpectedElementSaxParser.h diff --git a/src/Files/CaretVolumeExtension.cxx b/src/Files/CaretVolumeExtension.cxx index 3621e16ed..305fa9e55 100644 --- a/src/Files/CaretVolumeExtension.cxx +++ b/src/Files/CaretVolumeExtension.cxx @@ -27,6 +27,7 @@ #include "PaletteColorMappingSaxReader.h" #include "PaletteColorMappingXmlElements.h" #include "CaretLogger.h" +#include "XmlUnexpectedElementSaxParser.h" #include using namespace caret; @@ -141,6 +142,7 @@ CaretVolumeExtensionXMLReader::CaretVolumeExtensionXMLReader(CaretVolumeExtensio CaretAssert(toFill != NULL); m_toFill = toFill; m_viIndex = -1; + m_unexpectedXmlElementSaxParser.grabNew(NULL); } void CaretVolumeExtensionXMLReader::characters(const char* ch) @@ -162,8 +164,9 @@ void CaretVolumeExtensionXMLReader::characters(const char* ch) CaretAssert(m_metadataReader); m_metadataReader->characters(ch); break; - case IGNORING_INVALID_ELEMENT: - m_ignoringInvalidElementContent.append(AString(ch).trimmed()); + case UNEXPECTED_XML: + CaretAssert(m_unexpectedXmlElementSaxParser); + m_unexpectedXmlElementSaxParser->characters(ch); break; default: m_charDataStack.back() += ch; @@ -269,22 +272,21 @@ void CaretVolumeExtensionXMLReader::endElement(const AString& namespaceURI, cons m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::UNKNOWN; } break; - case IGNORING_INVALID_ELEMENT: - if (qualifiedName == m_ignoringInvalidElementName) { - /* finished parsing of invalid element */ - warning(XmlSaxParserException("Unrecognized content discarded (attributes/whitespace removed): <" - + qualifiedName - + ">" - + m_ignoringInvalidElementContent - + "")); - m_ignoringInvalidElementName = ""; - m_ignoringInvalidElementContent = ""; - } - else { - m_ignoringInvalidElementContent.append(""); - popState = false; + case UNEXPECTED_XML: + CaretAssert(m_unexpectedXmlElementSaxParser); + switch (m_unexpectedXmlElementSaxParser->endElement(namespaceURI, localName, qualifiedName)) { + case XmlUnexpectedElementSaxParser::ReturnCodeEnum::DONE: + warning(XmlSaxParserException("Unexpected XML ignored:\n" + + m_unexpectedXmlElementSaxParser->getUnexpectedContentXML())); + m_unexpectedXmlElementSaxParser.grabNew(NULL); + break; + case XmlUnexpectedElementSaxParser::ReturnCodeEnum::ERROR: + throw XmlSaxParserException("Processing of unexpected elements failed: " + + m_unexpectedXmlElementSaxParser->getUnexpectedContentXML()); + break; + case XmlUnexpectedElementSaxParser::ReturnCodeEnum::NOT_DONE: + popState = false; + break; } break; } @@ -411,9 +413,10 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri CaretAssert(m_metadataReader); m_metadataReader->startElement(uri, localName, qName, atts); break; - case IGNORING_INVALID_ELEMENT: + case UNEXPECTED_XML: addState = false; - m_ignoringInvalidElementContent.append("<" + qName + ">"); + CaretAssert(m_unexpectedXmlElementSaxParser); + m_unexpectedXmlElementSaxParser->startElement(uri, localName, qName, atts); break; } } @@ -426,13 +429,10 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri * then we are processing child elements of the * invalid element. */ - if (m_ignoringInvalidElementName.isEmpty()) { - m_ignoringInvalidElementName = qName; - nextState = IGNORING_INVALID_ELEMENT; - } -// else { -// throw XmlSaxParserException(AString("CaretVolumeExtension encountered an unexpected element: ") + invalidInfo); -// } + CaretAssert(m_unexpectedXmlElementSaxParser == NULL); + m_unexpectedXmlElementSaxParser.grabNew(new XmlUnexpectedElementSaxParser()); + m_unexpectedXmlElementSaxParser->startElement(uri, localName, qName, atts); + nextState = UNEXPECTED_XML; } m_stateStack.push_back(nextState); m_charDataStack.push_back(AString()); diff --git a/src/Files/CaretVolumeExtension.h b/src/Files/CaretVolumeExtension.h index c0b795ef4..4a40afefe 100644 --- a/src/Files/CaretVolumeExtension.h +++ b/src/Files/CaretVolumeExtension.h @@ -35,6 +35,7 @@ namespace caret { class GiftiMetaData; + class XmlUnexpectedElementSaxParser; struct StudyMetadataLinkSet { @@ -92,7 +93,7 @@ namespace caret VOLUME_TYPE, ROOT_META_DATA, VI_META_DATA, - IGNORING_INVALID_ELEMENT + UNEXPECTED_XML }; std::vector m_stateStack; CaretVolumeExtension* m_toFill; @@ -101,8 +102,7 @@ namespace caret CaretPointer m_paletteReader; CaretPointer m_labelReader; CaretPointer m_metadataReader; - AString m_ignoringInvalidElementName; - AString m_ignoringInvalidElementContent; + CaretPointer m_unexpectedXmlElementSaxParser; CaretVolumeExtensionXMLReader();//disallow default construction CaretVolumeExtensionXMLReader(const CaretVolumeExtensionXMLReader&);//disallow copy CaretVolumeExtensionXMLReader& operator=(const CaretVolumeExtensionXMLReader&);//disallow assignment diff --git a/src/Xml/CMakeLists.txt b/src/Xml/CMakeLists.txt index a75c1bbba..3b5f09631 100644 --- a/src/Xml/CMakeLists.txt +++ b/src/Xml/CMakeLists.txt @@ -22,22 +22,24 @@ ENDIF () # Create a Library # ADD_LIBRARY(Xml -XmlWriter.h -XmlException.h XmlAttributes.h +XmlException.h XmlSaxParser.h XmlSaxParserException.h XmlSaxParserHandlerInterface.h XmlSaxParserWithQt.h +XmlUnexpectedElementSaxParser.h XmlUtilities.h +XmlWriter.h -XmlWriter.cxx -XmlException.cxx XmlAttributes.cxx +XmlException.cxx XmlSaxParser.cxx XmlSaxParserException.cxx XmlSaxParserWithQt.cxx +XmlUnexpectedElementSaxParser.cxx XmlUtilities.cxx +XmlWriter.cxx ) # diff --git a/src/Xml/XmlUnexpectedElementSaxParser.cxx b/src/Xml/XmlUnexpectedElementSaxParser.cxx new file mode 100644 index 000000000..6b12837d5 --- /dev/null +++ b/src/Xml/XmlUnexpectedElementSaxParser.cxx @@ -0,0 +1,172 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __XML_UNEXPECTED_ELEMENT_SAX_PARSER_DECLARE__ +#include "XmlUnexpectedElementSaxParser.h" +#undef __XML_UNEXPECTED_ELEMENT_SAX_PARSER_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::XmlUnexpectedElementSaxParser + * \brief Assists with parsing unexpected elements in XML. + * \ingroup Xml + * + * Assists with processing unexpected XML elements that may actually be new elements + * or elements that may have been removed. It allows the XML parser to skip these + * new elements so that reading of XML does not prematurely terminate. It is able + * to handle nested child elements with the same name. It concludes processing when + * an element name that matches that passed to the first startElement() method and + * all children have been processed. + * + * When an unexpected element is encountered: + * (1) Create an instance of this class and call the startElement() method; + * (2) Call startElement(), characters() and endElement() methods of this class + * until endElement() returns a 'Done' status. + * (3) Call getUnexpectedContentXML() method to get/print the unexpected XML. + * (4) Destroy the instance of this class. + */ + +/** + * Constructor. + */ +XmlUnexpectedElementSaxParser::XmlUnexpectedElementSaxParser() +: CaretObject() +{ + m_textStreamString.reserve(1000); + m_textStream = std::unique_ptr(new QTextStream(&m_textStreamString, + QIODevice::WriteOnly)); + m_xmlWriter = std::unique_ptr(new XmlWriter(*m_textStream)); +} + +/** + * Destructor. + */ +XmlUnexpectedElementSaxParser::~XmlUnexpectedElementSaxParser() +{ +} + +/* + * Process characters. + * + * @param ch The characters from the XML document. + */ +void +XmlUnexpectedElementSaxParser::characters(const char* ch) +{ + if (AString(ch).trimmed().isEmpty()) { + /* all white space */ + return; + } + + if (m_hadElementCharacters) { + m_xmlWriter->writeCharacters(AString(ch)); + } + else { + m_xmlWriter->writeCharactersWithIndent(AString(ch)); + } + + m_hadElementCharacters = true; +} + +/** + * Process an end element. + * + * @param uri + * the Namespace URI, or the empty string if the element + * has no Namespace URI or if Namespace processing is not + * being performed + * @param localName + * the local name (without prefix), or the empty string if + * Namespace processing is not being performed + * @param qName + * the qualified name (with prefix), or the empty string + * if qualified names are not available + * @return + * The return code indicating status of element processing. + */ +XmlUnexpectedElementSaxParser::ReturnCodeEnum +XmlUnexpectedElementSaxParser::endElement(const AString& /*uri*/, const AString& localName, const AString& /*qName*/) +{ + if (m_elementNameStack.empty()) { + return ReturnCodeEnum::ERROR; + } + + if (localName == m_elementNameStack.top()) { + m_elementNameStack.pop(); + + if (m_hadElementCharacters) { + m_xmlWriter->writeCharacters("\n"); + m_hadElementCharacters = false; + } + + m_xmlWriter->writeEndElement(); + + if (m_elementNameStack.empty()) { + return ReturnCodeEnum::DONE; + } + + return ReturnCodeEnum::NOT_DONE; + } + + return ReturnCodeEnum::ERROR; +} + +/** + * Process a start element. + * + * @param uri + * the Namespace URI, or the empty string if the element + * has no Namespace URI or if Namespace processing is not + * being performed + * @param localName + * the local name (without prefix), or the empty string if + * Namespace processing is not being performed + * @param qName + * the qualified name (with prefix), or the empty string + * if qualified names are not available + * @param atts + * the attributes attached to the element. If there are + * no attributes, it shall be an empty Attributes object. + */ +void +XmlUnexpectedElementSaxParser::startElement(const AString& /*uri*/, const AString& localName, const AString& /*qName*/, const XmlAttributes& atts) +{ + m_elementNameStack.push(localName); + m_xmlWriter->writeStartElement(localName, atts); +} + +/** + * @return The unexpected content XML. + */ +AString +XmlUnexpectedElementSaxParser::getUnexpectedContentXML() const +{ + return m_textStreamString; +} + + diff --git a/src/Xml/XmlUnexpectedElementSaxParser.h b/src/Xml/XmlUnexpectedElementSaxParser.h new file mode 100644 index 000000000..4220a404d --- /dev/null +++ b/src/Xml/XmlUnexpectedElementSaxParser.h @@ -0,0 +1,94 @@ +#ifndef __XML_UNEXPECTED_ELEMENT_SAX_PARSER_H__ +#define __XML_UNEXPECTED_ELEMENT_SAX_PARSER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "CaretObject.h" + +class QTextStream; + +namespace caret { + class XmlAttributes; + class XmlWriter; + + class XmlUnexpectedElementSaxParser : public CaretObject { + + public: + /** + * Return code from end element method. + */ + enum class ReturnCodeEnum { + /** Done processing unrecognized XML */ + DONE, + /** Error encountered (unbalanced elements, unlikely since the SAX parser should catch this condition */ + ERROR, + /** Still processing unrecognized XML */ + NOT_DONE + }; + + XmlUnexpectedElementSaxParser(); + + virtual ~XmlUnexpectedElementSaxParser(); + + void startElement(const AString& uri, + const AString& localName, + const AString& qName, + const XmlAttributes& atts); + + ReturnCodeEnum endElement(const AString& namespaceURI, + const AString& localName, + const AString& qName); + + void characters(const char* ch); + + AString getUnexpectedContentXML() const; + + // ADD_NEW_METHODS_HERE + + private: + XmlUnexpectedElementSaxParser(const XmlUnexpectedElementSaxParser&); + + XmlUnexpectedElementSaxParser& operator=(const XmlUnexpectedElementSaxParser&); + + std::stack m_elementNameStack; + + AString m_textStreamString; + + std::unique_ptr m_textStream; + + std::unique_ptr m_xmlWriter; + + bool m_hadElementCharacters = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __XML_UNEXPECTED_ELEMENT_SAX_PARSER_DECLARE__ + // +#endif // __XML_UNEXPECTED_ELEMENT_SAX_PARSER_DECLARE__ + +} // namespace +#endif //__XML_UNEXPECTED_ELEMENT_SAX_PARSER_H__ -- GitLab From c227def9a39abbe68eddf36fc9f502e7085f6dc4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 6 Mar 2017 15:12:09 -0600 Subject: [PATCH 106/755] Related to WB-664 Data normalization should be saved in file: Older versions of wb_view/wb_command will cease processing XML in the CaretVolumeExtension if an unexpected element is encountered. WB-664 added metadata for VolumeFile for saving of the palette normalization mode. When writing the CaretVolumeExtension, if the file metadata contains only one element that is the palette normalization mode's default value, do not write the metadata. This will minimize any error message if a user tries to read a newer volume file containing metadata with an older version of wb_view/wb_command (and Caret5). --- src/Files/CaretVolumeExtension.cxx | 26 ++++++++++++++++++++++++-- src/FilesBase/GiftiMetaData.cxx | 10 ++++++++++ src/FilesBase/GiftiMetaData.h | 3 +++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Files/CaretVolumeExtension.cxx b/src/Files/CaretVolumeExtension.cxx index 305fa9e55..0e75fb0f6 100644 --- a/src/Files/CaretVolumeExtension.cxx +++ b/src/Files/CaretVolumeExtension.cxx @@ -22,10 +22,12 @@ #include "XmlSaxParser.h" #include "GiftiMetaData.h" #include "GiftiMetaDataSaxReader.h" +#include "GiftiMetaDataXmlElements.h" #include "GiftiXmlElements.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" #include "PaletteColorMappingXmlElements.h" +#include "PaletteNormalizationModeEnum.h" #include "CaretLogger.h" #include "XmlUnexpectedElementSaxParser.h" #include @@ -79,9 +81,29 @@ void CaretVolumeExtension::writeAsXML(XmlWriter& xmlWriter) { m_attributes[i]->writeAsXML(xmlWriter, i); } - if (m_metadata != NULL) { // write metadata only if it is not empty + if (m_metadata != NULL) { if ( ! m_metadata->isEmpty()) { - m_metadata->writeAsXML(xmlWriter); + /* + * Prior to "WB-664 Data normalization should be saved in file", VolumeFile did not contain + * file metadata. If one attempts to read a volume file containing metadata with older + * versions of wb_view/wb_command or Caret5, XML parsing of the CaretVolumeExtension will + * immediately cease if an unexpected element is encountered. So, to minimize isses with + * older versions of software, DO NOT write file metadata if it contains only one + * element that is the default value (selected map) of palette normalization. + */ + bool writeFileMetaDataFlag = true; + if (m_metadata->getNumberOfMetaData() == 1) { + const AString normalizationValueString = m_metadata->get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); + if ( ! normalizationValueString.isEmpty()) { + if (normalizationValueString == + PaletteNormalizationModeEnum::toName(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA)) { + writeFileMetaDataFlag = false; + } + } + } + if (writeFileMetaDataFlag) { + m_metadata->writeAsXML(xmlWriter); + } } } xmlWriter.writeEndElement();//just to make it clean diff --git a/src/FilesBase/GiftiMetaData.cxx b/src/FilesBase/GiftiMetaData.cxx index aff711a87..fd7747b41 100644 --- a/src/FilesBase/GiftiMetaData.cxx +++ b/src/FilesBase/GiftiMetaData.cxx @@ -686,4 +686,14 @@ GiftiMetaData::isEmpty() const return this->metadata.empty(); } +/** + * @return Number of metadata + */ +int32_t +GiftiMetaData::getNumberOfMetaData() const +{ + return this->metadata.size(); +} + + diff --git a/src/FilesBase/GiftiMetaData.h b/src/FilesBase/GiftiMetaData.h index 589c9bc7a..a98f3724c 100644 --- a/src/FilesBase/GiftiMetaData.h +++ b/src/FilesBase/GiftiMetaData.h @@ -131,6 +131,9 @@ public: bool isEmpty() const; + int32_t getNumberOfMetaData() const; + + private: void readEntry(QXmlStreamReader& xml); -- GitLab From 958f25241be17acbe7e523848d1278e0061cc4a1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Mar 2017 14:34:08 -0600 Subject: [PATCH 107/755] Resolve WB-662: 3x1 All volume slice view: Added menu to Toolbar-->Slice Plane-->All button. The menu allows the user to select Row, Column, or Grid layout for All Slice View. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 86 ++-- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 2 + src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 203 ++++++++-- src/Brain/BrainOpenGLVolumeSliceDrawing.h | 6 + src/Brain/BrowserTabContent.cxx | 22 + src/Brain/BrowserTabContent.h | 5 + src/Brain/CMakeLists.txt | 2 + src/Brain/VolumeSliceSettings.cxx | 31 +- src/Brain/VolumeSliceSettings.h | 10 +- .../VolumeSliceViewAllPlanesLayoutEnum.cxx | 377 ++++++++++++++++++ .../VolumeSliceViewAllPlanesLayoutEnum.h | 106 +++++ .../BrainBrowserWindowToolBarSlicePlane.cxx | 77 +++- .../BrainBrowserWindowToolBarSlicePlane.h | 8 + 13 files changed, 850 insertions(+), 85 deletions(-) create mode 100644 src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx create mode 100644 src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 3b14aa207..e9a9f2104 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -31,6 +31,7 @@ #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" +#include "BrainOpenGLVolumeSliceDrawing.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -194,6 +195,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli drawVolumeSliceViewPlane(sliceDrawingType, sliceProjectionType, browserTabContent->getSliceViewPlane(), + browserTabContent->getSlicePlanesAllViewLayout(), viewport); } else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { @@ -211,32 +213,41 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. + * @param allPlanesLayout + * The layout in ALL slices view. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, - const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const int32_t viewport[4]) + const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + const int32_t viewport[4]) { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: { - const int32_t gap = 2; + int32_t paraVP[4] = { 0, 0, 0, 0 }; + int32_t coronalVP[4] = { 0, 0, 0, 0 }; + int32_t axialVP[4] = { 0, 0, 0, 0 }; - const int32_t vpHalfX = viewport[2] / 2; - const int32_t vpHalfY = viewport[3] / 2; + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::PARASAGITTAL, + allPlanesLayout, + paraVP); + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::CORONAL, + allPlanesLayout, + coronalVP); + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::AXIAL, + allPlanesLayout, + axialVP); /* * Draw parasagittal slice */ - const int32_t paraVP[4] = { - viewport[0], - viewport[1] + vpHalfY + gap, - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -248,12 +259,6 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice /* * Draw coronal slice */ - const int32_t coronalVP[4] = { - viewport[0] + vpHalfX + gap, - viewport[1] + vpHalfY + gap, - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -265,12 +270,6 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice /* * Draw axial slice */ - const int32_t axialVP[4] = { - viewport[0] + vpHalfX + gap, - viewport[1], - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -278,22 +277,23 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice axialVP); glPopMatrix(); - /* - * 4th quadrant is used for axis showing orientation - */ - const int32_t allVP[4] = { - viewport[0], - viewport[1], - vpHalfX - gap, - vpHalfY - gap - }; - - switch (sliceProjectionType) { - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - drawOrientationAxes(allVP); - break; - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - break; + if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { + /* + * 4th quadrant is used for axis showing orientation + */ + int32_t allVP[4] = { 0, 0, 0, 0 }; + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::ALL, + allPlanesLayout, + allVP); + + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + drawOrientationAxes(allVP); + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } } } break; @@ -301,9 +301,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice case VolumeSliceViewPlaneEnum::CORONAL: case VolumeSliceViewPlaneEnum::PARASAGITTAL: drawVolumeSliceViewType(sliceDrawingType, - sliceProjectionType, - sliceViewPlane, - viewport); + sliceProjectionType, + sliceViewPlane, + viewport); break; } } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index 5dcf0e9a3..ae5fec6f6 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -26,6 +26,7 @@ #include "DisplayGroupEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" @@ -197,6 +198,7 @@ namespace caret { void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]); void drawVolumeSliceViewType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 030079125..b184aa2d7 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -195,6 +195,7 @@ BrainOpenGLVolumeSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawi drawVolumeSliceViewPlane(sliceDrawingType, sliceProjectionType, browserTabContent->getSliceViewPlane(), + browserTabContent->getSlicePlanesAllViewLayout(), viewport); } else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { @@ -212,6 +213,8 @@ BrainOpenGLVolumeSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawi * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. + * @param allPlanesLayout + * The layout in ALL slices view. * @param viewport * The viewport (region of graphics area) for drawing slices. */ @@ -219,25 +222,32 @@ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]) { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: { - const int32_t gap = 2; + int32_t paraVP[4] = { 0, 0, 0, 0 }; + int32_t coronalVP[4] = { 0, 0, 0, 0 }; + int32_t axialVP[4] = { 0, 0, 0, 0 }; - const int32_t vpHalfX = viewport[2] / 2; - const int32_t vpHalfY = viewport[3] / 2; + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::PARASAGITTAL, + allPlanesLayout, + paraVP); + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::CORONAL, + allPlanesLayout, + coronalVP); + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::AXIAL, + allPlanesLayout, + axialVP); /* * Draw parasagittal slice */ - const int32_t paraVP[4] = { - viewport[0], - viewport[1] + vpHalfY + gap, - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -249,12 +259,6 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing /* * Draw coronal slice */ - const int32_t coronalVP[4] = { - viewport[0] + vpHalfX + gap, - viewport[1] + vpHalfY + gap, - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -266,12 +270,6 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing /* * Draw axial slice */ - const int32_t axialVP[4] = { - viewport[0] + vpHalfX + gap, - viewport[1], - vpHalfX - gap, - vpHalfY - gap - }; glPushMatrix(); drawVolumeSliceViewType(sliceDrawingType, sliceProjectionType, @@ -279,22 +277,23 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing axialVP); glPopMatrix(); - /* - * 4th quadrant is used for axis showing orientation - */ - const int32_t allVP[4] = { - viewport[0], - viewport[1], - vpHalfX - gap, - vpHalfY - gap - }; - - switch (sliceProjectionType) { - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - drawOrientationAxes(allVP); - break; - case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: - break; + if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { + /* + * 4th quadrant is used for axis showing orientation + */ + int32_t allVP[4] = { 0, 0, 0, 0 }; + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + VolumeSliceViewPlaneEnum::ALL, + allPlanesLayout, + allVP); + + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + drawOrientationAxes(allVP); + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + break; + } } } break; @@ -309,6 +308,136 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing } } +/** + * Get the viewport for a slice in all slices view. + * + * @param tabViewport + * The viewport for the tab containing all slices. + * @param sliceViewPlane + * The plane for slice drawing. Note: "ALL" is used for orientation axes in oblique view. + * @param allPlanesLayout + * The layout in ALL slices view. + * @param viewportOut + * Output viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(const int32_t tabViewport[4], + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + int32_t viewportOut[4]) +{ + const int32_t gap = 2; + const int32_t tabViewportX = tabViewport[0]; + const int32_t tabViewportY = tabViewport[1]; + const int32_t tabViewportWidth = tabViewport[2]; + const int32_t tabViewportHeight = tabViewport[3]; + + switch (allPlanesLayout) { + case VolumeSliceViewAllPlanesLayoutEnum::COLUMN_LAYOUT: + { + const int32_t vpHeight = (tabViewportHeight - (gap * 2)) / 3; + const int32_t vpOffsetY = vpHeight + gap; + const int32_t vpWidth = tabViewportWidth; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = 0; + viewportOut[1] = 0; + viewportOut[2] = 0; + viewportOut[3] = 0; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + (vpOffsetY * 2); + viewportOut[2] = vpWidth; + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + } + } + break; + case VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT: + { + const int32_t vpWidth = (tabViewportWidth - gap) / 2; + const int32_t vpHeight = (tabViewportHeight - gap) / 2; + const int32_t vpOffsetX = vpWidth + gap; + const int32_t vpOffsetY = vpHeight + gap; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = vpWidth; + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + } + } + break; + case VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT: + { + const int32_t vpWidth = (tabViewportWidth - (gap * 2)) / 3; + const int32_t vpOffsetX = vpWidth + gap; + const int32_t vpHeight = tabViewportHeight; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = 0; + viewportOut[1] = 0; + viewportOut[2] = 0; + viewportOut[3] = 0; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX + (vpOffsetX * 2); + viewportOut[1] = tabViewportY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + } + } + break; + } +} + /** * Draw slices for the all structures view. * diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.h b/src/Brain/BrainOpenGLVolumeSliceDrawing.h index 00cfc95ec..3427dfc7a 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.h @@ -26,6 +26,7 @@ #include "DisplayGroupEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" @@ -55,6 +56,10 @@ namespace caret { const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); + static void getSliceAllViewViewport(const int32_t tabViewport[4], + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + int32_t viewportOut[4]); // ADD_NEW_METHODS_HERE private: @@ -178,6 +183,7 @@ namespace caret { void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]); void drawVolumeSliceViewType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 042f0c395..4f73306a5 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -3460,6 +3460,28 @@ BrowserTabContent::setSliceViewPlane(const VolumeSliceViewPlaneEnum::Enum sliceP updateYokedBrowserTabs(); } +/** + * @return The layout for all slices view (grid, row, column) + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +BrowserTabContent::getSlicePlanesAllViewLayout() const +{ + return m_volumeSliceSettings->getSlicePlanesAllViewLayout(); +} + +/** + * Set the layout for all slices view (grid, row, column) + * + * @param slicePlanesAllViewLayout + * New value for layout. + */ +void +BrowserTabContent::setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout) +{ + m_volumeSliceSettings->setSlicePlanesAllViewLayout(slicePlanesAllViewLayout); + updateYokedBrowserTabs(); +} + /** * @return Type of slice drawing (single/montage) */ diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index f40101c37..18bbd50f8 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -34,6 +34,7 @@ #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewPlaneEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "YokingGroupEnum.h" namespace caret { @@ -274,6 +275,10 @@ namespace caret { void setSliceViewPlane(VolumeSliceViewPlaneEnum::Enum sliceAxisMode); + VolumeSliceViewAllPlanesLayoutEnum::Enum getSlicePlanesAllViewLayout() const; + + void setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout); + VolumeSliceDrawingTypeEnum::Enum getSliceDrawingType() const; void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 38f80ef3b..e7f3280b2 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -184,6 +184,7 @@ ViewingTransformationsCerebellum.h ViewingTransformationsVolume.h VolumeSliceDrawingTypeEnum.h VolumeSliceSettings.h +VolumeSliceViewAllPlanesLayoutEnum.h VolumeSurfaceOutlineColorOrTabModel.h VolumeSurfaceOutlineModel.h VolumeSurfaceOutlineSetModel.h @@ -320,6 +321,7 @@ ViewingTransformationsCerebellum.cxx ViewingTransformationsVolume.cxx VolumeSliceDrawingTypeEnum.cxx VolumeSliceSettings.cxx +VolumeSliceViewAllPlanesLayoutEnum.cxx VolumeSurfaceOutlineColorOrTabModel.cxx VolumeSurfaceOutlineModel.cxx VolumeSurfaceOutlineSetModel.cxx diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index d0de0a4aa..e7f81c580 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -47,6 +47,7 @@ VolumeSliceSettings::VolumeSliceSettings() : CaretObject() { m_sliceViewPlane = VolumeSliceViewPlaneEnum::AXIAL; + m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; m_montageNumberOfColumns = 6; // was 3; @@ -61,11 +62,12 @@ VolumeSliceSettings::VolumeSliceSettings() m_sliceEnabledParasagittal = true; m_initializedFlag = false; - //m_lastVolumeFile = NULL; - + m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_sliceViewPlane", &m_sliceViewPlane); + m_sceneAssistant->add("m_slicePlanesAllViewLayout", + &m_slicePlanesAllViewLayout); m_sceneAssistant->add("m_sliceDrawingType", &m_sliceDrawingType); m_sceneAssistant->add("m_sliceProjectionType", @@ -130,6 +132,7 @@ void VolumeSliceSettings::copyHelperVolumeSliceSettings(const VolumeSliceSettings& obj) { m_sliceViewPlane = obj.m_sliceViewPlane; + m_slicePlanesAllViewLayout = obj.m_slicePlanesAllViewLayout; m_sliceDrawingType = obj.m_sliceDrawingType; m_sliceProjectionType = obj.m_sliceProjectionType; @@ -256,7 +259,29 @@ VolumeSliceSettings::setSliceViewPlane(const VolumeSliceViewPlaneEnum::Enum slic m_sliceViewPlane = slicePlane; } -/** +/** + * @return The layout for all slices view (grid, row, column) + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +VolumeSliceSettings::getSlicePlanesAllViewLayout() const +{ + return m_slicePlanesAllViewLayout; +} + +/** + * Set the layout for all slices view (grid, row, column) + * + * @param slicePlanesAllViewLayout + * New value for layout. + */ +void +VolumeSliceSettings::setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout) +{ + m_slicePlanesAllViewLayout = slicePlanesAllViewLayout; +} + + +/** * @return Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum diff --git a/src/Brain/VolumeSliceSettings.h b/src/Brain/VolumeSliceSettings.h index f653ea75d..59fe3d391 100644 --- a/src/Brain/VolumeSliceSettings.h +++ b/src/Brain/VolumeSliceSettings.h @@ -27,6 +27,7 @@ #include "SceneableInterface.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceProjectionTypeEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { @@ -51,6 +52,10 @@ namespace caret { void setSliceViewPlane(VolumeSliceViewPlaneEnum::Enum sliceAxisMode); + VolumeSliceViewAllPlanesLayoutEnum::Enum getSlicePlanesAllViewLayout() const; + + void setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout); + VolumeSliceDrawingTypeEnum::Enum getSliceDrawingType() const; void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); @@ -144,6 +149,9 @@ namespace caret { /** Axis of slice being viewed */ VolumeSliceViewPlaneEnum::Enum m_sliceViewPlane; + + /** Layout of slice in all slices view */ + VolumeSliceViewAllPlanesLayoutEnum::Enum m_slicePlanesAllViewLayout; /** Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum m_sliceDrawingType; @@ -165,7 +173,7 @@ namespace caret { mutable float m_sliceCoordinateCoronal; mutable float m_sliceCoordinateAxial; - + bool m_sliceEnabledParasagittal; bool m_sliceEnabledCoronal; diff --git a/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx b/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx new file mode 100644 index 000000000..47cfe2635 --- /dev/null +++ b/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.cxx @@ -0,0 +1,377 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ +#include "VolumeSliceViewAllPlanesLayoutEnum.h" +#undef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::VolumeSliceViewAllPlanesLayoutEnum + * \brief Enumerated type for layout in slice view all mode. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_volumeSliceViewAllPlanesLayoutEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void volumeSliceViewAllPlanesLayoutEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "VolumeSliceViewAllPlanesLayoutEnum.h" + * + * Instatiate: + * m_volumeSliceViewAllPlanesLayoutEnumComboBox = new EnumComboBoxTemplate(this); + * m_volumeSliceViewAllPlanesLayoutEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_volumeSliceViewAllPlanesLayoutEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(volumeSliceViewAllPlanesLayoutEnumComboBoxItemActivated())); + * + * Update the selection: + * m_volumeSliceViewAllPlanesLayoutEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const VolumeSliceViewAllPlanesLayoutEnum::Enum VARIABLE = m_volumeSliceViewAllPlanesLayoutEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +VolumeSliceViewAllPlanesLayoutEnum::VolumeSliceViewAllPlanesLayoutEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +VolumeSliceViewAllPlanesLayoutEnum::~VolumeSliceViewAllPlanesLayoutEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +VolumeSliceViewAllPlanesLayoutEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(GRID_LAYOUT, + "GRID_LAYOUT", + "Grid")); + + enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(COLUMN_LAYOUT, + "COLUMN_LAYOUT", + "Column")); + + enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(ROW_LAYOUT, + "ROW_LAYOUT", + "Row")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const VolumeSliceViewAllPlanesLayoutEnum* +VolumeSliceViewAllPlanesLayoutEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const VolumeSliceViewAllPlanesLayoutEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +VolumeSliceViewAllPlanesLayoutEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +VolumeSliceViewAllPlanesLayoutEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceViewAllPlanesLayoutEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +VolumeSliceViewAllPlanesLayoutEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +VolumeSliceViewAllPlanesLayoutEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceViewAllPlanesLayoutEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +VolumeSliceViewAllPlanesLayoutEnum::Enum +VolumeSliceViewAllPlanesLayoutEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceViewAllPlanesLayoutEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +VolumeSliceViewAllPlanesLayoutEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +VolumeSliceViewAllPlanesLayoutEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(VolumeSliceViewAllPlanesLayoutEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +VolumeSliceViewAllPlanesLayoutEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(VolumeSliceViewAllPlanesLayoutEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h b/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h new file mode 100644 index 000000000..3fb1d0921 --- /dev/null +++ b/src/Brain/VolumeSliceViewAllPlanesLayoutEnum.h @@ -0,0 +1,106 @@ +#ifndef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ +#define __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class VolumeSliceViewAllPlanesLayoutEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + GRID_LAYOUT, + /** */ + COLUMN_LAYOUT, + /** */ + ROW_LAYOUT + }; + + + ~VolumeSliceViewAllPlanesLayoutEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + VolumeSliceViewAllPlanesLayoutEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const VolumeSliceViewAllPlanesLayoutEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ +std::vector VolumeSliceViewAllPlanesLayoutEnum::enumData; +bool VolumeSliceViewAllPlanesLayoutEnum::initializedFlag = false; +int32_t VolumeSliceViewAllPlanesLayoutEnum::integerCodeCounter = 0; +#endif // __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ + +} // namespace +#endif //__VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx index c58fd33e8..5e9c89098 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BrainBrowserWindowToolBar.h" @@ -93,9 +94,11 @@ m_parentToolBar(parentToolBar) } m_volumePlaneAllToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::ALL), - "View the PARASAGITTAL, CORONAL, and AXIAL slices", + "View the PARASAGITTAL, CORONAL, and AXIAL slices\n" + "Press arrow to display menu for layout selection", this); m_volumePlaneAllToolButtonAction->setCheckable(true); + m_volumePlaneAllToolButtonAction->setMenu(createViewAllSlicesLayoutMenu()); m_volumePlaneActionGroup = new QActionGroup(this); @@ -201,9 +204,81 @@ BrainBrowserWindowToolBarSlicePlane::updateContent(BrowserTabContent* browserTab break; } + updateViewAllSlicesLayoutMenu(browserTabContent); + m_volumePlaneWidgetGroup->blockAllSignals(false); } +/** + * @return A new instance of the view all slices layout menu. + */ +QMenu* +BrainBrowserWindowToolBarSlicePlane::createViewAllSlicesLayoutMenu() +{ + std::vector allLayouts; + VolumeSliceViewAllPlanesLayoutEnum::getAllEnums(allLayouts); + + QMenu* menu = new QMenu(); + QActionGroup* actionGroup = new QActionGroup(this); + + for (auto layout : allLayouts) { + QAction* action = menu->addAction(VolumeSliceViewAllPlanesLayoutEnum::toGuiName(layout)); + action->setData((int)VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(layout)); + action->setCheckable(true); + m_viewAllSliceLayoutMenuActions.push_back(action); + + actionGroup->addAction(action); + } + + QObject::connect(menu, &QMenu::triggered, + this, &BrainBrowserWindowToolBarSlicePlane::viewAllSliceLayoutMenuTriggered); + return menu; +} + +/** + * Gets called when the user selects an item on the view all slices layout menu. + * + * @param action + * Action of menu item selected. + */ +void +BrainBrowserWindowToolBarSlicePlane::viewAllSliceLayoutMenuTriggered(QAction* action) +{ + const int layoutInt = action->data().toInt(); + bool validFlag = false; + const VolumeSliceViewAllPlanesLayoutEnum::Enum layout = VolumeSliceViewAllPlanesLayoutEnum::fromIntegerCode(layoutInt, &validFlag); + if (validFlag) { + BrowserTabContent* btc = getTabContentFromSelectedTab(); + + btc->setSlicePlanesAllViewLayout(layout); + + m_parentToolBar->updateVolumeIndicesWidget(btc); + updateGraphicsWindow(); + updateOtherYokedWindows(); + } + else { + CaretLogSevere("Invalid layout in menu item: " + + action->text()); + } +} + +/** + * Update the view all slices layout menu. + */ +void +BrainBrowserWindowToolBarSlicePlane::updateViewAllSlicesLayoutMenu(BrowserTabContent* browserTabContent) +{ + const VolumeSliceViewAllPlanesLayoutEnum::Enum layout = browserTabContent->getSlicePlanesAllViewLayout(); + const int layoutIntValue = VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(layout); + + for (auto action : m_viewAllSliceLayoutMenuActions) { + if (action->data().toInt() == layoutIntValue) { + action->setChecked(true); + break; + } + } +} + /** * Called when volume slice plane button is clicked. */ diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h index 45795d015..02f32eea7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h @@ -25,6 +25,7 @@ #include "BrainBrowserWindowToolBarComponent.h" class QActionGroup; +class QMenu; namespace caret { @@ -46,14 +47,21 @@ namespace caret { void volumePlaneActionGroupTriggered(QAction*); void volumePlaneResetToolButtonTriggered(bool checked); + void viewAllSliceLayoutMenuTriggered(QAction* action); private: BrainBrowserWindowToolBarSlicePlane(const BrainBrowserWindowToolBarSlicePlane&); BrainBrowserWindowToolBarSlicePlane& operator=(const BrainBrowserWindowToolBarSlicePlane&); + QMenu* createViewAllSlicesLayoutMenu(); + + void updateViewAllSlicesLayoutMenu(BrowserTabContent* browserTabContent); + BrainBrowserWindowToolBar* m_parentToolBar; + std::vector m_viewAllSliceLayoutMenuActions; + WuQWidgetObjectGroup* m_volumePlaneWidgetGroup; QAction* m_volumePlaneParasagittalToolButtonAction; -- GitLab From 244da7aac91d7113cf475c8a3d23d73fc1d4e983 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Mar 2017 14:40:26 -0600 Subject: [PATCH 108/755] On Mac, outline was missing around Toolbar-->Montage-->On button and Toolbar-->Slice Indices/Coords->ID Crosshairs button. --- src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx | 1 + src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index d91e88365..8d48b6cd9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -168,6 +168,7 @@ m_parentToolBar(parentToolBar) } QToolButton* volumeIDToolButton = new QToolButton; volumeIDToolButton->setDefaultAction(m_volumeIdentificationUpdatesSlicesAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIDToolButton); m_volumeSliceProjectionTypeEnumComboBox = new EnumComboBoxTemplate(this); m_volumeSliceProjectionTypeEnumComboBox->setup(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx index d5f9d8127..9b80ad4c6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx @@ -93,7 +93,8 @@ m_parentToolBar(parentToolBar) m_montageEnabledAction->setCheckable(true); QToolButton* montageEnabledToolButton = new QToolButton(); montageEnabledToolButton->setDefaultAction(m_montageEnabledAction); - + WuQtUtilities::setToolButtonStyleForQt5Mac(montageEnabledToolButton); + QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->setVerticalSpacing(2); -- GitLab From e8e17d21279a503b2472033ada827bc51a1233e2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Mar 2017 15:29:44 -0600 Subject: [PATCH 109/755] When using Spec File Dialog->More Sprocket Icon-> "Set File Name", the choose file dialog was not filtering files and displaying all files types. It has been corrected to display only existing files with the appropriate extension. --- src/GuiQt/CaretFileDialog.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/CaretFileDialog.cxx b/src/GuiQt/CaretFileDialog.cxx index 6a9f78787..30f0f3f72 100644 --- a/src/GuiQt/CaretFileDialog.cxx +++ b/src/GuiQt/CaretFileDialog.cxx @@ -396,7 +396,9 @@ CaretFileDialog::getChooseFileNameDialog(const DataFileTypeEnum::Enum dataFileTy QWidget *parent) { CaretFileDialog fd(parent); - //fd.setFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + if (dataFileType != DataFileTypeEnum::UNKNOWN) { + fd.setNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + } fd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); fd.setAcceptMode(CaretFileDialog::AcceptSave); fd.setFileMode(CaretFileDialog::AnyFile); -- GitLab From db9e4b40ac47ab9d076eaeb97270c9cbc461bde2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 09:42:37 -0600 Subject: [PATCH 110/755] Update to WB-662 3x1 all volume slice view: Correct translation of volume slices when all slices layout is row or column. --- src/Brain/BrowserTabContent.cxx | 296 ++++++++++++++++++++++---------- 1 file changed, 204 insertions(+), 92 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 4f73306a5..5d4baab20 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -30,6 +30,7 @@ #include "BorderFile.h" #include "Brain.h" #include "BrainOpenGLViewportContent.h" +#include "BrainOpenGLVolumeSliceDrawing.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" @@ -2017,66 +2018,166 @@ BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport int32_t sliceViewportOut[4]) const { VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; - - const int32_t halfWidth = viewport[2] / 2; - const int32_t halfHeight = viewport[3] / 2; - const int32_t viewportMousePressedX = mousePressX - viewport[0]; - const int32_t viewportMousePressedY = mousePressY - viewport[1]; - bool isRight = false; - bool isTop = false; - if (viewportMousePressedX > halfWidth) { - isRight = true; - } - if (viewportMousePressedY > halfHeight) { - isTop = true; - } - - /* - * Top Right is Coronal - * Top Left is Parasagittal - * Bottom Right is Axial - * Bottom Left is Empty or Surfaces - */ - if (isTop) { - if (isRight) { - view = VolumeSliceViewPlaneEnum::CORONAL; - } - else { - view = VolumeSliceViewPlaneEnum::PARASAGITTAL; - } - } - else { - if (isRight) { - view = VolumeSliceViewPlaneEnum::AXIAL; - } - else { - + + std::vector allSlicePlanes; + VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); + for (auto slicePlane : allSlicePlanes) { + BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + slicePlane, + getSlicePlanesAllViewLayout(), + sliceViewportOut); + const int32_t vpX = mousePressX - sliceViewportOut[0]; + const int32_t vpY = mousePressY - sliceViewportOut[1]; + if ((vpX >= 0) + && (vpY >= 0) + && (vpX < sliceViewportOut[2]) + && (vpY < sliceViewportOut[3])) { + return slicePlane; } } - - sliceViewportOut[0] = viewport[0]; - sliceViewportOut[1] = viewport[1]; - sliceViewportOut[2] = halfWidth; - sliceViewportOut[3] = halfHeight; - switch (view) { - case VolumeSliceViewPlaneEnum::ALL: - sliceViewportOut[2] = viewport[2]; - sliceViewportOut[3] = viewport[3]; - break; - case VolumeSliceViewPlaneEnum::AXIAL: - sliceViewportOut[0] = halfWidth; - break; - case VolumeSliceViewPlaneEnum::CORONAL: - sliceViewportOut[0] = halfWidth; - sliceViewportOut[1] = halfHeight; - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - sliceViewportOut[1] = halfHeight; - break; - } + CaretLogSevere("Failed to find slice plane in all sliced view"); return view; -} + +// const int32_t halfWidth = viewport[2] / 2; +// const int32_t halfHeight = viewport[3] / 2; +// const int32_t viewportMousePressedX = mousePressX - viewport[0]; +// const int32_t viewportMousePressedY = mousePressY - viewport[1]; +// bool isRight = false; +// bool isTop = false; +// if (viewportMousePressedX > halfWidth) { +// isRight = true; +// } +// if (viewportMousePressedY > halfHeight) { +// isTop = true; +// } +// +// /* +// * Top Right is Coronal +// * Top Left is Parasagittal +// * Bottom Right is Axial +// * Bottom Left is Empty or Surfaces +// */ +// if (isTop) { +// if (isRight) { +// view = VolumeSliceViewPlaneEnum::CORONAL; +// } +// else { +// view = VolumeSliceViewPlaneEnum::PARASAGITTAL; +// } +// } +// else { +// if (isRight) { +// view = VolumeSliceViewPlaneEnum::AXIAL; +// } +// else { +// +// } +// } +// +// sliceViewportOut[0] = viewport[0]; +// sliceViewportOut[1] = viewport[1]; +// sliceViewportOut[2] = halfWidth; +// sliceViewportOut[3] = halfHeight; +// +// switch (view) { +// case VolumeSliceViewPlaneEnum::ALL: +// sliceViewportOut[2] = viewport[2]; +// sliceViewportOut[3] = viewport[3]; +// break; +// case VolumeSliceViewPlaneEnum::AXIAL: +// sliceViewportOut[0] = halfWidth; +// break; +// case VolumeSliceViewPlaneEnum::CORONAL: +// sliceViewportOut[0] = halfWidth; +// sliceViewportOut[1] = halfHeight; +// break; +// case VolumeSliceViewPlaneEnum::PARASAGITTAL: +// sliceViewportOut[1] = halfHeight; +// break; +// } +// return view; +} + +///* +// * @return The slice view plane for the given viewport coordinate. +// * If ALL is returned, is indicates that the given viewport coordinate +// * is in the bottom left region in which volume slices are not displayed. +// * +// * @param viewport +// * The viewport. +// * @param mousePressX +// * X Location of the mouse press. +// * @param mousePressY +// * Y Location of the mouse press. +// */ +//VolumeSliceViewPlaneEnum::Enum +//BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], +// const int32_t mousePressX, +// const int32_t mousePressY, +// int32_t sliceViewportOut[4]) const +//{ +// VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; +// +// const int32_t halfWidth = viewport[2] / 2; +// const int32_t halfHeight = viewport[3] / 2; +// const int32_t viewportMousePressedX = mousePressX - viewport[0]; +// const int32_t viewportMousePressedY = mousePressY - viewport[1]; +// bool isRight = false; +// bool isTop = false; +// if (viewportMousePressedX > halfWidth) { +// isRight = true; +// } +// if (viewportMousePressedY > halfHeight) { +// isTop = true; +// } +// +// /* +// * Top Right is Coronal +// * Top Left is Parasagittal +// * Bottom Right is Axial +// * Bottom Left is Empty or Surfaces +// */ +// if (isTop) { +// if (isRight) { +// view = VolumeSliceViewPlaneEnum::CORONAL; +// } +// else { +// view = VolumeSliceViewPlaneEnum::PARASAGITTAL; +// } +// } +// else { +// if (isRight) { +// view = VolumeSliceViewPlaneEnum::AXIAL; +// } +// else { +// +// } +// } +// +// sliceViewportOut[0] = viewport[0]; +// sliceViewportOut[1] = viewport[1]; +// sliceViewportOut[2] = halfWidth; +// sliceViewportOut[3] = halfHeight; +// +// switch (view) { +// case VolumeSliceViewPlaneEnum::ALL: +// sliceViewportOut[2] = viewport[2]; +// sliceViewportOut[3] = viewport[3]; +// break; +// case VolumeSliceViewPlaneEnum::AXIAL: +// sliceViewportOut[0] = halfWidth; +// break; +// case VolumeSliceViewPlaneEnum::CORONAL: +// sliceViewportOut[0] = halfWidth; +// sliceViewportOut[1] = halfHeight; +// break; +// case VolumeSliceViewPlaneEnum::PARASAGITTAL: +// sliceViewportOut[1] = halfHeight; +// break; +// } +// return view; +//} /** * Apply mouse rotation to the displayed model. @@ -2512,44 +2613,55 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon float dx = 0.0; float dy = 0.0; float dz = 0.0; - switch (this->getSliceViewPlane()) - { + + int viewport[4]; + viewportContent->getModelViewport(viewport); + int sliceViewport[4]; + viewportContent->getModelViewport(sliceViewport); + + VolumeSliceViewPlaneEnum::Enum slicePlane = getSliceViewPlane(); + if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { + slicePlane = getSliceViewPlaneForVolumeAllSliceView(viewport, + mousePressX, + mousePressY, + sliceViewport); + } + + switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: - { - int viewport[4]; - viewportContent->getModelViewport(viewport); - const int32_t halfWidth = viewport[2] / 2; - const int32_t halfHeight = viewport[3] / 2; - const int32_t viewportMousePressedX = mousePressX - viewport[0]; - const int32_t viewportMousePressedY = mousePressY - viewport[1]; - bool isRight = false; - bool isTop = false; - if (viewportMousePressedX > halfWidth) { - isRight = true; - } - if (viewportMousePressedY > halfHeight) { - isTop = true; - } - //CaretLogInfo("right: " + AString::fromBool(isRight) + " top: " + AString::fromBool(isTop)); - if (isTop) - { - if (isRight)//coronal - { - dx = mouseDX * slowdown; - dz = mouseDY * slowdown; - } else {//parasaggital - dy = -mouseDX * slowdown; - dz = mouseDY * slowdown; - } - } else { - if (isRight)//axial - { - dx = mouseDX * slowdown; - dy = mouseDY * slowdown; - }//bottom left has no slice - } +// { +// const int32_t halfWidth = viewport[2] / 2; +// const int32_t halfHeight = viewport[3] / 2; +// const int32_t viewportMousePressedX = mousePressX - viewport[0]; +// const int32_t viewportMousePressedY = mousePressY - viewport[1]; +// bool isRight = false; +// bool isTop = false; +// if (viewportMousePressedX > halfWidth) { +// isRight = true; +// } +// if (viewportMousePressedY > halfHeight) { +// isTop = true; +// } +// //CaretLogInfo("right: " + AString::fromBool(isRight) + " top: " + AString::fromBool(isTop)); +// if (isTop) +// { +// if (isRight)//coronal +// { +// dx = mouseDX * slowdown; +// dz = mouseDY * slowdown; +// } else {//parasaggital +// dy = -mouseDX * slowdown; +// dz = mouseDY * slowdown; +// } +// } else { +// if (isRight)//axial +// { +// dx = mouseDX * slowdown; +// dy = mouseDY * slowdown; +// }//bottom left has no slice +// } +// } break; - } case VolumeSliceViewPlaneEnum::AXIAL: dx = mouseDX * slowdown; dy = mouseDY * slowdown; -- GitLab From 80c3edc164de5ef203ab8057e2700e6030395cab Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 12:08:17 -0600 Subject: [PATCH 111/755] Moved recently added code for volume slice all view layouts out of BrainOpenGLVolumeSliceDrawing and into BrainOpenGLViewport. Otherwise, including BrainOpenGLVolumeSliceDrawing.h/cxx causes linking to the OpenGL libraries which causes linking errors in the Test module since the Test module does not use OpenGL. --- src/Brain/BrainOpenGLViewportContent.cxx | 177 ++++++++++++++++++ src/Brain/BrainOpenGLViewportContent.h | 12 ++ .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 10 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 139 +------------- src/Brain/BrainOpenGLVolumeSliceDrawing.h | 4 - src/Brain/BrowserTabContent.cxx | 101 +++++----- src/Brain/BrowserTabContent.h | 8 +- 7 files changed, 254 insertions(+), 197 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index d5feb698e..88d3d1f59 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -863,3 +863,180 @@ BrainOpenGLViewportContent::TileTabsViewportSizingInfo::print(const int32_t x, std::cout << qPrintable(msg) << std::endl; } + +/** + * Get the viewport for a slice in all slices view. + * + * @param tabViewport + * The viewport for the tab containing all slices. + * @param sliceViewPlane + * The plane for slice drawing. Note: "ALL" is used for orientation axes in oblique view. + * @param allPlanesLayout + * The layout in ALL slices view. + * @param viewportOut + * Output viewport (region of graphics area) for drawing slices. + */ +void +BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4], + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + int32_t viewportOut[4]) +{ + const int32_t gap = 2; + const int32_t tabViewportX = tabViewport[0]; + const int32_t tabViewportY = tabViewport[1]; + const int32_t tabViewportWidth = tabViewport[2]; + const int32_t tabViewportHeight = tabViewport[3]; + + switch (allPlanesLayout) { + case VolumeSliceViewAllPlanesLayoutEnum::COLUMN_LAYOUT: + { + const int32_t vpHeight = (tabViewportHeight - (gap * 2)) / 3; + const int32_t vpOffsetY = vpHeight + gap; + const int32_t vpWidth = tabViewportWidth; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = 0; + viewportOut[1] = 0; + viewportOut[2] = 0; + viewportOut[3] = 0; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + (vpOffsetY * 2); + viewportOut[2] = vpWidth; + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + } + } + break; + case VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT: + { + const int32_t vpWidth = (tabViewportWidth - gap) / 2; + const int32_t vpHeight = (tabViewportHeight - gap) / 2; + const int32_t vpOffsetX = vpWidth + gap; + const int32_t vpOffsetY = vpHeight + gap; + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY + vpOffsetY; + viewportOut[2] = vpWidth; + viewportOut[3] = (tabViewportHeight - viewportOut[1]); + break; + } + } + break; + case VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT: + { + const int32_t vpWidth = (tabViewportWidth - (gap * 2)) / 3; + const int32_t vpOffsetX = vpWidth + gap; + const int32_t vpHeight = tabViewportHeight; + + switch (sliceViewPlane) { + case VolumeSliceViewPlaneEnum::ALL: + viewportOut[0] = 0; + viewportOut[1] = 0; + viewportOut[2] = 0; + viewportOut[3] = 0; + break; + case VolumeSliceViewPlaneEnum::AXIAL: + viewportOut[0] = tabViewportX + (vpOffsetX * 2); + viewportOut[1] = tabViewportY; + viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::CORONAL: + viewportOut[0] = tabViewportX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + case VolumeSliceViewPlaneEnum::PARASAGITTAL: + viewportOut[0] = tabViewportX + vpOffsetX; + viewportOut[1] = tabViewportY; + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; + break; + } + } + break; + } +} + +/* + * @return The slice view plane for the given viewport coordinate. + * If ALL is returned, is indicates that the given viewport coordinate + * is in the bottom left region in which volume slices are not displayed. + * + * @param viewport + * The viewport. + * @param mousePressX + * X Location of the mouse press. + * @param mousePressY + * Y Location of the mouse press. + * @param allPlanesLayout + * The layout in ALL slices view. + * @param sliceViewportOut + * Output viewport (region of graphics area) for drawing slices. + */ +VolumeSliceViewPlaneEnum::Enum +BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + const int32_t mousePressX, + const int32_t mousePressY, + int32_t sliceViewportOut[4]) +{ + VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; + + std::vector allSlicePlanes; + VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); + for (auto slicePlane : allSlicePlanes) { + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, + slicePlane, + allPlanesLayout, + sliceViewportOut); + const int32_t vpX = mousePressX - sliceViewportOut[0]; + const int32_t vpY = mousePressY - sliceViewportOut[1]; + if ((vpX >= 0) + && (vpY >= 0) + && (vpX < sliceViewportOut[2]) + && (vpY < sliceViewportOut[3])) { + return slicePlane; + } + } + + CaretLogSevere("Failed to find slice plane in all sliced view"); + return view; +} + diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index e714685f6..04a68cde2 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -23,6 +23,8 @@ #include "CaretObject.h" +#include "VolumeSliceViewPlaneEnum.h" +#include "VolumeSliceViewAllPlanesLayoutEnum.h" namespace caret { @@ -76,6 +78,16 @@ namespace caret { const int32_t windowIndex, const int32_t windowViewport[4]); + static void getSliceAllViewViewport(const int32_t tabViewport[4], + const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + int32_t viewportOut[4]); + + static VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], + const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, + const int32_t mousePressX, + const int32_t mousePressY, + int sliceViewportOut[4]); private: /** * Assists with creation of the tile tab viewports diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index e9a9f2104..31b54fbeb 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -31,7 +31,7 @@ #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" -#include "BrainOpenGLVolumeSliceDrawing.h" +#include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -232,15 +232,15 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice int32_t coronalVP[4] = { 0, 0, 0, 0 }; int32_t axialVP[4] = { 0, 0, 0, 0 }; - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::PARASAGITTAL, allPlanesLayout, paraVP); - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::CORONAL, allPlanesLayout, coronalVP); - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::AXIAL, allPlanesLayout, axialVP); @@ -282,7 +282,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSlice * 4th quadrant is used for axis showing orientation */ int32_t allVP[4] = { 0, 0, 0, 0 }; - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::ALL, allPlanesLayout, allVP); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index b184aa2d7..456eea709 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -31,6 +31,7 @@ #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" +#include "BrainOpenGLViewportContent.h" #include "BrainordinateRegionOfInterest.h" #include "BrowserTabContent.h" #include "CaretAssert.h" @@ -232,15 +233,15 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing int32_t coronalVP[4] = { 0, 0, 0, 0 }; int32_t axialVP[4] = { 0, 0, 0, 0 }; - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::PARASAGITTAL, allPlanesLayout, paraVP); - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::CORONAL, allPlanesLayout, coronalVP); - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::AXIAL, allPlanesLayout, axialVP); @@ -282,7 +283,7 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing * 4th quadrant is used for axis showing orientation */ int32_t allVP[4] = { 0, 0, 0, 0 }; - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, + BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::ALL, allPlanesLayout, allVP); @@ -308,136 +309,6 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawing } } -/** - * Get the viewport for a slice in all slices view. - * - * @param tabViewport - * The viewport for the tab containing all slices. - * @param sliceViewPlane - * The plane for slice drawing. Note: "ALL" is used for orientation axes in oblique view. - * @param allPlanesLayout - * The layout in ALL slices view. - * @param viewportOut - * Output viewport (region of graphics area) for drawing slices. - */ -void -BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(const int32_t tabViewport[4], - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, - int32_t viewportOut[4]) -{ - const int32_t gap = 2; - const int32_t tabViewportX = tabViewport[0]; - const int32_t tabViewportY = tabViewport[1]; - const int32_t tabViewportWidth = tabViewport[2]; - const int32_t tabViewportHeight = tabViewport[3]; - - switch (allPlanesLayout) { - case VolumeSliceViewAllPlanesLayoutEnum::COLUMN_LAYOUT: - { - const int32_t vpHeight = (tabViewportHeight - (gap * 2)) / 3; - const int32_t vpOffsetY = vpHeight + gap; - const int32_t vpWidth = tabViewportWidth; - - switch (sliceViewPlane) { - case VolumeSliceViewPlaneEnum::ALL: - viewportOut[0] = 0; - viewportOut[1] = 0; - viewportOut[2] = 0; - viewportOut[3] = 0; - break; - case VolumeSliceViewPlaneEnum::AXIAL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY; - viewportOut[2] = vpWidth; - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::CORONAL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY + vpOffsetY; - viewportOut[2] = vpWidth; - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY + (vpOffsetY * 2); - viewportOut[2] = vpWidth; - viewportOut[3] = (tabViewportHeight - viewportOut[1]); - break; - } - } - break; - case VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT: - { - const int32_t vpWidth = (tabViewportWidth - gap) / 2; - const int32_t vpHeight = (tabViewportHeight - gap) / 2; - const int32_t vpOffsetX = vpWidth + gap; - const int32_t vpOffsetY = vpHeight + gap; - switch (sliceViewPlane) { - case VolumeSliceViewPlaneEnum::ALL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY; - viewportOut[2] = vpWidth; - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::AXIAL: - viewportOut[0] = tabViewportX + vpOffsetX; - viewportOut[1] = tabViewportY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::CORONAL: - viewportOut[0] = tabViewportX + vpOffsetX; - viewportOut[1] = tabViewportY + vpOffsetY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); - viewportOut[3] = (tabViewportHeight - viewportOut[1]); - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY + vpOffsetY; - viewportOut[2] = vpWidth; - viewportOut[3] = (tabViewportHeight - viewportOut[1]); - break; - } - } - break; - case VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT: - { - const int32_t vpWidth = (tabViewportWidth - (gap * 2)) / 3; - const int32_t vpOffsetX = vpWidth + gap; - const int32_t vpHeight = tabViewportHeight; - - switch (sliceViewPlane) { - case VolumeSliceViewPlaneEnum::ALL: - viewportOut[0] = 0; - viewportOut[1] = 0; - viewportOut[2] = 0; - viewportOut[3] = 0; - break; - case VolumeSliceViewPlaneEnum::AXIAL: - viewportOut[0] = tabViewportX + (vpOffsetX * 2); - viewportOut[1] = tabViewportY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::CORONAL: - viewportOut[0] = tabViewportX; - viewportOut[1] = tabViewportY; - viewportOut[2] = vpWidth; - viewportOut[3] = vpHeight; - break; - case VolumeSliceViewPlaneEnum::PARASAGITTAL: - viewportOut[0] = tabViewportX + vpOffsetX; - viewportOut[1] = tabViewportY; - viewportOut[2] = vpWidth; - viewportOut[3] = vpHeight; - break; - } - } - break; - } -} - /** * Draw slices for the all structures view. * diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.h b/src/Brain/BrainOpenGLVolumeSliceDrawing.h index 3427dfc7a..387701133 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.h @@ -56,10 +56,6 @@ namespace caret { const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); - static void getSliceAllViewViewport(const int32_t tabViewport[4], - const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, - const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, - int32_t viewportOut[4]); // ADD_NEW_METHODS_HERE private: diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 5d4baab20..d7b5baef1 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -30,7 +30,6 @@ #include "BorderFile.h" #include "Brain.h" #include "BrainOpenGLViewportContent.h" -#include "BrainOpenGLVolumeSliceDrawing.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" @@ -1999,46 +1998,46 @@ BrowserTabContent::ventralView() updateYokedBrowserTabs(); } -/* - * @return The slice view plane for the given viewport coordinate. - * If ALL is returned, is indicates that the given viewport coordinate - * is in the bottom left region in which volume slices are not displayed. - * - * @param viewport - * The viewport. - * @param mousePressX - * X Location of the mouse press. - * @param mousePressY - * Y Location of the mouse press. - */ -VolumeSliceViewPlaneEnum::Enum -BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], - const int32_t mousePressX, - const int32_t mousePressY, - int32_t sliceViewportOut[4]) const -{ - VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; - - std::vector allSlicePlanes; - VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); - for (auto slicePlane : allSlicePlanes) { - BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, - slicePlane, - getSlicePlanesAllViewLayout(), - sliceViewportOut); - const int32_t vpX = mousePressX - sliceViewportOut[0]; - const int32_t vpY = mousePressY - sliceViewportOut[1]; - if ((vpX >= 0) - && (vpY >= 0) - && (vpX < sliceViewportOut[2]) - && (vpY < sliceViewportOut[3])) { - return slicePlane; - } - } - - CaretLogSevere("Failed to find slice plane in all sliced view"); - return view; - +///* +// * @return The slice view plane for the given viewport coordinate. +// * If ALL is returned, is indicates that the given viewport coordinate +// * is in the bottom left region in which volume slices are not displayed. +// * +// * @param viewport +// * The viewport. +// * @param mousePressX +// * X Location of the mouse press. +// * @param mousePressY +// * Y Location of the mouse press. +// */ +//VolumeSliceViewPlaneEnum::Enum +//BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], +// const int32_t mousePressX, +// const int32_t mousePressY, +// int32_t sliceViewportOut[4]) const +//{ +// VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; +// +// std::vector allSlicePlanes; +// VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); +// for (auto slicePlane : allSlicePlanes) { +// BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, +// slicePlane, +// getSlicePlanesAllViewLayout(), +// sliceViewportOut); +// const int32_t vpX = mousePressX - sliceViewportOut[0]; +// const int32_t vpY = mousePressY - sliceViewportOut[1]; +// if ((vpX >= 0) +// && (vpY >= 0) +// && (vpX < sliceViewportOut[2]) +// && (vpY < sliceViewportOut[3])) { +// return slicePlane; +// } +// } +// +// CaretLogSevere("Failed to find slice plane in all sliced view"); +// return view; +// // const int32_t halfWidth = viewport[2] / 2; // const int32_t halfHeight = viewport[3] / 2; // const int32_t viewportMousePressedX = mousePressX - viewport[0]; @@ -2097,7 +2096,7 @@ BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport // break; // } // return view; -} +//} ///* // * @return The slice view plane for the given viewport coordinate. @@ -2218,10 +2217,11 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten viewport[3] }; if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { - slicePlane = getSliceViewPlaneForVolumeAllSliceView(viewport, - mousePressX, - mousePressY, - sliceViewport); + slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, + getSlicePlanesAllViewLayout(), + mousePressX, + mousePressY, + sliceViewport); } Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); @@ -2621,10 +2621,11 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon VolumeSliceViewPlaneEnum::Enum slicePlane = getSliceViewPlane(); if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { - slicePlane = getSliceViewPlaneForVolumeAllSliceView(viewport, - mousePressX, - mousePressY, - sliceViewport); + slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, + getSlicePlanesAllViewLayout(), + mousePressX, + mousePressY, + sliceViewport); } switch (slicePlane) { diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 18bbd50f8..b7d63e4f6 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -406,10 +406,10 @@ namespace caret { BrowserTabContent& operator=(const BrowserTabContent&); - VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], - const int32_t mousePressX, - const int32_t mousePressY, - int sliceViewportOut[4]) const; +// VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], +// const int32_t mousePressX, +// const int32_t mousePressY, +// int sliceViewportOut[4]) const; ViewingTransformations* getViewingTransformation(); -- GitLab From 17a279977b2d63307a8cd8ff132dbf17349651f5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 12:51:38 -0600 Subject: [PATCH 112/755] Removed code from BrowserTabContent.cxx that had been commented out in a recent change. --- src/Brain/BrowserTabContent.cxx | 212 -------------------------------- 1 file changed, 212 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index d7b5baef1..3c7918fe6 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1998,186 +1998,6 @@ BrowserTabContent::ventralView() updateYokedBrowserTabs(); } -///* -// * @return The slice view plane for the given viewport coordinate. -// * If ALL is returned, is indicates that the given viewport coordinate -// * is in the bottom left region in which volume slices are not displayed. -// * -// * @param viewport -// * The viewport. -// * @param mousePressX -// * X Location of the mouse press. -// * @param mousePressY -// * Y Location of the mouse press. -// */ -//VolumeSliceViewPlaneEnum::Enum -//BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], -// const int32_t mousePressX, -// const int32_t mousePressY, -// int32_t sliceViewportOut[4]) const -//{ -// VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; -// -// std::vector allSlicePlanes; -// VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); -// for (auto slicePlane : allSlicePlanes) { -// BrainOpenGLVolumeSliceDrawing::getSliceAllViewViewport(viewport, -// slicePlane, -// getSlicePlanesAllViewLayout(), -// sliceViewportOut); -// const int32_t vpX = mousePressX - sliceViewportOut[0]; -// const int32_t vpY = mousePressY - sliceViewportOut[1]; -// if ((vpX >= 0) -// && (vpY >= 0) -// && (vpX < sliceViewportOut[2]) -// && (vpY < sliceViewportOut[3])) { -// return slicePlane; -// } -// } -// -// CaretLogSevere("Failed to find slice plane in all sliced view"); -// return view; -// -// const int32_t halfWidth = viewport[2] / 2; -// const int32_t halfHeight = viewport[3] / 2; -// const int32_t viewportMousePressedX = mousePressX - viewport[0]; -// const int32_t viewportMousePressedY = mousePressY - viewport[1]; -// bool isRight = false; -// bool isTop = false; -// if (viewportMousePressedX > halfWidth) { -// isRight = true; -// } -// if (viewportMousePressedY > halfHeight) { -// isTop = true; -// } -// -// /* -// * Top Right is Coronal -// * Top Left is Parasagittal -// * Bottom Right is Axial -// * Bottom Left is Empty or Surfaces -// */ -// if (isTop) { -// if (isRight) { -// view = VolumeSliceViewPlaneEnum::CORONAL; -// } -// else { -// view = VolumeSliceViewPlaneEnum::PARASAGITTAL; -// } -// } -// else { -// if (isRight) { -// view = VolumeSliceViewPlaneEnum::AXIAL; -// } -// else { -// -// } -// } -// -// sliceViewportOut[0] = viewport[0]; -// sliceViewportOut[1] = viewport[1]; -// sliceViewportOut[2] = halfWidth; -// sliceViewportOut[3] = halfHeight; -// -// switch (view) { -// case VolumeSliceViewPlaneEnum::ALL: -// sliceViewportOut[2] = viewport[2]; -// sliceViewportOut[3] = viewport[3]; -// break; -// case VolumeSliceViewPlaneEnum::AXIAL: -// sliceViewportOut[0] = halfWidth; -// break; -// case VolumeSliceViewPlaneEnum::CORONAL: -// sliceViewportOut[0] = halfWidth; -// sliceViewportOut[1] = halfHeight; -// break; -// case VolumeSliceViewPlaneEnum::PARASAGITTAL: -// sliceViewportOut[1] = halfHeight; -// break; -// } -// return view; -//} - -///* -// * @return The slice view plane for the given viewport coordinate. -// * If ALL is returned, is indicates that the given viewport coordinate -// * is in the bottom left region in which volume slices are not displayed. -// * -// * @param viewport -// * The viewport. -// * @param mousePressX -// * X Location of the mouse press. -// * @param mousePressY -// * Y Location of the mouse press. -// */ -//VolumeSliceViewPlaneEnum::Enum -//BrowserTabContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], -// const int32_t mousePressX, -// const int32_t mousePressY, -// int32_t sliceViewportOut[4]) const -//{ -// VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; -// -// const int32_t halfWidth = viewport[2] / 2; -// const int32_t halfHeight = viewport[3] / 2; -// const int32_t viewportMousePressedX = mousePressX - viewport[0]; -// const int32_t viewportMousePressedY = mousePressY - viewport[1]; -// bool isRight = false; -// bool isTop = false; -// if (viewportMousePressedX > halfWidth) { -// isRight = true; -// } -// if (viewportMousePressedY > halfHeight) { -// isTop = true; -// } -// -// /* -// * Top Right is Coronal -// * Top Left is Parasagittal -// * Bottom Right is Axial -// * Bottom Left is Empty or Surfaces -// */ -// if (isTop) { -// if (isRight) { -// view = VolumeSliceViewPlaneEnum::CORONAL; -// } -// else { -// view = VolumeSliceViewPlaneEnum::PARASAGITTAL; -// } -// } -// else { -// if (isRight) { -// view = VolumeSliceViewPlaneEnum::AXIAL; -// } -// else { -// -// } -// } -// -// sliceViewportOut[0] = viewport[0]; -// sliceViewportOut[1] = viewport[1]; -// sliceViewportOut[2] = halfWidth; -// sliceViewportOut[3] = halfHeight; -// -// switch (view) { -// case VolumeSliceViewPlaneEnum::ALL: -// sliceViewportOut[2] = viewport[2]; -// sliceViewportOut[3] = viewport[3]; -// break; -// case VolumeSliceViewPlaneEnum::AXIAL: -// sliceViewportOut[0] = halfWidth; -// break; -// case VolumeSliceViewPlaneEnum::CORONAL: -// sliceViewportOut[0] = halfWidth; -// sliceViewportOut[1] = halfHeight; -// break; -// case VolumeSliceViewPlaneEnum::PARASAGITTAL: -// sliceViewportOut[1] = halfHeight; -// break; -// } -// return view; -//} - /** * Apply mouse rotation to the displayed model. * @@ -2630,38 +2450,6 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: -// { -// const int32_t halfWidth = viewport[2] / 2; -// const int32_t halfHeight = viewport[3] / 2; -// const int32_t viewportMousePressedX = mousePressX - viewport[0]; -// const int32_t viewportMousePressedY = mousePressY - viewport[1]; -// bool isRight = false; -// bool isTop = false; -// if (viewportMousePressedX > halfWidth) { -// isRight = true; -// } -// if (viewportMousePressedY > halfHeight) { -// isTop = true; -// } -// //CaretLogInfo("right: " + AString::fromBool(isRight) + " top: " + AString::fromBool(isTop)); -// if (isTop) -// { -// if (isRight)//coronal -// { -// dx = mouseDX * slowdown; -// dz = mouseDY * slowdown; -// } else {//parasaggital -// dy = -mouseDX * slowdown; -// dz = mouseDY * slowdown; -// } -// } else { -// if (isRight)//axial -// { -// dx = mouseDX * slowdown; -// dy = mouseDY * slowdown; -// }//bottom left has no slice -// } -// } break; case VolumeSliceViewPlaneEnum::AXIAL: dx = mouseDX * slowdown; -- GitLab From 14448927fc36da206c8d51dbf84774df8dfb48fc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Mar 2017 08:57:25 -0600 Subject: [PATCH 113/755] Changed metadata declaration in CaretVolumeExtension so that it is no longer a pointer. --- src/Files/CaretVolumeExtension.cxx | 54 +++++++++++++----------------- src/Files/CaretVolumeExtension.h | 6 ++-- src/Files/VolumeFile.cxx | 28 +++------------- 3 files changed, 32 insertions(+), 56 deletions(-) diff --git a/src/Files/CaretVolumeExtension.cxx b/src/Files/CaretVolumeExtension.cxx index 0e75fb0f6..d068447d3 100644 --- a/src/Files/CaretVolumeExtension.cxx +++ b/src/Files/CaretVolumeExtension.cxx @@ -51,7 +51,7 @@ CaretVolumeExtension::clear() { m_comment.clear(); m_date.clear(); m_attributes.clear(); - m_metadata.grabNew(NULL); + m_metadata.clear(); } void CaretVolumeExtension::readFromXmlString(const AString& s) @@ -81,29 +81,27 @@ void CaretVolumeExtension::writeAsXML(XmlWriter& xmlWriter) { m_attributes[i]->writeAsXML(xmlWriter, i); } - if (m_metadata != NULL) { - if ( ! m_metadata->isEmpty()) { - /* - * Prior to "WB-664 Data normalization should be saved in file", VolumeFile did not contain - * file metadata. If one attempts to read a volume file containing metadata with older - * versions of wb_view/wb_command or Caret5, XML parsing of the CaretVolumeExtension will - * immediately cease if an unexpected element is encountered. So, to minimize isses with - * older versions of software, DO NOT write file metadata if it contains only one - * element that is the default value (selected map) of palette normalization. - */ - bool writeFileMetaDataFlag = true; - if (m_metadata->getNumberOfMetaData() == 1) { - const AString normalizationValueString = m_metadata->get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); - if ( ! normalizationValueString.isEmpty()) { - if (normalizationValueString == - PaletteNormalizationModeEnum::toName(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA)) { - writeFileMetaDataFlag = false; - } + if ( ! m_metadata.isEmpty()) { + /* + * Prior to "WB-664 Data normalization should be saved in file", VolumeFile did not contain + * file metadata. If one attempts to read a volume file containing metadata with older + * versions of wb_view/wb_command or Caret5, XML parsing of the CaretVolumeExtension will + * immediately cease if an unexpected element is encountered. So, to minimize isses with + * older versions of software, DO NOT write file metadata if it contains only one + * element that is the default value (selected map) of palette normalization. + */ + bool writeFileMetaDataFlag = true; + if (m_metadata.getNumberOfMetaData() == 1) { + const AString normalizationValueString = m_metadata.get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); + if ( ! normalizationValueString.isEmpty()) { + if (normalizationValueString == + PaletteNormalizationModeEnum::toName(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA)) { + writeFileMetaDataFlag = false; } } - if (writeFileMetaDataFlag) { - m_metadata->writeAsXML(xmlWriter); - } + } + if (writeFileMetaDataFlag) { + m_metadata.writeAsXML(xmlWriter); } } xmlWriter.writeEndElement();//just to make it clean @@ -145,10 +143,8 @@ void SubvolumeAttributes::writeAsXML(XmlWriter& xmlWriter, int index) typeString = "Unknown"; } xmlWriter.writeElementCData(CARET_VOL_EXT_VI_TYPE, typeString); - if (m_metadata != NULL) { // write metadata only if it is not empty - if ( ! m_metadata->isEmpty()) { - m_metadata->writeAsXML(xmlWriter); - } + if ( ! m_metadata.isEmpty()) { + m_metadata.writeAsXML(xmlWriter); } xmlWriter.writeEndElement(); } @@ -377,8 +373,7 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri m_toFill->m_attributes[m_viIndex].grabNew(new SubvolumeAttributes()); } else if (qName == GiftiXmlElements::TAG_METADATA) { nextState = ROOT_META_DATA; - m_toFill->m_metadata.grabNew(new GiftiMetaData); - m_metadataReader.grabNew(new GiftiMetaDataSaxReader(m_toFill->m_metadata)); + m_metadataReader.grabNew(new GiftiMetaDataSaxReader(&m_toFill->m_metadata)); m_metadataReader->startDocument(); m_metadataReader->startElement(uri, localName, qName, atts); }//anything else gets caught in INVALID below @@ -408,8 +403,7 @@ void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AStri } else if (qName == GiftiXmlElements::TAG_METADATA) { nextState = VI_META_DATA; CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); - m_toFill->m_attributes[m_viIndex]->m_metadata.grabNew(new GiftiMetaData); - m_metadataReader.grabNew(new GiftiMetaDataSaxReader(m_toFill->m_attributes[m_viIndex]->m_metadata)); + m_metadataReader.grabNew(new GiftiMetaDataSaxReader(&m_toFill->m_attributes[m_viIndex]->m_metadata)); m_metadataReader->startDocument(); m_metadataReader->startElement(uri, localName, qName, atts); } else if (qName == CARET_VOL_EXT_VI_TYPE) { diff --git a/src/Files/CaretVolumeExtension.h b/src/Files/CaretVolumeExtension.h index 4a40afefe..f866f9709 100644 --- a/src/Files/CaretVolumeExtension.h +++ b/src/Files/CaretVolumeExtension.h @@ -29,12 +29,12 @@ #include "XmlSaxParserHandlerInterface.h" #include "PaletteColorMappingSaxReader.h" #include "GiftiLabelTableSaxReader.h" +#include "GiftiMetaData.h" #include "GiftiMetaDataSaxReader.h" namespace caret { - class GiftiMetaData; class XmlUnexpectedElementSaxParser; struct StudyMetadataLinkSet @@ -57,7 +57,7 @@ namespace caret AString m_comment; AString m_guiLabel; CaretPointer m_labelTable; - CaretPointer m_metadata; + GiftiMetaData m_metadata; StudyMetadataLinkSet m_studyMetadata; CaretPointer m_palette; VolumeType m_type; @@ -67,7 +67,7 @@ namespace caret struct CaretVolumeExtension { - mutable CaretPointer m_metadata; + GiftiMetaData m_metadata; AString m_comment; AString m_date;//TODO: make a class to handle ISO-8601 dates std::vector > m_attributes; diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index ecf208bce..2bd0ff493 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -813,21 +813,13 @@ VolumeFile::setMapName(const int32_t mapIndex, const GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); - if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) - { - m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); - } - return m_caretVolExt.m_attributes[mapIndex]->m_metadata; + return &m_caretVolExt.m_attributes[mapIndex]->m_metadata; } GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); - if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) - { - m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); - } - return m_caretVolExt.m_attributes[mapIndex]->m_metadata; + return &m_caretVolExt.m_attributes[mapIndex]->m_metadata; } void VolumeFile::checkStatisticsValid() @@ -1071,10 +1063,7 @@ VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, GiftiMetaData* VolumeFile::getFileMetaData() { - if (m_caretVolExt.m_metadata == NULL) { - m_caretVolExt.m_metadata.grabNew(new GiftiMetaData); - } - return m_caretVolExt.m_metadata; + return &m_caretVolExt.m_metadata; } /** @@ -1083,10 +1072,7 @@ VolumeFile::getFileMetaData() const GiftiMetaData* VolumeFile::getFileMetaData() const { - if (m_caretVolExt.m_metadata == NULL) { - m_caretVolExt.m_metadata.grabNew(new GiftiMetaData); - } - return m_caretVolExt.m_metadata; + return &m_caretVolExt.m_metadata; } @@ -1303,11 +1289,7 @@ AString VolumeFile::getMapUniqueID(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); - if (m_caretVolExt.m_attributes[mapIndex]->m_metadata == NULL) - { - m_caretVolExt.m_attributes[mapIndex]->m_metadata.grabNew(new GiftiMetaData()); - } - return m_caretVolExt.m_attributes[mapIndex]->m_metadata->getUniqueID(); + return m_caretVolExt.m_attributes[mapIndex]->m_metadata.getUniqueID(); } /** -- GitLab From b71b8be179af06f65a7507ee61db1fc2e67427b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 13 Mar 2017 08:46:11 -0500 Subject: [PATCH 114/755] A pure virtual function error was caused by a recent change that used metadata for storage of the palette normalization mode. Use of the CaretMappableDataFile's copy constructor resulted in a call to the virtual function getMetaData() for copying of the palette normalization mode. This copying of the palette normalization mode has been removed and was probably unnecessary since the file metadata (that contains the palette normalization mode) should be copied by the file's copy constructor. --- src/Files/CaretMappableDataFile.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 97bd7d4fe..510a92197 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -95,9 +95,8 @@ CaretMappableDataFile::operator=(const CaretMappableDataFile& cmdf) * Assists with copying instances of this class. */ void -CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& cmdf) +CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& /*cmdf*/) { - setPaletteNormalizationMode(cmdf.getPaletteNormalizationMode()); } // note: method is documented in header file -- GitLab From 757a05b85a3f15b8418621f0a584ed29e2f5f67c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 17 Mar 2017 15:02:16 -0500 Subject: [PATCH 115/755] attempt to make travis build use trusty, qt5 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c28a05377..d5d6ee796 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: cpp +dist: trusty sudo: false notifications: @@ -11,7 +12,7 @@ cache: addons: apt: packages: - - libqt4-dev + - qt5-default - zlib1g-dev - libosmesa6-dev - libssl-dev -- GitLab From ac555a23896c13e9b2c2d08fd3d59fefe54392f0 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 17 Mar 2017 15:10:10 -0500 Subject: [PATCH 116/755] set travis to use c++11, release build type --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5d6ee796..a1ffa4ed6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ addons: env: global: - - OSMESA_DIR=/usr - OMP_NUM_THREADS=4 before_install: @@ -30,6 +29,6 @@ before_install: - cd ../build script: - - cmake ../workbench/src + - cmake -D CMAKE_CXX_FLAGS=-std=c++11 -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src - make -j 4 - ctest -- GitLab From 24dd5cca9033d5234967c137cc2ad81b92922e22 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 17 Mar 2017 15:14:52 -0500 Subject: [PATCH 117/755] suppress narrowing conversion warnings in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a1ffa4ed6..f8852c5ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,6 @@ before_install: - cd ../build script: - - cmake -D CMAKE_CXX_FLAGS=-std=c++11 -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src + - cmake -D CMAKE_CXX_FLAGS="-std=c++11 -Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src - make -j 4 - ctest -- GitLab From 4548d82fea3356b3fe2acafd53d84254b5f2842e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 17 Mar 2017 15:33:23 -0500 Subject: [PATCH 118/755] tell cmakelists to use qt5 in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f8852c5ea..cf0bb5488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,6 @@ before_install: - cd ../build script: - - cmake -D CMAKE_CXX_FLAGS="-std=c++11 -Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src + - cmake -D CMAKE_CXX_FLAGS="-std=c++11 -Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr -D WORKBENCH_USE_QT5=TRUE ../workbench/src - make -j 4 - ctest -- GitLab From 10c1892ecf89e993c47c0a178e9c85c11874fa94 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 17 Mar 2017 15:37:06 -0500 Subject: [PATCH 119/755] add qt5opengl to travis packages --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cf0bb5488..42a77a6e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: apt: packages: - qt5-default + - libqt5opengl5-dev - zlib1g-dev - libosmesa6-dev - libssl-dev -- GitLab From 576dbfba0f66b7cf5c0b1b58e660c3ffe8e6b356 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 22 Mar 2017 21:18:35 -0500 Subject: [PATCH 120/755] rename "strain" surface distortion option to "local affine" --- src/Algorithms/AlgorithmSurfaceDistortion.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Algorithms/AlgorithmSurfaceDistortion.cxx b/src/Algorithms/AlgorithmSurfaceDistortion.cxx index 9dd5620a4..28140294d 100644 --- a/src/Algorithms/AlgorithmSurfaceDistortion.cxx +++ b/src/Algorithms/AlgorithmSurfaceDistortion.cxx @@ -61,17 +61,17 @@ OperationParameters* AlgorithmSurfaceDistortion::getParameters() ret->createOptionalParameter(6, "-edge-method", "calculate distortion of edge lengths rather than areas"); - ret->createOptionalParameter(7, "-strain-method", "calculate distortion by the local affines between triangles"); + ret->createOptionalParameter(7, "-local-affine-method", "calculate distortion by the local affines between triangles"); ret->setHelpText( - AString("This command, when not using -caret5-method, -edge-method, or -strain-method, is equivalent to using -surface-vertex-areas on each surface, ") + + AString("This command, when not using -caret5-method, -edge-method, or -local-affine-method, is equivalent to using -surface-vertex-areas on each surface, ") + "smoothing both output metrics with the GEO_GAUSS_EQUAL method on the surface they came from if -smooth is specified, and then using the formula " + "'ln(distorted/reference)/ln(2)' on the smoothed results.\n\n" + "When using -caret5-method, it uses the surface distortion method from caret5, which takes the base 2 log of the ratio of tile areas, " + "then averages those results at each vertex, and then smooths the result on the reference surface.\n\n" + "When using -edge-method, the -smooth option is ignored, and the output at each vertex is the average of 'abs(ln(refEdge/distortEdge)/ln(2))' over all edges " + "connected to the vertex.\n\n" + - "When using -strain-method, the -smooth option is ignored. The output is two columns, the first is the area distortion ratio, and the second is anisotropic strain. " + + "When using -local-affine-method, the -smooth option is ignored. The output is two columns, the first is the area distortion ratio, and the second is anisotropic strain. " + "These are calculated by an affine transform between matching triangles, and then averaged across the triangles of a vertex." ); return ret; @@ -96,7 +96,7 @@ void AlgorithmSurfaceDistortion::useParameters(OperationParameters* myParams, Pr if (edgeMethod) ++methodCount; bool strainMethod = myParams->getOptionalParameter(7)->m_present; if (strainMethod) ++methodCount; - if (methodCount > 1) throw AlgorithmException("you may not specify more than one of -caret5-method, -edge-method, or -strain-method"); + if (methodCount > 1) throw AlgorithmException("you may not specify more than one of -caret5-method, -edge-method, or -local-affine-method"); AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod, strainMethod); } -- GitLab From 4e57c60c6efc61d718bc619630b160553e2099c8 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 23 Mar 2017 19:03:49 -0500 Subject: [PATCH 121/755] add a loop collapse to -volume-smoothing and a comment about the testing done --- src/Algorithms/AlgorithmVolumeSmoothing.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Algorithms/AlgorithmVolumeSmoothing.cxx b/src/Algorithms/AlgorithmVolumeSmoothing.cxx index fd84fbad1..c385e2f22 100644 --- a/src/Algorithms/AlgorithmVolumeSmoothing.cxx +++ b/src/Algorithms/AlgorithmVolumeSmoothing.cxx @@ -328,7 +328,8 @@ void AlgorithmVolumeSmoothing::smoothFrame(const float* inFrame, vector } } } -#pragma omp CARET_PARFOR schedule(dynamic) +//somehow this loop set is helped by collapsing the two outers, while the other two are not helped by it +#pragma omp CARET_PARFOR schedule(dynamic) collapse(2) for (int j = 0; j < myDims[1]; ++j)//and finally k { for (int i = 0; i < myDims[0]; ++i) -- GitLab From b785ccead4189c7a7b818db747a7403e0448d300 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 23 Mar 2017 19:17:01 -0500 Subject: [PATCH 122/755] remove "collapse" clause for now, windows compiler doesn't support it --- src/Algorithms/AlgorithmVolumeSmoothing.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Algorithms/AlgorithmVolumeSmoothing.cxx b/src/Algorithms/AlgorithmVolumeSmoothing.cxx index c385e2f22..d3572aa69 100644 --- a/src/Algorithms/AlgorithmVolumeSmoothing.cxx +++ b/src/Algorithms/AlgorithmVolumeSmoothing.cxx @@ -329,7 +329,8 @@ void AlgorithmVolumeSmoothing::smoothFrame(const float* inFrame, vector } } //somehow this loop set is helped by collapsing the two outers, while the other two are not helped by it -#pragma omp CARET_PARFOR schedule(dynamic) collapse(2) +//however, we need to upgrade our windows compiler before we can use "collapse" +#pragma omp CARET_PARFOR schedule(dynamic) for (int j = 0; j < myDims[1]; ++j)//and finally k { for (int i = 0; i < myDims[0]; ++i) -- GitLab From b1d1b44bdf2c9ff1c11af363352f4d2e9033368e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 23 Mar 2017 23:22:29 -0500 Subject: [PATCH 123/755] add a switch for better choice of dimensions in converting cifti to nifti --- src/Operations/OperationCiftiConvert.cxx | 31 +++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/Operations/OperationCiftiConvert.cxx b/src/Operations/OperationCiftiConvert.cxx index b80b68000..be9339222 100644 --- a/src/Operations/OperationCiftiConvert.cxx +++ b/src/Operations/OperationCiftiConvert.cxx @@ -75,6 +75,7 @@ OperationParameters* OperationCiftiConvert::getParameters() OptionalParameter* toNifti = ret->createOptionalParameter(3, "-to-nifti", "convert to NIFTI1"); toNifti->addCiftiParameter(1, "cifti-in", "the input cifti file"); toNifti->addVolumeOutputParameter(2, "nifti-out", "the output nifti file"); + toNifti->createOptionalParameter(3, "-smaller-file", "use better-fitting dimension lengths"); OptionalParameter* fromNifti = ret->createOptionalParameter(4, "-from-nifti", "convert a NIFTI (1 or 2) file made with this command back into CIFTI"); fromNifti->addVolumeParameter(1, "nifti-in", "the input nifti file"); @@ -293,20 +294,32 @@ void OperationCiftiConvert::useParameters(OperationParameters* myParams, Progres CiftiFile* myCiftiIn = toNifti->getCifti(1); if (myCiftiIn->getCiftiXML().getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); VolumeFile* myNiftiOut = toNifti->getOutputVolume(2); + bool betterDims = toNifti->getOptionalParameter(3)->m_present; vector outDims(4, 1); outDims[3] = myCiftiIn->getNumberOfColumns(); if (outDims[3] > numeric_limits::max()) throw OperationException("cifti rows are too long for nifti1, failing"); int64_t numRows = myCiftiIn->getNumberOfRows(); - int64_t temp = numRows; - int index = 0; - while (temp > numeric_limits::max()) - { - if (index > 1) throw OperationException("too many cifti rows for nifti1 spatial dimensions, failing"); - outDims[index] = numeric_limits::max(); - temp = (temp - 1) / numeric_limits::max() + 1;//round up - ++index; + const int64_t SHORTMAX = numeric_limits::max();//less ugly than writing it out every time + if (betterDims) + {//find the minimum needed third dimension, then compute from that how many elements the first two dimensions must encompass, etc + outDims[2] = (numRows - 1) / (SHORTMAX * SHORTMAX) + 1;//round up + if (outDims[2] > SHORTMAX) throw OperationException("too many cifti rows for nifti1 spatial dimensions, failing"); + int64_t temp = (numRows - 1) / outDims[2] + 1;//and again... + outDims[1] = (temp - 1) / SHORTMAX + 1; + outDims[0] = (temp - 1) / outDims[1] + 1; + } else { + int64_t temp = numRows; + int index = 0; + while (temp > SHORTMAX) + { + if (index > 1) throw OperationException("too many cifti rows for nifti1 spatial dimensions, failing"); + outDims[index] = SHORTMAX; + temp = (temp - 1) / SHORTMAX + 1;//round up + ++index; + } + outDims[index] = temp; } - outDims[index] = temp; + CaretAssert(outDims[0] * outDims[1] * outDims[2] >= numRows);//make sure we didn't screw up the math myNiftiOut->reinitialize(outDims, FloatMatrix::identity(4).getMatrix()); myNiftiOut->setValueAllVoxels(0.0f); int64_t ijk[3] = { 0, 0, 0 }; -- GitLab From 7be557c2304e2f306f9091c32308e6351c8ca1fd Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 27 Mar 2017 23:21:29 -0500 Subject: [PATCH 124/755] add option to output separate dconns per fiber in -convert-matrix4-to-matrix2 --- .../OperationConvertMatrix4ToMatrix2.cxx | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Operations/OperationConvertMatrix4ToMatrix2.cxx b/src/Operations/OperationConvertMatrix4ToMatrix2.cxx index e276ea704..2dbe3c845 100644 --- a/src/Operations/OperationConvertMatrix4ToMatrix2.cxx +++ b/src/Operations/OperationConvertMatrix4ToMatrix2.cxx @@ -47,8 +47,14 @@ OperationParameters* OperationConvertMatrix4ToMatrix2::getParameters() OptionalParameter* distanceOpt = ret->createOptionalParameter(3, "-distances", "output average trajectory distance"); distanceOpt->addCiftiOutputParameter(1, "distance-out", "the distances, as a cifti file"); + OptionalParameter* fibersOpt = ret->createOptionalParameter(4, "-individual-fibers", "output files for each fiber direction"); + fibersOpt->addCiftiOutputParameter(1, "fiber-1", "output file for first fiber"); + fibersOpt->addCiftiOutputParameter(2, "fiber-2", "output file for second fiber"); + fibersOpt->addCiftiOutputParameter(3, "fiber-3", "output file for third fiber"); + ret->setHelpText( - AString("This command makes a cifti file from the fiber counts in a matrix4 wbsparse file, and optionally a second cifti file from the distances.") + AString("This command makes a cifti file from the fiber counts in a matrix4 wbsparse file, and optionally a second cifti file from the distances. ") + + "Note that while the total count is stored exactly, the per-fiber counts are stored as approximate fractions, so the output of -individual-fibers will contain nonintegers." ); return ret; } @@ -64,23 +70,51 @@ void OperationConvertMatrix4ToMatrix2::useParameters(OperationParameters* myPara { myDistOut = distanceOpt->getOutputCifti(1); } + CiftiFile* fiber1 = NULL, *fiber2 = NULL, *fiber3 = NULL; + OptionalParameter* fibersOpt = myParams->getOptionalParameter(4); + if (fibersOpt->m_present) + { + fiber1 = fibersOpt->getOutputCifti(1); + fiber2 = fibersOpt->getOutputCifti(2); + fiber3 = fibersOpt->getOutputCifti(3); + } CaretSparseFile matrix4(matrix4Name); const CiftiXML& myXML = matrix4.getCiftiXML(); myCountsOut->setCiftiXML(myXML); if (myDistOut != NULL) myDistOut->setCiftiXML(myXML); + if (fiber1 != NULL) + { + fiber1->setCiftiXML(myXML); + fiber2->setCiftiXML(myXML); + fiber3->setCiftiXML(myXML); + } int rowSize = myXML.getDimensionLength(CiftiXML::ALONG_ROW), numRows = myXML.getDimensionLength(CiftiXML::ALONG_COLUMN); - vector scratchRow(rowSize, 0.0f); - vector indices; - vector fibers; for (int i = 0; i < numRows; ++i) { + vector scratchRow(rowSize, 0.0f); + vector scratchFiber1 = scratchRow, scratchFiber2 = scratchRow, scratchFiber3 = scratchRow; + vector indices; + vector fibers; matrix4.getFibersRowSparse(i, indices, fibers); int numIndices = (int)indices.size(); for (int j = 0; j < numIndices; ++j) { scratchRow[indices[j]] = fibers[j].totalCount; + if (fiber1 != NULL) + { + CaretAssert(fibers[j].fiberFractions.size() == 3); + scratchFiber1[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[0]; + scratchFiber2[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[1]; + scratchFiber3[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[2]; + } } myCountsOut->setRow(scratchRow.data(), i); + if (fiber1 != NULL) + { + fiber1->setRow(scratchFiber1.data(), i); + fiber2->setRow(scratchFiber2.data(), i); + fiber3->setRow(scratchFiber3.data(), i); + } if (myDistOut != NULL) { for (int j = 0; j < numIndices; ++j) @@ -89,9 +123,5 @@ void OperationConvertMatrix4ToMatrix2::useParameters(OperationParameters* myPara } myDistOut->setRow(scratchRow.data(), i); } - for (int j = 0; j < numIndices; ++j) - { - scratchRow[indices[j]] = 0.0f; - } } } -- GitLab From 500f08078b6fb7906ec442a706aaabb898c5ec8d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 28 Mar 2017 10:16:37 -0500 Subject: [PATCH 125/755] Resolve WB-672 images are not displaying correctly in scenes: Changes made to image display properties were incompatible with older scenes. Logic has been added to test for, and apply, older image display properties. --- src/Brain/DisplayPropertiesImages.cxx | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Brain/DisplayPropertiesImages.cxx b/src/Brain/DisplayPropertiesImages.cxx index 30990535a..0d736d510 100644 --- a/src/Brain/DisplayPropertiesImages.cxx +++ b/src/Brain/DisplayPropertiesImages.cxx @@ -35,6 +35,8 @@ #include "SceneClassAssistant.h" #include "ScenePathName.h" #include "ScenePathNameArray.h" +#include "ScenePrimitive.h" +#include "ScenePrimitiveArray.h" using namespace caret; @@ -590,6 +592,35 @@ DisplayPropertiesImages::restoreFromScene(const SceneAttributes* sceneAttributes } } } + + /* + * Old scenes image display status for tab + */ + const SceneObjectMapIntegerKey* oldTabStatus = sceneClass->getMapIntegerKey("m_displayStatusInTab"); + if (oldTabStatus != NULL) { + const std::map& dataMap = oldTabStatus->getMap(); + for (auto& tabPrim : dataMap) { + const int32_t tabIndex = tabPrim.first; + const ScenePrimitive* primitive = dynamic_cast(tabPrim.second); + CaretAssert(primitive); + m_displayStatus->setValue(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, primitive->booleanValue()); + } + } + + /* + * Old scenes image display status for display group + */ + const ScenePrimitiveArray* oldGroupStatus = sceneClass->getPrimitiveArray("m_displayStatusInDisplayGroup"); + if (oldGroupStatus != NULL) { + const int32_t numValues = std::min(oldGroupStatus->getNumberOfArrayElements(), + static_cast(DisplayGroupEnum::NUMBER_OF_GROUPS)); + for (int32_t i = 0; i < numValues; i++) { + bool validFlag = false; + const DisplayGroupEnum::Enum dg = DisplayGroupEnum::fromIntegerCode(i, &validFlag); + CaretAssert(validFlag); + m_displayStatus->setValue(dg, 0, oldGroupStatus->booleanValue(i)); + } + } } /** -- GitLab From 2008f0d215ec48d2726c28eb4907a2e2e5414837 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 28 Mar 2017 16:16:28 -0500 Subject: [PATCH 126/755] After scene restoration, many mappable data files contained a modified status. This was caused by restoration of the palette normalization mode's use of the file metadata. Logic has been added to prevent this from occurring. --- src/Files/CaretMappableDataFile.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 510a92197..025e36a87 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -394,7 +394,16 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr if (std::find(paletteNormalizationModes.begin(), paletteNormalizationModes.end(), palNormValue) != paletteNormalizationModes.end()) { + /* + * Do not allow the metadata's modification status + * to change or else many files will have a modified + * status after restoration of the scene. + */ + const bool metadataModFlag = getFileMetaData()->isModified(); setPaletteNormalizationMode(palNormValue); + if ( ! metadataModFlag) { + getFileMetaData()->clearModified(); + } } } } -- GitLab From a8fdf276f2db521d46cbccdf2e8e94eaecde8d60 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 30 Mar 2017 22:59:52 -0500 Subject: [PATCH 127/755] add -only-cifti-xml option to -file-information (because wbsparse has cifti xml too) --- src/Files/CaretMappableDataFile.cxx | 9 +++++++++ src/Files/CaretMappableDataFile.h | 12 ++++++++++++ src/Files/CiftiFiberTrajectoryFile.cxx | 13 +++++++++++++ src/Files/CiftiFiberTrajectoryFile.h | 4 ++++ src/Files/CiftiMappableDataFile.cxx | 13 +++++++++++++ src/Files/CiftiMappableDataFile.h | 4 ++++ src/Operations/OperationFileInformation.cxx | 15 +++++++++++++++ 7 files changed, 70 insertions(+) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 025e36a87..786c6cc7a 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -28,6 +28,7 @@ #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "CiftiMappableConnectivityMatrixDataFile.h" +#include "CiftiXML.h" #include "DataFileContentInformation.h" #include "FastStatistics.h" #include "FileInformation.h" @@ -1053,5 +1054,13 @@ CaretMappableDataFile::isMappedWithRGBA() const return false; } +bool CaretMappableDataFile::hasCiftiXML() const +{ + return false; +} +const CiftiXML CaretMappableDataFile::getCiftiXML() const +{ + return CiftiXML(); +} diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index f507152bd..b9efad61a 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -31,6 +31,7 @@ namespace caret { class ChartDataCartesian; + class CiftiXML; class FastStatistics; class GiftiMetaData; class GiftiLabelTable; @@ -436,6 +437,17 @@ namespace caret { /* documented in cxx file. */ virtual bool isModifiedPaletteColorMapping() const; + /** + * Check whether the file contains Cifti XML (all cifti types and also wbsparse have it) + */ + virtual bool hasCiftiXML() const; + + /** + * Get the Cifti XML, if the file has it + * This could be faster if it returned a reference, but then it would have to throw when there is no xml object + */ + virtual const CiftiXML getCiftiXML() const; + /* documented in cxx file. */ bool isModified() const; diff --git a/src/Files/CiftiFiberTrajectoryFile.cxx b/src/Files/CiftiFiberTrajectoryFile.cxx index 59b2d5188..423085f12 100644 --- a/src/Files/CiftiFiberTrajectoryFile.cxx +++ b/src/Files/CiftiFiberTrajectoryFile.cxx @@ -1903,3 +1903,16 @@ CiftiFiberTrajectoryFile::addToDataFileContentInformation(DataFileContentInforma } +bool CiftiFiberTrajectoryFile::hasCiftiXML() const +{ + return true; +} + +const CiftiXML CiftiFiberTrajectoryFile::getCiftiXML() const +{ + if (m_sparseFile != NULL) + { + return m_sparseFile->getCiftiXML(); + } + return CiftiXML(); +} diff --git a/src/Files/CiftiFiberTrajectoryFile.h b/src/Files/CiftiFiberTrajectoryFile.h index 607cc8ce9..91bd25557 100644 --- a/src/Files/CiftiFiberTrajectoryFile.h +++ b/src/Files/CiftiFiberTrajectoryFile.h @@ -171,6 +171,10 @@ namespace caret { void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); + bool hasCiftiXML() const; + + const CiftiXML getCiftiXML() const; + // ADD_NEW_METHODS_HERE private: diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 71fc6d0db..e8ac6b79e 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -6896,3 +6896,16 @@ CiftiMappableDataFile::MapContent::updateColoring(const std::vector& data m_rgbaValid = true; } +bool CiftiMappableDataFile::hasCiftiXML() const +{ + return true; +} + +const CiftiXML CiftiMappableDataFile::getCiftiXML() const +{ + if (m_ciftiFile != NULL) + { + return m_ciftiFile->getCiftiXML(); + } + return CiftiXML(); +} diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index b89767a02..1af9f54bf 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -450,6 +450,10 @@ namespace caret { int64_t voxelIJKOut[3], float voxelXYZOut[3], bool& voxelValidOut) const; + + bool hasCiftiXML() const; + + const CiftiXML getCiftiXML() const; private: diff --git a/src/Operations/OperationFileInformation.cxx b/src/Operations/OperationFileInformation.cxx index 94f998885..d22a9770e 100644 --- a/src/Operations/OperationFileInformation.cxx +++ b/src/Operations/OperationFileInformation.cxx @@ -27,6 +27,7 @@ #include "CaretMappableDataFile.h" #include "CaretPointer.h" #include "CiftiMappableDataFile.h" +#include "CiftiXML.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "GiftiMetaData.h" @@ -81,6 +82,8 @@ OperationFileInformation::getParameters() OptionalParameter* mdKeyOpt = metadataOpt->createOptionalParameter(1, "-key", "only print the metadata for one key, with no formatting"); mdKeyOpt->addStringParameter(1, "key", "the metadata key"); + ret->createOptionalParameter(7, "-only-cifti-xml", "suppress normal output, print the cifti xml if the file type has it"); + AString helpText("List information about the content of a data file. " "Only one -only option may be specified. " "The information listed when no -only option is present is dependent upon the type of data file."); @@ -130,6 +133,9 @@ OperationFileInformation::useParameters(OperationParameters* myParams, } } + bool onlyCiftiXML = myParams->getOptionalParameter(7)->m_present; + if (onlyCiftiXML) ++countOnlys; + if (countOnlys > 1) throw OperationException("only one -only-* option may be specified"); bool preferOnDisk = (!showMapInformationFlag || countOnlys != 0); @@ -185,6 +191,15 @@ OperationFileInformation::useParameters(OperationParameters* myParams, cout << myMD->get(mdKey) << endl; } } + if (onlyCiftiXML) + { + CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); + if (mappableFile != NULL && mappableFile->hasCiftiXML()) + { + const CiftiXML& myXML = mappableFile->getCiftiXML(); + cout << myXML.writeXMLToString(myXML.getParsedVersion()) << endl; + } + } if (countOnlys == 0) { DataFileContentInformation dataFileContentInformation; -- GitLab From b565e5c2e6b40a8ca70ac68b1568fa0a0c732216 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 3 Apr 2017 20:47:35 -0500 Subject: [PATCH 128/755] make cifti methods throw DataFileException to prevent gui crashes on incorrect xml --- src/Cifti/CiftiBrainModelsMap.cxx | 128 +++++++++++++++--------------- src/Cifti/CiftiFile.cxx | 2 +- src/Cifti/CiftiLabelsMap.cxx | 30 +++---- src/Cifti/CiftiParcelsMap.cxx | 92 ++++++++++----------- src/Cifti/CiftiScalarsMap.cxx | 22 ++--- src/Cifti/CiftiSeriesMap.cxx | 38 ++++----- src/Cifti/CiftiVersion.cxx | 10 +-- src/Cifti/CiftiXML.cxx | 88 ++++++++++---------- 8 files changed, 205 insertions(+), 205 deletions(-) diff --git a/src/Cifti/CiftiBrainModelsMap.cxx b/src/Cifti/CiftiBrainModelsMap.cxx index 612de8041..4afc7dc23 100644 --- a/src/Cifti/CiftiBrainModelsMap.cxx +++ b/src/Cifti/CiftiBrainModelsMap.cxx @@ -20,7 +20,7 @@ #include "CiftiBrainModelsMap.h" -#include "CaretException.h" +#include "DataFileException.h" #include @@ -47,7 +47,7 @@ void CiftiBrainModelsMap::addSurfaceModel(const int64_t& numberOfNodes, const St { if (m_surfUsed.find(structure) != m_surfUsed.end()) { - throw CaretException("surface structures cannot be repeated in a brain models map"); + throw DataFileException("surface structures cannot be repeated in a brain models map"); } BrainModelPriv myModel; myModel.m_type = SURFACE; @@ -63,13 +63,13 @@ void CiftiBrainModelsMap::BrainModelPriv::setupSurface(const int64_t& start) { if (m_surfaceNumberOfNodes < 1) { - throw CaretException("surface must have at least 1 vertex"); + throw DataFileException("surface must have at least 1 vertex"); } m_modelStart = start; int64_t listSize = (int64_t)m_nodeIndices.size(); if (listSize == 0) { - throw CaretException("vertex list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic + throw DataFileException("vertex list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic } m_modelEnd = start + listSize;//one after last vector used(m_surfaceNumberOfNodes, false); @@ -78,15 +78,15 @@ void CiftiBrainModelsMap::BrainModelPriv::setupSurface(const int64_t& start) { if (m_nodeIndices[i] < 0) { - throw CaretException("vertex list contains negative index"); + throw DataFileException("vertex list contains negative index"); } if (m_nodeIndices[i] >= m_surfaceNumberOfNodes) { - throw CaretException("vertex list contains an index that don't exist in the surface"); + throw DataFileException("vertex list contains an index that don't exist in the surface"); } if (used[m_nodeIndices[i]]) { - throw CaretException("vertex list contains reused index"); + throw DataFileException("vertex list contains reused index"); } used[m_nodeIndices[i]] = true; m_nodeToIndexLookup[m_nodeIndices[i]] = start + i; @@ -97,16 +97,16 @@ void CiftiBrainModelsMap::addVolumeModel(const StructureEnum::Enum& structure, c { if (m_volUsed.find(structure) != m_volUsed.end()) { - throw CaretException("volume structures cannot be repeated in a brain models map"); + throw DataFileException("volume structures cannot be repeated in a brain models map"); } int64_t listSize = (int64_t)ijkList.size(); if (listSize == 0) { - throw CaretException("voxel list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic + throw DataFileException("voxel list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic } if (listSize % 3 != 0) { - throw CaretException("voxel list must have a length that is a multiple of 3"); + throw DataFileException("voxel list must have a length that is a multiple of 3"); } int64_t numElems = listSize / 3; const int64_t* dims = NULL; @@ -114,7 +114,7 @@ void CiftiBrainModelsMap::addVolumeModel(const StructureEnum::Enum& structure, c { if (!m_haveVolumeSpace) { - throw CaretException("you must set the volume space before adding volume models"); + throw DataFileException("you must set the volume space before adding volume models"); } dims = m_volSpace.getDims(); } @@ -125,18 +125,18 @@ void CiftiBrainModelsMap::addVolumeModel(const StructureEnum::Enum& structure, c int64_t index3 = index * 3; if (ijkList[index3] < 0 || ijkList[index3 + 1] < 0 || ijkList[index3 + 2] < 0) { - throw CaretException("found negative index in voxel list"); + throw DataFileException("found negative index in voxel list"); } if (!m_ignoreVolSpace && (ijkList[index3] >= dims[0] || ijkList[index3 + 1] >= dims[1] || ijkList[index3 + 2] >= dims[2])) { - throw CaretException("found invalid index triple in voxel list: (" + AString::number(ijkList[index3]) + ", " + throw DataFileException("found invalid index triple in voxel list: (" + AString::number(ijkList[index3]) + ", " + AString::number(ijkList[index3 + 1]) + ", " + AString::number(ijkList[index3 + 2]) + ")"); } if (tempLookup.find(ijkList[index3], ijkList[index3 + 1], ijkList[index3 + 2]) != NULL) { - throw CaretException("volume models may not reuse voxels, either internally or from other structures"); + throw DataFileException("volume models may not reuse voxels, either internally or from other structures"); } tempLookup.at(ijkList[index3], ijkList[index3 + 1], ijkList[index3 + 2]) = pair(nextStart + index, structure); } @@ -257,7 +257,7 @@ const vector& CiftiBrainModelsMap::getNodeList(const StructureEnum::Enu map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { - throw CaretException("getNodeList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this + throw DataFileException("getNodeList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this } CaretAssertVectorIndex(m_modelsInfo, iter->second); return m_modelsInfo[iter->second].m_nodeIndices; @@ -269,7 +269,7 @@ vector CiftiBrainModelsMap::getSurfaceMap(const map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { - throw CaretException("getSurfaceMap called for nonexistant structure");//also throw, for consistency + throw DataFileException("getSurfaceMap called for nonexistant structure");//also throw, for consistency } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; @@ -349,7 +349,7 @@ const VolumeSpace& CiftiBrainModelsMap::getVolumeSpace() const CaretAssert(!m_ignoreVolSpace); if (!m_haveVolumeSpace) { - throw CaretException("getVolumeSpace called when no volume space exists"); + throw DataFileException("getVolumeSpace called when no volume space exists"); } return m_volSpace; } @@ -375,7 +375,7 @@ vector CiftiBrainModelsMap::getVolumeStructureMa map::const_iterator iter = m_volUsed.find(structure); if (iter == m_volUsed.end()) { - throw CaretException("getVolumeStructureMap called for nonexistant structure");//also throw, for consistency + throw DataFileException("getVolumeStructureMap called for nonexistant structure");//also throw, for consistency } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; @@ -399,7 +399,7 @@ const vector& CiftiBrainModelsMap::getVoxelList(const StructureEnum::En map::const_iterator iter = m_volUsed.find(structure); if (iter == m_volUsed.end()) { - throw CaretException("getVoxelList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this + throw DataFileException("getVoxelList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this } CaretAssertVectorIndex(m_modelsInfo, iter->second); return m_modelsInfo[iter->second].m_voxelIndicesIJK; @@ -428,7 +428,7 @@ void CiftiBrainModelsMap::setVolumeSpace(const VolumeSpace& space) { if (!space.indexValid(myModel.m_voxelIndicesIJK[i3], myModel.m_voxelIndicesIJK[i3 + 1], myModel.m_voxelIndicesIJK[i3 + 2])) { - throw CaretException("invalid voxel found for volume space"); + throw DataFileException("invalid voxel found for volume space"); } } } @@ -514,7 +514,7 @@ void CiftiBrainModelsMap::readXML1(QXmlStreamReader& xml) QStringRef name = xml.name(); if (name != "BrainModel") { - throw CaretException("unexpected element in brain models map: " + name.toString()); + throw DataFileException("unexpected element in brain models map: " + name.toString()); } ParseHelperModel thisModel; thisModel.parseBrainModel1(xml); @@ -536,9 +536,9 @@ void CiftiBrainModelsMap::readXML1(QXmlStreamReader& xml) { if (parsedModels[i].m_offset < curOffset) { - throw CaretException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); + throw DataFileException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); } else { - throw CaretException("index " + QString::number(curOffset) + " is not assigned to any model"); + throw DataFileException("index " + QString::number(curOffset) + " is not assigned to any model"); } } curOffset += parsedModels[i].m_count; @@ -579,14 +579,14 @@ void CiftiBrainModelsMap::readXML2(QXmlStreamReader& xml) } else if (name == "Volume") { if (m_haveVolumeSpace) { - throw CaretException("Volume specified more than once in Brain Models mapping type"); + throw DataFileException("Volume specified more than once in Brain Models mapping type"); } else { m_volSpace.readCiftiXML2(xml); if (xml.hasError()) return; m_haveVolumeSpace = true; } } else { - throw CaretException("unexpected element in brain models map: " + name.toString()); + throw DataFileException("unexpected element in brain models map: " + name.toString()); } break;//the readNext in the for will remove the BrainModel or Volume end element } @@ -604,9 +604,9 @@ void CiftiBrainModelsMap::readXML2(QXmlStreamReader& xml) { if (parsedModels[i].m_offset < curOffset) { - throw CaretException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); + throw DataFileException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); } else { - throw CaretException("index " + QString::number(curOffset) + " is not assigned to any model"); + throw DataFileException("index " + QString::number(curOffset) + " is not assigned to any model"); } } curOffset += parsedModels[i].m_count; @@ -631,7 +631,7 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& x QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("ModelType")) { - throw CaretException("BrainModel missing required attribute ModelType"); + throw DataFileException("BrainModel missing required attribute ModelType"); } QStringRef value = attrs.value("ModelType"); if (value == "CIFTI_MODEL_TYPE_SURFACE") @@ -640,50 +640,50 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& x } else if (value == "CIFTI_MODEL_TYPE_VOXELS") { m_type = VOXELS; } else { - throw CaretException("invalid value for ModelType: " + value.toString()); + throw DataFileException("invalid value for ModelType: " + value.toString()); } if (!attrs.hasAttribute("BrainStructure")) { - throw CaretException("BrainModel missing required attribute BrainStructure"); + throw DataFileException("BrainModel missing required attribute BrainStructure"); } value = attrs.value("BrainStructure"); bool ok = false; m_brainStructure = StructureEnum::fromCiftiName(value.toString(), &ok); if (!ok) { - throw CaretException("invalid value for BrainStructure: " + value.toString()); + throw DataFileException("invalid value for BrainStructure: " + value.toString()); } if (!attrs.hasAttribute("IndexOffset")) { - throw CaretException("BrainModel missing required attribute IndexOffset"); + throw DataFileException("BrainModel missing required attribute IndexOffset"); } value = attrs.value("IndexOffset"); m_offset = value.toString().toLongLong(&ok); if (!ok || m_offset < 0) { - throw CaretException("IndexOffset must be a non-negative integer"); + throw DataFileException("IndexOffset must be a non-negative integer"); } if (!attrs.hasAttribute("IndexCount")) { - throw CaretException("BrainModel missing required attribute IndexCount"); + throw DataFileException("BrainModel missing required attribute IndexCount"); } value = attrs.value("IndexCount"); m_count = value.toString().toLongLong(&ok); if (!ok || m_count < 1)//NOTE: not technically required by cifti-1, would need some rewriting to support empty brainmodels { - throw CaretException("IndexCount must be a positive integer"); + throw DataFileException("IndexCount must be a positive integer"); } if (m_type == SURFACE) { if (!attrs.hasAttribute("SurfaceNumberOfNodes")) { - throw CaretException("BrainModel missing required attribute SurfaceNumberOfNodes"); + throw DataFileException("BrainModel missing required attribute SurfaceNumberOfNodes"); } value = attrs.value("SurfaceNumberOfNodes"); m_surfaceNumberOfNodes = value.toString().toLongLong(&ok); if (!ok || m_surfaceNumberOfNodes < 1) { - throw CaretException("SurfaceNumberOfNodes must be a positive integer"); + throw DataFileException("SurfaceNumberOfNodes must be a positive integer"); } if (!xml.readNextStartElement())//special case in cifti-1 { @@ -695,7 +695,7 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& x } else { if (xml.name() != "NodeIndices") { - throw CaretException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); + throw DataFileException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); } m_nodeIndices = readIndexArray(xml); xml.readNext();//remove the end element of NodeIndices @@ -703,26 +703,26 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& x if (xml.hasError()) return; if ((int64_t)m_nodeIndices.size() != m_count) { - throw CaretException("number of vertex indices does not match IndexCount"); + throw DataFileException("number of vertex indices does not match IndexCount"); } } else { if (!xml.readNextStartElement()) { - throw CaretException("BrainModel requires a child element"); + throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VoxelIndicesIJK") { - throw CaretException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); + throw DataFileException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); } m_voxelIndicesIJK = readIndexArray(xml); if (xml.hasError()) return; if (m_voxelIndicesIJK.size() % 3 != 0) { - throw CaretException("number of voxel indices is not a multiple of 3"); + throw DataFileException("number of voxel indices is not a multiple of 3"); } if ((int64_t)m_voxelIndicesIJK.size() != m_count * 3) { - throw CaretException("number of voxel indices does not match IndexCount"); + throw DataFileException("number of voxel indices does not match IndexCount"); } xml.readNext();//remove the end element of VoxelIndicesIJK } @@ -731,7 +731,7 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& x switch(xml.readNext()) { case QXmlStreamReader::StartElement: - throw CaretException("unexpected second element in BrainModel: " + xml.name().toString()); + throw DataFileException("unexpected second element in BrainModel: " + xml.name().toString()); default: break; } @@ -744,7 +744,7 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel2(QXmlStreamReader& x QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("ModelType")) { - throw CaretException("BrainModel missing required attribute ModelType"); + throw DataFileException("BrainModel missing required attribute ModelType"); } QStringRef value = attrs.value("ModelType"); if (value == "CIFTI_MODEL_TYPE_SURFACE") @@ -753,84 +753,84 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel2(QXmlStreamReader& x } else if (value == "CIFTI_MODEL_TYPE_VOXELS") { m_type = VOXELS; } else { - throw CaretException("invalid value for ModelType: " + value.toString()); + throw DataFileException("invalid value for ModelType: " + value.toString()); } if (!attrs.hasAttribute("BrainStructure")) { - throw CaretException("BrainModel missing required attribute BrainStructure"); + throw DataFileException("BrainModel missing required attribute BrainStructure"); } value = attrs.value("BrainStructure"); bool ok = false; m_brainStructure = StructureEnum::fromCiftiName(value.toString(), &ok); if (!ok) { - throw CaretException("invalid value for BrainStructure: " + value.toString()); + throw DataFileException("invalid value for BrainStructure: " + value.toString()); } if (!attrs.hasAttribute("IndexOffset")) { - throw CaretException("BrainModel missing required attribute IndexOffset"); + throw DataFileException("BrainModel missing required attribute IndexOffset"); } value = attrs.value("IndexOffset"); m_offset = value.toString().toLongLong(&ok); if (!ok || m_offset < 0) { - throw CaretException("IndexOffset must be a non-negative integer"); + throw DataFileException("IndexOffset must be a non-negative integer"); } if (!attrs.hasAttribute("IndexCount")) { - throw CaretException("BrainModel missing required attribute IndexCount"); + throw DataFileException("BrainModel missing required attribute IndexCount"); } value = attrs.value("IndexCount"); m_count = value.toString().toLongLong(&ok); if (!ok || m_count < 1) { - throw CaretException("IndexCount must be a positive integer"); + throw DataFileException("IndexCount must be a positive integer"); } if (m_type == SURFACE) { if (!attrs.hasAttribute("SurfaceNumberOfVertices")) { - throw CaretException("BrainModel missing required attribute SurfaceNumberOfVertices"); + throw DataFileException("BrainModel missing required attribute SurfaceNumberOfVertices"); } value = attrs.value("SurfaceNumberOfVertices"); m_surfaceNumberOfNodes = value.toString().toLongLong(&ok); if (!ok || m_surfaceNumberOfNodes < 1) { - throw CaretException("SurfaceNumberOfVertices must be a positive integer"); + throw DataFileException("SurfaceNumberOfVertices must be a positive integer"); } if (!xml.readNextStartElement()) { - throw CaretException("BrainModel requires a child element"); + throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VertexIndices") { - throw CaretException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); + throw DataFileException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); } m_nodeIndices = readIndexArray(xml); if (xml.hasError()) return; if ((int64_t)m_nodeIndices.size() != m_count) { - throw CaretException("number of vertex indices does not match IndexCount"); + throw DataFileException("number of vertex indices does not match IndexCount"); } xml.readNext();//remove the end element of NodeIndices } else { if (!xml.readNextStartElement()) { - throw CaretException("BrainModel requires a child element"); + throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VoxelIndicesIJK") { - throw CaretException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); + throw DataFileException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); } m_voxelIndicesIJK = readIndexArray(xml); if (xml.hasError()) return; if (m_voxelIndicesIJK.size() % 3 != 0) { - throw CaretException("number of voxel indices is not a multiple of 3"); + throw DataFileException("number of voxel indices is not a multiple of 3"); } if ((int64_t)m_voxelIndicesIJK.size() != m_count * 3) { - throw CaretException("number of voxel indices does not match IndexCount"); + throw DataFileException("number of voxel indices does not match IndexCount"); } xml.readNext();//remove the end element of VoxelIndicesIJK } @@ -839,7 +839,7 @@ void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel2(QXmlStreamReader& x switch(xml.readNext()) { case QXmlStreamReader::StartElement: - throw CaretException("unexpected second element in BrainModel: " + xml.name().toString()); + throw DataFileException("unexpected second element in BrainModel: " + xml.name().toString()); default: break; } @@ -861,11 +861,11 @@ vector CiftiBrainModelsMap::ParseHelperModel::readIndexArray(QXmlStream ret.push_back(separated[i].toLongLong(&ok)); if (!ok) { - throw CaretException("found noninteger in index array: " + separated[i]); + throw DataFileException("found noninteger in index array: " + separated[i]); } if (ret.back() < 0) { - throw CaretException("found negative integer in index array: " + separated[i]); + throw DataFileException("found negative integer in index array: " + separated[i]); } } return ret; diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index 56f736038..f735f209d 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -587,7 +587,7 @@ namespace break; default: CaretAssert(0); - throw CaretException("internal error, tell the developers what you just tried to do"); + throw DataFileException("internal error, tell the developers what you just tried to do"); } } } diff --git a/src/Cifti/CiftiLabelsMap.cxx b/src/Cifti/CiftiLabelsMap.cxx index 633deb405..164304b0a 100644 --- a/src/Cifti/CiftiLabelsMap.cxx +++ b/src/Cifti/CiftiLabelsMap.cxx @@ -21,7 +21,7 @@ #include "CiftiLabelsMap.h" #include "CaretAssert.h" -#include "CaretException.h" +#include "DataFileException.h" #include "CaretLogger.h" using namespace caret; @@ -124,7 +124,7 @@ void CiftiLabelsMap::readXML1(QXmlStreamReader& xml) { if (xml.name() != "NamedMap") { - throw CaretException("unexpected element in labels map: " + xml.name().toString()); + throw DataFileException("unexpected element in labels map: " + xml.name().toString()); } LabelMap tempMap; tempMap.readXML1(xml); @@ -149,7 +149,7 @@ void CiftiLabelsMap::readXML2(QXmlStreamReader& xml) { if (xml.name() != "NamedMap") { - throw CaretException("unexpected element in labels map: " + xml.name().toString()); + throw DataFileException("unexpected element in labels map: " + xml.name().toString()); } LabelMap tempMap; tempMap.readXML2(xml); @@ -177,7 +177,7 @@ void CiftiLabelsMap::LabelMap::readXML1(QXmlStreamReader& xml) { if (haveMetaData) { - throw CaretException("MetaData specified multiple times in one NamedMap"); + throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML1(xml); if (xml.hasError()) return; @@ -185,7 +185,7 @@ void CiftiLabelsMap::LabelMap::readXML1(QXmlStreamReader& xml) } else if (name == "LabelTable") { if (haveTable) { - throw CaretException("LabelTable specified multiple times in one NamedMap"); + throw DataFileException("LabelTable specified multiple times in one NamedMap"); } m_labelTable.readFromQXmlStreamReader(xml); if (xml.hasError()) return; @@ -193,13 +193,13 @@ void CiftiLabelsMap::LabelMap::readXML1(QXmlStreamReader& xml) } else if (name == "MapName") { if (haveName) { - throw CaretException("MapName specified multiple times in one NamedMap"); + throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { - throw CaretException("unexpected element in NamedMap: " + name.toString()); + throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } @@ -209,11 +209,11 @@ void CiftiLabelsMap::LabelMap::readXML1(QXmlStreamReader& xml) } if (!haveName) { - throw CaretException("NamedMap missing required child element MapName"); + throw DataFileException("NamedMap missing required child element MapName"); } if (!haveTable) { - throw CaretException("NamedMap in labels mapping missing required child element LabelTable"); + throw DataFileException("NamedMap in labels mapping missing required child element LabelTable"); } } @@ -231,7 +231,7 @@ void CiftiLabelsMap::LabelMap::readXML2(QXmlStreamReader& xml) { if (haveMetaData) { - throw CaretException("MetaData specified multiple times in one NamedMap"); + throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML2(xml); if (xml.hasError()) return; @@ -239,7 +239,7 @@ void CiftiLabelsMap::LabelMap::readXML2(QXmlStreamReader& xml) } else if (name == "LabelTable") { if (haveTable) { - throw CaretException("LabelTable specified multiple times in one NamedMap"); + throw DataFileException("LabelTable specified multiple times in one NamedMap"); } m_labelTable.readFromQXmlStreamReader(xml); if (xml.hasError()) return; @@ -247,13 +247,13 @@ void CiftiLabelsMap::LabelMap::readXML2(QXmlStreamReader& xml) } else if (name == "MapName") { if (haveName) { - throw CaretException("MapName specified multiple times in one NamedMap"); + throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { - throw CaretException("unexpected element in NamedMap: " + name.toString()); + throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } @@ -263,11 +263,11 @@ void CiftiLabelsMap::LabelMap::readXML2(QXmlStreamReader& xml) } if (!haveName) { - throw CaretException("NamedMap missing required child element MapName"); + throw DataFileException("NamedMap missing required child element MapName"); } if (!haveTable) { - throw CaretException("NamedMap in labels mapping missing required child element LabelTable"); + throw DataFileException("NamedMap in labels mapping missing required child element LabelTable"); } } diff --git a/src/Cifti/CiftiParcelsMap.cxx b/src/Cifti/CiftiParcelsMap.cxx index b8df159f0..555d1ae04 100644 --- a/src/Cifti/CiftiParcelsMap.cxx +++ b/src/Cifti/CiftiParcelsMap.cxx @@ -20,7 +20,7 @@ #include "CiftiParcelsMap.h" -#include "CaretException.h" +#include "DataFileException.h" #include "CaretLogger.h" #include @@ -36,7 +36,7 @@ void CiftiParcelsMap::addParcel(const CiftiParcelsMap::Parcel& parcel) { if (parcel.m_name == m_parcels[i].m_name) { - throw CaretException("cannot add parcel with duplicate name '" + parcel.m_name + "'");//NOTE: technically this restriction isn't in the standard, but that was probably an oversight + throw DataFileException("cannot add parcel with duplicate name '" + parcel.m_name + "'");//NOTE: technically this restriction isn't in the standard, but that was probably an oversight } } int64_t voxelListSize = (int64_t)parcel.m_voxelIndices.size(); @@ -48,7 +48,7 @@ void CiftiParcelsMap::addParcel(const CiftiParcelsMap::Parcel& parcel) { if (!m_haveVolumeSpace) { - throw CaretException("you must set the volume space before adding parcels that use voxels"); + throw DataFileException("you must set the volume space before adding parcels that use voxels"); } dims = m_volSpace.getDims(); } @@ -56,17 +56,17 @@ void CiftiParcelsMap::addParcel(const CiftiParcelsMap::Parcel& parcel) { if (iter->m_ijk[0] < 0 || iter->m_ijk[1] < 0 || iter->m_ijk[2] < 0) { - throw CaretException("found negative index triple in voxel list"); + throw DataFileException("found negative index triple in voxel list"); } if (!m_ignoreVolSpace && (iter->m_ijk[0] >= dims[0] || iter->m_ijk[1] >= dims[1] || iter->m_ijk[2] >= dims[2])) { - throw CaretException("found invalid index triple in voxel list"); + throw DataFileException("found invalid index triple in voxel list"); } if (tempLookup.find(iter->m_ijk) != NULL) { - throw CaretException("parcels may not overlap in voxels"); + throw DataFileException("parcels may not overlap in voxels"); } tempLookup.at(iter->m_ijk) = thisParcel; } @@ -76,26 +76,26 @@ void CiftiParcelsMap::addParcel(const CiftiParcelsMap::Parcel& parcel) map::const_iterator info = m_surfInfo.find(iter->first); if (info == m_surfInfo.end()) { - throw CaretException("you must set surfaces before adding parcels that use them"); + throw DataFileException("you must set surfaces before adding parcels that use them"); } const set& nodeSet = iter->second; if (nodeSet.size() == 0) { - throw CaretException("parcels may not include empty node lists");//NOTE: technically not required by Cifti, change if problematic, but probably never allow empty list in internal state + throw DataFileException("parcels may not include empty node lists");//NOTE: technically not required by Cifti, change if problematic, but probably never allow empty list in internal state } for (set::const_iterator iter2 = nodeSet.begin(); iter2 != nodeSet.end(); ++iter2) { if (*iter2 < 0) { - throw CaretException("found negative vertex in parcel"); + throw DataFileException("found negative vertex in parcel"); } if (*iter2 >= info->second.m_numNodes) { - throw CaretException("found invalid vertex in parcel"); + throw DataFileException("found invalid vertex in parcel"); } if (info->second.m_lookup[*iter2] != -1) { - throw CaretException("parcels may not overlap in vertices"); + throw DataFileException("parcels may not overlap in vertices"); } } } @@ -122,7 +122,7 @@ void CiftiParcelsMap::addSurface(const int64_t& numberOfNodes, const StructureEn map::const_iterator test = m_surfInfo.find(structure); if (test != m_surfInfo.end()) { - throw CaretException("parcel surface structures may not be used more than once"); + throw DataFileException("parcel surface structures may not be used more than once"); } SurfaceInfo tempInfo; tempInfo.m_numNodes = numberOfNodes; @@ -152,7 +152,7 @@ void CiftiParcelsMap::setVolumeSpace(const VolumeSpace& space) iter->m_ijk[1] >= dims[1] || iter->m_ijk[2] >= dims[2]) { - throw CaretException("parcels may not contain voxel indices outside the volume space"); + throw DataFileException("parcels may not contain voxel indices outside the volume space"); } } } @@ -223,7 +223,7 @@ const VolumeSpace& CiftiParcelsMap::getVolumeSpace() const CaretAssert(!m_ignoreVolSpace);//this should never be set except during parsing of cifti-1 if (!m_haveVolumeSpace) { - throw CaretException("getVolumeSpace called when no volume space exists"); + throw DataFileException("getVolumeSpace called when no volume space exists"); } return m_volSpace; } @@ -384,32 +384,32 @@ void CiftiParcelsMap::readXML1(QXmlStreamReader& xml) QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("BrainStructure")) { - throw CaretException("Surface element missing required attribute BrainStructure"); + throw DataFileException("Surface element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum tempStructure = StructureEnum::fromCiftiName(attrs.value("BrainStructure").toString(), &ok); if (!ok) { - throw CaretException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); + throw DataFileException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); } if (!attrs.hasAttribute("SurfaceNumberOfNodes")) { - throw CaretException("Surface element missing required attribute SurfaceNumberOfNodes"); + throw DataFileException("Surface element missing required attribute SurfaceNumberOfNodes"); } int64_t numNodes = attrs.value("SurfaceNumberOfNodes").toString().toLongLong(&ok); if (!ok || numNodes < 1) { - throw CaretException("invalid value for SurfaceNumberOfNodes: " + attrs.value("SurfaceNumberOfNodes").toString()); + throw DataFileException("invalid value for SurfaceNumberOfNodes: " + attrs.value("SurfaceNumberOfNodes").toString()); } addSurface(numNodes, tempStructure);//let the standard modification functions do error checking if (xml.readNextStartElement()) { - throw CaretException("unexpected element inside Surface: " + xml.name().toString()); + throw DataFileException("unexpected element inside Surface: " + xml.name().toString()); } } else if (name == "Parcel") { myParcels.push_back(readParcel1(xml)); } else { - throw CaretException("unexpected element in parcels map: " + name.toString()); + throw DataFileException("unexpected element in parcels map: " + name.toString()); } } int64_t numParcels = (int64_t)myParcels.size(); @@ -433,27 +433,27 @@ void CiftiParcelsMap::readXML2(QXmlStreamReader& xml) QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("BrainStructure")) { - throw CaretException("Surface element missing required attribute BrainStructure"); + throw DataFileException("Surface element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum tempStructure = StructureEnum::fromCiftiName(attrs.value("BrainStructure").toString(), &ok); if (!ok) { - throw CaretException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); + throw DataFileException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); } if (!attrs.hasAttribute("SurfaceNumberOfVertices")) { - throw CaretException("Surface element missing required attribute SurfaceNumberOfVertices"); + throw DataFileException("Surface element missing required attribute SurfaceNumberOfVertices"); } int64_t numNodes = attrs.value("SurfaceNumberOfVertices").toString().toLongLong(&ok); if (!ok || numNodes < 1) { - throw CaretException("invalid value for SurfaceNumberOfVertices: " + attrs.value("SurfaceNumberOfVertices").toString()); + throw DataFileException("invalid value for SurfaceNumberOfVertices: " + attrs.value("SurfaceNumberOfVertices").toString()); } addSurface(numNodes, tempStructure);//let the standard modification functions do error checking if (xml.readNextStartElement()) { - throw CaretException("unexpected element inside Surface: " + xml.name().toString()); + throw DataFileException("unexpected element inside Surface: " + xml.name().toString()); } } else if (name == "Parcel") { myParcels.push_back(readParcel2(xml)); @@ -461,14 +461,14 @@ void CiftiParcelsMap::readXML2(QXmlStreamReader& xml) } else if (name == "Volume") { if (m_haveVolumeSpace) { - throw CaretException("Volume specified more than once in Parcels mapping type"); + throw DataFileException("Volume specified more than once in Parcels mapping type"); } else { m_volSpace.readCiftiXML2(xml); if (xml.hasError()) return; m_haveVolumeSpace = true; } } else { - throw CaretException("unexpected element in parcels map: " + name.toString()); + throw DataFileException("unexpected element in parcels map: " + name.toString()); } } int64_t numParcels = (int64_t)myParcels.size(); @@ -486,7 +486,7 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel1(QXmlStreamReader& xml) QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("Name")) { - throw CaretException("Parcel element missing required attribute Name"); + throw DataFileException("Parcel element missing required attribute Name"); } ret.m_name = attrs.value("Name").toString(); while (xml.readNextStartElement()) @@ -497,17 +497,17 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel1(QXmlStreamReader& xml) QXmlStreamAttributes attrs1 = xml.attributes(); if (!attrs1.hasAttribute("BrainStructure")) { - throw CaretException("Nodes element missing required attribute BrainStructure"); + throw DataFileException("Nodes element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum myStructure = StructureEnum::fromCiftiName(attrs1.value("BrainStructure").toString(), &ok); if (!ok) { - throw CaretException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); + throw DataFileException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); } if (ret.m_surfaceNodes.find(myStructure) != ret.m_surfaceNodes.end()) { - throw CaretException("Nodes elements may not reuse a BrainStructure within a Parcel"); + throw DataFileException("Nodes elements may not reuse a BrainStructure within a Parcel"); } set& mySet = ret.m_surfaceNodes[myStructure]; vector array = readIndexArray(xml); @@ -517,34 +517,34 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel1(QXmlStreamReader& xml) { if (mySet.find(array[i]) != mySet.end()) { - throw CaretException("Nodes elements may not reuse indices"); + throw DataFileException("Nodes elements may not reuse indices"); } mySet.insert(array[i]); } } else if (name == "VoxelIndicesIJK") { if (haveVoxels) { - throw CaretException("VoxelIndicesIJK may only appear once in a Parcel"); + throw DataFileException("VoxelIndicesIJK may only appear once in a Parcel"); } vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); if (arraySize % 3 != 0) { - throw CaretException("number of indices in VoxelIndicesIJK must be a multiple of 3"); + throw DataFileException("number of indices in VoxelIndicesIJK must be a multiple of 3"); } for (int64_t index3 = 0; index3 < arraySize; index3 += 3) { VoxelIJK temp(array.data() + index3); if (ret.m_voxelIndices.find(temp) != ret.m_voxelIndices.end()) { - throw CaretException("VoxelIndicesIJK elements may not reuse voxels"); + throw DataFileException("VoxelIndicesIJK elements may not reuse voxels"); } ret.m_voxelIndices.insert(temp); } haveVoxels = true; } else { - throw CaretException("unexpected element in Parcel: " + name.toString()); + throw DataFileException("unexpected element in Parcel: " + name.toString()); } } CaretAssert(xml.isEndElement() && xml.name() == "Parcel"); @@ -558,7 +558,7 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel2(QXmlStreamReader& xml) QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("Name")) { - throw CaretException("Parcel element missing required attribute Name"); + throw DataFileException("Parcel element missing required attribute Name"); } ret.m_name = attrs.value("Name").toString(); while (xml.readNextStartElement()) @@ -569,17 +569,17 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel2(QXmlStreamReader& xml) QXmlStreamAttributes attrs1 = xml.attributes(); if (!attrs1.hasAttribute("BrainStructure")) { - throw CaretException("Vertices element missing required attribute BrainStructure"); + throw DataFileException("Vertices element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum myStructure = StructureEnum::fromCiftiName(attrs1.value("BrainStructure").toString(), &ok); if (!ok) { - throw CaretException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); + throw DataFileException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); } if (ret.m_surfaceNodes.find(myStructure) != ret.m_surfaceNodes.end()) { - throw CaretException("Vertices elements may not reuse a BrainStructure within a Parcel"); + throw DataFileException("Vertices elements may not reuse a BrainStructure within a Parcel"); } set& mySet = ret.m_surfaceNodes[myStructure]; vector array = readIndexArray(xml); @@ -589,34 +589,34 @@ CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel2(QXmlStreamReader& xml) { if (mySet.find(array[i]) != mySet.end()) { - throw CaretException("Vertices elements may not reuse indices"); + throw DataFileException("Vertices elements may not reuse indices"); } mySet.insert(array[i]); } } else if (name == "VoxelIndicesIJK") { if (haveVoxels) { - throw CaretException("VoxelIndicesIJK may only appear once in a Parcel"); + throw DataFileException("VoxelIndicesIJK may only appear once in a Parcel"); } vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); if (arraySize % 3 != 0) { - throw CaretException("number of indices in VoxelIndicesIJK must be a multiple of 3"); + throw DataFileException("number of indices in VoxelIndicesIJK must be a multiple of 3"); } for (int64_t index3 = 0; index3 < arraySize; index3 += 3) { VoxelIJK temp(array.data() + index3); if (ret.m_voxelIndices.find(temp) != ret.m_voxelIndices.end()) { - throw CaretException("VoxelIndicesIJK elements may not reuse voxels"); + throw DataFileException("VoxelIndicesIJK elements may not reuse voxels"); } ret.m_voxelIndices.insert(temp); } haveVoxels = true; } else { - throw CaretException("unexpected element in Parcel: " + name.toString()); + throw DataFileException("unexpected element in Parcel: " + name.toString()); } } CaretAssert(xml.isEndElement() && xml.name() == "Parcel"); @@ -637,7 +637,7 @@ vector CiftiParcelsMap::readIndexArray(QXmlStreamReader& xml) ret.push_back(separated[i].toLongLong(&ok)); if (!ok) { - throw CaretException("found noninteger in index array: " + separated[i]); + throw DataFileException("found noninteger in index array: " + separated[i]); } } return ret; diff --git a/src/Cifti/CiftiScalarsMap.cxx b/src/Cifti/CiftiScalarsMap.cxx index f12271014..96ac89791 100644 --- a/src/Cifti/CiftiScalarsMap.cxx +++ b/src/Cifti/CiftiScalarsMap.cxx @@ -21,7 +21,7 @@ #include "CiftiScalarsMap.h" #include "CaretAssert.h" -#include "CaretException.h" +#include "DataFileException.h" #include "CaretLogger.h" //HACK: to compare metadata in a const function, we make a copy and remove the palette data - but metadata's copy intentionally breaks == because of the UUID, so we need to reset it #include "GiftiMetaDataXmlElements.h" @@ -155,7 +155,7 @@ void CiftiScalarsMap::readXML1(QXmlStreamReader& xml) { if (xml.name() != "NamedMap") { - throw CaretException("unexpected element in scalars map: " + xml.name().toString()); + throw DataFileException("unexpected element in scalars map: " + xml.name().toString()); } m_maps.push_back(ScalarMap());//HACK: because operator= is deliberately broken by GiftiMetadata for UUID m_maps.back().readXML1(xml); @@ -180,7 +180,7 @@ void CiftiScalarsMap::readXML2(QXmlStreamReader& xml) { if (xml.name() != "NamedMap") { - throw CaretException("unexpected element in scalars map: " + xml.name().toString()); + throw DataFileException("unexpected element in scalars map: " + xml.name().toString()); } m_maps.push_back(ScalarMap());//HACK: because operator= is deliberately broken by GiftiMetadata for UUID m_maps.back().readXML2(xml); @@ -208,7 +208,7 @@ void CiftiScalarsMap::ScalarMap::readXML1(QXmlStreamReader& xml) { if (haveMetaData) { - throw CaretException("MetaData specified multiple times in one NamedMap"); + throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML1(xml); if (xml.hasError()) return; @@ -216,7 +216,7 @@ void CiftiScalarsMap::ScalarMap::readXML1(QXmlStreamReader& xml) } else if (name == "MapName") { if (haveName) { - throw CaretException("MapName specified multiple times in one NamedMap"); + throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; @@ -226,7 +226,7 @@ void CiftiScalarsMap::ScalarMap::readXML1(QXmlStreamReader& xml) xml.readElementText(QXmlStreamReader::SkipChildElements);//accept some malformed Cifti-1 files if (xml.hasError()) return; } else { - throw CaretException("unexpected element in NamedMap: " + name.toString()); + throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } @@ -236,7 +236,7 @@ void CiftiScalarsMap::ScalarMap::readXML1(QXmlStreamReader& xml) } if (!haveName) { - throw CaretException("NamedMap missing required child element MapName"); + throw DataFileException("NamedMap missing required child element MapName"); } CaretAssert(xml.isEndElement() && xml.name() == "NamedMap"); } @@ -255,7 +255,7 @@ void CiftiScalarsMap::ScalarMap::readXML2(QXmlStreamReader& xml) { if (haveMetaData) { - throw CaretException("MetaData specified multiple times in one NamedMap"); + throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML2(xml); if (xml.hasError()) return; @@ -263,13 +263,13 @@ void CiftiScalarsMap::ScalarMap::readXML2(QXmlStreamReader& xml) } else if (name == "MapName") { if (haveName) { - throw CaretException("MapName specified multiple times in one NamedMap"); + throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { - throw CaretException("unexpected element in NamedMap: " + name.toString()); + throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } @@ -279,7 +279,7 @@ void CiftiScalarsMap::ScalarMap::readXML2(QXmlStreamReader& xml) } if (!haveName) { - throw CaretException("NamedMap missing required child element MapName"); + throw DataFileException("NamedMap missing required child element MapName"); } CaretAssert(xml.isEndElement() && xml.name() == "NamedMap"); } diff --git a/src/Cifti/CiftiSeriesMap.cxx b/src/Cifti/CiftiSeriesMap.cxx index 981686ca4..8683eb280 100644 --- a/src/Cifti/CiftiSeriesMap.cxx +++ b/src/Cifti/CiftiSeriesMap.cxx @@ -21,7 +21,7 @@ #include "CiftiSeriesMap.h" #include "CaretAssert.h" -#include "CaretException.h" +#include "DataFileException.h" #include "CaretLogger.h" #include @@ -86,7 +86,7 @@ void CiftiSeriesMap::readXML1(QXmlStreamReader& xml) bool ok = false; if (!attrs.hasAttribute("TimeStepUnits")) { - throw CaretException("timepoints mapping is missing required attribute TimeStepUnits"); + throw DataFileException("timepoints mapping is missing required attribute TimeStepUnits"); } QStringRef unitString = attrs.value("TimeStepUnits"); if (unitString == "NIFTI_UNITS_SEC") @@ -97,28 +97,28 @@ void CiftiSeriesMap::readXML1(QXmlStreamReader& xml) } else if (unitString == "NIFTI_UNITS_USEC") { mult = 0.000001f; } else { - throw CaretException("unrecognized value for TimeStepUnits: " + unitString.toString()); + throw DataFileException("unrecognized value for TimeStepUnits: " + unitString.toString()); } if (attrs.hasAttribute("TimeStart"))//optional and nonstandard { newStart = mult * attrs.value("TimeStart").toString().toFloat(&ok); if (!ok) { - throw CaretException("unrecognized value for TimeStart: " + attrs.value("TimeStart").toString()); + throw DataFileException("unrecognized value for TimeStart: " + attrs.value("TimeStart").toString()); } } if (!attrs.hasAttribute("TimeStep")) { - throw CaretException("timepoints mapping is missing required attribute TimeStep"); + throw DataFileException("timepoints mapping is missing required attribute TimeStep"); } newStep = mult * attrs.value("TimeStep").toString().toFloat(&ok); if (!ok) { - throw CaretException("unrecognized value for TimeStep: " + attrs.value("TimeStep").toString()); + throw DataFileException("unrecognized value for TimeStep: " + attrs.value("TimeStep").toString()); } if (xml.readNextStartElement()) { - throw CaretException("unexpected element in timepoints map: " + xml.name().toString()); + throw DataFileException("unexpected element in timepoints map: " + xml.name().toString()); } m_length = -1;//cifti-1 doesn't know length in xml, must be set by checking the matrix m_start = newStart; @@ -136,7 +136,7 @@ void CiftiSeriesMap::readXML2(QXmlStreamReader& xml) bool ok = false; if (!attrs.hasAttribute("SeriesUnit")) { - throw CaretException("series mapping is missing required attribute SeriesUnit"); + throw DataFileException("series mapping is missing required attribute SeriesUnit"); } QStringRef unitString = attrs.value("SeriesUnit"); if (unitString == "HERTZ") @@ -149,52 +149,52 @@ void CiftiSeriesMap::readXML2(QXmlStreamReader& xml) } else if (unitString == "SECOND") { newUnit = SECOND; } else { - throw CaretException("unrecognized value for SeriesUnit: " + unitString.toString()); + throw DataFileException("unrecognized value for SeriesUnit: " + unitString.toString()); } if (!attrs.hasAttribute("SeriesExponent")) { - throw CaretException("series mapping is missing required attribute SeriesExponent"); + throw DataFileException("series mapping is missing required attribute SeriesExponent"); } int exponent = attrs.value("SeriesExponent").toString().toInt(&ok); if (!ok) { - throw CaretException("unrecognized value for SeriesExponent: " + attrs.value("SeriesExponent").toString()); + throw DataFileException("unrecognized value for SeriesExponent: " + attrs.value("SeriesExponent").toString()); } mult = pow(10.0f, exponent); if (!attrs.hasAttribute("SeriesStart")) { - throw CaretException("series mapping is missing required attribute SeriesStart"); + throw DataFileException("series mapping is missing required attribute SeriesStart"); } newStart = mult * attrs.value("SeriesStart").toString().toFloat(&ok); if (!ok) { - throw CaretException("unrecognized value for SeriesStart: " + attrs.value("SeriesStart").toString()); + throw DataFileException("unrecognized value for SeriesStart: " + attrs.value("SeriesStart").toString()); } if (!attrs.hasAttribute("SeriesStep")) { - throw CaretException("series mapping is missing required attribute SeriesStep"); + throw DataFileException("series mapping is missing required attribute SeriesStep"); } newStep = mult * attrs.value("SeriesStep").toString().toFloat(&ok); if (!ok) { - throw CaretException("unrecognized value for SeriesStep: " + attrs.value("SeriesStep").toString()); + throw DataFileException("unrecognized value for SeriesStep: " + attrs.value("SeriesStep").toString()); } if (!attrs.hasAttribute("NumberOfSeriesPoints")) { - throw CaretException("series mapping is missing required attribute NumberOfSeriesPoints"); + throw DataFileException("series mapping is missing required attribute NumberOfSeriesPoints"); } newLength = attrs.value("NumberOfSeriesPoints").toString().toLongLong(&ok); if (!ok) { - throw CaretException("unrecognized value for NumberOfSeriesPoints: " + attrs.value("NumberOfSeriesPoints").toString()); + throw DataFileException("unrecognized value for NumberOfSeriesPoints: " + attrs.value("NumberOfSeriesPoints").toString()); } if (newLength < 1) { - throw CaretException("NumberOfSeriesPoints must be positive"); + throw DataFileException("NumberOfSeriesPoints must be positive"); } if (xml.readNextStartElement()) { - throw CaretException("unexpected element in series map: " + xml.name().toString()); + throw DataFileException("unexpected element in series map: " + xml.name().toString()); } m_length = newLength; m_start = newStart; diff --git a/src/Cifti/CiftiVersion.cxx b/src/Cifti/CiftiVersion.cxx index 413cedaac..451181381 100644 --- a/src/Cifti/CiftiVersion.cxx +++ b/src/Cifti/CiftiVersion.cxx @@ -20,7 +20,7 @@ #include "CiftiVersion.h" -#include "CaretException.h" +#include "DataFileException.h" using namespace caret; @@ -44,13 +44,13 @@ CiftiVersion::CiftiVersion(const QString& versionString) { m_minor = 0; m_major = versionString.toShort(&ok); - if (!ok) throw CaretException("improperly formatted CIFTI version string: '" + versionString + "'"); + if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); } else { - if (result == 0) throw CaretException("improperly formatted CIFTI version string: '" + versionString + "'"); + if (result == 0) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); m_major = versionString.mid(0, result).toShort(&ok); - if (!ok) throw CaretException("improperly formatted CIFTI version string: '" + versionString + "'"); + if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); m_minor = versionString.mid(result + 1).toShort(&ok); - if (!ok) throw CaretException("improperly formatted CIFTI version string: '" + versionString + "'"); + if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); } } diff --git a/src/Cifti/CiftiXML.cxx b/src/Cifti/CiftiXML.cxx index 400b13f8f..53e2438ee 100644 --- a/src/Cifti/CiftiXML.cxx +++ b/src/Cifti/CiftiXML.cxx @@ -21,7 +21,7 @@ #include "CiftiXML.h" #include "CaretAssert.h" -#include "CaretException.h" +#include "DataFileException.h" #include "CaretLogger.h" #include "GiftiMetaData.h" #include "PaletteColorMapping.h" @@ -39,12 +39,12 @@ int CiftiXML::directionFromString(const QString& input) int converted = input.toInt(&ok); if (ok) { - if (converted < 1) throw CaretException("invalid integer direction, use 1 or greater"); + if (converted < 1) throw DataFileException("invalid integer direction, use 1 or greater"); return converted - 1;//use 1-indexed convention for input } if (input == "ROW") return ALONG_ROW; if (input == "COLUMN") return ALONG_COLUMN;//should we also allow STACK? integers seem cleaner - throw CaretException("unrecognized direction string, please use an integer, 'ROW', or 'COLUMN'"); + throw DataFileException("unrecognized direction string, please use an integer, 'ROW', or 'COLUMN'"); } QString CiftiXML::directionFromStringExplanation() @@ -251,7 +251,7 @@ void CiftiXML::setMap(const int& direction, const CiftiMappingType& mapIn) { if (i != direction && m_indexMaps[i] != NULL && m_indexMaps[i]->getType() == CiftiMappingType::LABELS) { - throw CaretException("Cifti XML cannot contain a label mapping on more than one dimension"); + throw DataFileException("Cifti XML cannot contain a label mapping on more than one dimension"); } } } @@ -323,7 +323,7 @@ int32_t CiftiXML::getIntentInfo(const CiftiVersion& writingVersion, char intentN break; } } else { - throw CaretException("unknown cifti version: " + writingVersion.toString()); + throw DataFileException("unknown cifti version: " + writingVersion.toString()); } int i; for (i = 0; i < 16 && name[i] != '\0'; ++i) intentNameOut[i] = name[i]; @@ -346,14 +346,14 @@ void CiftiXML::readXML(QXmlStreamReader& xml) { if (haveCifti) { - throw CaretException("CIFTI element may only be specified once"); + throw DataFileException("CIFTI element may only be specified once"); } QXmlStreamAttributes attributes = xml.attributes(); if(attributes.hasAttribute("Version")) { m_parsedVersion = CiftiVersion(attributes.value("Version").toString()); } else { - throw CaretException("Cifti XML missing Version attribute."); + throw DataFileException("Cifti XML missing Version attribute."); } if (m_parsedVersion == CiftiVersion(1, 0))//switch/case on major/minor would be much harder to read { @@ -367,24 +367,24 @@ void CiftiXML::readXML(QXmlStreamReader& xml) parseCIFTI2(xml); if (xml.hasError()) break; } else { - throw CaretException("unknown Cifti Version: '" + m_parsedVersion.toString()); + throw DataFileException("unknown Cifti Version: '" + m_parsedVersion.toString()); } haveCifti = true; } else { - throw CaretException("unexpected root element in Cifti XML: " + name.toString()); + throw DataFileException("unexpected root element in Cifti XML: " + name.toString()); } } } if (!xml.hasError() && !haveCifti) { - throw CaretException("CIFTI element not found"); + throw DataFileException("CIFTI element not found"); } } catch (CaretException& e) { - throw CaretException("Cifti XML error: " + e.whatString());//so we can throw on error instead of doing a bunch of dancing with xml.raiseError and xml.hasError + throw DataFileException("Cifti XML error: " + e.whatString());//so we can throw on error instead of doing a bunch of dancing with xml.raiseError and xml.hasError } if(xml.hasError()) { - throw CaretException("Cifti XML error: " + xml.errorString()); + throw DataFileException("Cifti XML error: " + xml.errorString()); } } @@ -395,10 +395,10 @@ void CiftiXML::parseCIFTI1(QXmlStreamReader& xml) { if (attributes.value("NumberOfMatrices") != "1") { - throw CaretException("attribute NumberOfMatrices in CIFTI is required to be 1 for CIFTI-1"); + throw DataFileException("attribute NumberOfMatrices in CIFTI is required to be 1 for CIFTI-1"); } } else { - throw CaretException("missing attribute NumberOfMatrices in CIFTI"); + throw DataFileException("missing attribute NumberOfMatrices in CIFTI"); } bool haveMatrix = false; while (!xml.atEnd()) @@ -411,13 +411,13 @@ void CiftiXML::parseCIFTI1(QXmlStreamReader& xml) { if (haveMatrix) { - throw CaretException("Matrix element may only be specified once"); + throw DataFileException("Matrix element may only be specified once"); } parseMatrix1(xml); if (xml.hasError()) return; haveMatrix = true; } else { - throw CaretException("unexpected element in CIFTI: " + name.toString()); + throw DataFileException("unexpected element in CIFTI: " + name.toString()); } } else if (xml.isEndElement()) { break; @@ -425,7 +425,7 @@ void CiftiXML::parseCIFTI1(QXmlStreamReader& xml) } if (!haveMatrix) { - throw CaretException("Matrix element not found in CIFTI"); + throw DataFileException("Matrix element not found in CIFTI"); } if (xml.hasError()) return; CaretAssert(xml.isEndElement() && xml.name() == "CIFTI"); @@ -445,13 +445,13 @@ void CiftiXML::parseCIFTI2(QXmlStreamReader& xml)//yes, these will often have la { if (haveMatrix) { - throw CaretException("Matrix element may only be specified once"); + throw DataFileException("Matrix element may only be specified once"); } parseMatrix2(xml); if (xml.hasError()) return; haveMatrix = true; } else { - throw CaretException("unexpected element in CIFTI: " + name.toString()); + throw DataFileException("unexpected element in CIFTI: " + name.toString()); } } else if (xml.isEndElement()) { break; @@ -459,7 +459,7 @@ void CiftiXML::parseCIFTI2(QXmlStreamReader& xml)//yes, these will often have la } if (!haveMatrix) { - throw CaretException("Matrix element not found in CIFTI"); + throw DataFileException("Matrix element not found in CIFTI"); } CaretAssert(xml.isEndElement() && xml.name() == "CIFTI"); } @@ -479,7 +479,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) { if (haveMetadata) { - throw CaretException("MetaData may only be specified once in Matrix"); + throw DataFileException("MetaData may only be specified once in Matrix"); } m_fileMetaData.readCiftiXML1(xml); if (xml.hasError()) return; @@ -490,7 +490,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) } else if (name == "Volume") { if (haveVolSpace) { - throw CaretException("Volume may only be specified once in Matrix"); + throw DataFileException("Volume may only be specified once in Matrix"); } fileVolSpace.readCiftiXML1(xml); if (xml.hasError()) return; @@ -499,7 +499,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) CaretLogFiner("skipping unused LabelTable element in Matrix in CIFTI-1"); xml.readElementText(QXmlStreamReader::SkipChildElements); } else { - throw CaretException("unexpected element in Matrix: " + name.toString()); + throw DataFileException("unexpected element in Matrix: " + name.toString()); } } else if (xml.isEndElement()) { break; @@ -511,7 +511,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) { int displaynum = i; if (displaynum < 2) displaynum = 1 - displaynum;//re-invert so that it shows the same number as the XML is missing - throw CaretException("missing mapping for dimension '" + QString::number(displaynum) + "'"); + throw DataFileException("missing mapping for dimension '" + QString::number(displaynum) + "'"); } switch (m_indexMaps[i]->getType()) { @@ -524,7 +524,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) { myMap.setVolumeSpace(fileVolSpace);//also does the needed checking of voxel indices } else { - throw CaretException("BrainModels map uses voxels, but no Volume element exists"); + throw DataFileException("BrainModels map uses voxels, but no Volume element exists"); } } break; @@ -538,7 +538,7 @@ void CiftiXML::parseMatrix1(QXmlStreamReader& xml) { myMap.setVolumeSpace(fileVolSpace);//ditto } else { - throw CaretException("Parcels map uses voxels, but no Volume element exists"); + throw DataFileException("Parcels map uses voxels, but no Volume element exists"); } } break; @@ -564,7 +564,7 @@ void CiftiXML::parseMatrix2(QXmlStreamReader& xml) { if (haveMetadata) { - throw CaretException("MetaData may only be specified once in Matrix"); + throw DataFileException("MetaData may only be specified once in Matrix"); } m_fileMetaData.readCiftiXML2(xml); if (xml.hasError()) return; @@ -573,7 +573,7 @@ void CiftiXML::parseMatrix2(QXmlStreamReader& xml) parseMatrixIndicesMap2(xml); if (xml.hasError()) return; } else { - throw CaretException("unexpected element in Matrix: " + name.toString()); + throw DataFileException("unexpected element in Matrix: " + name.toString()); } } else if (xml.isEndElement()) { break; @@ -583,7 +583,7 @@ void CiftiXML::parseMatrix2(QXmlStreamReader& xml) { if (m_indexMaps[i] == NULL) { - throw CaretException("missing mapping for dimension '" + QString::number(i) + "'"); + throw DataFileException("missing mapping for dimension '" + QString::number(i) + "'"); } } CaretAssert(xml.isEndElement() && xml.name() == "Matrix"); @@ -594,11 +594,11 @@ void CiftiXML::parseMatrixIndicesMap1(QXmlStreamReader& xml) QXmlStreamAttributes attributes = xml.attributes(); if (!attributes.hasAttribute("AppliesToMatrixDimension")) { - throw CaretException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); + throw DataFileException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); } if (!attributes.hasAttribute("IndicesMapToDataType")) { - throw CaretException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); + throw DataFileException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); } QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); bool ok = false; @@ -608,12 +608,12 @@ void CiftiXML::parseMatrixIndicesMap1(QXmlStreamReader& xml) int parsed = values[i].toInt(&ok); if (!ok || parsed < 0) { - throw CaretException("bad value in AppliesToMatrixDimension list: " + values[i]); + throw DataFileException("bad value in AppliesToMatrixDimension list: " + values[i]); } if (parsed < 2) parsed = 1 - parsed;//in other words, 0 becomes 1 and 1 becomes 0, since cifti-1 had them reversed if (used.find(parsed) != used.end()) { - throw CaretException("AppliesToMatrixDimension contains repeated value: " + values[i]); + throw DataFileException("AppliesToMatrixDimension contains repeated value: " + values[i]); } used.insert(parsed); } @@ -631,7 +631,7 @@ void CiftiXML::parseMatrixIndicesMap1(QXmlStreamReader& xml) } else if (type == "CIFTI_INDEX_TYPE_SCALARS") { toRead = CaretPointer(new CiftiScalarsMap()); } else { - throw CaretException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); + throw DataFileException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); } toRead->readXML1(xml);//this will warn (with 'finer' log level?) if it is nonstandard if (xml.hasError()) return; @@ -655,11 +655,11 @@ void CiftiXML::parseMatrixIndicesMap2(QXmlStreamReader& xml) QXmlStreamAttributes attributes = xml.attributes(); if (!attributes.hasAttribute("AppliesToMatrixDimension")) { - throw CaretException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); + throw DataFileException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); } if (!attributes.hasAttribute("IndicesMapToDataType")) { - throw CaretException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); + throw DataFileException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); } QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); bool ok = false; @@ -669,11 +669,11 @@ void CiftiXML::parseMatrixIndicesMap2(QXmlStreamReader& xml) int parsed = values[i].toInt(&ok); if (!ok || parsed < 0) { - throw CaretException("bad value in AppliesToMatrixDimension list: " + values[i]); + throw DataFileException("bad value in AppliesToMatrixDimension list: " + values[i]); } if (used.find(parsed) != used.end()) { - throw CaretException("AppliesToMatrixDimension contains repeated value: " + values[i]); + throw DataFileException("AppliesToMatrixDimension contains repeated value: " + values[i]); } used.insert(parsed); } @@ -691,7 +691,7 @@ void CiftiXML::parseMatrixIndicesMap2(QXmlStreamReader& xml) } else if (type == "CIFTI_INDEX_TYPE_SERIES") { toRead = CaretPointer(new CiftiSeriesMap()); } else { - throw CaretException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); + throw DataFileException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); } toRead->readXML2(xml); if (xml.hasError()) return; @@ -746,7 +746,7 @@ void CiftiXML::writeXML(QXmlStreamWriter& xml, const CiftiVersion& writingVersio } else if (writingVersion == CiftiVersion(2, 0)) { writeMatrix2(xml); } else { - throw CaretException("unknown Cifti writing version: '" + writingVersion.toString() + "'"); + throw DataFileException("unknown Cifti writing version: '" + writingVersion.toString() + "'"); } xml.writeEndElement(); } @@ -758,7 +758,7 @@ void CiftiXML::writeMatrix1(QXmlStreamWriter& xml) const VolumeSpace volSpace; for (int i = 0; i < numDims; ++i) { - if (m_indexMaps[i] == NULL) throw CaretException("dimension " + QString::number(i) + " was not given a mapping"); + if (m_indexMaps[i] == NULL) throw DataFileException("dimension " + QString::number(i) + " was not given a mapping"); switch (m_indexMaps[i]->getType()) { case CiftiMappingType::BRAIN_MODELS: @@ -770,7 +770,7 @@ void CiftiXML::writeMatrix1(QXmlStreamWriter& xml) const { if (myMap.getVolumeSpace() != volSpace) { - throw CaretException("cannot write different volume spaces for different dimensions in CIFTI-1"); + throw DataFileException("cannot write different volume spaces for different dimensions in CIFTI-1"); } } else { haveVolData = true; @@ -788,7 +788,7 @@ void CiftiXML::writeMatrix1(QXmlStreamWriter& xml) const { if (myMap.getVolumeSpace() != volSpace) { - throw CaretException("cannot write different volume spaces for different dimensions in CIFTI-1"); + throw DataFileException("cannot write different volume spaces for different dimensions in CIFTI-1"); } } else { haveVolData = true; @@ -847,7 +847,7 @@ void CiftiXML::writeMatrix2(QXmlStreamWriter& xml) const int numDims = (int)m_indexMaps.size(); for (int i = 0; i < numDims; ++i) { - if (m_indexMaps[i] == NULL) throw CaretException("dimension " + QString::number(i) + " was not given a mapping"); + if (m_indexMaps[i] == NULL) throw DataFileException("dimension " + QString::number(i) + " was not given a mapping"); } xml.writeStartElement("Matrix"); if (m_filePalette != NULL) -- GitLab From 47defc0ea750c013ffac4a737370f08f5090e34e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Apr 2017 15:39:57 -0500 Subject: [PATCH 129/755] On Identify Brainordinate Dialog, start the CIFTI File Row Index at 1 and perform an identify operation when the value is changed by clicking an arrow or pressing the return key. --- src/GuiQt/IdentifyBrainordinateDialog.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/IdentifyBrainordinateDialog.cxx b/src/GuiQt/IdentifyBrainordinateDialog.cxx index 93c377c1b..260e4f94f 100644 --- a/src/GuiQt/IdentifyBrainordinateDialog.cxx +++ b/src/GuiQt/IdentifyBrainordinateDialog.cxx @@ -332,9 +332,11 @@ IdentifyBrainordinateDialog::createCiftiRowWidget(const std::vector::max(), 1); + QObject::connect(m_ciftiRowFileIndexSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(apply())); m_ciftiRowFileIndexSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at zero."); @@ -748,7 +750,7 @@ IdentifyBrainordinateDialog::processCiftiRowWidget(AString& errorMessageOut) CiftiMappableDataFile* ciftiMapFile = dynamic_cast(dataFile); CiftiFiberTrajectoryFile* ciftiTrajFile = dynamic_cast(dataFile); - const int32_t selectedCiftiRowIndex = m_ciftiRowFileIndexSpinBox->value(); + const int32_t selectedCiftiRowIndex = m_ciftiRowFileIndexSpinBox->value() - m_ciftiRowFileIndexSpinBox->minimum(); try { StructureEnum::Enum surfaceStructure; -- GitLab From 837b2408bbf1cc027443eb48be816bbc7135f1c3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 6 Apr 2017 12:46:11 -0500 Subject: [PATCH 130/755] Fixed compilation warning that was acutually a bug in CiftiBrainordinateDataSeriesFile.cxx. What should be of been a pointer symbol '->' was missing the '>' and performing subtraction. --- src/Files/CiftiBrainordinateDataSeriesFile.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Files/CiftiBrainordinateDataSeriesFile.cxx b/src/Files/CiftiBrainordinateDataSeriesFile.cxx index 96dc6a4b3..a40b36195 100644 --- a/src/Files/CiftiBrainordinateDataSeriesFile.cxx +++ b/src/Files/CiftiBrainordinateDataSeriesFile.cxx @@ -106,7 +106,7 @@ CiftiBrainordinateDataSeriesFile::initializeDenseDynamicFile() GiftiMetaData* fileMetaData = m_ciftiFile->getCiftiXML().getFileMetaData(); const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); if ( ! encodedPaletteColorMappingString.isEmpty()) { - if (m_lazyInitializedDenseDynamicFile-getNumberOfMaps() > 0) { + if (m_lazyInitializedDenseDynamicFile->getNumberOfMaps() > 0) { PaletteColorMapping* pcm = m_lazyInitializedDenseDynamicFile->getMapPaletteColorMapping(0); CaretAssert(pcm); pcm->decodeFromStringXML(encodedPaletteColorMappingString); @@ -171,7 +171,7 @@ CiftiBrainordinateDataSeriesFile::writeFile(const AString& ciftiMapFileName) if (m_lazyInitializedDenseDynamicFile != NULL) { GiftiMetaData* fileMetaData = m_ciftiFile->getCiftiXML().getFileMetaData(); CaretAssert(fileMetaData); - if (m_lazyInitializedDenseDynamicFile-getNumberOfMaps() > 0) { + if (m_lazyInitializedDenseDynamicFile->getNumberOfMaps() > 0) { fileMetaData->set(s_paletteColorMappingNameInMetaData, m_lazyInitializedDenseDynamicFile->getMapPaletteColorMapping(0)->encodeInXML()); } -- GitLab From b2fc9abb8ef70121158c719738678e82e880c1f9 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 6 Apr 2017 17:40:23 -0500 Subject: [PATCH 131/755] update readme to saying qt5 is required --- README | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README b/README index 7984b23b5..e79505c77 100644 --- a/README +++ b/README @@ -1,19 +1,17 @@ -Connectome Workbench requires QT4 or QT5 to compile. Recommended is the latest 4.8.x release, or 5.6 or later. For QT4, try the following configure options: +Connectome Workbench requires QT5 to compile. Recommended is version 5.6 or later (due to an issue with the toolbar size on earlier versions). --system-zlib -no-webkit -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -nomake demos -nomake examples -no-qt3support -no-dbus -opensource -exceptions -stl -no-multimedia -no-phonon -no-audio-backend -openssl +It is highly recommended to compile with OSMesa, which allow the -show-scene command and the "render pixmap" image capture method to work. Use it by setting the *cmake* variable WORKBENCH_MESA_DIR, such that ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h exists. -It is highly recommended to compile with OSMesa, which allow the -show-scene command and the "render pixmap" image capture method to work. Use it by setting OSMESA_DIR as an environment variable, such that $OSMESA_DIR/include/GL/osmesa.h exists, before running cmake. - -It is compiled using cmake, on linux do: +It is compiled using cmake, for example, on linux you can do: mkdir build cd build -cmake -D CMAKE_BUILD_TYPE=Release ../workbench/src -make +cmake -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr -D WORKBENCH_USE_QT5=TRUE ../workbench/src +nice make -j8 For other OSes, see http://www.cmake.org/cmake/help/runningcmake.html -Also note the -j flag of "make" (like "make -j4") can be used to speed up the build by compiling multiple source files at the same time. +Note the -j flag of "make" is used in the example to speed up the build by compiling multiple source files at the same time. If you have a different number of cores/hardware threads or want to reduce the load, adjust it accordingly. The "nice" command is not needed, it is used to make the compilation have less priority than other processes. This produces 3 executables, 2 of which are useful to the end user (Desktop/wb_view, CommandLine/wb_command), and one for running internal tests (Tests/test_driver). @@ -29,7 +27,7 @@ make install It should be noted that wb_import, provided in the HCP binary releases of Connectome Workbench, is actually part of caret5 (http://brainvis.wustl.edu/wiki/index.php/Caret:Download). -Connectome Workbench itself is licensed under GPLv2 or later, copyright 2014-2016 Washington University School of Medicine, see LICENSE file +Connectome Workbench itself is licensed under GPLv2 or later, copyright 2014-2017 Washington University School of Medicine, see LICENSE file Some source files are licensed under an MIT license (Expat), for easier code reuse in non-GPL projects: Files/SurfaceResamplingHelper.cxx -- GitLab From 589f067652c5278d69b27f5b08bba46c9bc3c5ec Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 7 Apr 2017 09:48:53 -0500 Subject: [PATCH 132/755] Correct tooltip on Identify Brainordinate Dialog row index to indicate that rows start at one --- src/GuiQt/IdentifyBrainordinateDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/IdentifyBrainordinateDialog.cxx b/src/GuiQt/IdentifyBrainordinateDialog.cxx index 260e4f94f..8348040dd 100644 --- a/src/GuiQt/IdentifyBrainordinateDialog.cxx +++ b/src/GuiQt/IdentifyBrainordinateDialog.cxx @@ -338,7 +338,7 @@ IdentifyBrainordinateDialog::createCiftiRowWidget(const std::vectorsetFixedWidth(INDEX_SPIN_BOX_WIDTH); - m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at zero."); + m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at one."); QWidget* widget = new QWidget(); QGridLayout* ciftiRowLayout = new QGridLayout(widget); -- GitLab From d8586aa051a70b8402cbd88489a28393d1fbdeb8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 7 Apr 2017 11:05:24 -0500 Subject: [PATCH 133/755] CIFTI row/column indices in the graphical user interface now start at one. This includes the Identify Brainordinate dialog and text in the Identify Window. This "base index" is controlled by the protected variable CiftiMappableDataFile::CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI and the public function CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI(). To go back to zero-based indices in the GUI, one only needs to change the value of CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI. --- ...CiftiConnectivityMatrixDataFileManager.cxx | 28 +++++------ src/Brain/IdentificationTextGenerator.cxx | 4 +- ...iftiMappableConnectivityMatrixDataFile.cxx | 46 +++++++++---------- src/Files/CiftiMappableDataFile.cxx | 9 ++++ src/Files/CiftiMappableDataFile.h | 14 ++++++ src/GuiQt/IdentifyBrainordinateDialog.cxx | 14 +++++- 6 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/Brain/CiftiConnectivityMatrixDataFileManager.cxx b/src/Brain/CiftiConnectivityMatrixDataFileManager.cxx index b22814cfe..66298a700 100644 --- a/src/Brain/CiftiConnectivityMatrixDataFileManager.cxx +++ b/src/Brain/CiftiConnectivityMatrixDataFileManager.cxx @@ -195,7 +195,7 @@ CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromParcelFile(Brain* bra paletteFile); rowColumnInformationOut.push_back(pf->getFileNameNoPath() + " column index=" - + AString::number(rowColumnIndexToLoad)); + + AString::number(rowColumnIndexToLoad + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: pf->loadDataForRowIndex(rowColumnIndexToLoad); @@ -203,7 +203,7 @@ CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromParcelFile(Brain* bra paletteFile); rowColumnInformationOut.push_back(pf->getFileNameNoPath() + " row index=" - + AString::number(rowColumnIndexToLoad)); + + AString::number(rowColumnIndexToLoad + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); break; } } @@ -227,7 +227,7 @@ CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromConnectivityMatrixFil paletteFile); rowColumnInformationOut.push_back(ciftiConnMatrixFile->getFileNameNoPath() + " row index=" - + AString::number(rowIndex)); + + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { ciftiConnMatrixFile->loadDataForColumnIndex(columnIndex); @@ -235,7 +235,7 @@ CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromConnectivityMatrixFil paletteFile); rowColumnInformationOut.push_back(ciftiConnMatrixFile->getFileNameNoPath() + " column index=" - + AString::number(columnIndex)); + + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } return true; @@ -292,20 +292,20 @@ CiftiConnectivityMatrixDataFileManager::loadDataForSurfaceNode(Brain* brain, * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() - + " nodeIndex=" + + " vertex index=" + AString::number(nodeIndex) - + ", row index= " - + AString::number(rowIndex)); + + ", row index=" + + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() - + " nodeIndex=" + + " vertex index=" + AString::number(nodeIndex) - + ", column index= " - + AString::number(columnIndex)); + + ", column index=" + + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } } } @@ -409,8 +409,8 @@ CiftiConnectivityMatrixDataFileManager::loadDataForVoxelAtCoordinate(Brain* brai rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " Voxel XYZ=" + AString::fromNumbers(xyz, 3, ",") - + ", row index= " - + AString::number(rowIndex)); + + ", row index=" + + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { /* @@ -419,8 +419,8 @@ CiftiConnectivityMatrixDataFileManager::loadDataForVoxelAtCoordinate(Brain* brai rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " Voxel XYZ=" + AString::fromNumbers(xyz, 3, ",") - + ", column index= " - + AString::number(columnIndex)); + + ", column index=" + + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } } } diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 660eb19e8..ccf7508e7 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -799,12 +799,12 @@ IdentificationTextGenerator::generateCiftiConnectivityMatrixIdentificationText(I if (validData) { if (rowIndex >= 0) { idText.addLine(true, - ("Row " + AString::number(rowIndex + 1)), + ("Row " + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())), rowName); } if (colIndex >= 0) { idText.addLine(true, - ("Column " + AString::number(colIndex + 1)), + ("Column " + AString::number(colIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())), colName); } } diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx index c88434743..589db8589 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx @@ -664,17 +664,17 @@ CiftiMappableConnectivityMatrixDataFile::loadDataForRowIndex(const int64_t rowIn if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())) { m_rowLoadedTextForMapName = ("Row: " - + AString::number(rowIndex)); + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_rowLoadedText = ("Row_" - + AString::number(rowIndex)); + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); CaretAssert((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())); m_loadedRowData.resize(dataCount); getProcessedDataForRow(&m_loadedRowData[0], rowIndex); - CaretLogFine("Read row " + AString::number(rowIndex)); + CaretLogFine("Read row " + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_connectivityDataLoaded->setRowColumnLoading(rowIndex, -1); } @@ -705,17 +705,17 @@ CiftiMappableConnectivityMatrixDataFile::loadDataForColumnIndex(const int64_t co if ((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { m_rowLoadedTextForMapName = ("Column: " - + AString::number(columnIndex)); + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_rowLoadedText = ("Column_" - + AString::number(columnIndex)); + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); CaretAssert((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())); m_loadedRowData.resize(dataCount); getProcessedDataForColumn(&m_loadedRowData[0], columnIndex); - CaretLogFine("Read column " + AString::number(columnIndex)); + CaretLogFine("Read column " + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_connectivityDataLoaded->setRowColumnLoading(-1, columnIndex); } @@ -806,15 +806,15 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t if (dataCount > 0) { m_rowLoadedTextForMapName = ("Row: " - + AString::number(rowIndex) - + ", Node Index: " + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + + ", Vertex Index: " + AString::number(nodeIndex) + ", Structure: " + StructureEnum::toName(structure)); m_rowLoadedText = ("Row_" - + AString::number(rowIndex) - + "_Node_Index_" + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + + "_Vertex_Index_" + AString::number(nodeIndex) + "_Structure_" + StructureEnum::toGuiName(structure)); @@ -823,7 +823,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t getProcessedDataForRow(&m_loadedRowData[0], rowIndex); - CaretLogFine("Read row for node " + AString::number(nodeIndex)); + CaretLogFine("Read row for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->setSurfaceNodeLoading(structure, surfaceNumberOfNodes, @@ -839,15 +839,15 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t const int64_t dataCount = m_ciftiFile->getNumberOfRows(); if (dataCount > 0) { m_rowLoadedTextForMapName = ("Column: " - + AString::number(columnIndex) - + ", Node Index: " + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + + ", Vertex Index: " + AString::number(nodeIndex) + ", Structure: " + StructureEnum::toName(structure)); m_rowLoadedText = ("Column_" - + AString::number(columnIndex) - + "_Node_Index_" + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + + "_Vertex_Index_" + AString::number(nodeIndex) + "_Structure_" + StructureEnum::toGuiName(structure)); @@ -856,7 +856,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t getProcessedDataForColumn(&m_loadedRowData[0], columnIndex); - CaretLogFine("Read column for node " + AString::number(nodeIndex)); + CaretLogFine("Read column for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->setSurfaceNodeLoading(structure, surfaceNumberOfNodes, @@ -869,7 +869,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t } if (dataWasLoaded == false) { - CaretLogFine("FAILED to read data for node " + AString::number(nodeIndex)); + CaretLogFine("FAILED to read data for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->reset(); } } @@ -880,7 +880,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t updateForChangeInMapDataWithMapIndex(0); - AString msg = ("Time load data for surface node in " + AString msg = ("Time load data for surface vertex in " + getFileNameNoPath() + " was " + AString::number(timer.getElapsedTimeSeconds()) @@ -979,7 +979,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapAverageDataForSurfaceNodes(const } if (dataWasLoaded == false) { - CaretLogFine("FAILED to read data for node average" + AString::fromNumbers(nodeIndices, ",")); + CaretLogFine("FAILED to read data for vertex average" + AString::fromNumbers(nodeIndices, ",")); } updateForChangeInMapDataWithMapIndex(0); @@ -1064,13 +1064,13 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForVoxelAtCoordinate(const i rowIndex); m_rowLoadedTextForMapName = ("Row: " - + AString::number(rowIndex) + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Voxel XYZ: (" + AString::fromNumbers(xyz, 3, ",") + ")"); m_rowLoadedText = ("Row_" - + AString::number(rowIndex) + + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Voxel_XYZ_" + AString::fromNumbers(xyz, 3, "_").replace('-', 'm')); @@ -1089,13 +1089,13 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForVoxelAtCoordinate(const i columnIndex); m_rowLoadedTextForMapName = ("Column: " - + AString::number(columnIndex) + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Voxel XYZ: (" + AString::fromNumbers(xyz, 3, ",") + ")"); m_rowLoadedText = ("Column_" - + AString::number(columnIndex) + + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Voxel_XYZ_" + AString::fromNumbers(xyz, 3, "_").replace('-', 'm')); diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index e8ac6b79e..0b12ecc10 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -75,6 +75,15 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi m_classNameHierarchy.grabNew(NULL); m_fileDataReadingType = FILE_READ_DATA_ALL; + switch (CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) { + case 0: + case 1: + break; + default: + CaretAssertMessage(0, "CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI must be zero or one!"); + break; + } + m_containsSurfaceData = false; m_containsVolumeData = false; m_mappingTimeStart = 0.0; diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 1af9f54bf..69ce9c372 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -455,6 +455,11 @@ namespace caret { const CiftiXML getCiftiXML() const; + /** + * @return The index base (zero or one) for displaying row and column indices in the Graphical User Interface + */ + static inline int32_t getCiftiFileRowColumnIndexBaseForGUI() { return CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI; } + private: CiftiMappableDataFile(const CiftiMappableDataFile&); @@ -744,6 +749,15 @@ namespace caret { static const int32_t S_CIFTI_XML_ALONG_INVALID; + protected: + /** + * This value is used for the "base index" of CIFTI rows/columns + * in the user-interface. + */ + static const int32_t CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI = 1; + + private: + // std::vector m_ciftiDimensions; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/IdentifyBrainordinateDialog.cxx b/src/GuiQt/IdentifyBrainordinateDialog.cxx index 8348040dd..1f8fdd28d 100644 --- a/src/GuiQt/IdentifyBrainordinateDialog.cxx +++ b/src/GuiQt/IdentifyBrainordinateDialog.cxx @@ -332,13 +332,23 @@ IdentifyBrainordinateDialog::createCiftiRowWidget(const std::vector::max(), 1); QObject::connect(m_ciftiRowFileIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(apply())); m_ciftiRowFileIndexSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); - m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at one."); + switch (CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI()) { + case 0: + m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at zero."); + break; + case 1: + m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at one."); + break; + default: + CaretAssert(0); + m_ciftiRowFileIndexSpinBox->setToolTip("PROGRAM ERROR CIFTI FILE ROW/COLUMN BASE INDEX SHOULD BE ONE OR ZERO."); + } QWidget* widget = new QWidget(); QGridLayout* ciftiRowLayout = new QGridLayout(widget); -- GitLab From b45d206971b9e2aafed9e04621e3cab8f9500782 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 11 Apr 2017 09:45:38 -0500 Subject: [PATCH 134/755] Resolve WB-676 wb_view crash if all surfaces removed and an ID operation is performed on volume slice: Each hemisphere has its own "BrainStructure" in the source code. The BrainStructure should be "deleted" when all of its files have been removed but this was not performed. Since the BrainStructure was not deleted, there was an attempt to ID on a non-existent (NULL) surface causing a crash. In addition, Montage View was still available even though no surfaces were loaded. Now, when files are removed any "empty" BrainStructures are removed. All tab names are also updated when files toolbar is updated. --- src/Brain/Brain.cxx | 25 +++++++++++++++++++++++++ src/Brain/Brain.h | 2 ++ src/Brain/BrainStructure.cxx | 13 +++++++++++++ src/Brain/BrainStructure.h | 2 ++ src/GuiQt/BrainBrowserWindowToolBar.cxx | 13 ++++++++++++- src/GuiQt/BrainBrowserWindowToolBar.h | 1 + 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index e48cd3447..197a34118 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -370,6 +370,30 @@ Brain::getBrainStructure(StructureEnum::Enum structure, return NULL; } +/** + * Update brain structures by removing any that contain zero data files + */ +void +Brain::updateBrainStructures() +{ + std::vector validBrainStructures; + + for (auto bs : m_brainStructures) { + CaretAssert(bs); + if (bs->hasDataFiles()) { + validBrainStructures.push_back(bs); + } + else { + delete bs; + } + } + + if (m_brainStructures.size() != validBrainStructures.size()) { + m_brainStructures = validBrainStructures; + } +} + + /** * Increment and return the duplicate counter for the given data file type. * @@ -5215,6 +5239,7 @@ Brain::readDataFile(const DataFileTypeEnum::Enum dataFileType, void Brain::updateAfterFilesAddedOrRemoved() { + updateBrainStructures(); updateChartModel(); updateVolumeSliceModel(); updateWholeBrainModel(); diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index 742f08dcb..488b63714 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -691,6 +691,8 @@ namespace caret { void updateSurfaceMontageModel(); + void updateBrainStructures(); + void updateFiberTrajectoryMatchingFiberOrientationFiles(); void validateCiftiMappableDataFile(const CiftiMappableDataFile* ciftiMapFile) const; diff --git a/src/Brain/BrainStructure.cxx b/src/Brain/BrainStructure.cxx index 2dc4807ef..59165150b 100644 --- a/src/Brain/BrainStructure.cxx +++ b/src/Brain/BrainStructure.cxx @@ -1109,6 +1109,19 @@ BrainStructure::getNodeAttributes() const return m_nodeAttributes; } +/** + * @return True if this brain structure contains any data files, else false. + */ +bool +BrainStructure::hasDataFiles() const +{ + std::vector allDataFiles; + getAllDataFiles(allDataFiles); + + return ( ! allDataFiles.empty()); +} + + /** * Get all loaded data files. * @param allDataFilesOut diff --git a/src/Brain/BrainStructure.h b/src/Brain/BrainStructure.h index 58d535a48..1a9f7f581 100644 --- a/src/Brain/BrainStructure.h +++ b/src/Brain/BrainStructure.h @@ -149,6 +149,8 @@ namespace caret { const BrainStructureNodeAttributes* getNodeAttributes() const; + bool hasDataFiles() const; + void getAllDataFiles(std::vector& allDataFilesOut) const; bool removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 6d663aa6b..6aecc4aac 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1168,6 +1168,17 @@ BrainBrowserWindowToolBar::renameTab() } +/** + * Update the names of all tabs. + */ +void +BrainBrowserWindowToolBar::updateAllTabNames() +{ + for (int32_t i = 0; i < this->tabBar->count(); i++) { + updateTabName(i); + } +} + /** * Update the name of the tab at the given index. The * name is obtained from the tabs browser content. @@ -1462,7 +1473,7 @@ BrainBrowserWindowToolBar::updateToolBar() CaretLogSevere("Update counter is non-zero at end of updateToolBar()"); } - this->updateTabName(-1); + this->updateAllTabNames(); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); if (browserWindow != NULL) { diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 1dedb2472..e8659c2ff 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -128,6 +128,7 @@ namespace caret { void updateGraphicsWindow(); void updateUserInterface(); void updateToolBox(); + void updateAllTabNames(); void updateTabName(const int32_t tabIndex); void updateOtherYokedWindows(); -- GitLab From 78e61e6fd0af5f675d2c21f6915e475d2da36d58 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 17 Apr 2017 17:14:03 -0500 Subject: [PATCH 135/755] Implemented WB-673 New flag for wb_command -show-scene to adjust yoking index: Added option -set-map-yoke that allows one to change the selected map index for overlays with a specific map yoking group selected. [-set-map-yoke] - Override selected map index for a map yoking group. - Roman numeral identifying the map yoking group (I, II, III, IV, V, VI, VII, VIII, IX, X - Map index for yoking group. Indices start at 1 (one) --- src/Operations/OperationShowScene.cxx | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 59df02ca8..39c1d9525 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -37,11 +37,13 @@ #include "CaretLogger.h" #include "DataFileException.h" #include "EventBrowserTabGet.h" +#include "EventMapYokingSelectMap.h" #include "EventManager.h" #include "FileInformation.h" #include "DummyFontTextRenderer.h" #include "FtglFontTextRenderer.h" #include "ImageFile.h" +#include "MapYokingGroupEnum.h" #include "OperationShowScene.h" #include "OperationException.h" #include "Scene.h" @@ -106,6 +108,10 @@ OperationShowScene::getParameters() ret->createOptionalParameter(7, "-no-scene-colors", "Do not use background and foreground colors in scene"); + OptionalParameter* mapYokeOpt = ret->createOptionalParameter(8, "-set-map-yoke", "Override selected map index for a map yoking group."); + mapYokeOpt->addStringParameter(1, "Map Yoking Roman Numeral", "Roman numeral identifying the map yoking group (I, II, III, IV, V, VI, VII, VIII, IX, X)"); + mapYokeOpt->addIntegerParameter(2, "Map Index", "Map index for yoking group. Indices start at 1 (one)"); + AString helpText("Render content of browser windows displayed in a scene " "into image file(s). The image file name should be " "similar to \"capture.png\". If there is only one image " @@ -179,6 +185,28 @@ OperationShowScene::useParameters(OperationParameters* myParams, const bool doNotUseSceneColorsFlag = myParams->getOptionalParameter(7)->m_present; + MapYokingGroupEnum::Enum mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + int32_t mapYokingMapIndex = -1; + OptionalParameter* mapYokeOpt = myParams->getOptionalParameter(8); + if (mapYokeOpt->m_present) { + const AString romanNumeral = mapYokeOpt->getString(1); + bool validFlag = false; + mapYokingGroup = MapYokingGroupEnum::fromGuiName(romanNumeral, &validFlag); + if ( ! validFlag) { + throw OperationException(romanNumeral + + " does not identify a valid Map Yoking Group. "); + } + mapYokingMapIndex = mapYokeOpt->getInteger(2); + if (mapYokingMapIndex < 1) { + throw OperationException("Map yoking map index must be one or greater."); + } + + /* + * Map indice in code start at zero + */ + mapYokingMapIndex--; + } + if ( ! useWindowSizeForImageSizeFlag) { if ((userImageWidth <= 0) || (userImageHeight <= 0)) { @@ -247,6 +275,19 @@ OperationShowScene::useParameters(OperationParameters* myParams, bool missingWindowMessageHasBeenDisplayed = false; + /* + * Apply map yoking + */ + if (mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + MapYokingGroupEnum::setSelectedMapIndex(mapYokingGroup, mapYokingMapIndex); + + EventMapYokingSelectMap yokeEvent(mapYokingGroup, + NULL, + mapYokingMapIndex, + true); + EventManager::get()->sendEvent(yokeEvent.getPointer()); + } + /* * Restore windows */ -- GitLab From 585bd5d7f5a808fb6a94abf147948557843e25ab Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 26 Apr 2017 18:08:39 -0500 Subject: [PATCH 136/755] improve error messages for attempting to load cifti as volume, and catch more cases by looking for a cifti header extension --- src/Files/VolumeFile.cxx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 2bd0ff493..8bcf5d17b 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -223,6 +223,13 @@ void VolumeFile::readFile(const AString& filename) NiftiIO myIO;//begin nifti specific code - should this go somewhere else? myIO.openRead(fileToRead); const NiftiHeader& inHeader = myIO.getHeader(); + for (int i = 0; i < (int)inHeader.m_extensions.size(); ++i) + {//check for actually being cifti + if (inHeader.m_extensions[i]->m_ecode == NIFTI_ECODE_CIFTI) + { + throw DataFileException(filename, "Cifti files cannot be used as volume files"); + } + } int numComponents = myIO.getNumComponents(); vector myDims = myIO.getDimensions(); int fullDims = 3;//deal with nifti with less than 3 dimensions @@ -233,8 +240,20 @@ void VolumeFile::readFile(const AString& filename) extraDims = vector(myDims.begin() + 3, myDims.end()); } while (myDims.size() < 3) myDims.push_back(1);//pretend we have 3 dimensions in header, always, things that use getOriginalDimensions assume this (because "VolumeFile") + if (myDims.size() > 3) + {//check for cifti-like dimensions here, so that we have the filename to report in the error + int64_t numFrames = myDims[3]; + for (int i = 4; i < (int)myDims.size(); ++i) + { + numFrames *= myDims[i]; + } + if (myDims[0] == 1 && myDims[1] == 1 && myDims[2] == 1 && numFrames > 10000) + { + throw DataFileException(filename, "volume FOV is 1x1x1 voxel, with over 10,000 frames, which suggests a broken cifti file (no header extension)"); + } + }//this check is also done in reinitialize(), but we don't want to call getSForm before this check when reading a file reinitialize(myDims, inHeader.getSForm(), numComponents); - setFileName(filename); // must be donw after reinitialize() since it calls clear() which clears the name of the file + setFileName(filename); // must be done after reinitialize() since it calls clear() which clears the name of the file int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; if (numComponents != 1) { -- GitLab From 9b3b37aa69504e6e650501c30ef04c7690485123 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 27 Apr 2017 23:45:08 -0500 Subject: [PATCH 137/755] add information command about parallelization --- build_scripts/commandhtml.sh | 23 ++++++------ src/Commands/CommandOperationManager.cxx | 45 ++++++++++++++++++++---- src/Commands/CommandOperationManager.h | 6 ++-- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/build_scripts/commandhtml.sh b/build_scripts/commandhtml.sh index 2eb5c0f18..025d6ff8c 100755 --- a/build_scripts/commandhtml.sh +++ b/build_scripts/commandhtml.sh @@ -36,32 +36,44 @@ infoLine=`echo "$initialText" | grep -n Information | cut -f1 -d:` #include -help line as plain text echo -n "$initialText" | head -n $((infoLine + 1)) >> "$outDir/$startPage" #-arguments-help +make_basic_command_page "-arguments-help" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -arguments-help >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" #-global-options +make_basic_command_page "-global-options" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -global-options >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" +#-parallel-help +make_basic_command_page "-parallel-help" +echo -n '' >> "$outDir/$startPage" +echo "$initialText" | grep -- -parallel-help >> "$outDir/$startPage" +echo -n '' >> "$outDir/$startPage" #-cifti-help +make_basic_command_page "-cifti-help" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -cifti-help >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" #-gifti-help +make_basic_command_page "-gifti-help" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -gifti-help >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" #-version echo "$initialText" | grep -- -version >> "$outDir/$startPage" #-list-commands +#special code to make page below echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -list-commands >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" #-list-deprecated-commands +#again, special code below echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -- -list-deprecated-commands >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" #-all-commands-help - takes 2 lines! +make_basic_command_page "-all-commands-help" echo -n '' >> "$outDir/$startPage" echo "$initialText" | grep -A 1 -- -all-commands-help >> "$outDir/$startPage" echo -n '' >> "$outDir/$startPage" @@ -72,17 +84,6 @@ echo "$initialText" | tail -n +$((allCommandsLine+2)) >> "$outDir/$startPage" echo '' >> "$outDir/$startPage" echo '' >> "$outDir/$startPage" -#-arguments-help page -make_basic_command_page "-arguments-help" -#-arguments-help page -make_basic_command_page "-global-options" -#-cifti-help page -make_basic_command_page "-cifti-help" -#-cifti-help page -make_basic_command_page "-gifti-help" -#-all-commands-help page -make_basic_command_page "-all-commands-help" - #-list-commands page, and its subpages outPage="$outDir/`command_to_page_name -list-commands`" #header diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 688ab90a7..4f2e7c0a8 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -599,17 +599,21 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) AString commandSwitch; commandSwitch = fixUnicode(parameters.nextString("Command Name"), false); + //hardcode program name, instead of taking it from the parameters, so that it doesn't include path or show wrapper script details + const AString myProgramName = "wb_command"; if (commandSwitch == "-help") { printHelpInfo(); } else if (commandSwitch == "-arguments-help") { - printArgumentsHelp("wb_command"); + printArgumentsHelp(myProgramName); } else if (commandSwitch == "-global-options") { printGlobalOptions(); } else if (commandSwitch == "-cifti-help") { - printCiftiHelp("wb_command"); + printCiftiHelp(); } else if (commandSwitch == "-gifti-help") { - printGiftiHelp("wb_command"); + printGiftiHelp(); + } else if (commandSwitch == "-parallel-help") { + printParallelHelp(myProgramName); } else if (commandSwitch == "-version") { printVersionInfo(); } else if (commandSwitch == "-list-commands") { @@ -617,7 +621,7 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) } else if (commandSwitch == "-list-deprecated-commands") { printDeprecatedCommands(); } else if (commandSwitch == "-all-commands-help") { - printAllCommandsHelpInfo("wb_command"); + printAllCommandsHelpInfo(myProgramName); } else { CommandOperation* operation = NULL; @@ -652,7 +656,7 @@ CommandOperationManager::runCommand(ProgramParameters& parameters) } else { if (!parameters.hasNext() && operation->takesParameters()) { - cout << operation->getHelpInformation("wb_command") << endl; + cout << operation->getHelpInformation(myProgramName) << endl; } else { if (ciftiScale) { @@ -959,6 +963,7 @@ void CommandOperationManager::printHelpInfo() cout << " -help show this help info" << endl; cout << " -arguments-help explain the format of subcommand help info" << endl; cout << " -global-options display options that can be added to any command" << endl; + cout << " -parallel-help details on how wb_command uses parallelization" << endl; cout << " -cifti-help explain the cifti file format and related terms" << endl; cout << " -gifti-help explain the gifti file format (metric, surface)" << endl; cout << " -version show extended version information" << endl; @@ -1090,7 +1095,7 @@ void CommandOperationManager::printGlobalOptions() cout << endl; } -void CommandOperationManager::printCiftiHelp(const AString& /*programName*/) +void CommandOperationManager::printCiftiHelp() { //guide for wrap, assuming 80 columns: | cout << " The CIFTI format is a new data file format intended to make it easier to" << endl; @@ -1154,7 +1159,7 @@ void CommandOperationManager::printCiftiHelp(const AString& /*programName*/) cout << endl;//guide for wrap, assuming 80 columns: | } -void CommandOperationManager::printGiftiHelp(const AString& /*programName*/) +void CommandOperationManager::printGiftiHelp() { //guide for wrap, assuming 80 columns: | cout << " The GIFTI format is an established data file format intended for use with" << endl; @@ -1178,6 +1183,32 @@ void CommandOperationManager::printGiftiHelp(const AString& /*programName*/) cout << endl;//guide for wrap, assuming 80 columns: | } +void CommandOperationManager::printParallelHelp(const AString& programName) +{ + //guide for wrap, assuming 80 columns: | + cout << " Many processing commands make use of multithreading so that scripts can" << endl; + cout << " finish more quickly. By default, these commands will use all available" << endl; + cout << " cores on the system. Because we use OpenMP for the parallelization, this" << endl; + cout << " behavior can be controlled through various environment variables. In" << endl; + cout << " particular, 'OMP_NUM_THREADS' will set the maximum number of threads it will" << endl; + cout << " use, when exported as an environment variable. Additionally, some shells," << endl; + cout << " such as bash, have syntax that allows you to set an environment variable for" << endl; + cout << " a single command or script, for instance:" << endl; + cout << endl;//guide for wrap, assuming 80 columns: | + cout << "$ OMP_NUM_THREADS=4 "<< programName << " -volume-smoothing input.nii.gz 4 output.nii.gz" << endl; + cout << endl;//guide for wrap, assuming 80 columns: | + cout << " If you have a multi-socket system, be aware that the parallelization can be" << endl; + cout << " much slower when threads are on different sockets, and this interacts badly" << endl; + cout << " with the default behavior of using all available cores. It is advisable to" << endl; + cout << " use other tools to restrict the entire script to execute on a single socket," << endl; + cout << " especially if a queueing system is involved." << endl; + cout << endl;//guide for wrap, assuming 80 columns: | + cout << " Also note that wb_view contains a few features that use multithreading," << endl; + cout << " which can be controlled by setting the same environment variables before" << endl; + cout << " launching wb_view (dynamic connectivity, border optimize)." << endl; + cout << endl;//guide for wrap, assuming 80 columns: | +} + void CommandOperationManager::printVersionInfo() { ApplicationInformation myInfo; diff --git a/src/Commands/CommandOperationManager.h b/src/Commands/CommandOperationManager.h index d89ff78ea..620e47465 100644 --- a/src/Commands/CommandOperationManager.h +++ b/src/Commands/CommandOperationManager.h @@ -69,9 +69,11 @@ namespace caret { void printGlobalOptions(); - void printCiftiHelp(const AString& programName); + void printCiftiHelp(); - void printGiftiHelp(const AString& programName); + void printGiftiHelp(); + + void printParallelHelp(const AString& programName); void printVersionInfo(); -- GitLab From 348fe3ec795b13194670c42e2efc0945d0dca084 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 28 Apr 2017 19:03:14 -0500 Subject: [PATCH 138/755] fix some crashes in -cifti-create-dense-from-template due to volume structures in cifti being handled improperly --- .../OperationCiftiCreateDenseFromTemplate.cxx | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Operations/OperationCiftiCreateDenseFromTemplate.cxx b/src/Operations/OperationCiftiCreateDenseFromTemplate.cxx index 4fea76aab..f1b275990 100644 --- a/src/Operations/OperationCiftiCreateDenseFromTemplate.cxx +++ b/src/Operations/OperationCiftiCreateDenseFromTemplate.cxx @@ -262,15 +262,15 @@ void OperationCiftiCreateDenseFromTemplate::useParameters(OperationParameters* m { for (int whichStruct = 0; whichStruct < (int)thisVolStructs.size(); ++whichStruct) { - vector::const_iterator iter = std::find(volStructures.begin(), volStructures.end(), thisSurfStructs[whichStruct]); + vector::const_iterator iter = std::find(volStructures.begin(), volStructures.end(), thisVolStructs[whichStruct]); if (iter == volStructures.end()) { - cout << ("discarding volume structure " + StructureEnum::toName(thisSurfStructs[whichStruct]) + " from file '" + thisCifti->getFileName() + "'") << endl; + cout << ("discarding volume structure " + StructureEnum::toName(thisVolStructs[whichStruct]) + " from file '" + thisCifti->getFileName() + "'") << endl; } else { int outIndex = (int)(iter - volStructures.begin()); if (volInfo[outIndex].type != NONE) { - throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains data for structure " + StructureEnum::toName(thisSurfStructs[whichStruct]) + + throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains data for structure " + StructureEnum::toName(thisVolStructs[whichStruct]) + ", but data for this structure also exists in an another option's file"); } volInfo[outIndex].type = CIFTI; @@ -283,9 +283,10 @@ void OperationCiftiCreateDenseFromTemplate::useParameters(OperationParameters* m cout << ("discarding volume structures from file '" + thisCifti->getFileName() + "'") << endl; } } - if (ciftiNameFile == NULL && (isLabel || thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS)) + if (ciftiNameFile == NULL && (isLabel || thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS || + thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS)) { - ciftiNameFile = thisCifti;//cifti trumps everything, if it has scalar or label + ciftiNameFile = thisCifti;//cifti trumps everything, if it has scalar or label or parcels } } const vector& metricInstances = *(myParams->getRepeatableParameterInstances(6)); @@ -477,10 +478,12 @@ void OperationCiftiCreateDenseFromTemplate::useParameters(OperationParameters* m outMap.setMapName(i, nameMap.getIndexName(i)); } } else { - CaretAssert(nameFile != NULL); - for (int64_t i = 0; i < numMaps; ++i) + if (nameFile != NULL)//if only input is cifti dtseries, there are no names to use { - outMap.setMapName(i, nameFile->getMapName(i)); + for (int64_t i = 0; i < numMaps; ++i) + { + outMap.setMapName(i, nameFile->getMapName(i)); + } } } outXML.setMap(CiftiXML::ALONG_ROW, outMap); @@ -495,10 +498,12 @@ void OperationCiftiCreateDenseFromTemplate::useParameters(OperationParameters* m outMap.setMapName(i, nameMap.getIndexName(i)); } } else { - CaretAssert(nameFile != NULL); - for (int64_t i = 0; i < numMaps; ++i) + if (nameFile != NULL) { - outMap.setMapName(i, nameFile->getMapName(i)); + for (int64_t i = 0; i < numMaps; ++i) + { + outMap.setMapName(i, nameFile->getMapName(i)); + } } } outXML.setMap(CiftiXML::ALONG_ROW, outMap); -- GitLab From cf24b75573d091704a2d79f51b6ab515f74796c3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 1 May 2017 15:04:59 -0500 Subject: [PATCH 139/755] Re-resolve WB-662 3x1 all volume slice view: Improper (and invalid) viewports for volume slice "ALL" layouts in Tile Tabs have been corrected. --- src/Brain/BrainOpenGLViewportContent.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 88d3d1f59..0d7255910 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -918,7 +918,7 @@ BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4] viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY + (vpOffsetY * 2); viewportOut[2] = vpWidth; - viewportOut[3] = (tabViewportHeight - viewportOut[1]); + viewportOut[3] = vpHeight; break; } } @@ -939,20 +939,20 @@ BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4] case VolumeSliceViewPlaneEnum::AXIAL: viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY + vpOffsetY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); - viewportOut[3] = (tabViewportHeight - viewportOut[1]); + viewportOut[2] = vpWidth; + viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY + vpOffsetY; viewportOut[2] = vpWidth; - viewportOut[3] = (tabViewportHeight - viewportOut[1]); + viewportOut[3] = vpHeight; break; } } @@ -973,7 +973,7 @@ BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4] case VolumeSliceViewPlaneEnum::AXIAL: viewportOut[0] = tabViewportX + (vpOffsetX * 2); viewportOut[1] = tabViewportY; - viewportOut[2] = (tabViewportWidth - viewportOut[0]); + viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: -- GitLab From f062ea1b9ebf0426971a69d9ab30ba4e6ca48c42 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 1 May 2017 16:05:45 -0500 Subject: [PATCH 140/755] Resolve WB-678 Thresholding does not get applied to all maps when apply to all maps is checked: Thresholds changes were processed separately from other changes on the dialog since the low/high thresholds must be valid ("low" less than or equal to "high"). Now, after thresholding is changed, updates are applied so that all maps get updated when "Apply to All Maps" is checked. --- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 2b07e2f99..0b24a197e 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -363,8 +363,7 @@ MapSettingsPaletteColorMappingWidget::updateAfterThresholdValuesChanged(const fl this->paletteColorMapping->setThresholdMinimum(threshType, lowThreshold); this->paletteColorMapping->setThresholdMaximum(threshType, highThreshold); updateThresholdSection(); - updateHistogramPlot(); - updateColoringAndGraphics(); + this->applySelections(); } /** @@ -2148,6 +2147,8 @@ void MapSettingsPaletteColorMappingWidget::applySelections() pcm->copy(*this->paletteColorMapping); } } + PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); + this->caretMappableDataFile->updateScalarColoringForAllMaps(paletteFile); } this->updateHistogramPlot(); -- GitLab From e0ae405a16ecc25d2f6e91a017ff7eaef8ebbe4b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 2 May 2017 16:20:47 -0500 Subject: [PATCH 141/755] Resolve WB-679: Volume surface outlines not saved in scenes if surfaces have the same name but different locations: Prior to this change, surfaces were matched using only the name of the file, excluding any path. Now, surfaces are matched using that maximum number of characters matched starting at the end of the full path name (directory and filename). In addition, a tooltip containing the filename and path has been added to the surface selection control in the Volume Surface Outline tab. --- src/Brain/SurfaceSelectionModel.cxx | 54 +++++++++++++++----- src/GuiQt/SurfaceSelectionViewController.cxx | 16 ++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/Brain/SurfaceSelectionModel.cxx b/src/Brain/SurfaceSelectionModel.cxx index 44b8aa8c0..5a49aa43f 100644 --- a/src/Brain/SurfaceSelectionModel.cxx +++ b/src/Brain/SurfaceSelectionModel.cxx @@ -389,6 +389,8 @@ SurfaceSelectionModel::saveToScene(const SceneAttributes* /*sceneAttributes*/, Surface* surface = getSurface(); if (surface != NULL) { + sceneClass->addString("m_selectedSurfaceFullPath", + surface->getFileName()); sceneClass->addString("m_selectedSurface", surface->getFileNameNoPath()); } @@ -416,21 +418,47 @@ SurfaceSelectionModel::restoreFromScene(const SceneAttributes* /*sceneAttributes return; } - const AString& surfaceFileName = sceneClass->getStringValue("m_selectedSurface", - ""); - if (surfaceFileName.isEmpty() == false) { - std::vector surfaces = getAvailableSurfaces(); - - for (std::vector::iterator iter = surfaces.begin(); - iter != surfaces.end(); - iter++) { - Surface* s = *iter; - if (s->getFileNameNoPath() == surfaceFileName) { - setSurface(s); - break; + std::vector allSurfaces = getAvailableSurfaces(); + + const AString& surfaceFileNameFullPath = sceneClass->getStringValue("m_selectedSurfaceFullPath", + ""); + /* + * For full path, find the best match using the right-most characters that + * will contain any relative path. When scene files are moved to different + * computers the full path may change the parts of the path nearest the + * name of the file will match. + */ + Surface* nameMatchSurface = NULL; + int32_t nameMatchLength = 0; + if ( ! surfaceFileNameFullPath.isEmpty()) { + for (auto surface : allSurfaces) { + const AString name = surface->getFileName(); + const int32_t numMatch = name.countMatchingCharactersFromEnd(surfaceFileNameFullPath); + if (numMatch > nameMatchLength) { + nameMatchLength = numMatch; + nameMatchSurface = surface; } } - + } + + if (nameMatchSurface == NULL) { + /* + * Match name of file with NO path + */ + const AString& surfaceFileName = sceneClass->getStringValue("m_selectedSurface", + ""); + if ( ! surfaceFileName.isEmpty()) { + for (auto surface : allSurfaces) { + if (surface->getFileNameNoPath() == surfaceFileName) { + nameMatchSurface = surface; + break; + } + } + } + } + + if (nameMatchSurface != NULL) { + setSurface(nameMatchSurface); } } diff --git a/src/GuiQt/SurfaceSelectionViewController.cxx b/src/GuiQt/SurfaceSelectionViewController.cxx index 355fe5ea5..de658f0ca 100644 --- a/src/GuiQt/SurfaceSelectionViewController.cxx +++ b/src/GuiQt/SurfaceSelectionViewController.cxx @@ -26,6 +26,7 @@ #include #include "BrainStructure.h" +#include "FileInformation.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "WuQEventBlockingFilter.h" @@ -176,9 +177,24 @@ SurfaceSelectionViewController::updateControl(SurfaceSelectionModel* selectionMo } } + AString toolTipText; if (numSurfaces > 0) { this->surfaceComboBox->setCurrentIndex(selectedIndex); + + /* + * ToolTip contains file and path + */ + CaretAssertVectorIndex(surfaces, selectedIndex); + const Surface* s = surfaces[selectedIndex]; + if (s != NULL) { + FileInformation fileInfo(s->getFileName()); + toolTipText = ("Name: " + + fileInfo.getFileName() + + "\nPath: " + + fileInfo.getPathName()); + } } + this->surfaceComboBox->setToolTip(toolTipText); this->surfaceComboBox->blockSignals(false); -- GitLab From 019ba364bf1b4f42793d43427848e3c77154c173 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 4 May 2017 09:33:53 -0500 Subject: [PATCH 142/755] Use FilePathNamePrefixCompactor for the surface selection combo boxes in the volume surface outline toolbox. As a result, the filename is displayed followed by a sufficient amount of the file's path so that files with the same name but different paths are easily identified. Prior to this change, only the filenames (no path) were displayed and this was a problem if there were files with the same name but different paths. --- src/GuiQt/SurfaceSelectionViewController.cxx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/SurfaceSelectionViewController.cxx b/src/GuiQt/SurfaceSelectionViewController.cxx index de658f0ca..f8b52c432 100644 --- a/src/GuiQt/SurfaceSelectionViewController.cxx +++ b/src/GuiQt/SurfaceSelectionViewController.cxx @@ -27,6 +27,7 @@ #include "BrainStructure.h" #include "FileInformation.h" +#include "FilePathNamePrefixCompactor.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "WuQEventBlockingFilter.h" @@ -150,7 +151,7 @@ SurfaceSelectionViewController::initializeControl(const Mode mode, * Selection model used to update this control. If this parameter is NULL * all selections are removed from the control. */ -void +void SurfaceSelectionViewController::updateControl(SurfaceSelectionModel* selectionModel) { std::vector surfaces; @@ -163,13 +164,24 @@ SurfaceSelectionViewController::updateControl(SurfaceSelectionModel* selectionMo this->surfaceComboBox->blockSignals(true); + /* + * There may be surface files with the same name but different + * paths so include unique parts of path in names + */ + std::vector caretDataFiles(surfaces.begin(), + surfaces.end()); + std::vector displayNames; + FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(caretDataFiles, + displayNames); + CaretAssert(surfaces.size() == displayNames.size()); + int32_t selectedIndex = 0; this->surfaceComboBox->clear(); const int32_t numSurfaces = static_cast(surfaces.size()); for (int32_t i = 0; i < numSurfaces; i++) { const int32_t indx = this->surfaceComboBox->count(); - this->surfaceComboBox->addItem(surfaces[i]->getFileNameNoPath()); + this->surfaceComboBox->addItem(displayNames[i]); this->surfaceComboBox->setItemData(indx, qVariantFromValue((void*)surfaces[i])); if (surfaces[i] == selectedSurface) { @@ -197,7 +209,6 @@ SurfaceSelectionViewController::updateControl(SurfaceSelectionModel* selectionMo this->surfaceComboBox->setToolTip(toolTipText); this->surfaceComboBox->blockSignals(false); - } /** -- GitLab From 12a542371459bb3b2a37cae74b73ab8c7c78eea9 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 9 May 2017 17:06:17 -0500 Subject: [PATCH 143/755] add option to print nifti header from a truncated file --- src/Operations/OperationNiftiInformation.cxx | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Operations/OperationNiftiInformation.cxx b/src/Operations/OperationNiftiInformation.cxx index ab2ed9fab..770fe8aa1 100644 --- a/src/Operations/OperationNiftiInformation.cxx +++ b/src/Operations/OperationNiftiInformation.cxx @@ -21,6 +21,7 @@ #include "OperationNiftiInformation.h" #include "OperationException.h" +#include "CaretBinaryFile.h" #include "CiftiFile.h" #include "NiftiIO.h" #include "CiftiXML.h" @@ -46,7 +47,8 @@ OperationParameters* OperationNiftiInformation::getParameters() OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "nifti-file", "the nifti/cifti file to examine"); - ret->createOptionalParameter(2, "-print-header", "display the header contents"); + OptionalParameter* headerOpt = ret->createOptionalParameter(2, "-print-header", "display the header contents"); + headerOpt->createOptionalParameter(1, "-allow-truncated", "print the header even if the data is truncated"); ret->createOptionalParameter(3, "-print-matrix", "output the values in the matrix (cifti only)"); @@ -64,7 +66,8 @@ void OperationNiftiInformation::useParameters(OperationParameters* myParams, Pro { LevelProgress myProgress(myProgObj); const AString fileName = myParams->getString(1); - bool printHeader = myParams->getOptionalParameter(2)->m_present; + OptionalParameter* headerOpt = myParams->getOptionalParameter(2); + bool printHeader = headerOpt->m_present; bool printMatrix = myParams->getOptionalParameter(3)->m_present; OptionalParameter* printXmlOpt = myParams->getOptionalParameter(4); bool printXml = printXmlOpt->m_present; @@ -73,10 +76,19 @@ void OperationNiftiInformation::useParameters(OperationParameters* myParams, Pro if(printHeader) { - NiftiIO myIO; - myIO.openRead(fileName); - cout << myIO.getHeader().toString() << endl; - cout << getMemorySizeAsString(myIO.getDimensions()) << endl; + if (!headerOpt->getOptionalParameter(1)->m_present) + {//NiftiIO contains the file length check + NiftiIO myIO; + myIO.openRead(fileName); + cout << myIO.getHeader().toString() << endl; + cout << getMemorySizeAsString(myIO.getDimensions()) << endl; + } else {//NiftiHeader doesn't + CaretBinaryFile myFile(fileName); + NiftiHeader myHeader; + myHeader.read(myFile); + cout << myHeader.toString() << endl; + cout << getMemorySizeAsString(myHeader.getDimensions()) << endl; + } } if(printXml) { -- GitLab From d480712c8869eb9e335c406e0d47cb2ddc603163 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 18 May 2017 14:16:46 -0500 Subject: [PATCH 144/755] update wb_shortcuts, improve unknown cifti intent code handling in extension wrning code --- src/Cifti/CiftiFile.cxx | 6 +- src/CommandLine/wb_shortcuts | 381 ++++++++++++++++++++++++++++++++--- 2 files changed, 359 insertions(+), 28 deletions(-) diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index f735f209d..23c1f6d59 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -512,6 +512,9 @@ namespace int32_t intent_code = myXML.getIntentInfo(CiftiVersion(), junk);//use default writing version to check file extension, older version is missing some intent codes switch (intent_code) { + default: + CaretAssert(0); + CaretLogWarning("unhandled cifti type in extension warning check, tell the developers what you just tried to do"); case 3000://unknown if (!filename.contains(QRegExp("\\.[^.]*\\.nii$"))) { @@ -585,9 +588,6 @@ namespace CaretLogWarning("parcels by parcels by scalar cifti file '" + filename + "' should be saved ending in .pconnscalar.nii, see wb_command -cifti-help"); } break; - default: - CaretAssert(0); - throw DataFileException("internal error, tell the developers what you just tried to do"); } } } diff --git a/src/CommandLine/wb_shortcuts b/src/CommandLine/wb_shortcuts index a249ef934..08511599f 100755 --- a/src/CommandLine/wb_shortcuts +++ b/src/CommandLine/wb_shortcuts @@ -119,7 +119,6 @@ function switch_to_func_name () #ADDING FUNCTIONS: #the function to call is automatically generated from the command switch (see above functions) #the function MUST follow the same naming convention -#the short description (second argument to create_function) MUST NOT be empty, or it will think the operation doesn't exist, and run a partial match search #you can add names of temporary files before they are created by any command, to ensure that no extra files get left behind on failure #if the temporaries could be large, feel free to both add them to the list, and delete them manually @@ -133,12 +132,18 @@ function border_file_concatenate () echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo return 0 fi if (($# < 2)) @@ -148,7 +153,55 @@ function border_file_concatenate () local -a merge_arg_array for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-border" "${!i}") + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-border" "${filecontents[$j]}") + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + merge_arg_array+=("-border" "${!i}") + fi done wb_command -border-merge "$1" "${merge_arg_array[@]}" } @@ -165,13 +218,21 @@ function cifti_concatenate () echo " [-map ] - use only the specified map from each input" echo " file" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." - echo " The -map option takes either a 1-based index or a map name, and causes" - echo " the operation to use only one map from each input file." + echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo + echo " The -map option takes either a 1-based" + echo " index or a map name, and causes the" + echo " operation to use only one map from each input file." echo return 0 fi @@ -192,7 +253,59 @@ function cifti_concatenate () local -a merge_arg_array for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-cifti" "${!i}" ${maparg[@]+"${maparg[@]}"}) + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-cifti" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + #we INTENTIONALLY expand an empty array to 0 elements, but set -u doesn't like this, and there is no simple syntax to tell it to allow it + #so, use complicated syntax to tell it to allow it + #this syntax is apparently UNDOCUMENTED, but it came from stackoverflow, and it works, so it must be right + #http://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u + merge_arg_array+=("-cifti" "${!i}" ${maparg[@]+"${maparg[@]}"}) + fi done wb_command -cifti-merge "$1" "${merge_arg_array[@]}" } @@ -475,13 +588,21 @@ function label_concatenate () echo " [-map ] - use only the specified map from each input" echo " file" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." - echo " The -map option takes either a 1-based index or a map name, and causes" - echo " the operation to use only one map from each input file." + echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo + echo " The -map option takes either a 1-based" + echo " index or a map name, and causes the" + echo " operation to use only one map from each input file." echo return 0 fi @@ -503,7 +624,55 @@ function label_concatenate () local i for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-label" "${!i}" ${maparg[@]+"${maparg[@]}"}) + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-label" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + merge_arg_array+=("-label" "${!i}" ${maparg[@]+"${maparg[@]}"}) + fi done wb_command -label-merge "$1" "${merge_arg_array[@]}" } @@ -520,13 +689,21 @@ function metric_concatenate () echo " [-map ] - use only the specified map from each input" echo " file" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." - echo " The -map option takes either a 1-based index or a map name, and causes" - echo " the operation to use only one map from each input file." + echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo + echo " The -map option takes either a 1-based" + echo " index or a map name, and causes the" + echo " operation to use only one map from each input file." echo return 0 fi @@ -548,7 +725,55 @@ function metric_concatenate () local i for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-metric" "${!i}" ${maparg[@]+"${maparg[@]}"}) + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-metric" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + merge_arg_array+=("-metric" "${!i}" ${maparg[@]+"${maparg[@]}"}) + fi done wb_command -metric-merge "$1" "${merge_arg_array[@]}" } @@ -563,12 +788,18 @@ function scene_file_concatenate () echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo return 0 fi if (($# < 2)) @@ -579,7 +810,55 @@ function scene_file_concatenate () local i for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-scene-file" "${!i}") + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-scene-file" "${filecontents[$j]}") + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + merge_arg_array+=("-scene-file" "${!i}") + fi done wb_command -scene-file-merge "$1" "${merge_arg_array[@]}" } @@ -596,13 +875,21 @@ function volume_concatenate () echo " [-map ] - use only the specified map from each input" echo " file" echo " " - echo " " + echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." - echo " The -map option takes either a 1-based index or a map name, and causes" - echo " the operation to use only one map from each input file." + echo + echo " Any input argument can be replaced with a -from-file option followed by a" + echo " text file. Each text file must have one data file per line. The" + echo " -big-text option allows the use of very large text files (>1MB). This" + echo " is otherwise considered an error, in order to prevent accidentally" + echo " loading a data file into shell memory as a text file." + echo + echo " The -map option takes either a 1-based" + echo " index or a map name, and causes the" + echo " operation to use only one map from each input file." echo return 0 fi @@ -622,13 +909,57 @@ function volume_concatenate () fi local -a merge_arg_array local i - #we INTENTIONALLY expand an empty array to 0 elements, but set -u doesn't like this, and there is no simple syntax to tell it to allow it - #so, use complicated syntax to tell it to allow it - #this syntax is apparently UNDOCUMENTED, but it came from stackoverflow, and it works, so it must be right - #http://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u for ((i = 2; i <= $#; ++i)) do - merge_arg_array+=("-volume" "${!i}" ${maparg[@]+"${maparg[@]}"}) + if [[ "${!i}" == -* ]] + then + case "${!i}" in + (-from-file) + i=$((i + 1)) + if ((i > $#)) + then + error "-from-file option requires an argument" + fi + local checksize=1 + if [[ "${!i}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + local filename="${!i}" + local nexti=$((i + 1)) + #allow the option after the filename, too, because that is the easy place to put it + if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] + then + checksize=0 + i=$((i + 1)) + fi + if ((checksize == 1)) + then + local filesize=`wc -c "$filename" | cut -d' ' -f1` + if ((filesize > 1000000)) + then + error "file '${!i}' seems too large to be a text file" + fi + fi + local -a filecontents + readarray -t filecontents < "$filename" + for ((j = 0; j < ${#filecontents[@]}; ++j)) + do + #ignore empty lines + if [[ "${filecontents[$j]}" != "" ]] + then + merge_arg_array+=("-volume" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) + fi + done + ;; + (*) + error "unrecognized option '${!i}'" + ;; + esac + else + merge_arg_array+=("-volume" "${!i}" ${maparg[@]+"${maparg[@]}"}) + fi done wb_command -volume-merge "$1" "${merge_arg_array[@]}" } -- GitLab From 51f8f16a511f1030a3d53ca31c0b125ee9810510 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 18 May 2017 14:18:24 -0500 Subject: [PATCH 145/755] Initial implementation of WB-681 Make Scenes Great Again. --- src/Common/DataFile.cxx | 48 +- src/Common/DataFile.h | 8 +- src/Files/CaretDataFile.cxx | 5 +- src/Files/SceneFile.cxx | 29 + src/Files/SceneFile.h | 7 + src/Files/SceneFileSaxReader.cxx | 8 + src/Files/SceneFileSaxReader.h | 2 + src/GuiQt/BalsaDatabaseManager.cxx | 166 +++ src/GuiQt/BalsaDatabaseManager.h | 63 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 287 ++++- .../BalsaDatabaseUploadSceneFileDialog.h | 33 +- src/GuiQt/CMakeLists.txt | 6 + src/GuiQt/CaretFileDialog.cxx | 46 + src/GuiQt/CaretFileDialog.h | 7 + src/GuiQt/GuiManager.cxx | 43 +- src/GuiQt/GuiManager.h | 6 +- src/GuiQt/SceneCreateOptionsDialog.cxx | 136 +++ src/GuiQt/SceneCreateOptionsDialog.h | 94 ++ src/GuiQt/SceneCreateReplaceDialog.cxx | 19 + src/GuiQt/SceneDialog.cxx | 1063 +++++++++++++---- src/GuiQt/SceneDialog.h | 89 +- src/GuiQt/ScenePreviewDialog.cxx | 1 + src/GuiQt/SceneShowOptionsDialog.cxx | 134 +++ src/GuiQt/SceneShowOptionsDialog.h | 94 ++ src/GuiQt/WuQDataEntryDialog.cxx | 33 +- src/GuiQt/WuQDataEntryDialog.h | 4 + src/Resources/Gui/Caution/caution.png | Bin 0 -> 476 bytes src/Resources/Gui/gui_resources.qrc | 1 + src/Scenes/SceneXmlElements.h | 6 +- 29 files changed, 2077 insertions(+), 361 deletions(-) create mode 100644 src/GuiQt/SceneCreateOptionsDialog.cxx create mode 100644 src/GuiQt/SceneCreateOptionsDialog.h create mode 100644 src/GuiQt/SceneShowOptionsDialog.cxx create mode 100644 src/GuiQt/SceneShowOptionsDialog.h create mode 100644 src/Resources/Gui/Caution/caution.png diff --git a/src/Common/DataFile.cxx b/src/Common/DataFile.cxx index cbc2ecc89..53288498d 100644 --- a/src/Common/DataFile.cxx +++ b/src/Common/DataFile.cxx @@ -78,8 +78,8 @@ DataFile::operator=(const DataFile& df) void DataFile::copyHelperDataFile(const DataFile& df) { - this->filename = df.filename; - modifiedFlag = false; + m_filename = df.m_filename; + m_modifiedFlag = false; } /** @@ -88,8 +88,8 @@ DataFile::copyHelperDataFile(const DataFile& df) void DataFile::initializeMembersDataFile() { - this->filename = ""; - modifiedFlag = false; + m_filename = ""; + m_modifiedFlag = false; } /** @@ -107,7 +107,7 @@ DataFile::clear() AString DataFile::getFileName() const { - return this->filename; + return m_filename; } /** @@ -116,12 +116,14 @@ DataFile::getFileName() const AString DataFile::getFileNameNoPath() const { - FileInformation fileInfo(this->filename); + FileInformation fileInfo(m_filename); return fileInfo.getFileName(); } /** * Set the name of the data file. + * This method is virtual so NEVER call it from + * a constructor. Instead, use setFileNameProtected(). * * @param filename * New name of data file. @@ -129,8 +131,22 @@ DataFile::getFileNameNoPath() const void DataFile::setFileName(const AString& filename) { - if (this->filename != filename) { - this->filename = filename; + setFileNameProtected(filename); +} + +/** + * Set the name of the data file. + * This method is NOT virtual so it may be called + * from a constructor. + * + * @param filename + * New name of data file. + */ +void +DataFile::setFileNameProtected(const AString& filename) +{ + if (m_filename != filename) { + m_filename = filename; this->setModified(); } } @@ -153,7 +169,7 @@ DataFile::addToDataFileContentInformation(DataFileContentInformation& dataFileIn void DataFile::setModified() { - this->modifiedFlag = true; + m_modifiedFlag = true; } /** @@ -162,7 +178,7 @@ DataFile::setModified() void DataFile::clearModified() { - this->modifiedFlag = false; + m_modifiedFlag = false; } /** @@ -172,7 +188,17 @@ DataFile::clearModified() bool DataFile::isModified() const { - return this->modifiedFlag; + return m_modifiedFlag; +} + +/** + * @return True if a file with the current file name exists, else false. + */ +bool +DataFile::exists() const +{ + FileInformation fileInfo(getFileName()); + return fileInfo.exists(); } /** diff --git a/src/Common/DataFile.h b/src/Common/DataFile.h index f3e878538..13ec67b2a 100644 --- a/src/Common/DataFile.h +++ b/src/Common/DataFile.h @@ -45,6 +45,8 @@ namespace caret { DataFile& operator=(const DataFile&); + void setFileNameProtected(const AString& filename); + public: virtual AString getFileName() const; @@ -90,16 +92,18 @@ namespace caret { void checkFileWritability(const AString& filename); + bool exists() const; + private: void copyHelperDataFile(const DataFile& df); void initializeMembersDataFile(); /** name of data file */ - AString filename; + AString m_filename; /** modification status */ - bool modifiedFlag; + bool m_modifiedFlag; }; diff --git a/src/Files/CaretDataFile.cxx b/src/Files/CaretDataFile.cxx index 5ae5561c7..4865f0e77 100644 --- a/src/Files/CaretDataFile.cxx +++ b/src/Files/CaretDataFile.cxx @@ -47,14 +47,13 @@ SceneableInterface() { m_dataFileType = dataFileType; - AString name = (DataFileTypeEnum::toName(m_dataFileType).toLower() - + "_file_" + AString name = ("untitled_" + AString::number(s_defaultFileNameCounter) + "." + DataFileTypeEnum::toFileExtension(m_dataFileType)); s_defaultFileNameCounter++; - setFileName(name); + setFileNameProtected(name); } /** diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index fc0fcd052..34f678b1e 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -63,6 +63,7 @@ SceneFile::SceneFile() : CaretDataFile(DataFileTypeEnum::SCENE) { m_balsaStudyID = ""; + m_balsaStudyTitle = ""; m_baseDirectory = ""; m_metadata = new GiftiMetaData(); } @@ -93,6 +94,7 @@ SceneFile::clear() m_metadata->clear(); m_balsaStudyID = ""; + m_balsaStudyTitle = ""; m_baseDirectory = ""; for (std::vector::iterator iter = m_scenes.begin(); @@ -489,6 +491,30 @@ SceneFile::setBalsaStudyID(const AString& balsaStudyID) } } +/** + * @return The BALSA Study Title. + */ +AString +SceneFile::getBalsaStudyTitle() const +{ + return m_balsaStudyTitle; +} + +/** + * Set the BALSA Study Title. + * + * @param balsaStudyTitle + * New value for BALSA Study Title. + */ +void +SceneFile::setBalsaStudyTitle(const AString& balsaStudyTitle) +{ + if (balsaStudyTitle != m_balsaStudyTitle) { + m_balsaStudyTitle = balsaStudyTitle; + setModified(); + } +} + /** * @return The Base Directory */ @@ -646,8 +672,11 @@ SceneFile::writeFile(const AString& filename) xmlWriter.writeStartElement(SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_ID_TAG, getBalsaStudyID()); + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG, + getBalsaStudyTitle()); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BASE_DIRECTORY_TAG, getBaseDirectory()); + for (int32_t i = 0; i < numScenes; i++) { m_scenes[i]->getSceneInfo()->writeSceneInfo(xmlWriter, i); diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 9881cb424..2993c8f30 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -87,6 +87,10 @@ namespace caret { void setBalsaStudyID(const AString& balsaStudyID); + AString getBalsaStudyTitle() const; + + void setBalsaStudyTitle(const AString& balsaStudyTitle); + AString getBaseDirectory() const; void setBaseDirectory(const AString& baseDirectory); @@ -124,6 +128,9 @@ namespace caret { /** the BALSA Study ID */ AString m_balsaStudyID; + /** the BALSA Study Title */ + AString m_balsaStudyTitle; + /** the Base Directory */ AString m_baseDirectory; diff --git a/src/Files/SceneFileSaxReader.cxx b/src/Files/SceneFileSaxReader.cxx index a37d53e97..c1b957cac 100644 --- a/src/Files/SceneFileSaxReader.cxx +++ b/src/Files/SceneFileSaxReader.cxx @@ -128,6 +128,9 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, else if (qName == SceneXmlElements::SCENE_INFO_BALSA_STUDY_ID_TAG) { m_state = STATE_SCENE_INFO_BALSA_STUDY_ID; } + else if (qName == SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG) { + m_state = STATE_SCENE_INFO_BALSA_STUDY_TITLE; + } else if (qName == SceneXmlElements::SCENE_INFO_BASE_DIRECTORY_TAG) { m_state = STATE_SCENE_INFO_BASE_DIRECTORY; } @@ -142,6 +145,8 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, break; case STATE_SCENE_INFO_BALSA_STUDY_ID: break; + case STATE_SCENE_INFO_BALSA_STUDY_TITLE: + break; case STATE_SCENE_INFO_BASE_DIRECTORY: break; case STATE_SCENE_INFO: @@ -228,6 +233,9 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, case STATE_SCENE_INFO_BALSA_STUDY_ID: m_sceneFile->setBalsaStudyID(m_elementText); break; + case STATE_SCENE_INFO_BALSA_STUDY_TITLE: + m_sceneFile->setBalsaStudyTitle(m_elementText); + break; case STATE_SCENE_INFO_BASE_DIRECTORY: m_sceneFile->setBaseDirectory(m_elementText); break; diff --git a/src/Files/SceneFileSaxReader.h b/src/Files/SceneFileSaxReader.h index 60e22e4a8..c082f555e 100644 --- a/src/Files/SceneFileSaxReader.h +++ b/src/Files/SceneFileSaxReader.h @@ -83,6 +83,8 @@ namespace caret { STATE_SCENE_INFO_DIRECTORY, /// processing scene info Balsa Study ID tag STATE_SCENE_INFO_BALSA_STUDY_ID, + /// processing scene info Balsa Study Title tag + STATE_SCENE_INFO_BALSA_STUDY_TITLE, /// processing scene info Base Directory tag STATE_SCENE_INFO_BASE_DIRECTORY, /// processing SceneInfo tag diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index ed365deba..b083d85e9 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -512,6 +512,172 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, return false; } +/** + * Get the study ID from a study Title + * + * @param databaseURL + * URL for database + * @param studyTitle + * Title of the study + * @param studyIDOut + * Output with the study ID + * @param errorMessageOut + * Output with error message + * @return + * True if success, else false. + */ +bool +BalsaDatabaseManager::requestStudyID(const AString& databaseURL, + const AString& studyTitle, + AString& studyIDOut, + AString& errorMessageOut) +{ + const AString studyIdURL(databaseURL + + "/study/save"); + + errorMessageOut.clear(); + + CaretHttpRequest uploadRequest; + uploadRequest.m_method = CaretHttpManager::POST_ARGUMENTS; + uploadRequest.m_url = studyIdURL; + uploadRequest.m_headers.insert(std::make_pair("Content-Type", + "application/x-www-form-urlencoded")); + uploadRequest.m_headers.insert(std::make_pair("Cookie", + getJSessionIdCookie())); + uploadRequest.m_arguments.push_back(std::make_pair("title", + studyTitle)); + + CaretHttpResponse idResponse; + CaretHttpManager::httpRequest(uploadRequest, idResponse); + + if (m_debugFlag) { + std::cout << "Request study ID response Code: " << idResponse.m_responseCode << std::endl; + } + + AString locationFromHeader; + for (std::map::iterator mapIter = idResponse.m_headers.begin(); + mapIter != idResponse.m_headers.end(); + mapIter++) { + if (m_debugFlag) { + std::cout << " Request study ID Response Header: " << qPrintable(mapIter->first) + << " -> " << qPrintable(mapIter->second) << std::endl; + } + if (mapIter->first.toLower() == "location") { + locationFromHeader = mapIter->second; + } + } + + idResponse.m_body.push_back('\0'); + AString responseContent(&idResponse.m_body[0]); + + if (m_debugFlag) { + std::cout << "Request Study ID reply body:" << responseContent << std::endl; + } + + CaretLogFine("Request Study ID to BALSA reply body: " + + responseContent); + + if (idResponse.m_responseCode != 200) { + errorMessageOut = ("Requesting study ID failed HTTP code: " + + QString::number(idResponse.m_responseCode) + + "\n" + "Could be due failure to agree to data user terms."); + + return false; + } + + if ( ! locationFromHeader.isEmpty()) { + const int lastSlashIndex = locationFromHeader.lastIndexOf('/'); + if (lastSlashIndex >= 0) { + studyIDOut = locationFromHeader.mid(lastSlashIndex + 1); + if (studyIDOut.isNull() + || studyIDOut.isEmpty()) { + errorMessageOut = ("Received 'Location' from BALSA but unable to find study ID in the URL: " + + locationFromHeader); + return false; + } + + /* + * Have the Study ID + */ + return true; + } + else { + errorMessageOut = ("Received 'Location' from BALSA but unable to find study ID in the URL: " + + locationFromHeader); + } + } + else { + if (responseContent.indexOf("must be unique") >= 0) { + errorMessageOut = ("A study with the title \"" + + studyTitle + + "\" already exists and duplicate study titles are not allowed in the BALSA database."); + } + else { + errorMessageOut = "Unable to find 'Location' in response from BALSA."; + } + } + + return false; +} + +/** + * Login to BALSA and request a study ID from a study title. + * + * @param databaseURL + * URL of the database. + * @param username + * Username for logging in. + * @param password + * Password for logging in. + * @param studyTitle + * The study's titlee. + * @param studyIdOut + * Output containing the study ID. + * @param errorMessageOut + * Contains description of any error(s). + * @return + * True if processing was successful, else false. + */ +bool +BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, + const AString& username, + const AString& password, + const AString& studyTitle, + AString& studyIdOut, + AString& errorMessageOut) +{ + if (studyTitle.isEmpty()) { + errorMessageOut = "The study title is empty."; + return false; + } + + /* + * Login + */ + const AString loginURL(databaseURL + + "/j_spring_security_check"); + if ( ! login(loginURL, + username, + password, + errorMessageOut)) { + + return false; + } + + CaretLogInfo("SESSION ID from BALSA Login: " + + getJSessionIdCookie()); + + if ( ! requestStudyID(databaseURL, + studyTitle, + studyIdOut, + errorMessageOut)) { + return false; + } + + return true; +} + /** * Login to BALSA, zip the scene and data files, and upload the * ZIP file to BALSA. diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index 104ca6644..df1a6963b 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -36,19 +36,42 @@ namespace caret { virtual ~BalsaDatabaseManager(); + bool getStudyIDFromStudyTitle(const AString& databaseURL, + const AString& username, + const AString& password, + const AString& studyTitle, + AString& studyIdOut, + AString& errorMessageOut); + bool uploadZippedSceneFile(const AString& databaseURL, - const AString& username, - const AString& password, - const SceneFile* sceneFile, - const AString& zipFileName, - const AString& extractToDirectoryName, - AString& errorMessageOut); + const AString& username, + const AString& password, + const SceneFile* sceneFile, + const AString& zipFileName, + const AString& extractToDirectoryName, + AString& errorMessageOut); + + static bool zipSceneAndDataFiles(const SceneFile* sceneFile, + const AString& extractDirectory, + const AString& zipFileName, + AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + private: + BalsaDatabaseManager(const BalsaDatabaseManager&); + + BalsaDatabaseManager& operator=(const BalsaDatabaseManager&); bool login(const AString& loginURL, const AString& username, const AString& password, AString& errorMessageOut); - + AString getJSessionIdCookie() const; bool uploadFile(const AString& uploadURL, @@ -62,21 +85,10 @@ namespace caret { AString& responseContentOut, AString& errorMessageOut); - static bool zipSceneAndDataFiles(const SceneFile* sceneFile, - const AString& extractDirectory, - const AString& zipFileName, - AString& errorMessageOut); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - virtual void receiveEvent(Event* event); - - private: - BalsaDatabaseManager(const BalsaDatabaseManager&); - - BalsaDatabaseManager& operator=(const BalsaDatabaseManager&); + bool requestStudyID(const AString& databaseURL, + const AString& studyTitle, + AString& studyIDOut, + AString& errorMessageOut); bool uploadFileWithCaretHttpManager(const AString& uploadURL, const AString& fileName, @@ -84,13 +96,6 @@ namespace caret { AString& responseContentOut, AString& errorMessageOut); - bool uploadFileWithHttpCommunicator(const AString& uploadURL, - const AString& fileName, - const AString& httpContentTypeName, - AString& responseContentOut, - AString& errorMessageOut); - - bool processUploadResponse(const std::map& responseHeaders, const AString& responseContent, const int32_t responseHttpCode, diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 215e4c671..52ed80186 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -28,16 +28,22 @@ #include #include #include +#include #include "BalsaDatabaseManager.h" +#include "Brain.h" #include "CaretAssert.h" +#include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CursorDisplayScoped.h" +#include "DataFileException.h" #include "FileInformation.h" +#include "GuiManager.h" #include "ProgressReportingDialog.h" #include "SceneFile.h" #include "SystemUtilities.h" +#include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -59,12 +65,14 @@ using namespace caret; * @param parent * Parent of this dialog. */ -BalsaDatabaseUploadSceneFileDialog::BalsaDatabaseUploadSceneFileDialog(const SceneFile* sceneFile, +BalsaDatabaseUploadSceneFileDialog::BalsaDatabaseUploadSceneFileDialog(SceneFile* sceneFile, QWidget* parent) : WuQDialogModal("Upload Scene File to BALSA", parent), m_sceneFile(sceneFile) { + CaretAssert(m_sceneFile); + QString defaultUserName = "balsaTest"; QString defaultPassword = "@2password"; @@ -115,11 +123,11 @@ m_sceneFile(sceneFile) sceneFile->getFileNameNoPathNoExtension() , "zip"); - QLabel* zipFileNameLabel = new QLabel("Zip File Name"); + QLabel* zipFileNameLabel = new QLabel("Zip File Name: "); m_zipFileNameLineEdit = new QLineEdit; m_zipFileNameLineEdit->setText(zipFileName); - QLabel* extractDirectoryLabel = new QLabel("Extract to Directory"); + QLabel* extractDirectoryLabel = new QLabel("Extract to Directory: "); m_extractDirectoryNameLineEdit = new QLineEdit(); m_extractDirectoryNameLineEdit->setText("ExtDir"); @@ -128,33 +136,107 @@ m_sceneFile(sceneFile) + m_sceneFile->getBalsaStudyID()); m_extractDirectoryNameLineEdit->setText(defaultDirName); + + /* + * Scene BALSA Study ID + */ + QLabel* studyIDLabel = new QLabel("BALSA Study ID: "); + m_fileBalsaStudyIDLineEdit = new QLineEdit(); + m_fileBalsaStudyIDLineEdit->setToolTip("Press Edit button to change Study ID for use with BALSA Database"); + m_fileBalsaStudyIDLineEdit->setReadOnly(true); + + /* + * Edit BALSA Study ID button + */ + m_editBalsaStudyIDPushButton = new QPushButton("Edit..."); + m_editBalsaStudyIDPushButton->setToolTip("Edit the Scene File's BALSA Study ID"); + QObject::connect(m_editBalsaStudyIDPushButton, SIGNAL(clicked()), + this, SLOT(editFileBalsaStudyIDButtonClicked())); + + m_getBalsaStudyIDPushButton = new QPushButton("Get..."); + m_getBalsaStudyIDPushButton->setToolTip("Get the BALSA Study ID by sending Study Title to BALSA"); + QObject::connect(m_getBalsaStudyIDPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked); + + /* + * Scene BALSA Study Title + */ + QLabel* studyTitleLabel = new QLabel("BALSA Study Title: "); + m_balsaStudyTitleLineEdit = new QLineEdit(); + m_balsaStudyTitleLineEdit->setToolTip("Press Edit button to change Study Title for use with BALSA Database"); + m_balsaStudyTitleLineEdit->setReadOnly(true); + + + /* + * Edit BALSA Title button + */ + m_editBalsaStudyTitlePushButton = new QPushButton("Edit..."); + m_editBalsaStudyTitlePushButton->setToolTip("Edit the Scene File's BALSA Study Title"); + QObject::connect(m_editBalsaStudyTitlePushButton, SIGNAL(clicked()), + this, SLOT(editFileBalsaStudyTitleButtonClicked())); + + /* + * Base Directory + */ + QLabel* baseDirectoryLabel = new QLabel("Base Directory: "); + m_baseDirectoryLineEdit = new QLineEdit(); + m_baseDirectoryLineEdit->setToolTip("Press Browse or Edit button to change base directory"); + m_baseDirectoryLineEdit->setReadOnly(true); + m_editBaseDirectoryPushButton = new QPushButton("Edit..."); + m_editBaseDirectoryPushButton->setToolTip("Edit the base directory in a text edit"); + QObject::connect(m_editBaseDirectoryPushButton, SIGNAL(clicked()), + this, SLOT(editBaseDirectoryPushButtonClicked())); + m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); + m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); + QObject::connect(m_browseBaseDirectoryPushButton, SIGNAL(clicked()), + this, SLOT(browseBaseDirectoryPushButtonClicked())); + + + + + QWidget* dialogWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(dialogWidget); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); int row = 0; - gridLayout->addWidget(databaseNameLabel, row, 0); + gridLayout->addWidget(databaseNameLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_databaseComboBox, row, 1); gridLayout->addWidget(registerLabel, row, 2); row++; - gridLayout->addWidget(usernameLabel, row, 0); + gridLayout->addWidget(usernameLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_usernameLineEdit, row, 1); gridLayout->addWidget(forgotUsernameLabel, row, 2); row++; - gridLayout->addWidget(passwordLabel, row, 0); + gridLayout->addWidget(passwordLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_passwordLineEdit, row, 1); gridLayout->addWidget(forgotPasswordLabel, row, 2); row++; - gridLayout->addWidget(zipFileNameLabel, row, 0); - gridLayout->addWidget(m_zipFileNameLineEdit, row, 1, 1, 2); + gridLayout->addWidget(zipFileNameLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_zipFileNameLineEdit, row, 1, 1, 3); row++; - gridLayout->addWidget(extractDirectoryLabel, row, 0); - gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1, 1, 2); + gridLayout->addWidget(extractDirectoryLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1, 1, 3); row++; + gridLayout->addWidget(baseDirectoryLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_baseDirectoryLineEdit, row, 1); + gridLayout->addWidget(m_editBaseDirectoryPushButton, row, 2); + gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, 3); + row++; + gridLayout->addWidget(studyTitleLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, 1); + gridLayout->addWidget(m_editBalsaStudyTitlePushButton, row, 2); + row++; + gridLayout->addWidget(studyIDLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_fileBalsaStudyIDLineEdit, row, 1); + gridLayout->addWidget(m_editBalsaStudyIDPushButton, row, 2); + gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, 3); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); + + loadSceneFileMetaDataWidgets(); } /** @@ -200,6 +282,35 @@ BalsaDatabaseUploadSceneFileDialog::labelHtmlLinkClicked(const QString& linkPath void BalsaDatabaseUploadSceneFileDialog::okButtonClicked() { + CaretAssert(m_sceneFile); + + if (m_sceneFile->getBalsaStudyID().trimmed().isEmpty()) { + const QString msg("The BALSA Study ID is missing. You must either: (1) Go to " + "BALSA Database and get a BALSA Study ID or " + "(2) Enter a Study Title and press the Get button to request a BALSA Study ID " + "using the Study Title"); + WuQMessageBox::errorOk(this, msg); + return; + } + + if (m_sceneFile->isModified()) { + const QString msg("The scene file is modified and must be saved before continuing. Would you like " + "to save the scene file using its current name and continue?"); + if (WuQMessageBox::warningYesNo(this, msg)) { + try { + Brain* brain = GuiManager::get()->getBrain(); + brain->writeDataFile(m_sceneFile); + } + catch (const DataFileException& e) { + WuQMessageBox::errorOk(this, e.whatString()); + return; + } + } + else { + return; + } + } + CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -240,3 +351,159 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() WuQDialogModal::okButtonClicked(); } +/** + * Load the Scene File BALSA Study ID Line Edit + */ +void +BalsaDatabaseUploadSceneFileDialog::loadSceneFileMetaDataWidgets() +{ + CaretAssert(m_sceneFile); + + m_fileBalsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); + m_baseDirectoryLineEdit->setText(m_sceneFile->getBaseDirectory()); + m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); +} + +/** + * Called when Edit Study ID button is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::editFileBalsaStudyIDButtonClicked() +{ + CaretAssert(m_sceneFile); + + WuQDataEntryDialog ded("Edit BALSA Database Info", + m_editBalsaStudyIDPushButton, + WuQDialog::SCROLL_AREA_AS_NEEDED); + + QLineEdit* lineEdit = ded.addLineEditWidget("BALSA Study ID"); + lineEdit->setText(m_sceneFile->getBalsaStudyID()); + lineEdit->setMinimumWidth(200); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + const AString idText = lineEdit->text().trimmed(); + m_sceneFile->setBalsaStudyID(idText); + loadSceneFileMetaDataWidgets(); + } +} + +/** + * Called when get BALSA study ID push button is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() +{ + const AString title = m_balsaStudyTitleLineEdit->text().trimmed(); + if (title.isEmpty()) { + WuQMessageBox::errorOk(m_getBalsaStudyIDPushButton, + "The BALSA Study Title is required to get a BALSA Study ID"); + return; + } + + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + const AString username = m_usernameLineEdit->text().trimmed(); + const AString password = m_passwordLineEdit->text().trimmed(); + const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); + const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); + + AString studyID; + AString errorMessage; + CaretPointer balsaDatabaseManager(new BalsaDatabaseManager()); + const bool successFlag = balsaDatabaseManager->getStudyIDFromStudyTitle(getDataBaseURL(), + username, + password, + title, + studyID, + errorMessage); + + cursor.restoreCursor(); + + if (successFlag) { + m_sceneFile->setBalsaStudyID(studyID); + loadSceneFileMetaDataWidgets(); + } + else { + WuQMessageBox::errorOk(this, + errorMessage); + } +} + +/** + * Called when Edit Study Title button is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::editFileBalsaStudyTitleButtonClicked() +{ + CaretAssert(m_sceneFile); + + WuQDataEntryDialog ded("Edit BALSA Database Info", + m_editBalsaStudyTitlePushButton, + WuQDialog::SCROLL_AREA_AS_NEEDED); + + QLineEdit* lineEdit = ded.addLineEditWidget("BALSA Study Title"); + lineEdit->setText(m_sceneFile->getBalsaStudyTitle()); + lineEdit->setMinimumWidth(200); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + const AString titleText = lineEdit->text().trimmed(); + m_sceneFile->setBalsaStudyTitle(titleText); + loadSceneFileMetaDataWidgets(); + } +} +/** + * Called when upload scene file is selected. + */ +void +BalsaDatabaseUploadSceneFileDialog::editBaseDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + WuQDataEntryDialog ded("Edit Base Directory", + m_editBaseDirectoryPushButton, + WuQDialog::SCROLL_AREA_AS_NEEDED); + + QLineEdit* lineEdit = ded.addLineEditWidget("Base Directory"); + lineEdit->setText(m_sceneFile->getBaseDirectory()); + lineEdit->setMinimumWidth(500); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + const AString idText = lineEdit->text().trimmed(); + m_sceneFile->setBaseDirectory(idText); + loadSceneFileMetaDataWidgets(); + } +} + +/** + * Called when upload scene file is selected. + */ +void +BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + /* + * Let user choose directory path + */ + QString directoryName; + FileInformation fileInfo(m_sceneFile->getBaseDirectory()); + if (fileInfo.exists()) { + if (fileInfo.isDirectory()) { + directoryName = fileInfo.getAbsoluteFilePath(); + } + } + AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, + "Choose Base Directory", + directoryName); + /* + * If user cancels, return + */ + if (newDirectoryName.isEmpty()) { + return; + } + + /* + * Set name of new scene file and add to brain + */ + m_sceneFile->setBaseDirectory(newDirectoryName); + loadSceneFileMetaDataWidgets(); +} + diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index a31bcd518..0a1261176 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -27,6 +27,7 @@ class QComboBox; class QLabel; class QLineEdit; +class QPushButton; @@ -39,7 +40,7 @@ namespace caret { Q_OBJECT public: - BalsaDatabaseUploadSceneFileDialog(const SceneFile* sceneFile, + BalsaDatabaseUploadSceneFileDialog(SceneFile* sceneFile, QWidget* parent); virtual ~BalsaDatabaseUploadSceneFileDialog(); @@ -50,6 +51,16 @@ namespace caret { private slots: void labelHtmlLinkClicked(const QString&); + void editFileBalsaStudyIDButtonClicked(); + + void editFileBalsaStudyTitleButtonClicked(); + + void editBaseDirectoryPushButtonClicked(); + + void browseBaseDirectoryPushButtonClicked(); + + void getBalsaStudyIDPushButtonClicked(); + protected: virtual void okButtonClicked(); @@ -58,9 +69,11 @@ namespace caret { BalsaDatabaseUploadSceneFileDialog& operator=(const BalsaDatabaseUploadSceneFileDialog&); + void loadSceneFileMetaDataWidgets(); + AString getDataBaseURL() const; - const SceneFile* m_sceneFile; + SceneFile* m_sceneFile; QComboBox* m_databaseComboBox; @@ -71,6 +84,22 @@ namespace caret { QLineEdit* m_zipFileNameLineEdit; QLineEdit* m_extractDirectoryNameLineEdit; + + QPushButton* m_editBalsaStudyIDPushButton; + + QPushButton* m_getBalsaStudyIDPushButton; + + QLineEdit* m_fileBalsaStudyIDLineEdit; + + QLineEdit* m_balsaStudyTitleLineEdit; + + QPushButton* m_editBalsaStudyTitlePushButton; + + QPushButton* m_browseBaseDirectoryPushButton; + + QPushButton* m_editBaseDirectoryPushButton; + + QLineEdit* m_baseDirectoryLineEdit; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 0d9097ecd..cdec49e29 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -147,9 +147,11 @@ ELSE() ProgressReportingFromEvent.h ProgressReportingWithSlots.h RegionOfInterestCreateFromBorderDialog.h + SceneCreateOptionsDialog.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h + SceneShowOptionsDialog.h SpecFileManagementDialog.h SplashScreen.h StructureEnumComboBox.h @@ -352,9 +354,11 @@ ProgressReportingFromEvent.h ProgressReportingWithSlots.h QGLWidgetTextRenderer.h RegionOfInterestCreateFromBorderDialog.h +SceneCreateOptionsDialog.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h +SceneShowOptionsDialog.h SceneWindowGeometry.h SpecFileManagementDialog.h SplashScreen.h @@ -552,9 +556,11 @@ ProgressReportingFromEvent.cxx ProgressReportingWithSlots.cxx QGLWidgetTextRenderer.cxx RegionOfInterestCreateFromBorderDialog.cxx +SceneCreateOptionsDialog.cxx SceneCreateReplaceDialog.cxx SceneDialog.cxx ScenePreviewDialog.cxx +SceneShowOptionsDialog.cxx SceneWindowGeometry.cxx SpecFileManagementDialog.cxx SplashScreen.cxx diff --git a/src/GuiQt/CaretFileDialog.cxx b/src/GuiQt/CaretFileDialog.cxx index 30f0f3f72..fb51fee68 100644 --- a/src/GuiQt/CaretFileDialog.cxx +++ b/src/GuiQt/CaretFileDialog.cxx @@ -264,6 +264,52 @@ CaretFileDialog::getOpenFileNameDialog(QWidget *parent, return QString(); } + +/** + * Like QFileDialog::getOpenFileName() except that this + * NEVER uses the native file dialog thus providing + * a consistent user-interface across platforms. + * + * @param dataFileType + * Type of Workbench data file + * @param parent + * Parent on which this dialog is displayed. + * @param caption + * Caption for dialog (if not provided a default caption is shown) + * @param dir + * Directory show by dialog (Brain's current directory if empty string) + * @param options + * Options (see QFileDialog). + * @return + * Name of file selected or empty string if user cancelled. + */ +QString +CaretFileDialog::getOpenFileNameDialog(const DataFileTypeEnum::Enum dataFileType, + QWidget* parent, + const QString& caption, + const QString& dir, + Options options) +{ + + CaretFileDialog cfd(parent, + caption, + dir, + DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + cfd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); + cfd.setOptions(options); + cfd.setAcceptMode(CaretFileDialog::AcceptOpen); + cfd.setFileMode(CaretFileDialog::AnyFile); + + if (cfd.exec() == CaretFileDialog::Accepted) { + QStringList selectedFiles = cfd.selectedFiles(); + if (selectedFiles.size() > 0) { + return selectedFiles[0]; + } + } + + return QString(); +} + /** * Like QFileDialog::getSaveFileName() except that this * NEVER uses the native file dialog thus providing diff --git a/src/GuiQt/CaretFileDialog.h b/src/GuiQt/CaretFileDialog.h index 3a159e2b8..5a435f20e 100644 --- a/src/GuiQt/CaretFileDialog.h +++ b/src/GuiQt/CaretFileDialog.h @@ -52,6 +52,13 @@ namespace caret { QString *selectedFilter = 0, Options options = 0); + // model method to get open file name + static QString getOpenFileNameDialog(const DataFileTypeEnum::Enum dataFileType, + QWidget* parent = 0, + const QString& caption = QString(), + const QString& dir = QString(), + Options options = 0); + // modal method to get save file name static QString getSaveFileNameDialog(QWidget *parent = 0, const QString &caption = QString(), diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index e341468a2..f6f443831 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -650,7 +650,8 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: break; - case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: dataFileTypesToExclude.push_back(DataFileTypeEnum::SCENE); dataFileTypesToExclude.push_back(DataFileTypeEnum::SPECIFICATION); break; @@ -679,7 +680,26 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: modifiedDataFiles.push_back(file); break; - case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: + { + /* + * Is modification data but NOT palette + */ + CaretMappableDataFile* mappableDataFile = dynamic_cast(file); + bool dataModFlag = false; + if (mappableDataFile != NULL) { + if ( ! mappableDataFile->isModifiedPaletteColorMapping()) { + if (mappableDataFile->isModifiedExcludingPaletteColorMapping()) { + dataModFlag = true; + } + } + } + if (dataModFlag) { + modifiedDataFiles.push_back(file); + } + break; + } + case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: { /* * Is modification just the palette color mapping? @@ -696,9 +716,6 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, if (paletteOnlyModFlag) { paletteModifiedDataFiles.push_back(file); } - else { - modifiedDataFiles.push_back(file); - } } break; @@ -719,7 +736,8 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: break; - case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: /* * Do not need to notify about modified scene annotations * since scene annotations are saved to the scene @@ -732,7 +750,7 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, if ((modFileCount > 0) || sceneAnnotationsModifiedFlag - || paletteModFileCount) { + || paletteModFileCount > 0) { /* * Display dialog allowing user to save files (goes to Save/Manage * Files dialog), exit without saving, or cancel. @@ -741,7 +759,8 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: textMessageOut = "Do you want to save changes you made to these files?"; break; - case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: + case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: textMessageOut = "Do you want to continue creating the scene?"; break; case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: @@ -762,9 +781,9 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, infoTextMsg.append("\n"); } if (paletteModFileCount > 0) { - infoTextMsg.appendWithNewLine("These file(s) contain modified palette color mapping. It is not " - "necessary to save these file(s) if the save palette color mapping " - "option is selected on the scene creation dialog:\n"); + infoTextMsg.appendWithNewLine("These file(s) contain modified palette color mapping " + "AND \"Add modified palette color mapping to scene\" " + "is NOT checked on the Create New Scene Dialog.\n"); for (std::vector::iterator iter = paletteModifiedDataFiles.begin(); iter != paletteModifiedDataFiles.end(); iter++) { @@ -1617,6 +1636,8 @@ GuiManager::showHideSceneDialog(const bool status, this->sceneDialog->show(); this->sceneDialog->activateWindow(); + + this->sceneDialog->createDefaultSceneFile(); } else { this->sceneDialog->close(); diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index 1dc7604c8..fe5b089ab 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -171,8 +171,10 @@ namespace caret { enum TestModifiedMode { /** Testing when user is exiting Workbench */ TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT, - /** Testing when a scene is added */ - TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD, + /** Testing when a scene is added for modified but not palette modified */ + TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, + /** Testing when a scene is added for modified palettes only */ + TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD, /** Testing when a scene is shown */ TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW }; diff --git a/src/GuiQt/SceneCreateOptionsDialog.cxx b/src/GuiQt/SceneCreateOptionsDialog.cxx new file mode 100644 index 000000000..7e0f07def --- /dev/null +++ b/src/GuiQt/SceneCreateOptionsDialog.cxx @@ -0,0 +1,136 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ +#include "SceneCreateOptionsDialog.h" +#undef __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "WuQDataEntryDialog.h" + +using namespace caret; + + + +/** + * \class caret::SceneCreateOptionsDialog + * \brief Dialog for setting create scene options + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param options + * Options displayed in dialog. + * @param parent + * Optional parent for dialog. + */ +SceneCreateOptionsDialog::SceneCreateOptionsDialog(const Options& options, + QWidget* parent) +: WuQDialogModal("Create Scene Options", + parent) +{ + CaretAssertMessage(0, "This dialog was copied from the show scene options and needs to be implemented with the show scene options"); + + /* + * Use colors contained in the scene for background and foreground + */ + const QString colorTip("Override foreground/background colors from preferences with those in scene"); + + m_useSceneColorsCheckBox = new QCheckBox("Use background and foreground colors from scene"); + m_useSceneColorsCheckBox->setToolTip(colorTip); + m_useSceneColorsCheckBox->setChecked(options.isUseSceneColorsSelected()); + + m_useSceneColorsToolButton = new QToolButton(); + m_useSceneColorsToolButton->setText("Info..."); + QObject::connect(m_useSceneColorsToolButton, &QToolButton::clicked, + this, &SceneCreateOptionsDialog::useSceneColorsInfoButtonClicked); + + QHBoxLayout* useSceneColorsLayout = new QHBoxLayout(); + useSceneColorsLayout->addWidget(m_useSceneColorsCheckBox); + useSceneColorsLayout->addWidget(m_useSceneColorsToolButton); + useSceneColorsLayout->addStretch(); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addLayout(useSceneColorsLayout); + + + dialogWidget->setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); +} + +/** + * Destructor. + */ +SceneCreateOptionsDialog::~SceneCreateOptionsDialog() +{ +} + +/** + * @return Status of options in dialog. + */ +SceneCreateOptionsDialog::Options +SceneCreateOptionsDialog::getOptions() const +{ + return Options(m_useSceneColorsCheckBox->isChecked()); +} + +void +SceneCreateOptionsDialog::useSceneColorsInfoButtonClicked() +{ + const QString infoText("Scenes created after 01 May 2016 contain the background and foreground from when the\n" + "scene was created. If this box is checked, background and foreground colors from the\n" + "scene will override the foreground and background colors in the Preferences Dialog.\n" + "The background and foreground colors will revert to those on the Preferences Dialog\n" + "when any of these events occur:\n" + " * This checkbox is unchecked\n" + " * A scene without background and foreground colors is loaded\n" + " * A Spec File and its data files are loaded\n" + " * File Menu->Close All Files is selected\n" + " * Any of the colors on the Preferences Dialog are changed\n" + " * The user quits wb_view"); + + WuQDataEntryDialog ded("Scene Colors Info", + m_useSceneColorsToolButton); + ded.hideCancelButton(); + QLabel* label = new QLabel(infoText); + ded.addWidget(label); + ded.exec(); +} + +/** + * Gets called if the user presses the OK button. + */ +void +SceneCreateOptionsDialog::okButtonClicked() +{ + WuQDialogModal::okButtonClicked(); +} + diff --git a/src/GuiQt/SceneCreateOptionsDialog.h b/src/GuiQt/SceneCreateOptionsDialog.h new file mode 100644 index 000000000..680420073 --- /dev/null +++ b/src/GuiQt/SceneCreateOptionsDialog.h @@ -0,0 +1,94 @@ +#ifndef __SCENE_CREATE_OPTIONS_DIALOG_H__ +#define __SCENE_CREATE_OPTIONS_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogModal.h" + +class QCheckBox; +class QToolButton; + +namespace caret { + + class SceneCreateOptionsDialog : public WuQDialogModal { + + Q_OBJECT + + public: + /** + * Options for display in dialog + */ + class Options { + public: + /** + * Constructor + * + * @param useSceneColorsSelected + * Status of use scene colors + */ + Options(const bool useSceneColorsSelected) + : m_useSceneColorsSelected(useSceneColorsSelected) { } + + /** @return Status of use scene colors */ + bool isUseSceneColorsSelected() const { return m_useSceneColorsSelected; } + + private: + bool m_useSceneColorsSelected = false; + }; + + + SceneCreateOptionsDialog(const Options& options, + QWidget* parent = 0); + + virtual ~SceneCreateOptionsDialog(); + + Options getOptions() const; + + // ADD_NEW_METHODS_HERE + + protected: + virtual void okButtonClicked(); + + void useSceneColorsInfoButtonClicked(); + + private: + SceneCreateOptionsDialog(const SceneCreateOptionsDialog&); + + SceneCreateOptionsDialog& operator=(const SceneCreateOptionsDialog&); + + QCheckBox* m_useSceneColorsCheckBox; + + QToolButton* m_useSceneColorsToolButton; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ + // +#endif // __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ + +} // namespace +#endif //__SCENE_CREATE_OPTIONS_DIALOG_H__ diff --git a/src/GuiQt/SceneCreateReplaceDialog.cxx b/src/GuiQt/SceneCreateReplaceDialog.cxx index cccc57339..168716ba4 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.cxx +++ b/src/GuiQt/SceneCreateReplaceDialog.cxx @@ -48,6 +48,7 @@ #include "PlainTextStringBuilder.h" #include "Scene.h" #include "SceneAttributes.h" +#include "SceneDialog.h" #include "SceneFile.h" #include "SceneInfo.h" #include "SessionManager.h" @@ -202,6 +203,9 @@ SceneCreateReplaceDialog::SceneCreateReplaceDialog(const AString& dialogTitle, } QString descriptionString = description.getText().trimmed(); + const AString defaultNewSceneName = ("New Scene " + AString::number(sceneFile->getNumberOfScenes() + 1)); + m_nameLineEdit->setText(defaultNewSceneName); + switch (m_mode) { case MODE_ADD_NEW_SCENE: m_descriptionTextEdit->setPlainText(descriptionString); @@ -216,6 +220,9 @@ SceneCreateReplaceDialog::SceneCreateReplaceDialog(const AString& dialogTitle, break; } + m_nameLineEdit->setFocus(); + m_nameLineEdit->selectAll(); + setMinimumWidth(600); setMinimumHeight(300); @@ -613,6 +620,18 @@ SceneCreateReplaceDialog::okButtonClicked() return; } + if ( ! s_previousSelections.m_addModifiedPaletteSettings) { + if ( ! SceneDialog::checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD, + this)) { + /* + * Add modified palettes to scene is off but + * there are modified palettes and user has + * chose to not create the scene + */ + return; + } + } + Scene* newScene = new Scene(SceneTypeEnum::SCENE_TYPE_FULL); Scene::setSceneBeingCreated(newScene); newScene->setName(newSceneName); diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 9338f1e66..33e6d03e6 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -70,10 +71,12 @@ #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" +#include "SceneCreateOptionsDialog.h" #include "SceneCreateReplaceDialog.h" #include "SceneFile.h" #include "SceneInfo.h" #include "ScenePreviewDialog.h" +#include "SceneShowOptionsDialog.h" #include "SessionManager.h" #include "UsernamePasswordWidget.h" #include "WuQDataEntryDialog.h" @@ -121,10 +124,23 @@ SceneDialog::SceneDialog(QWidget* parent) */ setApplyButtonText(""); + + /* + * Construction Tool Button + */ + m_cautionIconValid = WuQtUtilities::loadIcon(":/Caution/caution.png", + m_cautionIcon); + +// this->constructionAction = WuQtUtilities::createAction("M", +// "Add/Move/Remove Overlays", +// this); +// if (constructionIconValid) { +// this->constructionAction->setIcon(constructionIcon); +// } /* * Set the dialog's widget */ - this->setCentralWidget(createMainPage(), + this->setCentralWidget(createScenesWidget(), WuQDialog::SCROLL_AREA_NEVER); /* @@ -147,6 +163,8 @@ SceneDialog::SceneDialog(QWidget* parent) * so that our receiveEvent() method is called after the files have been * read. */ + EventManager::get()->addProcessedEventListener(this, + EventTypeEnum::EVENT_DATA_FILE_ADD); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_READ); EventManager::get()->addProcessedEventListener(this, @@ -164,6 +182,60 @@ SceneDialog::~SceneDialog() EventManager::get()->removeAllEventsFromListener(this); } +/** + * Process a close event. + * + * @param event + * The close event. + */ +void +SceneDialog::closeEvent(QCloseEvent* event) +{ + Brain* brain = GuiManager::get()->getBrain(); + const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); + if (numSceneFiles <= 0) { + WuQDialogNonModal::closeEvent(event); + return; + } + + int32_t numberOfModifiedSceneFiles = 0; + for (int32_t i = 0; i < numSceneFiles; i++) { + const SceneFile* sceneFile = brain->getSceneFile(i); + if (sceneFile->isModified()) { + numberOfModifiedSceneFiles++; + } + } + + if (numberOfModifiedSceneFiles <= 0) { + WuQDialogNonModal::closeEvent(event); + return; + } + +// const SceneFile* sceneFile = getSelectedSceneFile(); +// +// if ((numberOfModifiedSceneFiles == 1) +// && sceneFile->isModified()) { +// const bool successFlag = warnIfSceneFileIsModified(ModifiedWarningType::CLOSE_DIALOG_BUTTON); +// if (successFlag) { +// return; +// } +// event->ignore(); +// WuQDialogNonModal::closeEvent(event); +// return; +// } + + const AString msg("There are modified scene file(s). You can save modified scene files using File Menu->Save/Manage Files " + "or by selecting them on the Scene Dialog and using the Save/Save As buttons.

" + "Continue closing this Scene Dialog?"); + if (WuQMessageBox::warningOkCancel(this, msg)) { + WuQDialogNonModal::closeEvent(event); + return; + } + + event->ignore(); + WuQDialogNonModal::closeEvent(event); +} + /** * Update the scene dialog. */ @@ -172,8 +244,28 @@ SceneDialog::updateDialog() { loadSceneFileComboBox(NULL); loadScenesIntoDialog(NULL); + + updateSceneFileModifiedStatusLabel(); +} + +/** + * Create the default scene file if + * there are any models and there are no + * scene files. + */ +void +SceneDialog::createDefaultSceneFile() +{ + if (getSelectedSceneFile() == NULL) { + EventModelGetAll allModelsEvent; + EventManager::get()->sendEvent(allModelsEvent.getPointer()); + if ( ! allModelsEvent.getModels().empty()) { + newSceneFileButtonClicked(); + } + } } + /** * Get the selected scene file. * @return SceneFile or NULL if no scene file. @@ -231,7 +323,35 @@ SceneDialog::getSelectedScene() return selectedScene; } - +/** + * Update the modified icons in the scene file combo box. + */ +void +SceneDialog::updateSceneFileComboBoxModifiedIcons() +{ + if ( ! m_cautionIconValid) { + return; + } + + m_sceneFileSelectionComboBox->blockSignals(true); + + const int32_t numItems = m_sceneFileSelectionComboBox->count(); + for (int32_t itemIndex = 0; itemIndex < numItems; itemIndex++) { + void* filePointer = m_sceneFileSelectionComboBox->itemData(itemIndex).value(); + SceneFile* sceneFile = (SceneFile*)filePointer; + CaretAssert(sceneFile); + if (sceneFile->isModified()) { + m_sceneFileSelectionComboBox->setItemIcon(itemIndex, + m_cautionIcon); + } + else { + m_sceneFileSelectionComboBox->setItemIcon(itemIndex, + QIcon()); + } + } + + m_sceneFileSelectionComboBox->blockSignals(false); +} /** * Load the scene files into the scene file combo box. @@ -260,33 +380,26 @@ SceneDialog::loadSceneFileComboBox(SceneFile* selectedSceneFileIn) } const AString name = sceneFile->getFileNameNoPath(); - m_sceneFileSelectionComboBox->addItem(name, - qVariantFromValue((void*)sceneFile)); + if (sceneFile->isModified() + && m_cautionIconValid) { + m_sceneFileSelectionComboBox->addItem(m_cautionIcon, + name, + qVariantFromValue((void*)sceneFile)); + } + else { + m_sceneFileSelectionComboBox->addItem(name, + qVariantFromValue((void*)sceneFile)); + } } if (numSceneFiles > 0) { m_sceneFileSelectionComboBox->setCurrentIndex(defaultFileComboIndex); - loadSceneFileMetaDataWidgets(); } m_sceneFileButtonsGroup->setEnabled(getSelectedSceneFile() != NULL); -} -/** - * Load the Scene File BALSA Study ID Line Edit - */ -void -SceneDialog::loadSceneFileMetaDataWidgets() -{ - m_fileBalsaStudyIDLineEdit->clear(); - m_fileBaseDirectoryLineEdit->clear(); - - SceneFile* sceneFile = getSelectedSceneFile(); - if (sceneFile != NULL) { - m_fileBalsaStudyIDLineEdit->setText(sceneFile->getBalsaStudyID()); - m_fileBaseDirectoryLineEdit->setText(sceneFile->getBaseDirectory()); - } + updateSceneFileModifiedStatusLabel(); } /** @@ -393,6 +506,24 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) m_replaceScenePushButton->setEnabled(validScene); m_showScenePushButton->setEnabled(validScene); m_showSceneImagePreviewPushButton->setEnabled(validScene); + m_showSceneOptionsPushButton->setEnabled(validScene); +} + +/** + * @return Number of valid scene info widgets. + */ +int32_t +SceneDialog::getNumberOfValidSceneInfoWidgets() const +{ + int32_t numValid = 0; + + for (auto ssiw : m_sceneClassInfoWidgets) { + if (ssiw->isValid()) { + numValid++; + } + } + + return numValid; } /** @@ -401,7 +532,7 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) void SceneDialog::enableSceneMoveUpAndDownButtons() { - const int32_t numberOfSceneInfoWidgets = static_cast(m_sceneClassInfoWidgets.size()); + const int32_t numberOfSceneInfoWidgets = getNumberOfValidSceneInfoWidgets(); m_moveSceneUpPushButton->setEnabled(m_selectedSceneClassInfoIndex > 0); m_moveSceneDownPushButton->setEnabled((m_selectedSceneClassInfoIndex >= 0) && (m_selectedSceneClassInfoIndex < (numberOfSceneInfoWidgets - 1))); @@ -475,191 +606,445 @@ SceneDialog::highlightScene(const Scene* scene) } /** - * Called to create a new scene file. + * Called to open a scene file. */ -void -SceneDialog::newSceneFileButtonClicked() +void +SceneDialog::openSceneFileButtonClicked() { if ( ! displayNewSceneWarning()) { return; } + if ( ! warnIfSceneFileIsModified(ModifiedWarningType::OPEN_FILE_BUTTON)) { + return; + } + /* * Let user choose a different path/name */ - SceneFile* newSceneFile = new SceneFile(); - GuiManager::get()->getBrain()->convertDataFilePathNameToAbsolutePathName(newSceneFile); - AString newSceneFileName = CaretFileDialog::getSaveFileNameDialog(DataFileTypeEnum::SCENE, - this, - "Choose Scene File Name", - newSceneFile->getFileName()); + AString openSceneFileName = CaretFileDialog::getOpenFileNameDialog(DataFileTypeEnum::SCENE, + m_openSceneFilePushButton, + "Open a Scene File", + ""); /* - * If user cancels, delete the new scene file and return + * If user cancels, return */ - if (newSceneFileName.isEmpty()) { - delete newSceneFile; + if (openSceneFileName.isEmpty()) { return; } + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + /* - * Set name of new scene file and add to brain + * Note that this dialog receives EventDataFileRead + * as a post-processed event and will take care of + * the dialog updates. */ - newSceneFile->setFileName(newSceneFileName); - EventManager::get()->sendEvent(EventDataFileAdd(newSceneFile).getPointer()); - this->loadSceneFileComboBox(newSceneFile); - this->sceneFileSelected(); + EventDataFileRead dataFileEvent(GuiManager::get()->getBrain()); + dataFileEvent.addDataFile(DataFileTypeEnum::SCENE, openSceneFileName); + EventManager::get()->sendEvent(dataFileEvent.getPointer()); } + /** - * Called when upload scene file is selected. + * Called to create a new scene file. */ -void -SceneDialog::uploadSceneFileButtonClicked() +void +SceneDialog::newSceneFileButtonClicked() { - SceneFile* sceneFile = getSelectedSceneFile(); - if (sceneFile == NULL) { - WuQMessageBox::errorOk(m_uploadSceneFilePushButton, - "No Scene File is selected."); - return; - } - if (sceneFile->isModified()) { - WuQMessageBox::errorOk(m_uploadSceneFilePushButton, - "Selected Scene File is modified and must be saved prior to uploading."); + if ( ! displayNewSceneWarning()) { return; } - if (sceneFile->getBalsaStudyID().trimmed().isEmpty()) { - const QString msg("The BALSA Study ID is missing. You must go to the " - "BALSA Database and get a BALSA Study ID."); - WuQMessageBox::errorOk(m_uploadSceneFilePushButton, msg); + if ( ! warnIfSceneFileIsModified(ModifiedWarningType::NEW_FILE_BUTTON)) { return; } - BalsaDatabaseUploadSceneFileDialog uploadDialog(sceneFile, - this); - uploadDialog.exec(); -} + SceneFile* newSceneFile = new SceneFile(); + GuiManager::get()->getBrain()->convertDataFilePathNameToAbsolutePathName(newSceneFile); + newSceneFile->clearModified(); + /* + * Note that this dialog receives EventDataFileAdd + * as a post-processed event and will take care of + * the dialog updates. + */ + EventManager::get()->sendEvent(EventDataFileAdd(newSceneFile).getPointer()); +} /** - * Called when zip scene file is selected. + * Save the selected scene file. */ void -SceneDialog::zipSceneFileButtonClicked() +SceneDialog::saveSceneFileButtonClicked() { - SceneFile* sceneFile = getSelectedSceneFile(); - if (sceneFile == NULL) { - WuQMessageBox::errorOk(m_zipSceneFilePushButton, - "No Scene File is selected."); - return; - } - if (sceneFile->isModified()) { - WuQMessageBox::errorOk(m_zipSceneFilePushButton, - "Selected Scene File is modified and must be saved prior to zipping."); - return; - } - - ZipSceneFileDialog zipDialog(sceneFile, - this); - zipDialog.exec(); + saveSelectedSceneFile(); } /** - * Called when a scene file is selected. + * Save the selected scene file with a new name. */ -void -SceneDialog::sceneFileSelected() +void SceneDialog::saveAsSceneFileButtonClicked() { - loadScenesIntoDialog(NULL); - loadSceneFileMetaDataWidgets(); + saveAsSelectedSceneFile(); } /** - * Called when Edit Study ID button is clicked. + * Save the selected scene file using the file' current name. + * + * @return True if file was saved else false and an error message is displayed. */ -void -SceneDialog::editFileBalsaStudyIDButtonClicked() +bool +SceneDialog::saveSelectedSceneFile() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { - return; + WuQMessageBox::errorOk(m_saveSceneFilePushButton, "There is no selected scene file to save"); + return false; + } + + try { + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + Brain* brain = GuiManager::get()->getBrain(); + brain->writeDataFile(sceneFile); + } + catch (const DataFileException& e) { + WuQMessageBox::errorOk(m_saveSceneFilePushButton, e.whatString()); + return false; } - WuQDataEntryDialog ded("Edit BALSA Database Info", - m_editBalsaStudyIDPushButton, - WuQDialog::SCROLL_AREA_AS_NEEDED); + updateSceneFileModifiedStatusLabel(); - QLineEdit* lineEdit = ded.addLineEditWidget("BALSA Study ID"); - lineEdit->setText(sceneFile->getBalsaStudyID()); - lineEdit->setMinimumWidth(200); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - const AString idText = lineEdit->text().trimmed(); - sceneFile->setBalsaStudyID(idText); - loadSceneFileMetaDataWidgets(); - } + return true; } /** - * Called when upload scene file is selected. + * Save the selected scene file with display of a file selection dialog using the file' current name. + * + * @return True if file was saved else false and an error message is displayed. */ -void -SceneDialog::editBaseDirectoryPushButtonClicked() +bool +SceneDialog::saveAsSelectedSceneFile() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { - return; + WuQMessageBox::errorOk(m_saveAsSceneFilePushButton, "There is no selected scene file to save"); + return false; } - WuQDataEntryDialog ded("Edit Base Directory", - m_editBaseDirectoryPushButton, - WuQDialog::SCROLL_AREA_AS_NEEDED); + const AString filename = CaretFileDialog::getSaveFileNameDialog(sceneFile->getDataFileType(), + m_saveAsSceneFilePushButton, + "Save Scene File As", + sceneFile->getFileName()); + if (filename.isEmpty()) { + return false; + } - QLineEdit* lineEdit = ded.addLineEditWidget("Base Directory"); - lineEdit->setText(sceneFile->getBaseDirectory()); - lineEdit->setMinimumWidth(500); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - const AString idText = lineEdit->text().trimmed(); - sceneFile->setBaseDirectory(idText); - loadSceneFileMetaDataWidgets(); + try { + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + sceneFile->setFileName(filename); + Brain* brain = GuiManager::get()->getBrain(); + brain->writeDataFile(sceneFile); + } + catch (const DataFileException& e) { + WuQMessageBox::errorOk(m_saveAsSceneFilePushButton, e.whatString()); + return false; } + + updateSceneFileModifiedStatusLabel(); + + return true; } /** - * Called when upload scene file is selected. + * If the selected scene file is modified, warn the user and + * suggest saving the file prior to continuing. + * + * @param warningType + * Type of warning. + * @return + * True if the operation should continue, else false. */ -void -SceneDialog::browseBaseDirectoryPushButtonClicked() +bool +SceneDialog::warnIfSceneFileIsModified(const ModifiedWarningType warningType) { - SceneFile* sceneFile = getSelectedSceneFile(); + const SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { - return; + return true; + } + if ( ! sceneFile->isModified()) { + return true; + } + + /** + * Return true if warning is disabled for an operation + */ + switch (warningType) { + case ModifiedWarningType::CLOSE_DIALOG_BUTTON: + break; + case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: + return true; + break; + case ModifiedWarningType::NEW_FILE_BUTTON: + return true; + break; + case ModifiedWarningType::OPEN_FILE_BUTTON: + return true; + break; + case ModifiedWarningType::UPLOAD_FILE_BUTTON: + break; + case ModifiedWarningType::ZIP_FILE_BUTTON: + break; } /* - * Let user choose directory path + * Parent for message box dialogs */ - QString directoryName; - FileInformation fileInfo(sceneFile->getBaseDirectory()); - if (fileInfo.exists()) { - if (fileInfo.isDirectory()) { - directoryName = fileInfo.getAbsoluteFilePath(); + QWidget* messageBoxParent = NULL; + switch (warningType) { + case ModifiedWarningType::CLOSE_DIALOG_BUTTON: + messageBoxParent = this; + break; + case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: + messageBoxParent = m_sceneFileSelectionComboBox; + break; + case ModifiedWarningType::NEW_FILE_BUTTON: + messageBoxParent = m_newSceneFilePushButton; + break; + case ModifiedWarningType::OPEN_FILE_BUTTON: + messageBoxParent = m_openSceneFilePushButton; + break; + case ModifiedWarningType::UPLOAD_FILE_BUTTON: + messageBoxParent = m_uploadSceneFilePushButton; + break; + case ModifiedWarningType::ZIP_FILE_BUTTON: + messageBoxParent = m_zipSceneFilePushButton; + break; + } + CaretAssert(messageBoxParent); + + if (sceneFile->getNumberOfScenes() <= 0) { + switch (warningType) { + case ModifiedWarningType::CLOSE_DIALOG_BUTTON: + return true; + break; + case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: + return true; + break; + case ModifiedWarningType::NEW_FILE_BUTTON: + return true; + break; + case ModifiedWarningType::OPEN_FILE_BUTTON: + return true; + break; + case ModifiedWarningType::UPLOAD_FILE_BUTTON: + break; + case ModifiedWarningType::ZIP_FILE_BUTTON: + break; } + + WuQMessageBox::errorOk(messageBoxParent, + "There are no scenes in the scene file !"); + return false; } - AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, - "Choose Base Directory", - directoryName); + + bool enableContinueButton = false; + bool enableSaveButton = sceneFile->exists(); + QMessageBox::Icon messageBoxIcon = QMessageBox::NoIcon; + /* - * If user cancels, return + * Set up the informative text */ - if (newDirectoryName.isEmpty()) { - return; - } + AString saveText = ("Press the Save button to save the scene file with its current name "); + AString saveAsText = ("Press the Save As button to save the scene file to a new name using a file dialog "); + AString continueText = ("Press the Continue button to skip saving the scene file (you may save it at a later time) "); + AString cancelText = ("Press the Cancel button to skip saving the scene file and "); + switch (warningType) { + case ModifiedWarningType::CLOSE_DIALOG_BUTTON: + messageBoxIcon = QMessageBox::Warning; + enableContinueButton = true; + saveText.append("and close the scene dialog"); + saveAsText.append("and close the scene dialog"); + continueText.append("and close the scene dialog"); + cancelText.append("do not close the scene dialog"); + break; + case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: + messageBoxIcon = QMessageBox::Warning; + enableContinueButton = true; + saveText.append("and change the selected scene file"); + saveAsText.append("and change the selected scene file"); + continueText.append("and change the selected scene file"); + cancelText.append("cancel changing the selected scene file"); + break; + case ModifiedWarningType::NEW_FILE_BUTTON: + messageBoxIcon = QMessageBox::Warning; + enableContinueButton = true; + saveText.append(" and create a new scene file"); + saveAsText.append(" and create a new scene file"); + continueText.append(" and create a new scene file"); + cancelText.append("cancel creation of a new scene file"); + break; + case ModifiedWarningType::OPEN_FILE_BUTTON: + messageBoxIcon = QMessageBox::Warning; + enableContinueButton = true; + saveText.append("and display a dialog for opening a scene file"); + saveAsText.append("and display a dialog for opening a scene file"); + continueText.append("and display a dialog for opening a scene file"); + cancelText.append("cancel opening a scene file"); + break; + case ModifiedWarningType::UPLOAD_FILE_BUTTON: + messageBoxIcon = QMessageBox::Warning; + saveText.append("and continue uploading the scene file"); + saveAsText.append("and continue uploading the scene file"); + continueText.append(""); + cancelText.append("cancel uploading the scene file"); + break; + case ModifiedWarningType::ZIP_FILE_BUTTON: + messageBoxIcon = QMessageBox::Warning; + saveText.append("and zip the scene file"); + saveAsText.append("and zip the scene file"); + continueText.append("and zip the scene file"); + cancelText.append("and cancel zipping the scene file"); + break; + } + + AString informativeText(""); + if (enableSaveButton) { + informativeText.append(saveText + "

"); + } + informativeText.append(saveAsText + "

"); + if (enableContinueButton) { + informativeText.append(continueText + "

"); + } + informativeText.append(cancelText + "

"); + informativeText.append(""); /* - * Set name of new scene file and add to brain + * Create and display the message box dialog */ - sceneFile->setBaseDirectory(newDirectoryName); - loadSceneFileMetaDataWidgets(); + QMessageBox messageBox(messageBoxParent); + messageBox.setText("The selected scene file has been modified but not saved: " + + sceneFile->getFileNameNoPath()); + messageBox.setInformativeText(informativeText); + messageBox.setIcon(messageBoxIcon); + QPushButton* saveButton = NULL; + if (enableSaveButton) { + saveButton = messageBox.addButton("Save", QMessageBox::AcceptRole); + } + QPushButton* saveAsButton = messageBox.addButton("Save As...", QMessageBox::AcceptRole); + QPushButton* cancelButton = messageBox.addButton("Cancel", QMessageBox::NoRole); + QPushButton* continueButton = NULL; + if (enableContinueButton) { + continueButton = messageBox.addButton("Continue", QMessageBox::AcceptRole); + } + + if (saveButton != NULL) { + messageBox.setDefaultButton(saveButton); + } + else { + messageBox.setDefaultButton(saveAsButton); + } + + messageBox.exec(); + + QAbstractButton* button = messageBox.clickedButton(); + CaretAssert(button); + + bool successFlag = false; + + if (button == saveButton) { + successFlag = saveSelectedSceneFile(); + } + else if (button == saveAsButton) { + successFlag = saveAsSelectedSceneFile(); + + } + else if (button == cancelButton) { + successFlag = false; + + } + else if (button == continueButton) { + successFlag = true; + } + else { + CaretAssertMessage(0, "Button clicked not handled " + button->text()); + } + + return successFlag; +} + + +/** + * Called when upload scene file is selected. + */ +void +SceneDialog::uploadSceneFileButtonClicked() +{ + if ( ! warnIfSceneFileIsModified(ModifiedWarningType::UPLOAD_FILE_BUTTON)) { + return; + } + + SceneFile* sceneFile = getSelectedSceneFile(); +// if (sceneFile->isModified()) { +// WuQMessageBox::errorOk(m_uploadSceneFilePushButton, +// "Selected Scene File is modified and must be saved prior to uploading."); +// return; +// } + + BalsaDatabaseUploadSceneFileDialog uploadDialog(sceneFile, + this); + uploadDialog.exec(); + + updateSceneFileModifiedStatusLabel(); +} + + +/** + * Called when zip scene file is selected. + */ +void +SceneDialog::zipSceneFileButtonClicked() +{ + if ( ! warnIfSceneFileIsModified(ModifiedWarningType::ZIP_FILE_BUTTON)) { + return; + } + + SceneFile* sceneFile = getSelectedSceneFile(); +// if (sceneFile == NULL) { +// WuQMessageBox::errorOk(m_zipSceneFilePushButton, +// "No Scene File is selected."); +// return; +// } +// if (sceneFile->isModified()) { +// WuQMessageBox::errorOk(m_zipSceneFilePushButton, +// "Selected Scene File is modified and must be saved prior to zipping."); +// return; +// } + + ZipSceneFileDialog zipDialog(sceneFile, + this); + zipDialog.exec(); + + updateSceneFileModifiedStatusLabel(); +} + +/** + * Called when a scene file is selected. + * + * @param index + * Index of item selected. + */ +void +SceneDialog::sceneFileSelected(int index) +{ + loadScenesIntoDialog(NULL); + + updateSceneFileModifiedStatusLabel(); } /** @@ -672,7 +1057,8 @@ SceneDialog::addNewSceneButtonClicked() return; } - if ( ! checkForModifiedFiles(true)) { + if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, + this)) { return; } @@ -686,6 +1072,9 @@ SceneDialog::addNewSceneButtonClicked() loadScenesIntoDialog(newScene); } + + + updateSceneFileModifiedStatusLabel(); } /** @@ -698,7 +1087,8 @@ SceneDialog::insertSceneButtonClicked() return; } - if ( ! checkForModifiedFiles(true)) { + if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, + this)) { return; } @@ -716,6 +1106,8 @@ SceneDialog::insertSceneButtonClicked() loadScenesIntoDialog(newScene); } } + + updateSceneFileModifiedStatusLabel(); } /** @@ -972,6 +1364,8 @@ SceneDialog::moveSceneUpButtonClicked() if (scene != NULL) { sceneFile->moveScene(scene, -1); loadScenesIntoDialog(scene); + + updateSceneFileModifiedStatusLabel(); } } } @@ -988,6 +1382,8 @@ SceneDialog::moveSceneDownButtonClicked() if (scene != NULL) { sceneFile->moveScene(scene, 1); loadScenesIntoDialog(scene); + + updateSceneFileModifiedStatusLabel(); } } } @@ -1002,7 +1398,8 @@ SceneDialog::replaceSceneButtonClicked() return; } - if ( ! checkForModifiedFiles(true)) { + if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, + this)) { return; } @@ -1018,6 +1415,8 @@ SceneDialog::replaceSceneButtonClicked() } loadScenesIntoDialog(newScene); + + updateSceneFileModifiedStatusLabel(); } } } @@ -1115,14 +1514,28 @@ SceneDialog::replaceSceneButtonClicked() * true if the scene should be created, otherwise false. */ bool -SceneDialog::checkForModifiedFiles(const bool creatingSceneFlag) +SceneDialog::checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, + QWidget* parent) { + bool creatingSceneFlag = false; + switch (testMode) { + case GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: + creatingSceneFlag = true; + break; + case GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: + break; + case GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: + break; + case GuiManager::TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: + break; + } + if (creatingSceneFlag) { EventModelGetAll allModelsEvent; EventManager::get()->sendEvent(allModelsEvent.getPointer()); if (allModelsEvent.getModels().empty()) { const QString msg("No surfaces or volumes are loaded. Continue creating scene?"); - if ( ! WuQMessageBox::warningYesNo(this, + if ( ! WuQMessageBox::warningYesNo(parent, msg)) { return false; } @@ -1131,10 +1544,10 @@ SceneDialog::checkForModifiedFiles(const bool creatingSceneFlag) AString dialogMessage; AString modifiedFilesMessage; - GuiManager::TestModifiedMode testMode = GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW; - if (creatingSceneFlag) { - testMode = GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_ADD; - } +// GuiManager::TestModifiedMode testMode = GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW; +// if (creatingSceneFlag) { +// testMode = GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD; +// } const bool haveModifiedFilesFlag = GuiManager::get()->testForModifiedFiles(testMode, dialogMessage, modifiedFilesMessage); @@ -1146,7 +1559,7 @@ SceneDialog::checkForModifiedFiles(const bool creatingSceneFlag) "Warning", dialogMessage, QMessageBox::NoButton, - this); + parent); warningDialog.setInformativeText(modifiedFilesMessage); QPushButton* yesButton = warningDialog.addButton("Yes", QMessageBox::AcceptRole); @@ -1172,11 +1585,10 @@ SceneDialog::checkForModifiedFiles(const bool creatingSceneFlag) } /** - * Create the main page. - * @return the main page. + * @return The Scenes widget. */ QWidget* -SceneDialog::createMainPage() +SceneDialog::createScenesWidget() { QWidget* sceneFileWidget = createSceneFileWidget(); @@ -1253,28 +1665,95 @@ SceneDialog::createMainPage() * Show scene image button */ m_showSceneImagePreviewPushButton = new QPushButton("Preview..."); - m_showSceneImagePreviewPushButton->setToolTip("Show larger image and full description\n" + m_showSceneImagePreviewPushButton->setToolTip("Show larger preview image and full description\n" "for the selected scene"); QObject::connect(m_showSceneImagePreviewPushButton, SIGNAL(clicked()), this, SLOT(showImagePreviewButtonClicked())); + /* + * Show scene options button + */ + m_showSceneOptionsPushButton = new QPushButton("Options..."); + m_showSceneOptionsPushButton->setToolTip("Display a dialog for show scene options"); + QObject::connect(m_showSceneOptionsPushButton, &QPushButton::clicked, + this, &SceneDialog::showSceneOptionsButtonClicked); + + /* + * Create scene options button + */ + m_createSceneOptionsPushButton = NULL; + bool haveCreateOptionsFlag = false; + if (haveCreateOptionsFlag) { + m_createSceneOptionsPushButton = new QPushButton("Options..."); + m_createSceneOptionsPushButton->setToolTip("Display a dialog for create scene options"); + QObject::connect(m_createSceneOptionsPushButton, &QPushButton::clicked, + this, &SceneDialog::createSceneOptionsButtonClicked); + } + + /* + * Margins/spacing for button groups + */ + /* + * Group for show buttons + */ + QGroupBox* showGroupBox = new QGroupBox("Show Scene"); + showGroupBox->setFlat(true); + showGroupBox->setSizePolicy(showGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + QVBoxLayout* showGroupLayout = new QVBoxLayout(showGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(showGroupLayout, 2, 2); + showGroupLayout->addWidget(m_showScenePushButton); + showGroupLayout->addWidget(m_showSceneImagePreviewPushButton); + showGroupLayout->addWidget(m_showSceneOptionsPushButton); + + /* + * Group for create buttons + */ + QGroupBox* createGroupBox = new QGroupBox("Create Scene"); + createGroupBox->setFlat(true); + createGroupBox->setSizePolicy(createGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + QVBoxLayout* createGroupLayout = new QVBoxLayout(createGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(createGroupLayout, 2, 2); + createGroupLayout->addWidget(m_addNewScenePushButton); + createGroupLayout->addWidget(m_insertNewScenePushButton); + createGroupLayout->addWidget(m_replaceScenePushButton); + if (m_createSceneOptionsPushButton) { + createGroupLayout->addWidget(m_createSceneOptionsPushButton); + } + + /* + * Group for test buttons + */ + QGroupBox* testGroupBox = new QGroupBox("Testing"); + testGroupBox->setFlat(true); + testGroupBox->setSizePolicy(testGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + QVBoxLayout* testGroupLayout = new QVBoxLayout(testGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(testGroupLayout, 2, 2); + testGroupLayout->addWidget(m_testScenesPushButton); + + /* + * Group for organize buttons + */ + QGroupBox* organizeGroupBox = new QGroupBox("Selected Scene"); + organizeGroupBox->setFlat(true); + organizeGroupBox->setSizePolicy(organizeGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + QVBoxLayout* organizeGroupLayout = new QVBoxLayout(organizeGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(organizeGroupLayout, 2, 2); + organizeGroupLayout->addWidget(m_moveSceneUpPushButton); + organizeGroupLayout->addWidget(m_moveSceneDownPushButton); + organizeGroupLayout->addSpacing(5); + organizeGroupLayout->addWidget(m_deleteScenePushButton); + /* * Layout for scene buttons */ QVBoxLayout* sceneButtonLayout = new QVBoxLayout(); - sceneButtonLayout->addWidget(m_showScenePushButton); - sceneButtonLayout->addWidget(m_showSceneImagePreviewPushButton); + sceneButtonLayout->addWidget(showGroupBox); sceneButtonLayout->addSpacing(20); - sceneButtonLayout->addWidget(m_addNewScenePushButton); - sceneButtonLayout->addWidget(m_insertNewScenePushButton); - sceneButtonLayout->addWidget(m_replaceScenePushButton); + sceneButtonLayout->addWidget(createGroupBox); sceneButtonLayout->addStretch(); - sceneButtonLayout->addWidget(m_testScenesPushButton); - sceneButtonLayout->addSpacing(20); - sceneButtonLayout->addWidget(m_moveSceneUpPushButton); - sceneButtonLayout->addWidget(m_moveSceneDownPushButton); + sceneButtonLayout->addWidget(testGroupBox); sceneButtonLayout->addSpacing(20); - sceneButtonLayout->addWidget(m_deleteScenePushButton); + sceneButtonLayout->addWidget(organizeGroupBox); /* * Widget and layout containing the scene class info. @@ -1292,11 +1771,6 @@ SceneDialog::createMainPage() m_sceneSelectionScrollArea->setWidget(m_sceneSelectionWidget); m_sceneSelectionScrollArea->setWidgetResizable(true); - QVBoxLayout* showOptionsLabelsLayout = new QVBoxLayout(); - WuQtUtilities::setLayoutMargins(showOptionsLabelsLayout, 0); - showOptionsLabelsLayout->addWidget(new QLabel(" Show Scene"), 0, Qt::AlignRight); - showOptionsLabelsLayout->addWidget(new QLabel("Options"), 0, Qt::AlignHCenter); - /* * Layout widgets */ @@ -1318,9 +1792,6 @@ SceneDialog::createMainPage() row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 3); row++; - gridLayout->addLayout(showOptionsLabelsLayout, row, 0, Qt::AlignTop); - gridLayout->addWidget(createShowOptionsWidget(), row, 1, 1, 1); //, Qt::AlignTop); - row++; return widget; } @@ -1343,16 +1814,46 @@ SceneDialog::createSceneFileWidget() "Selects an existing scene file\n" "to which new scenes are added."); QObject::connect(m_sceneFileSelectionComboBox, SIGNAL(activated(int)), - this, SLOT(sceneFileSelected())); + this, SLOT(sceneFileSelected(int))); + + /* + * Scene file modified status + */ + QLabel* modifiedLabel = new QLabel("Modified"); + m_sceneFileModifiedStatusLabel = new QLabel(""); /* * New File button */ - QPushButton* newSceneFilePushButton = new QPushButton("New..."); - newSceneFilePushButton->setToolTip("Create a new scene file"); - QObject::connect(newSceneFilePushButton, SIGNAL(clicked()), + m_newSceneFilePushButton = new QPushButton("New"); + m_newSceneFilePushButton->setToolTip("Create a new scene file"); + QObject::connect(m_newSceneFilePushButton, SIGNAL(clicked()), this, SLOT(newSceneFileButtonClicked())); + /* + * Open File button + */ + m_openSceneFilePushButton = new QPushButton("Open..."); + m_openSceneFilePushButton->setToolTip("Open an existing scene file"); + QObject::connect(m_openSceneFilePushButton, SIGNAL(clicked()), + this, SLOT(openSceneFileButtonClicked())); + + /* + * Save File button + */ + m_saveSceneFilePushButton = new QPushButton("Save"); + m_saveSceneFilePushButton->setToolTip("Save the scene file using its current name"); + QObject::connect(m_saveSceneFilePushButton, SIGNAL(clicked()), + this, SLOT(saveSceneFileButtonClicked())); + + /* + * Save As File button + */ + m_saveAsSceneFilePushButton = new QPushButton("Save As..."); + m_saveAsSceneFilePushButton->setToolTip("Display a file selection dialog for saving scene file with a new name"); + QObject::connect(m_saveAsSceneFilePushButton, SIGNAL(clicked()), + this, SLOT(saveAsSceneFileButtonClicked())); + /* * Upload button */ @@ -1369,56 +1870,14 @@ SceneDialog::createSceneFileWidget() QObject::connect(m_zipSceneFilePushButton, SIGNAL(clicked()), this, SLOT(zipSceneFileButtonClicked())); - /* - * Scene BALSA Study ID - */ - QLabel* studyIDLabel = new QLabel("BALSA Study ID"); - m_fileBalsaStudyIDLineEdit = new QLineEdit(); - m_fileBalsaStudyIDLineEdit->setToolTip("Press Edit button to change Study ID for use with BALSA Database"); - m_fileBalsaStudyIDLineEdit->setReadOnly(true); - - /* - * Edit BALSA Study ID button - */ - m_editBalsaStudyIDPushButton = new QPushButton("Edit..."); - m_editBalsaStudyIDPushButton->setToolTip("Edit the Scene File's BALSA Study ID"); - QObject::connect(m_editBalsaStudyIDPushButton, SIGNAL(clicked()), - this, SLOT(editFileBalsaStudyIDButtonClicked())); - - /* - * Base Directory - */ - QLabel* baseDirectoryLabel = new QLabel("Base Directory"); - m_fileBaseDirectoryLineEdit = new QLineEdit(); - m_fileBaseDirectoryLineEdit->setToolTip("Press Browse or Edit button to change base directory"); - m_fileBaseDirectoryLineEdit->setReadOnly(true); - m_editBaseDirectoryPushButton = new QPushButton("Edit..."); - m_editBaseDirectoryPushButton->setToolTip("Edit the base directory in a text edit"); - QObject::connect(m_editBaseDirectoryPushButton, SIGNAL(clicked()), - this, SLOT(editBaseDirectoryPushButtonClicked())); - m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); - m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); - QObject::connect(m_browseBaseDirectoryPushButton, SIGNAL(clicked()), - this, SLOT(browseBaseDirectoryPushButtonClicked())); - /* * Group for scene file buttons that are only valid when a scene file is available */ m_sceneFileButtonsGroup = new WuQWidgetObjectGroup(this); + m_sceneFileButtonsGroup->add(m_saveSceneFilePushButton); + m_sceneFileButtonsGroup->add(m_saveAsSceneFilePushButton); m_sceneFileButtonsGroup->add(m_uploadSceneFilePushButton); m_sceneFileButtonsGroup->add(m_zipSceneFilePushButton); - m_sceneFileButtonsGroup->add(m_editBalsaStudyIDPushButton); - m_sceneFileButtonsGroup->add(m_editBaseDirectoryPushButton); - m_sceneFileButtonsGroup->add(m_browseBaseDirectoryPushButton); - - /* - * Scene file buttons layout - */ - QHBoxLayout* fileButtonsLayout = new QHBoxLayout(); - fileButtonsLayout->setContentsMargins(0, 0, 0, 0); - fileButtonsLayout->addWidget(newSceneFilePushButton); - fileButtonsLayout->addWidget(m_uploadSceneFilePushButton); - fileButtonsLayout->addWidget(m_zipSceneFilePushButton); /* * Layout widgets @@ -1434,66 +1893,24 @@ SceneDialog::createSceneFileWidget() gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); + gridLayout->setColumnStretch(4, 0); int row = 0; - gridLayout->addWidget(sceneFileLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_sceneFileSelectionComboBox, row, 1); - gridLayout->addLayout(fileButtonsLayout, row, 2, 1, 2); -// gridLayout->addWidget(newSceneFilePushButton, row, 2); -// gridLayout->addWidget(m_uploadSceneFilePushButton, row, 3); -// gridLayout->addWidget(m_zipSceneFilePushButton, row, 4); + gridLayout->addWidget(sceneFileLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_sceneFileSelectionComboBox, row, 1); + gridLayout->addWidget(m_newSceneFilePushButton, row, 2); + gridLayout->addWidget(m_saveSceneFilePushButton, row, 3); + gridLayout->addWidget(m_zipSceneFilePushButton, row, 4); row++; - gridLayout->addWidget(baseDirectoryLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_fileBaseDirectoryLineEdit, row, 1); - gridLayout->addWidget(m_editBaseDirectoryPushButton, row, 2); - gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, 3); + gridLayout->addWidget(modifiedLabel, row, 0, Qt::AlignRight); + gridLayout->addWidget(m_sceneFileModifiedStatusLabel, row, 1, Qt::AlignLeft); + gridLayout->addWidget(m_openSceneFilePushButton, row, 2); + gridLayout->addWidget(m_saveAsSceneFilePushButton, row, 3); + gridLayout->addWidget(m_uploadSceneFilePushButton, row, 4); row++; - gridLayout->addWidget(studyIDLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_fileBalsaStudyIDLineEdit, row, 1); - gridLayout->addWidget(m_editBalsaStudyIDPushButton, row, 2); return widget; } - -/** - * @return The show scene options widget. - */ -QWidget* -SceneDialog::createShowOptionsWidget() -{ - /* - * Use colors contained in the scene for background and foreground - */ - const QString colorTip1("Scenes created after 01 May 2016 contain the active background and foreground\n" - "colors. When this box is checked and the colors are present in the scene loaded,\n" - "they will temporarily override the colors in the Preferences Dialog. The background\n" - "and foreground colors will revert to those on the Preferences Dialog when any\n" - "of these events occur:\n" - " * This checkbox is unchecked\n" - " * A scene without background and foreground colors is loaded\n" - " * A Spec File and its data files are loaded\n" - " * File Menu->Close All Files is selected\n" - " * Any of the colors on the Preferences Dialog are changed\n" - " * The user quits wb_view"); - - m_useSceneColorsCheckBox = new QCheckBox("Use background and foreground colors from scene"); - m_useSceneColorsCheckBox->setToolTip(colorTip1); - m_useSceneColorsCheckBox->setChecked(true); - QObject::connect(m_useSceneColorsCheckBox, SIGNAL(clicked(bool)), - this, SLOT(useSceneColorsCheckBoxClicked(bool))); - - QFrame* frame = new QFrame(); - frame->setFrameShape(QFrame::StyledPanel); - frame->setFrameShadow(QFrame::Plain); - frame->setLineWidth(1); - frame->setMidLineWidth(1); - QVBoxLayout* layout = new QVBoxLayout(frame); - WuQtUtilities::setLayoutMargins(layout, 5); - layout->addWidget(m_useSceneColorsCheckBox, 0, Qt::AlignLeft); - - return frame; -} - /** * Gets called to verify the content of the scene creation dialog. * @param sceneCreateDialog @@ -1642,6 +2059,54 @@ SceneDialog::showSceneButtonClicked() } } +/** + * Display the scene show options dialog + */ +void +SceneDialog::showSceneOptionsButtonClicked() +{ + Scene* scene = getSelectedScene(); + if (scene != NULL) { + SceneShowOptionsDialog::Options options(s_useSceneForegroundBackgroundColorsFlag); + SceneShowOptionsDialog optionsDialog(options, + m_showSceneOptionsPushButton); + if (optionsDialog.exec() == QDialog::Accepted) { + const SceneShowOptionsDialog::Options optionsResult = optionsDialog.getOptions(); + s_useSceneForegroundBackgroundColorsFlag = optionsResult.isUseSceneColorsSelected(); + + if ( ! optionsResult.isUseSceneColorsSelected()) { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + } + } +} + +/** + * Display the scene show options dialog + */ +void +SceneDialog::createSceneOptionsButtonClicked() +{ + Scene* scene = getSelectedScene(); + if (scene != NULL) { + SceneCreateOptionsDialog::Options options(s_useSceneForegroundBackgroundColorsFlag); + SceneCreateOptionsDialog optionsDialog(options, + m_createSceneOptionsPushButton); + if (optionsDialog.exec() == QDialog::Accepted) { + const SceneCreateOptionsDialog::Options optionsResult = optionsDialog.getOptions(); + s_useSceneForegroundBackgroundColorsFlag = optionsResult.isUseSceneColorsSelected(); + + if ( ! optionsResult.isUseSceneColorsSelected()) { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + } + } +} + /** * Called when show image preview button is clicked. */ @@ -1701,6 +2166,7 @@ SceneDialog::showImagePreviewButtonClicked() AString descriptionText; const int32_t negativeIsUnlimitedNumberOfLines = -1; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), + -1, nameText, sceneIdText, descriptionText, @@ -1845,7 +2311,7 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, sceneAttributes->setSceneFileName(sceneFileName); sceneAttributes->setSceneName(scene->getName()); sceneAttributes->setWindowRestoreBehaviorInSceneDisplay(SceneAttributes::RESTORE_WINDOW_POSITION_RELATIVE_TO_FIRST_AND_USE_SIZES); - sceneAttributes->setUseSceneForegroundAndBackgroundColors(m_useSceneColorsCheckBox->isChecked()); + sceneAttributes->setUseSceneForegroundAndBackgroundColors(s_useSceneForegroundBackgroundColorsFlag); GuiManager::get()->restoreFromScene(sceneAttributes, guiManagerClass); @@ -1895,6 +2361,19 @@ SceneDialog::receiveEvent(Event* event) updateDialog(); uiEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_ADD) { + EventDataFileAdd* addEvent = + dynamic_cast(event); + CaretAssert(addEvent); + + /* + * Determine if a scene file was read + */ + CaretDataFile* dataFile = addEvent->getCaretDataFile(); + if (dataFile != NULL) { + lastSceneFileRead = dynamic_cast(dataFile); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_READ) { EventDataFileRead* readEvent = dynamic_cast(event); @@ -1937,6 +2416,8 @@ SceneDialog::receiveEvent(Event* event) highlightSceneAtIndex(0); m_sceneSelectionScrollArea->horizontalScrollBar()->setSliderPosition(0); } + + updateSceneFileModifiedStatusLabel(); } /** @@ -1992,6 +2473,45 @@ SceneDialog::displayNewSceneWarning() return true; } +/** + * Update the modified status label. + */ +void +SceneDialog::updateSceneFileModifiedStatusLabel() +{ + /* + * Modified icons in scene file selection combo box + */ + updateSceneFileComboBoxModifiedIcons(); + + /* + * Modified status of selected scene file + */ + AString statusText; + + /* + * Save button is enabled only if: + * (1) The scene file is modified + * (2) The filename is not the untitled file name + */ + bool saveButtonEnabledFlag = false; + SceneFile* sceneFile = getSelectedSceneFile(); + if (sceneFile != NULL) { + if (sceneFile->isModified()) { + if (sceneFile->exists()) { + saveButtonEnabledFlag = true; + } + statusText = "YES"; + } + else { + statusText = "NO"; + } + } + + m_sceneFileModifiedStatusLabel->setText(statusText); + m_saveSceneFilePushButton->setEnabled(saveButtonEnabledFlag); +} + /* ======================================================================== */ @@ -2099,6 +2619,7 @@ SceneClassInfoWidget::updateContent(Scene* scene, AString descriptionText; const int32_t numLinesToDisplay = 9; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), + sceneIndex, nameText, sceneIdText, descriptionText, @@ -2200,6 +2721,7 @@ SceneClassInfoWidget::limitToNumberOfLines(AString& textLines, */ void SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(const SceneInfo* sceneInfo, + const int32_t sceneIndex, AString& nameTextOut, AString& sceneIdTextOut, AString& descriptionTextOut, @@ -2212,7 +2734,18 @@ SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(const SceneInfo name = "NAME IS MISSING !!!"; } - nameTextOut = ("NAME: " + AString indexText; + const bool showSceneIndexFlag = false; + if (showSceneIndexFlag) { + if (sceneIndex >= 0) { + indexText = ("(" + AString::number(sceneIndex + 1) + ") "); + } + } + + nameTextOut = ("" + + indexText + + "NAME" + + ": " + name + ""); diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index e06c5b705..3c18e1bab 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -22,11 +22,14 @@ /*LICENSE_END*/ #include +#include #include "EventListenerInterface.h" +#include "GuiManager.h" #include "WuQDialogNonModal.h" class QCheckBox; +class QCloseEvent; class QComboBox; class QLabel; class QLineEdit; @@ -58,18 +61,29 @@ namespace caret { bool displayScene(SceneFile* sceneFile, Scene* scene); + void createDefaultSceneFile(); + static bool isInformUserAboutScenesOnExit(); + static bool checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, + QWidget* parent); + private: SceneDialog(const SceneDialog&); SceneDialog& operator=(const SceneDialog&); private slots: - void sceneFileSelected(); + void sceneFileSelected(int); void newSceneFileButtonClicked(); + void openSceneFileButtonClicked(); + + void saveSceneFileButtonClicked(); + + void saveAsSceneFileButtonClicked(); + void uploadSceneFileButtonClicked(); void zipSceneFileButtonClicked(); @@ -90,6 +104,10 @@ namespace caret { void showImagePreviewButtonClicked(); + void createSceneOptionsButtonClicked(); + + void showSceneOptionsButtonClicked(); + void validateContentOfCreateSceneDialog(WuQDataEntryDialog*); void sceneHighlighted(const int32_t sceneIndex); @@ -98,18 +116,15 @@ namespace caret { void useSceneColorsCheckBoxClicked(bool checked); - void editFileBalsaStudyIDButtonClicked(); - - void editBaseDirectoryPushButtonClicked(); - - void browseBaseDirectoryPushButtonClicked(); - void testScenesPushButtonClicked(); public: // ADD_NEW_METHODS_HERE + protected: + virtual void closeEvent(QCloseEvent* event); + private: SceneFile* getSelectedSceneFile(); @@ -117,17 +132,19 @@ namespace caret { void loadSceneFileComboBox(SceneFile* selectedSceneFileIn); + void updateSceneFileComboBoxModifiedIcons(); + void loadScenesIntoDialog(Scene* selectedSceneIn); + int32_t getNumberOfValidSceneInfoWidgets() const; + void addImageToScene(Scene* scene); void highlightSceneAtIndex(const int32_t sceneIndex); void highlightScene(const Scene* scene); - QWidget* createMainPage(); - - QWidget* createShowOptionsWidget(); + QWidget* createScenesWidget(); QWidget* createSceneFileWidget(); @@ -140,20 +157,43 @@ namespace caret { const bool showWaitCursor, AString& errorMessageOut); - bool checkForModifiedFiles(const bool creatingSceneFlag); - bool displayNewSceneWarning(); void enableSceneMoveUpAndDownButtons(); - void loadSceneFileMetaDataWidgets(); + void updateSceneFileModifiedStatusLabel(); QImage* getQImageFromSceneInfo(const SceneInfo* sceneInfo) const; + enum class ModifiedWarningType { + CLOSE_DIALOG_BUTTON, + FILE_COMBO_BOX_CHANGE_FILE, + NEW_FILE_BUTTON, + OPEN_FILE_BUTTON, + UPLOAD_FILE_BUTTON, + ZIP_FILE_BUTTON + }; + + bool warnIfSceneFileIsModified(const ModifiedWarningType warningType); + + bool saveSelectedSceneFile(); + + bool saveAsSelectedSceneFile(); + // ADD_NEW_MEMBERS_HERE + QLabel* m_sceneFileModifiedStatusLabel; + QComboBox* m_sceneFileSelectionComboBox; + QPushButton* m_newSceneFilePushButton; + + QPushButton* m_openSceneFilePushButton; + + QPushButton* m_saveSceneFilePushButton; + + QPushButton* m_saveAsSceneFilePushButton; + QPushButton* m_uploadSceneFilePushButton; QPushButton* m_zipSceneFilePushButton; @@ -176,7 +216,9 @@ namespace caret { QPushButton* m_showSceneImagePreviewPushButton; - QCheckBox* m_useSceneColorsCheckBox; + QPushButton* m_showSceneOptionsPushButton; + + QPushButton* m_createSceneOptionsPushButton; QScrollArea* m_sceneSelectionScrollArea; @@ -188,25 +230,21 @@ namespace caret { int32_t m_selectedSceneClassInfoIndex; - QPushButton* m_editBalsaStudyIDPushButton; - - QLineEdit* m_fileBalsaStudyIDLineEdit; - - QPushButton* m_browseBaseDirectoryPushButton; - - QPushButton* m_editBaseDirectoryPushButton; - - QLineEdit* m_fileBaseDirectoryLineEdit; - WuQWidgetObjectGroup* m_sceneFileButtonsGroup; AString m_testAllScenesDescription; + QIcon m_cautionIcon; + + bool m_cautionIconValid = false; + static const AString PREFERRED_IMAGE_FORMAT; static bool s_informUserAboutScenesOnExitFlag; static bool s_warnUserWhenCreatingSceneFlag; + + static bool s_useSceneForegroundBackgroundColorsFlag; }; class SceneClassInfoWidget : public QGroupBox { @@ -229,6 +267,7 @@ namespace caret { bool isValid() const; static void getFormattedTextForSceneNameAndDescription(const SceneInfo* sceneInfo, + const int32_t sceneIndex, AString& nameTextOut, AString& sceneIdTextOut, AString& descriptionTextOut, @@ -281,6 +320,8 @@ namespace caret { const AString SceneDialog::PREFERRED_IMAGE_FORMAT = "jpg"; bool SceneDialog::s_informUserAboutScenesOnExitFlag = true; bool SceneDialog::s_warnUserWhenCreatingSceneFlag = true; + bool SceneDialog::s_useSceneForegroundBackgroundColorsFlag = true; + #endif // __SCENE_DIALOG_DECLARE__ } // namespace diff --git a/src/GuiQt/ScenePreviewDialog.cxx b/src/GuiQt/ScenePreviewDialog.cxx index 8cdef6f5d..7353ae9d1 100644 --- a/src/GuiQt/ScenePreviewDialog.cxx +++ b/src/GuiQt/ScenePreviewDialog.cxx @@ -97,6 +97,7 @@ ScenePreviewDialog::ScenePreviewDialog(const Scene* scene, AString descriptionText; const int32_t negativeIsUnlimitedNumberOfLines = -1; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), + -1, nameText, sceneIdText, descriptionText, diff --git a/src/GuiQt/SceneShowOptionsDialog.cxx b/src/GuiQt/SceneShowOptionsDialog.cxx new file mode 100644 index 000000000..a148f5fd1 --- /dev/null +++ b/src/GuiQt/SceneShowOptionsDialog.cxx @@ -0,0 +1,134 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ +#include "SceneShowOptionsDialog.h" +#undef __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "WuQDataEntryDialog.h" + +using namespace caret; + + + +/** + * \class caret::SceneShowOptionsDialog + * \brief Dialog for setting show scene options + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param options + * Options displayed in dialog. + * @param parent + * Optional parent for dialog. + */ +SceneShowOptionsDialog::SceneShowOptionsDialog(const Options& options, + QWidget* parent) +: WuQDialogModal("Show Scene Options", + parent) +{ + /* + * Use colors contained in the scene for background and foreground + */ + const QString colorTip("Override foreground/background colors from preferences with those in scene"); + + m_useSceneColorsCheckBox = new QCheckBox("Use background and foreground colors from scene"); + m_useSceneColorsCheckBox->setToolTip(colorTip); + m_useSceneColorsCheckBox->setChecked(options.isUseSceneColorsSelected()); + + m_useSceneColorsToolButton = new QToolButton(); + m_useSceneColorsToolButton->setText("Info..."); + QObject::connect(m_useSceneColorsToolButton, &QToolButton::clicked, + this, &SceneShowOptionsDialog::useSceneColorsInfoButtonClicked); + + QHBoxLayout* useSceneColorsLayout = new QHBoxLayout(); + useSceneColorsLayout->addWidget(m_useSceneColorsCheckBox); + useSceneColorsLayout->addWidget(m_useSceneColorsToolButton); + useSceneColorsLayout->addStretch(); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addLayout(useSceneColorsLayout); + + + dialogWidget->setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); +} + +/** + * Destructor. + */ +SceneShowOptionsDialog::~SceneShowOptionsDialog() +{ +} + +/** + * @return Status of options in dialog. + */ +SceneShowOptionsDialog::Options +SceneShowOptionsDialog::getOptions() const +{ + return Options(m_useSceneColorsCheckBox->isChecked()); +} + +void +SceneShowOptionsDialog::useSceneColorsInfoButtonClicked() +{ + const QString infoText("Scenes created after 01 May 2016 contain the background and foreground from when the\n" + "scene was created. If this box is checked, background and foreground colors from the\n" + "scene will override the foreground and background colors in the Preferences Dialog.\n" + "The background and foreground colors will revert to those on the Preferences Dialog\n" + "when any of these events occur:\n" + " * This checkbox is unchecked\n" + " * A scene without background and foreground colors is loaded\n" + " * A Spec File and its data files are loaded\n" + " * File Menu->Close All Files is selected\n" + " * Any of the colors on the Preferences Dialog are changed\n" + " * The user quits wb_view"); + + WuQDataEntryDialog ded("Scene Colors Info", + m_useSceneColorsToolButton); + ded.hideCancelButton(); + QLabel* label = new QLabel(infoText); + ded.addWidget(label); + ded.exec(); +} + +/** + * Gets called if the user presses the OK button. + */ +void +SceneShowOptionsDialog::okButtonClicked() +{ + WuQDialogModal::okButtonClicked(); +} + diff --git a/src/GuiQt/SceneShowOptionsDialog.h b/src/GuiQt/SceneShowOptionsDialog.h new file mode 100644 index 000000000..05f66defe --- /dev/null +++ b/src/GuiQt/SceneShowOptionsDialog.h @@ -0,0 +1,94 @@ +#ifndef __SCENE_SHOW_OPTIONS_DIALOG_H__ +#define __SCENE_SHOW_OPTIONS_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogModal.h" + +class QCheckBox; +class QToolButton; + +namespace caret { + + class SceneShowOptionsDialog : public WuQDialogModal { + + Q_OBJECT + + public: + /** + * Options for display in dialog + */ + class Options { + public: + /** + * Constructor + * + * @param useSceneColorsSelected + * Status of use scene colors + */ + Options(const bool useSceneColorsSelected) + : m_useSceneColorsSelected(useSceneColorsSelected) { } + + /** @return Status of use scene colors */ + bool isUseSceneColorsSelected() const { return m_useSceneColorsSelected; } + + private: + bool m_useSceneColorsSelected = false; + }; + + + SceneShowOptionsDialog(const Options& options, + QWidget* parent = 0); + + virtual ~SceneShowOptionsDialog(); + + Options getOptions() const; + + // ADD_NEW_METHODS_HERE + + protected: + virtual void okButtonClicked(); + + void useSceneColorsInfoButtonClicked(); + + private: + SceneShowOptionsDialog(const SceneShowOptionsDialog&); + + SceneShowOptionsDialog& operator=(const SceneShowOptionsDialog&); + + QCheckBox* m_useSceneColorsCheckBox; + + QToolButton* m_useSceneColorsToolButton; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ + // +#endif // __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ + +} // namespace +#endif //__SCENE_SHOW_OPTIONS_DIALOG_H__ diff --git a/src/GuiQt/WuQDataEntryDialog.cxx b/src/GuiQt/WuQDataEntryDialog.cxx index e534a16bf..a1b557523 100644 --- a/src/GuiQt/WuQDataEntryDialog.cxx +++ b/src/GuiQt/WuQDataEntryDialog.cxx @@ -102,6 +102,16 @@ WuQDataEntryDialog::~WuQDataEntryDialog() { } +/** + * Hide the cancel button. + */ +void +WuQDataEntryDialog::hideCancelButton() +{ + setCancelButtonText(""); +} + + /** * Finish construction of the dialog. * @@ -287,7 +297,28 @@ WuQDataEntryDialog::addWidget(const QString& labelText, return widget; } - + +/** + * add widget that spans both the label and widget columns to next available row in the dialog. + */ +QWidget* +WuQDataEntryDialog::addWidget(QWidget* widget) +{ + // + // Keep pointer to widget + // + widgets.push_back(widget); + + // + // add widget to layout + // + const int rowNumber = widgetGridLayout->rowCount(); + widgetGridLayout->addWidget(widget, + rowNumber, 0, 1, 2); + + return widget; +} + /** * add a check box. */ diff --git a/src/GuiQt/WuQDataEntryDialog.h b/src/GuiQt/WuQDataEntryDialog.h index 0b1aaeb6c..30a14d2cd 100644 --- a/src/GuiQt/WuQDataEntryDialog.h +++ b/src/GuiQt/WuQDataEntryDialog.h @@ -64,6 +64,8 @@ namespace caret { const WuQDialog::ScrollAreaStatus scrollBarStatus, Qt::WindowFlags f = 0); + void hideCancelButton(); + // destructor ~WuQDataEntryDialog(); @@ -71,6 +73,8 @@ namespace caret { QWidget* addWidget(const QString& labelText, QWidget* widget); + QWidget* addWidget(QWidget* widget); + // add widgets to the next available row in the dialog void addWidgetsToNextRow(QWidget* leftColumnWidget, QWidget* rightColumnWidget); diff --git a/src/Resources/Gui/Caution/caution.png b/src/Resources/Gui/Caution/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..8d77405385039f4d7c41b29a33fb47f378b4326c GIT binary patch literal 476 zcmV<20VDp2P)Z2HcGh@WT%8!VWqw1Bq`4J~9JNKm?O_35sM1RYe8Xt_|C= z4U2IIiC79P90Tr|5sGjKTS^6DPzLXs5i=kIMl1!vd=8Rn34&7z!+j1)F9q?$4>U<$ z%c~y7s30^+T})Y1T47EnlX6vP4yd{04q3|##HkpKVy z%1J~)RCr#k(Z_BBF$_h~k?q92_m=Xg>D~7Kf13d=xFQExvsc8*nki=z=REW&x8s1s`5-&Ku(l1VE_n;LNK8Nco03n zgbtt}Dr5@Av6GO3n4TBVF-l~fd4`gLIC*-Aq3D4 zgg80qPr#iS*ureV!ZL$V_Qk??V_am-j)nc9E?-JzeYpnQ?LO=&4S#-vKlBF19z4i+ SKxWzi0000 ./About/hcp-logo.png +./Caution/caution.png ./Cursor/pen_eraser.png ./gui_resources.qrc ./LayersPanel/colorbar.png diff --git a/src/Scenes/SceneXmlElements.h b/src/Scenes/SceneXmlElements.h index 69326f928..a784d23a6 100644 --- a/src/Scenes/SceneXmlElements.h +++ b/src/Scenes/SceneXmlElements.h @@ -155,7 +155,11 @@ namespace caret { * XML Tag for BALSA Study ID element. */ static const AString SCENE_INFO_BALSA_STUDY_ID_TAG = "BalsaStudyID"; - + + /** + * XML Tag for BALSA Study ID element. + */ + static const AString SCENE_INFO_BALSA_STUDY_TITLE_TAG = "BalsaStudyTitle"; /** * XML Tag for Base Directory ID element. -- GitLab From a73605fe3a4f8cb01c1ec274eff1cc7b28a4941d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 23 May 2017 12:53:24 -0500 Subject: [PATCH 146/755] Partial revision of Scene and BALSA dialogs. --- src/Common/FileInformation.cxx | 85 ++- src/Common/FileInformation.h | 8 + src/Files/SceneFile.cxx | 82 +++ src/Files/SceneFile.h | 18 + src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx | 148 +++++ src/GuiQt/BalsaDatabaseStudyTitleDialog.h | 80 +++ .../BalsaDatabaseUploadSceneFileDialog.cxx | 559 +++++++++++++----- .../BalsaDatabaseUploadSceneFileDialog.h | 59 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/SceneDialog.cxx | 20 +- .../Gui/BalsaUploadDialog/lock-closed.png | Bin 0 -> 866 bytes .../Gui/BalsaUploadDialog/lock-open.png | Bin 0 -> 967 bytes .../{Caution => SceneFileDialog}/caution.png | Bin src/Resources/Gui/gui_resources.qrc | 5 +- 14 files changed, 885 insertions(+), 182 deletions(-) create mode 100644 src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx create mode 100644 src/GuiQt/BalsaDatabaseStudyTitleDialog.h create mode 100644 src/Resources/Gui/BalsaUploadDialog/lock-closed.png create mode 100644 src/Resources/Gui/BalsaUploadDialog/lock-open.png rename src/Resources/Gui/{Caution => SceneFileDialog}/caution.png (100%) diff --git a/src/Common/FileInformation.cxx b/src/Common/FileInformation.cxx index 397fe37e0..7f15a2ee8 100644 --- a/src/Common/FileInformation.cxx +++ b/src/Common/FileInformation.cxx @@ -565,12 +565,95 @@ FileInformation::assembleFileComponents(const AString& pathName, } name += fileNameWithoutExtension; if ( ! extensionWithoutDot.isEmpty()) { - name += ("." + extensionWithoutDot); + /* + * User might include dot at beginning of extension + */ + if (extensionWithoutDot.startsWith(".")) { + name += extensionWithoutDot; + } + else { + name += ("." + extensionWithoutDot); + } } return name; } +/** + * Assemble the file components into a file path and name. + * + * @param pathName + * Path for file (may be absolute, relative, or empty). + * @param fileNameWithExtension + * Name of file with extension. + */ +AString +FileInformation::assembleFileComponents(const AString& pathName, + const AString& fileNameWithExtension) +{ + AString name; + if ( ! pathName.isEmpty()) { + name += (pathName + "/"); + } + name += fileNameWithExtension; + + return name; +} + +/** + * Create the file path for a file with the given name in the + * computer system's temporary directory. + * + * @param fileName + * Name of the file with an extension. Any path in the name is ignored. + * @return + * File path in the temporary directory with the given file name. + */ +AString +FileInformation::createTemporaryFilePathName(const AString& fileName) +{ + AString nameOut; + + FileInformation fileInfo(fileName); + AString nameNoPath = fileInfo.getFileName(); + if (nameNoPath.isEmpty()) { + nameOut = FileInformation::assembleFileComponents(SystemUtilities::getTempDirectory(), "name_missing.tmp"); + } + else { + nameOut = FileInformation::assembleFileComponents(SystemUtilities::getTempDirectory(), nameNoPath); + } + + return nameOut; +} + +/** + * Replace the extension in a file name. + * + * @param fileName + * Name of file + * @param newExtension + * New extension that replaces the extension in fileName + * @return + * fileName with extension replaced with newExtension. + */ +AString +FileInformation::replaceExtension(const AString& fileName, + const AString& newExtension) +{ + AString thePath, theName, theExtension; + + FileInformation fileInfo(fileName); + fileInfo.getFileComponents(thePath, + theName, + theExtension); + + const AString nameOut = assembleFileComponents(thePath, + theName, + newExtension); + return nameOut; +} + + /** * Convert, if needed, the file information to a local, absolute path. * diff --git a/src/Common/FileInformation.h b/src/Common/FileInformation.h index 19cd55ff5..589995192 100644 --- a/src/Common/FileInformation.h +++ b/src/Common/FileInformation.h @@ -96,6 +96,14 @@ namespace caret { const AString& fileNameWithoutExtension, const AString& extensionWithoutDot); + static AString assembleFileComponents(const AString& pathName, + const AString& fileNameWithExtension); + + static AString createTemporaryFilePathName(const AString& fileNameWithExtension); + + static AString replaceExtension(const AString& fileName, + const AString& newExtension); + bool remove(); void getRemoteUrlUsernameAndPassword(AString& urlOut, diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 34f678b1e..3789c7f31 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -19,6 +19,7 @@ */ /*LICENSE_END*/ +#include #include #include @@ -775,3 +776,84 @@ SceneFile::addToDataFileContentInformation(DataFileContentInformation& dataFileI } } +/** + * @return Name of zip file + */ +AString +SceneFile::getZipFileName() const +{ + return m_zipFileName; +} + +/** + * Set Name of zip file + * + * @param zipFileName + * New value for Name of zip file + */ +void +SceneFile::setZipFileName(const AString& zipFileName) +{ + if (zipFileName != m_zipFileName) { + // not stored in Scene File setModified(); + m_zipFileName = zipFileName; + } +} + +/** + * @return Extract to directory name for zip file + */ +AString +SceneFile::getExtractToDirectoryName() const +{ + return m_extractToDirectoryName; +} + +/** + * Set Extract to directory name for zip file + * + * @param extractToDirectoryName + * New value for Extract to directory name for zip file + */ +void +SceneFile::setExtractToDirectoryName(const AString& extractToDirectoryName) +{ + if (extractToDirectoryName != m_extractToDirectoryName) { + // not stored in Scene File setModified(); + m_extractToDirectoryName = extractToDirectoryName; + } +} + +/** + * @return Default name for a ZIP file containing the scene file and its data files. + */ +AString +SceneFile::getDefaultZipFileName() const +{ + return FileInformation::replaceExtension(getFileName(), ".zip"); +} + +/** + * @return The default extract to directory name (directory containing the scene file, EXCLUDING THE PATH) + */ +AString +SceneFile::getDefaultExtractToDirectoryName() const +{ + AString directoryName; + + FileInformation fileInfo(getFileName()); + AString sceneFileDirectory = fileInfo.getAbsolutePath(); + if ( ! sceneFileDirectory.isEmpty()) { + QDir dir(sceneFileDirectory); + directoryName = dir.dirName(); + } + + if (directoryName.isEmpty()) { + QDir dir(SystemUtilities::systemCurrentDirectory()); + directoryName = dir.dirName(); + } + + return directoryName; +} + + diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 2993c8f30..0955a2767 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -101,6 +101,18 @@ namespace caret { Scene* releaseScene(const int32_t& index); + AString getZipFileName() const; + + void setZipFileName(const AString& zipFileName); + + AString getDefaultZipFileName() const; + + AString getExtractToDirectoryName() const; + + void setExtractToDirectoryName(const AString& extractToDirectoryName); + + AString getDefaultExtractToDirectoryName() const; + // ADD_NEW_METHODS_HERE /** Version of file */ @@ -134,6 +146,12 @@ namespace caret { /** the Base Directory */ AString m_baseDirectory; + /** the ZIP file name */ + AString m_zipFileName; + + /** The "extract to" directory name */ + AString m_extractToDirectoryName; + // ADD_NEW_MEMBERS_HERE /** Version of this SceneFile */ diff --git a/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx b/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx new file mode 100644 index 000000000..b10474773 --- /dev/null +++ b/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx @@ -0,0 +1,148 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ +#include "BalsaDatabaseStudyTitleDialog.h" +#undef __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ + +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "WuQMessageBox.h" + +using namespace caret; + + + +/** + * \class caret::BalsaDatabaseStudyTitleDialog + * \brief Dialog for selection and getting study titles with BALSA Database + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param balsaUsername + * Username for BALSA Database + * @param balsaPassword + * Password for BALSA Database + * @param parent + * Parent dialog + */ +BalsaDatabaseStudyTitleDialog::BalsaDatabaseStudyTitleDialog(const std::vector studyTitles, + const AString& balsaUsername, + const AString& balsaPassword, + QWidget* parent) +: WuQDialogModal("BALSA Study Title", + parent), +m_studyTitles(studyTitles), +m_balsaUsername(balsaUsername), +m_balsaPassword(balsaPassword) +{ + m_studyTitleListWidget = new QListWidget(); + m_studyTitleListWidget->setSelectionMode(QListWidget::SingleSelection); + + QPushButton* newStudyTitlePushButton = new QPushButton("Add New Study..."); + QObject::connect(newStudyTitlePushButton, &QPushButton::clicked, + this, &BalsaDatabaseStudyTitleDialog::newStudyButtonClicked); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addWidget(m_studyTitleListWidget, 100); + dialogLayout->addWidget(newStudyTitlePushButton, 0); + + setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); + + loadStudyTitleListWidget(); +} + +/** + * Destructor. + */ +BalsaDatabaseStudyTitleDialog::~BalsaDatabaseStudyTitleDialog() +{ +} + +/** + * Load the list widget for the study titles + */ +void +BalsaDatabaseStudyTitleDialog::loadStudyTitleListWidget() +{ + const int32_t selectedRow = m_studyTitleListWidget->currentRow(); + m_studyTitleListWidget->clear(); + + for (auto title : m_studyTitles) { + m_studyTitleListWidget->addItem(title); + } + + if (selectedRow >= 0) { + m_studyTitleListWidget->setCurrentRow(selectedRow); + } +} + +/** + * @return The selected study title or empty string if no selected title. + */ +AString +BalsaDatabaseStudyTitleDialog::getSelectedStudyTitle() const +{ + QListWidgetItem* item = m_studyTitleListWidget->currentItem(); + if (item != NULL) { + return item->text(); + } + return ""; +} + +/** + * Called when the new study button is clicked. + */ +void +BalsaDatabaseStudyTitleDialog::newStudyButtonClicked() +{ + const AString name = QInputDialog::getText(this, + "Study Title", + "New Study Title"); + if ( ! name.isNull()) { + m_studyTitles.push_back(name); + loadStudyTitleListWidget(); + m_studyTitleListWidget->setCurrentRow(m_studyTitleListWidget->count() - 1); + } +} + +/** + * Called when the OK button is clicked. + */ +void +BalsaDatabaseStudyTitleDialog::okButtonClicked() +{ + if ( m_studyTitleListWidget->currentItem() == NULL) { + WuQMessageBox::errorOk(this, "No Study Title is selected"); + return; + } + + WuQDialogModal::okButtonClicked(); +} + diff --git a/src/GuiQt/BalsaDatabaseStudyTitleDialog.h b/src/GuiQt/BalsaDatabaseStudyTitleDialog.h new file mode 100644 index 000000000..d647d0291 --- /dev/null +++ b/src/GuiQt/BalsaDatabaseStudyTitleDialog.h @@ -0,0 +1,80 @@ +#ifndef __BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ +#define __BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogModal.h" + +class QListWidget; + + +namespace caret { + + class BalsaDatabaseStudyTitleDialog : public WuQDialogModal { + + Q_OBJECT + + public: + BalsaDatabaseStudyTitleDialog(const std::vector studyTitles, + const AString& balsaUsername, + const AString& balsaPassword, + QWidget* parent); + + virtual ~BalsaDatabaseStudyTitleDialog(); + + virtual void okButtonClicked() override; + + AString getSelectedStudyTitle() const; + + // ADD_NEW_METHODS_HERE + + private slots: + void newStudyButtonClicked(); + + private: + BalsaDatabaseStudyTitleDialog(const BalsaDatabaseStudyTitleDialog&); + + BalsaDatabaseStudyTitleDialog& operator=(const BalsaDatabaseStudyTitleDialog&); + + void loadStudyTitleListWidget(); + + std::vector m_studyTitles; + + const AString& m_balsaUsername; + + const AString& m_balsaPassword; + + QListWidget* m_studyTitleListWidget; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ + // +#endif // __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ + +} // namespace +#endif //__BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 52ed80186..9b45535e0 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -29,8 +29,11 @@ #include #include #include +#include +#include #include "BalsaDatabaseManager.h" +#include "BalsaDatabaseStudyTitleDialog.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" @@ -81,7 +84,18 @@ m_sceneFile(sceneFile) defaultPassword = ""; #endif - QLabel* databaseNameLabel = new QLabel("DataBase: "); + /* + * Icons + */ + m_lockClosedIconValid = WuQtUtilities::loadIcon(":/BalsaUploadDialog/lock-closed.png", + m_lockClosedIcon); + m_lockOpenIconValid = WuQtUtilities::loadIcon(":/BalsaUploadDialog/lock-open.png", + m_lockOpenIcon); + + /* + * Database selection + */ + m_databaseLabel = new QLabel(""); m_databaseComboBox = new QComboBox(); m_databaseComboBox->setEditable(true); m_databaseComboBox->addItem("https://balsa.wustl.edu"); @@ -90,153 +104,213 @@ m_sceneFile(sceneFile) const int minimumLineEditWidth = 250; - QLabel* usernameLabel = new QLabel("Username: "); + /* + * Username + */ + m_usernameLabel = new QLabel(""); m_usernameLineEdit = new QLineEdit(); m_usernameLineEdit->setMinimumWidth(minimumLineEditWidth); m_usernameLineEdit->setText(defaultUserName); + m_usernameLineEdit->setValidator(createValidator(LabelName::LABEL_USERNAME)); + QObject::connect(m_usernameLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); - QLabel* passwordLabel = new QLabel("Password: "); + /* + * Password + */ + m_passwordLabel = new QLabel(""); m_passwordLineEdit = new QLineEdit(); m_passwordLineEdit->setMinimumWidth(minimumLineEditWidth); m_passwordLineEdit->setEchoMode(QLineEdit::Password); m_passwordLineEdit->setText(defaultPassword); + m_passwordLineEdit->setValidator(createValidator(LabelName::LABEL_PASSWORD)); + QObject::connect(m_passwordLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); + /* + * Forgot username label/link + */ QLabel* forgotUsernameLabel = new QLabel("" "Forgot Username" ""); QObject::connect(forgotUsernameLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); + /* + * Forgot password label/link + */ QLabel* forgotPasswordLabel = new QLabel("" "Forgot Password" ""); QObject::connect(forgotPasswordLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); + /* + * Register label/link + */ QLabel* registerLabel = new QLabel("" "Register" ""); QObject::connect(registerLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); - const QString zipFileName = FileInformation::assembleFileComponents(SystemUtilities::getTempDirectory(), - sceneFile->getFileNameNoPathNoExtension() , - "zip"); - - QLabel* zipFileNameLabel = new QLabel("Zip File Name: "); + /* + * Zip file name + */ + const AString defaultZipFileName = m_sceneFile->getDefaultZipFileName(); + m_zipFileNameLabel = new QLabel(""); m_zipFileNameLineEdit = new QLineEdit; - m_zipFileNameLineEdit->setText(zipFileName); + m_zipFileNameLineEdit->setText(defaultZipFileName); + m_zipFileNameLineEdit->setValidator(createValidator(LabelName::LABEL_ZIP_FILENAME)); + m_zipFileNameLineEdit->setToolTip("Name of ZIP file that user will download"); + QObject::connect(m_zipFileNameLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); - QLabel* extractDirectoryLabel = new QLabel("Extract to Directory: "); + /* + * Extract to directory + */ + const AString defaultExtractDirectoryName = m_sceneFile->getDefaultExtractToDirectoryName(); + m_extractDirectoryNameLabel = new QLabel(""); m_extractDirectoryNameLineEdit = new QLineEdit(); m_extractDirectoryNameLineEdit->setText("ExtDir"); - - const AString defaultDirName(SystemUtilities::getUserName() - + "_" - + m_sceneFile->getBalsaStudyID()); - m_extractDirectoryNameLineEdit->setText(defaultDirName); + m_extractDirectoryNameLineEdit->setValidator(createValidator(LabelName::LABEL_EXTRACT_DIRECTORY)); + m_extractDirectoryNameLineEdit->setToolTip("Directory that is created when user unzips the ZIP file"); + m_extractDirectoryNameLineEdit->setText(defaultExtractDirectoryName); + QObject::connect(m_extractDirectoryNameLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); /* * Scene BALSA Study ID */ - QLabel* studyIDLabel = new QLabel("BALSA Study ID: "); - m_fileBalsaStudyIDLineEdit = new QLineEdit(); - m_fileBalsaStudyIDLineEdit->setToolTip("Press Edit button to change Study ID for use with BALSA Database"); - m_fileBalsaStudyIDLineEdit->setReadOnly(true); + m_balsaStudyIDLabel = new QLabel(""); + m_balsaStudyIDLineEdit = new QLineEdit(); + m_balsaStudyIDLineEdit->setReadOnly(true); + m_balsaStudyIDLineEdit->setToolTip("The Study ID is available from the BALSA Database; click the Get button to get a Study ID"); + m_balsaStudyIDLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_ID)); + QObject::connect(m_balsaStudyIDLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); /* - * Edit BALSA Study ID button + * Get BALSA Study ID button */ - m_editBalsaStudyIDPushButton = new QPushButton("Edit..."); - m_editBalsaStudyIDPushButton->setToolTip("Edit the Scene File's BALSA Study ID"); - QObject::connect(m_editBalsaStudyIDPushButton, SIGNAL(clicked()), - this, SLOT(editFileBalsaStudyIDButtonClicked())); - m_getBalsaStudyIDPushButton = new QPushButton("Get..."); m_getBalsaStudyIDPushButton->setToolTip("Get the BALSA Study ID by sending Study Title to BALSA"); QObject::connect(m_getBalsaStudyIDPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked); + /* + * BALSA Study ID Lock button + */ + m_balsaStudyIDLockPushButton = new QPushButton("Lock"); + m_balsaStudyIDLockPushButton->setToolTip("Unlock to allow manual editing of the Study ID."); + QObject::connect(m_balsaStudyIDLockPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::balsaStudyIDLockPushButtonClicked); + if (m_lockClosedIconValid + && m_lockOpenIconValid) { + m_balsaStudyIDLockPushButton->setText(""); + } + /* * Scene BALSA Study Title */ - QLabel* studyTitleLabel = new QLabel("BALSA Study Title: "); + m_balsaStudyTitleLabel = new QLabel(""); m_balsaStudyTitleLineEdit = new QLineEdit(); - m_balsaStudyTitleLineEdit->setToolTip("Press Edit button to change Study Title for use with BALSA Database"); - m_balsaStudyTitleLineEdit->setReadOnly(true); + m_balsaStudyTitleLineEdit->setToolTip("Title for the study"); + m_balsaStudyTitleLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_TITLE)); + QObject::connect(m_balsaStudyTitleLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); - - /* - * Edit BALSA Title button + /** + * Select Study Push Button */ - m_editBalsaStudyTitlePushButton = new QPushButton("Edit..."); - m_editBalsaStudyTitlePushButton->setToolTip("Edit the Scene File's BALSA Study Title"); - QObject::connect(m_editBalsaStudyTitlePushButton, SIGNAL(clicked()), - this, SLOT(editFileBalsaStudyTitleButtonClicked())); + m_selectStudyTitlePushButton = new QPushButton("Select..."); + m_selectStudyTitlePushButton->setToolTip("Select from user's studies in BALSA Database"); + QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); /* * Base Directory */ - QLabel* baseDirectoryLabel = new QLabel("Base Directory: "); + m_baseDirectoryLabel = new QLabel(""); m_baseDirectoryLineEdit = new QLineEdit(); - m_baseDirectoryLineEdit->setToolTip("Press Browse or Edit button to change base directory"); - m_baseDirectoryLineEdit->setReadOnly(true); - m_editBaseDirectoryPushButton = new QPushButton("Edit..."); - m_editBaseDirectoryPushButton->setToolTip("Edit the base directory in a text edit"); - QObject::connect(m_editBaseDirectoryPushButton, SIGNAL(clicked()), - this, SLOT(editBaseDirectoryPushButtonClicked())); + m_baseDirectoryLineEdit->setToolTip("Directory that contains all data files"); + m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::LABEL_BASE_DIRECTORY)); + QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); + + /* + * Browse for base directory + */ m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); QObject::connect(m_browseBaseDirectoryPushButton, SIGNAL(clicked()), this, SLOT(browseBaseDirectoryPushButtonClicked())); - - - + int columnCounter = 0; + const int COLUMN_LABEL = columnCounter++; + const int COLUMN_DATA_WIDGET = columnCounter++; + const int COLUMN_BUTTON_ONE = columnCounter++; + const int COLUMN_BUTTON_TWO = columnCounter++; QWidget* dialogWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(dialogWidget); - gridLayout->setColumnStretch(0, 0); - gridLayout->setColumnStretch(1, 100); + gridLayout->setSpacing(2); + gridLayout->setColumnStretch(COLUMN_LABEL, 0); + gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); + gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); + gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; - gridLayout->addWidget(databaseNameLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_databaseComboBox, row, 1); - gridLayout->addWidget(registerLabel, row, 2); + gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(usernameLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_usernameLineEdit, row, 1); - gridLayout->addWidget(forgotUsernameLabel, row, 2); + gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(passwordLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_passwordLineEdit, row, 1); - gridLayout->addWidget(forgotPasswordLabel, row, 2); + gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(zipFileNameLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_zipFileNameLineEdit, row, 1, 1, 3); + gridLayout->addWidget(m_zipFileNameLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_zipFileNameLineEdit, row, COLUMN_DATA_WIDGET); row++; - gridLayout->addWidget(extractDirectoryLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1, 1, 3); + gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); row++; - gridLayout->addWidget(baseDirectoryLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_baseDirectoryLineEdit, row, 1); - gridLayout->addWidget(m_editBaseDirectoryPushButton, row, 2); - gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, 3); + gridLayout->addWidget(m_baseDirectoryLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_baseDirectoryLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(studyTitleLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, 1); - gridLayout->addWidget(m_editBalsaStudyTitlePushButton, row, 2); + gridLayout->addWidget(m_balsaStudyTitleLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(m_selectStudyTitlePushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(studyIDLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_fileBalsaStudyIDLineEdit, row, 1); - gridLayout->addWidget(m_editBalsaStudyIDPushButton, row, 2); - gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, 3); + gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(m_balsaStudyIDLockPushButton, row, COLUMN_BUTTON_ONE); + gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, COLUMN_BUTTON_TWO); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); - loadSceneFileMetaDataWidgets(); + m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); + m_baseDirectoryLineEdit->setText(m_sceneFile->getBaseDirectory()); + m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); + m_extractDirectoryNameLineEdit->setText(m_sceneFile->getExtractToDirectoryName()); + m_zipFileNameLineEdit->setText(m_sceneFile->getZipFileName()); + + if (m_extractDirectoryNameLineEdit->text().trimmed().isEmpty()) { + m_extractDirectoryNameLineEdit->setText(m_sceneFile->getDefaultExtractToDirectoryName()); + } + if (m_zipFileNameLineEdit->text().trimmed().isEmpty()) { + m_zipFileNameLineEdit->setText(m_sceneFile->getDefaultZipFileName()); + } + + updateBalsaStudyIDLockButtonIcon(); + validateData(); } /** @@ -284,15 +358,59 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() { CaretAssert(m_sceneFile); - if (m_sceneFile->getBalsaStudyID().trimmed().isEmpty()) { - const QString msg("The BALSA Study ID is missing. You must either: (1) Go to " - "BALSA Database and get a BALSA Study ID or " - "(2) Enter a Study Title and press the Get button to request a BALSA Study ID " - "using the Study Title"); + m_sceneFile->setBalsaStudyID(m_balsaStudyIDLineEdit->text().trimmed()); + m_sceneFile->setBalsaStudyTitle(m_balsaStudyTitleLineEdit->text().trimmed()); + m_sceneFile->setBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); + m_sceneFile->setZipFileName(m_zipFileNameLineEdit->text().trimmed()); + m_sceneFile->setExtractToDirectoryName(m_extractDirectoryNameLineEdit->text().trimmed()); + + AString msg; + if ( ! m_usernameLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Username is missing. If you do not have an account, press the \"Register\" link. " + "If you have forgotten your username, press the \"Forgot Username\" link.

"); + } + if ( ! m_passwordLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Password is missing. If you do not remember your password, press the \"Forgot Password\" link.

"); + } + if ( ! m_zipFileNameLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Zip Filename is invalid. Must end in \".zip\".

"); + } + if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Extract to Directory is invalid.

"); + } + if ( ! m_baseDirectoryLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Base Directory is invalid.

"); + } + if ( ! m_balsaStudyTitleLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Study Title is invalid.

"); + } + if ( ! m_balsaStudyIDLineEdit->hasAcceptableInput()) { + msg.appendWithNewLine("Study ID is invalid. To get a Study ID, press the \"Get\" button which " + "sends the Study Title to the Database and returns a Study ID. You may " + "also go to https://balsa.wustl.edu to get a Study ID

"); + } + + if ( ! msg.isEmpty()) { + msg.insert(0, ""); + msg.append(""); WuQMessageBox::errorOk(this, msg); return; } + const AString username = m_usernameLineEdit->text().trimmed(); + const AString password = m_passwordLineEdit->text().trimmed(); + const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); + const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); + +// if (m_sceneFile->getBalsaStudyID().trimmed().isEmpty()) { +// const QString msg("The BALSA Study ID is missing. You must either: (1) Go to " +// "BALSA Database and get a BALSA Study ID or " +// "(2) Enter a Study Title and press the Get button to request a BALSA Study ID " +// "using the Study Title"); +// WuQMessageBox::errorOk(this, msg); +// return; +// } + if (m_sceneFile->isModified()) { const QString msg("The scene file is modified and must be saved before continuing. Would you like " "to save the scene file using its current name and continue?"); @@ -320,11 +438,6 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() progressDialog.setCancelButton((QPushButton*)0); // no cancel button - const AString username = m_usernameLineEdit->text().trimmed(); - const AString password = m_passwordLineEdit->text().trimmed(); - const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); - const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); - AString errorMessage; CaretPointer balsaDatabaseManager(new BalsaDatabaseManager()); const bool successFlag = balsaDatabaseManager->uploadZippedSceneFile(getDataBaseURL(), @@ -352,40 +465,59 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() } /** - * Load the Scene File BALSA Study ID Line Edit + * Select a Study Title from those user has in BALSA Database */ void -BalsaDatabaseUploadSceneFileDialog::loadSceneFileMetaDataWidgets() +BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() { - CaretAssert(m_sceneFile); + const AString username = m_usernameLineEdit->text().trimmed(); + const AString password = m_passwordLineEdit->text().trimmed(); - m_fileBalsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); - m_baseDirectoryLineEdit->setText(m_sceneFile->getBaseDirectory()); - m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); + std::vector studyTitles; + + BalsaDatabaseStudyTitleDialog dialog(studyTitles, + username, + password, + this); + if (dialog.exec() == BalsaDatabaseStudyTitleDialog::Accepted) { + m_balsaStudyTitleLineEdit->setText(dialog.getSelectedStudyTitle().trimmed()); + validateData(); + } } /** - * Called when Edit Study ID button is clicked. + * Update the Icon in the BALSA Study ID Lock Button */ void -BalsaDatabaseUploadSceneFileDialog::editFileBalsaStudyIDButtonClicked() +BalsaDatabaseUploadSceneFileDialog::updateBalsaStudyIDLockButtonIcon() { - CaretAssert(m_sceneFile); - WuQDataEntryDialog ded("Edit BALSA Database Info", - m_editBalsaStudyIDPushButton, - WuQDialog::SCROLL_AREA_AS_NEEDED); - - QLineEdit* lineEdit = ded.addLineEditWidget("BALSA Study ID"); - lineEdit->setText(m_sceneFile->getBalsaStudyID()); - lineEdit->setMinimumWidth(200); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - const AString idText = lineEdit->text().trimmed(); - m_sceneFile->setBalsaStudyID(idText); - loadSceneFileMetaDataWidgets(); + if (m_lockClosedIconValid + && m_lockOpenIconValid) { + if (m_balsaStudyIDLineEdit->isReadOnly()) { + m_balsaStudyIDLockPushButton->setIcon(m_lockClosedIcon); + } + else { + m_balsaStudyIDLockPushButton->setIcon(m_lockOpenIcon); + } } } +/** + * Called when BALSA Study ID Lock Button is clicked + */ +void +BalsaDatabaseUploadSceneFileDialog::balsaStudyIDLockPushButtonClicked() +{ + /* + * Toggle the 'read only' status of the Study ID's Line Edit + */ + m_balsaStudyIDLineEdit->setReadOnly( ! m_balsaStudyIDLineEdit->isReadOnly()); + + updateBalsaStudyIDLockButtonIcon(); +} + + /** * Called when get BALSA study ID push button is clicked. */ @@ -395,7 +527,7 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() const AString title = m_balsaStudyTitleLineEdit->text().trimmed(); if (title.isEmpty()) { WuQMessageBox::errorOk(m_getBalsaStudyIDPushButton, - "The BALSA Study Title is required to get a BALSA Study ID"); + "The Study Title is required to get a Study ID"); return; } @@ -420,8 +552,9 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() cursor.restoreCursor(); if (successFlag) { - m_sceneFile->setBalsaStudyID(studyID); - loadSceneFileMetaDataWidgets(); + //m_sceneFile->setBalsaStudyID(studyID); + m_balsaStudyIDLineEdit->setText(studyID); + validateData(); } else { WuQMessageBox::errorOk(this, @@ -429,49 +562,6 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() } } -/** - * Called when Edit Study Title button is clicked. - */ -void -BalsaDatabaseUploadSceneFileDialog::editFileBalsaStudyTitleButtonClicked() -{ - CaretAssert(m_sceneFile); - - WuQDataEntryDialog ded("Edit BALSA Database Info", - m_editBalsaStudyTitlePushButton, - WuQDialog::SCROLL_AREA_AS_NEEDED); - - QLineEdit* lineEdit = ded.addLineEditWidget("BALSA Study Title"); - lineEdit->setText(m_sceneFile->getBalsaStudyTitle()); - lineEdit->setMinimumWidth(200); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - const AString titleText = lineEdit->text().trimmed(); - m_sceneFile->setBalsaStudyTitle(titleText); - loadSceneFileMetaDataWidgets(); - } -} -/** - * Called when upload scene file is selected. - */ -void -BalsaDatabaseUploadSceneFileDialog::editBaseDirectoryPushButtonClicked() -{ - CaretAssert(m_sceneFile); - - WuQDataEntryDialog ded("Edit Base Directory", - m_editBaseDirectoryPushButton, - WuQDialog::SCROLL_AREA_AS_NEEDED); - - QLineEdit* lineEdit = ded.addLineEditWidget("Base Directory"); - lineEdit->setText(m_sceneFile->getBaseDirectory()); - lineEdit->setMinimumWidth(500); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - const AString idText = lineEdit->text().trimmed(); - m_sceneFile->setBaseDirectory(idText); - loadSceneFileMetaDataWidgets(); - } -} - /** * Called when upload scene file is selected. */ @@ -484,7 +574,7 @@ BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() * Let user choose directory path */ QString directoryName; - FileInformation fileInfo(m_sceneFile->getBaseDirectory()); + FileInformation fileInfo(m_baseDirectoryLineEdit->text().trimmed()); if (fileInfo.exists()) { if (fileInfo.isDirectory()) { directoryName = fileInfo.getAbsoluteFilePath(); @@ -503,7 +593,174 @@ BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() /* * Set name of new scene file and add to brain */ - m_sceneFile->setBaseDirectory(newDirectoryName); - loadSceneFileMetaDataWidgets(); + //m_sceneFile->setBaseDirectory(newDirectoryName); + m_baseDirectoryLineEdit->setText(newDirectoryName); + validateData(); +} + +/** + * Create a regular expression validatory for the give label/data. + * + * @param labelName + * 'Name' of label. + */ +QRegularExpressionValidator* +BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) +{ + QRegularExpression regEx; + + switch (labelName) { + case LabelName::LABEL_BASE_DIRECTORY: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_DATABASE: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_EXTRACT_DIRECTORY: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_PASSWORD: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_STUDY_ID: + { + const AString lowerCaseNoVowels("bcdfghjklmnpqrstvwxyz"); + const AString upperCaseNoVowels(lowerCaseNoVowels.toUpper()); + regEx.setPattern("[0-9" + lowerCaseNoVowels + upperCaseNoVowels + "]+"); + } + break; + case LabelName::LABEL_STUDY_TITLE: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_USERNAME: + regEx.setPattern(".+"); + break; + case LabelName::LABEL_ZIP_FILENAME: + regEx.setPattern(".+\\.zip"); + break; + } + CaretAssert(regEx.isValid()); + + QRegularExpressionValidator* validator = new QRegularExpressionValidator(regEx, + this); + return validator; } +/** + * Called by validators. + */ +void +BalsaDatabaseUploadSceneFileDialog::validateData() +{ + updateAllLabels(); + m_getBalsaStudyIDPushButton->setEnabled(m_balsaStudyTitleLineEdit->hasAcceptableInput()); +} + +/** + * Update all of the labels. + */ +void +BalsaDatabaseUploadSceneFileDialog::updateAllLabels() +{ + setLabelText(LabelName::LABEL_BASE_DIRECTORY); + setLabelText(LabelName::LABEL_DATABASE); + setLabelText(LabelName::LABEL_EXTRACT_DIRECTORY); + setLabelText(LabelName::LABEL_PASSWORD); + setLabelText(LabelName::LABEL_STUDY_ID); + setLabelText(LabelName::LABEL_STUDY_TITLE); + setLabelText(LabelName::LABEL_USERNAME); + setLabelText(LabelName::LABEL_ZIP_FILENAME); +} + + +/** + * Set the label's text. + * + * @param label + * The label + * @param labelName + * 'Name' of the label + */ +void +BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) +{ + QLabel* label = NULL; + AString labelText; + bool validFlag = false; + switch (labelName) { + case LabelName::LABEL_BASE_DIRECTORY: + label = m_baseDirectoryLabel; + labelText = "Base Directory"; + validFlag = m_baseDirectoryLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_DATABASE: + label = m_databaseLabel; + labelText = "Database"; + validFlag = true; + break; + case LabelName::LABEL_EXTRACT_DIRECTORY: + label = m_extractDirectoryNameLabel; + labelText = "Extract to Directory"; + validFlag = m_extractDirectoryNameLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_PASSWORD: + label = m_passwordLabel; + labelText = "Password"; + validFlag = m_passwordLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_STUDY_ID: + label = m_balsaStudyIDLabel; + labelText = "Study ID"; + validFlag = m_balsaStudyIDLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_STUDY_TITLE: + label = m_balsaStudyTitleLabel; + labelText = "Study Title"; + validFlag = m_balsaStudyTitleLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_USERNAME: + label = m_usernameLabel; + labelText = "Username"; + validFlag = m_usernameLineEdit->hasAcceptableInput(); + break; + case LabelName::LABEL_ZIP_FILENAME: + label = m_zipFileNameLabel; + labelText = "Zip Filename"; + validFlag = m_zipFileNameLineEdit->hasAcceptableInput(); + break; + } + + const bool textRedIfInvalid = true; + + AString coloredText; + if (validFlag) { + if (textRedIfInvalid) { + coloredText = (labelText + + ": "); + } + else { + coloredText = (" " + + labelText + + ": "); + } + } + else { + if (textRedIfInvalid) { + coloredText = ("" + + labelText + + ": "); + } + else { + coloredText = ("" + + labelText + + "*" + ": "); + } + } + + CaretAssert(label); + label->setText(coloredText); + +} + + diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 0a1261176..b554c5b5f 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include "WuQDialogModal.h" @@ -28,8 +29,7 @@ class QComboBox; class QLabel; class QLineEdit; class QPushButton; - - +class QRegularExpressionValidator; namespace caret { @@ -51,20 +51,31 @@ namespace caret { private slots: void labelHtmlLinkClicked(const QString&); - void editFileBalsaStudyIDButtonClicked(); - - void editFileBalsaStudyTitleButtonClicked(); - - void editBaseDirectoryPushButtonClicked(); - void browseBaseDirectoryPushButtonClicked(); void getBalsaStudyIDPushButtonClicked(); + void balsaStudyIDLockPushButtonClicked(); + + void validateData(); + + void selectStudyTitleButtonClicked(); + protected: virtual void okButtonClicked(); private: + enum class LabelName { + LABEL_BASE_DIRECTORY, + LABEL_DATABASE, + LABEL_EXTRACT_DIRECTORY, + LABEL_PASSWORD, + LABEL_STUDY_ID, + LABEL_STUDY_TITLE, + LABEL_USERNAME, + LABEL_ZIP_FILENAME + }; + BalsaDatabaseUploadSceneFileDialog(const BalsaDatabaseUploadSceneFileDialog&); BalsaDatabaseUploadSceneFileDialog& operator=(const BalsaDatabaseUploadSceneFileDialog&); @@ -73,34 +84,52 @@ namespace caret { AString getDataBaseURL() const; + void updateBalsaStudyIDLockButtonIcon(); + + QRegularExpressionValidator* createValidator(const LabelName labelName); + + void updateAllLabels(); + + void setLabelText(const LabelName labelName); + SceneFile* m_sceneFile; + QLabel* m_databaseLabel; QComboBox* m_databaseComboBox; + QLabel* m_usernameLabel; QLineEdit* m_usernameLineEdit; + QLabel* m_passwordLabel; QLineEdit* m_passwordLineEdit; + QLabel* m_zipFileNameLabel; QLineEdit* m_zipFileNameLineEdit; + QLabel* m_extractDirectoryNameLabel; QLineEdit* m_extractDirectoryNameLineEdit; - QPushButton* m_editBalsaStudyIDPushButton; - QPushButton* m_getBalsaStudyIDPushButton; + QPushButton* m_balsaStudyIDLockPushButton; - QLineEdit* m_fileBalsaStudyIDLineEdit; + QLabel* m_balsaStudyIDLabel; + QLineEdit* m_balsaStudyIDLineEdit; + QLabel* m_balsaStudyTitleLabel; QLineEdit* m_balsaStudyTitleLineEdit; - - QPushButton* m_editBalsaStudyTitlePushButton; + QPushButton* m_selectStudyTitlePushButton; QPushButton* m_browseBaseDirectoryPushButton; - QPushButton* m_editBaseDirectoryPushButton; - + QLabel* m_baseDirectoryLabel; QLineEdit* m_baseDirectoryLineEdit; + QIcon m_lockClosedIcon; + bool m_lockClosedIconValid = false; + + QIcon m_lockOpenIcon; + bool m_lockOpenIconValid = false; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index cdec49e29..4f599e111 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -60,6 +60,7 @@ ELSE() AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationWidthHeightWidget.h + BalsaDatabaseStudyTitleDialog.h BalsaDatabaseUploadSceneFileDialog.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h @@ -236,6 +237,7 @@ AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationWidgetParentEnum.h AnnotationWidthHeightWidget.h +BalsaDatabaseStudyTitleDialog.h BalsaDatabaseManager.h BalsaDatabaseUploadSceneFileDialog.h BorderEditingSelectionDialog.h @@ -440,6 +442,7 @@ AnnotationTextOrientationWidget.cxx AnnotationWidgetParentEnum.cxx AnnotationWidthHeightWidget.cxx BalsaDatabaseManager.cxx +BalsaDatabaseStudyTitleDialog.cxx BalsaDatabaseUploadSceneFileDialog.cxx BorderEditingSelectionDialog.cxx BorderFileSplitDialog.cxx diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 33e6d03e6..f29517997 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -126,17 +126,11 @@ SceneDialog::SceneDialog(QWidget* parent) /* - * Construction Tool Button + * Icons */ - m_cautionIconValid = WuQtUtilities::loadIcon(":/Caution/caution.png", + m_cautionIconValid = WuQtUtilities::loadIcon(":/SceneFileDialog/caution.png", m_cautionIcon); -// this->constructionAction = WuQtUtilities::createAction("M", -// "Add/Move/Remove Overlays", -// this); -// if (constructionIconValid) { -// this->constructionAction->setIcon(constructionIcon); -// } /* * Set the dialog's widget */ @@ -716,7 +710,7 @@ SceneDialog::saveSelectedSceneFile() return false; } - updateSceneFileModifiedStatusLabel(); + loadSceneFileComboBox(sceneFile); return true; } @@ -756,7 +750,7 @@ SceneDialog::saveAsSelectedSceneFile() return false; } - updateSceneFileModifiedStatusLabel(); + loadSceneFileComboBox(sceneFile); return true; } @@ -1595,7 +1589,7 @@ SceneDialog::createScenesWidget() /* * Scene controls */ - QLabel* sceneLabel = new QLabel("Scenes"); + QLabel* sceneLabel = new QLabel(" Scenes"); /* * Add new scene button @@ -1750,10 +1744,10 @@ SceneDialog::createScenesWidget() sceneButtonLayout->addWidget(showGroupBox); sceneButtonLayout->addSpacing(20); sceneButtonLayout->addWidget(createGroupBox); - sceneButtonLayout->addStretch(); - sceneButtonLayout->addWidget(testGroupBox); sceneButtonLayout->addSpacing(20); sceneButtonLayout->addWidget(organizeGroupBox); + sceneButtonLayout->addStretch(); + sceneButtonLayout->addWidget(testGroupBox); /* * Widget and layout containing the scene class info. diff --git a/src/Resources/Gui/BalsaUploadDialog/lock-closed.png b/src/Resources/Gui/BalsaUploadDialog/lock-closed.png new file mode 100644 index 0000000000000000000000000000000000000000..2b86ab2bd5b597ffbce6f2b4c3777f616aa22e45 GIT binary patch literal 866 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}oCO|{#S9GG z!XV7ZFl&wkP(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1aVPZ!6K2+p@t zV!fCRMOv++Hrl=95@~(JS7P`|O5~vV-R2*k-zj}Ln0h1hN5GcQD1j>_nRpI}3 zd&PqOmm5yqm?3W#>muIVXf!jSfb*M!_?r_m{d75CDqp|R-D|pJIVa{C+)otdXCJTt19^Gsqy1wnOf!l9!Id- zK28_;;ny$PKEW?jaQe_DOI4Y4b8S1;b)cazsY oN9DW@)B6`O%on5GUb6gSI5=zRnp{(sI8eg(boFyt=akR{0BsjfQ2+n{ literal 0 HcmV?d00001 diff --git a/src/Resources/Gui/BalsaUploadDialog/lock-open.png b/src/Resources/Gui/BalsaUploadDialog/lock-open.png new file mode 100644 index 0000000000000000000000000000000000000000..6442f8f7e989ba1c4f469cc7caf982984aef2c9c GIT binary patch literal 967 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W7>k44ofy`glX(f`a29w(7Bet# z3xhBt!>l_)Q7iwV z%v7MwAoJ}EZNMr~#Gv-r=z}araty?$U{Rn~?YM08;lXCd<#R|ql7WGV-P6S}#Dn*2 z*zP{YK#6;iLPvMCUw9-d;+3yZV$@#T zoNmM2W&VYKKF@vs|KI7IEk%3d?$;IXd3{uWy7&6)r&EkBW?XsxIkD~T`|pjfGoR&z zI2^06={x>de$7M=m9)(_#V_7j&tzpZ%SY{GO3~J+kDEUK{@Z*|L8$WsM~n=k-*Vxz zwgMa>tFOK+sj`tX4A&C%n7k_B_|F=%>Gqr2owwgs6$+5=bz|#%Sm2SI(9W~^lE1El z)>I|NtgTX)8A}D6tmdW(u`Cc{n5+8l1?Ob0IRZ%=B_=B{Z1pYM88c&}_v^2>(l+1C z7ms@XwW?9OYt!Al_nb^FyV+f2*@9(v+|5%Ln&N3EKXZTV7I&F5MR7t6C2iN`H)~4& zh+=JZI{2_)#j31`-xJT@4pzKcWHq;C^X<1wQfwcpRxjYs*udZJyfK2O)k(x%^O7K6 zyZ2I|IO7V>D3-5fyM3?vO8%_bcQM0*N#Xn7x_qzclkVnyPue(v#ld{VVPQ7EBk}p0 z6kb>D-4~{U?~#}mbtP--g4;P}m9JRp_c8rYcKoQhA*9iw za97q#k+aW>wT>9;Z0%6@`dEKK>7(2wpP6j)xE@ThJ@K^2=efJXqw3$g4-_kiZ@v67 o$4px8x!m^(o0~b?V)T+<3VRze<^JQ3eGAH6p00i_>zopr0G#%9bpQYW literal 0 HcmV?d00001 diff --git a/src/Resources/Gui/Caution/caution.png b/src/Resources/Gui/SceneFileDialog/caution.png similarity index 100% rename from src/Resources/Gui/Caution/caution.png rename to src/Resources/Gui/SceneFileDialog/caution.png diff --git a/src/Resources/Gui/gui_resources.qrc b/src/Resources/Gui/gui_resources.qrc index 6997441b2..c9a45154b 100644 --- a/src/Resources/Gui/gui_resources.qrc +++ b/src/Resources/Gui/gui_resources.qrc @@ -1,13 +1,14 @@ ./About/hcp-logo.png -./Caution/caution.png +./BalsaUploadDialog/lock-closed.png +./BalsaUploadDialog/lock-open.png ./Cursor/pen_eraser.png -./gui_resources.qrc ./LayersPanel/colorbar.png ./LayersPanel/construction.png ./LayersPanel/wrench.png ./PaletteSettings/chain_link_icon.png +./SceneFileDialog/caution.png ./SpecFileDialog/delete_icon.png ./SpecFileDialog/load_icon.png ./SpecFileDialog/options_icon.png -- GitLab From add1a1f57d63ef68a5f59fd9b475d943a94ccd54 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 May 2017 12:47:31 -0500 Subject: [PATCH 147/755] Updates to both Scene and BALSA dialogs. --- src/Files/SceneFile.cxx | 58 ++-- src/Files/SceneFile.h | 19 +- src/Files/SceneFileSaxReader.cxx | 19 +- src/Files/SceneFileSaxReader.h | 4 +- src/GuiQt/BalsaDatabaseManager.cxx | 9 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 295 ++++++++++++++---- .../BalsaDatabaseUploadSceneFileDialog.h | 22 +- src/GuiQt/ProgressReportingDialog.cxx | 19 ++ src/GuiQt/ProgressReportingDialog.h | 2 + src/GuiQt/SceneDialog.cxx | 36 ++- src/Scenes/SceneXmlElements.h | 8 +- 11 files changed, 365 insertions(+), 126 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 3789c7f31..f7dd23d9e 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -65,7 +65,8 @@ SceneFile::SceneFile() { m_balsaStudyID = ""; m_balsaStudyTitle = ""; - m_baseDirectory = ""; + m_balsaBaseDirectory = ""; + m_balsaExtractToDirectoryName = ""; m_metadata = new GiftiMetaData(); } @@ -96,7 +97,8 @@ SceneFile::clear() m_balsaStudyID = ""; m_balsaStudyTitle = ""; - m_baseDirectory = ""; + m_balsaBaseDirectory = ""; + m_balsaExtractToDirectoryName = ""; for (std::vector::iterator iter = m_scenes.begin(); iter != m_scenes.end(); @@ -520,9 +522,9 @@ SceneFile::setBalsaStudyTitle(const AString& balsaStudyTitle) * @return The Base Directory */ AString -SceneFile::getBaseDirectory() const +SceneFile::getBalsaBaseDirectory() const { - return m_baseDirectory; + return m_balsaBaseDirectory; } /** @@ -532,10 +534,10 @@ SceneFile::getBaseDirectory() const * New value for Base Directory. */ void -SceneFile::setBaseDirectory(const AString& baseDirectory) +SceneFile::setBalsaBaseDirectory(const AString& balsaBaseDirectory) { - if (baseDirectory != m_baseDirectory) { - m_baseDirectory = baseDirectory; + if (balsaBaseDirectory != m_balsaBaseDirectory) { + m_balsaBaseDirectory = balsaBaseDirectory; setModified(); } } @@ -675,8 +677,10 @@ SceneFile::writeFile(const AString& filename) getBalsaStudyID()); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG, getBalsaStudyTitle()); - xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BASE_DIRECTORY_TAG, - getBaseDirectory()); + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, + getBalsaBaseDirectory()); + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG, + getBalsaExtractToDirectoryName()); for (int32_t i = 0; i < numScenes; i++) { m_scenes[i]->getSceneInfo()->writeSceneInfo(xmlWriter, @@ -776,37 +780,13 @@ SceneFile::addToDataFileContentInformation(DataFileContentInformation& dataFileI } } -/** - * @return Name of zip file - */ -AString -SceneFile::getZipFileName() const -{ - return m_zipFileName; -} - -/** - * Set Name of zip file - * - * @param zipFileName - * New value for Name of zip file - */ -void -SceneFile::setZipFileName(const AString& zipFileName) -{ - if (zipFileName != m_zipFileName) { - // not stored in Scene File setModified(); - m_zipFileName = zipFileName; - } -} - /** * @return Extract to directory name for zip file */ AString -SceneFile::getExtractToDirectoryName() const +SceneFile::getBalsaExtractToDirectoryName() const { - return m_extractToDirectoryName; + return m_balsaExtractToDirectoryName; } /** @@ -816,11 +796,11 @@ SceneFile::getExtractToDirectoryName() const * New value for Extract to directory name for zip file */ void -SceneFile::setExtractToDirectoryName(const AString& extractToDirectoryName) +SceneFile::setBalsaExtractToDirectoryName(const AString& extractToDirectoryName) { - if (extractToDirectoryName != m_extractToDirectoryName) { - // not stored in Scene File setModified(); - m_extractToDirectoryName = extractToDirectoryName; + if (extractToDirectoryName != m_balsaExtractToDirectoryName) { + setModified(); + m_balsaExtractToDirectoryName = extractToDirectoryName; } } diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 0955a2767..05da4495d 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -91,9 +91,9 @@ namespace caret { void setBalsaStudyTitle(const AString& balsaStudyTitle); - AString getBaseDirectory() const; + AString getBalsaBaseDirectory() const; - void setBaseDirectory(const AString& baseDirectory); + void setBalsaBaseDirectory(const AString& balsaBaseDirectory); void reorderScenes(std::vector& orderedScenes); @@ -101,15 +101,11 @@ namespace caret { Scene* releaseScene(const int32_t& index); - AString getZipFileName() const; - - void setZipFileName(const AString& zipFileName); - AString getDefaultZipFileName() const; - AString getExtractToDirectoryName() const; + AString getBalsaExtractToDirectoryName() const; - void setExtractToDirectoryName(const AString& extractToDirectoryName); + void setBalsaExtractToDirectoryName(const AString& balsaExtractToDirectoryName); AString getDefaultExtractToDirectoryName() const; @@ -144,13 +140,10 @@ namespace caret { AString m_balsaStudyTitle; /** the Base Directory */ - AString m_baseDirectory; - - /** the ZIP file name */ - AString m_zipFileName; + AString m_balsaBaseDirectory; /** The "extract to" directory name */ - AString m_extractToDirectoryName; + AString m_balsaExtractToDirectoryName; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/SceneFileSaxReader.cxx b/src/Files/SceneFileSaxReader.cxx index c1b957cac..6a41ceedf 100644 --- a/src/Files/SceneFileSaxReader.cxx +++ b/src/Files/SceneFileSaxReader.cxx @@ -131,8 +131,12 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, else if (qName == SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG) { m_state = STATE_SCENE_INFO_BALSA_STUDY_TITLE; } - else if (qName == SceneXmlElements::SCENE_INFO_BASE_DIRECTORY_TAG) { - m_state = STATE_SCENE_INFO_BASE_DIRECTORY; + else if ((qName == SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG) + || (qName == SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG_OLD)) { + m_state = STATE_SCENE_INFO_BALSA_BASE_DIRECTORY; + } + else if (qName == SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG) { + m_state = STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY; } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(SceneXmlElements::SCENE_INFO_TAG, @@ -147,7 +151,9 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, break; case STATE_SCENE_INFO_BALSA_STUDY_TITLE: break; - case STATE_SCENE_INFO_BASE_DIRECTORY: + case STATE_SCENE_INFO_BALSA_BASE_DIRECTORY: + break; + case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: break; case STATE_SCENE_INFO: m_sceneInfoSaxReader->startElement(namespaceURI, localName, qName, attributes); @@ -236,8 +242,11 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, case STATE_SCENE_INFO_BALSA_STUDY_TITLE: m_sceneFile->setBalsaStudyTitle(m_elementText); break; - case STATE_SCENE_INFO_BASE_DIRECTORY: - m_sceneFile->setBaseDirectory(m_elementText); + case STATE_SCENE_INFO_BALSA_BASE_DIRECTORY: + m_sceneFile->setBalsaBaseDirectory(m_elementText); + break; + case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: + m_sceneFile->setBalsaExtractToDirectoryName(m_elementText); break; case STATE_SCENE_INFO: CaretAssert(m_sceneInfo); diff --git a/src/Files/SceneFileSaxReader.h b/src/Files/SceneFileSaxReader.h index c082f555e..f4a45f29c 100644 --- a/src/Files/SceneFileSaxReader.h +++ b/src/Files/SceneFileSaxReader.h @@ -86,7 +86,9 @@ namespace caret { /// processing scene info Balsa Study Title tag STATE_SCENE_INFO_BALSA_STUDY_TITLE, /// processing scene info Base Directory tag - STATE_SCENE_INFO_BASE_DIRECTORY, + STATE_SCENE_INFO_BALSA_BASE_DIRECTORY, + /// processing scene info Balsa Extract to Directory + STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY, /// processing SceneInfo tag STATE_SCENE_INFO, /// processing Scene tag diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index b083d85e9..d12ca9d5a 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -25,6 +25,8 @@ #include "BalsaDatabaseManager.h" #undef __BALSA_DATABASE_MANAGER_DECLARE__ +#include + #include "CaretAssert.h" #include "CaretHttpManager.h" #include "CaretJsonObject.h" @@ -326,6 +328,9 @@ BalsaDatabaseManager::processUploadResponse(const std::map& re contentErrorMessage = "No Content-Type header received from file upload.\n"; } + QJsonDocument jsonDocument = QJsonDocument::fromRawData(responseContent.toLatin1().constData(), + responseContent.length()); + CaretJsonObject json(responseContent); if (responseHttpCode != 200) { @@ -393,9 +398,9 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, } AString baseDirectoryName; - if ( ! sceneFile->getBaseDirectory().isEmpty()) { + if ( ! sceneFile->getBalsaBaseDirectory().isEmpty()) { /* validate ? */ - baseDirectoryName = sceneFile->getBaseDirectory(); + baseDirectoryName = sceneFile->getBalsaBaseDirectory(); } bool successFlag = false; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 9b45535e0..959b62535 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -23,14 +23,19 @@ #include "BalsaDatabaseUploadSceneFileDialog.h" #undef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ +#include #include +#include #include #include +#include #include #include #include +#include #include #include +#include #include "BalsaDatabaseManager.h" #include "BalsaDatabaseStudyTitleDialog.h" @@ -76,14 +81,6 @@ m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); - QString defaultUserName = "balsaTest"; - QString defaultPassword = "@2password"; - -#ifdef NDEBUG - defaultUserName = ""; - defaultPassword = ""; -#endif - /* * Icons */ @@ -92,6 +89,41 @@ m_sceneFile(sceneFile) m_lockOpenIconValid = WuQtUtilities::loadIcon(":/BalsaUploadDialog/lock-open.png", m_lockOpenIcon); + QTabWidget* tabWidget = new QTabWidget(); + tabWidget->addTab(createUploadTab(), "Upload"); + tabWidget->addTab(createAdvancedTab(), "Advanced"); + + setCentralWidget(tabWidget, + WuQDialogModal::SCROLL_AREA_NEVER); + + updateBalsaStudyIDLockButtonIcon(); + validateData(); + + setSizePolicy(sizePolicy().horizontalPolicy(), + QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +BalsaDatabaseUploadSceneFileDialog::~BalsaDatabaseUploadSceneFileDialog() +{ +} + +/** + * @return New instance of the upload tab. + */ +QWidget* +BalsaDatabaseUploadSceneFileDialog::createUploadTab() +{ + QString defaultUserName = "balsaTest"; + QString defaultPassword = "@2password"; + +#ifdef NDEBUG + defaultUserName = ""; + defaultPassword = ""; +#endif + /* * Database selection */ @@ -153,18 +185,6 @@ m_sceneFile(sceneFile) ""); QObject::connect(registerLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); - - /* - * Zip file name - */ - const AString defaultZipFileName = m_sceneFile->getDefaultZipFileName(); - m_zipFileNameLabel = new QLabel(""); - m_zipFileNameLineEdit = new QLineEdit; - m_zipFileNameLineEdit->setText(defaultZipFileName); - m_zipFileNameLineEdit->setValidator(createValidator(LabelName::LABEL_ZIP_FILENAME)); - m_zipFileNameLineEdit->setToolTip("Name of ZIP file that user will download"); - QObject::connect(m_zipFileNameLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); /* * Extract to directory @@ -238,7 +258,7 @@ m_sceneFile(sceneFile) m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::LABEL_BASE_DIRECTORY)); QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, this, [=] { this->validateData(); }); - + /* * Browse for base directory */ @@ -253,8 +273,8 @@ m_sceneFile(sceneFile) const int COLUMN_BUTTON_ONE = columnCounter++; const int COLUMN_BUTTON_TWO = columnCounter++; - QWidget* dialogWidget = new QWidget(); - QGridLayout* gridLayout = new QGridLayout(dialogWidget); + QWidget* widget = new QWidget(); + QGridLayout* gridLayout = new QGridLayout(widget); gridLayout->setSpacing(2); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); @@ -273,9 +293,6 @@ m_sceneFile(sceneFile) gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE, 1, 2); row++; - gridLayout->addWidget(m_zipFileNameLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_zipFileNameLineEdit, row, COLUMN_DATA_WIDGET); - row++; gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); row++; @@ -293,31 +310,67 @@ m_sceneFile(sceneFile) gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, COLUMN_BUTTON_TWO); - setCentralWidget(dialogWidget, - WuQDialogModal::SCROLL_AREA_NEVER); - m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); - m_baseDirectoryLineEdit->setText(m_sceneFile->getBaseDirectory()); + m_baseDirectoryLineEdit->setText(m_sceneFile->getBalsaBaseDirectory()); m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); - m_extractDirectoryNameLineEdit->setText(m_sceneFile->getExtractToDirectoryName()); - m_zipFileNameLineEdit->setText(m_sceneFile->getZipFileName()); + m_extractDirectoryNameLineEdit->setText(m_sceneFile->getBalsaExtractToDirectoryName()); if (m_extractDirectoryNameLineEdit->text().trimmed().isEmpty()) { m_extractDirectoryNameLineEdit->setText(m_sceneFile->getDefaultExtractToDirectoryName()); } - if (m_zipFileNameLineEdit->text().trimmed().isEmpty()) { - m_zipFileNameLineEdit->setText(m_sceneFile->getDefaultZipFileName()); - } - updateBalsaStudyIDLockButtonIcon(); - validateData(); + return widget; } /** - * Destructor. + * @return New instance of the advanced tab */ -BalsaDatabaseUploadSceneFileDialog::~BalsaDatabaseUploadSceneFileDialog() +QWidget* +BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() { + m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("Use System Temporary Directory"); + m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); + + QButtonGroup* buttGroup = new QButtonGroup(this); + buttGroup->addButton(m_zipFileTemporaryDirectoryRadioButton); + buttGroup->addButton(m_zipFileCustomDirectoryRadioButton); + m_zipFileTemporaryDirectoryRadioButton->setChecked(true); // do before signal + QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), + [=](int id){ this->zipFileDirectoryRadioButtonClicked(id); }); + + m_zipFileCustomDirectoryLineEdit = new QLineEdit(); + + QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); + QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); + //QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), + // this, &BalsaDatabaseUploadSceneFileDialog::zipFileDirectoryComboBoxActivated); + // QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), + // this, [=](int) { this->validateData(); }); + // QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), + // this, [=]{ this->validateData(); }); + // QObject::connect(m_zipFileDirectoryComboBox, &QComboBox::activated, + // this, [=](int) { this->validateData(); }); + + QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); + QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); + gridLayout->setSpacing(2); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 100); + gridLayout->setColumnStretch(2, 0); + int row = 0; + gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, 0, 0, 1, 3); + gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, 1, 0); + gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, 1, 1); + gridLayout->addWidget(browseCustomDirectoryPushButton, 1, 2); + row++; + + QWidget* widget = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addWidget(zipDirectoryGroupBox); + layout->addStretch(); + + return widget; } /** @@ -349,6 +402,89 @@ BalsaDatabaseUploadSceneFileDialog::labelHtmlLinkClicked(const QString& linkPath } } +/** + * Called when a Zip File Directory radio button is clicked + */ +void +BalsaDatabaseUploadSceneFileDialog::zipFileDirectoryRadioButtonClicked(int) +{ + validateData(); +} + +/** + * Get the ZIP file name. + * + * @param errorMessageOut + * Output if failure to create zip file name. + * + * @return + * Name of ZIP file. If empty, check errorMessageOut for explanation. + */ +AString +BalsaDatabaseUploadSceneFileDialog::getZipFileNameWithPath(AString& errorMessageOut) const +{ + errorMessageOut = ""; + + AString directoryName; + if (m_zipFileTemporaryDirectoryRadioButton->isChecked()) { + directoryName = SystemUtilities::getTempDirectory(); + if ( ! FileInformation(directoryName).exists()) { + errorMessageOut = "Default temporary directory is invalid. Please choose a Custom Zip File Directory on Advanced tab"; + return ""; + } + } + else if (m_zipFileCustomDirectoryRadioButton->isChecked()) { + directoryName = m_zipFileCustomDirectoryLineEdit->text().trimmed(); + if (directoryName.isEmpty()) { + errorMessageOut = "Zip File Custom directory is selected but is empty (see Advanced tab)."; + return ""; + } + if ( ! FileInformation(directoryName).exists()) { + errorMessageOut = "Zip File Custom directory is invalid. Please choose a Custom Zip File Directory on Advanced tab"; + return ""; + } + } + else { + CaretAssert(0); + } + + FileInformation zipFileName(directoryName, + "BalsaUpload_" + QString::number(QDateTime::currentMSecsSinceEpoch())+ ".zip"); + + return zipFileName.getAbsoluteFilePath(); +} + + + +///** +// * @return the ZIP file directory. Will be empty if the directory is invalid (does not exist). +// */ +//AString +//BalsaDatabaseUploadSceneFileDialog::getZipFileDirectory() const +//{ +// AString directoryName; +// if (m_zipFileTemporaryDirectoryRadioButton->isChecked()) { +// directoryName = SystemUtilities::getTempDirectory(); +// } +// else if (m_zipFileCustomDirectoryRadioButton->isChecked()) { +// directoryName = m_zipFileCustomDirectoryLineEdit->text().trimmed(); +// } +// else { +// CaretAssert(0); +// } +// +// if (directoryName.isEmpty()) { +// return ""; +// } +// +// FileInformation fileInfo(directoryName); +// if (fileInfo.exists()) { +// return directoryName; +// } +// +// return ""; +//} + /** * Gets called when the OK button is clicked. @@ -360,9 +496,11 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() m_sceneFile->setBalsaStudyID(m_balsaStudyIDLineEdit->text().trimmed()); m_sceneFile->setBalsaStudyTitle(m_balsaStudyTitleLineEdit->text().trimmed()); - m_sceneFile->setBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); - m_sceneFile->setZipFileName(m_zipFileNameLineEdit->text().trimmed()); - m_sceneFile->setExtractToDirectoryName(m_extractDirectoryNameLineEdit->text().trimmed()); + m_sceneFile->setBalsaBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); + AString zipFileErrorMessage; + const AString zipFileName = getZipFileNameWithPath(zipFileErrorMessage); + + m_sceneFile->setBalsaExtractToDirectoryName(m_extractDirectoryNameLineEdit->text().trimmed()); AString msg; if ( ! m_usernameLineEdit->hasAcceptableInput()) { @@ -372,8 +510,8 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() if ( ! m_passwordLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Password is missing. If you do not remember your password, press the \"Forgot Password\" link.

"); } - if ( ! m_zipFileNameLineEdit->hasAcceptableInput()) { - msg.appendWithNewLine("Zip Filename is invalid. Must end in \".zip\".

"); + if (zipFileName.isEmpty()) { + msg.appendWithNewLine(zipFileErrorMessage + "

"); } if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Extract to Directory is invalid.

"); @@ -399,7 +537,7 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); - const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); + const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); // if (m_sceneFile->getBalsaStudyID().trimmed().isEmpty()) { @@ -536,8 +674,8 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); - const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); - const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); + //const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); + //const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); AString studyID; AString errorMessage; @@ -562,6 +700,47 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() } } +/** + * Choose the custom directory + */ +void +BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + /* + * Let user choose directory path + */ + QString directoryName; + FileInformation fileInfo(m_zipFileCustomDirectoryLineEdit->text().trimmed()); + if (fileInfo.exists()) { + if (fileInfo.isDirectory()) { + directoryName = fileInfo.getAbsoluteFilePath(); + } + } + AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, + "Choose Custom Zip File Directory", + directoryName); + /* + * If user cancels, return + */ + if (newDirectoryName.isEmpty()) { + return; + } + + /* + * Set name of new scene file and add to brain + */ + m_zipFileCustomDirectoryLineEdit->setText(newDirectoryName); + FileInformation newFileInfo(newDirectoryName); + if (newFileInfo.exists() + && newFileInfo.isDirectory()) { + m_zipFileCustomDirectoryRadioButton->setChecked(true); + } + + validateData(); +} + /** * Called when upload scene file is selected. */ @@ -635,9 +814,9 @@ BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) case LabelName::LABEL_USERNAME: regEx.setPattern(".+"); break; - case LabelName::LABEL_ZIP_FILENAME: - regEx.setPattern(".+\\.zip"); - break; +// case LabelName::LABEL_ZIP_FILE_DIRECTORY: +// regEx.setPattern(".+\\.zip"); +// break; } CaretAssert(regEx.isValid()); @@ -669,7 +848,7 @@ BalsaDatabaseUploadSceneFileDialog::updateAllLabels() setLabelText(LabelName::LABEL_STUDY_ID); setLabelText(LabelName::LABEL_STUDY_TITLE); setLabelText(LabelName::LABEL_USERNAME); - setLabelText(LabelName::LABEL_ZIP_FILENAME); +// setLabelText(LabelName::LABEL_ZIP_FILE_DIRECTORY); } @@ -723,11 +902,15 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) labelText = "Username"; validFlag = m_usernameLineEdit->hasAcceptableInput(); break; - case LabelName::LABEL_ZIP_FILENAME: - label = m_zipFileNameLabel; - labelText = "Zip Filename"; - validFlag = m_zipFileNameLineEdit->hasAcceptableInput(); - break; +// case LabelName::LABEL_ZIP_FILE_DIRECTORY: +// { +// label = m_zipFileDirectoryNameLabel; +// labelText = "Zip File Directory"; +// if ( ! getZipFileDirectory().isEmpty()) { +// validFlag = true; +// } +// } +// break; } const bool textRedIfInvalid = true; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index b554c5b5f..fae7a1e45 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -29,6 +29,7 @@ class QComboBox; class QLabel; class QLineEdit; class QPushButton; +class QRadioButton; class QRegularExpressionValidator; namespace caret { @@ -61,6 +62,10 @@ namespace caret { void selectStudyTitleButtonClicked(); + void zipFileDirectoryRadioButtonClicked(int); + + void browseZipFileCustomDirectoryPushButtonClicked(); + protected: virtual void okButtonClicked(); @@ -72,14 +77,18 @@ namespace caret { LABEL_PASSWORD, LABEL_STUDY_ID, LABEL_STUDY_TITLE, - LABEL_USERNAME, - LABEL_ZIP_FILENAME + LABEL_USERNAME + //LABEL_ZIP_FILE_DIRECTORY }; BalsaDatabaseUploadSceneFileDialog(const BalsaDatabaseUploadSceneFileDialog&); BalsaDatabaseUploadSceneFileDialog& operator=(const BalsaDatabaseUploadSceneFileDialog&); + QWidget* createUploadTab(); + + QWidget* createAdvancedTab(); + void loadSceneFileMetaDataWidgets(); AString getDataBaseURL() const; @@ -88,6 +97,10 @@ namespace caret { QRegularExpressionValidator* createValidator(const LabelName labelName); + AString getZipFileNameWithPath(AString& errorMessageOut) const; + + //AString getZipFileDirectory() const; + void updateAllLabels(); void setLabelText(const LabelName labelName); @@ -103,8 +116,9 @@ namespace caret { QLabel* m_passwordLabel; QLineEdit* m_passwordLineEdit; - QLabel* m_zipFileNameLabel; - QLineEdit* m_zipFileNameLineEdit; + QRadioButton* m_zipFileTemporaryDirectoryRadioButton; + QRadioButton* m_zipFileCustomDirectoryRadioButton; + QLineEdit* m_zipFileCustomDirectoryLineEdit; QLabel* m_extractDirectoryNameLabel; QLineEdit* m_extractDirectoryNameLineEdit; diff --git a/src/GuiQt/ProgressReportingDialog.cxx b/src/GuiQt/ProgressReportingDialog.cxx index db0c751d6..ef42cb968 100644 --- a/src/GuiQt/ProgressReportingDialog.cxx +++ b/src/GuiQt/ProgressReportingDialog.cxx @@ -149,3 +149,22 @@ ProgressReportingDialog::runEvent(Event* event, prd.setValue(prd.maximum()); } + +/** + * Set event receiving enabled. This method is used to enable + * and disable the receiving of EventProgressUpdate events. + * The default is true. + * + * @param enabled + * New status for receiving the events. + */ +void +ProgressReportingDialog::setEventReceivingEnabled(bool status) +{ + ProgressReportingFromEvent* progFromEvent = dynamic_cast(m_progressReporter); + if (progFromEvent != NULL) { + progFromEvent->setEventReceivingEnabled(status); + } +} + + diff --git a/src/GuiQt/ProgressReportingDialog.h b/src/GuiQt/ProgressReportingDialog.h index b26766085..9e508310d 100644 --- a/src/GuiQt/ProgressReportingDialog.h +++ b/src/GuiQt/ProgressReportingDialog.h @@ -44,6 +44,8 @@ namespace caret { QWidget* parent, const AString& title); + void setEventReceivingEnabled(bool status); + public: virtual ~ProgressReportingDialog(); diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index f29517997..063e59382 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -21,6 +21,7 @@ #include +#include #include #include #include @@ -1153,10 +1154,6 @@ SceneDialog::testScenesPushButtonClicked() return; } - std::vector sceneNames; - std::vector sceneErrors; - std::vector sceneImages; - std::vector newImages; const int32_t numScenes = sceneFile->getNumberOfScenes(); if (numScenes == 0) { @@ -1200,12 +1197,39 @@ SceneDialog::testScenesPushButtonClicked() } } - showWaitCursor(); + //showWaitCursor(); + ProgressReportingDialog progressDialog("Test All Scenes", + "Starting...", + m_testScenesPushButton); + progressDialog.setEventReceivingEnabled(false); + progressDialog.setMinimumDuration(0); + progressDialog.setMinimum(0); + progressDialog.setMaximum(numScenes); + progressDialog.setValue(1); + progressDialog.setLabelText("Starting testing..."); + progressDialog.repaint(); + progressDialog.show(); + QApplication::processEvents(); + + std::vector sceneNames; + std::vector sceneErrors; + std::vector sceneImages; + std::vector newImages; const int IMAGE_DISPLAY_WIDTH = 500; for (int32_t i = 0; i < numScenes; i++) { + if (progressDialog.wasCanceled()) { + break; + } + Scene* origScene = sceneFile->getSceneAtIndex(i); if (origScene != NULL) { + progressDialog.setValue(i+1); + progressDialog.setLabelText("Testing: " + origScene->getName() + + "\n\nPressing Cancel will cease testing after the current scene is loaded."); + progressDialog.repaint(); + progressDialog.show(); + QApplication::processEvents(); if (origScene->hasFilesWithRemotePaths()) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); @@ -1251,6 +1275,8 @@ SceneDialog::testScenesPushButtonClicked() } } + progressDialog.close(); + CaretAssert(sceneNames.size() == sceneErrors.size()); CaretAssert(sceneNames.size() == sceneImages.size()); CaretAssert(sceneNames.size() == sceneErrors.size()); diff --git a/src/Scenes/SceneXmlElements.h b/src/Scenes/SceneXmlElements.h index a784d23a6..42370c80b 100644 --- a/src/Scenes/SceneXmlElements.h +++ b/src/Scenes/SceneXmlElements.h @@ -164,7 +164,13 @@ namespace caret { /** * XML Tag for Base Directory ID element. */ - static const AString SCENE_INFO_BASE_DIRECTORY_TAG = "BaseDirectory"; + static const AString SCENE_INFO_BALSA_BASE_DIRECTORY_TAG = "BalsaBaseDirectory"; + static const AString SCENE_INFO_BALSA_BASE_DIRECTORY_TAG_OLD = "BaseDirectory"; + + /** + * XML Tag for Base Directory ID element. + */ + static const AString SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG = "BalsaExtractToDirectory"; } // namespace SceneXmlElements -- GitLab From 0d1c77cfb7a5057f75ea04cc4366d6e763e6f0e1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 May 2017 15:34:19 -0500 Subject: [PATCH 148/755] Correct drawing of volume surface outlines so that the outlines are drawn in order, from bottom to top, as listed in Toolbox->Vol/Surf Outline. Older scene are identified and the order of volume surface outlines is inverted during scene loading so that the outlines are listed correctly in the ToolBox and drawn in the correct order. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 7 ++++--- src/Brain/VolumeSurfaceOutlineSetModel.cxx | 18 +++++++++++++++++- src/GuiQt/BalsaDatabaseManager.cxx | 6 ++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 456eea709..80027a6ce 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3560,11 +3560,12 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) /* * Process each surface outline + * As of 24 May, "zero" is on top so draw in reverse order */ const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); - for (int io = 0; - io < numberOfOutlines; - io++) { + for (int32_t io = (numberOfOutlines - 1); + io >= 0; + io--) { VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); diff --git a/src/Brain/VolumeSurfaceOutlineSetModel.cxx b/src/Brain/VolumeSurfaceOutlineSetModel.cxx index 9d334e36b..78f167145 100644 --- a/src/Brain/VolumeSurfaceOutlineSetModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineSetModel.cxx @@ -336,7 +336,7 @@ VolumeSurfaceOutlineSetModel::saveToScene(const SceneAttributes* sceneAttributes { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSurfaceOutlineSetModel", - 1); + 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -371,6 +371,8 @@ VolumeSurfaceOutlineSetModel::restoreFromScene(const SceneAttributes* sceneAttri return; } + const int32_t version = sceneClass->getVersionNumber(); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); @@ -382,5 +384,19 @@ VolumeSurfaceOutlineSetModel::restoreFromScene(const SceneAttributes* sceneAttri m_outlineModels[i]->restoreFromScene(sceneAttributes, outlineModelsArrayClass->getClassAtIndex(i)); } + + /* + * In older scenes, last was drawn on top. + * Now, zero is drawn on top so need to reverse + * the order of the volume surface outlines + */ + if (version < 2) { + if (maxNum > 1) { + const int32_t numDisplayed = getNumberOfDislayedVolumeSurfaceOutlines(); + CaretAssertArrayIndex(m_outlineModels, BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES, numDisplayed - 1); + std::reverse(m_outlineModels, + m_outlineModels + numDisplayed); + } + } } } diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index d12ca9d5a..2dcb5e6c0 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -328,8 +328,10 @@ BalsaDatabaseManager::processUploadResponse(const std::map& re contentErrorMessage = "No Content-Type header received from file upload.\n"; } - QJsonDocument jsonDocument = QJsonDocument::fromRawData(responseContent.toLatin1().constData(), - responseContent.length()); +// std::cout << std::endl << "RESPONSE CONTENT: " << responseContent << std::endl << std::endl; +// +// QJsonDocument jsonDocument = QJsonDocument::fromRawData(responseContent.toLatin1().constData(), +// responseContent.length()); CaretJsonObject json(responseContent); -- GitLab From 29d6236c5d0bd46652e98c7776c82b6845995fa8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 26 May 2017 15:58:19 -0500 Subject: [PATCH 149/755] Additional updates for BALSA and Add/Select Study Dialogs. --- src/GuiQt/BalsaDatabaseManager.cxx | 316 ++++++++++++++---- src/GuiQt/BalsaDatabaseManager.h | 8 +- src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx | 148 -------- src/GuiQt/BalsaDatabaseStudyTitleDialog.h | 80 ----- .../BalsaDatabaseUploadSceneFileDialog.cxx | 145 ++++---- .../BalsaDatabaseUploadSceneFileDialog.h | 9 +- src/GuiQt/BalsaStudyInformation.cxx | 201 +++++++++++ src/GuiQt/BalsaStudyInformation.h | 81 +++++ src/GuiQt/BalsaStudySelectionDialog.cxx | 261 +++++++++++++++ src/GuiQt/BalsaStudySelectionDialog.h | 95 ++++++ src/GuiQt/CMakeLists.txt | 8 +- src/GuiQt/SceneDialog.cxx | 2 +- 12 files changed, 967 insertions(+), 387 deletions(-) delete mode 100644 src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx delete mode 100644 src/GuiQt/BalsaDatabaseStudyTitleDialog.h create mode 100644 src/GuiQt/BalsaStudyInformation.cxx create mode 100644 src/GuiQt/BalsaStudyInformation.h create mode 100644 src/GuiQt/BalsaStudySelectionDialog.cxx create mode 100644 src/GuiQt/BalsaStudySelectionDialog.h diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 2dcb5e6c0..34b32d0ea 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -19,6 +19,7 @@ */ /*LICENSE_END*/ +#include #include #define __BALSA_DATABASE_MANAGER_DECLARE__ @@ -328,10 +329,9 @@ BalsaDatabaseManager::processUploadResponse(const std::map& re contentErrorMessage = "No Content-Type header received from file upload.\n"; } -// std::cout << std::endl << "RESPONSE CONTENT: " << responseContent << std::endl << std::endl; -// -// QJsonDocument jsonDocument = QJsonDocument::fromRawData(responseContent.toLatin1().constData(), -// responseContent.length()); + if (m_debugFlag) { + std::cout << std::endl << "RESPONSE CONTENT: " << responseContent << std::endl << std::endl; + } CaretJsonObject json(responseContent); @@ -519,6 +519,39 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, return false; } +/** + * Get the value for the given header name using + * a case-insensitive string comparison. + * + * @param headerName + * The header name. + * @return + * Value for header name. If the header name is + * not found the returned string will be NULL + * (test with .isNull()). + */ +static AString getHeaderValue(const CaretHttpResponse& httpResponse, + const AString& headerName) +{ + /* + * NULL string + */ + AString value; + CaretAssert(value.isNull()); + + const QString headerNameLower(headerName.toLower()); + + + for (auto iter : httpResponse.m_headers) { + if (iter.first.toLower() == headerNameLower) { + value = iter.second; + break; + } + } + + return value; +} + /** * Get the study ID from a study Title * @@ -544,85 +577,84 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, errorMessageOut.clear(); - CaretHttpRequest uploadRequest; - uploadRequest.m_method = CaretHttpManager::POST_ARGUMENTS; - uploadRequest.m_url = studyIdURL; - uploadRequest.m_headers.insert(std::make_pair("Content-Type", + CaretHttpRequest caretRequest; + caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; + caretRequest.m_url = studyIdURL; + caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); - uploadRequest.m_headers.insert(std::make_pair("Cookie", + caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); - uploadRequest.m_arguments.push_back(std::make_pair("title", + caretRequest.m_arguments.push_back(std::make_pair("title", studyTitle)); + caretRequest.m_arguments.push_back(std::make_pair("type", + "json")); - CaretHttpResponse idResponse; - CaretHttpManager::httpRequest(uploadRequest, idResponse); + CaretHttpResponse studyResponse; + CaretHttpManager::httpRequest(caretRequest, studyResponse); if (m_debugFlag) { - std::cout << "Request study ID response Code: " << idResponse.m_responseCode << std::endl; + std::cout << "Request study ID response Code: " << studyResponse.m_responseCode << std::endl; } - AString locationFromHeader; - for (std::map::iterator mapIter = idResponse.m_headers.begin(); - mapIter != idResponse.m_headers.end(); - mapIter++) { - if (m_debugFlag) { - std::cout << " Request study ID Response Header: " << qPrintable(mapIter->first) - << " -> " << qPrintable(mapIter->second) << std::endl; - } - if (mapIter->first.toLower() == "location") { - locationFromHeader = mapIter->second; - } + if (studyResponse.m_responseCode != 200) { + errorMessageOut = ("Requesting study ID failed with HTTP code=" + + AString::number(studyResponse.m_responseCode) + + ". This error may be caused by failure to agree to data use terms."); + return false; } - idResponse.m_body.push_back('\0'); - AString responseContent(&idResponse.m_body[0]); + AString contentType = getHeaderValue(studyResponse, "Content-Type"); + //AString contentType = studyResponse.getHeaderValue("Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Requesting study ID failed. Content type returned by BALSA is unknown"); + return false; + } - if (m_debugFlag) { - std::cout << "Request Study ID reply body:" << responseContent << std::endl; + if ( ! contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Requesting study ID failed. Content type return by BALSA should be JSON format but is " + + contentType); + return false; } + + studyResponse.m_body.push_back('\0'); + AString responseContent(&studyResponse.m_body[0]); - CaretLogFine("Request Study ID to BALSA reply body: " - + responseContent); + if (m_debugFlag) { + std::cout << "Request study ID body:\n" << responseContent << std::endl << std::endl; + } - if (idResponse.m_responseCode != 200) { - errorMessageOut = ("Requesting study ID failed HTTP code: " - + QString::number(idResponse.m_responseCode) - + "\n" - "Could be due failure to agree to data user terms."); - + QJsonParseError jsonError; + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + &jsonError); + if (jsonDocument.isNull()) { + errorMessageOut = ("Requesting study ID failed. Failed to parse JSON, error:" + + jsonError.errorString()); return false; } - if ( ! locationFromHeader.isEmpty()) { - const int lastSlashIndex = locationFromHeader.lastIndexOf('/'); - if (lastSlashIndex >= 0) { - studyIDOut = locationFromHeader.mid(lastSlashIndex + 1); - if (studyIDOut.isNull() - || studyIDOut.isEmpty()) { - errorMessageOut = ("Received 'Location' from BALSA but unable to find study ID in the URL: " - + locationFromHeader); - return false; - } - - /* - * Have the Study ID - */ - return true; - } - else { - errorMessageOut = ("Received 'Location' from BALSA but unable to find study ID in the URL: " - + locationFromHeader); - } + QByteArray json = jsonDocument.toJson(); + if (m_debugFlag) { + std::cout << "Array?: " << jsonDocument.isArray() << std::endl; + std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; + std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; + std::cout << "Object?: " << jsonDocument.isObject() << std::endl; + std::cout << "JSON length: " << json.size() << std::endl; + AString str(json); + std::cout << ("Formatted JSON:\n" + str) << std::endl; } - else { - if (responseContent.indexOf("must be unique") >= 0) { - errorMessageOut = ("A study with the title \"" - + studyTitle - + "\" already exists and duplicate study titles are not allowed in the BALSA database."); - } - else { - errorMessageOut = "Unable to find 'Location' in response from BALSA."; - } + + if ( ! jsonDocument.isObject()) { + errorMessageOut = ("Requesting study ID failed. JSON content is not an object." + "JSON is displayed in terminal if logging level is warning or higher."); + CaretLogWarning("Study ID JSON is not Object\n" + + AString(jsonDocument.toJson())); + return false; + } + + BalsaStudyInformation bsi(jsonDocument.object()); + if ( ! bsi.getStudyID().isEmpty()) { + studyIDOut = bsi.getStudyID(); + return true; } return false; @@ -685,6 +717,160 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, return true; } + +/** + * Login to BALSA and request a study ID from a study title. + * + * @param databaseURL + * URL of the database. + * @param username + * Username for logging in. + * @param password + * Password for logging in. + * @param studyInformationOut + * Output containing information for all of the user's studies. + * @param errorMessageOut + * Contains description of any error(s). + * @return + * True if processing was successful, else false. + */ +bool +BalsaDatabaseManager::getAllStudyInformationForUser(const AString& databaseURL, + const AString& username, + const AString& password, + std::vector& studyInformationOut, + AString& errorMessageOut) +{ + studyInformationOut.clear(); + errorMessageOut = ""; + + /* + * Login + */ + const AString loginURL(databaseURL + + "/j_spring_security_check"); + if ( ! login(loginURL, + username, + password, + errorMessageOut)) { + + return false; + } + + if (m_debugFlag) { + std::cout << "SESSION ID from BALSA Login: " << getJSessionIdCookie() << std::endl; + } + else { + CaretLogInfo("SESSION ID from BALSA Login: " + + getJSessionIdCookie()); + } + + const AString studyIdURL(databaseURL + + "/study/mine"); + + errorMessageOut.clear(); + + CaretHttpRequest caretRequest; + caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; + caretRequest.m_url = studyIdURL; + caretRequest.m_headers.insert(std::make_pair("Content-Type", + "application/x-www-form-urlencoded")); + caretRequest.m_headers.insert(std::make_pair("Cookie", + getJSessionIdCookie())); + caretRequest.m_arguments.push_back(std::make_pair("type", + "json")); + + CaretHttpResponse idResponse; + CaretHttpManager::httpRequest(caretRequest, idResponse); + + if (m_debugFlag) { + std::cout << "Request all studies response Code: " << idResponse.m_responseCode << std::endl; + } + + if (idResponse.m_responseCode != 200) { + errorMessageOut = ("Requesting all study information failed with HTTP code=" + + AString::number(idResponse.m_responseCode) + + ". This error may be caused by failure to agree to data use terms."); + return false; + } + + AString contentType = getHeaderValue(idResponse, "Content-Type"); + //AString contentType = idResponse.getHeaderValue("Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Requesting all study information failed. Content type returned by BALSA is unknown"); + return false; + } + + if ( ! contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Requesting all study information failed. Content type return by BALSA should be JSON format but is " + + contentType); + return false; + } + + idResponse.m_body.push_back('\0'); + AString responseContent(&idResponse.m_body[0]); + + if (m_debugFlag) { + std::cout << "Request all studies reply body:\n" << responseContent << std::endl << std::endl; + } + + QJsonParseError jsonError; + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + &jsonError); + if (jsonDocument.isNull()) { + errorMessageOut = ("Requesting all study information failed. Failed to parse JSON, error:" + + jsonError.errorString()); + return false; + } + QByteArray json = jsonDocument.toJson(); + + if (m_debugFlag) { + std::cout << "Array?: " << jsonDocument.isArray() << std::endl; + std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; + std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; + std::cout << "Object?: " << jsonDocument.isObject() << std::endl; + std::cout << "JSON length: " << json.size() << std::endl; + AString str(json); + std::cout << ("Formatted JSON:\n" + str) << std::endl; + } + + if ( ! jsonDocument.isArray()) { + errorMessageOut = ("Requesting all study information failed. JSON content is not an array." + "JSON is displayed in terminal if logging level is warning or higher."); + CaretLogWarning("Study Information JSON is not Array\n" + + AString(jsonDocument.toJson())); + return false; + } + + QJsonArray jsonArray = jsonDocument.array(); + for (QJsonArray::iterator iter = jsonArray.begin(); + iter != jsonArray.end(); + iter++) { + QJsonValue jsonValue = *iter; + if ( ! jsonValue.isNull()) { + if (jsonValue.isObject()) { + QJsonObject studyInfo = jsonValue.toObject(); + + BalsaStudyInformation bsi(studyInfo); + if ( ! bsi.isEmpty()) { + studyInformationOut.push_back(bsi); + } + } + } + } + + if (studyInformationOut.empty()) { + errorMessageOut = "No study information was found."; + return false; + } + + std::sort(studyInformationOut.begin(), + studyInformationOut.end()); + + return true; +} + + /** * Login to BALSA, zip the scene and data files, and upload the * ZIP file to BALSA. diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index df1a6963b..6ff942b44 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -21,8 +21,8 @@ */ /*LICENSE_END*/ +#include "BalsaStudyInformation.h" #include "CaretObject.h" - #include "EventListenerInterface.h" namespace caret { @@ -36,6 +36,12 @@ namespace caret { virtual ~BalsaDatabaseManager(); + bool getAllStudyInformationForUser(const AString& databaseURL, + const AString& username, + const AString& password, + std::vector& studyInformationOut, + AString& errorMessageOut); + bool getStudyIDFromStudyTitle(const AString& databaseURL, const AString& username, const AString& password, diff --git a/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx b/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx deleted file mode 100644 index b10474773..000000000 --- a/src/GuiQt/BalsaDatabaseStudyTitleDialog.cxx +++ /dev/null @@ -1,148 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ -#include "BalsaDatabaseStudyTitleDialog.h" -#undef __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ - -#include -#include -#include -#include - -#include "CaretAssert.h" -#include "WuQMessageBox.h" - -using namespace caret; - - - -/** - * \class caret::BalsaDatabaseStudyTitleDialog - * \brief Dialog for selection and getting study titles with BALSA Database - * \ingroup GuiQt - */ - -/** - * Constructor. - * - * @param balsaUsername - * Username for BALSA Database - * @param balsaPassword - * Password for BALSA Database - * @param parent - * Parent dialog - */ -BalsaDatabaseStudyTitleDialog::BalsaDatabaseStudyTitleDialog(const std::vector studyTitles, - const AString& balsaUsername, - const AString& balsaPassword, - QWidget* parent) -: WuQDialogModal("BALSA Study Title", - parent), -m_studyTitles(studyTitles), -m_balsaUsername(balsaUsername), -m_balsaPassword(balsaPassword) -{ - m_studyTitleListWidget = new QListWidget(); - m_studyTitleListWidget->setSelectionMode(QListWidget::SingleSelection); - - QPushButton* newStudyTitlePushButton = new QPushButton("Add New Study..."); - QObject::connect(newStudyTitlePushButton, &QPushButton::clicked, - this, &BalsaDatabaseStudyTitleDialog::newStudyButtonClicked); - - QWidget* dialogWidget = new QWidget; - QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); - dialogLayout->addWidget(m_studyTitleListWidget, 100); - dialogLayout->addWidget(newStudyTitlePushButton, 0); - - setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); - - loadStudyTitleListWidget(); -} - -/** - * Destructor. - */ -BalsaDatabaseStudyTitleDialog::~BalsaDatabaseStudyTitleDialog() -{ -} - -/** - * Load the list widget for the study titles - */ -void -BalsaDatabaseStudyTitleDialog::loadStudyTitleListWidget() -{ - const int32_t selectedRow = m_studyTitleListWidget->currentRow(); - m_studyTitleListWidget->clear(); - - for (auto title : m_studyTitles) { - m_studyTitleListWidget->addItem(title); - } - - if (selectedRow >= 0) { - m_studyTitleListWidget->setCurrentRow(selectedRow); - } -} - -/** - * @return The selected study title or empty string if no selected title. - */ -AString -BalsaDatabaseStudyTitleDialog::getSelectedStudyTitle() const -{ - QListWidgetItem* item = m_studyTitleListWidget->currentItem(); - if (item != NULL) { - return item->text(); - } - return ""; -} - -/** - * Called when the new study button is clicked. - */ -void -BalsaDatabaseStudyTitleDialog::newStudyButtonClicked() -{ - const AString name = QInputDialog::getText(this, - "Study Title", - "New Study Title"); - if ( ! name.isNull()) { - m_studyTitles.push_back(name); - loadStudyTitleListWidget(); - m_studyTitleListWidget->setCurrentRow(m_studyTitleListWidget->count() - 1); - } -} - -/** - * Called when the OK button is clicked. - */ -void -BalsaDatabaseStudyTitleDialog::okButtonClicked() -{ - if ( m_studyTitleListWidget->currentItem() == NULL) { - WuQMessageBox::errorOk(this, "No Study Title is selected"); - return; - } - - WuQDialogModal::okButtonClicked(); -} - diff --git a/src/GuiQt/BalsaDatabaseStudyTitleDialog.h b/src/GuiQt/BalsaDatabaseStudyTitleDialog.h deleted file mode 100644 index d647d0291..000000000 --- a/src/GuiQt/BalsaDatabaseStudyTitleDialog.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ -#define __BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "WuQDialogModal.h" - -class QListWidget; - - -namespace caret { - - class BalsaDatabaseStudyTitleDialog : public WuQDialogModal { - - Q_OBJECT - - public: - BalsaDatabaseStudyTitleDialog(const std::vector studyTitles, - const AString& balsaUsername, - const AString& balsaPassword, - QWidget* parent); - - virtual ~BalsaDatabaseStudyTitleDialog(); - - virtual void okButtonClicked() override; - - AString getSelectedStudyTitle() const; - - // ADD_NEW_METHODS_HERE - - private slots: - void newStudyButtonClicked(); - - private: - BalsaDatabaseStudyTitleDialog(const BalsaDatabaseStudyTitleDialog&); - - BalsaDatabaseStudyTitleDialog& operator=(const BalsaDatabaseStudyTitleDialog&); - - void loadStudyTitleListWidget(); - - std::vector m_studyTitles; - - const AString& m_balsaUsername; - - const AString& m_balsaPassword; - - QListWidget* m_studyTitleListWidget; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ - // -#endif // __BALSA_DATABASE_STUDY_TITLE_DIALOG_DECLARE__ - -} // namespace -#endif //__BALSA_DATABASE_STUDY_TITLE_DIALOG_H__ diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 959b62535..743acaecd 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -38,7 +38,7 @@ #include #include "BalsaDatabaseManager.h" -#include "BalsaDatabaseStudyTitleDialog.h" +#include "BalsaStudySelectionDialog.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" @@ -124,6 +124,11 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() defaultPassword = ""; #endif + /* + * Create the BALSA database manager + */ + m_balsaDatabaseManager = std::unique_ptr(new BalsaDatabaseManager()); + /* * Database selection */ @@ -214,10 +219,14 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() /* * Get BALSA Study ID button */ - m_getBalsaStudyIDPushButton = new QPushButton("Get..."); - m_getBalsaStudyIDPushButton->setToolTip("Get the BALSA Study ID by sending Study Title to BALSA"); - QObject::connect(m_getBalsaStudyIDPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked); + const bool showGetStudyIdButtonFlag = false; + m_getBalsaStudyIDPushButton = NULL; + if (showGetStudyIdButtonFlag) { + m_getBalsaStudyIDPushButton = new QPushButton("Get..."); + m_getBalsaStudyIDPushButton->setToolTip("Get the BALSA Study ID by sending Study Title to BALSA"); + QObject::connect(m_getBalsaStudyIDPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked); + } /* * BALSA Study ID Lock button @@ -244,8 +253,8 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() /** * Select Study Push Button */ - m_selectStudyTitlePushButton = new QPushButton("Select..."); - m_selectStudyTitlePushButton->setToolTip("Select from user's studies in BALSA Database"); + m_selectStudyTitlePushButton = new QPushButton("Add/Choose..."); + m_selectStudyTitlePushButton->setToolTip("Add new study or choose from user's studies in BALSA Database"); QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); @@ -307,7 +316,9 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(m_balsaStudyIDLockPushButton, row, COLUMN_BUTTON_ONE); - gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, COLUMN_BUTTON_TWO); + if (m_getBalsaStudyIDPushButton != NULL) { + gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, COLUMN_BUTTON_TWO); + } m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); @@ -343,14 +354,6 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); - //QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), - // this, &BalsaDatabaseUploadSceneFileDialog::zipFileDirectoryComboBoxActivated); - // QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), - // this, [=](int) { this->validateData(); }); - // QObject::connect(m_zipFileDirectoryComboBox, static_cast(&QComboBox::activated), - // this, [=]{ this->validateData(); }); - // QObject::connect(m_zipFileDirectoryComboBox, &QComboBox::activated, - // this, [=](int) { this->validateData(); }); QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); @@ -454,38 +457,6 @@ BalsaDatabaseUploadSceneFileDialog::getZipFileNameWithPath(AString& errorMessage return zipFileName.getAbsoluteFilePath(); } - - -///** -// * @return the ZIP file directory. Will be empty if the directory is invalid (does not exist). -// */ -//AString -//BalsaDatabaseUploadSceneFileDialog::getZipFileDirectory() const -//{ -// AString directoryName; -// if (m_zipFileTemporaryDirectoryRadioButton->isChecked()) { -// directoryName = SystemUtilities::getTempDirectory(); -// } -// else if (m_zipFileCustomDirectoryRadioButton->isChecked()) { -// directoryName = m_zipFileCustomDirectoryLineEdit->text().trimmed(); -// } -// else { -// CaretAssert(0); -// } -// -// if (directoryName.isEmpty()) { -// return ""; -// } -// -// FileInformation fileInfo(directoryName); -// if (fileInfo.exists()) { -// return directoryName; -// } -// -// return ""; -//} - - /** * Gets called when the OK button is clicked. */ @@ -540,15 +511,6 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); -// if (m_sceneFile->getBalsaStudyID().trimmed().isEmpty()) { -// const QString msg("The BALSA Study ID is missing. You must either: (1) Go to " -// "BALSA Database and get a BALSA Study ID or " -// "(2) Enter a Study Title and press the Get button to request a BALSA Study ID " -// "using the Study Title"); -// WuQMessageBox::errorOk(this, msg); -// return; -// } - if (m_sceneFile->isModified()) { const QString msg("The scene file is modified and must be saved before continuing. Would you like " "to save the scene file using its current name and continue?"); @@ -577,8 +539,7 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() progressDialog.setCancelButton((QPushButton*)0); // no cancel button AString errorMessage; - CaretPointer balsaDatabaseManager(new BalsaDatabaseManager()); - const bool successFlag = balsaDatabaseManager->uploadZippedSceneFile(getDataBaseURL(), + const bool successFlag = m_balsaDatabaseManager->uploadZippedSceneFile(getDataBaseURL(), username, password, m_sceneFile, @@ -611,14 +572,42 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); - std::vector studyTitles; + std::vector studyInfo; + studyInfo.emplace(studyInfo.end(), "AV4H", "Study One"); + studyInfo.emplace(studyInfo.end(), "BX32", "Study Two"); + studyInfo.emplace(studyInfo.end(), "CR33", "Study Three"); - BalsaDatabaseStudyTitleDialog dialog(studyTitles, - username, - password, - this); - if (dialog.exec() == BalsaDatabaseStudyTitleDialog::Accepted) { - m_balsaStudyTitleLineEdit->setText(dialog.getSelectedStudyTitle().trimmed()); + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + AString errorMessage; + if ( ! m_balsaDatabaseManager->getAllStudyInformationForUser(getDataBaseURL(), + username, + password, + studyInfo, + errorMessage)) { + cursor.restoreCursor(); + WuQMessageBox::errorOk(this, + errorMessage); + return; + } + + cursor.restoreCursor(); + + const AString selectedStudyName = m_balsaStudyTitleLineEdit->text().trimmed(); + + BalsaStudySelectionDialog dialog(studyInfo, + selectedStudyName, + m_balsaDatabaseManager.get(), + getDataBaseURL(), + username, + password, + this); + if (dialog.exec() == BalsaStudySelectionDialog::Accepted) { + BalsaStudyInformation bsi = dialog.getSelectedStudyInformation(); + if ( ! bsi.isEmpty()) { + m_balsaStudyIDLineEdit->setText(bsi.getStudyID()); + m_balsaStudyTitleLineEdit->setText(bsi.getStudyTitle()); + } validateData(); } } @@ -662,6 +651,8 @@ BalsaDatabaseUploadSceneFileDialog::balsaStudyIDLockPushButtonClicked() void BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() { + CaretAssert(m_getBalsaStudyIDPushButton); + const AString title = m_balsaStudyTitleLineEdit->text().trimmed(); if (title.isEmpty()) { WuQMessageBox::errorOk(m_getBalsaStudyIDPushButton, @@ -674,8 +665,6 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); - //const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); - //const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); AString studyID; AString errorMessage; @@ -690,7 +679,6 @@ BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() cursor.restoreCursor(); if (successFlag) { - //m_sceneFile->setBalsaStudyID(studyID); m_balsaStudyIDLineEdit->setText(studyID); validateData(); } @@ -772,7 +760,6 @@ BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() /* * Set name of new scene file and add to brain */ - //m_sceneFile->setBaseDirectory(newDirectoryName); m_baseDirectoryLineEdit->setText(newDirectoryName); validateData(); } @@ -814,9 +801,6 @@ BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) case LabelName::LABEL_USERNAME: regEx.setPattern(".+"); break; -// case LabelName::LABEL_ZIP_FILE_DIRECTORY: -// regEx.setPattern(".+\\.zip"); -// break; } CaretAssert(regEx.isValid()); @@ -832,7 +816,9 @@ void BalsaDatabaseUploadSceneFileDialog::validateData() { updateAllLabels(); - m_getBalsaStudyIDPushButton->setEnabled(m_balsaStudyTitleLineEdit->hasAcceptableInput()); + if (m_getBalsaStudyIDPushButton != NULL) { + m_getBalsaStudyIDPushButton->setEnabled(m_balsaStudyTitleLineEdit->hasAcceptableInput()); + } } /** @@ -848,7 +834,6 @@ BalsaDatabaseUploadSceneFileDialog::updateAllLabels() setLabelText(LabelName::LABEL_STUDY_ID); setLabelText(LabelName::LABEL_STUDY_TITLE); setLabelText(LabelName::LABEL_USERNAME); -// setLabelText(LabelName::LABEL_ZIP_FILE_DIRECTORY); } @@ -902,15 +887,6 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) labelText = "Username"; validFlag = m_usernameLineEdit->hasAcceptableInput(); break; -// case LabelName::LABEL_ZIP_FILE_DIRECTORY: -// { -// label = m_zipFileDirectoryNameLabel; -// labelText = "Zip File Directory"; -// if ( ! getZipFileDirectory().isEmpty()) { -// validFlag = true; -// } -// } -// break; } const bool textRedIfInvalid = true; @@ -943,7 +919,6 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) CaretAssert(label); label->setText(coloredText); - } diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index fae7a1e45..9e7badc38 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include #include "WuQDialogModal.h" @@ -33,7 +35,7 @@ class QRadioButton; class QRegularExpressionValidator; namespace caret { - + class BalsaDatabaseManager; class SceneFile; class BalsaDatabaseUploadSceneFileDialog : public WuQDialogModal { @@ -78,7 +80,6 @@ namespace caret { LABEL_STUDY_ID, LABEL_STUDY_TITLE, LABEL_USERNAME - //LABEL_ZIP_FILE_DIRECTORY }; BalsaDatabaseUploadSceneFileDialog(const BalsaDatabaseUploadSceneFileDialog&); @@ -99,14 +100,14 @@ namespace caret { AString getZipFileNameWithPath(AString& errorMessageOut) const; - //AString getZipFileDirectory() const; - void updateAllLabels(); void setLabelText(const LabelName labelName); SceneFile* m_sceneFile; + std::unique_ptr m_balsaDatabaseManager; + QLabel* m_databaseLabel; QComboBox* m_databaseComboBox; diff --git a/src/GuiQt/BalsaStudyInformation.cxx b/src/GuiQt/BalsaStudyInformation.cxx new file mode 100644 index 000000000..bfc93f33b --- /dev/null +++ b/src/GuiQt/BalsaStudyInformation.cxx @@ -0,0 +1,201 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BALSA_STUDY_INFORMATION_DECLARE__ +#include "BalsaStudyInformation.h" +#undef __BALSA_STUDY_INFORMATION_DECLARE__ + +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::BalsaStudyInformation + * \brief Information about a BALSA Study + * \ingroup GuiQt + */ + +/** + * Constructor with invalid ID and title. + */ +BalsaStudyInformation::BalsaStudyInformation() +: CaretObject() +{ + +} + +/** + * Constructor with ID and title. + * + * @param studyID + * The Study Identifier + * @param studyTitle + * The Study Title + */ +BalsaStudyInformation::BalsaStudyInformation(const AString& studyID, + const AString& studyTitle) +: CaretObject(), +m_studyID(studyID), +m_studyTitle(studyTitle) +{ +} + +/** + * Constructor that creates BALSA study information from a JSON object. + * + * @param jsonObject + * The JSON object. + */ +BalsaStudyInformation::BalsaStudyInformation(const QJsonObject& jsonObject) +{ + QJsonObject::const_iterator idIter = jsonObject.find("id"); + QJsonObject::const_iterator titleIter = jsonObject.find("title"); + if ((idIter != jsonObject.end()) + && (titleIter != jsonObject.end())) { + m_studyID = idIter->toString(); + m_studyTitle = titleIter->toString(); + } +} + +/** + * Destructor. + */ +BalsaStudyInformation::~BalsaStudyInformation() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +BalsaStudyInformation::BalsaStudyInformation(const BalsaStudyInformation& obj) +: CaretObject(obj) +{ + this->copyHelperBalsaStudyInformation(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +BalsaStudyInformation& +BalsaStudyInformation::operator=(const BalsaStudyInformation& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperBalsaStudyInformation(obj); + } + return *this; +} + +/** + * Comparison operator using study title. + * + * @param obj + * Other study information. + * @return + * True if "this" is less than obj. + */ +bool +BalsaStudyInformation::operator<(const BalsaStudyInformation& obj) const +{ + return m_studyTitle < obj.m_studyTitle; +} + + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +BalsaStudyInformation::copyHelperBalsaStudyInformation(const BalsaStudyInformation& obj) +{ + m_studyID = obj.m_studyID; + m_studyTitle = obj.m_studyTitle; +} + +/** + * @return True if ID is not empty (title may be empty). + */ +bool +BalsaStudyInformation::isEmpty() const +{ + return m_studyID.isEmpty(); +} + +/** + * @return study identifier generated by BALSA + */ +AString +BalsaStudyInformation::getStudyID() const +{ + return m_studyID; +} + +/** + * Set study identifier generated by BALSA + * @param studyID + * New value for study identifier generated by BALSA + */ +void +BalsaStudyInformation::setStudyID(const AString& studyID) +{ + m_studyID = studyID; +} + +/** + * @return study title + */ +AString +BalsaStudyInformation::getStudyTitle() const +{ + return m_studyTitle; +} + +/** + * Set study title + * @param studyTitle + * New value for study title + */ +void +BalsaStudyInformation::setStudyTitle(const AString& studyTitle) +{ + m_studyTitle = studyTitle; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +BalsaStudyInformation::toString() const +{ + return "BalsaStudyInformation"; +} + diff --git a/src/GuiQt/BalsaStudyInformation.h b/src/GuiQt/BalsaStudyInformation.h new file mode 100644 index 000000000..d0cca0924 --- /dev/null +++ b/src/GuiQt/BalsaStudyInformation.h @@ -0,0 +1,81 @@ +#ifndef __BALSA_STUDY_INFORMATION_H__ +#define __BALSA_STUDY_INFORMATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +class QJsonObject; + +namespace caret { + + class BalsaStudyInformation : public CaretObject { + + public: + BalsaStudyInformation(const QJsonObject& jsonObject); + + BalsaStudyInformation(); + + BalsaStudyInformation(const AString& studyID, + const AString& studyTitle); + + virtual ~BalsaStudyInformation(); + + BalsaStudyInformation(const BalsaStudyInformation& obj); + + BalsaStudyInformation& operator=(const BalsaStudyInformation& obj); + + bool operator<(const BalsaStudyInformation& obj) const; + + bool isEmpty() const; + + AString getStudyID() const; + + void setStudyID(const AString& studyID); + + AString getStudyTitle() const; + + void setStudyTitle(const AString& studyTitle); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperBalsaStudyInformation(const BalsaStudyInformation& obj); + + /** study identifier generated by BALSA*/ + AString m_studyID; + + /** study title*/ + AString m_studyTitle; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BALSA_STUDY_INFORMATION_DECLARE__ + // +#endif // __BALSA_STUDY_INFORMATION_DECLARE__ + +} // namespace +#endif //__BALSA_STUDY_INFORMATION_H__ diff --git a/src/GuiQt/BalsaStudySelectionDialog.cxx b/src/GuiQt/BalsaStudySelectionDialog.cxx new file mode 100644 index 000000000..d5646ef9d --- /dev/null +++ b/src/GuiQt/BalsaStudySelectionDialog.cxx @@ -0,0 +1,261 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ +#include "BalsaStudySelectionDialog.h" +#undef __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include + +#include "BalsaDatabaseManager.h" +#include "CaretAssert.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BalsaStudySelectionDialog + * \brief Dialog for selection and getting study titles with BALSA Database + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param studyInformation + * The study information. + * @param selectedStudyName + * Name of study information that is selected. + * @param balsaDatabaseManager + * Database manager. + * @param databaseURL + * URL for database requests. + * @param balsaUsername + * Username for BALSA Database + * @param balsaPassword + * Password for BALSA Database + * @param parent + * Parent dialog + */ +BalsaStudySelectionDialog::BalsaStudySelectionDialog(const std::vector& studyInformation, + const AString selectedStudyName, + BalsaDatabaseManager* balsaDatabaseManager, + const AString& databaseURL, + const AString& balsaUsername, + const AString& balsaPassword, + QWidget* parent) +: WuQDialogModal("BALSA Studies", + parent), +m_studyInformation(studyInformation), +m_balsaDatabaseManager(balsaDatabaseManager), +m_databaseURL(databaseURL), +m_balsaUsername(balsaUsername), +m_balsaPassword(balsaPassword) +{ + m_studyTableWidget = new QTableWidget(); + + QPushButton* newStudyTitlePushButton = new QPushButton("Create New Study..."); + newStudyTitlePushButton->setSizePolicy(QSizePolicy::Fixed, + newStudyTitlePushButton->sizePolicy().verticalPolicy()); + + QObject::connect(newStudyTitlePushButton, &QPushButton::clicked, + this, &BalsaStudySelectionDialog::newStudyButtonClicked); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addWidget(m_studyTableWidget, 100); + dialogLayout->addWidget(newStudyTitlePushButton, 0); + + setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); + + loadStudyTitleTableWidget(selectedStudyName); + + const QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_studyTableWidget); + + WuQtUtilities::resizeWindow(this, + std::min(tableSize.width() + 40, + 600), + std::min(tableSize.height() + 40, + 600)); +} + +/** + * Destructor. + */ +BalsaStudySelectionDialog::~BalsaStudySelectionDialog() +{ +} + +/** + * Load the list widget for the studies. + * + * @param selectedStudyName + * Name of study information that is selected. + */ +void +BalsaStudySelectionDialog::loadStudyTitleTableWidget(const AString selectedStudyNameIn) +{ + AString selectedStudyName = selectedStudyNameIn; + + const int numRows = static_cast(m_studyInformation.size()); + if (selectedStudyName.isEmpty()) { + const int32_t selectedRow = m_studyTableWidget->currentRow(); + if ((selectedRow >= 0) + && (selectedRow < numRows)) { + selectedStudyName = m_studyTableWidget->item(selectedRow, + COLUMN_TITLE)->text(); + } + } + + m_studyTableWidget->clear(); + m_studyTableWidget->setSelectionMode(QTableWidget::SingleSelection); + m_studyTableWidget->setSelectionBehavior(QTableWidget::SelectRows); + m_studyTableWidget->setRowCount(numRows); + m_studyTableWidget->setColumnCount(COLUMN_COUNT); + m_studyTableWidget->setHorizontalHeaderItem(COLUMN_ID, new QTableWidgetItem("ID")); + m_studyTableWidget->setHorizontalHeaderItem(COLUMN_TITLE, new QTableWidgetItem("Title")); + m_studyTableWidget->setShowGrid(false); + + std::sort(m_studyInformation.begin(), + m_studyInformation.end()); + + int32_t selectedRow = 0; + for (int32_t iRow = 0; iRow < numRows; iRow++) { + const AString studyTitle = m_studyInformation[iRow].getStudyTitle(); + if ( ! selectedStudyName.isEmpty()) { + if (selectedStudyName.toLower() == studyTitle.toLower()) { + selectedRow = iRow; + } + } + + CaretAssertVectorIndex(m_studyInformation, iRow); + QTableWidgetItem* idItem = new QTableWidgetItem(m_studyInformation[iRow].getStudyID()); + idItem->setFlags(idItem->flags().setFlag(Qt::ItemIsEditable, false)); + m_studyTableWidget->setItem(iRow, COLUMN_ID, idItem); + + QTableWidgetItem* titleItem = new QTableWidgetItem(studyTitle); + titleItem->setFlags(idItem->flags().setFlag(Qt::ItemIsEditable, false)); + m_studyTableWidget->setItem(iRow, COLUMN_TITLE, titleItem); + } + + if (numRows > 0) { + if (selectedRow >= 0) { + m_studyTableWidget->selectRow(selectedRow); + } + else { + m_studyTableWidget->selectRow(0); + } + const int32_t rowIndex = m_studyTableWidget->currentRow(); + if (rowIndex >= 0) { + QTableWidgetItem* item = m_studyTableWidget->item(rowIndex, 0); + if (item != NULL) { + m_studyTableWidget->scrollToItem(item); + } + } + + QHeaderView* horizontalHeader = m_studyTableWidget->horizontalHeader(); + for (int32_t i = 0; i < COLUMN_COUNT; i++) { + const int logicalIndex = horizontalHeader->logicalIndex(i); + horizontalHeader->setSectionResizeMode(logicalIndex, + QHeaderView::ResizeToContents); + } + } +} + +/** + * @return The selected study information. Will return + * and empty instance (test with isEmpty()) if no study information was selected. + */ +BalsaStudyInformation +BalsaStudySelectionDialog::getSelectedStudyInformation() const +{ + const int32_t selectedRow = m_studyTableWidget->currentRow(); + if (selectedRow < 0) { + return BalsaStudyInformation(); + } + + CaretAssertVectorIndex(m_studyInformation, selectedRow); + return m_studyInformation[selectedRow]; +} + +/** + * Called when the new study button is clicked. + */ +void +BalsaStudySelectionDialog::newStudyButtonClicked() +{ + AString title = QInputDialog::getText(this, + "Create New Study", + "Title of New Study"); + if ( ! title.isNull()) { + title = title.trimmed(); + AString studyID; + AString errorMessage; + const bool successFlag = m_balsaDatabaseManager->getStudyIDFromStudyTitle(m_databaseURL, + m_balsaUsername, + m_balsaPassword, + title, + studyID, + errorMessage); + + if (successFlag) { + const AString titleLower = title.toLower(); + for (auto infoIter : m_studyInformation) { + if (infoIter.getStudyTitle().toLower() == titleLower) { + WuQMessageBox::errorOk(this, ("Duplicate study names are not allowed: \"" + + title + + "\" ")); + return; + } + } + m_studyInformation.emplace_back(studyID, + title); + loadStudyTitleTableWidget(title); + } + else { + WuQMessageBox::errorOk(this, + errorMessage); + } + } +} + +/** + * Called when the OK button is clicked. + */ +void +BalsaStudySelectionDialog::okButtonClicked() +{ + if ( m_studyTableWidget->currentItem() == NULL) { + WuQMessageBox::errorOk(this, "No Study Title is selected"); + return; + } + + WuQDialogModal::okButtonClicked(); +} + diff --git a/src/GuiQt/BalsaStudySelectionDialog.h b/src/GuiQt/BalsaStudySelectionDialog.h new file mode 100644 index 000000000..dd9db2354 --- /dev/null +++ b/src/GuiQt/BalsaStudySelectionDialog.h @@ -0,0 +1,95 @@ +#ifndef __BALSA_STUDY_SELECTION_DIALOG_H__ +#define __BALSA_STUDY_SELECTION_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "BalsaStudyInformation.h" +#include "WuQDialogModal.h" + +class QTableWidget; + + +namespace caret { + class BalsaDatabaseManager; + + class BalsaStudySelectionDialog : public WuQDialogModal { + + Q_OBJECT + + public: + BalsaStudySelectionDialog(const std::vector& studyInformation, + const AString selectedStudyName, + BalsaDatabaseManager* balsaDatabaseManager, + const AString& databaseURL, + const AString& balsaUsername, + const AString& balsaPassword, + QWidget* parent); + + virtual ~BalsaStudySelectionDialog(); + + virtual void okButtonClicked() override; + + BalsaStudyInformation getSelectedStudyInformation() const; + + // ADD_NEW_METHODS_HERE + + private slots: + void newStudyButtonClicked(); + + private: + const int32_t COLUMN_TITLE = 0; + + const int32_t COLUMN_ID = 1; + + const int32_t COLUMN_COUNT = 2; + + BalsaStudySelectionDialog(const BalsaStudySelectionDialog&); + + BalsaStudySelectionDialog& operator=(const BalsaStudySelectionDialog&); + + void loadStudyTitleTableWidget(const AString selectedStudyName); + + std::vector m_studyInformation; + + BalsaDatabaseManager* m_balsaDatabaseManager; + + const AString& m_databaseURL; + + const AString& m_balsaUsername; + + const AString& m_balsaPassword; + + QTableWidget* m_studyTableWidget; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ + // +#endif // __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ + +} // namespace +#endif //__BALSA_STUDY_SELECTION_DIALOG_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 4f599e111..5cd3d612b 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -60,8 +60,8 @@ ELSE() AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationWidthHeightWidget.h - BalsaDatabaseStudyTitleDialog.h BalsaDatabaseUploadSceneFileDialog.h + BalsaStudySelectionDialog.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h @@ -237,9 +237,10 @@ AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationWidgetParentEnum.h AnnotationWidthHeightWidget.h -BalsaDatabaseStudyTitleDialog.h BalsaDatabaseManager.h BalsaDatabaseUploadSceneFileDialog.h +BalsaStudySelectionDialog.h +BalsaStudyInformation.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h @@ -442,8 +443,9 @@ AnnotationTextOrientationWidget.cxx AnnotationWidgetParentEnum.cxx AnnotationWidthHeightWidget.cxx BalsaDatabaseManager.cxx -BalsaDatabaseStudyTitleDialog.cxx BalsaDatabaseUploadSceneFileDialog.cxx +BalsaStudyInformation.cxx +BalsaStudySelectionDialog.cxx BorderEditingSelectionDialog.cxx BorderFileSplitDialog.cxx BorderOptimizeDialog.cxx diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 063e59382..a41016fdd 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1035,7 +1035,7 @@ SceneDialog::zipSceneFileButtonClicked() * Index of item selected. */ void -SceneDialog::sceneFileSelected(int index) +SceneDialog::sceneFileSelected(int /*index*/) { loadScenesIntoDialog(NULL); -- GitLab From d07e064c49a0762db6914d7f3e1d5d85fc069e71 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 26 May 2017 17:09:43 -0500 Subject: [PATCH 150/755] try to fix travis build on older qt5, improve build setup to use qt5 and c++11 by default --- .travis.yml | 2 +- src/CMakeLists.txt | 23 +++++++++++++++++++---- src/GuiQt/BalsaStudyInformation.cxx | 4 ++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42a77a6e4..18823adfe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,6 @@ before_install: - cd ../build script: - - cmake -D CMAKE_CXX_FLAGS="-std=c++11 -Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr -D WORKBENCH_USE_QT5=TRUE ../workbench/src + - cmake -D CMAKE_CXX_FLAGS="-Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src - make -j 4 - ctest diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 644c697d1..0c5476249 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,7 @@ set (WORKBENCH_QT5_DISABLE_DEPRECATED FALSE CACHE BOOL "If TRUE, use of Qt 5 deprecated functionality will cause compiler to fail") set (WORKBENCH_USE_CMAKE_AUTOMOC FALSE CACHE BOOL "If TRUE, use CMAKE_AUTOMOC command for generating 'moc' files") -set (WORKBENCH_USE_QT5 FALSE CACHE BOOL +set (WORKBENCH_USE_QT5 TRUE CACHE BOOL "If TRUE, require Qt5, else Qt4.Specify as argument to cmake: -DWORKBENCH_USE_QT5=TRUE") set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "With Qt5, QOpenGLWidget instead of deprecated QGLWidget") @@ -122,8 +122,7 @@ ENDIF (NOT MSVC) # If GNU compiler, use SIMD-based dot computation, if possible # SET(SIMD_RESULT "Search for SIMD disabled for compiler on this system.") -if (CMAKE_COMPILER_IS_GNUCC - OR CLANG_FLAG) +if (CMAKE_COMPILER_IS_GNUCC OR CLANG_FLAG) # # Define flag to avoid trying to compile SIMD stuff (coded for x86 only) # @@ -149,7 +148,23 @@ if (CMAKE_COMPILER_IS_GNUCC ELSE (WORKBENCH_USE_SIMD) SET(SIMD_RESULT "Search for SIMD disabled, WORKBENCH_USE_SIMD=FALSE") ENDIF (WORKBENCH_USE_SIMD) -endif() +endif(CMAKE_COMPILER_IS_GNUCC OR CLANG_FLAG) + +#TSC: we require c++11, so it needs to be in the compile flags - in older cmake, this needs to be done manually +IF (${CMAKE_VERSION} VERSION_LESS "3.1") + IF (CMAKE_COMPILER_IS_GNUCC) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" GCC_STD11) + IF (${GCC_STD11}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + ELSE (${GCC_STD11}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + ENDIF (${GCC_STD11}) + ENDIF (CMAKE_COMPILER_IS_GNUCC) +ELSE (${CMAKE_VERSION} VERSION_LESS "3.1") + SET(CMAKE_CXX_STANDARD 11) + SET(CMAKE_CXX_STANDARD_REQUIRED TRUE) +ENDIF (${CMAKE_VERSION} VERSION_LESS "3.1") ########################################################################################## # diff --git a/src/GuiQt/BalsaStudyInformation.cxx b/src/GuiQt/BalsaStudyInformation.cxx index bfc93f33b..e27fa2cda 100644 --- a/src/GuiQt/BalsaStudyInformation.cxx +++ b/src/GuiQt/BalsaStudyInformation.cxx @@ -73,8 +73,8 @@ BalsaStudyInformation::BalsaStudyInformation(const QJsonObject& jsonObject) QJsonObject::const_iterator titleIter = jsonObject.find("title"); if ((idIter != jsonObject.end()) && (titleIter != jsonObject.end())) { - m_studyID = idIter->toString(); - m_studyTitle = titleIter->toString(); + m_studyID = (*idIter).toString(); + m_studyTitle = (*titleIter).toString(); } } -- GitLab From 3f1a0700f2a18ae5398a1347d02eb04b29647380 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 26 May 2017 17:26:29 -0500 Subject: [PATCH 151/755] another edit for older qt --- src/GuiQt/BalsaStudySelectionDialog.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/BalsaStudySelectionDialog.cxx b/src/GuiQt/BalsaStudySelectionDialog.cxx index d5646ef9d..1e0bc4ce7 100644 --- a/src/GuiQt/BalsaStudySelectionDialog.cxx +++ b/src/GuiQt/BalsaStudySelectionDialog.cxx @@ -156,11 +156,11 @@ BalsaStudySelectionDialog::loadStudyTitleTableWidget(const AString selectedStudy CaretAssertVectorIndex(m_studyInformation, iRow); QTableWidgetItem* idItem = new QTableWidgetItem(m_studyInformation[iRow].getStudyID()); - idItem->setFlags(idItem->flags().setFlag(Qt::ItemIsEditable, false)); + idItem->setFlags(idItem->flags() &= (~Qt::ItemIsEditable)); m_studyTableWidget->setItem(iRow, COLUMN_ID, idItem); QTableWidgetItem* titleItem = new QTableWidgetItem(studyTitle); - titleItem->setFlags(idItem->flags().setFlag(Qt::ItemIsEditable, false)); + titleItem->setFlags(idItem->flags() &= (~Qt::ItemIsEditable)); m_studyTableWidget->setItem(iRow, COLUMN_TITLE, titleItem); } -- GitLab From 76db6ea394cb816bc44dba64477fe49d337f8369 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 May 2017 09:40:11 -0500 Subject: [PATCH 152/755] Removed the CaretJsonObject class and replaced its usage with Qt's Json classes. --- src/Common/CMakeLists.txt | 2 - src/Common/CaretJsonObject.cxx | 214 ----------------------------- src/Common/CaretJsonObject.h | 71 ---------- src/GuiQt/BalsaDatabaseManager.cxx | 51 ++++++- 4 files changed, 44 insertions(+), 294 deletions(-) delete mode 100644 src/Common/CaretJsonObject.cxx delete mode 100644 src/Common/CaretJsonObject.h diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 8537fb8d3..e8e776642 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -68,7 +68,6 @@ CaretException.h CaretFunctionName.h CaretHeap.h CaretHttpManager.h -CaretJsonObject.h CaretLogger.h CaretMathExpression.h CaretMutex.h @@ -173,7 +172,6 @@ CaretColorEnum.cxx CaretCommandLine.cxx CaretException.cxx CaretHttpManager.cxx -CaretJsonObject.cxx CaretLogger.cxx CaretMathExpression.cxx CaretObject.cxx diff --git a/src/Common/CaretJsonObject.cxx b/src/Common/CaretJsonObject.cxx deleted file mode 100644 index a1a4c77df..000000000 --- a/src/Common/CaretJsonObject.cxx +++ /dev/null @@ -1,214 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#define __CARET_JSON_OBJECT_DECLARE__ -#include "CaretJsonObject.h" -#undef __CARET_JSON_OBJECT_DECLARE__ - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "MathFunctions.h" - -using namespace caret; - -static bool debugFlag = false; - -/** - * \class caret::CaretJsonObject - * \brief Supports parsing of simple json object consisting of key/value pairs until Qt 5 available. - * \ingroup Common - * - * Supports parsing of simple json object consisting of key/value pairs as - * returned by BALSA database. Some of API is based upon Qt5's QJsonObject. - */ - -/** - * Constructor that splits the given text into key/value pairs. - * - * Example: {"written":false,"fileName":"balsa_upload_to_balsa_dot_wustl_dot_edu-1.zip", - * "status":500, - * "statusText":"RB6l/balsa_upload_to_balsa_dot_wustl_dot_edu-1.zip (No such file or directory)"} - * - * @param jsonText - * Text containing a JSON object. - */ -CaretJsonObject::CaretJsonObject(const AString& jsonText) -: CaretObject() -{ - AString text(jsonText); - const int32_t firstBracket = text.indexOf("{"); - const int32_t lastBracket = text.lastIndexOf("}"); - - if ((firstBracket >= 0) - && (lastBracket > (firstBracket + 3))) { - const int32_t startIndex = firstBracket + 1; - const int32_t len = lastBracket - startIndex; - text = text.mid(startIndex, len); - if (debugFlag) std::cout << "Brackets removed: " << text << std::endl; - } - else { - CaretLogInfo("JSON missing opening and closing brackets."); - return; - } - - /* - * Iterate through string looking for commas. - * Note: Need to avoid commas in name value strings in double quotes) - */ - const int32_t textLen = text.length(); - std::vector commas; - int32_t doubleQuoteCounter = 0; - int32_t lastComma = -1; - for (int32_t i = 0; i < textLen; i++) { - const QChar ch = text[i]; - if (ch == ',') { - if ( ! MathFunctions::isOddNumber(doubleQuoteCounter)) { - const int32_t start = lastComma + 1; - const int32_t len = i - start; - const AString nameValuePair = text.mid(start, len); - if (debugFlag) std::cout << "Name/Value pair: " << nameValuePair << std::endl; - processNameValueString(nameValuePair); - lastComma = i; - } - } - else if (ch == '\"') { - doubleQuoteCounter++; - } - } - if ( ! MathFunctions::isOddNumber(doubleQuoteCounter)) { - const int32_t start = lastComma + 1; - const int32_t len = textLen - start; - if (len > 2) { - const AString nameValuePair = text.mid(start, len); - if (debugFlag) std::cout << "Name/Value pair: " << nameValuePair << std::endl; - processNameValueString(nameValuePair); - } - } -} - -/** - * Destructor. - */ -CaretJsonObject::~CaretJsonObject() -{ -} - -/** - * Process a name value string by splitting into name and value. - * - * @param nameValueString - * Name value string that is split, ie: "fileName":"balsa_upload_to_balsa_dot_wustl_dot_edu-1.zip" - */ -void -CaretJsonObject::processNameValueString(const AString& nameValueString) -{ - const int32_t colonIndex = nameValueString.indexOf(":"); - if (colonIndex > 0) { - AString name = nameValueString.left(colonIndex).trimmed(); - AString value = nameValueString.mid(colonIndex + 1).trimmed(); - - trimLeadingTrailingDoubleQuotes(name); - trimLeadingTrailingDoubleQuotes(value); - - m_data.insert(std::make_pair(name, value)); - - if (debugFlag) std::cout << " " << name << " -> " << value << std::endl; - } -} - -/** - * Trim the leading and trailing quotes from the given text. - * - * @param text - * In/Out text that has any leading and/or trailing quotes removed. - */ -void -CaretJsonObject::trimLeadingTrailingDoubleQuotes(AString& text) -{ - if (text.endsWith("\"")) { - text.resize(text.size() - 1); - } - if (text.startsWith("\"")) { - text = text.mid(1); - } -} - -/** - * @return Number of key/value pairs. - */ -int32_t -CaretJsonObject::count() const -{ - return m_data.size(); -} - -/** - * @return True if no key/value pairs. - */ -bool -CaretJsonObject::empty() const -{ - return m_data.empty(); -} - -/** - * @return The keys. - */ -std::vector -CaretJsonObject::keys() const -{ - std::vector keysOut; - - for (std::map::const_iterator iter = m_data.begin(); - iter != m_data.end(); - iter++) { - keysOut.push_back(iter->first); - } - - return keysOut; -} - -/** - * @return True if the key exists. - */ -bool -CaretJsonObject::hasKey(const AString& key) const -{ - const std::map::const_iterator iter = m_data.find(key); - return (iter != m_data.end()); -} - -/** - * @return Value for the given key. Empty string if key is missing. - */ -AString -CaretJsonObject::value(const AString& key) const -{ - const std::map::const_iterator iter = m_data.find(key); - if (iter != m_data.end()) { - return iter->second; - } - - return ""; -} - diff --git a/src/Common/CaretJsonObject.h b/src/Common/CaretJsonObject.h deleted file mode 100644 index 924042810..000000000 --- a/src/Common/CaretJsonObject.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __CARET_JSON_OBJECT_H__ -#define __CARET_JSON_OBJECT_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#include "CaretObject.h" - - - -namespace caret { - - class CaretJsonObject : public CaretObject { - - public: - CaretJsonObject(const AString& jsonText); - - virtual ~CaretJsonObject(); - - int32_t count() const; - - bool empty() const; - - std::vector keys() const; - - bool hasKey(const AString& key) const; - - AString value(const AString& key) const; - - // ADD_NEW_METHODS_HERE - - private: - CaretJsonObject(const CaretJsonObject&); - - CaretJsonObject& operator=(const CaretJsonObject&); - - void processNameValueString(const AString& nameValueString); - - void trimLeadingTrailingDoubleQuotes(AString& text); - - std::map m_data; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __CARET_JSON_OBJECT_DECLARE__ - // -#endif // __CARET_JSON_OBJECT_DECLARE__ - -} // namespace -#endif //__CARET_JSON_OBJECT_H__ diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 34b32d0ea..b37965174 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -30,7 +30,6 @@ #include "CaretAssert.h" #include "CaretHttpManager.h" -#include "CaretJsonObject.h" #include "CaretLogger.h" #include "CommandOperationManager.h" #include "EventManager.h" @@ -333,12 +332,51 @@ BalsaDatabaseManager::processUploadResponse(const std::map& re std::cout << std::endl << "RESPONSE CONTENT: " << responseContent << std::endl << std::endl; } - CaretJsonObject json(responseContent); + + + AString statusText; + { + QJsonParseError jsonError; + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + &jsonError); + if (jsonDocument.isNull()) { + errorMessageOut = ("Process upload response failed. Failed to parse JSON, error:" + + jsonError.errorString()); + return false; + } + + QByteArray json = jsonDocument.toJson(); + if (m_debugFlag) { + std::cout << "Array?: " << jsonDocument.isArray() << std::endl; + std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; + std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; + std::cout << "Object?: " << jsonDocument.isObject() << std::endl; + std::cout << "JSON length: " << json.size() << std::endl; + AString str(json); + std::cout << ("Formatted JSON:\n" + str) << std::endl; + } + + if ( ! jsonDocument.isObject()) { + errorMessageOut = ("Process upload response failed. JSON content is not an object." + "JSON is displayed in terminal if logging level is warning or higher."); + CaretLogWarning("Study ID JSON is not Object\n" + + AString(jsonDocument.toJson())); + return false; + } + + QJsonObject responseObject = jsonDocument.object(); + const QJsonValue statusValue = responseObject.value("statusText"); + if (statusValue.type() == QJsonValue::String) { + statusText = statusValue.toString(); + } + if (m_debugFlag) { + std::cout << "Status Text: " << statusText << std::endl; + } + } if (responseHttpCode != 200) { - AString msg = json.value("statusText"); - if ( ! msg.isEmpty()) { - contentErrorMessage.insert(0, msg + "\n"); + if ( ! statusText.isEmpty()) { + contentErrorMessage.insert(0, statusText + "\n"); } errorMessageOut = ("Upload failed. Http Code=" @@ -349,7 +387,7 @@ BalsaDatabaseManager::processUploadResponse(const std::map& re } if ( ! haveJsonResponseContentFlag) { - errorMessageOut = (contentErrorMessage); + errorMessageOut = contentErrorMessage; return false; } @@ -795,7 +833,6 @@ BalsaDatabaseManager::getAllStudyInformationForUser(const AString& databaseURL, } AString contentType = getHeaderValue(idResponse, "Content-Type"); - //AString contentType = idResponse.getHeaderValue("Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting all study information failed. Content type returned by BALSA is unknown"); return false; -- GitLab From c0d3a0be3cb5b13abcbb952ec63963c0a8550be6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 May 2017 09:43:50 -0500 Subject: [PATCH 153/755] If the base directory is empty when the Upload Scene File to Balsa dialog is displayed, default the base directory to the directory containing the scene file. --- src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 743acaecd..4ed33f315 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -322,7 +322,12 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); - m_baseDirectoryLineEdit->setText(m_sceneFile->getBalsaBaseDirectory()); + AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); + if (baseDirectory.isEmpty()) { + FileInformation fileInfo(m_sceneFile->getFileName()); + baseDirectory = fileInfo.getPathName(); + } + m_baseDirectoryLineEdit->setText(baseDirectory); m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); m_extractDirectoryNameLineEdit->setText(m_sceneFile->getBalsaExtractToDirectoryName()); -- GitLab From 8951f7eccbad8cfed5bbd65323cd1c70fa536d0b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 May 2017 10:34:41 -0500 Subject: [PATCH 154/755] Resolve WB-687 Tab highlight square not maximally foreground: Highlight box was drawn at Z=0 with depth testing enabled which can be 'under' volume slices (e.g.: axial view with slice Z greater than zero). Fixed by disabling depth test when highlight box is drawn. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 147 ++++++++++++++----------- src/Brain/BrainOpenGLFixedPipeline.h | 4 + 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index ce4b54e53..2542a62d8 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -601,68 +601,9 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, * in Tile Tabs when user selects a tab. */ if (vpContent->isTabHighlighted()) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); -// const float width = windowViewport[2]; -// const float height = windowViewport[3]; - const float width = m_tabViewport[2]; - const float height = m_tabViewport[3]; - glOrtho(0.0, width, 0.0, height, -100.0, 100.0); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glColor3fv(m_foregroundColorFloat); - - const float thickness = 10; - - /* - * Left Side - */ - glBegin(GL_QUADS); - glVertex3f(0.0, 0.0, 0.0); - glVertex3f(thickness, 0.0, 0.0); - glVertex3f(thickness, height, 0.0); - glVertex3f(0.0, height, 0.0); - glEnd(); - - /* - * Right Side - */ - glBegin(GL_QUADS); - glVertex3f(width - thickness, 0.0, 0.0); - glVertex3f(width, 0.0, 0.0); - glVertex3f(width, height, 0.0); - glVertex3f(width - thickness, height, 0.0); - glEnd(); - - /* - * Bottom Side - */ - glBegin(GL_QUADS); - glVertex3f(0.0, 0.0, 0.0); - glVertex3f(width, 0.0, 0.0); - glVertex3f(width, thickness, 0.0); - glVertex3f(0.0, thickness, 0.0); - glEnd(); - - /* - * Top Side - */ - glBegin(GL_QUADS); - glVertex3f(0.0, height - thickness, 0.0); - glVertex3f(width, height - thickness, 0.0); - glVertex3f(width, height, 0.0); - glVertex3f(0.0, height, 0.0); - glEnd(); - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); + drawTabHighlighting(m_tabViewport[2], + m_tabViewport[3], + m_foregroundColorFloat); } } @@ -707,6 +648,88 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, m_brain = NULL; } +/** + * Draw a box to highlight a selected tab. + * + * @param width + * Width of tab. + * @param height + * Height of tab. + * @param rgb + * RGB color components for the 'frame' drawn around the tab. + */ +void +BrainOpenGLFixedPipeline::drawTabHighlighting(const float width, + const float height, + const float rgb[3]) +{ + const bool depthFlag = glIsEnabled(GL_DEPTH_TEST); + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0, width, 0.0, height, -100.0, 100.0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glColor3fv(rgb); + + const float thickness = 10; + + /* + * Left Side + */ + glBegin(GL_QUADS); + glVertex3f(0.0, 0.0, 0.0); + glVertex3f(thickness, 0.0, 0.0); + glVertex3f(thickness, height, 0.0); + glVertex3f(0.0, height, 0.0); + glEnd(); + + /* + * Right Side + */ + glBegin(GL_QUADS); + glVertex3f(width - thickness, 0.0, 0.0); + glVertex3f(width, 0.0, 0.0); + glVertex3f(width, height, 0.0); + glVertex3f(width - thickness, height, 0.0); + glEnd(); + + /* + * Bottom Side + */ + glBegin(GL_QUADS); + glVertex3f(0.0, 0.0, 0.0); + glVertex3f(width, 0.0, 0.0); + glVertex3f(width, thickness, 0.0); + glVertex3f(0.0, thickness, 0.0); + glEnd(); + + /* + * Top Side + */ + glBegin(GL_QUADS); + glVertex3f(0.0, height - thickness, 0.0); + glVertex3f(width, height - thickness, 0.0); + glVertex3f(width, height, 0.0); + glVertex3f(0.0, height, 0.0); + glEnd(); + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + + if (depthFlag) { + glEnable(GL_DEPTH_TEST); + } +} + /** * Draw the tab annotations. * diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 75c6a9c4c..3934f166a 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -507,6 +507,10 @@ namespace caret { void setAnnotationColorBarsForDrawing(std::vector& viewportContents); + void drawTabHighlighting(const float width, + const float height, + const float rgb[3]); + /** Index of window */ const int32_t m_windowIndex; -- GitLab From 413e108fcf37acc1439d6d66ec1af3d29bcb1eb9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 May 2017 15:17:43 -0500 Subject: [PATCH 155/755] Resolve WB-684 Annotation arrow orientation during drawing: When creating a line annotation with one arrow enabled, the arrow was appearing at the wrong end (when dragging the mouse the start arrow was at the end of the line where the mouse was released). Now start arrow appears at the location where the mouse is pressed. Also, the Arrow buttons in the Line section of the toolbar were updated so that their on/off status is visible (background is darker when enabled on Mac). --- src/GuiQt/AnnotationCoordinateInformation.cxx | 8 +- src/GuiQt/AnnotationCreateDialog.cxx | 75 ++++++- src/GuiQt/AnnotationLineArrowTipsWidget.cxx | 199 +++++++++++++++--- src/GuiQt/AnnotationLineArrowTipsWidget.h | 15 +- 4 files changed, 257 insertions(+), 40 deletions(-) diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index 2d1234b71..b1cf8f892 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -493,11 +493,13 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; + endCoordinate->setXYZ(xyz); } else { xyz[1] += 25.0; + endCoordinate->setXYZ(coordInfoOne->m_tabXYZ); + startCoordinate->setXYZ(xyz); } - endCoordinate->setXYZ(xyz); } } break; @@ -524,11 +526,13 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; + endCoordinate->setXYZ(xyz); } else { xyz[1] += 25.0; + endCoordinate->setXYZ(coordInfoOne->m_windowXYZ); + startCoordinate->setXYZ(xyz); } - endCoordinate->setXYZ(xyz); } } break; diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index e177d84df..220ba8abd 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -722,6 +722,66 @@ AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, annotation); } +///** +// * Constructor for information used to create a new annotation. +// * +// * @param mouseEvent +// * The mouse event. +// * @param selectedSpace +// * The space selected by the user. +// * @param annotationType +// * The annotation type. +// * @param useBothCoordinatesFromMouseFlag +// * Use both coords (X/Y and pressed X/Y) +// * @param annotationFile +// * File to which annotation is added. +// */ +//AnnotationCreateDialog::NewAnnotationInfo::NewAnnotationInfo(const MouseEvent& mouseEvent, +// const AnnotationCoordinateSpaceEnum::Enum selectedSpace, +// const AnnotationTypeEnum::Enum annotationType, +// const bool useBothCoordinatesFromMouseFlag, +// AnnotationFile* annotationFile) +//: m_mouseEvent(mouseEvent), +//m_selectedSpace(selectedSpace), +//m_annotationType(annotationType), +//m_annotationFile(annotationFile) +//{ +// CaretAssert(annotationFile); +// +// m_validSpaces.clear(); +// m_coordOneInfo.reset(); +// m_coordTwoInfo.reset(); +// m_coordTwoInfoValid = false; +// m_percentageWidth = -1; +// m_percentageHeight = -1; +// +// AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, +// mouseEvent.getX(), +// mouseEvent.getY(), +// m_coordOneInfo); +// +// if (useBothCoordinatesFromMouseFlag) { +// AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, +// mouseEvent.getPressedX(), +// mouseEvent.getPressedY(), +// m_coordTwoInfo); +// +// AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, +// &m_coordTwoInfo, +// m_validSpaces); +// +// if (isValid()) { +// m_coordTwoInfoValid = true; +// +// processTwoCoordInfo(); +// } +// } +// else { +// AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, +// NULL, +// m_validSpaces); +// } +//} /** * Constructor for information used to create a new annotation. * @@ -755,16 +815,16 @@ m_annotationFile(annotationFile) m_percentageWidth = -1; m_percentageHeight = -1; - AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, - mouseEvent.getX(), - mouseEvent.getY(), - m_coordOneInfo); if (useBothCoordinatesFromMouseFlag) { + AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, + mouseEvent.getX(), + mouseEvent.getY(), + m_coordTwoInfo); AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, mouseEvent.getPressedX(), mouseEvent.getPressedY(), - m_coordTwoInfo); + m_coordOneInfo); AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, &m_coordTwoInfo, @@ -777,6 +837,11 @@ m_annotationFile(annotationFile) } } else { + AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, + mouseEvent.getX(), + mouseEvent.getY(), + m_coordOneInfo); + AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, NULL, m_validSpaces); diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index 5af9f8583..861a2f1e1 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "AnnotationLine.h" @@ -59,33 +60,40 @@ m_browserWindowIndex(browserWindowIndex) { QLabel* label = new QLabel("Line"); - const QSize toolButtonSize(18, 18); - - m_endArrowToolButton = new QToolButton(); - m_endArrowToolButton->setArrowType(Qt::DownArrow); - m_endArrowToolButton->setCheckable(true); - m_endArrowToolButton->setToolTip("Show arrow at line's end coordinate"); - m_endArrowToolButton->setFixedSize(toolButtonSize); - QObject::connect(m_endArrowToolButton, SIGNAL(clicked(bool)), - this, SLOT(endArrowTipActionToggled())); - WuQtUtilities::setToolButtonStyleForQt5Mac(m_endArrowToolButton); - - m_startArrowToolButton = new QToolButton(); - m_startArrowToolButton->setArrowType(Qt::UpArrow); - m_startArrowToolButton->setCheckable(true); - m_startArrowToolButton->setToolTip("Show arrow at line's start coordinate"); - m_startArrowToolButton->setFixedSize(toolButtonSize); - QObject::connect(m_startArrowToolButton, SIGNAL(clicked(bool)), - this, SLOT(startArrowTipActionToggled())); - WuQtUtilities::setToolButtonStyleForQt5Mac(m_startArrowToolButton); + const QSize toolButtonSize(24, 24); //(18, 18); + + + + QToolButton* endArrowToolButton = new QToolButton(); + m_endArrowAction = new QAction(this); + m_endArrowAction->setCheckable(true); + m_endArrowAction->setToolTip("Show arrow at line's end coordinate"); + m_endArrowAction->setIcon(QIcon(createArrowPixmap(endArrowToolButton, ArrowType::DOWN))); + QObject::connect(m_endArrowAction, &QAction::triggered, + this, &AnnotationLineArrowTipsWidget::endArrowTipActionToggled); + //this, [=] { this->endArrowTipActionToggled(); }); + endArrowToolButton->setDefaultAction(m_endArrowAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(endArrowToolButton); + + + QToolButton* startArrowToolButton = new QToolButton(); + m_startArrowAction = new QAction(this); + m_startArrowAction->setCheckable(true); + m_startArrowAction->setToolTip("Show arrow at line's start coordinate"); + m_startArrowAction->setIcon(QIcon(createArrowPixmap(startArrowToolButton, ArrowType::UP))); + QObject::connect(m_startArrowAction, &QAction::triggered, + this, &AnnotationLineArrowTipsWidget::startArrowTipActionToggled); + //this, [=] { this->startArrowTipActionToggled(); }); + startArrowToolButton->setDefaultAction(m_startArrowAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(startArrowToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->addWidget(label, 0, 0, Qt::AlignHCenter); - gridLayout->addWidget(m_startArrowToolButton, + gridLayout->addWidget(startArrowToolButton, 1, 0, Qt::AlignHCenter); - gridLayout->addWidget(m_endArrowToolButton, + gridLayout->addWidget(endArrowToolButton, 2, 0, Qt::AlignHCenter); setSizePolicy(QSizePolicy::Fixed, @@ -136,14 +144,14 @@ AnnotationLineArrowTipsWidget::updateContent(std::vector& annot allEndOnFlag = false; } - m_startArrowToolButton->setChecked(allStartOnFlag); - m_endArrowToolButton->setChecked(allEndOnFlag); + m_startArrowAction->setChecked(allStartOnFlag); + m_endArrowAction->setChecked(allEndOnFlag); if (numLines > 0) { setEnabled(true); - AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowToolButton->isChecked()); - AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowToolButton->isChecked()); + AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowAction->isChecked()); + AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowAction->isChecked()); } else { setEnabled(false); @@ -158,7 +166,7 @@ void AnnotationLineArrowTipsWidget::startArrowTipActionToggled() { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); - undoCommand->setModeLineArrowStart(m_startArrowToolButton->isChecked(), + undoCommand->setModeLineArrowStart(m_startArrowAction->isChecked(), m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); @@ -171,7 +179,7 @@ AnnotationLineArrowTipsWidget::startArrowTipActionToggled() EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowToolButton->isChecked()); + AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowAction->isChecked()); } /** @@ -181,7 +189,7 @@ void AnnotationLineArrowTipsWidget::endArrowTipActionToggled() { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); - undoCommand->setModeLineArrowEnd(m_endArrowToolButton->isChecked(), + undoCommand->setModeLineArrowEnd(m_endArrowAction->isChecked(), m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); @@ -195,5 +203,138 @@ AnnotationLineArrowTipsWidget::endArrowTipActionToggled() EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowToolButton->isChecked()); + AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowAction->isChecked()); +} + +/** + * Create a pixmap for the given arrow type type. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @param arrowType + * The arrow type. + * @return + * Pixmap with icon for the given arrow type. + */ +QPixmap +AnnotationLineArrowTipsWidget::createArrowPixmap(const QWidget* widget, + const ArrowType arrowType) +{ + CaretAssert(widget); + + /* + * Create a small, square pixmap that will contain + * the foreground color around the pixmap's perimeter. + */ + const float width = 24.0; + const float height = 24.0; + QPixmap pixmap(static_cast(width), + static_cast(height)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); + + const bool fillShapeFlag = false; + if (fillShapeFlag) { + QBrush brush = painter->brush(); + brush.setColor(painter->pen().color()); + brush.setStyle(Qt::SolidPattern); + painter->setBrush(brush); + } + + const float percentage = 0.10f; + const float left = width * percentage; + const float right = width * (1.0 - percentage); + const float bottom = height * percentage; + const float top = height * (1.0 - percentage); + const float centerX = width * 0.5; + QPolygonF triangle; + switch (arrowType) { + case ArrowType::DOWN: + triangle.push_back(QPointF(right, top)); + triangle.push_back(QPointF(left, top)); + triangle.push_back(QPointF(centerX, bottom)); + break; + case ArrowType::UP: + triangle.push_back(QPointF(left, bottom)); + triangle.push_back(QPointF(right, bottom)); + triangle.push_back(QPointF(centerX, top)); + break; + } + painter->drawPolygon(triangle); + + return pixmap; + +// switch (annotationType) { +// case AnnotationTypeEnum::BOX: +// painter->drawRect(1, 1, width - 2, height - 2); +// break; +// case AnnotationTypeEnum::COLOR_BAR: +// CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); +// break; +// case AnnotationTypeEnum::IMAGE: +// { +// const int blueAsGray = qGray(25,25,255); +// QColor skyColor(blueAsGray, blueAsGray, blueAsGray); +// +// /* +// * Background (sky) +// */ +// painter->fillRect(pixmap.rect(), skyColor); +// +// const int greenAsGray = qGray(0, 255, 0); +// QColor terrainColor(greenAsGray, greenAsGray, greenAsGray); +// +// /* +// * Terrain +// */ +// painter->setBrush(terrainColor); +// painter->setPen(terrainColor); +// const int w14 = width * 0.25; +// const int h23 = height * 0.667; +// const int h34 = height * 0.75; +// QPolygon terrain; +// terrain.push_back(QPoint(1, height - 1)); +// terrain.push_back(QPoint(width - 1, height - 1)); +// terrain.push_back(QPoint(width - 1, h23)); +// terrain.push_back(QPoint(w14 * 3, h34)); +// terrain.push_back(QPoint(w14 * 2, h23)); +// terrain.push_back(QPoint(w14, h34)); +// terrain.push_back(QPoint(1, h23)); +// terrain.push_back(QPoint(1, height - 1)); +// painter->drawPolygon(terrain); +// +// const int yellowAsGray = qGray(255, 255, 0); +// QColor sunColor(yellowAsGray, yellowAsGray, yellowAsGray); +// +// /* +// * Sun +// */ +// painter->setBrush(sunColor); +// painter->setPen(sunColor); +// const int radius = width * 0.25; +// painter->drawEllipse(width * 0.33, height * 0.33, radius, radius); +// } +// break; +// case AnnotationTypeEnum::LINE: +// painter->drawLine(1, height - 1, width - 1, 1); +// break; +// case AnnotationTypeEnum::OVAL: +// painter->drawEllipse(1, 1, width - 1, height - 1); +// break; +// case AnnotationTypeEnum::TEXT: +// { +// QFont font = painter->font(); +// font.setPixelSize(20); +// painter->setFont(font); +// painter->drawText(pixmap.rect(), +// (Qt::AlignCenter), +// "A"); +// } +// break; +// } +// +// return pixmap; +// } + + diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.h b/src/GuiQt/AnnotationLineArrowTipsWidget.h index dbc0bc584..688f54b5d 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.h +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.h @@ -26,8 +26,6 @@ #include -class QToolButton; - namespace caret { class Annotation; @@ -54,15 +52,24 @@ namespace caret { // ADD_NEW_METHODS_HERE private: + enum class ArrowType { + DOWN, + UP + }; + AnnotationLineArrowTipsWidget(const AnnotationLineArrowTipsWidget&); AnnotationLineArrowTipsWidget& operator=(const AnnotationLineArrowTipsWidget&); + QPixmap createArrowPixmap(const QWidget* widget, + const ArrowType arrowType); + + const int32_t m_browserWindowIndex; - QToolButton* m_startArrowToolButton; + QAction* m_startArrowAction; - QToolButton* m_endArrowToolButton; + QAction* m_endArrowAction; std::vector m_annotations; -- GitLab From 283ea0d3d277111aa1626193809185cd7e1bc622 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 May 2017 15:44:18 -0500 Subject: [PATCH 156/755] Fixed OpenGL error that occurred when user was dragging the mouse to create an annotation image prior to the image being valid. --- .../BrainOpenGLAnnotationDrawingFixedPipeline.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index cb0fc638f..2cd544820 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -2562,6 +2562,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImageBytesWithTexture(DrawnWithOp const int32_t imageWidth, const int32_t imageHeight) { + /* + * Images may be invalid such as when the user is + * dragging the mouse to create an annotation image + */ + if ((imageBytesRGBA == NULL) + || (imageWidth <= 0) + || (imageHeight <= 0)) { + return; + } + m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At beginning of annotation drawImageBytesWithTexture()")); /* -- GitLab From be939d5540cb6fe4f1b9bb5bb0db49629c3bb280 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 6 Jun 2017 16:38:53 -0500 Subject: [PATCH 157/755] add -include-empty option to -cifti-parcellate which makes the output parcels map depend only on the dlabel file --- src/Algorithms/AlgorithmCiftiParcellate.cxx | 321 ++++++++++++++------ src/Algorithms/AlgorithmCiftiParcellate.h | 11 +- 2 files changed, 238 insertions(+), 94 deletions(-) diff --git a/src/Algorithms/AlgorithmCiftiParcellate.cxx b/src/Algorithms/AlgorithmCiftiParcellate.cxx index b07198c99..14c6922e1 100644 --- a/src/Algorithms/AlgorithmCiftiParcellate.cxx +++ b/src/Algorithms/AlgorithmCiftiParcellate.cxx @@ -82,9 +82,16 @@ OperationParameters* AlgorithmCiftiParcellate::getParameters() ret->createOptionalParameter(9, "-only-numeric", "exclude non-numeric values"); + OptionalParameter* emptyOpt = ret->createOptionalParameter(10, "-include-empty", "create parcels for labels that have no vertices or voxels"); + OptionalParameter* emptyValOpt = emptyOpt->createOptionalParameter(1, "-fill-value", "specify value to use in empty parcels (default 0)"); + emptyValOpt->addDoubleParameter(1, "value", "the value to fill empty parcels with"); + OptionalParameter* emptyRoiOpt = emptyOpt->createOptionalParameter(2, "-nonempty-mask-out", "output a matching pscalar file that has 0s in empty parcels, and 1s elsewhere"); + emptyRoiOpt->addCiftiOutputParameter(1, "mask-out", "the output mask file"); + ret->setHelpText( - AString("Each label in the cifti label file will be treated as a parcel, and all rows or columns within the parcel are averaged together to form the output ") + + AString("Each non-empty label (other than the unlabeled key) in the cifti label file will be treated as a parcel, and all rows or columns within the parcel are averaged together to form the output ") + "row or column. " + + "If -include-empty is specified, empty labels will be treated as parcels with no elements, and filled with a constant value. " + CiftiXML::directionFromStringExplanation() + " " + "For dtseries or dscalar, use COLUMN. " + "If you are parcellating a dconn in both directions, parcellating by ROW first will use much less memory.\n\n" + @@ -131,6 +138,23 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog excludeHigh = (float)excludeOpt->getDouble(2); if (!(excludeLow > 0.0f && excludeHigh > 0.0f)) throw AlgorithmException("exclusion sigmas must be positive"); } + OptionalParameter* emptyOpt = myParams->getOptionalParameter(10); + bool includeEmpty = emptyOpt->m_present; + float emptyFillValue = 0.0f; + CiftiFile* emptyMaskOut = NULL; + if (includeEmpty) + { + OptionalParameter* emptyValOpt = emptyOpt->getOptionalParameter(1); + if (emptyValOpt->m_present) + { + emptyFillValue = emptyValOpt->getDouble(1); + } + OptionalParameter* emptyRoiOpt = emptyOpt->getOptionalParameter(2); + if (emptyRoiOpt->m_present) + { + emptyMaskOut = emptyRoiOpt->getOutputCifti(1); + } + } OptionalParameter* spatialWeightOpt = myParams->getOptionalParameter(5); OptionalParameter* ciftiWeightOpt = myParams->getOptionalParameter(6); if (spatialWeightOpt->m_present && ciftiWeightOpt->m_present) @@ -194,19 +218,28 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog *thisWeights = thisStore; } } - AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, leftWeights, rightWeights, cerebWeights, method, excludeLow, excludeHigh, onlyNumeric); + AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, + leftWeights, rightWeights, cerebWeights, + method, excludeLow, excludeHigh, onlyNumeric, + includeEmpty, emptyFillValue, emptyMaskOut); return; } if (ciftiWeightOpt->m_present) { - AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, ciftiWeightOpt->getCifti(1), method, excludeLow, excludeHigh, onlyNumeric); + AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, + ciftiWeightOpt->getCifti(1), + method, excludeLow, excludeHigh, onlyNumeric, + includeEmpty, emptyFillValue, emptyMaskOut); return; } - AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, method, excludeLow, excludeHigh, onlyNumeric); + AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, + method, excludeLow, excludeHigh, onlyNumeric, + includeEmpty, emptyFillValue, emptyMaskOut); } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, - const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric) : AbstractAlgorithm(myProgObj) + const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, + const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -235,7 +268,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -255,6 +288,26 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co ++parcelCounts[parcel]; } } + if (emptyMaskOut != NULL) + { + CiftiXML maskOutXML; + maskOutXML.setNumberOfDimensions(2); + maskOutXML.setMap(CiftiXML::ALONG_COLUMN, outParcelMap); + CiftiScalarsMap maskNameMap; + maskNameMap.setLength(1); + maskNameMap.setMapName(0, "parcel not empty"); + maskOutXML.setMap(CiftiXML::ALONG_ROW, maskNameMap); + emptyMaskOut->setCiftiXML(maskOutXML); + vector emptyMaskData(numParcels, 1.0f); + for (int i = 0; i < numParcels; ++i) + { + if (parcelCounts[i] == 0) + { + emptyMaskData[i] = 0.0f; + } + } + emptyMaskOut->setColumn(emptyMaskData.data(), 0); + } bool isLabel = false; int labelDir = -1; for (int i = 0; i < (int)dims.size(); ++i) @@ -319,7 +372,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable((*iter)[labelDir - 1])->getUnassignedLabelKey(); } else { - scratchOutRow[j] = 0.0f; + scratchOutRow[j] = emptyFillVal;//odd corner case, but probably fine: with nonzero empty fill value and SAMPSTDEV, parcels with only one element get the fill value, but aren't technically empty } } } @@ -411,7 +464,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable(indices[labelDir - 1])->getUnassignedLabelKey(); } } else { - scratchOutRow[j] = 0.0f; + scratchOutRow[j] = emptyFillVal; } } } @@ -424,7 +477,8 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co namespace { void doWeightedParcellation(const CiftiFile* myCiftiIn, const int& direction, CiftiFile* myCiftiOut, const vector& indexToParcel, - const vector >& parcelWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric) + const vector >& parcelWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, + const float& emptyFillVal, CiftiFile* emptyMaskOut) { const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); const CiftiXML& myOutXML = myCiftiOut->getCiftiXML(); @@ -445,7 +499,27 @@ namespace { CaretLogWarning(ReductionEnum::toName(method) + " reduction requested while parcellating label data"); } - int numParcels = myCiftiOut->getCiftiXML().getDimensionLength(direction); + int numParcels = myOutXML.getDimensionLength(direction); + if (emptyMaskOut != NULL) + { + CiftiXML maskOutXML; + maskOutXML.setNumberOfDimensions(2); + maskOutXML.setMap(CiftiXML::ALONG_COLUMN, myOutXML.getParcelsMap(direction)); + CiftiScalarsMap maskNameMap; + maskNameMap.setLength(1); + maskNameMap.setMapName(0, "parcel not empty"); + maskOutXML.setMap(CiftiXML::ALONG_ROW, maskNameMap); + emptyMaskOut->setCiftiXML(maskOutXML); + vector emptyMaskData(numParcels, 1.0f); + for (int i = 0; i < numParcels; ++i) + { + if (parcelWeights[i].size() == 0) + { + emptyMaskData[i] = 0.0f; + } + } + emptyMaskOut->setColumn(emptyMaskData.data(), 0); + } int64_t numCols = myInputXML.getDimensionLength(CiftiXML::ALONG_ROW); vector scratchRow(numCols); if (direction == CiftiXML::ALONG_ROW) @@ -497,7 +571,7 @@ namespace { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable((*iter)[labelDir - 1])->getUnassignedLabelKey(); } else { - scratchOutRow[j] = 0.0f; + scratchOutRow[j] = emptyFillVal; } } } @@ -589,7 +663,7 @@ namespace scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable(indices[labelDir - 1])->getUnassignedLabelKey(); } } else { - scratchOutRow[j] = 0.0f; + scratchOutRow[j] = emptyFillVal; } } } @@ -602,7 +676,8 @@ namespace AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights, const MetricFile* cerebWeights, const ReductionEnum::Enum& method, - const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric): AbstractAlgorithm(myProgObj) + const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, + const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -660,7 +735,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -698,11 +773,12 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } } } - doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric); + doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric, emptyFillVal, emptyMaskOut); } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, - const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric): AbstractAlgorithm(myProgObj) + const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, + const bool& includeEmpty, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); @@ -740,7 +816,7 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co } vector indexToParcel; CiftiXML myOutXML = myInputXML; - CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel); + CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, includeEmpty); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { @@ -759,10 +835,10 @@ AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, co parcelWeights[parcel].push_back(weightCol[j]);//we already tested that the dense mappings matched } } - doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric); + doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric, emptyFillVal, emptyMaskOut); } -CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, vector& indexToParcelOut) +CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, vector& indexToParcelOut, const bool& includeEmpty) { const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); if (myLabelXML.getNumberOfDimensions() != 2 || @@ -772,11 +848,11 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC throw AlgorithmException("AlgorithmCiftiParcellate::parcellateMapping requires a cifti dlabel file as input"); } const CiftiLabelsMap& myLabelsMap = myLabelXML.getLabelsMap(CiftiXML::ALONG_ROW); - const CiftiBrainModelsMap& myDenseMap = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); + const CiftiBrainModelsMap& labelDenseMap = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); CiftiParcelsMap ret; - if (toParcellate.hasVolumeData() && myDenseMap.hasVolumeData()) + if (toParcellate.hasVolumeData() && labelDenseMap.hasVolumeData()) { - if(!toParcellate.getVolumeSpace().matches(myDenseMap.getVolumeSpace())) + if(!toParcellate.getVolumeSpace().matches(labelDenseMap.getVolumeSpace())) { throw AlgorithmException("AlgorithmCiftiParcellate::parcellateMapping requires matching volume space between dlabel and dense mapping to parcellate"); } @@ -786,102 +862,167 @@ CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myC vector labelData(myLabelXML.getDimensionLength(CiftiXML::ALONG_COLUMN)); int unusedKey = myLabelTable->getUnassignedLabelKey(); myCiftiLabel->getColumn(labelData.data(), 0); - map > usedKeys;//the keys from the label table that actually overlap with data in the input file indexToParcelOut.clear(); indexToParcelOut.resize(toParcellate.getLength(), -1); vector surfList = toParcellate.getSurfaceStructureList(); - vector volList = toParcellate.getVolumeStructureList(); - for (int i = 0; i < (int)surfList.size(); ++i) - { - StructureEnum::Enum myStruct = surfList[i]; - if (myDenseMap.hasSurfaceData(myStruct) && toParcellate.hasSurfaceData(myStruct)) + if (includeEmpty) + {//if we include empty, then the dlabel file by itself determines the entire parcel map, ignoring the data map + const vector labelSurfList = labelDenseMap.getSurfaceStructureList(); + const set allLabelKeys = myLabelTable->getKeys(); + map keyToParcel; + int32_t count = 0; + vector parcelList; + for (set::const_iterator iter = allLabelKeys.begin(); iter != allLabelKeys.end(); ++iter) + { + if (*iter != unusedKey) + { + keyToParcel[*iter] = count; + parcelList.push_back(CiftiParcelsMap::Parcel()); + parcelList.back().m_name = myLabelTable->getLabelName(*iter); + ++count; + } + } + for (int i = 0; i < (int)labelSurfList.size(); ++i) + { + StructureEnum::Enum myStruct = labelSurfList[i]; + if (labelDenseMap.hasSurfaceData(myStruct) && toParcellate.hasSurfaceData(myStruct)) + {//if they don't match in vertex count but one is empty, don't error? + if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) + { + throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); + } + } + ret.addSurface(labelDenseMap.getSurfaceNumberOfNodes(myStruct), myStruct); + vector labelSurfMap = labelDenseMap.getSurfaceMap(myStruct); + for (int64_t j = 0; j < (int64_t)labelSurfMap.size(); ++j) + { + int labelKey = (int)floor(labelData[labelSurfMap[j].m_ciftiIndex] + 0.5f); + map::iterator found = keyToParcel.find(labelKey);//could be unlabeled, or wild key value + if (found != keyToParcel.end()) + { + int32_t whichParcel = found->second; + parcelList[whichParcel].m_surfaceNodes[myStruct].insert(labelSurfMap[j].m_surfaceNode); + int64_t dataIndex = toParcellate.getIndexForNode(labelSurfMap[j].m_surfaceNode, myStruct); + if (dataIndex != -1) + { + indexToParcelOut[dataIndex] = whichParcel; + } + } + } + } + const vector labelVolMap = labelDenseMap.getFullVolumeMap(); + for (int64_t i = 0; i < (int64_t)labelVolMap.size(); ++i) { - if (myDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) + int labelKey = (int)floor(labelData[labelVolMap[i].m_ciftiIndex] + 0.5f); + map::iterator found = keyToParcel.find(labelKey);//could be unlabeled, or wild key value + if (found != keyToParcel.end()) { - throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); + int32_t whichParcel = found->second; + parcelList[whichParcel].m_voxelIndices.insert(labelVolMap[i].m_ijk); + int64_t dataIndex = toParcellate.getIndexForVoxel(labelVolMap[i].m_ijk); + if (dataIndex != -1) + { + indexToParcelOut[dataIndex] = whichParcel; + } } - ret.addSurface(toParcellate.getSurfaceNumberOfNodes(myStruct), myStruct); - vector surfMap = toParcellate.getSurfaceMap(myStruct); - int64_t mapSize = (int64_t)surfMap.size(); - for (int64_t j = 0; j < mapSize; ++j) + } + for (int i = 0; i < (int)parcelList.size(); ++i) + { + ret.addParcel(parcelList[i]); + } + } else { + map > usedKeys;//the keys from the label table that actually overlap with data in the input file + for (int i = 0; i < (int)surfList.size(); ++i) + { + StructureEnum::Enum myStruct = surfList[i]; + if (labelDenseMap.hasSurfaceData(myStruct) && toParcellate.hasSurfaceData(myStruct)) { - int64_t labelIndex = myDenseMap.getIndexForNode(surfMap[j].m_surfaceNode, myStruct); - if (labelIndex != -1) + if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) { - int labelKey = (int)floor(labelData[labelIndex] + 0.5f); - if (labelKey != unusedKey) + throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); + } + ret.addSurface(toParcellate.getSurfaceNumberOfNodes(myStruct), myStruct); + vector surfMap = toParcellate.getSurfaceMap(myStruct); + int64_t mapSize = (int64_t)surfMap.size(); + for (int64_t j = 0; j < mapSize; ++j) + { + int64_t labelIndex = labelDenseMap.getIndexForNode(surfMap[j].m_surfaceNode, myStruct); + if (labelIndex != -1) { - int tempVal = -1; - map >::iterator iter = usedKeys.find(labelKey); - if (iter == usedKeys.end()) + int labelKey = (int)floor(labelData[labelIndex] + 0.5f); + if (labelKey != unusedKey) { - const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); - if (myLabel != NULL)//ignore values that aren't in the label table + int tempVal = -1; + map >::iterator iter = usedKeys.find(labelKey); + if (iter == usedKeys.end()) { - tempVal = usedKeys.size(); - CiftiParcelsMap::Parcel tempParcel; - tempParcel.m_name = myLabel->getName(); + const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); + if (myLabel != NULL)//ignore values that aren't in the label table + { + tempVal = usedKeys.size(); + CiftiParcelsMap::Parcel tempParcel; + tempParcel.m_name = myLabel->getName(); + tempParcel.m_surfaceNodes[myStruct].insert(surfMap[j].m_surfaceNode); + usedKeys[labelKey] = pair(tempParcel, tempVal); + } + } else { + tempVal = iter->second.second; + CiftiParcelsMap::Parcel& tempParcel = iter->second.first; tempParcel.m_surfaceNodes[myStruct].insert(surfMap[j].m_surfaceNode); - usedKeys[labelKey] = pair(tempParcel, tempVal); } - } else { - tempVal = iter->second.second; - CiftiParcelsMap::Parcel& tempParcel = iter->second.first; - tempParcel.m_surfaceNodes[myStruct].insert(surfMap[j].m_surfaceNode); + indexToParcelOut[surfMap[j].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } - indexToParcelOut[surfMap[j].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } } } } - } - vector volMap = toParcellate.getFullVolumeMap(); - int64_t mapSize = (int64_t)volMap.size(); - for (int64_t i = 0; i < mapSize; ++i) - { - int64_t labelIndex = myDenseMap.getIndexForVoxel(volMap[i].m_ijk); - if (labelIndex != -1) + vector volMap = toParcellate.getFullVolumeMap(); + for (int64_t i = 0; i < (int64_t)volMap.size(); ++i) { - int labelKey = (int)floor(labelData[labelIndex] + 0.5f); - if (labelKey != unusedKey) + int64_t labelIndex = labelDenseMap.getIndexForVoxel(volMap[i].m_ijk); + if (labelIndex != -1) { - int tempVal = -1; - map >::iterator iter = usedKeys.find(labelKey); - if (iter == usedKeys.end()) + int labelKey = (int)floor(labelData[labelIndex] + 0.5f); + if (labelKey != unusedKey) { - const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); - if (myLabel != NULL)//ignore values that aren't in the label table + int tempVal = -1; + map >::iterator iter = usedKeys.find(labelKey); + if (iter == usedKeys.end()) { - tempVal = usedKeys.size(); - CiftiParcelsMap::Parcel tempParcel; - tempParcel.m_name = myLabel->getName(); + const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); + if (myLabel != NULL)//ignore values that aren't in the label table + { + tempVal = usedKeys.size(); + CiftiParcelsMap::Parcel tempParcel; + tempParcel.m_name = myLabel->getName(); + tempParcel.m_voxelIndices.insert(VoxelIJK(volMap[i].m_ijk)); + usedKeys[labelKey] = pair(tempParcel, tempVal); + } + } else { + tempVal = iter->second.second; + CiftiParcelsMap::Parcel& tempParcel = iter->second.first; tempParcel.m_voxelIndices.insert(VoxelIJK(volMap[i].m_ijk)); - usedKeys[labelKey] = pair(tempParcel, tempVal); } - } else { - tempVal = iter->second.second; - CiftiParcelsMap::Parcel& tempParcel = iter->second.first; - tempParcel.m_voxelIndices.insert(VoxelIJK(volMap[i].m_ijk)); + indexToParcelOut[volMap[i].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } - indexToParcelOut[volMap[i].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } } - } - int numParcels = (int)usedKeys.size(); - vector valRemap(numParcels, -1); - int count = 0; - for (map >::const_iterator iter = usedKeys.begin(); iter != usedKeys.end(); ++iter) - { - valRemap[iter->second.second] = count;//build a lookup from temp values to label key rank - ret.addParcel(iter->second.first); - ++count; - } - int64_t lookupSize = (int64_t)indexToParcelOut.size(); - for (int64_t i = 0; i < lookupSize; ++i)//finally, remap the temporary values to the key order of the labels - { - if (indexToParcelOut[i] != -1) + int numParcels = (int)usedKeys.size(); + vector valRemap(numParcels, -1); + int count = 0; + for (map >::const_iterator iter = usedKeys.begin(); iter != usedKeys.end(); ++iter) { - indexToParcelOut[i] = valRemap[indexToParcelOut[i]]; + valRemap[iter->second.second] = count;//build a lookup from temp values to label key rank + ret.addParcel(iter->second.first); + ++count; + } + int64_t lookupSize = (int64_t)indexToParcelOut.size(); + for (int64_t i = 0; i < lookupSize; ++i)//finally, remap the temporary values to the key order of the labels + { + if (indexToParcelOut[i] != -1) + { + indexToParcelOut[i] = valRemap[indexToParcelOut[i]]; + } } } return ret; diff --git a/src/Algorithms/AlgorithmCiftiParcellate.h b/src/Algorithms/AlgorithmCiftiParcellate.h index 3d8d5e83d..5d2771ae6 100644 --- a/src/Algorithms/AlgorithmCiftiParcellate.h +++ b/src/Algorithms/AlgorithmCiftiParcellate.h @@ -38,15 +38,18 @@ namespace caret { public: AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const ReductionEnum::Enum& method = ReductionEnum::MEAN, - const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false); + const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, + const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights = NULL, const MetricFile* cerebWeights = NULL, const ReductionEnum::Enum& method = ReductionEnum::MEAN, - const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false); + const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, + const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method = ReductionEnum::MEAN, - const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false); - static CiftiParcelsMap parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, std::vector& indexToParcelOut); + const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, + const bool& includeEmpty = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); + static CiftiParcelsMap parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, std::vector& indexToParcelOut, const bool& includeEmpty = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); -- GitLab From fad7d761908c19f20bd0522a19437a7681f9964e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 14 Jun 2017 21:05:25 -0500 Subject: [PATCH 158/755] make errors on closing nifti files throw an error instead of a severe log --- src/Cifti/CiftiFile.cxx | 36 +++++++++++++++++++++++++--------- src/Cifti/CiftiFile.h | 2 ++ src/Commands/CommandParser.cxx | 1 + src/Files/VolumeFile.cxx | 1 + 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index 23c1f6d59..6caac94ae 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -51,6 +51,7 @@ namespace bool isSwapped() const { return m_nifti.getHeader().isSwapped(); } void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index); + void close(); }; class CiftiMemoryImpl : public CiftiFile::WriteImplInterface @@ -115,9 +116,7 @@ CiftiFile::CiftiFile(const QString& fileName) void CiftiFile::openFile(const QString& fileName) { - m_writingImpl.grabNew(NULL); - m_readingImpl.grabNew(NULL);//to make sure it closes everything first, even if the open throws - m_dims.clear(); + close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiOnDiskImpl(FileInformation(fileName).getAbsoluteFilePath()));//this constructor opens existing file read-only m_readingImpl = newRead;//it should be noted that if the constructor throws (if the file isn't readable), new guarantees the memory allocated for the object will be freed m_xml = newRead->getCiftiXML(); @@ -128,9 +127,7 @@ void CiftiFile::openFile(const QString& fileName) void CiftiFile::openURL(const QString& url, const QString& user, const QString& pass) { - m_writingImpl.grabNew(NULL); - m_readingImpl.grabNew(NULL);//to make sure it closes everything first, even if the open throws - m_dims.clear(); + close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiXnatImpl(url, user, pass)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); @@ -140,9 +137,7 @@ void CiftiFile::openURL(const QString& url, const QString& user, const QString& void CiftiFile::openURL(const QString& url) { - m_writingImpl.grabNew(NULL); - m_readingImpl.grabNew(NULL);//to make sure it closes everything first, even if the open throws - m_dims.clear(); + close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiXnatImpl(url)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); @@ -209,6 +204,23 @@ void CiftiFile::writeFile(const QString& fileName, const CiftiVersion& writingVe m_xml.clearMutablesModified(); } +void CiftiFile::close() +{ + if (m_writingImpl != NULL) + { + m_writingImpl->close();//only writing implementations should ever throw errors on close, and specifically only on-disk + } + m_writingImpl.grabNew(NULL); + m_readingImpl.grabNew(NULL); + m_dims.clear(); + m_xml = CiftiXML(); + m_writingFile = ""; + m_fileName = ""; + m_onDiskVersion = CiftiVersion();//for completeness, it gets reset on open anyway + m_endianPref = NATIVE;//reset things to defaults + setWritingDataTypeNoScaling();//default argument is float32 +} + void CiftiFile::convertToInMemory() { if (isInMemory()) return; @@ -640,6 +652,12 @@ CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, c m_xml = xml; } +void CiftiOnDiskImpl::close() +{ + m_nifti.close();//lets this throw when there is a writing problem +}//don't bother resetting m_xml, this instance is about to be destroyed + + void CiftiOnDiskImpl::getRow(float* dataOut, const vector& indexSelect, const bool& tolerateShortRead) const { m_nifti.readData(dataOut, 5, indexSelect, tolerateShortRead);//5 means 4 reserved (space and time) plus the first cifti dimension diff --git a/src/Cifti/CiftiFile.h b/src/Cifti/CiftiFile.h index 194cea333..62119ff13 100644 --- a/src/Cifti/CiftiFile.h +++ b/src/Cifti/CiftiFile.h @@ -57,6 +57,7 @@ namespace caret void openURL(const QString& url);//same, without user/pass (or curently, reusing existing auth if the server matches void setWritingFile(const QString& fileName, const CiftiVersion& writingVersion = CiftiVersion(), const ENDIAN& endian = NATIVE);//starts on-disk writing void writeFile(const QString& fileName, const CiftiVersion& writingVersion = CiftiVersion(), const ENDIAN& endian = ANY);//leaves current state as-is, rewrites if already writing to that filename and version mismatch + void close();//closes the underlying file to flush it, so that exceptions can be thrown void convertToInMemory(); QString getFileName() const { return m_fileName; } @@ -99,6 +100,7 @@ namespace caret public: virtual void setRow(const float* dataIn, const std::vector& indexSelect) = 0; virtual void setColumn(const float* dataIn, const int64_t& index) = 0; + virtual void close() {} virtual ~WriteImplInterface(); }; private: diff --git a/src/Commands/CommandParser.cxx b/src/Commands/CommandParser.cxx index f1135ad2b..785a28669 100644 --- a/src/Commands/CommandParser.cxx +++ b/src/Commands/CommandParser.cxx @@ -1000,6 +1000,7 @@ void CommandParser::writeOutput(const vector& outAssociation) { CiftiFile* myFile = ((CiftiParameter*)myParam)->m_parameter;//we can't set metadata here because the XML is already on disk, see provenanceForOnDiskOutputs myFile->writeFile(outAssociation[i].m_fileName);//this is basically a noop unless outputs and inputs collide, we opened ON_DISK and set cache file to this name back in makeOnDiskOutputs + myFile->close();//if there is a problem flushing the file, let it throw here instead of doing a severe log message break; } case OperationParametersEnum::DOUBLE: diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 8bcf5d17b..e568c7057 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -349,6 +349,7 @@ VolumeFile::writeFile(const AString& filename) { myIO.writeData(getFrame(getBrickIndexFromNonSpatialIndexes(*myiter)), 3, *myiter);//NOTE: does not deal with multi-component volumes } + myIO.close();//call close explicitly to get a throw rather than a severe log when there is a problem m_header.grabNew(new NiftiHeader(outHeader));//update header to last written version, end nifti-specific code m_volumeFileEditorDelegate->clear(); -- GitLab From afa3a6ff0dd7aeb73e1afc21cbc45d608827fcec Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Jun 2017 15:24:04 -0500 Subject: [PATCH 159/755] Resolve WB-690 Data Normalization All maps not saved to scenes. Functionality has been restored. It had been removed by WB-664 Data normalization selection should be saved in file. Do not recall the motivation for WB-664. --- src/Files/CaretMappableDataFile.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 786c6cc7a..85c10561f 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -307,6 +307,13 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute * longer added to scenes since the palette normalization is a file * property stored in the file's metadata. */ + /* + * WB-690 request normalization mode be saved to scenes + * so adding it back in. + */ + sceneClass->addEnumeratedType("m_paletteNormalizationMode", + getPaletteNormalizationMode()); if (sceneAttributes->isModifiedPaletteSettingsSavedToScene()) { std::vector pcmClassVector; -- GitLab From 315a97b498f31c9c1eebbd539d6cc1195b536834 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 6 Jul 2017 15:51:22 -0500 Subject: [PATCH 160/755] Resolve WB-691 wb_command -show-scene fails silently: Query for error information from scene loading was missing and has been added. If an error occurs, scene processing continues since the error may not affect the scene. After scene image generation completes, the error message is printed. --- src/Operations/OperationShowScene.cxx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 39c1d9525..80e608143 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -265,7 +265,12 @@ OperationShowScene::useParameters(OperationParameters* myParams, sessionManager->restoreFromScene(&sceneAttributes, guiManagerClass->getClass("m_sessionManager")); - + /* + * Get the error message but continue processing since the error + * may not affect the scene. Print error message later. + */ + const AString sceneErrorMessage = sceneAttributes.getErrorMessage(); + if (sessionManager->getNumberOfBrains() <= 0) { throw OperationException("Scene loading failure, SessionManager contains no Brains"); } @@ -552,6 +557,14 @@ OperationShowScene::useParameters(OperationParameters* myParams, OSMesaDestroyContext(mesaContext); } } + + /* + * Print error messages + */ + if ( ! sceneErrorMessage.isEmpty()) { + std::cerr << "ERRORS loading scene, output image may be incorrect." << std::endl; + std::cerr << sceneErrorMessage << std::endl; + } } /** -- GitLab From 2f22e88933d15bf46806528a9d70b3a6b5b5b46f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 6 Jul 2017 16:04:19 -0500 Subject: [PATCH 161/755] Resolve WB-689 Lock tab aspect ratio setting not carried over tab duplication: Both the the tab aspect ratio and the status are now copied when a duplicate tab is created. --- src/Brain/BrowserTabContent.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 3c7918fe6..0fbc244cd 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -265,6 +265,8 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) *m_clippingPlaneGroup = *tabToClone->m_clippingPlaneGroup; m_yokingGroup = tabToClone->m_yokingGroup; + m_aspectRatio = tabToClone->m_aspectRatio; + m_aspectRatioLocked = tabToClone->m_aspectRatioLocked; *m_cerebellumViewingTransformation = *tabToClone->m_cerebellumViewingTransformation; *m_flatSurfaceViewingTransformation = *tabToClone->m_flatSurfaceViewingTransformation; -- GitLab From e55c57c17aa311f9d6dfcb3e3664d2dc6fe0ac4e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 7 Jul 2017 08:50:19 -0500 Subject: [PATCH 162/755] Improved formatting (removed blank line and added indentation to additional information) of error message for a file not found --- src/Brain/Brain.cxx | 2 +- src/Common/DataFileException.cxx | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 197a34118..ea52a06d2 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -5219,7 +5219,7 @@ Brain::readDataFile(const DataFileTypeEnum::Enum dataFileType, FileInformation fileInfoFullPath(dataFileName); if (fileInfoFullPath.exists() == false) { throw DataFileException(dataFileName, - "File does not exist!"); + "File not found:"); } } diff --git a/src/Common/DataFileException.cxx b/src/Common/DataFileException.cxx index 41ebc7afc..f75382430 100644 --- a/src/Common/DataFileException.cxx +++ b/src/Common/DataFileException.cxx @@ -81,14 +81,13 @@ DataFileException::DataFileException(const AString& dataFileName, AString msg = s; if ( ! dataFileName.isEmpty()) { - msg += "\n"; FileInformation fileInfo(dataFileName); const AString pathName = fileInfo.getPathName(); - msg.appendWithNewLine("File: " + fileInfo.getFileName()); + msg.appendWithNewLine(" Name: " + fileInfo.getFileName()); if ( ! pathName.isEmpty()) { if (pathName != ".") { - msg.appendWithNewLine("Path: " + pathName); + msg.appendWithNewLine(" Path: " + pathName); } } } -- GitLab From b59a8bc4b0c1c0389ec251cb0318d68ac66a6d46 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 10 Jul 2017 17:56:31 -0500 Subject: [PATCH 163/755] add -surface-set-coordinates command --- src/Commands/CommandOperationManager.cxx | 2 + src/Operations/CMakeLists.txt | 2 + .../OperationSurfaceSetCoordinates.cxx | 83 +++++++++++++++++++ .../OperationSurfaceSetCoordinates.h | 75 +++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 src/Operations/OperationSurfaceSetCoordinates.cxx create mode 100644 src/Operations/OperationSurfaceSetCoordinates.h diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 4f2e7c0a8..10bffec2c 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -207,6 +207,7 @@ #include "OperationSurfaceGeodesicROIs.h" #include "OperationSurfaceInformation.h" #include "OperationSurfaceNormals.h" +#include "OperationSurfaceSetCoordinates.h" #include "OperationSurfaceVertexAreas.h" #include "OperationVolumeCapturePlane.h" #include "OperationVolumeCopyExtensions.h" @@ -460,6 +461,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceGeodesicROIs())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceInformation())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceNormals())); + this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceSetCoordinates())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceVertexAreas())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeCapturePlane())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeCopyExtensions())); diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index d40c4f28f..e59d0c796 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -90,6 +90,7 @@ OperationSurfaceGeodesicDistance.h OperationSurfaceGeodesicROIs.h OperationSurfaceInformation.h OperationSurfaceNormals.h +OperationSurfaceSetCoordinates.h OperationSurfaceVertexAreas.h OperationVolumeCapturePlane.h OperationVolumeCopyExtensions.h @@ -178,6 +179,7 @@ OperationSurfaceGeodesicDistance.cxx OperationSurfaceGeodesicROIs.cxx OperationSurfaceInformation.cxx OperationSurfaceNormals.cxx +OperationSurfaceSetCoordinates.cxx OperationSurfaceVertexAreas.cxx OperationVolumeCapturePlane.cxx OperationVolumeCopyExtensions.cxx diff --git a/src/Operations/OperationSurfaceSetCoordinates.cxx b/src/Operations/OperationSurfaceSetCoordinates.cxx new file mode 100644 index 000000000..dd4fb0e63 --- /dev/null +++ b/src/Operations/OperationSurfaceSetCoordinates.cxx @@ -0,0 +1,83 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "OperationSurfaceSetCoordinates.h" +#include "OperationException.h" + +#include "MetricFile.h" +#include "SurfaceFile.h" + +using namespace caret; +using namespace std; + +AString OperationSurfaceSetCoordinates::getCommandSwitch() +{ + return "-surface-set-coordinates"; +} + +AString OperationSurfaceSetCoordinates::getShortDescription() +{ + return "MODIFY COORDINATES OF A SURFACE"; +} + +OperationParameters* OperationSurfaceSetCoordinates::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + + ret->addSurfaceParameter(1, "surface-in", "the surface to use for the topology"); + + ret->addMetricParameter(2, "coord-metric", "the new coordinates, as a 3-column metric file"); + + ret->addSurfaceOutputParameter(3, "surface-out", "the new surface"); + + ret->setHelpText( + AString("Takes the topology from an existing surface file, and uses values from a metric file as coordinates to construct a new surface file.\n\n") + + "See -surface-coordinates-to-metric for how to get surface coordinates as a metric file, such that you can then modify them via metric commands, etc." + ); + return ret; +} + +void OperationSurfaceSetCoordinates::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + LevelProgress myProgress(myProgObj); + SurfaceFile* inSurf = myParams->getSurface(1); + MetricFile* coordsIn = myParams->getMetric(2); + SurfaceFile* outSurf = myParams->getOutputSurface(3); + int numNodes = inSurf->getNumberOfNodes(); + if (coordsIn->getNumberOfNodes() != numNodes) + { + throw OperationException("coordinate metric file must have the same number of vertices as the input surface"); + } + if (coordsIn->getNumberOfColumns() != 3) + { + throw OperationException("coordinate metric file must have exactly 3 columns: x, y, and z"); + } + *outSurf = *inSurf; + vector combinedCoords(numNodes * 3); + for (int i = 0; i < 3; ++i) + { + const float* colData = coordsIn->getValuePointerForColumn(i); + for (int j = 0; j < numNodes; ++j) + { + combinedCoords[j * 3 + i] = colData[j]; + } + } + outSurf->setCoordinates(combinedCoords.data()); +} diff --git a/src/Operations/OperationSurfaceSetCoordinates.h b/src/Operations/OperationSurfaceSetCoordinates.h new file mode 100644 index 000000000..4b0f8adc0 --- /dev/null +++ b/src/Operations/OperationSurfaceSetCoordinates.h @@ -0,0 +1,75 @@ +#ifndef __OPERATION_SURFACE_SET_COORDINATES_H__ +#define __OPERATION_SURFACE_SET_COORDINATES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +/* +file->save as... and enter what you will name the class, plus .h + +find and replace these strings in plain text mode (not "whole word only"): + +OperationSurfaceSetCoordinates : operation name, in CamelCase, with initial capital, same as what you saved the header file to +OPERATION_SURFACE_SET_COORDINATES : uppercase of operation name, with underscore between words, used in #ifdef guards + +next, make OperationSurfaceSetCoordinates.cxx from OperationTemplate.cxx.txt via one of the following (depending on working directory): + +cat OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > OperationSurfaceSetCoordinates.cxx +cat Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > Operations/OperationSurfaceSetCoordinates.cxx +cat src/Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > src/Operations/OperationSurfaceSetCoordinates.cxx + +or manually copy and replace + +next, implement its functions + +add these to Operations/CMakeLists.txt: + +OperationSurfaceSetCoordinates.h +OperationSurfaceSetCoordinates.cxx + +place the following lines into Commands/CommandOperationManager.cxx: + +#include "OperationSurfaceSetCoordinates.h" + //near the top + + this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceSetCoordinates())); + //in CommandOperationManager() + +finally, remove this block comment +*/ + +#include "AbstractOperation.h" + +namespace caret { + + class OperationSurfaceSetCoordinates : public AbstractOperation + { + public: + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoOperationSurfaceSetCoordinates; + +} + +#endif //__OPERATION_SURFACE_SET_COORDINATES_H__ -- GitLab From b1a7c8ce48a4b98d72c080748b16889df4d1568c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 12 Jul 2017 17:17:39 -0500 Subject: [PATCH 164/755] add aspect ratio warning to -volume-capture-plane --- src/Operations/OperationVolumeCapturePlane.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Operations/OperationVolumeCapturePlane.cxx b/src/Operations/OperationVolumeCapturePlane.cxx index f7749ceca..40ef9766b 100644 --- a/src/Operations/OperationVolumeCapturePlane.cxx +++ b/src/Operations/OperationVolumeCapturePlane.cxx @@ -141,6 +141,11 @@ void OperationVolumeCapturePlane::useParameters(OperationParameters* myParams, P { CaretLogWarning("corner points describe non-orthogonal directions, image will be skewed"); } + float aspectRatio = (rightTraverse.length() / width) / (upTraverse.length() / height); + if (aspectRatio > 1.001f || aspectRatio < 0.999f) + { + CaretLogWarning("corner points and image dimensions are different aspect ratios, image will be stretched"); + } vector imageData(width * height * 4); for (int h = 0; h < height; ++h) { -- GitLab From d07dcb283ecffe194ce23fd83df19a01a2175621 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 14 Jul 2017 15:25:53 -0500 Subject: [PATCH 165/755] some wording edits to -cifti-help --- src/Commands/CommandOperationManager.cxx | 33 ++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 10bffec2c..8c2410868 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -1103,11 +1103,11 @@ void CommandOperationManager::printCiftiHelp() cout << " The CIFTI format is a new data file format intended to make it easier to" << endl; cout << " work with data from multiple disjoint structures at the same time - often" << endl; cout << " this means both hemispheres of cortex as surface data, and other structures" << endl; - cout << " as voxel data (amygdala, thalamus, hippocampus, etc). Additionally, it" << endl; - cout << " can exclude locations that are uninteresting for the task at hand (medial" << endl; - cout << " wall, white matter, csf), preventing them from taking up room in the data of" << endl; - cout << " the file. The set of structures and the locations in them that are used in" << endl; - cout << " a cifti file is referred to as 'brainordinates', or for the specific case of" << endl; + cout << " as voxel data (amygdala, thalamus, putamen, etc). Additionally, it can" << endl; + cout << " exclude locations that are uninteresting for the task at hand (medial wall," << endl; + cout << " white matter, csf), preventing them from taking up room in the data of the" << endl; + cout << " file. The set of structures and the locations in them that are used in a" << endl; + cout << " cifti file are referred to as 'brainordinates', or for the specific case of" << endl; cout << " 'all gray matter locations', 'grayordinates'." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " However, to explain the cifti format, it is easiest to work from the" << endl; @@ -1115,17 +1115,18 @@ void CommandOperationManager::printCiftiHelp() cout << " single rectangular data matrix (usually 2 dimensions, but supports 3, and" << endl; cout << " may support more in the future), where each dimension is labeled with what" << endl; cout << " we call a 'mapping', each of which uses one of (currently) five possible" << endl; - cout << " 'mapping types'. It is these mapping types that give rise to the diverse" << endl; - cout << " types of cifti files. A single mapping of type 'brain models' (also known" << endl; - cout << " as 'dense') can represent both hemispheres and all subcortical structures" << endl; - cout << " simultaneously, meaning that only a single dimension is used to represent" << endl; - cout << " over a dozen structures, both surface-based and voxel-based. The mapping" << endl; - cout << " contains all information needed to figure out what every index along the" << endl; - cout << " dimension means. By putting a dense mapping along both dimensions in a 2D" << endl; - cout << " cifti file, you get a brainordinates by brainordinates matrix, frequently" << endl; - cout << " used for connectivity measures. Notably, even if two dimensions use the" << endl; - cout << " same mapping *type*, they can have different information in them, for" << endl; - cout << " example a connectivity matrix between two different parcellations." << endl; + cout << " 'mapping types'. It is the combinations of these mapping types that give" << endl; + cout << " rise to the diverse types of cifti files. A single mapping of type 'brain" << endl; + cout << " models' (also known as 'dense') can represent both hemispheres and all" << endl; + cout << " subcortical structures simultaneously, meaning that only a single matrix" << endl; + cout << " dimension is used to represent over a dozen structures, both surface-based" << endl; + cout << " and voxel-based. Each mapping contains all information needed to figure out" << endl; + cout << " what every index along the matrix dimension means. By putting a dense" << endl; + cout << " mapping along both dimensions in a 2D cifti file, you get a brainordinates" << endl; + cout << " by brainordinates matrix, which is used for connectivity measures. Notably," << endl; + cout << " even if two dimensions use the same mapping *type*, they can have different" << endl; + cout << " information in them, for example a connectivity matrix between two different" << endl; + cout << " parcellations." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The other mapping types that currently may be used in a cifti file are:" << endl; cout << " Parcels: each index refers to a named subset of the brainordinates (i.e." << endl; -- GitLab From 679079f272bb5e4e3d5796bf88aa53d3f9bc9b3e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 21 Jul 2017 16:39:23 -0500 Subject: [PATCH 166/755] remove instruction comment --- .../OperationSurfaceSetCoordinates.h | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/src/Operations/OperationSurfaceSetCoordinates.h b/src/Operations/OperationSurfaceSetCoordinates.h index 4b0f8adc0..88e51b813 100644 --- a/src/Operations/OperationSurfaceSetCoordinates.h +++ b/src/Operations/OperationSurfaceSetCoordinates.h @@ -21,40 +21,6 @@ */ /*LICENSE_END*/ -/* -file->save as... and enter what you will name the class, plus .h - -find and replace these strings in plain text mode (not "whole word only"): - -OperationSurfaceSetCoordinates : operation name, in CamelCase, with initial capital, same as what you saved the header file to -OPERATION_SURFACE_SET_COORDINATES : uppercase of operation name, with underscore between words, used in #ifdef guards - -next, make OperationSurfaceSetCoordinates.cxx from OperationTemplate.cxx.txt via one of the following (depending on working directory): - -cat OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > OperationSurfaceSetCoordinates.cxx -cat Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > Operations/OperationSurfaceSetCoordinates.cxx -cat src/Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationSurfaceSetCoordinates/g' > src/Operations/OperationSurfaceSetCoordinates.cxx - -or manually copy and replace - -next, implement its functions - -add these to Operations/CMakeLists.txt: - -OperationSurfaceSetCoordinates.h -OperationSurfaceSetCoordinates.cxx - -place the following lines into Commands/CommandOperationManager.cxx: - -#include "OperationSurfaceSetCoordinates.h" - //near the top - - this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceSetCoordinates())); - //in CommandOperationManager() - -finally, remove this block comment -*/ - #include "AbstractOperation.h" namespace caret { -- GitLab From a2135920aa8213138a0de09173368b5fb2c7a6f4 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 21 Jul 2017 21:17:20 -0500 Subject: [PATCH 167/755] fix test for thin columns option --- src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx index 4d945c417..a948f7782 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx @@ -199,7 +199,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam throw AlgorithmException("invalid number of subdivisions specified"); } } - bool thinColumns = ribbonOpt->getOptionalParameter(7); + bool thinColumns = ribbonOpt->getOptionalParameter(7)->m_present; int weightsOutVertex = -1; VolumeFile* weightsOut = NULL; OptionalParameter* ribbonWeights = ribbonOpt->getOptionalParameter(5); -- GitLab From cc85666009c068ea6c40aeb33c2c73b5ab921923 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 25 Jul 2017 15:44:10 -0500 Subject: [PATCH 168/755] make function to expose whether the volume file has good spatial information --- src/Files/VolumeFile.cxx | 9 +++++++++ src/Files/VolumeFile.h | 2 ++ src/FilesBase/VolumeBase.h | 2 ++ src/Nifti/NiftiHeader.cxx | 7 ++++++- src/Nifti/NiftiHeader.h | 2 ++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index e568c7057..ccf606ee6 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -356,6 +356,15 @@ VolumeFile::writeFile(const AString& filename) m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); } +bool VolumeFile::hasGoodSpatialInformation() const +{ + if (m_header != NULL) + { + return m_header->hasGoodSpatialInformation(); + } + return true; +} + float VolumeFile::interpolateValue(const float* coordIn, InterpType interp, bool* validOut, const int64_t brickIndex, const int64_t component) const { return interpolateValue(coordIn[0], coordIn[1], coordIn[2], interp, validOut, brickIndex, component); diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index 03752548a..f1dffa016 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -185,6 +185,8 @@ namespace caret { bool isEmpty() const { return VolumeBase::isEmpty(); } + bool hasGoodSpatialInformation() const; + virtual void setModified(); virtual void clearModified(); diff --git a/src/FilesBase/VolumeBase.h b/src/FilesBase/VolumeBase.h index 7731f2675..770900135 100644 --- a/src/FilesBase/VolumeBase.h +++ b/src/FilesBase/VolumeBase.h @@ -33,6 +33,8 @@ namespace caret { struct AbstractHeader { + virtual bool hasGoodSpatialInformation() const = 0; + enum HeaderType { NIFTI diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index 90db97cea..f492a34c6 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -265,7 +265,7 @@ vector > NiftiHeader::getSForm() const ret[1][3] = m_header.qoffset_y; ret[2][3] = m_header.qoffset_z; } else { - CaretLogWarning("found quaternion with length greater than 1 in nifti header"); + CaretLogWarning("found quaternion with length greater than 1 in nifti header, using ANALYZE coordinates!"); ret[0][0] = m_header.pixdim[1]; ret[1][1] = m_header.pixdim[2]; ret[2][2] = m_header.pixdim[3]; @@ -610,6 +610,11 @@ int NiftiHeader::getNumComponents() const } } +bool NiftiHeader::hasGoodSpatialInformation() const +{ + return (m_header.sform_code != 0 || m_header.qform_code != 0); +} + void NiftiHeader::read(CaretBinaryFile& inFile) { nifti_1_header buffer1; diff --git a/src/Nifti/NiftiHeader.h b/src/Nifti/NiftiHeader.h index 874139ac1..1ddb17bc4 100644 --- a/src/Nifti/NiftiHeader.h +++ b/src/Nifti/NiftiHeader.h @@ -61,6 +61,7 @@ namespace caret const char* getIntentName() const { return m_header.intent_name; }//NOTE: 16 BYTES, MAY NOT HAVE A NULL TERMINATOR bool getDataScaling(double& mult, double& offset) const;//returns false if scaling not needed int getNumComponents() const; + bool hasGoodSpatialInformation() const; QString toString() const; void setDimensions(const std::vector& dimsIn); @@ -70,6 +71,7 @@ namespace caret void clearDataScaling(); void setDataScaling(const double& mult, const double& offset); void setDataTypeAndScaleRange(const int16_t& type, const double& minval, const double& maxval); + ///get the FSL "scale" space std::vector > getFSLSpace() const; -- GitLab From 933ce8beee56b967fb128ad1d18f437e45543646 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 25 Jul 2017 18:37:07 -0500 Subject: [PATCH 169/755] add -volume-warpfield-affine-regression command --- ...gorithmVolumeWarpfieldAffineRegression.cxx | 167 ++++++++++++++++++ ...AlgorithmVolumeWarpfieldAffineRegression.h | 48 +++++ src/Algorithms/CMakeLists.txt | 2 + src/Commands/CommandOperation.cxx | 1 + src/Commands/CommandOperationManager.cxx | 2 + 5 files changed, 220 insertions(+) create mode 100644 src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.cxx create mode 100644 src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.h diff --git a/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.cxx b/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.cxx new file mode 100644 index 000000000..4bd4d5dc7 --- /dev/null +++ b/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.cxx @@ -0,0 +1,167 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AlgorithmVolumeWarpfieldAffineRegression.h" +#include "AlgorithmException.h" + +#include "AffineFile.h" +#include "MatrixFunctions.h" +#include "Vector3D.h" +#include "VolumeFile.h" +#include "WarpfieldFile.h" + +using namespace caret; +using namespace std; + +AString AlgorithmVolumeWarpfieldAffineRegression::getCommandSwitch() +{ + return "-volume-warpfield-affine-regression"; +} + +AString AlgorithmVolumeWarpfieldAffineRegression::getShortDescription() +{ + return "REGRESS AFFINE FROM WARPFIELD"; +} + +OperationParameters* AlgorithmVolumeWarpfieldAffineRegression::getParameters() +{ + OperationParameters* ret = new OperationParameters(); + + ret->addStringParameter(1, "warpfield", "the input warpfield"); + + ret->addStringParameter(2, "affine-out", "output - the output affine file");//HACK: fake the output help formatting + + OptionalParameter* roiOpt = ret->createOptionalParameter(3, "-roi", "only consider voxels within a mask (e.g., a brain mask)"); + roiOpt->addVolumeParameter(1, "roi-vol", "the mask volume"); + + OptionalParameter* fnirtInOpt = ret->createOptionalParameter(4, "-fnirt", "input is a fnirt warpfield"); + fnirtInOpt->addStringParameter(1, "source-volume", "the source volume used when generating the fnirt warpfield"); + + OptionalParameter* flirtOutOpt = ret->createOptionalParameter(5, "-flirt-out", "write output as a flirt matrix rather than a world coordinate transform"); + flirtOutOpt->addStringParameter(1, "source-volume", "the volume you want to apply the transform to"); + flirtOutOpt->addStringParameter(2, "target-volume", "the target space you want the transformed volume to match"); + + ret->setHelpText( + AString("For all voxels in the warpfield, do a regression that predicts the post-warp coordinate from the source coordinate. ") + + "When -roi is specified, only consider voxels with a value greater than 0 in .\n\n" + + "The default is to expect the warpfield to be in relative world coordinates (mm space), and to write the output as a world affine (mm space to mm space). " + + "If you are using FSL-created files and utilities, specify -fnirt and -flirt as needed, as their coordinate conventions are different." + ); + return ret; +} + +void AlgorithmVolumeWarpfieldAffineRegression::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) +{ + AString warpfieldName = myParams->getString(1); + AString affineOutName = myParams->getString(2); + VolumeFile* myRoi = NULL; + OptionalParameter* roiOpt = myParams->getOptionalParameter(3); + if (roiOpt->m_present) + { + myRoi = roiOpt->getVolume(1); + } + WarpfieldFile myWarpfield; + OptionalParameter* fnirtInOpt = myParams->getOptionalParameter(4); + if (fnirtInOpt->m_present) + { + myWarpfield.readFnirt(warpfieldName, fnirtInOpt->getString(1)); + } else { + myWarpfield.readWorld(warpfieldName); + } + FloatMatrix affineMatOut; + AlgorithmVolumeWarpfieldAffineRegression(myProgObj, myWarpfield.getWarpfield(), affineMatOut, myRoi); + AffineFile affineOut; + affineOut.setMatrix(affineMatOut); + OptionalParameter* flirtOutOpt = myParams->getOptionalParameter(5); + if (flirtOutOpt->m_present) + { + affineOut.writeFlirt(affineOutName, flirtOutOpt->getString(1), flirtOutOpt->getString(2)); + } else { + affineOut.writeWorld(affineOutName); + } +} + +AlgorithmVolumeWarpfieldAffineRegression::AlgorithmVolumeWarpfieldAffineRegression(ProgressObject* myProgObj, const VolumeFile* warpVol, FloatMatrix& affineMatOut, const VolumeFile* myRoi) : AbstractAlgorithm(myProgObj) +{ + LevelProgress myProgress(myProgObj); + if (myRoi != NULL && !warpVol->matchesVolumeSpace(myRoi)) + { + throw AlgorithmException("roi volume does not match the volume space of the warpfield"); + } + vector voldims = warpVol->getDimensions(); + if (voldims[3] != 3) + { + throw AlgorithmException("warpfield volume does not have 3 subvolumes"); + } + //three regressions with the same predictors and different target values + vector > indep(4, vector(4, 0.0)), dep(4, vector(3, 0.0)); + for (int64_t k = 0; k < voldims[2]; ++k) + { + for (int64_t j = 0; j < voldims[1]; ++j) + { + for (int64_t i = 0; i < voldims[0]; ++i) + { + if (myRoi == NULL || myRoi->getValue(i, j, k) > 0.0f) + { + Vector3D outCoord, displacement, inCoord;//outCoord is the post-warp coordinate + warpVol->indexToSpace(i, j, k, outCoord); + displacement[0] = warpVol->getValue(i, j, k, 0); + displacement[1] = warpVol->getValue(i, j, k, 1); + displacement[2] = warpVol->getValue(i, j, k, 2); + inCoord = outCoord + displacement; + for (int dim1 = 0; dim1 < 3; ++dim1)//compute X' * X and X' * Y + { + for (int dim2 = 0; dim2 < 3; ++dim2) + { + indep[dim1][dim2] += inCoord[dim1] * inCoord[dim2]; + dep[dim2][dim1] += outCoord[dim1] * inCoord[dim2]; + } + indep[dim1][3] += inCoord[dim1]; + indep[3][dim1] += inCoord[dim1]; + dep[3][dim1] += outCoord[dim1]; + } + indep[3][3] += 1.0; + } + } + } + } + vector > rrefMat; + MatrixFunctions::horizCat(indep, dep, rrefMat); + MatrixFunctions::rref(rrefMat); + affineMatOut = FloatMatrix::identity(4); + for (int dim1 = 0; dim1 < 3; ++dim1) + { + for (int dim2 = 0; dim2 < 4; ++dim2) + { + affineMatOut[dim1][dim2] = rrefMat[dim2][4 + dim1]; + } + } +} + +float AlgorithmVolumeWarpfieldAffineRegression::getAlgorithmInternalWeight() +{ + return 1.0f;//override this if needed, if the progress bar isn't smooth +} + +float AlgorithmVolumeWarpfieldAffineRegression::getSubAlgorithmWeight() +{ + //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm + return 0.0f; +} diff --git a/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.h b/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.h new file mode 100644 index 000000000..bea406731 --- /dev/null +++ b/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.h @@ -0,0 +1,48 @@ +#ifndef __ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ +#define __ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "AbstractAlgorithm.h" + +#include "FloatMatrix.h" + +namespace caret { + + class AlgorithmVolumeWarpfieldAffineRegression : public AbstractAlgorithm + { + AlgorithmVolumeWarpfieldAffineRegression(); + protected: + static float getSubAlgorithmWeight(); + static float getAlgorithmInternalWeight(); + public: + AlgorithmVolumeWarpfieldAffineRegression(ProgressObject* myProgObj, const VolumeFile* warpVol, FloatMatrix& affineMatOut, const VolumeFile* myRoi = NULL); + static OperationParameters* getParameters(); + static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); + static AString getCommandSwitch(); + static AString getShortDescription(); + }; + + typedef TemplateAutoOperation AutoAlgorithmVolumeWarpfieldAffineRegression; + +} + +#endif //__ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ diff --git a/src/Algorithms/CMakeLists.txt b/src/Algorithms/CMakeLists.txt index c1ff6495b..bce71f1b2 100644 --- a/src/Algorithms/CMakeLists.txt +++ b/src/Algorithms/CMakeLists.txt @@ -135,6 +135,7 @@ AlgorithmVolumeSmoothing.h AlgorithmVolumeTFCE.h AlgorithmVolumeToSurfaceMapping.h AlgorithmVolumeVectorOperation.h +AlgorithmVolumeWarpfieldAffineRegression.h AlgorithmVolumeWarpfieldResample.h OverlapLogicEnum.h @@ -251,6 +252,7 @@ AlgorithmVolumeSmoothing.cxx AlgorithmVolumeTFCE.cxx AlgorithmVolumeToSurfaceMapping.cxx AlgorithmVolumeVectorOperation.cxx +AlgorithmVolumeWarpfieldAffineRegression.cxx AlgorithmVolumeWarpfieldResample.cxx OverlapLogicEnum.cxx ) diff --git a/src/Commands/CommandOperation.cxx b/src/Commands/CommandOperation.cxx index 548c966de..9943c1c1d 100644 --- a/src/Commands/CommandOperation.cxx +++ b/src/Commands/CommandOperation.cxx @@ -37,6 +37,7 @@ CommandOperation::CommandOperation(const AString& commandLineSwitch, { this->commandLineSwitch = commandLineSwitch; this->operationShortDescription = operationShortDescription; + CaretAssert(commandLineSwitch != "-command-switch");//catch failure to change things in the command template for (int i = 0; i < commandLineSwitch.length(); ++i)//release build should optimize out empty loops { CaretAssert(commandLineSwitch[i].unicode() < 128); diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 8c2410868..658f7bdb2 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -134,6 +134,7 @@ #include "AlgorithmVolumeTFCE.h" #include "AlgorithmVolumeToSurfaceMapping.h" #include "AlgorithmVolumeVectorOperation.h" +#include "AlgorithmVolumeWarpfieldAffineRegression.h" #include "AlgorithmVolumeWarpfieldResample.h" #include "OperationAddToSpecFile.h" @@ -393,6 +394,7 @@ CommandOperationManager::CommandOperationManager() this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeTFCE())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeToSurfaceMapping())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeVectorOperation())); + this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeWarpfieldAffineRegression())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeWarpfieldResample())); this->commandOperations.push_back(new CommandParser(new AutoOperationAddToSpecFile())); -- GitLab From 5c39f12df3c83e101ecd451dabe33dcc873ac488 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Dec 2016 14:55:16 -0600 Subject: [PATCH 170/755] VolumeSurfaceOutlineColorOrTabModel was duplicating the tab index (m_browserTabIndex) in the scene. --- src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx index 3595d50c7..08fc0c622 100644 --- a/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx @@ -527,9 +527,6 @@ VolumeSurfaceOutlineColorOrTabModel::Item::saveToScene(const SceneAttributes* /* break; } - sceneClass->addInteger("m_browserTabIndex", - m_browserTabIndex); - return sceneClass; } -- GitLab From 7641553ae434329456eb1d219ccb789b5b01807b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Dec 2016 15:00:25 -0600 Subject: [PATCH 171/755] Fixed saving of display sphere orientations in display group values to scene (was incorrectly saving the tab's values twice). --- src/Brain/DisplayPropertiesFiberOrientation.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Brain/DisplayPropertiesFiberOrientation.cxx b/src/Brain/DisplayPropertiesFiberOrientation.cxx index 4404a0115..f1c29fe8b 100644 --- a/src/Brain/DisplayPropertiesFiberOrientation.cxx +++ b/src/Brain/DisplayPropertiesFiberOrientation.cxx @@ -145,10 +145,10 @@ DisplayPropertiesFiberOrientation::DisplayPropertiesFiberOrientation() m_fanMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_fanMultiplierInDisplayGroup[0]); - m_sceneAssistant->addArray("m_displaySphereOrientationsInTab", - m_displaySphereOrientationsInTab, + m_sceneAssistant->addArray("m_displaySphereOrientationsInDisplayGroup", + m_displaySphereOrientationsInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, - m_displaySphereOrientationsInTab[0]); + m_displaySphereOrientationsInDisplayGroup[0]); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_fiberColoringTypeInTab", m_fiberColoringTypeInTab); -- GitLab From 4c6a962966d20dae4fb3c83de2bc12d8ed4e9c60 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Dec 2016 11:39:38 -0600 Subject: [PATCH 172/755] Updates to verify that scenes are fully restored --- src/Brain/CaretDataFileSelectionModel.cxx | 8 ++++---- src/Brain/ModelSurfaceMontage.cxx | 4 +++- src/Files/GroupAndNameHierarchyItem.cxx | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Brain/CaretDataFileSelectionModel.cxx b/src/Brain/CaretDataFileSelectionModel.cxx index ee4cc8e18..f3ea30c1f 100644 --- a/src/Brain/CaretDataFileSelectionModel.cxx +++ b/src/Brain/CaretDataFileSelectionModel.cxx @@ -534,17 +534,17 @@ CaretDataFileSelectionModel::restoreFromScene(const SceneAttributes* sceneAttrib } } + const AString selectedFileNameNoPath = sceneClass->getStringValue("selectedFileNameNoPath", + ""); if ( ! foundFileFlag) { - const AString selectedFileName = sceneClass->getStringValue("selectedFileNameNoPath", - ""); - if ( ! selectedFileName.isEmpty()) { + if ( ! selectedFileNameNoPath.isEmpty()) { std::vector caretDataFiles = getAvailableFiles(); for (std::vector::iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; - if (cdf->getFileNameNoPath() == selectedFileName) { + if (cdf->getFileNameNoPath() == selectedFileNameNoPath) { setSelectedFile(cdf); break; } diff --git a/src/Brain/ModelSurfaceMontage.cxx b/src/Brain/ModelSurfaceMontage.cxx index d72122dc1..56a127e3f 100644 --- a/src/Brain/ModelSurfaceMontage.cxx +++ b/src/Brain/ModelSurfaceMontage.cxx @@ -635,6 +635,7 @@ ModelSurfaceMontage::restoreModelSpecificInformationFromScene(const SceneAttribu iter++) { const int32_t key = iter->first; const SceneClass* cerebellarSceneClass = dynamic_cast(iter->second); + cerebellarSceneClass->setRestored(true); // prevents "failed to restore" CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, @@ -656,7 +657,7 @@ ModelSurfaceMontage::restoreModelSpecificInformationFromScene(const SceneAttribu iter++) { const int32_t key = iter->first; const SceneClass* cerebralSceneClass = dynamic_cast(iter->second); - + cerebralSceneClass->setRestored(true);// prevents "failed to restore" CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); @@ -677,6 +678,7 @@ ModelSurfaceMontage::restoreModelSpecificInformationFromScene(const SceneAttribu iter++) { const int32_t key = iter->first; const SceneClass* flatClass = dynamic_cast(iter->second); + flatClass->setRestored(true); // prevents "failed to restore" CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, diff --git a/src/Files/GroupAndNameHierarchyItem.cxx b/src/Files/GroupAndNameHierarchyItem.cxx index b80f04d8f..ac5154b70 100644 --- a/src/Files/GroupAndNameHierarchyItem.cxx +++ b/src/Files/GroupAndNameHierarchyItem.cxx @@ -928,6 +928,7 @@ GroupAndNameHierarchyItem::restoreFromScene(const SceneAttributes* sceneAttribut return; } + sceneClass->getStringValue("m_name"); // prevents "failed to restore" m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); -- GitLab From 17bfff05f6e21de51e5db800bba25197cbc2da1e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Dec 2016 11:40:44 -0600 Subject: [PATCH 173/755] Updates to verify that scenes are fully restored --- src/GuiQt/BrainBrowserWindow.cxx | 10 +++++++++- src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx | 5 +++++ src/GuiQt/SceneWindowGeometry.cxx | 8 ++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index a157290ec..59bb7d1ea 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -4090,6 +4090,7 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); + /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); sceneClass->addBoolean("m_windowAspectRatioLockedAction", @@ -4187,7 +4188,7 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, m_viewTileTabsSelected); /* - * Graphics position and size + * Graphics position and size, used with wb_command -show-scene */ SceneWindowGeometry openGLGeometry(m_openGLWidget); sceneClass->addClass(openGLGeometry.saveToScene(sceneAttributes, @@ -4432,6 +4433,13 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, if (maximizedWindow) { showMaximized(); } + + /* prevent "failed to restore" messages */ + sceneClass->getIntegerValue("m_browserWindowIndex"); + const SceneClass* openglGeomClass = sceneClass->getClass("openGLWidgetGeometry"); + if (openglGeomClass != NULL) { + openglGeomClass->setDescendantsRestored(true); + } } ///** diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 86f2f105d..639812d08 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -462,6 +462,11 @@ BrainBrowserWindowOrientedToolBox::restoreFromScene(const SceneAttributes* scene sceneClass->getClass("geometry")); } else { + const SceneClass* geometryClass = sceneClass->getClass("geometry"); + if (geometryClass != NULL) { + /* is restored only when floating and visible. */ + geometryClass->setDescendantsRestored(true); + } #if QT_VERSION < 0x050000 /* * Do this for Qt4 only. Qt5 restores size in BrainBrowserWindow. diff --git a/src/GuiQt/SceneWindowGeometry.cxx b/src/GuiQt/SceneWindowGeometry.cxx index a0ba72bfb..a5e591844 100644 --- a/src/GuiQt/SceneWindowGeometry.cxx +++ b/src/GuiQt/SceneWindowGeometry.cxx @@ -170,6 +170,10 @@ SceneWindowGeometry::restoreFromScene(const SceneAttributes* sceneAttributes, -1); const int32_t sceneHeight = sceneClass->getIntegerValue("geometryHeight", -1); + const int32_t offsetX = sceneClass->getIntegerValue("geometryOffsetX", 100); + const int32_t offsetY = sceneClass->getIntegerValue("geometryOffsetY", 100); + const bool windowVisible = sceneClass->getBooleanValue("visibility", + true); const bool isDialog = (qobject_cast(m_window) != NULL); QDockWidget* dockWidget = qobject_cast(m_window); @@ -216,8 +220,6 @@ SceneWindowGeometry::restoreFromScene(const SceneAttributes* sceneAttributes, /* * Get offset from parent */ - const int32_t offsetX = sceneClass->getIntegerValue("geometryOffsetX", 100); - const int32_t offsetY = sceneClass->getIntegerValue("geometryOffsetY", 100); const int32_t windowX = m_parentWindow->x() + offsetX; const int32_t windowY = m_parentWindow->y() + offsetY; @@ -238,8 +240,6 @@ SceneWindowGeometry::restoreFromScene(const SceneAttributes* sceneAttributes, /* * Visibility */ - const bool windowVisible = sceneClass->getBooleanValue("visibility", - true); m_window->setVisible(windowVisible); /* -- GitLab From b0856cf4331ea8a9f2847e19894e20ca45d3cbb9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Dec 2016 11:41:48 -0600 Subject: [PATCH 174/755] Added logic that verifies restoration of every item in a scene file. When enabled, it will log at the warning level: (1) Duplicate child items with same name; (2) Items that are not restored. --- src/GuiQt/SceneCreateReplaceDialog.cxx | 20 +- src/GuiQt/SceneCreateReplaceDialog.h | 5 +- src/GuiQt/SceneDialog.cxx | 269 ++++++++++++++++++++++ src/GuiQt/SceneDialog.h | 8 + src/Scenes/Scene.cxx | 24 ++ src/Scenes/Scene.h | 3 + src/Scenes/SceneBoolean.cxx | 5 + src/Scenes/SceneClass.cxx | 291 ++++++++++++++++++------ src/Scenes/SceneClass.h | 8 +- src/Scenes/SceneClassArray.cxx | 29 ++- src/Scenes/SceneClassArray.h | 2 + src/Scenes/SceneFloat.cxx | 5 + src/Scenes/SceneInteger.cxx | 5 + src/Scenes/SceneObject.cxx | 119 +++++++++- src/Scenes/SceneObject.h | 25 ++ src/Scenes/SceneObjectArray.cxx | 1 + src/Scenes/SceneObjectMapIntegerKey.cxx | 24 ++ src/Scenes/SceneObjectMapIntegerKey.h | 6 +- src/Scenes/ScenePathName.cxx | 1 + src/Scenes/ScenePathNameArray.cxx | 22 +- src/Scenes/ScenePathNameArray.h | 2 + src/Scenes/ScenePrimitive.cxx | 14 ++ src/Scenes/ScenePrimitive.h | 2 + src/Scenes/SceneString.cxx | 6 + src/Scenes/SceneStringArray.cxx | 5 + src/Scenes/SceneUnsignedByte.cxx | 5 + 26 files changed, 816 insertions(+), 90 deletions(-) diff --git a/src/GuiQt/SceneCreateReplaceDialog.cxx b/src/GuiQt/SceneCreateReplaceDialog.cxx index 168716ba4..4fe6cb7c5 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.cxx +++ b/src/GuiQt/SceneCreateReplaceDialog.cxx @@ -345,9 +345,10 @@ SceneCreateReplaceDialog::replaceExistingScene(QWidget* parent, * Scene to which image is added. */ void -SceneCreateReplaceDialog::addImageToScene(Scene* scene) +SceneCreateReplaceDialog::addImageToScene(Scene* scene, + AString& errorMessageOut) { - AString errorMessage; + errorMessageOut.clear(); CaretAssert(scene); @@ -370,7 +371,7 @@ SceneCreateReplaceDialog::addImageToScene(Scene* scene) if (imageCaptureEvent.getEventProcessCount() > 0) { if (imageCaptureEvent.isError()) { - errorMessage.appendWithNewLine(imageCaptureEvent.getErrorMessage()); + errorMessageOut.appendWithNewLine(imageCaptureEvent.getErrorMessage()); } else { imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); @@ -415,9 +416,8 @@ SceneCreateReplaceDialog::addImageToScene(Scene* scene) PREFERRED_IMAGE_FORMAT); } catch (const DataFileException& dfe) { - WuQMessageBox::errorOk(this, - (dfe.whatString() - + "\n\nEven though image failed, scene was created.")); + errorMessageOut.appendWithNewLine((dfe.whatString() + + "\n\nEven though image failed, scene was created.")); } } @@ -670,7 +670,13 @@ SceneCreateReplaceDialog::okButtonClicked() newScene->addClass(GuiManager::get()->saveToScene(sceneAttributes, "guiManager")); - addImageToScene(newScene); + AString imageErrorMessage; + addImageToScene(newScene, + imageErrorMessage); + if ( ! imageErrorMessage.isEmpty()) { + WuQMessageBox::errorOk(this, + imageErrorMessage); + } switch (m_mode) { case MODE_ADD_NEW_SCENE: diff --git a/src/GuiQt/SceneCreateReplaceDialog.h b/src/GuiQt/SceneCreateReplaceDialog.h index 3a7e46877..ecc5fdf5f 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.h +++ b/src/GuiQt/SceneCreateReplaceDialog.h @@ -50,6 +50,9 @@ namespace caret { SceneFile* sceneFile, Scene* sceneToReplace); + static void addImageToScene(Scene* scene, + AString& errorMessageOut); + static bool createSceneImage(QImage& imageOut, AString& errorMessageOut); @@ -82,8 +85,6 @@ namespace caret { private: // ADD_NEW_MEMBERS_HERE - void addImageToScene(Scene* scene); - SceneFile* m_sceneFile; Mode m_mode; diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index a41016fdd..f1aeb6ee2 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -109,6 +109,7 @@ SceneDialog::SceneDialog(QWidget* parent) { m_selectedSceneClassInfoIndex = -1; + m_replaceAllScenesDescription = ("This operation may be slow as it loads and replaces all scenes."); m_testAllScenesDescription = ("This operation may be slow as it requires displaying all scenes. " "\n" "Each scene is displayed and an image of the graphic(s) regions is generated " @@ -496,6 +497,9 @@ SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) m_addNewScenePushButton->setEnabled(validFile); m_deleteScenePushButton->setEnabled(validScene); + if (m_replaceAllScenesPushButton != NULL) { + m_replaceAllScenesPushButton->setEnabled(haveScenes); + } m_testScenesPushButton->setEnabled(haveScenes); m_insertNewScenePushButton->setEnabled(validScene); m_replaceScenePushButton->setEnabled(validScene); @@ -1140,6 +1144,243 @@ SceneDialog::getQImageFromSceneInfo(const SceneInfo* sceneInfo) const return imageOut; } +/** + * Replace all scenes. + */ +void +SceneDialog::replaceAllScenesPushButtonClicked() +{ + SceneFile* sceneFile = getSelectedSceneFile(); + if (sceneFile == NULL) { + WuQMessageBox::errorOk(m_testScenesPushButton, "No scene file is loaded."); + return; + } + + const int32_t numScenes = sceneFile->getNumberOfScenes(); + if (numScenes == 0) { + WuQMessageBox::errorOk(m_replaceAllScenesPushButton, "Selected scene file contains no scenes."); + return; + } + + if ( ! WuQMessageBox::warningOkCancel(m_replaceAllScenesPushButton, + "Replace All Scenes", + m_replaceAllScenesDescription)) { + return; + } + + AString username; + AString password; + + /* + * Check to see if any scenes need a login/password. + * Same login/password is used for all scenes. + */ + for (int32_t i = 0; i < numScenes; i++) { + const Scene* scene = sceneFile->getSceneAtIndex(i); + if (scene != NULL) { + if (scene->hasFilesWithRemotePaths()) { + const QString msg("This scene contains files that are on the network. " + "If accessing the files requires a username and " + "password, enter it here. Otherwise, remove any " + "text from the username and password fields."); + + + if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(m_replaceAllScenesPushButton, + "Username and Password", + msg, + username, + password)) { + CaretDataFile::setFileReadingUsernameAndPassword(username, + password); + break; + } + } + } + } + + showWaitCursor(); + + const int IMAGE_DISPLAY_WIDTH = 400; + std::vector sceneNames; + std::vector sceneErrors; + std::vector oldImages; + std::vector newImages; + + for (int32_t i = 0; i < numScenes; i++) { + Scene* origScene = sceneFile->getSceneAtIndex(i); + if (origScene != NULL) { + if (origScene->hasFilesWithRemotePaths()) { + CaretDataFile::setFileReadingUsernameAndPassword(username, + password); + } + + const QImage* imageFromScene = getQImageFromSceneInfo(origScene->getSceneInfo()); + if (imageFromScene != NULL) { + oldImages.push_back(imageFromScene->scaledToWidth(IMAGE_DISPLAY_WIDTH)); + } + else { + oldImages.push_back(QImage()); + } + + /* + * Display the scene + */ + AString errorMessage; + const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); + sceneNames.push_back(origScene->getName()); + + /* + * Assume scene loads correctly + */ + Scene* newScene = new Scene(SceneTypeEnum::SCENE_TYPE_FULL); + Scene::setSceneBeingCreated(newScene); + newScene->setName(origScene->getName()); + newScene->setDescription(origScene->getDescription()); + newScene->setBalsaSceneID(origScene->getBalsaSceneID()); + + const std::vector windowIndices = GuiManager::get()->getAllOpenBrainBrowserWindowIndices(); + + /* + * Get all browser tabs and only save transformations for tabs + * that are valid. + */ + std::vector tabIndices; + EventBrowserTabGetAll getAllTabs; + EventManager::get()->sendEvent(getAllTabs.getPointer()); + tabIndices = getAllTabs.getBrowserTabIndices(); + std::sort(tabIndices.begin(), + tabIndices.end()); + + SceneAttributes* sceneAttributes = newScene->getAttributes(); + sceneAttributes->setSceneFileName(getSelectedSceneFile()->getFileName()); + sceneAttributes->setSceneName(origScene->getName()); + sceneAttributes->setIndicesOfTabsAndWindowsForSavingToScene(tabIndices, + windowIndices); + sceneAttributes->setSpecFileNameSavedToScene(true); + sceneAttributes->setAllLoadedFilesSavedToScene(true); + sceneAttributes->setModifiedPaletteSettingsSavedToScene(true); + + newScene->addClass(GuiManager::get()->saveToScene(sceneAttributes, + "guiManager")); + + AString imageErrorMessage; + SceneCreateReplaceDialog::addImageToScene(newScene, + imageErrorMessage); + if ( ! imageErrorMessage.isEmpty()) { + errorMessage.appendWithNewLine(imageErrorMessage); + } + + getSelectedSceneFile()->replaceScene(newScene, + origScene); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + loadScenesIntoDialog(newScene); + const QImage* newImage = getQImageFromSceneInfo(newScene->getSceneInfo()); + if (newImage != NULL) { + newImages.push_back(newImage->scaledToWidth(IMAGE_DISPLAY_WIDTH)); + } + else { + newImages.push_back(QImage()); + } + sceneErrors.push_back(errorMessage); + } + } + + CaretAssert(sceneNames.size() == sceneErrors.size()); + CaretAssert(sceneNames.size() == oldImages.size()); + CaretAssert(sceneNames.size() == newImages.size()); + + showNormalCursor(); + + const int32_t numValidScenes = static_cast(sceneNames.size()); + if (numValidScenes <= 0) { + WuQMessageBox::errorOk(m_replaceAllScenesPushButton, + "No scenes were loaded."); + return; + } + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 0); + + for (int32_t i = 0; i < numValidScenes; i++) { + int row = gridLayout->rowCount(); + if (i > 0) { + gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), + row, 0, 1, 4); + row++; + } + + gridLayout->addWidget(new QLabel("Scene Name: " + sceneNames[i]), + row, 0, Qt::AlignLeft); + + if ( ! sceneErrors[i].isEmpty()) { + QLabel* errorLabel = new QLabel("Scene Errors: " + sceneErrors[i]); + errorLabel->setWordWrap(true); + gridLayout->addWidget(errorLabel, + row, 1, Qt::AlignLeft); + } + + row++; + + const QSizePolicy::Policy imageSizePolicy = QSizePolicy::Preferred; + + QLabel* sceneImageLabel = new QLabel("Image Invalid"); + if ( ! oldImages[i].isNull()) { + sceneImageLabel->clear(); + sceneImageLabel->setPixmap(QPixmap::fromImage(oldImages[i])); + sceneImageLabel->setSizePolicy(imageSizePolicy, + imageSizePolicy); + } + gridLayout->addWidget(sceneImageLabel, + row, 0); + + QLabel* newImageLabel = new QLabel("Image Invalid"); + if ( ! newImages[i].isNull()) { + newImageLabel->clear(); + newImageLabel->setPixmap(QPixmap::fromImage(newImages[i])); + newImageLabel->setSizePolicy(imageSizePolicy, + imageSizePolicy); + } + gridLayout->addWidget(newImageLabel, + row, 1); + } + + const int numRows = gridLayout->rowCount(); + for (int32_t i = 0; i < numRows; i++) { + gridLayout->setRowStretch(i, 0); + } + + QWidget* dialogWidget = new QWidget(); + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addLayout(gridLayout); + + WuQDialogNonModal* dialog = new WuQDialogNonModal("Scene Results", + m_replaceAllScenesPushButton); + dialog->setDeleteWhenClosed(true); + dialog->setApplyButtonText(""); + dialog->setCentralWidget(dialogWidget, + WuQDialogNonModal::SCROLL_AREA_ALWAYS); + dialog->show(); + + WuQtUtilities::limitWindowSizePercentageOfMaximum(dialog, + 100.0, + 100.0); + + const int dialogWidth = (IMAGE_DISPLAY_WIDTH * 2) + 50; + const int dialogHeight = (IMAGE_DISPLAY_WIDTH * 2.5); + WuQtUtilities::resizeWindow(dialog, + dialogWidth, + dialogHeight); + + dialog->show(); +} + /** * Test all scenes by loading them and then * displaying images that are stored with the @@ -1633,6 +1874,14 @@ SceneDialog::createScenesWidget() QObject::connect(m_deleteScenePushButton, SIGNAL(clicked()), this, SLOT(deleteSceneButtonClicked())); + /* + * Replace all scenes + */ + m_replaceAllScenesPushButton = new QPushButton("Replace All..."); + m_replaceAllScenesPushButton->setToolTip(m_replaceAllScenesDescription); + QObject::connect(m_replaceAllScenesPushButton, SIGNAL(clicked()), + this, SLOT(replaceAllScenesPushButtonClicked())); + /* * Test all scenes */ @@ -2315,6 +2564,13 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, return false; } + std::vector allSceneObjects; + if (m_checkForUnrestoredItemsCheckBox->isChecked()) { + allSceneObjects = scene->getDescendants(); + } + + SceneClass::setDebugLoggingEnabled(m_checkForUnrestoredItemsCheckBox->isChecked()); + /* * Show the wait cursor */ @@ -2333,8 +2589,21 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, sceneAttributes->setWindowRestoreBehaviorInSceneDisplay(SceneAttributes::RESTORE_WINDOW_POSITION_RELATIVE_TO_FIRST_AND_USE_SIZES); sceneAttributes->setUseSceneForegroundAndBackgroundColors(s_useSceneForegroundBackgroundColorsFlag); + if ( ! allSceneObjects.empty()) { + SceneObject::setRestoredStatus(allSceneObjects, + false); + } + GuiManager::get()->restoreFromScene(sceneAttributes, guiManagerClass); + guiManagerClass->setRestored(true); + + if ( ! allSceneObjects.empty()) { + SceneObject::logObjectsFailedRestore(scene->getName(), + allSceneObjects); + } + + SceneClass::setDebugLoggingEnabled(false); cursor.restoreCursor(); diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index 3c18e1bab..8bd5692d1 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -118,6 +118,8 @@ namespace caret { void testScenesPushButtonClicked(); + void replaceAllScenesPushButtonClicked(); + public: // ADD_NEW_METHODS_HERE @@ -204,6 +206,8 @@ namespace caret { QPushButton* m_deleteScenePushButton; + QPushButton* m_replaceAllScenesPushButton; + QPushButton* m_testScenesPushButton; QPushButton* m_moveSceneUpPushButton; @@ -220,6 +224,8 @@ namespace caret { QPushButton* m_createSceneOptionsPushButton; + QCheckBox* m_checkForUnrestoredItemsCheckBox; + QScrollArea* m_sceneSelectionScrollArea; QWidget* m_sceneSelectionWidget; @@ -232,6 +238,8 @@ namespace caret { WuQWidgetObjectGroup* m_sceneFileButtonsGroup; + AString m_replaceAllScenesDescription; + AString m_testAllScenesDescription; QIcon m_cautionIcon; diff --git a/src/Scenes/Scene.cxx b/src/Scenes/Scene.cxx index 4a99dff33..b1fcd8ec8 100644 --- a/src/Scenes/Scene.cxx +++ b/src/Scenes/Scene.cxx @@ -265,6 +265,28 @@ Scene::~Scene() delete m_sceneInfo; } +/** + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +Scene::getDescendants() const +{ + std::vector descendants; + + const int32_t numberOfSceneClasses = this->getNumberOfClasses(); + for (int32_t i = 0; i < numberOfSceneClasses; i++) { + SceneObject* object = m_sceneClasses[i]; + descendants.push_back(object); + + std::vector objectDescendants = object->getDescendants(); + descendants.insert(descendants.end(), + objectDescendants.begin(), + objectDescendants.end()); + } + + return descendants; +} + /** * @return Attributes of the scene */ @@ -311,6 +333,7 @@ const SceneClass* Scene::getClassAtIndex(const int32_t indx) const { CaretAssertVectorIndex(m_sceneClasses, indx); + m_sceneClasses[indx]->setRestored(true); return m_sceneClasses[indx]; } @@ -326,6 +349,7 @@ Scene::getClassWithName(const AString& sceneClassName) const const int32_t numberOfSceneClasses = this->getNumberOfClasses(); for (int32_t i = 0; i < numberOfSceneClasses; i++) { if (m_sceneClasses[i]->getName() == sceneClassName) { + m_sceneClasses[i]->setRestored(true); return m_sceneClasses[i]; } } diff --git a/src/Scenes/Scene.h b/src/Scenes/Scene.h index 44232374a..02b932c56 100644 --- a/src/Scenes/Scene.h +++ b/src/Scenes/Scene.h @@ -29,6 +29,7 @@ namespace caret { class SceneAttributes; class SceneClass; class SceneInfo; + class SceneObject; class Scene : public CaretObject { @@ -48,6 +49,8 @@ namespace caret { SceneAttributes* getAttributes(); + std::vector getDescendants() const; + void addClass(SceneClass* sceneClass); int32_t getNumberOfClasses() const; diff --git a/src/Scenes/SceneBoolean.cxx b/src/Scenes/SceneBoolean.cxx index db25df123..6e057255a 100644 --- a/src/Scenes/SceneBoolean.cxx +++ b/src/Scenes/SceneBoolean.cxx @@ -86,6 +86,7 @@ SceneBoolean::setValue(const bool value) bool SceneBoolean::booleanValue() const { + m_restoredFlag = true; return m_value; } @@ -95,6 +96,7 @@ SceneBoolean::booleanValue() const float SceneBoolean::floatValue() const { + m_restoredFlag = true; const float f = (m_value ? 1.0 : 0.0); return f; } @@ -105,6 +107,7 @@ SceneBoolean::floatValue() const int32_t SceneBoolean::integerValue() const { + m_restoredFlag = true; const int32_t i = (m_value ? 1 : 0); return i; } @@ -115,6 +118,7 @@ SceneBoolean::integerValue() const AString SceneBoolean::stringValue() const { + m_restoredFlag = true; const AString s = (m_value ? "true" : "false"); return s; } @@ -125,5 +129,6 @@ SceneBoolean::stringValue() const uint8_t SceneBoolean::unsignedByteValue() const { + m_restoredFlag = true; return m_value; } diff --git a/src/Scenes/SceneClass.cxx b/src/Scenes/SceneClass.cxx index eac5b1a3e..12dfb959d 100644 --- a/src/Scenes/SceneClass.cxx +++ b/src/Scenes/SceneClass.cxx @@ -74,7 +74,7 @@ SceneClass::SceneClass(const AString& name, m_className(className), m_versionNumber(versionNumber) { - + } SceneClass::SceneClass(const SceneClass& rhs): SceneObject(rhs.getName(), SceneObjectDataTypeEnum::SCENE_CLASS), @@ -124,6 +124,30 @@ SceneClass::getVersionNumber() const return m_versionNumber; } +/** + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +SceneClass::getDescendants() const +{ + std::vector descendants; + + for (std::vector::const_iterator iter = m_childObjects.begin(); + iter != m_childObjects.end(); + iter++) { + SceneObject* so = *iter; + descendants.push_back(so); + + std::vector childDescendants = so->getDescendants(); + descendants.insert(descendants.end(), + childDescendants.begin(), + childDescendants.end()); + } + + return descendants; +} + + /** * Add a child to this class. * @param sceneObject @@ -486,10 +510,20 @@ AString SceneClass::getEnumeratedTypeValueAsString(const AString& name, const AString& defaultValue) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const SceneEnumeratedType* st = dynamic_cast(so); +// if (st != NULL) { +// if (st->getName() == name) { +// return st->stringValue(); +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { const SceneEnumeratedType* st = dynamic_cast(so); if (st != NULL) { if (st->getName() == name) { @@ -522,18 +556,29 @@ SceneClass::getEnumeratedTypeArrayValue(const AString& name, const int32_t arrayNumberOfElements, const AString& defaultValue) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const SceneEnumeratedTypeArray* enumArray = dynamic_cast(so); +// if (enumArray != NULL) { +// if (enumArray->getName() == name) { +// enumArray->stringValues(values, +// arrayNumberOfElements, +// defaultValue); +// return enumArray->getNumberOfArrayElements(); +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { const SceneEnumeratedTypeArray* enumArray = dynamic_cast(so); if (enumArray != NULL) { - if (enumArray->getName() == name) { - enumArray->stringValues(values, - arrayNumberOfElements, - defaultValue); - return enumArray->getNumberOfArrayElements(); - } + enumArray->stringValues(values, + arrayNumberOfElements, + defaultValue); + return enumArray->getNumberOfArrayElements(); } } @@ -789,15 +834,23 @@ SceneClass::getStringArrayValue(const AString& name, const ScenePrimitive* SceneClass::getPrimitive(const AString& name) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const ScenePrimitive* sp = dynamic_cast(so); +// if (sp != NULL) { +// if (sp->getName() == name) { +// return sp; +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { const ScenePrimitive* sp = dynamic_cast(so); if (sp != NULL) { - if (sp->getName() == name) { - return sp; - } + return sp; } } @@ -822,9 +875,7 @@ SceneClass::getPathName(const AString& name) const if (so != NULL) { const ScenePathName* sp = dynamic_cast(so); if (sp != NULL) { - if (sp->getName() == name) { - return sp; - } + return sp; } } @@ -845,15 +896,23 @@ SceneClass::getPathName(const AString& name) const const ScenePrimitiveArray* SceneClass::getPrimitiveArray(const AString& name) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const ScenePrimitiveArray* spa = dynamic_cast(so); +// if (spa != NULL) { +// if (spa->getName() == name) { +// return spa; +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { const ScenePrimitiveArray* spa = dynamic_cast(so); if (spa != NULL) { - if (spa->getName() == name) { - return spa; - } + return spa; } } @@ -873,15 +932,23 @@ SceneClass::getPrimitiveArray(const AString& name) const const ScenePathNameArray* SceneClass::getPathNameArray(const AString& name) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; - if (so->getName() == name) { - const ScenePathNameArray* spa = dynamic_cast(so); - if (spa != NULL) { - return spa; - } +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// if (so->getName() == name) { +// const ScenePathNameArray* spa = dynamic_cast(so); +// if (spa != NULL) { +// return spa; +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { + const ScenePathNameArray* spa = dynamic_cast(so); + if (spa != NULL) { + return spa; } } @@ -902,15 +969,23 @@ SceneClass::getPathNameArray(const AString& name) const const SceneClass* SceneClass::getClass(const AString& name) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const SceneClass* sc = dynamic_cast(so); +// if (sc != NULL) { +// if (sc->getName() == name) { +// return sc; +// } +// } +// } + + const SceneObject* so = getObjectWithName(name); + if (so != NULL) { const SceneClass* sc = dynamic_cast(so); if (sc != NULL) { - if (sc->getName() == name) { - return sc; - } + return sc; } } @@ -931,15 +1006,24 @@ SceneClass::getClass(const AString& name) const SceneClass* SceneClass::getClass(const AString& name) { - for (std::vector::iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - SceneObject* so = *iter; +// for (std::vector::iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// SceneObject* so = *iter; +// SceneClass* sc = dynamic_cast(so); +// if (sc != NULL) { +// if (sc->getName() == name) { +// return sc; +// } +// } +// } + + const SceneObject* soConst = getObjectWithName(name); + if (soConst != NULL) { + SceneObject* so = const_cast(soConst); SceneClass* sc = dynamic_cast(so); if (sc != NULL) { - if (sc->getName() == name) { - return sc; - } + return sc; } } @@ -987,15 +1071,24 @@ SceneClass::getMapIntegerKey(const AString& name) const SceneClassArray* SceneClass::getClassArray(const AString& name) { - for (std::vector::iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - SceneObject* so = *iter; +// for (std::vector::iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// SceneObject* so = *iter; +// SceneClassArray* sca = dynamic_cast(so); +// if (sca != NULL) { +// if (sca->getName() == name) { +// return sca; +// } +// } +// } + + const SceneObject* soConst = getObjectWithName(name); + if (soConst != NULL) { + SceneObject* so = const_cast(soConst); SceneClassArray* sca = dynamic_cast(so); if (sca != NULL) { - if (sca->getName() == name) { - return sca; - } + return sca; } } @@ -1016,15 +1109,24 @@ SceneClass::getClassArray(const AString& name) const SceneClassArray* SceneClass::getClassArray(const AString& name) const { - for (std::vector::const_iterator iter = m_childObjects.begin(); - iter != m_childObjects.end(); - iter++) { - const SceneObject* so = *iter; +// for (std::vector::const_iterator iter = m_childObjects.begin(); +// iter != m_childObjects.end(); +// iter++) { +// const SceneObject* so = *iter; +// const SceneClassArray* sca = dynamic_cast(so); +// if (sca != NULL) { +// if (sca->getName() == name) { +// return sca; +// } +// } +// } + + const SceneObject* soConst = getObjectWithName(name); + if (soConst != NULL) { + SceneObject* so = const_cast(soConst); const SceneClassArray* sca = dynamic_cast(so); if (sca != NULL) { - if (sca->getName() == name) { - return sca; - } + return sca; } } @@ -1051,6 +1153,7 @@ const SceneObject* SceneClass::getObjectAtIndex(const int32_t indx) const { CaretAssertVectorIndex(m_childObjects, indx); + m_childObjects[indx]->m_restoredFlag = true; return m_childObjects[indx]; } @@ -1063,16 +1166,52 @@ SceneClass::getObjectAtIndex(const int32_t indx) const const SceneObject* SceneClass::getObjectWithName(const AString& name) const { + SceneObject* sceneObject = NULL; + bool wasLoggedFlag = false; + for (std::vector::const_iterator iter = m_childObjects.begin(); iter != m_childObjects.end(); iter++) { - const SceneObject* so = *iter; + SceneObject* so = *iter; if (so->getName() == name) { - return so; + so->m_restoredFlag = true; + + if (s_debugLoggingEnabledFlag) { + if (sceneObject != NULL) { + if ( ! wasLoggedFlag) { + CaretLogWarning("Scene class named \"" + + getName() + + "\" contains more than one child named \"" + + name + + "\". If replacing the scene does not eliminate this message " + "there is an error in the source code"); + wasLoggedFlag = true; + } + } + } + else { + return so; + } + + sceneObject = so; } } - return NULL; + return sceneObject; +} + +/** + * Set debug logging enabled. + * If enabled, message are logged at the warning level + * for duplicated objects and missing objects. + * + * @param status + * New status. + */ +void +SceneClass::setDebugLoggingEnabled(const bool status) +{ + s_debugLoggingEnabledFlag = status; } /** @@ -1085,7 +1224,13 @@ SceneClass::getObjectWithName(const AString& name) const void SceneClass::logMissing(const AString& missingInfo) const { - CaretLogFine(missingInfo); + if (missingInfo.isEmpty()) { + return; + } + + if (s_debugLoggingEnabledFlag) { + CaretLogFine(missingInfo); + } } diff --git a/src/Scenes/SceneClass.h b/src/Scenes/SceneClass.h index 08a1bf68e..758cd4c5a 100644 --- a/src/Scenes/SceneClass.h +++ b/src/Scenes/SceneClass.h @@ -50,6 +50,8 @@ namespace caret { int32_t getVersionNumber() const; + virtual std::vector getDescendants() const; + void addBoolean(const AString& name, const bool value); @@ -299,6 +301,8 @@ namespace caret { virtual SceneObject* clone() const; + static void setDebugLoggingEnabled(const bool status); + // ADD_NEW_METHODS_HERE // private: // and are not used @@ -336,12 +340,14 @@ namespace caret { std::vector m_childObjects; + static bool s_debugLoggingEnabledFlag; + // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_CLASS_DECLARE__ - // + bool SceneClass::s_debugLoggingEnabledFlag = false; #endif // __SCENE_CLASS_DECLARE__ } // namespace diff --git a/src/Scenes/SceneClassArray.cxx b/src/Scenes/SceneClassArray.cxx index bb6ddb5dd..6af530ff8 100644 --- a/src/Scenes/SceneClassArray.cxx +++ b/src/Scenes/SceneClassArray.cxx @@ -116,6 +116,29 @@ SceneClassArray::~SceneClassArray() m_values.clear(); } +/** + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +SceneClassArray::getDescendants() const +{ + std::vector descendants; + + for (std::vector::const_iterator iter = m_values.begin(); + iter != m_values.end(); + iter++) { + SceneClass* sceneClass = *iter; + descendants.push_back(sceneClass); + + std::vector classDescendants = sceneClass->getDescendants(); + descendants.insert(descendants.end(), + classDescendants.begin(), + classDescendants.end()); + } + + return descendants; +} + /** * Set the class for an array index. * @param arrayIndex @@ -156,5 +179,9 @@ const SceneClass* SceneClassArray::getClassAtIndex(const int32_t arrayIndex) const { CaretAssertVectorIndex(m_values, arrayIndex); - return m_values[arrayIndex]; + const SceneClass* sc = m_values[arrayIndex]; + if (sc != NULL) { + sc->m_restoredFlag = true; + } + return sc; } diff --git a/src/Scenes/SceneClassArray.h b/src/Scenes/SceneClassArray.h index 2b626842c..3ee4bb0ea 100644 --- a/src/Scenes/SceneClassArray.h +++ b/src/Scenes/SceneClassArray.h @@ -50,6 +50,8 @@ namespace caret { const SceneClass* getClassAtIndex(const int32_t arrayIndex) const; + virtual std::vector getDescendants() const; + private: SceneClassArray& operator=(const SceneClassArray&); diff --git a/src/Scenes/SceneFloat.cxx b/src/Scenes/SceneFloat.cxx index acf1d64f3..25dedfc0d 100644 --- a/src/Scenes/SceneFloat.cxx +++ b/src/Scenes/SceneFloat.cxx @@ -88,6 +88,7 @@ SceneFloat::setValue(const float value) bool SceneFloat::booleanValue() const { + m_restoredFlag = true; const bool b = ((m_value != 0.0) ? true : false); return b; } @@ -98,6 +99,7 @@ SceneFloat::booleanValue() const float SceneFloat::floatValue() const { + m_restoredFlag = true; return m_value; } @@ -107,6 +109,7 @@ SceneFloat::floatValue() const int32_t SceneFloat::integerValue() const { + m_restoredFlag = true; if (m_value > std::numeric_limits::max()) { return std::numeric_limits::max(); } @@ -124,6 +127,7 @@ SceneFloat::integerValue() const AString SceneFloat::stringValue() const { + m_restoredFlag = true; const AString s = AString::number(m_value); return s; } @@ -137,6 +141,7 @@ SceneFloat::stringValue() const uint8_t SceneFloat::unsignedByteValue() const { + m_restoredFlag = true; if (m_value > std::numeric_limits::max()) { return std::numeric_limits::max(); } diff --git a/src/Scenes/SceneInteger.cxx b/src/Scenes/SceneInteger.cxx index f9dec5a70..83ec5b129 100644 --- a/src/Scenes/SceneInteger.cxx +++ b/src/Scenes/SceneInteger.cxx @@ -88,6 +88,7 @@ SceneInteger::setValue(const int32_t value) bool SceneInteger::booleanValue() const { + m_restoredFlag = true; const bool b = ((m_value != 0.0) ? true : false); return b; } @@ -98,6 +99,7 @@ SceneInteger::booleanValue() const float SceneInteger::floatValue() const { + m_restoredFlag = true; const float f = static_cast(m_value); return f; } @@ -108,6 +110,7 @@ SceneInteger::floatValue() const int32_t SceneInteger::integerValue() const { + m_restoredFlag = true; return m_value; } @@ -117,6 +120,7 @@ SceneInteger::integerValue() const AString SceneInteger::stringValue() const { + m_restoredFlag = true; const AString s = AString::number(m_value); return s; } @@ -130,6 +134,7 @@ SceneInteger::stringValue() const uint8_t SceneInteger::unsignedByteValue() const { + m_restoredFlag = true; if (m_value > std::numeric_limits::max()) { return std::numeric_limits::max(); } diff --git a/src/Scenes/SceneObject.cxx b/src/Scenes/SceneObject.cxx index 0e539d16f..f1b085d56 100644 --- a/src/Scenes/SceneObject.cxx +++ b/src/Scenes/SceneObject.cxx @@ -24,6 +24,7 @@ #undef __SCENE_OBJECT_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" using namespace caret; @@ -47,9 +48,9 @@ using namespace caret; SceneObject::SceneObject(const QString& name, const SceneObjectDataTypeEnum::Enum dataType) #ifdef CARET_SCENE_DEBUG -: CaretObject(), m_name(name), m_dataType(dataType) +: CaretObject(), m_name(name), m_dataType(dataType), m_restoredFlag(false) #else // CARET_SCENE_DEBUG -: m_name(name), m_dataType(dataType) +: m_name(name), m_dataType(dataType), m_restoredFlag(false) #endif // CARET_SCENE_DEBUG { CaretAssert(name.isEmpty() == false); @@ -81,6 +82,114 @@ SceneObject::getDataType() const return m_dataType; } +/** + * @return Has this instance been restored? + */ +bool +SceneObject::isRestored() const +{ + return m_restoredFlag; +} + +/** + * Set this instance restored. + * + * @param restoredFlag + * New restored status + */ +void +SceneObject::setRestored(const bool restoredFlag) const +{ + m_restoredFlag = restoredFlag; +} + +/** + * Set this instance and all descendants restored. + * + * @param restoredFlag + * New restored status + */ +void +SceneObject::setDescendantsRestored(const bool restoredFlag) const +{ + setRestored(restoredFlag); + std::vector descendants = getDescendants(); + setRestoredStatus(descendants, restoredFlag); +} + +/** + * Set the restored status for all scene objects. + * + * @param sceneObject + * Scene objects whose restored status is set. + * @param restoredStatus + * New status applied to all scene object. + */ +void +SceneObject::setRestoredStatus(std::vector sceneObjects, + const bool restoredStatus) +{ + for (std::vector::iterator iter = sceneObjects.begin(); + iter != sceneObjects.end(); + iter++) { + (*iter)->m_restoredFlag = restoredStatus; + } +} + +/** + * If scene objects failed to restore, log at the warning level. + * + * @param sceneName + * Name of the scene. + * @param sceneObjects + * Scene objects that are verified restored. + */ +void +SceneObject::logObjectsFailedRestore(const AString& sceneName, + const std::vector sceneObjects) +{ + int64_t failCount = 0; + + AString msg; + + for (std::vector::const_iterator iter = sceneObjects.begin(); + iter != sceneObjects.end(); + iter++) { + if ( ! (*iter)->m_restoredFlag) { + failCount++; + + if (failCount < 25) { + msg.appendWithNewLine(" " + + (*iter)->toString()); + } + } + } + + if (failCount > 0) { + CaretLogWarning(sceneName + + "\n" + "Failed to restore " + + AString::number(failCount) + + " scene objects.\n" + + msg); + } +} + + +/** + * Get all descendants of this instance. This method should be + * overridden by sub-classes that have children. + * + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +SceneObject::getDescendants() const +{ + std::vector descendants; + return descendants; +} + + /** * Get a description of this object's content. * @return String describing this object's content. @@ -88,5 +197,9 @@ SceneObject::getDataType() const AString SceneObject::toString() const { - return "SceneObject"; + QString objectInfo("Scene Object Type=" + + SceneObjectDataTypeEnum::toName(m_dataType) + + " name=" + + m_name); + return objectInfo; } diff --git a/src/Scenes/SceneObject.h b/src/Scenes/SceneObject.h index a6c739143..bd4b00709 100644 --- a/src/Scenes/SceneObject.h +++ b/src/Scenes/SceneObject.h @@ -40,6 +40,21 @@ namespace caret { SceneObjectDataTypeEnum::Enum getDataType() const; + bool isRestored() const; + + void setRestored(const bool restoredFlag) const; + + void setDescendantsRestored(const bool restoredFlag) const; + + static void setRestoredStatus(std::vector sceneObjects, + const bool restoredStatus); + + static void logObjectsFailedRestore(const AString& sceneName, + const std::vector sceneObjects); + + /// Should be overridden by any sub-classes that have children + virtual std::vector getDescendants() const; + protected: SceneObject(const QString& name, const SceneObjectDataTypeEnum::Enum dataType); @@ -66,6 +81,16 @@ namespace caret { /** Type of object */ const SceneObjectDataTypeEnum::Enum m_dataType; + protected: + mutable bool m_restoredFlag; + + private: + friend class SceneClass; + friend class SceneClassArray; + friend class SceneObjectMapIntegerKey; + friend class ScenePathName; + friend class ScenePathNameArray; + }; #ifdef __SCENE_OBJECT_DECLARE__ diff --git a/src/Scenes/SceneObjectArray.cxx b/src/Scenes/SceneObjectArray.cxx index a44c166ee..7ef2a8d0f 100644 --- a/src/Scenes/SceneObjectArray.cxx +++ b/src/Scenes/SceneObjectArray.cxx @@ -59,3 +59,4 @@ SceneObjectArray::~SceneObjectArray() { } + diff --git a/src/Scenes/SceneObjectMapIntegerKey.cxx b/src/Scenes/SceneObjectMapIntegerKey.cxx index e36ed985b..987493023 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.cxx +++ b/src/Scenes/SceneObjectMapIntegerKey.cxx @@ -78,6 +78,29 @@ SceneObjectMapIntegerKey::~SceneObjectMapIntegerKey() } } +/** + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +SceneObjectMapIntegerKey::getDescendants() const +{ + std::vector descendants; + + for (DATA_MAP_CONST_ITERATOR iter = m_dataMap.begin(); + iter != m_dataMap.end(); + iter++) { + SceneObject* sceneObject = iter->second; + descendants.push_back(sceneObject); + + std::vector objectDescendants = sceneObject->getDescendants(); + descendants.insert(descendants.end(), + objectDescendants.begin(), + objectDescendants.end()); + } + + return descendants; +} + /** * Add the given boolean value to the map using the given key. * @param key @@ -223,6 +246,7 @@ SceneObjectMapIntegerKey::getObject(const int32_t key) const CaretAssert(iter != m_dataMap.end()); const SceneObject* object = iter->second; CaretAssert(object); + object->m_restoredFlag = true; return object; } diff --git a/src/Scenes/SceneObjectMapIntegerKey.h b/src/Scenes/SceneObjectMapIntegerKey.h index 6ab9baa10..aa558a5b3 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.h +++ b/src/Scenes/SceneObjectMapIntegerKey.h @@ -37,6 +37,8 @@ namespace caret { SceneObjectMapIntegerKey(const QString& name, const SceneObjectDataTypeEnum::Enum valueDataType); + virtual std::vector getDescendants() const; + private: SceneObjectMapIntegerKey(const SceneObjectMapIntegerKey&); @@ -86,9 +88,9 @@ namespace caret { SceneClass* value); std::vector getKeys() const; - + const std::map& getMap() const; - + const SceneObject* getObject(const int32_t key) const; const SceneClass* classValue(const int32_t key) const; diff --git a/src/Scenes/ScenePathName.cxx b/src/Scenes/ScenePathName.cxx index 51e867251..f37ad16d5 100644 --- a/src/Scenes/ScenePathName.cxx +++ b/src/Scenes/ScenePathName.cxx @@ -104,6 +104,7 @@ ScenePathName::setValue(const AString& value) AString ScenePathName::stringValue() const { + m_restoredFlag = true; return m_value; } diff --git a/src/Scenes/ScenePathNameArray.cxx b/src/Scenes/ScenePathNameArray.cxx index ed5676fd3..4a53446f5 100644 --- a/src/Scenes/ScenePathNameArray.cxx +++ b/src/Scenes/ScenePathNameArray.cxx @@ -122,6 +122,22 @@ ScenePathNameArray::~ScenePathNameArray() m_values.clear(); } +/** + * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. + */ +std::vector +ScenePathNameArray::getDescendants() const +{ + std::vector descendants; + + for (std::vector::const_iterator iter = m_values.begin(); + iter != m_values.end(); + iter++) { + descendants.push_back(*iter); + } + + return descendants; +} /** * Set the class for an array index. * @param arrayIndex @@ -172,6 +188,10 @@ ScenePathName* ScenePathNameArray::getScenePathNameAtIndex(const int32_t arrayIndex) const { CaretAssertVectorIndex(m_values, arrayIndex); - return m_values[arrayIndex]; + ScenePathName* spm = m_values[arrayIndex]; + if (spm != NULL) { + spm->m_restoredFlag = true; + } + return spm; } diff --git a/src/Scenes/ScenePathNameArray.h b/src/Scenes/ScenePathNameArray.h index 8f7f5d192..dcc6d16ac 100644 --- a/src/Scenes/ScenePathNameArray.h +++ b/src/Scenes/ScenePathNameArray.h @@ -51,6 +51,8 @@ namespace caret { ScenePathName* getScenePathNameAtIndex(const int32_t arrayIndex) const; + virtual std::vector getDescendants() const; + private: ScenePathNameArray& operator=(const ScenePathNameArray&); diff --git a/src/Scenes/ScenePrimitive.cxx b/src/Scenes/ScenePrimitive.cxx index d48fb376f..70b707b98 100644 --- a/src/Scenes/ScenePrimitive.cxx +++ b/src/Scenes/ScenePrimitive.cxx @@ -60,3 +60,17 @@ ScenePrimitive::~ScenePrimitive() } +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ScenePrimitive::toString() const +{ + QString objectInfo(SceneObject::toString() + + " value=" + + stringValue()); + return objectInfo; +} + + diff --git a/src/Scenes/ScenePrimitive.h b/src/Scenes/ScenePrimitive.h index 24be2be81..e64c158df 100644 --- a/src/Scenes/ScenePrimitive.h +++ b/src/Scenes/ScenePrimitive.h @@ -40,6 +40,8 @@ namespace caret { ScenePrimitive& operator=(const ScenePrimitive&); + virtual AString toString() const; + public: // ADD_NEW_METHODS_HERE diff --git a/src/Scenes/SceneString.cxx b/src/Scenes/SceneString.cxx index 92132ada2..c16f9898f 100644 --- a/src/Scenes/SceneString.cxx +++ b/src/Scenes/SceneString.cxx @@ -88,6 +88,7 @@ SceneString::setValue(const AString& value) bool SceneString::booleanValue() const { + m_restoredFlag = true; const bool b = m_value.toBool(); return b; } @@ -100,6 +101,7 @@ SceneString::booleanValue() const float SceneString::floatValue() const { + m_restoredFlag = true; bool isValid = false; float f = m_value.toFloat(&isValid); if (isValid == false) { @@ -116,6 +118,7 @@ SceneString::floatValue() const int32_t SceneString::integerValue() const { + m_restoredFlag = true; bool isValid = false; int32_t i = m_value.toInt(&isValid); if (isValid == false) { @@ -130,6 +133,7 @@ SceneString::integerValue() const AString SceneString::stringValue() const { + m_restoredFlag = true; return m_value; } @@ -142,6 +146,7 @@ SceneString::stringValue() const uint8_t SceneString::unsignedByteValue() const { + m_restoredFlag = true; bool isValid = false; const uint32_t i = m_value.toUInt(&isValid); if ( ! isValid) { @@ -160,3 +165,4 @@ SceneString::unsignedByteValue() const const uint8_t b = static_cast(i); return b; } + diff --git a/src/Scenes/SceneStringArray.cxx b/src/Scenes/SceneStringArray.cxx index c5e4a0d63..bdab564ad 100644 --- a/src/Scenes/SceneStringArray.cxx +++ b/src/Scenes/SceneStringArray.cxx @@ -135,6 +135,7 @@ SceneStringArray::setValue(const int32_t arrayIndex, bool SceneStringArray::booleanValue(const int32_t arrayIndex) const { + m_restoredFlag = true; CaretAssertVectorIndex(m_values, arrayIndex); const bool b = m_values[arrayIndex].toBool(); return b; @@ -149,6 +150,7 @@ SceneStringArray::booleanValue(const int32_t arrayIndex) const float SceneStringArray::floatValue(const int32_t arrayIndex) const { + m_restoredFlag = true; CaretAssertVectorIndex(m_values, arrayIndex); bool isValid = false; float f = m_values[arrayIndex].toFloat(&isValid); @@ -167,6 +169,7 @@ SceneStringArray::floatValue(const int32_t arrayIndex) const int32_t SceneStringArray::integerValue(const int32_t arrayIndex) const { + m_restoredFlag = true; CaretAssertVectorIndex(m_values, arrayIndex); bool isValid = false; int32_t i = m_values[arrayIndex].toInt(&isValid); @@ -185,6 +188,7 @@ SceneStringArray::integerValue(const int32_t arrayIndex) const AString SceneStringArray::stringValue(const int32_t arrayIndex) const { + m_restoredFlag = true; CaretAssertVectorIndex(m_values, arrayIndex); return m_values[arrayIndex]; } @@ -198,6 +202,7 @@ SceneStringArray::stringValue(const int32_t arrayIndex) const uint8_t SceneStringArray::unsignedByteValue(const int32_t arrayIndex) const { + m_restoredFlag = true; bool isValid = false; const uint32_t i = m_values[arrayIndex].toUInt(&isValid); if ( ! isValid) { diff --git a/src/Scenes/SceneUnsignedByte.cxx b/src/Scenes/SceneUnsignedByte.cxx index 6dfab6b48..182d14f83 100644 --- a/src/Scenes/SceneUnsignedByte.cxx +++ b/src/Scenes/SceneUnsignedByte.cxx @@ -88,6 +88,7 @@ SceneUnsignedByte::setValue(const uint8_t value) bool SceneUnsignedByte::booleanValue() const { + m_restoredFlag = true; const bool b = ((m_value != 0) ? true : false); return b; } @@ -98,6 +99,7 @@ SceneUnsignedByte::booleanValue() const float SceneUnsignedByte::floatValue() const { + m_restoredFlag = true; const float f = static_cast(m_value); return f; } @@ -108,6 +110,7 @@ SceneUnsignedByte::floatValue() const int32_t SceneUnsignedByte::integerValue() const { + m_restoredFlag = true; return m_value; } @@ -117,6 +120,7 @@ SceneUnsignedByte::integerValue() const AString SceneUnsignedByte::stringValue() const { + m_restoredFlag = true; const AString s = AString::number(m_value); return s; } @@ -127,5 +131,6 @@ SceneUnsignedByte::stringValue() const uint8_t SceneUnsignedByte::unsignedByteValue() const { + m_restoredFlag = true; return m_value; } -- GitLab From 2a8e2e120f624a29379a69b06a09f2f031c363d6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 27 Dec 2016 16:23:43 -0600 Subject: [PATCH 175/755] Continuing development of version two of charting. Added chart overlays. --- src/Brain/BrowserTabContent.cxx | 27 + src/Brain/BrowserTabContent.h | 5 + src/Brain/CMakeLists.txt | 8 + src/Brain/ChartOverlay.cxx | 541 +++++++++ src/Brain/ChartOverlay.h | 152 +++ src/Brain/ChartOverlaySet.cxx | 574 +++++++++ src/Brain/ChartOverlaySet.h | 130 +++ src/Brain/ChartOverlaySetArray.cxx | 172 +++ src/Brain/ChartOverlaySetArray.h | 78 ++ src/Brain/MatrixViewingTypeEnum.cxx | 382 ++++++ src/Brain/MatrixViewingTypeEnum.h | 107 ++ src/Brain/Model.cxx | 28 + src/Brain/Model.h | 5 + src/Brain/ModelChart.cxx | 57 + src/Brain/ModelChart.h | 7 + src/GuiQt/AnnotationCoordinateWidget.cxx | 2 +- .../BrainBrowserWindowOrientedToolBox.cxx | 10 + src/GuiQt/BrainBrowserWindowOrientedToolBox.h | 7 +- src/GuiQt/CMakeLists.txt | 6 + src/GuiQt/ChartOverlaySetViewController.cxx | 396 +++++++ src/GuiQt/ChartOverlaySetViewController.h | 91 ++ src/GuiQt/ChartOverlayViewController.cxx | 1024 +++++++++++++++++ src/GuiQt/ChartOverlayViewController.h | 171 +++ ...ventOverlaySettingsEditorDialogRequest.cxx | 33 + .../EventOverlaySettingsEditorDialogRequest.h | 20 + src/GuiQt/MapYokingGroupComboBox.cxx | 42 + src/GuiQt/MapYokingGroupComboBox.h | 3 + 27 files changed, 4076 insertions(+), 2 deletions(-) create mode 100644 src/Brain/ChartOverlay.cxx create mode 100644 src/Brain/ChartOverlay.h create mode 100644 src/Brain/ChartOverlaySet.cxx create mode 100644 src/Brain/ChartOverlaySet.h create mode 100644 src/Brain/ChartOverlaySetArray.cxx create mode 100644 src/Brain/ChartOverlaySetArray.h create mode 100644 src/Brain/MatrixViewingTypeEnum.cxx create mode 100644 src/Brain/MatrixViewingTypeEnum.h create mode 100644 src/GuiQt/ChartOverlaySetViewController.cxx create mode 100644 src/GuiQt/ChartOverlaySetViewController.h create mode 100644 src/GuiQt/ChartOverlayViewController.cxx create mode 100644 src/GuiQt/ChartOverlayViewController.h diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 0fbc244cd..1b30ef45e 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -40,6 +40,7 @@ #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartModelDataSeries.h" +#include "ChartOverlaySet.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "ClippingPlaneGroup.h" @@ -847,6 +848,32 @@ BrowserTabContent::getOverlaySet() const return NULL; } +/** + * @return Overlay set for this tab. + */ +ChartOverlaySet* +BrowserTabContent::getChartOverlaySet() +{ + Model* model = getModelForDisplay(); + if (model != NULL) { + return model->getChartOverlaySet(m_tabNumber); + } + return NULL; +} + +/** + * @return Overlay set for this tab. + */ +const ChartOverlaySet* +BrowserTabContent::getChartOverlaySet() const +{ + const Model* model = getModelForDisplay(); + if (model != NULL) { + return model->getChartOverlaySet(m_tabNumber); + } + return NULL; +} + /** * Get the tab number for this content. * diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index b7d63e4f6..c8e9d28f8 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -43,6 +43,7 @@ namespace caret { class BrainOpenGLViewportContent; class CaretDataFile; class CaretMappableDataFile; + class ChartOverlaySet; class ClippingPlaneGroup; class Matrix4x4; class ModelChart; @@ -93,6 +94,10 @@ namespace caret { const OverlaySet* getOverlaySet() const; + ChartOverlaySet* getChartOverlaySet(); + + const ChartOverlaySet* getChartOverlaySet() const; + int32_t getTabNumber() const; ModelTypeEnum::Enum getSelectedModelType() const; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index e7f3280b2..fa1606c42 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -79,6 +79,9 @@ BrowserTabContent.h CaretDataFileSelectionModel.h CaretMappableDataFileAndMapSelectionModel.h CaretOpenGLInclude.h +ChartOverlay.h +ChartOverlaySet.h +ChartOverlaySetArray.h ChartingDataManager.h CiftiConnectivityMatrixDataFileManager.h CiftiFiberTrajectoryManager.h @@ -135,6 +138,7 @@ IdentifiedItem.h IdentifiedItemNode.h IdentifiedItemVoxel.h ImageDepthPositionEnum.h +MatrixViewingTypeEnum.h Model.h ModelChart.h ModelSurface.h @@ -218,6 +222,9 @@ BrainStructureNodeAttributes.cxx BrowserTabContent.cxx CaretDataFileSelectionModel.cxx CaretMappableDataFileAndMapSelectionModel.cxx +ChartOverlay.cxx +ChartOverlaySet.cxx +ChartOverlaySetArray.cxx ChartingDataManager.cxx CiftiConnectivityMatrixDataFileManager.cxx CiftiFiberTrajectoryManager.cxx @@ -272,6 +279,7 @@ IdentifiedItem.cxx IdentifiedItemNode.cxx IdentifiedItemVoxel.cxx ImageDepthPositionEnum.cxx +MatrixViewingTypeEnum.cxx Model.cxx ModelChart.cxx ModelSurface.cxx diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx new file mode 100644 index 000000000..eb23fc874 --- /dev/null +++ b/src/Brain/ChartOverlay.cxx @@ -0,0 +1,541 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_OVERLAY_DECLARE__ +#include "ChartOverlay.h" +#undef __CHART_OVERLAY_DECLARE__ + +#include "AnnotationColorBar.h" +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "ChartableLineSeriesBrainordinateInterface.h" +#include "ChartableLineSeriesRowColumnInterface.h" +#include "ChartableMatrixParcelInterface.h" +#include "ChartableMatrixSeriesInterface.h" +#include "EventCaretMappableDataFilesGet.h" +#include "EventManager.h" +#include "PlainTextStringBuilder.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartOverlay + * \brief Overlay for charts. + * \ingroup Brain + */ + +/** + * Constructor. + */ +ChartOverlay::ChartOverlay(const ChartDataTypeEnum::Enum chartDataType) +: CaretObject(), +m_chartDataType(chartDataType) +{ + m_name = "Overlay "; + m_enabled = true; + m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + m_matrixViewingType = MatrixViewingTypeEnum::MATRIX_VIEW_FULL; + + m_colorBar = new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL); + m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); + + m_selectedMapFile = NULL; + m_selectedMapIndex = -1; + m_allMapsSelectedFlag = false; + + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_enabled", &m_enabled); + m_sceneAssistant->add("m_mapYokingGroup", + &m_mapYokingGroup); + m_sceneAssistant->add("m_matrixViewingType", + &m_matrixViewingType); + m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar); + m_sceneAssistant->add("m_allMapsSelectedFlag", &m_allMapsSelectedFlag); + +// EventManager::get()->addEventListener(this, +// EventTypeEnum::EVENT_OVERLAY_VALIDATE); +} + +/** + * Destructor. + */ +ChartOverlay::~ChartOverlay() +{ + delete m_colorBar; + EventManager::get()->removeAllEventsFromListener(this); + delete m_sceneAssistant; +} + + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartOverlay::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + +/** + * Set the number of this overlay. + * + * @param overlayIndex + * Index for this overlay. + */ +void +ChartOverlay::setOverlayNumber(const int32_t overlayIndex) +{ + m_name = "Overlay " + AString::number(overlayIndex + 1); +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartOverlay::toString() const +{ + PlainTextStringBuilder tb; + getDescriptionOfContent(tb); + return tb.getText(); +} + +/** + * Get a text description of the window's content. + * + * @param descriptionOut + * Description of the window's content. + */ +void +ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const +{ + ChartOverlay* me = const_cast(this); + if (me != NULL) { + if (me->isEnabled()) { + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = 0; + me->getSelectionData(mapFile, + mapIndex); + if (mapFile != NULL) { + descriptionOut.addLine("File: "+ + mapFile->getFileNameNoPath()); + if (mapFile->hasMapAttributes()) { + if ((mapIndex >= 0) + && (mapIndex < mapFile->getNumberOfMaps())) { + descriptionOut.addLine("Map Index: " + + AString::number(mapIndex + 1)); + descriptionOut.addLine("Map Name: " + + mapFile->getMapName(mapIndex)); + } + } + } + } + } +} + +/** + * @return Enabled status for this surface overlay. + */ +bool +ChartOverlay::isEnabled() const +{ + return m_enabled; +} + +/** + * Set the enabled status for this surface overlay. + * @param enabled + * New status. + */ +void +ChartOverlay::setEnabled(const bool enabled) +{ + m_enabled = enabled; +} + +/** + * Copy the data from the given overlay to this overlay. + * @param overlay + * Overlay from which data is transferred. + */ +void +ChartOverlay::copyData(const ChartOverlay* overlay) +{ + CaretAssert(overlay); + + /* + * These members are not copied since they + * identify the overlay: + * name + * overlayIndex + * + */ + m_enabled = overlay->m_enabled; + + m_mapYokingGroup = overlay->m_mapYokingGroup; + m_matrixViewingType = overlay->m_matrixViewingType; + + *m_colorBar = *overlay->m_colorBar; + + m_selectedMapFile = overlay->m_selectedMapFile; + m_selectedMapIndex = overlay->m_selectedMapIndex; +} + +/** + * Swap the data from the given overlay to this overlay. + * @param overlay + * Overlay from which data is transferred. + */ +void +ChartOverlay::swapData(ChartOverlay* overlay) +{ + ChartOverlay* swapOverlay = new ChartOverlay(m_chartDataType); + + swapOverlay->copyData(overlay); + + overlay->copyData(this); + copyData(swapOverlay); + + delete swapOverlay; +} + +/** + * @return Selected map yoking group. + */ +MapYokingGroupEnum::Enum +ChartOverlay::getMapYokingGroup() const +{ + return m_mapYokingGroup; +} + +/** + * Set the map yoking group. + * + * @param mapYokingGroup + * New value for map yoking group. + */ +void +ChartOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) +{ + m_mapYokingGroup = mapYokingGroup; +} + +/** + * @return The color bar displayed in graphics window. + */ +AnnotationColorBar* +ChartOverlay::getColorBar() +{ + return m_colorBar; +} + +/** + * @return The color bar displayed in graphics window (const method). + */ +const AnnotationColorBar* +ChartOverlay::getColorBar() const +{ + return m_colorBar; +} + +/** + * @return The matrix viewing type. + */ +MatrixViewingTypeEnum::Enum +ChartOverlay::getMatrixViewingType() const +{ + return m_matrixViewingType; +} + +/** + * Set the matrix viewing type. + * + * @param matrixViewingType + * new value. + */ +void +ChartOverlay::setMatrixViewingType(const MatrixViewingTypeEnum::Enum matrixViewingType) +{ + m_matrixViewingType = matrixViewingType; +} + +/** + * Return the selection information. This method is typically + * called to update the user-interface. + * + * @param selectedMapFileOut + * The selected map file. May be NULL. + * @param selectedMapIndexOut + * Index of selected map in the selected file. + */ +void +ChartOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut) +{ + std::vector mapFiles; + + getSelectionData(mapFiles, + selectedMapFileOut, + selectedMapIndexOut); +} + +/** + * Return the selection information. This method is typically + * called to update the user-interface. + * + * @param mapFilesOut + * Contains all map files that can be selected. + * @param selectedMapFileOut + * The selected map file. May be NULL. + * @param selectedMapUniqueIDOut + * UniqueID of selected map. + * @param selectedMapIndexOut + * Index of selected map in the selected file. + */ +void +ChartOverlay::getSelectionData(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut) +{ + mapFilesOut.clear(); + selectedMapFileOut = NULL; + selectedMapIndexOut = -1; + + /** + * Get the data files. + */ + std::vector allDataFiles; + EventCaretMappableDataFilesGet eventGetMapDataFiles; + EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); + eventGetMapDataFiles.getAllFiles(allDataFiles); + + /* + * Use only those data files that meet criteria. + */ + for (std::vector::iterator iter = allDataFiles.begin(); + iter != allDataFiles.end(); + iter++) { + CaretMappableDataFile* mapFile = *iter; + bool useIt = false; + + ChartableLineSeriesInterface* lineChartFile = dynamic_cast(mapFile); + ChartableMatrixSeriesInterface* matrixChartFile = dynamic_cast(mapFile); + if (m_overlayIndex > 0) { + if ((lineChartFile != NULL) + || (matrixChartFile != NULL)) { + useIt = true; + } + } + else { + if ((lineChartFile != NULL) + || (matrixChartFile != NULL)) { + useIt = true; + } + } + + if (useIt) { + mapFilesOut.push_back(mapFile); + } + } + + /* + * Does selected data file still no longer exist? + */ + if (std::find(mapFilesOut.begin(), + mapFilesOut.end(), + m_selectedMapFile) == mapFilesOut.end()) { + /* + * Invalidate seleted file and disable yoking since + * the selected file will change. + */ + m_selectedMapFile = NULL; + m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + } + + /* + * If selected data file is valid, see if selected + * map is still valid. If not, use first map. + */ + if (m_selectedMapFile != NULL) { + if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { + m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; + } + if (m_selectedMapIndex < 0) { + m_selectedMapIndex = 0; + } + } + else { + /* + * Use first map in first file that has one or more maps. + */ + if (m_selectedMapFile == NULL) { + if (mapFilesOut.empty() == false) { + for (std::vector::iterator iter = mapFilesOut.begin(); + iter != mapFilesOut.end(); + iter++) { + CaretMappableDataFile* mapTypeFile = *iter; + if (mapTypeFile->getNumberOfMaps() > 0) { + m_selectedMapFile = mapTypeFile; + m_selectedMapIndex = 0; + } + } + } + } + } + + selectedMapFileOut = m_selectedMapFile; + if (selectedMapFileOut != NULL) { + // /* + // * Update for overlay yoking + // */ + // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); + // if ((yokeMapIndex >= 0) + // && (yokeMapIndex < selectedMapFileOut->getNumberOfMaps())) { + // m_selectedMapIndex = yokeMapIndex; + // } + // else if (yokeMapIndex >= selectedMapFileOut->getNumberOfMaps()) { + // m_selectedMapIndex = selectedMapFileOut->getNumberOfMaps() - 1; + // } + // } + // + selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); + } +} + +/** + * Set the selected map file and map. + * @param selectedMapFile + * File that is selected. + * @param selectedMapName + * Map name that is selected. + */ +void +ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, + const int32_t selectedMapIndex) +{ + m_selectedMapFile = selectedMapFile; + m_selectedMapIndex = selectedMapIndex; + + if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + if (m_selectedMapFile == NULL) { + m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + } + // if (selectedMapFile != NULL) { + // MapYokingGroupEnum::setSelectedMapIndex(m_mapYokingGroup, + // selectedMapIndex); + // } + // else { + // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + // } + } +} + +/** + * @return All maps selected. + */ +bool +ChartOverlay::isAllMapsSelected() const +{ + return m_allMapsSelectedFlag; +} + +/** + * Set all maps selected. + * + * @param status + * New status. + */ +void +ChartOverlay::setAllMapsSelected(const bool status) +{ + m_allMapsSelectedFlag = status; +} + + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartOverlay::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartOverlay", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h new file mode 100644 index 000000000..a3476f65f --- /dev/null +++ b/src/Brain/ChartOverlay.h @@ -0,0 +1,152 @@ +#ifndef __CHART_OVERLAY_H__ +#define __CHART_OVERLAY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +#include "ChartDataTypeEnum.h" +#include "EventListenerInterface.h" +#include "MapYokingGroupEnum.h" +#include "MatrixViewingTypeEnum.h" +#include "SceneableInterface.h" + + +namespace caret { + class AnnotationColorBar; + class CaretMappableDataFile; + class PlainTextStringBuilder; + class SceneClassAssistant; + + class ChartOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { + + public: + ChartOverlay(const ChartDataTypeEnum::Enum chartDataType); + + virtual ~ChartOverlay(); + + AString getName() const; + + void setOverlayNumber(const int32_t overlayIndex); + + virtual AString toString() const; + + virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; + + bool isEnabled() const; + + void setEnabled(const bool enabled); + + void copyData(const ChartOverlay* overlay); + + void swapData(ChartOverlay* overlay); + + MapYokingGroupEnum::Enum getMapYokingGroup() const; + + void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); + + AnnotationColorBar* getColorBar(); + + const AnnotationColorBar* getColorBar() const; + + MatrixViewingTypeEnum::Enum getMatrixViewingType() const; + + void setMatrixViewingType(const MatrixViewingTypeEnum::Enum matrixViewingType); + + void getSelectionData(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut); + + void getSelectionData(CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut); + + void setSelectionData(CaretMappableDataFile* selectedMapFile, + const int32_t selectedMapIndex); + + bool isAllMapsSelected() const; + + void setAllMapsSelected(const bool status); + + virtual void receiveEvent(Event* event); + + // ADD_NEW_METHODS_HERE + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + ChartOverlay(const ChartOverlay&); + + ChartOverlay& operator=(const ChartOverlay&); + + SceneClassAssistant* m_sceneAssistant; + + const ChartDataTypeEnum::Enum m_chartDataType; + + /** Name of overlay (DO NOT COPY)*/ + AString m_name; + + /** Index of this overlay (DO NOT COPY)*/ + int32_t m_overlayIndex; + + /** enabled status */ + mutable bool m_enabled; + + /** map yoking group */ + MapYokingGroupEnum::Enum m_mapYokingGroup; + + MatrixViewingTypeEnum::Enum m_matrixViewingType; + + /** The color bar displayed in the graphics window */ + AnnotationColorBar* m_colorBar; + + /** selected mappable file */ + CaretMappableDataFile* m_selectedMapFile; + + /** selected map index */ + int32_t m_selectedMapIndex; + + bool m_allMapsSelectedFlag; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_OVERLAY_DECLARE__ + // +#endif // __CHART_OVERLAY_DECLARE__ + +} // namespace +#endif //__CHART_OVERLAY_H__ diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx new file mode 100644 index 000000000..53078a3e1 --- /dev/null +++ b/src/Brain/ChartOverlaySet.cxx @@ -0,0 +1,574 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_OVERLAY_SET_DECLARE__ +#include "ChartOverlaySet.h" +#undef __CHART_OVERLAY_SET_DECLARE__ + +#include "CaretAssert.h" +#include "ChartOverlay.h" +#include "EventManager.h" +#include "PlainTextStringBuilder.h" +#include "SceneClass.h" +#include "SceneClassArray.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartOverlaySet + * \brief A set of chart overlays. + * \ingroup Brain + */ + +/** + * Constructor. + */ +ChartOverlaySet::ChartOverlaySet(const ChartDataTypeEnum::Enum chartDataType, + const AString& name, + const int32_t tabIndex) +: CaretObject(), +m_chartDataType(chartDataType), +m_name(name), +m_tabIndex(tabIndex) +{ + m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; + + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_numberOfDisplayedOverlays", + &m_numberOfDisplayedOverlays); + + for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + m_overlays[i] = new ChartOverlay(m_chartDataType); + } +// EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); +// EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); +} + +/** + * Destructor. + */ +ChartOverlaySet::~ChartOverlaySet() +{ + EventManager::get()->removeAllEventsFromListener(this); + for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + delete m_overlays[i]; + } + delete m_sceneAssistant; +} + +/** + * Copy the given overlay set to this overlay set. + * @param overlaySet + * Overlay set that is copied. + */ +void +ChartOverlaySet::copyOverlaySet(const ChartOverlaySet* overlaySet) +{ + for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + m_overlays[i]->copyData(overlaySet->getOverlay(i)); + } + m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; +} + +/** + * @return Returns the top-most overlay regardless of its enabled status. + */ +ChartOverlay* +ChartOverlaySet::getPrimaryOverlay() +{ + return m_overlays[0]; +} + +/** + * @return Returns the underlay which is the lowest + * displayed overlay. + */ +ChartOverlay* +ChartOverlaySet::getUnderlay() +{ + return m_overlays[getNumberOfDisplayedOverlays() - 1]; +} + +/** + * Get the overlay at the specified index. + * @param overlayNumber + * Index of the overlay. + * @return Overlay at the given index. + */ +const ChartOverlay* +ChartOverlaySet::getOverlay(const int32_t overlayNumber) const +{ + CaretAssertArrayIndex(m_overlays, + BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, + overlayNumber); + return m_overlays[overlayNumber]; +} + +/** + * Get the overlay at the specified index. + * @param overlayNumber + * Index of the overlay. + * @return Overlay at the given index. + */ +ChartOverlay* +ChartOverlaySet::getOverlay(const int32_t overlayNumber) +{ + CaretAssertArrayIndex(m_overlays, + BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, + overlayNumber); + return m_overlays[overlayNumber]; +} + +/** + * Get a text description of the window's content. + * + * @param descriptionOut + * Description of the window's content. + */ +void +ChartOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const +{ + descriptionOut.addLine("Overlay Set"); + + const int numOverlays = getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + if (getOverlay(i)->isEnabled()) { + descriptionOut.pushIndentation(); + + descriptionOut.addLine("Overlay " + + AString::number(i + 1) + + ": "); + + descriptionOut.pushIndentation(); + getOverlay(i)->getDescriptionOfContent(descriptionOut); + descriptionOut.popIndentation(); + + descriptionOut.popIndentation(); + } + } +} + + +/** + * Add a displayed overlay. If the maximum + * number of surface overlays is reached, + * this method has no effect. + */ +void +ChartOverlaySet::addDisplayedOverlay() +{ + m_numberOfDisplayedOverlays++; + if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; + } +} + +/** + * @return Returns the number of displayed overlays. + */ +int32_t +ChartOverlaySet::getNumberOfDisplayedOverlays() const +{ + return m_numberOfDisplayedOverlays; +} + +/** + * Sets the number of displayed overlays. + * @param numberOfDisplayedOverlays + * Number of overlays for display. + */ +void +ChartOverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays) +{ + const int32_t oldNumberOfDisplayedOverlays = m_numberOfDisplayedOverlays; + m_numberOfDisplayedOverlays = numberOfDisplayedOverlays; + if (m_numberOfDisplayedOverlays < BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; + } + if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; + } + + /* + * If one overlay added (probably through GUI), + * shift all overlays down one position so that + * new overlay appears at the top + */ + const int32_t numberOfOverlaysAdded = m_numberOfDisplayedOverlays - oldNumberOfDisplayedOverlays; + if (numberOfOverlaysAdded == 1) { + for (int32_t i = (m_numberOfDisplayedOverlays - 1); i >= 0; i--) { + moveDisplayedOverlayDown(i); + } + } +} + +/** + * Insert an overlay below this overlay + * @param overlayIndex + * Index of overlay for which an overlay is added below + */ +void +ChartOverlaySet::insertOverlayAbove(const int32_t overlayIndex) +{ + if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays++; + + for (int32_t i = (m_numberOfDisplayedOverlays - 2); i >= overlayIndex; i--) { + moveDisplayedOverlayDown(i); + } + } +} + +/** + * Insert an overlay above this overlay + * @param overlayIndex + * Index of overlay for which an overlay is added above + */ +void +ChartOverlaySet::insertOverlayBelow(const int32_t overlayIndex) +{ + if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays++; + + for (int32_t i = (m_numberOfDisplayedOverlays - 2); i > overlayIndex; i--) { + moveDisplayedOverlayDown(i); + } + } +} + + +/** + * Remove a displayed overlay. This method will have + * no effect if the minimum number of overlays are + * displayed + * + * @param overlayIndex + * Index of overlay for removal from display. + */ +void +ChartOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) +{ + CaretAssertArrayIndex(m_overlays, + BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, + overlayIndex); + m_overlays[overlayIndex]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); + + if (m_numberOfDisplayedOverlays > BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { + m_numberOfDisplayedOverlays--; + for (int32_t i = overlayIndex; i < m_numberOfDisplayedOverlays; i++) { + m_overlays[i]->copyData(m_overlays[i+1]); + } + } +} + +/** + * Move the overlay at the given index up one level + * (swap it with overlayIndex - 1). This method will + * have no effect if the overlay is the top-most overlay. + * + * @param overlayIndex + * Index of overlay that is to be moved up. + */ +void +ChartOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) +{ + if (overlayIndex > 0) { + m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1]); + } +} + +/** + * Move the overlay at the given index down one level + * (swap it with overlayIndex + 1). This method will + * have no effect if the overlay is the bottom-most overlay. + * + * @param overlayIndex + * Index of overlay that is to be moved down. + */ +void +ChartOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) +{ + const int32_t nextOverlayIndex = overlayIndex + 1; + if (nextOverlayIndex < m_numberOfDisplayedOverlays) { + m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex]); + } +} + +/** + * Initialize the overlays. + */ +void +ChartOverlaySet::initializeOverlays() +{ +// bool isMatchToVolumeUnderlay = false; +// bool isMatchToVolumeOverlays = false; +// +// switch (m_includeVolumeFiles) { +// case Overlay::INCLUDE_VOLUME_FILES_NO: +// break; +// case Overlay::INCLUDE_VOLUME_FILES_YES: +// /* +// * If no surface structures, then it must be volume slice view +// * so allow volumes to be in the overlays. +// */ +// if (m_includeSurfaceStructures.empty()) { +// isMatchToVolumeOverlays = true; +// } +// isMatchToVolumeUnderlay = true; +// break; +// } +// +// /* +// * Underlays consist of anatomical type data +// */ +// std::vector underlayMapFiles; +// std::vector underlayMapIndices; +// findUnderlayFiles(m_includeSurfaceStructures, +// isMatchToVolumeUnderlay, +// underlayMapFiles, +// underlayMapIndices); +// +// /* +// * Middle layers are Cifti labels or Gifti Labels +// * that do not contain shape data +// */ +// std::vector middleLayerMapFiles; +// std::vector middleLayerMapIndices; +// findMiddleLayerFiles(m_includeSurfaceStructures, +// isMatchToVolumeOverlays, +// middleLayerMapFiles, +// middleLayerMapIndices); +// +// /* +// * Overlays consist of Cifti scalars or Gifti Metric +// */ +// std::vector overlayMapFiles; +// std::vector overlayMapIndices; +// findOverlayFiles(m_includeSurfaceStructures, +// isMatchToVolumeOverlays, +// overlayMapFiles, +// overlayMapIndices); +// +// const int32_t numberOfUnderlayFiles = static_cast(underlayMapFiles.size()); +// +// /* +// * Number of overlay that are displayed. +// */ +// const int32_t numberOfDisplayedOverlays = getNumberOfDisplayedOverlays(); +// +// +// /* +// * Track overlay that were initialized +// */ +// std::vector overlayInitializedFlag(numberOfDisplayedOverlays, +// false); +// +// /* +// * Put in the shape files at the bottom +// * Note that highest overlay index is bottom +// */ +// int32_t overlayIndexForUnderlay = (numberOfDisplayedOverlays - 1); +// for (int32_t underlayFileIndex = 0; underlayFileIndex < numberOfUnderlayFiles; underlayFileIndex++) { +// if (overlayIndexForUnderlay >= 0) { +// Overlay* overlay = getOverlay(overlayIndexForUnderlay); +// overlay->setSelectionData(underlayMapFiles[underlayFileIndex], +// underlayMapIndices[underlayFileIndex]); +// overlayInitializedFlag[overlayIndexForUnderlay] = true; +// overlayIndexForUnderlay--; +// } +// else { +// break; +// } +// } +// +// /* +// * Combine overlay and middle layer files +// */ +// std::vector upperLayerFiles; +// std::vector upperLayerIndices; +// upperLayerFiles.insert(upperLayerFiles.end(), +// overlayMapFiles.begin(), +// overlayMapFiles.end()); +// upperLayerIndices.insert(upperLayerIndices.end(), +// overlayMapIndices.begin(), +// overlayMapIndices.end()); +// upperLayerFiles.insert(upperLayerFiles.end(), +// middleLayerMapFiles.begin(), +// middleLayerMapFiles.end()); +// upperLayerIndices.insert(upperLayerIndices.end(), +// middleLayerMapIndices.begin(), +// middleLayerMapIndices.end()); +// CaretAssert(upperLayerFiles.size() == upperLayerIndices.size()); +// +// const int32_t numberOfUpperFiles = static_cast(upperLayerFiles.size()); +// +// /* +// * Put in overlay and middle layer files +// */ +// for (int32_t upperFileIndex = 0; upperFileIndex < numberOfUpperFiles; upperFileIndex++) { +// /* +// * Find available overlay +// */ +// int32_t upperLayerOverlayIndex = -1; +// for (int32_t overlayIndex = 0; overlayIndex < numberOfDisplayedOverlays; overlayIndex++) { +// if (overlayInitializedFlag[overlayIndex] == false) { +// upperLayerOverlayIndex = overlayIndex; +// break; +// } +// } +// +// if (upperLayerOverlayIndex >= 0) { +// Overlay* upperLayerOverlay = getOverlay(upperLayerOverlayIndex); +// upperLayerOverlay->setSelectionData(upperLayerFiles[upperFileIndex], +// upperLayerIndices[upperFileIndex]); +// overlayInitializedFlag[upperLayerOverlayIndex] = true; +// } +// else { +// break; +// } +// } +// +// /* +// * Disable overlays that were not initialized +// */ +// for (int32_t i = 0; i < numberOfDisplayedOverlays; i++) { +// CaretAssertVectorIndex(overlayInitializedFlag, i); +// getOverlay(i)->setEnabled(overlayInitializedFlag[i]); +// } +} + +/** + * Reset the yoking status of all overlays to off. + */ +void +ChartOverlaySet::resetOverlayYokingToOff() +{ + for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + m_overlays[i]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartOverlaySet::toString() const +{ + return "ChartOverlaySet"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartOverlaySet::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartOverlaySet::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartOverlaySet", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + const int32_t numOverlaysToSave = getNumberOfDisplayedOverlays(); + + std::vector overlayClassVector; + for (int i = 0; i < numOverlaysToSave; i++) { + overlayClassVector.push_back(m_overlays[i]->saveToScene(sceneAttributes, "m_overlays")); + } + + SceneClassArray* overlayClassArray = new SceneClassArray("m_overlays", + overlayClassVector); + sceneClass->addChild(overlayClassArray); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + const SceneClassArray* overlayClassArray = sceneClass->getClassArray("m_overlays"); + if (overlayClassArray != NULL) { + const int32_t numOverlays = std::min(overlayClassArray->getNumberOfArrayElements(), + (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); + for (int32_t i = 0; i < numOverlays; i++) { + m_overlays[i]->restoreFromScene(sceneAttributes, + overlayClassArray->getClassAtIndex(i)); + } + } + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartOverlaySet.h new file mode 100644 index 000000000..3b3dcd38c --- /dev/null +++ b/src/Brain/ChartOverlaySet.h @@ -0,0 +1,130 @@ +#ifndef __CHART_OVERLAY_SET_H__ +#define __CHART_OVERLAY_SET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "BrainConstants.h" +#include "CaretObject.h" +#include "ChartDataTypeEnum.h" +#include "EventListenerInterface.h" +#include "SceneableInterface.h" + + +namespace caret { + class ChartOverlay; + class PlainTextStringBuilder; + class SceneClassAssistant; + + class ChartOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { + + public: + ChartOverlaySet(const ChartDataTypeEnum::Enum chartDataType, + const AString& name, + const int32_t tabIndex); + + virtual ~ChartOverlaySet(); + + void copyOverlaySet(const ChartOverlaySet* overlaySet); + + ChartOverlay* getPrimaryOverlay(); + + ChartOverlay* getUnderlay(); + + ChartOverlay* getOverlay(const int32_t overlayNumber); + + const ChartOverlay* getOverlay(const int32_t overlayNumber) const; + + void addDisplayedOverlay(); + + void setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays); + + int32_t getNumberOfDisplayedOverlays() const; + + void insertOverlayAbove(const int32_t overlayIndex); + + void insertOverlayBelow(const int32_t overlayIndex); + + void removeDisplayedOverlay(const int32_t overlayIndex); + + void moveDisplayedOverlayUp(const int32_t overlayIndex); + + void moveDisplayedOverlayDown(const int32_t overlayIndex); + + void initializeOverlays(); + + void resetOverlayYokingToOff(); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; + + virtual void receiveEvent(Event* event); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + ChartOverlaySet(const ChartOverlaySet&); + + ChartOverlaySet& operator=(const ChartOverlaySet&); + + SceneClassAssistant* m_sceneAssistant; + + ChartOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; + + const ChartDataTypeEnum::Enum m_chartDataType; + + const AString m_name; + + const int32_t m_tabIndex; + + int32_t m_numberOfDisplayedOverlays; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_OVERLAY_SET_DECLARE__ + // +#endif // __CHART_OVERLAY_SET_DECLARE__ + +} // namespace +#endif //__CHART_OVERLAY_SET_H__ diff --git a/src/Brain/ChartOverlaySetArray.cxx b/src/Brain/ChartOverlaySetArray.cxx new file mode 100644 index 000000000..cb4486301 --- /dev/null +++ b/src/Brain/ChartOverlaySetArray.cxx @@ -0,0 +1,172 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __OVERLAY_SET_ARRAY_DECLARE__ +#include "ChartOverlaySetArray.h" +#undef __OVERLAY_SET_ARRAY_DECLARE__ + +#include "BrainConstants.h" +#include "CaretAssert.h" +#include "EventBrowserTabDelete.h" +#include "EventManager.h" +#include "ChartOverlaySet.h" + +using namespace caret; + + + +/** + * \class caret::ChartOverlaySetArray + * \brief Maintains an array of chart overlay sets for use with a model + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param name + * Name of model using this chart overlay set. This name is displayed + * if there is an attempt to yoke models with incompatible chart overlays. + */ +ChartOverlaySetArray::ChartOverlaySetArray(const AString& name) +: CaretObject(), +m_name(name) +{ + m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartOverlaySets[i] = new ChartOverlaySet(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, + name, + i); + } + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); +} + +/** + * Destructor. + */ +ChartOverlaySetArray::~ChartOverlaySetArray() +{ + EventManager::get()->removeAllEventsFromListener(this); + + for (std::vector::iterator iter =m_chartOverlaySets.begin(); + iter !=m_chartOverlaySets.end(); + iter++) { + delete *iter; + } + m_chartOverlaySets.clear(); +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartOverlaySetArray::toString() const +{ + return "ChartOverlaySetArray"; +} + +/** + * @return The number of chart overlay sets. + */ +int32_t +ChartOverlaySetArray::getNumberOfChartOverlaySets() +{ + return m_chartOverlaySets.size(); +} + +/** + * Get the chart overlay set at the given index. + * + * @param indx + * Index of chart overlay set. + * @return + * Overlay set at given index. + */ +ChartOverlaySet* +ChartOverlaySetArray::getChartOverlaySet(const int32_t indx) +{ + CaretAssertVectorIndex(m_chartOverlaySets, indx); + + return m_chartOverlaySets[indx]; +} + +/** + * Initialize the chart overlay selections. + */ +void +ChartOverlaySetArray::initializeOverlaySelections() +{ + for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { + CaretAssertVectorIndex(m_chartOverlaySets, iTab); + m_chartOverlaySets[iTab]->initializeOverlays(); + } +} + + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartOverlaySetArray::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { + EventBrowserTabDelete* deleteTabEvent = dynamic_cast(event); + CaretAssert(deleteTabEvent); + + /* + * Since tab is being deleted, reset any chart overlay yoking for the tab. + */ + const int32_t tabIndex = deleteTabEvent->getBrowserTabIndex(); + if ((tabIndex > 0) + && (tabIndex < getNumberOfChartOverlaySets())) { + m_chartOverlaySets[tabIndex]->resetOverlayYokingToOff(); + } + + deleteTabEvent->setEventProcessed(); + } +} + +/** + * Copy the chart overlay set from the source tab index to the + * destination tab index. + * + * @param sourceTabIndex + * Source from which tab content is copied. + * @param destinationTabIndex + * Destination to which tab content is copied. + */ +void +ChartOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, + const int32_t destinationTabIndex) +{ + CaretAssertVectorIndex(m_chartOverlaySets, sourceTabIndex); + CaretAssertVectorIndex(m_chartOverlaySets, destinationTabIndex); + + const ChartOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; + ChartOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; + destinationChartOverlaySet->copyOverlaySet(sourceChartOverlaySet); +} + diff --git a/src/Brain/ChartOverlaySetArray.h b/src/Brain/ChartOverlaySetArray.h new file mode 100644 index 000000000..44bb8f3c0 --- /dev/null +++ b/src/Brain/ChartOverlaySetArray.h @@ -0,0 +1,78 @@ +#ifndef __CHART_OVERLAY_SET_ARRAY_H__ +#define __CHART_OVERLAY_SET_ARRAY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +#include "EventListenerInterface.h" +#include "Overlay.h" + +namespace caret { + class ChartOverlaySet; + + class ChartOverlaySetArray : public CaretObject, public EventListenerInterface { + + public: + ChartOverlaySetArray(const AString& name); + + virtual ~ChartOverlaySetArray(); + + int32_t getNumberOfChartOverlaySets(); + + ChartOverlaySet* getChartOverlaySet(const int32_t indx); + + void initializeOverlaySelections(); + + void copyChartOverlaySet(const int32_t sourceTabIndex, + const int32_t destinationTabIndex); + private: + ChartOverlaySetArray(const ChartOverlaySetArray&); + + ChartOverlaySetArray& operator=(const ChartOverlaySetArray&); + + public: + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + private: + // ADD_NEW_MEMBERS_HERE + + void initialize(); + + /** Name for this chart overlay set array */ + AString m_name; + + /** The chart overlay sets */ + std::vectorm_chartOverlaySets; + }; + +#ifdef __OVERLAY_SET_ARRAY_DECLARE__ + // +#endif // __OVERLAY_SET_ARRAY_DECLARE__ + +} // namespace +#endif //__CHART_OVERLAY_SET_ARRAY_H__ diff --git a/src/Brain/MatrixViewingTypeEnum.cxx b/src/Brain/MatrixViewingTypeEnum.cxx new file mode 100644 index 000000000..ef03cf01f --- /dev/null +++ b/src/Brain/MatrixViewingTypeEnum.cxx @@ -0,0 +1,382 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +#include "MatrixViewingTypeEnum.h" +#undef __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::MatrixViewingTypeEnum + * \brief + * + * + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_matrixViewingTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void matrixViewingTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "MatrixViewingTypeEnum.h" + * + * Instatiate: + * m_matrixViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_matrixViewingTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_matrixViewingTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(matrixViewingTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const MatrixViewingTypeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +MatrixViewingTypeEnum::MatrixViewingTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +MatrixViewingTypeEnum::~MatrixViewingTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +MatrixViewingTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_FULL, + "MATRIX_VIEW_FULL", + "Matrix View Full")); + + enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, + "MATRIX_VIEW_FULL_NO_DIAGONAL", + "Matrix View Full No Diagonal")); + + enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, + "MATRIX_VIEW_LOWER_NO_DIAGONAL", + "Matrix View Lower No Diagonal")); + + enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, + "MATRIX_VIEW_UPPER_NO_DIAGONAL", + "Matrix View Upper No Diagonal")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const MatrixViewingTypeEnum* +MatrixViewingTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const MatrixViewingTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MatrixViewingTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MatrixViewingTypeEnum::Enum +MatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MatrixViewingTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MatrixViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +MatrixViewingTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +MatrixViewingTypeEnum::Enum +MatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MatrixViewingTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MatrixViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +MatrixViewingTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +MatrixViewingTypeEnum::Enum +MatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const MatrixViewingTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MatrixViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +MatrixViewingTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MatrixViewingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(MatrixViewingTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +MatrixViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(MatrixViewingTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/MatrixViewingTypeEnum.h b/src/Brain/MatrixViewingTypeEnum.h new file mode 100644 index 000000000..df54d4c7c --- /dev/null +++ b/src/Brain/MatrixViewingTypeEnum.h @@ -0,0 +1,107 @@ +#ifndef __MATRIX_VIEWING_TYPE_ENUM_H__ +#define __MATRIX_VIEWING_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class MatrixViewingTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** View the full matrix */ + MATRIX_VIEW_FULL, + /** View the full matrix but hide the diagonal */ + MATRIX_VIEW_FULL_NO_DIAGONAL, + /** View the lower half of the matrix but hide the diagonal */ + MATRIX_VIEW_LOWER_NO_DIAGONAL, + /** View the upper half of the matrix but hide the diagonal */ + MATRIX_VIEW_UPPER_NO_DIAGONAL + }; + + ~MatrixViewingTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + MatrixViewingTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const MatrixViewingTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +std::vector MatrixViewingTypeEnum::enumData; +bool MatrixViewingTypeEnum::initializedFlag = false; +int32_t MatrixViewingTypeEnum::integerCodeCounter = 0; +#endif // __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__MATRIX_VIEWING_TYPE_ENUM_H__ diff --git a/src/Brain/Model.cxx b/src/Brain/Model.cxx index edcfc1acd..bc5c53562 100644 --- a/src/Brain/Model.cxx +++ b/src/Brain/Model.cxx @@ -116,6 +116,34 @@ Model::initializeSelectedSurfaces() /* nothing */ } +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +ChartOverlaySet* +Model::getChartOverlaySet(const int /*tabIndex*/) +{ + return NULL; +} + +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +const ChartOverlaySet* +Model::getChartOverlaySet(const int /*tabIndex*/) const +{ + return NULL; +} + /** * Create a scene for an instance of a class. * diff --git a/src/Brain/Model.h b/src/Brain/Model.h index 95286f434..872296a07 100644 --- a/src/Brain/Model.h +++ b/src/Brain/Model.h @@ -28,6 +28,7 @@ namespace caret { class Brain; + class ChartOverlaySet; class OverlaySet; class PlainTextStringBuilder; @@ -66,6 +67,10 @@ namespace caret { virtual const OverlaySet* getOverlaySet(const int tabIndex) const = 0; + virtual ChartOverlaySet* getChartOverlaySet(const int tabIndex); + + virtual const ChartOverlaySet* getChartOverlaySet(const int tabIndex) const; + virtual void initializeSelectedSurfaces(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index e155a5867..97436dac0 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -40,6 +40,7 @@ #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "CiftiMappableDataFile.h" +#include "ChartOverlaySetArray.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" @@ -68,6 +69,8 @@ ModelChart::ModelChart(Brain* brain) m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); + + m_chartOverlaySetArray = new ChartOverlaySetArray("Chart View"); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); @@ -86,6 +89,7 @@ ModelChart::ModelChart(Brain* brain) */ ModelChart::~ModelChart() { + delete m_chartOverlaySetArray; delete m_overlaySetArray; EventManager::get()->removeAllEventsFromListener(this); @@ -1873,3 +1877,56 @@ ModelChart::getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex) return m_chartableMatrixSeriesFileSelectionModel[tabIndex]; } + +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +ChartOverlaySet* +ModelChart::getChartOverlaySet(const int tabIndex) +{ + ChartOverlaySet* chartOverlaySet = NULL; + + switch (getSelectedChartDataType(tabIndex)) { + case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + break; + } + + chartOverlaySet = m_chartOverlaySetArray->getChartOverlaySet(tabIndex); + + return chartOverlaySet; +} + +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +const ChartOverlaySet* +ModelChart::getChartOverlaySet(const int tabIndex) const +{ + ModelChart* nonConstModelChart = const_cast(this); + CaretAssert(nonConstModelChart); + const ChartOverlaySet* chartOverlaySet = nonConstModelChart->getChartOverlaySet(tabIndex); + + return chartOverlaySet; +} + + diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index a3d9077f7..1d66bf4ef 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -48,6 +48,7 @@ namespace caret { class ChartModelDataSeries; class ChartModelFrequencySeries; class ChartModelTimeSeries; + class ChartOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; class OverlaySetArray; @@ -87,6 +88,10 @@ namespace caret { const OverlaySet* getOverlaySet(const int tabIndex) const; + virtual ChartOverlaySet* getChartOverlaySet(const int tabIndex); + + virtual const ChartOverlaySet* getChartOverlaySet(const int tabIndex) const; + virtual void receiveEvent(Event* event); void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; @@ -164,6 +169,8 @@ namespace caret { /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; + ChartOverlaySetArray* m_chartOverlaySetArray; + mutable ChartDataTypeEnum::Enum m_selectedChartDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index adc97d60d..0a8d3414b 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -454,7 +454,7 @@ AnnotationCoordinateWidget::valueChanged() if (updateUserInterfaceFlag) { EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, m_browserWindowIndex, - NULL, + (ChartOverlay*)NULL, NULL, -1).getPointer()); } diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 639812d08..44b061b68 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -38,6 +38,7 @@ #include "CaretDataFile.h" #include "CaretPreferences.h" #include "ChartableLineSeriesBrainordinateInterface.h" +#include "ChartOverlaySetViewController.h" #include "ChartableMatrixInterface.h" #include "ChartToolBoxViewController.h" #include "CiftiConnectivityMatrixViewController.h" @@ -116,6 +117,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 m_annotationViewController = NULL; m_borderSelectionViewController = NULL; + m_chartOverlaySetViewController = NULL; m_chartToolBoxViewController = NULL; m_connectivityMatrixViewController = NULL; m_fiberOrientationViewController = NULL; @@ -129,6 +131,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 m_annotationTabIndex = -1; m_borderTabIndex = -1; + m_chartOverlayTabIndex = -1; m_chartTabIndex = -1; m_connectivityTabIndex = -1; m_fiberOrientationTabIndex = -1; @@ -145,6 +148,13 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 m_overlayTabIndex = addToTabWidget(m_overlaySetViewController, "Layers"); } + if (isOverlayToolBox) { + m_chartOverlaySetViewController = new ChartOverlaySetViewController(orientation, + browserWindowIndex, + this); + m_chartOverlayTabIndex = addToTabWidget(m_chartOverlaySetViewController, + "Chart Layers"); + } if (isOverlayToolBox) { m_chartToolBoxViewController = new ChartToolBoxViewController(orientation, browserWindowIndex, diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h index fc443448d..8df423c23 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h @@ -33,6 +33,7 @@ class QTabWidget; namespace caret { class AnnotationSelectionViewController; class BorderSelectionViewController; + class ChartOverlaySetViewController; class ChartToolBoxViewController; class CiftiConnectivityMatrixViewController; class FiberOrientationSelectionViewController; @@ -85,6 +86,8 @@ namespace caret { BorderSelectionViewController* m_borderSelectionViewController; + ChartOverlaySetViewController* m_chartOverlaySetViewController; + CiftiConnectivityMatrixViewController* m_connectivityMatrixViewController; ChartToolBoxViewController* m_chartToolBoxViewController; @@ -104,7 +107,9 @@ namespace caret { QString m_toolBoxTitle; int32_t m_browserWindowIndex; - + + int32_t m_chartOverlayTabIndex; + int32_t m_overlayTabIndex; int32_t m_annotationTabIndex; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 5cd3d612b..38ec68383 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -95,6 +95,8 @@ ELSE() ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h + ChartOverlaySetViewController.h + ChartOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h @@ -276,6 +278,8 @@ ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h +ChartOverlaySetViewController.h +ChartOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h @@ -481,6 +485,8 @@ ChartHistoryViewController.cxx ChartLinesSelectionViewController.cxx ChartMatrixParcelSelectionViewController.cxx ChartMatrixSeriesSelectionViewController.cxx +ChartOverlaySetViewController.cxx +ChartOverlayViewController.cxx ChartSelectionViewController.cxx ChartToolBoxViewController.cxx CiftiConnectivityMatrixViewController.cxx diff --git a/src/GuiQt/ChartOverlaySetViewController.cxx b/src/GuiQt/ChartOverlaySetViewController.cxx new file mode 100644 index 000000000..72ebe5ffe --- /dev/null +++ b/src/GuiQt/ChartOverlaySetViewController.cxx @@ -0,0 +1,396 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ +#include "ChartOverlaySetViewController.h" +#undef __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BrainConstants.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "ChartOverlaySet.h" +#include "ChartOverlayViewController.h" +#include "EventGraphicsUpdateOneWindow.h" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" +#include "GuiManager.h" +#include "MapYokingGroupComboBox.h" +#include "WuQGridLayoutGroup.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::ChartOverlaySetViewController + * \brief View controller for a chart overlay set + * \ingroup GuiQt + */ + +/** + * Constructor. + * @param orientation + * Orientation for layout + * @param browserWindowIndex + * Index of browser window that contains this view controller. + * @param parent + * Parent widget. + */ +ChartOverlaySetViewController::ChartOverlaySetViewController(const Qt::Orientation orientation, + const int32_t browserWindowIndex, + QWidget* parent) +: QWidget(parent), +m_browserWindowIndex(browserWindowIndex) +{ + QWidget* gridWidget = new QWidget(); + QGridLayout* gridLayout = new QGridLayout(gridWidget); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + ChartOverlayViewController* ovc = new ChartOverlayViewController(orientation, + m_browserWindowIndex, + i, + this); + m_chartOverlayViewControllers.push_back(ovc); + m_chartOverlayGridLayoutGroups.push_back(new WuQGridLayoutGroup(gridLayout, + this)); + + QObject::connect(ovc, SIGNAL(requestAddOverlayAbove(const int32_t)), + this, SLOT(processAddOverlayAbove(const int32_t))); + QObject::connect(ovc, SIGNAL(requestAddOverlayBelow(const int32_t)), + this, SLOT(processAddOverlayBelow(const int32_t))); + QObject::connect(ovc, SIGNAL(requestRemoveOverlay(const int32_t)), + this, SLOT(processRemoveOverlay(const int32_t))); + QObject::connect(ovc, SIGNAL(requestMoveOverlayUp(const int32_t)), + this, SLOT(processMoveOverlayUp(const int32_t))); + QObject::connect(ovc, SIGNAL(requestMoveOverlayDown(const int32_t)), + this, SLOT(processMoveOverlayDown(const int32_t))); + } + + + if (orientation == Qt::Horizontal) { + static const int COLUMN_ON = 0; + static const int COLUMN_SETTINGS_EDIT = 1; + static const int COLUMN_SETTINGS_COLOR_BAR = 2; + static const int COLUMN_SETTINGS_CONSTRUCTION = 3; + static const int COLUMN_HISTORY = 4; + static const int COLUMN_FILE = 5; + static const int COLUMN_YOKE = 6; + static const int COLUMN_MAP_INDEX = 7; + static const int COLUMN_ALL_MAPS = 8; + static const int COLUMN_MAP_NAME = 9; + + gridLayout->setColumnStretch(COLUMN_ON, 0); + gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); + gridLayout->setColumnStretch(COLUMN_SETTINGS_COLOR_BAR, 0); + gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); + gridLayout->setColumnStretch(COLUMN_HISTORY, 0); + gridLayout->setColumnStretch(COLUMN_FILE, 100); + gridLayout->setColumnStretch(COLUMN_YOKE, 0); + gridLayout->setColumnStretch(COLUMN_ALL_MAPS, 0); + gridLayout->setColumnStretch(COLUMN_MAP_INDEX, 0); + gridLayout->setColumnStretch(COLUMN_MAP_NAME, 100); + + QLabel* onLabel = new QLabel("On"); + QLabel* settingsLabel = new QLabel("Settings"); + //QLabel* historyLabel = new QLabel("History"); + QLabel* fileLabel = new QLabel("File"); + QLabel* yokeLabel = new QLabel("Yoke"); + QLabel* allMapsLabel = new QLabel("All"); + QLabel* mapIndexLabel = new QLabel("Map Index"); + QLabel* mapNameLabel = new QLabel("Map Name"); + + int row = gridLayout->rowCount(); + gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); + gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 4, Qt::AlignHCenter); + //gridLayout->addWidget(historyLabel, row, COLUMN_HISTORY, Qt::AlignHCenter); + gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); + gridLayout->addWidget(yokeLabel, row, COLUMN_YOKE, Qt::AlignHCenter); + gridLayout->addWidget(allMapsLabel, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); + gridLayout->addWidget(mapIndexLabel, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); + gridLayout->addWidget(mapNameLabel, row, COLUMN_MAP_NAME, Qt::AlignHCenter); + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + row = gridLayout->rowCount(); + ChartOverlayViewController* covc = m_chartOverlayViewControllers[i]; + WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; + + glg->addWidget(covc->m_enabledCheckBox, row, COLUMN_ON, Qt::AlignHCenter); + glg->addWidget(covc->m_settingsToolButton, row, COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); + glg->addWidget(covc->m_colorBarToolButton, row, COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); + glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); + glg->addWidget(covc->m_historyToolButton, row, COLUMN_HISTORY, Qt::AlignHCenter); + glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); + glg->addWidget(covc->m_mapYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); + glg->addWidget(covc->m_allMapsCheckBox, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); + glg->addWidget(covc->m_mapIndexSpinBox, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); + glg->addWidget(covc->m_mapNameComboBox, row, COLUMN_MAP_NAME); + } + } + else { + static const int ROW_ONE_COLUMN_ON = 0; + static const int ROW_ONE_COLUMN_SETTINGS_EDIT = 1; + static const int ROW_ONE_COLUMN_SETTINGS_COLOR_BAR = 2; + static const int ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION = 3; + static const int ROW_ONE_COLUMN_HISTORY = 4; + static const int ROW_ONE_COLUMN_FILE_LABEL = 5; + static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 6; + + static const int ROW_TWO_COLUMN_YOKE = 0; + static const int ROW_TWO_COLUMN_ALL_MAPS = 3; + static const int ROW_TWO_COLUMN_MAP_INDEX = 6; + static const int ROW_TWO_COLUMN_MAP_NAME = 7; + + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 0); + gridLayout->setColumnStretch(4, 0); + gridLayout->setColumnStretch(5, 0); + gridLayout->setColumnStretch(6, 100); + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; + + int row = gridLayout->rowCount(); + if (i > 0) { + QFrame* bottomHorizontalLineWidget = new QFrame(); + bottomHorizontalLineWidget->setLineWidth(0); + bottomHorizontalLineWidget->setMidLineWidth(1); + bottomHorizontalLineWidget->setFrameStyle(QFrame::HLine | QFrame::Raised); + glg->addWidget(bottomHorizontalLineWidget, + row, 0, 1, -1); + row++; + } + + ChartOverlayViewController* covc = m_chartOverlayViewControllers[i]; + + QLabel* fileLabel = new QLabel("File"); + glg->addWidget(covc->m_enabledCheckBox, row, ROW_ONE_COLUMN_ON, Qt::AlignHCenter); + glg->addWidget(covc->m_settingsToolButton, row, ROW_ONE_COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); + glg->addWidget(covc->m_colorBarToolButton, row, ROW_ONE_COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); + glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); + glg->addWidget(covc->m_historyToolButton, row, ROW_ONE_COLUMN_HISTORY, Qt::AlignHCenter); + glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL); + glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 3); + row++; + + glg->addWidget(covc->m_mapYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); +// glg->addWidget(covc->m_historyToolButton, row, ROW_TWO_COLUMN_HISTORY, 1, 2, Qt::AlignHCenter); + glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 3, Qt::AlignRight); + glg->addWidget(covc->m_mapIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); + glg->addWidget(covc->m_mapNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); + } + } + + if (orientation == Qt::Horizontal) { + QVBoxLayout* verticalLayout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 2, 2); + verticalLayout->addWidget(gridWidget); + verticalLayout->addStretch(); + } + else { + /* + * Resolve WB-649 + */ + QVBoxLayout* verticalLayout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); + verticalLayout->addWidget(gridWidget); + verticalLayout->addStretch(); + } + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); +} + +/** + * Destructor. + */ +ChartOverlaySetViewController::~ChartOverlaySetViewController() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartOverlaySetViewController::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { + EventUserInterfaceUpdate* uiEvent = + dynamic_cast(event); + CaretAssert(uiEvent); + + if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { + if (uiEvent->isToolBoxUpdate()) { + this->updateViewController(); + uiEvent->setEventProcessed(); + } + } + } +} + +/** + * Update this overlay set view controller using the given overlay set. + */ +void +ChartOverlaySetViewController::updateViewController() +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet == NULL) { + return; + } + + const int32_t numberOfOverlays = static_cast(m_chartOverlayViewControllers.size()); + const int32_t numberOfDisplayedOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); + + for (int32_t i = 0; i < numberOfOverlays; i++) { + ChartOverlay* chartOverlay = NULL; + if (chartOverlaySet != NULL) { + chartOverlay = chartOverlaySet->getOverlay(i); + } + m_chartOverlayViewControllers[i]->updateViewController(chartOverlay); + + bool displayOverlay = (chartOverlay != NULL); + if (i >= numberOfDisplayedOverlays) { + displayOverlay = false; + } + CaretAssertVectorIndex(m_chartOverlayGridLayoutGroups, i); + m_chartOverlayGridLayoutGroups[i]->setVisible(displayOverlay); + } +} + +/** + * @return The overlay set in this view controller. + */ +ChartOverlaySet* +ChartOverlaySetViewController::getChartOverlaySet() +{ + ChartOverlaySet* chartOverlaySet = NULL; + BrowserTabContent* browserTabContent = + GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); + if (browserTabContent != NULL) { + chartOverlaySet = browserTabContent->getChartOverlaySet(); + } + + return chartOverlaySet; +} + +/** + * Add an overlay above the overlay with the given index. + * @param overlayIndex + * Index of overlay that will have an overlay added above it. + */ +void +ChartOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet != NULL) { + chartOverlaySet->insertOverlayAbove(overlayIndex); + this->updateColoringAndGraphics(); + } +} + +/** + * Add an overlay below the overlay with the given index. + * @param overlayIndex + * Index of overlay that will have an overlay added below it. + */ +void +ChartOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet != NULL) { + chartOverlaySet->insertOverlayBelow(overlayIndex); + this->updateColoringAndGraphics(); + } +} + +/** + * Remove an overlay above the overlay with the given index. + * @param overlayIndex + * Index of overlay that will be removed + */ +void +ChartOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet != NULL) { + chartOverlaySet->removeDisplayedOverlay(overlayIndex); + this->updateColoringAndGraphics(); + } +} + +/** + * Remove an overlay above the overlay with the given index. + * @param overlayIndex + * Index of overlay that will be removed + */ +void +ChartOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet != NULL) { + chartOverlaySet->moveDisplayedOverlayDown(overlayIndex); + this->updateColoringAndGraphics(); + } +} + +/** + * Remove an overlay above the overlay with the given index. + * @param overlayIndex + * Index of overlay that will be removed + */ +void +ChartOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) +{ + ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + if (chartOverlaySet != NULL) { + chartOverlaySet->moveDisplayedOverlayUp(overlayIndex); + this->updateColoringAndGraphics(); + } +} + +/** + * Update surface coloring and graphics after overlay changes. + */ +void +ChartOverlaySetViewController::updateColoringAndGraphics() +{ + this->updateViewController(); + + EventGraphicsUpdateOneWindow graphicsUpdate(m_browserWindowIndex); + EventManager::get()->sendEvent(graphicsUpdate.getPointer()); +} diff --git a/src/GuiQt/ChartOverlaySetViewController.h b/src/GuiQt/ChartOverlaySetViewController.h new file mode 100644 index 000000000..26b90e826 --- /dev/null +++ b/src/GuiQt/ChartOverlaySetViewController.h @@ -0,0 +1,91 @@ +#ifndef __CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ +#define __CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include "EventListenerInterface.h" + +class QScrollArea; + +namespace caret { + class ChartOverlaySet; + class ChartOverlayViewController; + class WuQGridLayoutGroup; + + class ChartOverlaySetViewController : public QWidget, public EventListenerInterface { + + Q_OBJECT + + public: + ChartOverlaySetViewController(const Qt::Orientation orientation, + const int32_t browserWindowIndex, + QWidget* parent = 0); + + virtual ~ChartOverlaySetViewController(); + + + // ADD_NEW_METHODS_HERE + + virtual void receiveEvent(Event* event); + + private slots: + void processAddOverlayAbove(const int32_t overlayIndex); + + void processAddOverlayBelow(const int32_t overlayIndex); + + void processRemoveOverlay(const int32_t overlayIndex); + + void processMoveOverlayDown(const int32_t overlayIndex); + + void processMoveOverlayUp(const int32_t overlayIndex); + + private: + ChartOverlaySetViewController(const ChartOverlaySetViewController&); + + ChartOverlaySetViewController& operator=(const ChartOverlaySetViewController&); + + ChartOverlaySet* getChartOverlaySet(); + + void updateViewController(); + + void updateColoringAndGraphics(); + + const int32_t m_browserWindowIndex; + + std::vector m_chartOverlayViewControllers; + + std::vector m_chartOverlayGridLayoutGroups; + + QScrollArea* m_scrollArea; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ + // +#endif // __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ + +} // namespace +#endif //__CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartOverlayViewController.cxx new file mode 100644 index 000000000..9f5951298 --- /dev/null +++ b/src/GuiQt/ChartOverlayViewController.cxx @@ -0,0 +1,1024 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ +#include "ChartOverlayViewController.h" +#undef __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +using namespace caret; + +#include "AnnotationColorBar.h" +#include "CaretMappableDataFile.h" +#include "ChartOverlay.h" +#include "EventDataFileReload.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventGraphicsUpdateOneWindow.h" +#include "EventManager.h" +#include "EventMapYokingSelectMap.h" +#include "EventOverlaySettingsEditorDialogRequest.h" +#include "EventUserInterfaceUpdate.h" +#include "FileInformation.h" +#include "FilePathNamePrefixCompactor.h" +#include "GuiManager.h" +#include "MapYokingGroupComboBox.h" +#include "UsernamePasswordWidget.h" +#include "WuQFactory.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +/** + * \class caret::ChartOverlayViewController + * \brief View controller for a chart overlay + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param orientation + * Orientation of view controller. + * @param browserWindowIndex + * Index of browser window in which this view controller resides. + * @param chartOverlayIndex + * Index of this overlay view controller. + * @param parent + * The parent widget. + */ +ChartOverlayViewController::ChartOverlayViewController(const Qt::Orientation orientation, + const int32_t browserWindowIndex, + const int32_t chartOverlayIndex, + QObject* parent) +: QObject(parent), +m_browserWindowIndex(browserWindowIndex), +m_chartOverlayIndex(chartOverlayIndex), +m_chartOverlay(NULL) +{ + int minComboBoxWidth = 200; + int maxComboBoxWidth = 100000; //400; + if (orientation == Qt::Horizontal) { + minComboBoxWidth = 50; + maxComboBoxWidth = 100000; + } + const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; + + /* + * Enabled Check Box + */ + const QString checkboxText = ((orientation == Qt::Horizontal) ? " " : " "); + m_enabledCheckBox = new QCheckBox(checkboxText); + QObject::connect(m_enabledCheckBox, SIGNAL(clicked(bool)), + this, SLOT(enabledCheckBoxClicked(bool))); + m_enabledCheckBox->setToolTip("Enables display of this layer"); + + /* + * Settings Tool Button + */ + QIcon settingsIcon; + const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", + settingsIcon); + + m_settingsAction = WuQtUtilities::createAction("S", + "Edit settings for this chart", + this, + this, + SLOT(settingsActionTriggered())); + if (settingsIconValid) { + m_settingsAction->setIcon(settingsIcon); + } + m_settingsToolButton = new QToolButton(); + m_settingsToolButton->setDefaultAction(m_settingsAction); + + /* + * ColorBar Tool Button + */ + QIcon colorBarIcon; + const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", + colorBarIcon); + m_colorBarAction = WuQtUtilities::createAction("CB", + "Display color bar for this overlay", + this, + this, + SLOT(colorBarActionTriggered(bool))); + m_colorBarAction->setCheckable(true); + if (colorBarIconValid) { + m_colorBarAction->setIcon(colorBarIcon); + } + m_colorBarToolButton = new QToolButton(); + m_colorBarToolButton->setDefaultAction(m_colorBarAction); + + /* + * Construction Tool Button + */ + QIcon constructionIcon; + const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", + constructionIcon); + m_constructionAction = WuQtUtilities::createAction("M", + "Add/Move/Remove Layers", + this); + if (constructionIconValid) { + m_constructionAction->setIcon(constructionIcon); + } + m_constructionToolButton = new QToolButton(); + QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); + m_constructionAction->setMenu(constructionMenu); + m_constructionToolButton->setDefaultAction(m_constructionAction); + m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); + + /* + * History button + */ + m_historyToolButton = new QToolButton(); + m_historyAction = WuQtUtilities::createAction("", + "Show history for line chart file", + this, + this, + SLOT(historyActionTriggered(bool))); + QPixmap historyPixmap = createHistoryPixmap(m_historyToolButton); + m_historyAction->setIcon(historyPixmap); + m_historyToolButton->setDefaultAction(m_historyAction); + //m_historyToolButton->setIconSize(historyPixmap.size()); + + /* + * Map file Selection Check Box + */ + m_mapFileComboBox = WuQFactory::newComboBox(); + m_mapFileComboBox->setMinimumWidth(minComboBoxWidth); + m_mapFileComboBox->setMaximumWidth(maxComboBoxWidth); + QObject::connect(m_mapFileComboBox, SIGNAL(activated(int)), + this, SLOT(fileComboBoxSelected(int))); + m_mapFileComboBox->setToolTip("Selects file for this overlay"); + m_mapFileComboBox->setSizeAdjustPolicy(comboSizePolicy); + + /* + * Yoking Group + */ + const AString yokeToolTip = ("Select a yoking group.\n" + "\n" + "When files with more than one map are yoked,\n" + "the seleted maps are synchronized by map index.\n" + "\n" + "If the SAME FILE is in yoked in multiple overlays,\n" + "the overlay enabled statuses are synchronized.\n"); + m_mapYokingGroupComboBox = new MapYokingGroupComboBox(this); + m_mapYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); + m_mapYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); +#ifdef CARET_OS_MACOSX + m_mapYokingGroupComboBox->getWidget()->setFixedWidth(m_mapYokingGroupComboBox->getWidget()->sizeHint().width() - 20); +#endif // CARET_OS_MACOSX + QObject::connect(m_mapYokingGroupComboBox, SIGNAL(itemActivated()), + this, SLOT(yokingGroupActivated())); + + /* + * All maps check box + */ + m_allMapsCheckBox = new QCheckBox("All Maps"); + m_allMapsCheckBox->setToolTip("Show histogram of all maps"); + if (orientation == Qt::Horizontal) { + m_allMapsCheckBox->setText(" "); + } + QObject::connect(m_allMapsCheckBox, SIGNAL(clicked(bool)), + this, SLOT(allMapsCheckBoxClicked(bool))); + + /* + * Map Index Spin Box + */ + m_mapIndexSpinBox = WuQFactory::newSpinBox(); + QObject::connect(m_mapIndexSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(mapIndexSpinBoxValueChanged(int))); + m_mapIndexSpinBox->setToolTip("Select map by its index"); + + /* + * Map Name Combo Box + */ + m_mapNameComboBox = WuQFactory::newComboBox(); + m_mapNameComboBox->setMinimumWidth(minComboBoxWidth); + m_mapNameComboBox->setMaximumWidth(maxComboBoxWidth); + QObject::connect(m_mapNameComboBox, SIGNAL(activated(int)), + this, SLOT(mapNameComboBoxSelected(int))); + m_mapNameComboBox->setToolTip("Select map by its name"); + m_mapNameComboBox->setSizeAdjustPolicy(comboSizePolicy); +} + +/** + * Destructor. + */ +ChartOverlayViewController::~ChartOverlayViewController() +{ +} + +/* + * If this overlay ins an overlay settings editor, update its content + */ +void +ChartOverlayViewController::updateOverlaySettingsEditor() +{ + if (m_chartOverlay == NULL) { + return; + } + + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + mapIndex); + + if ((mapFile != NULL) + && (mapIndex >= 0)) { + EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED, + m_browserWindowIndex, + m_chartOverlay, + mapFile, + mapIndex); + EventManager::get()->sendEvent(pcme.getPointer()); + } +} + +/** + * Called when a selection is made from the file combo box. + * @parm indx + * Index of selection. + */ +void +ChartOverlayViewController::fileComboBoxSelected(int indx) +{ + if (m_chartOverlay == NULL) { + return; + } + + void* pointer = m_mapFileComboBox->itemData(indx).value(); + CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; + m_chartOverlay->setSelectionData(file, 0); + + validateYokingSelection(); + + //validateYokingSelection(overlay->getYokingGroup()); + // not needed with call to validateYokingSelection: this->updateViewController(this->overlay); + + // called inside validateYokingSelection(); this->updateUserInterfaceAndGraphicsWindow(); + + updateOverlaySettingsEditor(); + updateViewController(m_chartOverlay); + updateGraphicsWindow(); + + if (file != NULL) { + if (file->isVolumeMappable()) { + /* + * Need to update slice indices/coords in toolbar. + */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); + } + } +} + +/** + * Called when a selection is made from the map index spin box. + * @parm indx + * Index of selection. + */ +void +ChartOverlayViewController::mapIndexSpinBoxValueChanged(int indx) +{ + if (m_chartOverlay == NULL) + { + //TSC: not sure how to put the displayed integer back to 0 where it starts when opening without data files + return; + } + /* + * Get the file that is selected from the file combo box + */ + const int32_t fileIndex = m_mapFileComboBox->currentIndex(); + void* pointer = m_mapFileComboBox->itemData(fileIndex).value(); + CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; + + /* + * Overlay indices range [0, N-1] but spin box shows [1, N]. + */ + const int overlayIndex = indx - 1; + + m_chartOverlay->setSelectionData(file, overlayIndex); + + const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + file, + overlayIndex, + m_chartOverlay->isEnabled()); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + + /* + * Need to update map name combo box. + */ + m_mapNameComboBox->blockSignals(true); + if ((overlayIndex >= 0) + && (overlayIndex < m_mapNameComboBox->count())) { + m_mapNameComboBox->setCurrentIndex(overlayIndex); + } + m_mapNameComboBox->blockSignals(false); + + this->updateUserInterface(); + this->updateGraphicsWindow(); + + updateOverlaySettingsEditor(); +} + +/** + * Called when a selection is made from the map name combo box. + * @parm indx + * Index of selection. + */ +void +ChartOverlayViewController::mapNameComboBoxSelected(int indx) +{ + if (m_chartOverlay == NULL) { + return; + } + + /* + * Get the file that is selected from the file combo box + */ + const int32_t fileIndex = m_mapFileComboBox->currentIndex(); + void* pointer = m_mapFileComboBox->itemData(fileIndex).value(); + CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; + + m_chartOverlay->setSelectionData(file, indx); + + const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + file, + indx, + m_chartOverlay->isEnabled()); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + + /* + * Need to update map index spin box. + * Note that the map index spin box ranges [1, N]. + */ + m_mapIndexSpinBox->blockSignals(true); + m_mapIndexSpinBox->setValue(indx + 1); + m_mapIndexSpinBox->blockSignals(false); + + this->updateUserInterface(); + this->updateGraphicsWindow(); + + updateOverlaySettingsEditor(); +} + +/** + * Called when enabled checkbox state is changed + * @parm checked + * Checked status + */ +void +ChartOverlayViewController::enabledCheckBoxClicked(bool checked) +{ + if (m_chartOverlay == NULL) { + return; + } + m_chartOverlay->setEnabled(checked); + + const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + CaretMappableDataFile* myFile = NULL; + int32_t myIndex = -1; + m_chartOverlay->getSelectionData(myFile, + myIndex); + + EventMapYokingSelectMap selectMapEvent(mapYoking, + myFile, + myIndex, + m_chartOverlay->isEnabled()); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + + this->updateUserInterface(); + + this->updateGraphicsWindow(); +} + +/** + * Called when colorbar toolbutton is toggled. + * @param status + * New status. + */ +void +ChartOverlayViewController::colorBarActionTriggered(bool status) +{ + if (m_chartOverlay == NULL) { + return; + } + + m_chartOverlay->getColorBar()->setDisplayed(status); + + this->updateGraphicsWindow(); +} + +/** + * Called when colorbar toolbutton is toggled. + * @param status + * New status. + */ +void +ChartOverlayViewController::allMapsCheckBoxClicked(bool status) +{ + if (m_chartOverlay == NULL) { + return; + } + + m_chartOverlay->setAllMapsSelected(status); + + this->updateGraphicsWindow(); +} + +/** + * Validate yoking when there are changes made to the overlay. + */ +void +ChartOverlayViewController::validateYokingSelection() +{ + m_mapYokingGroupComboBox->validateYokingChange(m_chartOverlay); + updateViewController(m_chartOverlay); + updateGraphicsWindow(); + //EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Called when the yoking group is changed. + */ +void +ChartOverlayViewController::yokingGroupActivated() +{ + MapYokingGroupEnum::Enum yokingGroup = m_mapYokingGroupComboBox->getMapYokingGroup(); + + /* + * Has yoking group changed? + * TSC: overlay can be null when opened without loaded files + */ + if (m_chartOverlay != NULL && yokingGroup != m_chartOverlay->getMapYokingGroup()) { + validateYokingSelection(); + } +} + + +/** + * Called when the settings action is selected. + */ +void +ChartOverlayViewController::settingsActionTriggered() +{ + if (m_chartOverlay == NULL) { + return; + } + + CaretMappableDataFile* mapFile; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + mapIndex); + if (mapFile != NULL) { + EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, + m_browserWindowIndex, + m_chartOverlay, + mapFile, + mapIndex); + EventManager::get()->sendEvent(pcme.getPointer()); + } +} + +/** + * Called when the history action is selected. + */ +void +ChartOverlayViewController::historyActionTriggered(bool) +{ + if (m_chartOverlay == NULL) { + return; + } + + CaretMappableDataFile* mapFile; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + mapIndex); + + CaretAssertToDoWarning(); +// if (mapFile != NULL) { +// EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, +// m_browserWindowIndex, +// m_chartOverlay, +// mapFile, +// mapIndex); +// EventManager::get()->sendEvent(pcme.getPointer()); +// } +} + + +/** + * Update this view controller using the given overlay. + * @param overlay + * Overlay that is used in this view controller. + */ +void +ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) +{ + m_chartOverlay = chartOverlay; + + m_mapFileComboBox->clear(); + + /* + * Get the selection information for the overlay. + */ + std::vector dataFiles; + CaretMappableDataFile* selectedFile = NULL; + //AString selectedMapUniqueID = ""; + int32_t selectedMapIndex = -1; + if (m_chartOverlay != NULL) { + m_chartOverlay->getSelectionData(dataFiles, + selectedFile, + //selectedMapUniqueID, + selectedMapIndex); + } + + std::vector displayNames; + FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(dataFiles, + displayNames); + CaretAssert(dataFiles.size() == displayNames.size()); + + /* + * Load the file selection combo box. + */ + int32_t selectedFileIndex = -1; + const int32_t numFiles = static_cast(dataFiles.size()); + for (int32_t i = 0; i < numFiles; i++) { + CaretMappableDataFile* dataFile = dataFiles[i]; + + AString dataTypeName = DataFileTypeEnum::toOverlayTypeName(dataFile->getDataFileType()); + CaretAssertVectorIndex(displayNames, i); + m_mapFileComboBox->addItem(displayNames[i], + qVariantFromValue((void*)dataFile)); + if (dataFile == selectedFile) { + selectedFileIndex = i; + } + } + if (selectedFileIndex >= 0) { + m_mapFileComboBox->setCurrentIndex(selectedFileIndex); + } + + /* + * Load the map selection combo box + */ + int32_t numberOfMaps = 0; + m_mapNameComboBox->blockSignals(true); + m_mapNameComboBox->clear(); + if (selectedFile != NULL) { + numberOfMaps = selectedFile->getNumberOfMaps(); + for (int32_t i = 0; i < numberOfMaps; i++) { + m_mapNameComboBox->addItem(selectedFile->getMapName(i)); + } + m_mapNameComboBox->setCurrentIndex(selectedMapIndex); + } + m_mapNameComboBox->blockSignals(false); + + /* + * Load the map index spin box that ranges [1, N]. + */ + m_mapIndexSpinBox->blockSignals(true); + m_mapIndexSpinBox->setRange(1, numberOfMaps); + if (selectedFile != NULL) { + m_mapIndexSpinBox->setValue(selectedMapIndex + 1); + } + m_mapIndexSpinBox->blockSignals(false); + + /* + * Update enable check box + */ + Qt::CheckState checkState = Qt::Unchecked; + if (m_chartOverlay != NULL) { + if (m_chartOverlay->isEnabled()) { + checkState = Qt::Checked; + } + } + m_enabledCheckBox->setCheckState(checkState); + + m_mapYokingGroupComboBox->setMapYokingGroup(m_chartOverlay->getMapYokingGroup()); + + m_allMapsCheckBox->setChecked(m_chartOverlay->isAllMapsSelected()); + + + m_colorBarAction->blockSignals(true); + m_colorBarAction->setChecked(m_chartOverlay->getColorBar()->isDisplayed()); + m_colorBarAction->blockSignals(false); + + const bool haveFile = (selectedFile != NULL); + bool haveMultipleMaps = false; + bool dataIsMappedWithPalette = false; + bool dataIsMappedWithLabelTable = false; + bool dataIsMappedWithRGBA = false; + bool haveOpacity = false; + if (haveFile) { + dataIsMappedWithPalette = selectedFile->isMappedWithPalette(); + dataIsMappedWithLabelTable = selectedFile->isMappedWithLabelTable(); + dataIsMappedWithRGBA = selectedFile->isMappedWithRGBA(); + haveMultipleMaps = (selectedFile->getNumberOfMaps() > 1); + haveOpacity = (dataIsMappedWithLabelTable + || dataIsMappedWithPalette + || dataIsMappedWithRGBA); + } + + /** + * Yoking is enabled when either: + * (1) The file maps to both surface and volumes + * (2) The file has multiple maps. + */ + bool haveYoking = false; + if (haveFile) { + if (selectedFile->isSurfaceMappable() + && selectedFile->isVolumeMappable()) { + haveYoking = true; + } + if (haveMultipleMaps) { + haveYoking = true; + } + } + + /* + * Update tooltips with full path to file and name of map + * as names may be too long to fit into combo boxes + */ + AString fileComboBoxToolTip("Select file for this overlay"); + AString nameComboBoxToolTip("Select map by its name"); + if (selectedFile != NULL) { + FileInformation fileInfo(selectedFile->getFileName()); + fileComboBoxToolTip.append(":\n" + + fileInfo.getFileName() + + "\n" + + fileInfo.getPathName() + + "\n\n" + + "Copy File Name/Path to Clipboard with Construction Menu"); + + nameComboBoxToolTip.append(":\n" + + m_mapNameComboBox->currentText()); + } + m_mapFileComboBox->setToolTip(fileComboBoxToolTip); + m_mapNameComboBox->setToolTip(nameComboBoxToolTip); + + /* + * Make sure items are enabled at the appropriate time + */ + m_enabledCheckBox->setEnabled(haveFile); + m_settingsAction->setEnabled(true); + m_colorBarAction->setEnabled(dataIsMappedWithPalette); + m_constructionAction->setEnabled(true); + m_historyAction->setEnabled(haveMultipleMaps); + m_mapFileComboBox->setEnabled(haveFile); + m_mapYokingGroupComboBox->getWidget()->setEnabled(haveYoking); + m_allMapsCheckBox->setEnabled(haveMultipleMaps); + m_mapIndexSpinBox->setEnabled(haveMultipleMaps); + m_mapNameComboBox->setEnabled(haveFile); +} + +/** + * Update graphics and GUI after selections made + */ +void +ChartOverlayViewController::updateUserInterfaceAndGraphicsWindow() +{ + updateUserInterface(); + updateGraphicsWindow(); +} + +/** + * Update graphics and GUI after selections made + */ +void +ChartOverlayViewController::updateUserInterface() +{ + if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + } + else { + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).getPointer()); + } +} + +/** + * Update graphics after selections made + */ +void +ChartOverlayViewController::updateGraphicsWindow() +{ + if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + else { + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + } +} + +/** + * Create the construction menu. + * @param parent + * Parent widget. + */ +QMenu* +ChartOverlayViewController::createConstructionMenu(QWidget* parent) +{ + QMenu* menu = new QMenu(parent); + QObject::connect(menu, SIGNAL(aboutToShow()), + this, SLOT(menuConstructionAboutToShow())); + + menu->addAction("Add Overlay Above", + this, + SLOT(menuAddOverlayAboveTriggered())); + + menu->addAction("Add Overlay Below", + this, + SLOT(menuAddOverlayBelowTriggered())); + + menu->addSeparator(); + + menu->addAction("Move Overlay Up", + this, + SLOT(menuMoveOverlayUpTriggered())); + + menu->addAction("Move Overlay Down", + this, + SLOT(menuMoveOverlayDownTriggered())); + + menu->addSeparator(); + + menu->addAction("Remove This Overlay", + this, + SLOT(menuRemoveOverlayTriggered())); + + menu->addSeparator(); + + m_constructionReloadFileAction = menu->addAction("Reload Selected File", + this, + SLOT(menuReloadFileTriggered())); + + menu->addSeparator(); + + menu->addAction("Copy Path and File Name to Clipboard", + this, + SLOT(menuCopyFileNameToClipBoard())); + + menu->addAction("Copy Map Name to Clipboard", + this, + SLOT(menuCopyMapNameToClipBoard())); + + return menu; + +} + +/** + * Called when construction menu is about to be displayed. + */ +void +ChartOverlayViewController::menuConstructionAboutToShow() +{ + if (m_chartOverlay != NULL) { + CaretMappableDataFile* caretDataFile = NULL; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(caretDataFile, + mapIndex); + + QString menuText = "Reload Selected File"; + if (caretDataFile != NULL) { + if (caretDataFile->isModified()) { + QString suffix = " (MODIFIED)"; + if (caretDataFile->isModifiedPaletteColorMapping()) { + if ( ! caretDataFile->isModifiedExcludingPaletteColorMapping()) { + suffix = " (MODIFIED PALETTE)"; + } + } + menuText += suffix; + } + } + m_constructionReloadFileAction->setText(menuText); + } +} + +/** + * Add an overlay above this overlay. + */ +void +ChartOverlayViewController::menuAddOverlayAboveTriggered() +{ + emit requestAddOverlayAbove(m_chartOverlayIndex); +} + +/** + * Add an overlay below this overlay. + */ +void +ChartOverlayViewController::menuAddOverlayBelowTriggered() +{ + emit requestAddOverlayBelow(m_chartOverlayIndex); +} + +/** + * Remove this overlay. + */ +void +ChartOverlayViewController::menuRemoveOverlayTriggered() +{ + emit requestRemoveOverlay(m_chartOverlayIndex); +} + +/** + * Move this overlay down. + */ +void +ChartOverlayViewController::menuMoveOverlayDownTriggered() +{ + emit requestMoveOverlayDown(m_chartOverlayIndex); +} + +/** + * Move this overlay down. + */ +void +ChartOverlayViewController::menuMoveOverlayUpTriggered() +{ + emit requestMoveOverlayUp(m_chartOverlayIndex); +} + +/** + * Copy the file name to the clip board. + */ +void +ChartOverlayViewController::menuCopyFileNameToClipBoard() +{ + if (m_chartOverlay != NULL) { + CaretMappableDataFile* caretDataFile = NULL; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(caretDataFile, + mapIndex); + + if (caretDataFile != NULL) { + QApplication::clipboard()->setText(caretDataFile->getFileName().trimmed(), + QClipboard::Clipboard); + } + } +} + +/** + * Copy the map name to the clip board. + */ +void +ChartOverlayViewController::menuCopyMapNameToClipBoard() +{ + if (m_chartOverlay != NULL) { + CaretMappableDataFile* caretDataFile = NULL; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(caretDataFile, + mapIndex); + + if (caretDataFile != NULL) { + if ((mapIndex >= 0) + && (mapIndex < caretDataFile->getNumberOfMaps())) { + QApplication::clipboard()->setText(caretDataFile->getMapName(mapIndex).trimmed(), + QClipboard::Clipboard); + } + } + } +} + +/** + * Reload the file in the overlay. + */ +void +ChartOverlayViewController::menuReloadFileTriggered() +{ + if (m_chartOverlay != NULL) { + CaretMappableDataFile* caretDataFile = NULL; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(caretDataFile, + mapIndex); + + if (caretDataFile != NULL) { + AString username; + AString password; + + if (DataFile::isFileOnNetwork(caretDataFile->getFileName())) { + const QString msg("This file is on the network. " + "If accessing the file requires a username and " + "password, enter it here. Otherwise, remove any " + "text from the username and password fields."); + + + if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(m_constructionToolButton, + "Username and Password", + msg, + username, + password)) { + /* nothing */ + } + else { + return; + } + } + + EventDataFileReload reloadEvent(GuiManager::get()->getBrain(), + caretDataFile); + reloadEvent.setUsernameAndPassword(username, + password); + EventManager::get()->sendEvent(reloadEvent.getPointer()); + + if (reloadEvent.isError()) { + WuQMessageBox::errorOk(m_constructionToolButton, + reloadEvent.getErrorMessage()); + } + + updateOverlaySettingsEditor(); + + updateUserInterfaceAndGraphicsWindow(); + } + } +} + +/** + * Create a history pixmap. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @return + * Pixmap for history. + */ +QPixmap +ChartOverlayViewController::createHistoryPixmap(QWidget* widget) +{ + CaretAssert(widget); + + /* + * Create a small, square pixmap that will contain + * the foreground color around the pixmap's perimeter. + */ + const qreal iconSize = 24.0; + const qreal centerX = iconSize / 2.0; + const qreal centerY = iconSize / 2.0; + + QPixmap pixmap(static_cast(iconSize), + static_cast(iconSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, + pixmap); + + QPen pen = painter->pen(); + pen.setWidthF(2.0); + painter->setPen(pen); + + const QPointF circleCenterXY(centerX, centerY); + const qreal circleRadius = iconSize * 0.45; + + painter->drawEllipse(circleCenterXY, + circleRadius, circleRadius); + + const qreal nineOClockX = circleRadius * 0.5; //0.25 * iconSize; + const qreal twelveOClockY = 0.15 * iconSize; + painter->drawLine(QPointF(centerX, centerY), + QPointF(nineOClockX, centerY)); + painter->drawLine(QPointF(centerX, centerY), + QPointF(centerY, twelveOClockY)); + +// painter->drawLine(QLineF(xStart, +// y, +// xEnd, +// y)); + + return pixmap; + +} + + + diff --git a/src/GuiQt/ChartOverlayViewController.h b/src/GuiQt/ChartOverlayViewController.h new file mode 100644 index 000000000..9c30eb56c --- /dev/null +++ b/src/GuiQt/ChartOverlayViewController.h @@ -0,0 +1,171 @@ +#ifndef __CHART_OVERLAY_VIEW_CONTROLLER_H__ +#define __CHART_OVERLAY_VIEW_CONTROLLER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + + +class QAction; +class QCheckBox; +class QComboBox; +class QGridLayout; +class QMenu; +class QSpinBox; +class QToolButton; + +namespace caret { + class ChartOverlay; + class MapYokingGroupComboBox; + class WuQGridLayoutGroup; + + class ChartOverlayViewController : public QObject { + + Q_OBJECT + + public: + ChartOverlayViewController(const Qt::Orientation orientation, + const int32_t browserWindowIndex, + const int32_t chartOverlayIndex, + QObject* parent); + + virtual ~ChartOverlayViewController(); + + void updateViewController(ChartOverlay* overlay); + + // ADD_NEW_METHODS_HERE + signals: + void requestAddOverlayAbove(const int32_t overlayIndex); + + void requestAddOverlayBelow(const int32_t overlayIndex); + + void requestRemoveOverlay(const int32_t overlayIndex); + + void requestMoveOverlayUp(const int32_t overlayIndex); + + void requestMoveOverlayDown(const int32_t overlayIndex); + + private slots: + void fileComboBoxSelected(int); + + void mapNameComboBoxSelected(int); + + void mapIndexSpinBoxValueChanged(int); + + void enabledCheckBoxClicked(bool); + + void colorBarActionTriggered(bool); + + void settingsActionTriggered(); + + void yokingGroupActivated(); + + void historyActionTriggered(bool); + + void allMapsCheckBoxClicked(bool); + + void menuAddOverlayAboveTriggered(); + + void menuAddOverlayBelowTriggered(); + + void menuRemoveOverlayTriggered(); + + void menuMoveOverlayDownTriggered(); + + void menuMoveOverlayUpTriggered(); + + void menuReloadFileTriggered(); + + void menuCopyFileNameToClipBoard(); + + void menuCopyMapNameToClipBoard(); + + void menuConstructionAboutToShow(); + + private: + ChartOverlayViewController(const ChartOverlayViewController&); + + ChartOverlayViewController& operator=(const ChartOverlayViewController&); + + void updateUserInterfaceAndGraphicsWindow(); + + void updateUserInterface(); + + void updateGraphicsWindow(); + + QMenu* createConstructionMenu(QWidget* parent); + + void validateYokingSelection(); + + void updateOverlaySettingsEditor(); + + QPixmap createHistoryPixmap(QWidget* widget); + + const int32_t m_browserWindowIndex; + + const int32_t m_chartOverlayIndex; + + ChartOverlay* m_chartOverlay; + + QCheckBox* m_enabledCheckBox; + + QToolButton* m_settingsToolButton; + + QAction* m_settingsAction; + + QToolButton* m_colorBarToolButton; + + QAction* m_colorBarAction; + + QAction* m_constructionAction; + + QToolButton* m_historyToolButton; + + QAction* m_historyAction; + + QComboBox* m_mapFileComboBox; + + MapYokingGroupComboBox* m_mapYokingGroupComboBox; + + QCheckBox* m_allMapsCheckBox; + + QSpinBox* m_mapIndexSpinBox; + + QComboBox* m_mapNameComboBox; + + QToolButton* m_constructionToolButton; + + QAction* m_constructionReloadFileAction; + + WuQGridLayoutGroup* m_gridLayoutGroup; + + // ADD_NEW_MEMBERS_HERE + + friend class ChartOverlaySetViewController; + }; + +#ifdef __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ + // +#endif // __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ + +} // namespace +#endif //__CHART_OVERLAY_VIEW_CONTROLLER_H__ diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx index cde63bec0..94eacf504 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx @@ -30,6 +30,9 @@ using namespace caret; /** * Constructor. + * + * @param mode + * The mode. * @param browserWindowIndex * Index of browser window. * @param overlay @@ -49,6 +52,36 @@ m_mode(mode) { m_browserWindowIndex = browserWindowIndex; m_overlay = overlay; + m_chartOverlay = NULL; + m_mapFile = mapFile; + m_mapIndex = mapIndex; +} + +/** + * Constructor. + * + * @param mode + * The mode. + * @param browserWindowIndex + * Index of browser window. + * @param overlay + * Overlay for map editor. + * @param mapFile + * Caret Mappable Data File. + * @param mapIndex + * Map index in mapFile. + */ +EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, + const int32_t browserWindowIndex, + ChartOverlay* chartOverlay, + CaretMappableDataFile* mapFile, + const int32_t mapIndex) +: Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), +m_mode(mode) +{ + m_browserWindowIndex = browserWindowIndex; + m_overlay = NULL; + m_chartOverlay = chartOverlay; m_mapFile = mapFile; m_mapIndex = mapIndex; } diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h index 2ce02f8d4..01ede0829 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h @@ -27,6 +27,7 @@ namespace caret { class CaretMappableDataFile; + class ChartOverlay; class Overlay; /// Event for showing edit map scalar color mapping editor @@ -44,6 +45,12 @@ namespace caret { CaretMappableDataFile* mapFile, const int32_t mapIndex); + EventOverlaySettingsEditorDialogRequest(const Mode mode, + const int32_t browserWindowIndex, + ChartOverlay* chartOverlay, + CaretMappableDataFile* mapFile, + const int32_t mapIndex); + virtual ~EventOverlaySettingsEditorDialogRequest(); /** @@ -76,6 +83,16 @@ namespace caret { */ const Overlay* getOverlay() const { return m_overlay; } + /** + * @return The chart overlay for the editor. + */ + ChartOverlay* getChartOverlay() { return m_chartOverlay; } + + /** + * @return The overlay for the editor. + */ + const ChartOverlay* getChartOverlay() const { return m_chartOverlay; } + private: EventOverlaySettingsEditorDialogRequest(const EventOverlaySettingsEditorDialogRequest&); @@ -90,6 +107,9 @@ namespace caret { /** Overlay for editor. */ Overlay* m_overlay; + /** Chart Overlay for editor. */ + ChartOverlay* m_chartOverlay; + /** Map file containing map whose color palette is edited */ CaretMappableDataFile* m_mapFile; diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index 6c7159992..e235398d5 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -25,6 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" +#include "ChartOverlay.h" #include "ChartableMatrixSeriesInterface.h" #include "CiftiScalarDataSeriesFile.h" #include "EnumComboBoxTemplate.h" @@ -195,6 +196,47 @@ MapYokingGroupComboBox::validateYokingChange(Overlay* overlay) } } +/** + * Validate a change in yoking for a chart overlay. + * + * @param chartOverlay + * Chart overlay whose yoking changes. + */ +void +MapYokingGroupComboBox::validateYokingChange(ChartOverlay* chartOverlay) +{ + const MapYokingGroupEnum::Enum previousMapYokingGroup = chartOverlay->getMapYokingGroup(); + const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = -1; + chartOverlay->getSelectionData(mapFile, mapIndex); + bool selectionStatus = chartOverlay->isEnabled(); + + if ((mapFile != NULL) + && (mapIndex >= 0)) { + const YokeValidationResult result = validateYoking(mapFile, + mapIndex, + selectionStatus); + + switch (result) { + case YOKE_VALIDATE_RESULT_ACCEPT: + chartOverlay->setEnabled(selectionStatus); + chartOverlay->setSelectionData(mapFile, + mapIndex); + chartOverlay->setMapYokingGroup(newYokingGroup); + break; + case YOKE_VALIDATE_RESULT_OFF: + chartOverlay->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); + break; + case YOKE_VALIDATE_RESULT_PREVIOUS: + chartOverlay->setMapYokingGroup(previousMapYokingGroup); + break; + } + + setMapYokingGroup(chartOverlay->getMapYokingGroup()); + } +} + /** * Validate yoking when a new file is added to a yoking group. * diff --git a/src/GuiQt/MapYokingGroupComboBox.h b/src/GuiQt/MapYokingGroupComboBox.h index 1fcb9345f..b0858cdbb 100644 --- a/src/GuiQt/MapYokingGroupComboBox.h +++ b/src/GuiQt/MapYokingGroupComboBox.h @@ -27,6 +27,7 @@ namespace caret { class CaretMappableDataFile; + class ChartOverlay; class ChartableMatrixSeriesInterface; class EnumComboBoxTemplate; class Overlay; @@ -50,6 +51,8 @@ namespace caret { void validateYokingChange(Overlay* overlay); + void validateYokingChange(ChartOverlay* chartOverlay); + // ADD_NEW_METHODS_HERE signals: -- GitLab From 02707bd99040d9c271d4cf3db36c72cc9dd7e729 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Dec 2016 09:20:12 -0600 Subject: [PATCH 176/755] Added ChartingVersionEnum that will be used to distinguish between old (version one) and the new charting implementation (version two). --- src/Brain/ModelChart.cxx | 294 ++++++++++++++++++++- src/Brain/ModelChart.h | 13 +- src/Charting/CMakeLists.txt | 2 + src/Charting/ChartingVersionEnum.cxx | 375 +++++++++++++++++++++++++++ src/Charting/ChartingVersionEnum.h | 104 ++++++++ 5 files changed, 778 insertions(+), 10 deletions(-) create mode 100644 src/Charting/ChartingVersionEnum.cxx create mode 100644 src/Charting/ChartingVersionEnum.h diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 97436dac0..99fab9620 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -39,8 +39,9 @@ #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" -#include "CiftiMappableDataFile.h" #include "ChartOverlaySetArray.h" +#include "ChartingVersionEnum.h" +#include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" @@ -751,6 +752,9 @@ void ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { + sceneClass->addEnumeratedType("chartingVersion", + ChartingVersionEnum::CHARTING_VERSION_TWO); + std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); std::set validChartDataIDs; @@ -800,7 +804,7 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr /** * Restore information specific to the type of model from the scene. - * + * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when @@ -809,17 +813,48 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr * @param sceneClass * sceneClass from which model specific information is obtained. */ -void +void ModelChart::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) + const SceneClass* sceneClass) { reset(); + const ChartingVersionEnum::Enum chartingVersion = + sceneClass->getEnumeratedTypeValue("chartingVersion", + ChartingVersionEnum::CHARTING_VERSION_ONE); + + switch (chartingVersion) { + case ChartingVersionEnum::CHARTING_VERSION_ONE: + restoreVersionOneModelSpecificInformationFromScene(sceneAttributes, + sceneClass); + break; + case ChartingVersionEnum::CHARTING_VERSION_TWO: + restoreVersionTwoModelSpecificInformationFromScene(sceneAttributes, + sceneClass); + break; + } +} + +/** + * Restore information specific to the type of model from VERSION ONE scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ /* * Restore the chart models */ - restoreChartModelsFromScene(sceneAttributes, - sceneClass); + restoreVersionOneChartModelsFromScene(sceneAttributes, + sceneClass); sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartDataType); @@ -857,6 +892,63 @@ ModelChart::restoreModelSpecificInformationFromScene(const SceneAttributes* scen } } +/** + * Restore information specific to the type of model from VERSION TWO scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + /* + * Restore the chart models + */ + restoreVersionTwoChartModelsFromScene(sceneAttributes, + sceneClass); + + sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", + m_selectedChartDataType); + + /* + * Restore matrix chart models from scene. + */ + const SceneObjectMapIntegerKey* matrixSceneMap = sceneClass->getMapIntegerKey("chartableMatrixFileSelectionModelMap"); + if (matrixSceneMap != NULL) { + const std::vector tabIndices = matrixSceneMap->getKeys(); + for (std::vector::const_iterator tabIter = tabIndices.begin(); + tabIter != tabIndices.end(); + tabIter++) { + const int32_t tabIndex = *tabIter; + const SceneClass* sceneClass = matrixSceneMap->classValue(tabIndex); + m_chartableMatrixFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); + } + } + + /* + * Restore matrix chart series models from scene. + */ + const SceneObjectMapIntegerKey* matrixSeriesSceneMap = sceneClass->getMapIntegerKey("chartableMatrixSeriesFileSelectionModelMap"); + if (matrixSeriesSceneMap != NULL) { + const std::vector tabIndices = matrixSeriesSceneMap->getKeys(); + for (std::vector::const_iterator tabIter = tabIndices.begin(); + tabIter != tabIndices.end(); + tabIter++) { + const int32_t tabIndex = *tabIter; + const SceneClass* sceneClass = matrixSeriesSceneMap->classValue(tabIndex); + m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); + } + } +} + /** * Save chart models to the scene. * @@ -967,7 +1059,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, } /** - * Restore the chart models from the scene. + * Restore the chart models from a VERSION ONE scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types @@ -978,7 +1070,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, * sceneClass from which model specific information is obtained. */ void -ModelChart::restoreChartModelsFromScene(const SceneAttributes* sceneAttributes, +ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { /* @@ -1152,6 +1244,192 @@ ModelChart::restoreChartModelsFromScene(const SceneAttributes* sceneAttributes, } } +/** + * Restore the chart models from a VERSION TWO scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + /* + * Restore the chart models + */ + const SceneClassArray* chartModelArray = sceneClass->getClassArray("chartModelArray"); + if (chartModelArray != NULL) { + const int numElements = chartModelArray->getNumberOfArrayElements(); + for (int32_t i = 0; i < numElements; i++) { + const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); + if (chartClassContainer != NULL) { + const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); + const ChartDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", + ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); + + if ((tabIndex >= 0) + && (chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartModelClass != NULL)) { + CaretAssertArrayIndex(m_chartModelDataSeries, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + + switch (chartDataType) { + case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + CaretAssert(0); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, + chartModelClass); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, + chartModelClass); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, + chartModelClass); + break; + } + } + } + } + } + + /* + * Restore the chart data. + */ + std::vector > restoredChartData; + const SceneClassArray* chartDataArray = sceneClass->getClassArray("chartDataArray"); + if (chartDataArray != NULL) { + const int numElements = chartDataArray->getNumberOfArrayElements(); + for (int32_t i = 0; i < numElements; i++) { + const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); + if (chartDataContainer != NULL) { + const ChartDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", + ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); + if ((chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartDataClass != NULL)) { + ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); + CaretAssert(chartData); + + /* + * The chart's points are saved in the scene and this + * function call restores the points. This is part of + * the original implementation. However, it was decided + * that the when the scene is restored, the data should + * be loaded from the file to reflect any changes made + * to the data file. But, we still load the chart points + * saved to the scene in case the file is missing. + */ + chartData->restoreFromScene(sceneAttributes, chartDataClass); + + /* + * Now load the chart data from the file using the + * information in the chart's data source. If this is + * successful, then overwrite the chart data points + * that were loaded from the scene file. + * + * Also need to copy the unique identifier so that + * the chart data goes to the correct model. + */ + ChartData* newChartData = loadCartesianChartWhenRestoringScene(chartData); + if (newChartData != NULL) { + newChartData->setUniqueIdentifier(chartData->getUniqueIdentifier()); + newChartData->copySelectionStatusForAllTabs(chartData); + delete chartData; + chartData = newChartData; + } + else { + const AString msg("FAILED to load line chart data from file for " + + chartData->getChartDataSource()->getDescription() + + " so chart points from scene will be used. If content of the file " + " has changed since the scene was created, the chart may not be accurate."); + sceneAttributes->addToErrorMessage(msg); + CaretLogWarning(msg); + } + + restoredChartData.push_back(QSharedPointer(chartData)); + } + } + } + } + + /* + * Have chart models restore pointers to chart data + * The chart models use shared pointers are used since the chart + * data may be in multiple tabs. User may remove the charts + * from some tabs but not others and shared pointers make management + * easier. + */ + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartModelDataSeries[i]->restoreChartDataFromScene(sceneAttributes, + restoredChartData); + } + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartModelFrequencySeries[i]->restoreChartDataFromScene(sceneAttributes, + restoredChartData); + } + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartModelTimeSeries[i]->restoreChartDataFromScene(sceneAttributes, + restoredChartData); + } + + /* + * The chart data are also saved here as weak pointers so + * that they can be saved to a scene only one time. If + */ + for (std::vector >::iterator rcdIter = restoredChartData.begin(); + rcdIter != restoredChartData.end(); + rcdIter++) { + QSharedPointer chartPointer = *rcdIter; + + switch (chartPointer->getChartDataType()) { + case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + CaretAssert(0); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + CaretAssert(0); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + CaretAssert(0); + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + { + QSharedPointer cartChartPointer = chartPointer.dynamicCast(); + CaretAssert( ! cartChartPointer.isNull()); + m_dataSeriesChartData.push_back(cartChartPointer); + } + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + { + QSharedPointer cartChartPointer = chartPointer.dynamicCast(); + CaretAssert( ! cartChartPointer.isNull()); + m_frequencySeriesChartData.push_back(cartChartPointer); + } + break; + case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + { + QSharedPointer cartChartPointer = chartPointer.dynamicCast(); + CaretAssert( ! cartChartPointer.isNull()); + m_timeSeriesChartData.push_back(cartChartPointer); + } + break; + } + } +} + /** * Load the cartesian chart data using the given chart data source. * diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 1d66bf4ef..272b00b32 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -155,9 +155,12 @@ namespace caret { const std::vector& tabIndices, std::set& validChartDataIDsOut); - void restoreChartModelsFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); + void restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + void restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; @@ -166,6 +169,12 @@ namespace caret { ChartData* loadCartesianChartWhenRestoringScene(const ChartData* chartData); + void restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + void restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 783166936..c8494cf49 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -36,6 +36,7 @@ ChartModelTimeSeries.h ChartPoint.h ChartScaleAutoRanging.h ChartSelectionModeEnum.h +ChartingVersionEnum.h ChartAxis.cxx ChartAxisCartesian.cxx @@ -58,6 +59,7 @@ ChartModelTimeSeries.cxx ChartPoint.cxx ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx +ChartingVersionEnum.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) diff --git a/src/Charting/ChartingVersionEnum.cxx b/src/Charting/ChartingVersionEnum.cxx new file mode 100644 index 000000000..a0315d5e1 --- /dev/null +++ b/src/Charting/ChartingVersionEnum.cxx @@ -0,0 +1,375 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHARTING_VERSION_ENUM_DECLARE__ +#include "ChartingVersionEnum.h" +#undef __CHARTING_VERSION_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartingVersionEnum + * \brief Version of Charting Implementation + * + * + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartingVersionEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartingVersionEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartingVersionEnum.h" + * + * Instatiate: + * m_chartingVersionEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartingVersionEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartingVersionEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartingVersionEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartingVersionEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartingVersionEnum::Enum VARIABLE = m_chartingVersionEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartingVersionEnum::ChartingVersionEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartingVersionEnum::~ChartingVersionEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartingVersionEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartingVersionEnum(CHARTING_VERSION_ONE, + "CHARTING_VERSION_ONE", + "Charting Version One")); + + enumData.push_back(ChartingVersionEnum(CHARTING_VERSION_TWO, + "CHARTING_VERSION_TWO", + "Charting Version Two")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartingVersionEnum* +ChartingVersionEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartingVersionEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartingVersionEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartingVersionEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartingVersionEnum::Enum +ChartingVersionEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartingVersionEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartingVersionEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartingVersionEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartingVersionEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartingVersionEnum::Enum +ChartingVersionEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartingVersionEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartingVersionEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartingVersionEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartingVersionEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartingVersionEnum::Enum +ChartingVersionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartingVersionEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartingVersionEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartingVersionEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartingVersionEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartingVersionEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartingVersionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartingVersionEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartingVersionEnum.h b/src/Charting/ChartingVersionEnum.h new file mode 100644 index 000000000..dd72f5120 --- /dev/null +++ b/src/Charting/ChartingVersionEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHARTING_VERSION_ENUM_H__ +#define __CHARTING_VERSION_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartingVersionEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + CHARTING_VERSION_ONE, + /** */ + CHARTING_VERSION_TWO + }; + + + ~ChartingVersionEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartingVersionEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartingVersionEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHARTING_VERSION_ENUM_DECLARE__ +std::vector ChartingVersionEnum::enumData; +bool ChartingVersionEnum::initializedFlag = false; +int32_t ChartingVersionEnum::integerCodeCounter = 0; +#endif // __CHARTING_VERSION_ENUM_DECLARE__ + +} // namespace +#endif //__CHARTING_VERSION_ENUM_H__ -- GitLab From ddff92829c858f54794abd66a6a8392a93ac7bc9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Dec 2016 09:50:26 -0600 Subject: [PATCH 177/755] Renamed ChartDataTypeEnum to ChartVersionOneDataTypeEnum --- src/Brain/Brain.cxx | 4 +- src/Brain/Brain.h | 6 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 14 +- src/Brain/BrowserTabContent.cxx | 40 +-- src/Brain/ChartOverlay.cxx | 2 +- src/Brain/ChartOverlay.h | 6 +- src/Brain/ChartOverlaySet.cxx | 2 +- src/Brain/ChartOverlaySet.h | 6 +- src/Brain/ChartOverlaySetArray.cxx | 2 +- src/Brain/ModelChart.cxx | 264 +++++++++--------- src/Brain/ModelChart.h | 10 +- src/Charting/CMakeLists.txt | 4 +- src/Charting/ChartData.cxx | 18 +- src/Charting/ChartData.h | 10 +- src/Charting/ChartDataCartesian.cxx | 2 +- src/Charting/ChartDataCartesian.h | 2 +- src/Charting/ChartModel.cxx | 4 +- src/Charting/ChartModel.h | 8 +- src/Charting/ChartModelCartesian.cxx | 4 +- src/Charting/ChartModelCartesian.h | 2 +- src/Charting/ChartModelDataSeries.cxx | 2 +- src/Charting/ChartModelFrequencySeries.cxx | 2 +- src/Charting/ChartModelTimeSeries.cxx | 2 +- ...um.cxx => ChartVersionOneDataTypeEnum.cxx} | 106 +++---- ...peEnum.h => ChartVersionOneDataTypeEnum.h} | 26 +- src/Files/CaretMappableDataFile.cxx | 16 +- src/Files/CaretMappableDataFile.h | 4 +- src/Files/ChartableLineSeriesInterface.cxx | 4 +- src/Files/ChartableLineSeriesInterface.h | 6 +- src/Files/ChartableMatrixInterface.cxx | 4 +- src/Files/ChartableMatrixInterface.h | 6 +- .../CiftiBrainordinateDataSeriesFile.cxx | 2 +- src/Files/CiftiBrainordinateDataSeriesFile.h | 2 +- src/Files/CiftiBrainordinateScalarFile.cxx | 4 +- src/Files/CiftiBrainordinateScalarFile.h | 2 +- .../CiftiConnectivityMatrixParcelFile.cxx | 4 +- src/Files/CiftiConnectivityMatrixParcelFile.h | 2 +- src/Files/CiftiParcelLabelFile.cxx | 4 +- src/Files/CiftiParcelLabelFile.h | 2 +- src/Files/CiftiParcelScalarFile.cxx | 8 +- src/Files/CiftiParcelScalarFile.h | 4 +- src/Files/CiftiParcelSeriesFile.cxx | 6 +- src/Files/CiftiParcelSeriesFile.h | 2 +- src/Files/CiftiScalarDataSeriesFile.cxx | 18 +- src/Files/CiftiScalarDataSeriesFile.h | 4 +- src/Files/MetricFile.cxx | 2 +- src/Files/MetricFile.h | 2 +- src/Files/VolumeFile.cxx | 2 +- src/Files/VolumeFile.h | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 12 +- ...ainBrowserWindowToolBarChartAttributes.cxx | 28 +- .../BrainBrowserWindowToolBarChartAxes.cxx | 14 +- .../BrainBrowserWindowToolBarChartType.cxx | 66 ++--- .../BrainBrowserWindowToolBarChartType.h | 4 +- src/GuiQt/ChartHistoryViewController.cxx | 12 +- .../ChartLinesSelectionViewController.cxx | 16 +- ...artMatrixParcelSelectionViewController.cxx | 16 +- ...artMatrixSeriesSelectionViewController.cxx | 16 +- src/GuiQt/ChartSelectionViewController.cxx | 14 +- src/GuiQt/ChartToolBoxViewController.cxx | 24 +- 60 files changed, 441 insertions(+), 441 deletions(-) rename src/Charting/{ChartDataTypeEnum.cxx => ChartVersionOneDataTypeEnum.cxx} (69%) rename src/Charting/{ChartDataTypeEnum.h => ChartVersionOneDataTypeEnum.h} (80%) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index ea52a06d2..f7cc9d89a 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -3445,7 +3445,7 @@ Brain::getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); @@ -3542,7 +3542,7 @@ Brain::getAllChartableMatrixDataFiles(std::vector& ch * Contains all chartable data files upon exit. */ void -Brain::getAllChartableMatrixDataFilesForChartDataType(const ChartDataTypeEnum::Enum chartDataType, +Brain::getAllChartableMatrixDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index 488b63714..6e933b945 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -25,7 +25,7 @@ #include #include "CaretObject.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" @@ -321,14 +321,14 @@ namespace caret { void getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const; - void getAllChartableLineSeriesDataFilesForChartDataType(const ChartDataTypeEnum::Enum chartDataType, + void getAllChartableLineSeriesDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; void getAllChartableBrainordinateDataFilesWithChartingEnabled(std::vector& chartableDataFilesOut) const; void getAllChartableMatrixDataFiles(std::vector& chartableDataFilesOut) const; - void getAllChartableMatrixDataFilesForChartDataType(const ChartDataTypeEnum::Enum chartDataType, + void getAllChartableMatrixDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; AString getCurrentDirectory() const; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 2542a62d8..82791c94b 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5283,34 +5283,34 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const int32_t tabIndex = browserTabContent->getTabNumber(); ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; - const ChartDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartDataType(tabIndex); SelectionItemDataTypeEnum::Enum selectionItemDataType = SelectionItemDataTypeEnum::INVALID; int32_t scalarDataSeriesMapIndex = -1; switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = chartModel->getSelectedDataSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_DATA_SERIES; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = chartModel->getSelectedFrequencySeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_FREQUENCY_SERIES; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = chartModel->getSelectedTimeSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_TIME_SERIES; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* matrixFileSelector = chartModel->getChartableMatrixParcelFileSelectionModel(tabIndex); matrixChartFile = matrixFileSelector->getSelectedFileOfType(); selectionItemDataType = SelectionItemDataTypeEnum::CHART_MATRIX; } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = chartModel->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 1b30ef45e..b0bc2dc7d 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1304,21 +1304,21 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo CaretDataFileSelectionModel* fileModel = NULL; switch (modelChart->getSelectedChartDataType(m_tabNumber)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -1453,21 +1453,21 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetSelectedChartDataType(m_tabNumber)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -2390,11 +2390,11 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { @@ -2506,11 +2506,11 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index eb23fc874..cf156ef8b 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -49,7 +49,7 @@ using namespace caret; /** * Constructor. */ -ChartOverlay::ChartOverlay(const ChartDataTypeEnum::Enum chartDataType) +ChartOverlay::ChartOverlay(const ChartVersionOneDataTypeEnum::Enum chartDataType) : CaretObject(), m_chartDataType(chartDataType) { diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index a3476f65f..d905cebae 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -24,7 +24,7 @@ #include "CaretObject.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "MatrixViewingTypeEnum.h" @@ -40,7 +40,7 @@ namespace caret { class ChartOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlay(const ChartDataTypeEnum::Enum chartDataType); + ChartOverlay(const ChartVersionOneDataTypeEnum::Enum chartDataType); virtual ~ChartOverlay(); @@ -113,7 +113,7 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - const ChartDataTypeEnum::Enum m_chartDataType; + const ChartVersionOneDataTypeEnum::Enum m_chartDataType; /** Name of overlay (DO NOT COPY)*/ AString m_name; diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx index 53078a3e1..2d01eb0a0 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartOverlaySet.cxx @@ -44,7 +44,7 @@ using namespace caret; /** * Constructor. */ -ChartOverlaySet::ChartOverlaySet(const ChartDataTypeEnum::Enum chartDataType, +ChartOverlaySet::ChartOverlaySet(const ChartVersionOneDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex) : CaretObject(), diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartOverlaySet.h index 3b3dcd38c..d1b970112 100644 --- a/src/Brain/ChartOverlaySet.h +++ b/src/Brain/ChartOverlaySet.h @@ -23,7 +23,7 @@ #include "BrainConstants.h" #include "CaretObject.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" @@ -36,7 +36,7 @@ namespace caret { class ChartOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlaySet(const ChartDataTypeEnum::Enum chartDataType, + ChartOverlaySet(const ChartVersionOneDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex); @@ -110,7 +110,7 @@ namespace caret { ChartOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; - const ChartDataTypeEnum::Enum m_chartDataType; + const ChartVersionOneDataTypeEnum::Enum m_chartDataType; const AString m_name; diff --git a/src/Brain/ChartOverlaySetArray.cxx b/src/Brain/ChartOverlaySetArray.cxx index cb4486301..677e77afd 100644 --- a/src/Brain/ChartOverlaySetArray.cxx +++ b/src/Brain/ChartOverlaySetArray.cxx @@ -52,7 +52,7 @@ m_name(name) { m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartOverlaySets[i] = new ChartOverlaySet(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, + m_chartOverlaySets[i] = new ChartOverlaySet(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, name, i); } diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 99fab9620..98f0cbd85 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -109,7 +109,7 @@ void ModelChart::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectedChartDataType[i] = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_selectedChartDataType[i] = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; m_chartModelDataSeries[i] = new ChartModelDataSeries(); m_chartModelDataSeries[i]->getLeftAxis()->setText("Value"); @@ -363,13 +363,13 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, { CaretAssert(chartData); - const ChartDataTypeEnum::Enum chartDataDataType = chartData->getChartDataType(); + const ChartVersionOneDataTypeEnum::Enum chartDataDataType = chartData->getChartDataType(); switch (chartDataDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -384,7 +384,7 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_dataSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -399,7 +399,7 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_frequencySeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -414,10 +414,10 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_timeSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; } } @@ -763,7 +763,7 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr tabIndices, validChartDataIDs); - sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartDataType, tabIndices); @@ -856,7 +856,7 @@ ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttrib restoreVersionOneChartModelsFromScene(sceneAttributes, sceneClass); - sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartDataType); /* @@ -913,7 +913,7 @@ ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttrib restoreVersionTwoChartModelsFromScene(sceneAttributes, sceneClass); - sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartDataType); /* @@ -981,19 +981,19 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, ChartModel* chartModel = NULL; switch (getSelectedChartDataType(tabIndex)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = getSelectedDataSeriesChartModel(tabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = getSelectedTimeSeriesChartModel(tabIndex); break; } @@ -1009,7 +1009,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, "ChartClassContainer", 1); chartClassContainer->addInteger("tabIndex", tabIndex); - chartClassContainer->addEnumeratedType("chartDataType", + chartClassContainer->addEnumeratedType("chartDataType", chartModel->getChartDataType()); chartClassContainer->addClass(chartModelClass); @@ -1043,7 +1043,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, SceneClass* chartDataContainer = new SceneClass("chartDataContainer", "ChartDataContainer", 1); - chartDataContainer->addEnumeratedType("chartDataType", + chartDataContainer->addEnumeratedType("chartDataType", chartData->getChartDataType()); chartDataContainer->addClass(chartDataClass); @@ -1083,34 +1083,34 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); if (chartClassContainer != NULL) { const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); - const ChartDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", - ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", + ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); if ((tabIndex >= 0) - && (chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartModelClass != NULL)) { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; @@ -1130,10 +1130,10 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); if (chartDataContainer != NULL) { - const ChartDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", - ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", + ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); - if ((chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + if ((chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartDataClass != NULL)) { ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); CaretAssert(chartData); @@ -1210,30 +1210,30 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt QSharedPointer chartPointer = *rcdIter; switch (chartPointer->getChartDataType()) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_dataSeriesChartData.push_back(cartChartPointer); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_frequencySeriesChartData.push_back(cartChartPointer); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); @@ -1269,34 +1269,34 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); if (chartClassContainer != NULL) { const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); - const ChartDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", - ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", + ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); if ((tabIndex >= 0) - && (chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartModelClass != NULL)) { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; @@ -1316,10 +1316,10 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); if (chartDataContainer != NULL) { - const ChartDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", - ChartDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", + ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); - if ((chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) + if ((chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartDataClass != NULL)) { ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); CaretAssert(chartData); @@ -1396,30 +1396,30 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt QSharedPointer chartPointer = *rcdIter; switch (chartPointer->getChartDataType()) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_dataSeriesChartData.push_back(cartChartPointer); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_frequencySeriesChartData.push_back(cartChartPointer); } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); @@ -1448,7 +1448,7 @@ ModelChart::loadCartesianChartWhenRestoringScene(const ChartData* chartData) const ChartDataCartesian* cartesianChart = dynamic_cast(chartData); if (cartesianChart != NULL) { - const ChartDataTypeEnum::Enum chartDataType = cartesianChart->getChartDataType(); + const ChartVersionOneDataTypeEnum::Enum chartDataType = cartesianChart->getChartDataType(); std::vector chartableDataFiles; m_brain->getAllChartableLineSeriesDataFiles(chartableDataFiles); @@ -1608,9 +1608,9 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, { ChartModel* chartModel = NULL; switch (getSelectedChartDataType(tabIndex)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* sm = m_chartableMatrixFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); @@ -1621,7 +1621,7 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* sm = m_chartableMatrixSeriesFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); @@ -1632,13 +1632,13 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = const_cast(getSelectedDataSeriesChartModel(tabIndex)); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = const_cast(getSelectedFrequencySeriesChartModel(tabIndex)); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = const_cast(getSelectedTimeSeriesChartModel(tabIndex)); break; } @@ -1647,7 +1647,7 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, if (chartModel != NULL) { descriptionOut.addLine("Chart Type: " - + ChartDataTypeEnum::toGuiName(chartModel->getChartDataType())); + + ChartVersionOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); descriptionOut.pushIndentation(); @@ -1711,7 +1711,7 @@ ModelChart::copyTabContent(const int32_t sourceTabIndex, */ void ModelChart::setSelectedChartDataType(const int32_t tabIndex, - const ChartDataTypeEnum::Enum dataType) + const ChartVersionOneDataTypeEnum::Enum dataType) { CaretAssertArrayIndex(m_selectedChartDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, @@ -1726,7 +1726,7 @@ ModelChart::setSelectedChartDataType(const int32_t tabIndex, * Output containing valid chart data types. */ void -ModelChart::getValidChartDataTypes(std::vector& validChartDataTypesOut) const +ModelChart::getValidChartDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); @@ -1744,27 +1744,27 @@ ModelChart::getValidChartDataTypes(std::vector& validCh fileIter++) { ChartableLineSeriesInterface* chartFile = *fileIter; - std::vector chartDataTypes; + std::vector chartDataTypes; chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); - for (std::vector::iterator typeIter = chartDataTypes.begin(); + for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { - const ChartDataTypeEnum::Enum cdt = *typeIter; + const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: haveDataSeries = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: haveFrequencySeries = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: haveTimeSeries = true; break; } @@ -1780,27 +1780,27 @@ ModelChart::getValidChartDataTypes(std::vector& validCh // fileIter++) { // ChartableLineSeriesBrainordinateInterface* chartFile = *fileIter; // -// std::vector chartDataTypes; +// std::vector chartDataTypes; // chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); // -// for (std::vector::iterator typeIter = chartDataTypes.begin(); +// for (std::vector::iterator typeIter = chartDataTypes.begin(); // typeIter != chartDataTypes.end(); // typeIter++) { -// const ChartDataTypeEnum::Enum cdt = *typeIter; +// const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; // switch (cdt) { -// case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // haveDataSeries = true; // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // haveFrequencySeries = true; // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // haveTimeSeries = true; // break; // } @@ -1815,46 +1815,46 @@ ModelChart::getValidChartDataTypes(std::vector& validCh fileIter++) { ChartableMatrixInterface* chartFile = *fileIter; - std::vector chartDataTypes; + std::vector chartDataTypes; chartFile->getSupportedMatrixChartDataTypes(chartDataTypes); - for (std::vector::iterator typeIter = chartDataTypes.begin(); + for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { - const ChartDataTypeEnum::Enum cdt = *typeIter; + const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: haveMatrixLayers = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: haveMatrixSeries = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } } if (haveDataSeries) { - validChartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); + validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); } if (haveFrequencySeries) { - validChartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); + validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); } if (haveMatrixLayers) { - validChartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } if (haveMatrixSeries) { - validChartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); + validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } if (haveTimeSeries) { - validChartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); } } @@ -1867,85 +1867,85 @@ ModelChart::getValidChartDataTypes(std::vector& validCh * @return * Chart type in the given tab. */ -ChartDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::Enum ModelChart::getSelectedChartDataType(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedChartDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - ChartDataTypeEnum::Enum chartDataType = m_selectedChartDataType[tabIndex]; + ChartVersionOneDataTypeEnum::Enum chartDataType = m_selectedChartDataType[tabIndex]; /* * Verify that the selected chart data type is valid. */ - std::vector validChartDataTypes; + std::vector validChartDataTypes; getValidChartDataTypes(validChartDataTypes); if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartDataType) == validChartDataTypes.end()) { - chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; } /* * If selected chart data type is invalid, find a valid chart type, * preferably one that contains data. */ - if (chartDataType == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { if ( ! validChartDataTypes.empty()) { /* * Will become the the first valid chart data type that contains * data (if there is one) */ - ChartDataTypeEnum::Enum chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; /* * Loop through all chart types (some or all valid charts * types may not contain data until the user commands loading of data) */ - std::vector allChartDataTypes; - ChartDataTypeEnum::getAllEnums(allChartDataTypes); - for (std::vector::iterator iter = allChartDataTypes.begin(); + std::vector allChartDataTypes; + ChartVersionOneDataTypeEnum::getAllEnums(allChartDataTypes); + for (std::vector::iterator iter = allChartDataTypes.begin(); iter != allChartDataTypes.end(); iter++) { - const ChartDataTypeEnum::Enum cdt = *iter; + const ChartVersionOneDataTypeEnum::Enum cdt = *iter; if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), cdt) != validChartDataTypes.end()) { - if (chartDataType == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = cdt; } switch (cdt) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (chartDataTypeWithValidData == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (chartDataTypeWithValidData == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; + if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; + if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; + if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; } } break; @@ -1953,10 +1953,10 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const } } - if (chartDataTypeWithValidData != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataTypeWithValidData != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = chartDataTypeWithValidData; } - else if (chartDataType == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + else if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = validChartDataTypes[0]; } } @@ -2170,17 +2170,17 @@ ModelChart::getChartOverlaySet(const int tabIndex) ChartOverlaySet* chartOverlaySet = NULL; switch (getSelectedChartDataType(tabIndex)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; } diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 272b00b32..63254614d 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -28,7 +28,7 @@ #include #include -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "Model.h" @@ -94,12 +94,12 @@ namespace caret { virtual void receiveEvent(Event* event); - void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; + void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; - ChartDataTypeEnum::Enum getSelectedChartDataType(const int32_t tabIndex) const; + ChartVersionOneDataTypeEnum::Enum getSelectedChartDataType(const int32_t tabIndex) const; void setSelectedChartDataType(const int32_t tabIndex, - const ChartDataTypeEnum::Enum dataType); + const ChartVersionOneDataTypeEnum::Enum dataType); ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex); @@ -180,7 +180,7 @@ namespace caret { ChartOverlaySetArray* m_chartOverlaySetArray; - mutable ChartDataTypeEnum::Enum m_selectedChartDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + mutable ChartVersionOneDataTypeEnum::Enum m_selectedChartDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ ChartModelDataSeries* m_chartModelDataSeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index c8494cf49..3730296ae 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -24,7 +24,6 @@ ChartData.h ChartDataCartesian.h ChartDataSource.h ChartDataSourceModeEnum.h -ChartDataTypeEnum.h ChartMatrixDisplayProperties.h ChartMatrixLoadingDimensionEnum.h ChartMatrixScaleModeEnum.h @@ -36,6 +35,7 @@ ChartModelTimeSeries.h ChartPoint.h ChartScaleAutoRanging.h ChartSelectionModeEnum.h +ChartVersionOneDataTypeEnum.h ChartingVersionEnum.h ChartAxis.cxx @@ -47,7 +47,6 @@ ChartData.cxx ChartDataCartesian.cxx ChartDataSource.cxx ChartDataSourceModeEnum.cxx -ChartDataTypeEnum.cxx ChartMatrixDisplayProperties.cxx ChartMatrixLoadingDimensionEnum.cxx ChartMatrixScaleModeEnum.cxx @@ -59,6 +58,7 @@ ChartModelTimeSeries.cxx ChartPoint.cxx ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx +ChartVersionOneDataTypeEnum.cxx ChartingVersionEnum.cxx ) diff --git a/src/Charting/ChartData.cxx b/src/Charting/ChartData.cxx index 98b37278d..1d63c0988 100644 --- a/src/Charting/ChartData.cxx +++ b/src/Charting/ChartData.cxx @@ -46,7 +46,7 @@ using namespace caret; * @param chartDataType * Type of chart model. */ -ChartData::ChartData(const ChartDataTypeEnum::Enum chartDataType) +ChartData::ChartData(const ChartVersionOneDataTypeEnum::Enum chartDataType) : CaretObject(), SceneableInterface(), m_chartDataType(chartDataType) @@ -143,30 +143,30 @@ ChartData::copyHelperChartData(const ChartData& obj) * Pointer to new instance. */ ChartData* -ChartData::newChartDataForChartDataType(const ChartDataTypeEnum::Enum chartDataType) +ChartData::newChartDataForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType) { ChartData* chartData = NULL; switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); @@ -233,7 +233,7 @@ ChartData::restoreFromScene(const SceneAttributes* sceneAttributes, /** * @return The chart data model type. */ -ChartDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::Enum ChartData::getChartDataType() const { return m_chartDataType; diff --git a/src/Charting/ChartData.h b/src/Charting/ChartData.h index 8598ca6ec..e291cbef5 100644 --- a/src/Charting/ChartData.h +++ b/src/Charting/ChartData.h @@ -23,7 +23,7 @@ #include "BrainConstants.h" #include "CaretObject.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "SceneableInterface.h" @@ -35,7 +35,7 @@ namespace caret { class ChartData : public CaretObject, public SceneableInterface { public: - static ChartData* newChartDataForChartDataType(const ChartDataTypeEnum::Enum chartDataType); + static ChartData* newChartDataForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType); virtual ~ChartData(); @@ -50,7 +50,7 @@ namespace caret { */ virtual ChartData* clone() const = 0; - ChartDataTypeEnum::Enum getChartDataType() const; + ChartVersionOneDataTypeEnum::Enum getChartDataType() const; const ChartDataSource* getChartDataSource() const; @@ -80,7 +80,7 @@ namespace caret { virtual AString toString() const; protected: - ChartData(const ChartDataTypeEnum::Enum chartDataType); + ChartData(const ChartVersionOneDataTypeEnum::Enum chartDataType); ChartData(const ChartData& obj); @@ -124,7 +124,7 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - ChartDataTypeEnum::Enum m_chartDataType; + ChartVersionOneDataTypeEnum::Enum m_chartDataType; ChartDataSource* m_chartDataSource; diff --git a/src/Charting/ChartDataCartesian.cxx b/src/Charting/ChartDataCartesian.cxx index 744576fdf..3ca8cfb18 100644 --- a/src/Charting/ChartDataCartesian.cxx +++ b/src/Charting/ChartDataCartesian.cxx @@ -52,7 +52,7 @@ using namespace caret; * @param dataAxisUnitsY * Data units for Y-axis. */ -ChartDataCartesian::ChartDataCartesian(const ChartDataTypeEnum::Enum chartDataType, +ChartDataCartesian::ChartDataCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartData(chartDataType), diff --git a/src/Charting/ChartDataCartesian.h b/src/Charting/ChartDataCartesian.h index aa29c3781..878a5b993 100644 --- a/src/Charting/ChartDataCartesian.h +++ b/src/Charting/ChartDataCartesian.h @@ -34,7 +34,7 @@ namespace caret { class ChartDataCartesian : public ChartData { public: - ChartDataCartesian(const ChartDataTypeEnum::Enum chartDataType, + ChartDataCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); diff --git a/src/Charting/ChartModel.cxx b/src/Charting/ChartModel.cxx index c460aeed9..2d35b8bf0 100644 --- a/src/Charting/ChartModel.cxx +++ b/src/Charting/ChartModel.cxx @@ -55,7 +55,7 @@ using namespace caret; * @param chartSelectionMode * The selection mode. */ -ChartModel::ChartModel(const ChartDataTypeEnum::Enum chartDataType, +ChartModel::ChartModel(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode) : CaretObject(), SceneableInterface(), @@ -244,7 +244,7 @@ ChartModel::copyHelperChartModel(const ChartModel& obj) /** * @return The chart data type. */ -ChartDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::Enum ChartModel::getChartDataType() const { return m_chartDataType; diff --git a/src/Charting/ChartModel.h b/src/Charting/ChartModel.h index 80b611ce5..b42bba6b4 100644 --- a/src/Charting/ChartModel.h +++ b/src/Charting/ChartModel.h @@ -26,7 +26,7 @@ #include #include "CaretObject.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "ChartSelectionModeEnum.h" #include "SceneableInterface.h" @@ -40,7 +40,7 @@ namespace caret { class ChartModel : public CaretObject, public SceneableInterface { public: - ChartModel(const ChartDataTypeEnum::Enum chartDataType, + ChartModel(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode); ChartModel(const ChartModel&); @@ -51,7 +51,7 @@ namespace caret { void removeChartData(); - ChartDataTypeEnum::Enum getChartDataType() const; + ChartVersionOneDataTypeEnum::Enum getChartDataType() const; ChartSelectionModeEnum::Enum getChartSelectionMode() const; @@ -160,7 +160,7 @@ namespace caret { void updateUsingMaximumNumberOfChartDatasToDisplay(); - ChartDataTypeEnum::Enum m_chartDataType; + ChartVersionOneDataTypeEnum::Enum m_chartDataType; ChartSelectionModeEnum::Enum m_chartSelectionMode; diff --git a/src/Charting/ChartModelCartesian.cxx b/src/Charting/ChartModelCartesian.cxx index 31e05ca3c..fcaf53acb 100644 --- a/src/Charting/ChartModelCartesian.cxx +++ b/src/Charting/ChartModelCartesian.cxx @@ -54,7 +54,7 @@ using namespace caret; * @param dataAxisUnitsY * Units for the Y-axis. */ -ChartModelCartesian::ChartModelCartesian(const ChartDataTypeEnum::Enum chartDataType, +ChartModelCartesian::ChartModelCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartModel(chartDataType, @@ -170,7 +170,7 @@ ChartModelCartesian::getAverageChartDataForDisplay(const int32_t tabIndex) const std::vector xValue; std::vector ySum; int64_t averageCounter = 0; - ChartDataTypeEnum::Enum firstChartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum firstChartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; bool firstFlag = true; for (std::vector::const_iterator iter = allData.begin(); diff --git a/src/Charting/ChartModelCartesian.h b/src/Charting/ChartModelCartesian.h index 96625f86c..e2d0204ec 100644 --- a/src/Charting/ChartModelCartesian.h +++ b/src/Charting/ChartModelCartesian.h @@ -32,7 +32,7 @@ namespace caret { class ChartModelCartesian : public ChartModel { public: - ChartModelCartesian(const ChartDataTypeEnum::Enum chartDataType, + ChartModelCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); diff --git a/src/Charting/ChartModelDataSeries.cxx b/src/Charting/ChartModelDataSeries.cxx index c39c555ed..031f50b00 100644 --- a/src/Charting/ChartModelDataSeries.cxx +++ b/src/Charting/ChartModelDataSeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelDataSeries::ChartModelDataSeries() -: ChartModelCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartModelFrequencySeries.cxx b/src/Charting/ChartModelFrequencySeries.cxx index 27b1e2b58..96bfc279c 100644 --- a/src/Charting/ChartModelFrequencySeries.cxx +++ b/src/Charting/ChartModelFrequencySeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelFrequencySeries::ChartModelFrequencySeries() -: ChartModelCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, +: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartModelTimeSeries.cxx b/src/Charting/ChartModelTimeSeries.cxx index 435055b94..d49803e36 100644 --- a/src/Charting/ChartModelTimeSeries.cxx +++ b/src/Charting/ChartModelTimeSeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelTimeSeries::ChartModelTimeSeries() -: ChartModelCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, +: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartDataTypeEnum.cxx b/src/Charting/ChartVersionOneDataTypeEnum.cxx similarity index 69% rename from src/Charting/ChartDataTypeEnum.cxx rename to src/Charting/ChartVersionOneDataTypeEnum.cxx index 48faa16af..273c47d96 100644 --- a/src/Charting/ChartDataTypeEnum.cxx +++ b/src/Charting/ChartVersionOneDataTypeEnum.cxx @@ -20,9 +20,9 @@ /*LICENSE_END*/ #include -#define __CHART_DATA_TYPE_ENUM_DECLARE__ -#include "ChartDataTypeEnum.h" -#undef __CHART_DATA_TYPE_ENUM_DECLARE__ +#define __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ +#include "ChartVersionOneDataTypeEnum.h" +#undef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,8 +30,8 @@ using namespace caret; /** - * \class caret::ChartDataTypeEnum - * \brief Enumerated type for type of chart data. + * \class caret::ChartVersionOneDataTypeEnum + * \brief Enumerated type for type of VERSION ONE chart data. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -49,21 +49,21 @@ using namespace caret; * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "ChartDataTypeEnum.h" + * #include "ChartVersionOneDataTypeEnum.h" * * Instatiate: * m_chartDataTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_chartDataTypeEnumComboBox->setup(); + * m_chartDataTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDataTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDataTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_chartDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_chartDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const ChartDataTypeEnum::Enum VARIABLE = m_chartDataTypeEnumComboBox->getSelectedItem(); + * const ChartVersionOneDataTypeEnum::Enum VARIABLE = m_chartDataTypeEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -ChartDataTypeEnum::ChartDataTypeEnum(const Enum enumValue, +ChartVersionOneDataTypeEnum::ChartVersionOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,7 +91,7 @@ ChartDataTypeEnum::ChartDataTypeEnum(const Enum enumValue, /** * Destructor. */ -ChartDataTypeEnum::~ChartDataTypeEnum() +ChartVersionOneDataTypeEnum::~ChartVersionOneDataTypeEnum() { } @@ -99,34 +99,34 @@ ChartDataTypeEnum::~ChartDataTypeEnum() * Initialize the enumerated metadata. */ void -ChartDataTypeEnum::initialize() +ChartVersionOneDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_INVALID, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_INVALID, "CHART_DATA_TYPE_INVALID", "Invalid")); - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_LINE_DATA_SERIES, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_DATA_SERIES, "CHART_DATA_TYPE_LINE_DATA_SERIES", "Data Series")); - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, "CHART_DATA_TYPE_LINE_FREQUENCY_SERIES", "Frequency Series")); - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_LINE_TIME_SERIES, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_TIME_SERIES, "CHART_DATA_TYPE_LINE_TIME_SERIES", "Time Series")); - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_MATRIX_LAYER, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_LAYER, "CHART_DATA_TYPE_MATRIX_LAYER", "Matrix - Layer")); - enumData.push_back(ChartDataTypeEnum(CHART_DATA_TYPE_MATRIX_SERIES, + enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_SERIES, "CHART_DATA_TYPE_MATRIX_SERIES", "Matrix - Series")); } @@ -138,14 +138,14 @@ ChartDataTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const ChartDataTypeEnum* -ChartDataTypeEnum::findData(const Enum enumValue) +const ChartVersionOneDataTypeEnum* +ChartVersionOneDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const ChartDataTypeEnum* d = &enumData[i]; + const ChartVersionOneDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -162,10 +162,10 @@ ChartDataTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -ChartDataTypeEnum::toName(Enum enumValue) { +ChartVersionOneDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartDataTypeEnum* enumInstance = findData(enumValue); + const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -179,8 +179,8 @@ ChartDataTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -ChartDataTypeEnum::Enum -ChartDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) +ChartVersionOneDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); @@ -199,12 +199,12 @@ ChartDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) } bool validFlag = false; - Enum enumValue = ChartDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartDataTypeEnum& d = *iter; + const ChartVersionOneDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -216,7 +216,7 @@ ChartDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartDataTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); } return enumValue; } @@ -229,10 +229,10 @@ ChartDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) * String representing enumerated value. */ AString -ChartDataTypeEnum::toGuiName(Enum enumValue) { +ChartVersionOneDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartDataTypeEnum* enumInstance = findData(enumValue); + const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -246,8 +246,8 @@ ChartDataTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -ChartDataTypeEnum::Enum -ChartDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) +ChartVersionOneDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); @@ -257,12 +257,12 @@ ChartDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) } bool validFlag = false; - Enum enumValue = ChartDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartDataTypeEnum& d = *iter; + const ChartVersionOneDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -274,7 +274,7 @@ ChartDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartDataTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); } return enumValue; } @@ -286,10 +286,10 @@ ChartDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) * Integer code for data type. */ int32_t -ChartDataTypeEnum::toIntegerCode(Enum enumValue) +ChartVersionOneDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartDataTypeEnum* enumInstance = findData(enumValue); + const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -304,18 +304,18 @@ ChartDataTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -ChartDataTypeEnum::Enum -ChartDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +ChartVersionOneDataTypeEnum::Enum +ChartVersionOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartDataTypeEnum& enumInstance = *iter; + const ChartVersionOneDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -327,7 +327,7 @@ ChartDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartDataTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); } return enumValue; } @@ -340,13 +340,13 @@ ChartDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) * A vector that is OUTPUT containing all of the enumerated values. */ void -ChartDataTypeEnum::getAllEnums(std::vector& allEnums) +ChartVersionOneDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -362,16 +362,16 @@ ChartDataTypeEnum::getAllEnums(std::vector& allEnums) * If true, the names are sorted in alphabetical order. */ void -ChartDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +ChartVersionOneDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(ChartDataTypeEnum::toName(iter->enumValue)); + allNames.push_back(ChartVersionOneDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -388,16 +388,16 @@ ChartDataTypeEnum::getAllNames(std::vector& allNames, const bool isSort * If true, the names are sorted in alphabetical order. */ void -ChartDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +ChartVersionOneDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(ChartDataTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(ChartVersionOneDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Charting/ChartDataTypeEnum.h b/src/Charting/ChartVersionOneDataTypeEnum.h similarity index 80% rename from src/Charting/ChartDataTypeEnum.h rename to src/Charting/ChartVersionOneDataTypeEnum.h index 11e32bec9..c9cff0afa 100644 --- a/src/Charting/ChartDataTypeEnum.h +++ b/src/Charting/ChartVersionOneDataTypeEnum.h @@ -1,5 +1,5 @@ -#ifndef __CHART_DATA_TYPE_ENUM_H__ -#define __CHART_DATA_TYPE_ENUM_H__ +#ifndef __CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ +#define __CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class ChartDataTypeEnum { +class ChartVersionOneDataTypeEnum { public: /** @@ -50,7 +50,7 @@ public: }; - ~ChartDataTypeEnum(); + ~ChartVersionOneDataTypeEnum(); static AString toName(Enum enumValue); @@ -71,14 +71,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - ChartDataTypeEnum(const Enum enumValue, + ChartVersionOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const ChartDataTypeEnum* findData(const Enum enumValue); + static const ChartVersionOneDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -102,11 +102,11 @@ private: AString guiName; }; -#ifdef __CHART_DATA_TYPE_ENUM_DECLARE__ -std::vector ChartDataTypeEnum::enumData; -bool ChartDataTypeEnum::initializedFlag = false; -int32_t ChartDataTypeEnum::integerCodeCounter = 0; -#endif // __CHART_DATA_TYPE_ENUM_DECLARE__ +#ifdef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ +std::vector ChartVersionOneDataTypeEnum::enumData; +bool ChartVersionOneDataTypeEnum::initializedFlag = false; +int32_t ChartVersionOneDataTypeEnum::integerCodeCounter = 0; +#endif // __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ } // namespace -#endif //__CHART_DATA_TYPE_ENUM_H__ +#endif //__CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 85c10561f..d9827d5cb 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -881,12 +881,12 @@ CaretMappableDataFile::helpCreateCartesianChartData(const std::vector& da ChartDataCartesian* chartData = NULL; if (timeSeriesFlag) { - chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, + chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } else { - chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, + chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } @@ -936,29 +936,29 @@ CaretMappableDataFile::helpCreateCartesianChartData(const std::vector& da * Chart types supported by this file. */ void -CaretMappableDataFile::helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CaretMappableDataFile::helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); switch (getMapIntervalUnits()) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: CaretLogSevere("Units - PPM not supported"); CaretAssertMessage(0, "Units - PPM not supported"); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; } } diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index b9efad61a..a28b378af 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -23,7 +23,7 @@ #include "CaretDataFile.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "CaretPointer.h" #include "NiftiEnums.h" #include "PaletteNormalizationModeEnum.h" @@ -462,7 +462,7 @@ namespace caret { ChartDataCartesian* helpCreateCartesianChartData(const std::vector& data); - void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); diff --git a/src/Files/ChartableLineSeriesInterface.cxx b/src/Files/ChartableLineSeriesInterface.cxx index 39633077f..7f8b97990 100644 --- a/src/Files/ChartableLineSeriesInterface.cxx +++ b/src/Files/ChartableLineSeriesInterface.cxx @@ -42,9 +42,9 @@ using namespace caret; * True if chart data type is supported by the file, else false. */ bool -ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported(const ChartDataTypeEnum::Enum chartDataType) const +ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const { - std::vector validTypes; + std::vector validTypes; getSupportedLineSeriesChartDataTypes(validTypes); if (std::find(validTypes.begin(), diff --git a/src/Files/ChartableLineSeriesInterface.h b/src/Files/ChartableLineSeriesInterface.h index b4328a165..73b6ed589 100644 --- a/src/Files/ChartableLineSeriesInterface.h +++ b/src/Files/ChartableLineSeriesInterface.h @@ -21,7 +21,7 @@ */ /*LICENSE_END*/ -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "StructureEnum.h" namespace caret { @@ -76,9 +76,9 @@ namespace caret { * @param chartDataTypesOut * Chart types supported by this file. */ - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const = 0; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const = 0; - bool isLineSeriesChartDataTypeSupported(const ChartDataTypeEnum::Enum chartDataType) const; + bool isLineSeriesChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const; private: // ChartableLineSeriesInterface(const ChartableLineSeriesInterface&); diff --git a/src/Files/ChartableMatrixInterface.cxx b/src/Files/ChartableMatrixInterface.cxx index 9505d93ac..ca855ba15 100644 --- a/src/Files/ChartableMatrixInterface.cxx +++ b/src/Files/ChartableMatrixInterface.cxx @@ -43,9 +43,9 @@ using namespace caret; * True if chart data type is supported by the file, else false. */ bool -ChartableMatrixInterface::isMatrixChartDataTypeSupported(const ChartDataTypeEnum::Enum chartDataType) const +ChartableMatrixInterface::isMatrixChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const { - std::vector validTypes; + std::vector validTypes; getSupportedMatrixChartDataTypes(validTypes); if (std::find(validTypes.begin(), diff --git a/src/Files/ChartableMatrixInterface.h b/src/Files/ChartableMatrixInterface.h index 91572ec58..3720efcbc 100644 --- a/src/Files/ChartableMatrixInterface.h +++ b/src/Files/ChartableMatrixInterface.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ #include "CaretColorEnum.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "CiftiParcelColoringModeEnum.h" #include "YokingGroupEnum.h" @@ -155,9 +155,9 @@ namespace caret { * @param chartDataTypesOut * Chart types supported by this file. */ - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const = 0; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const = 0; - bool isMatrixChartDataTypeSupported(const ChartDataTypeEnum::Enum chartDataType) const; + bool isMatrixChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/CiftiBrainordinateDataSeriesFile.cxx b/src/Files/CiftiBrainordinateDataSeriesFile.cxx index a40b36195..54861fc84 100644 --- a/src/Files/CiftiBrainordinateDataSeriesFile.cxx +++ b/src/Files/CiftiBrainordinateDataSeriesFile.cxx @@ -297,7 +297,7 @@ CiftiBrainordinateDataSeriesFile::loadLineSeriesChartDataForVoxelAtCoordinate(co * Chart types supported by this file. */ void -CiftiBrainordinateDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiBrainordinateDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/CiftiBrainordinateDataSeriesFile.h b/src/Files/CiftiBrainordinateDataSeriesFile.h index 34317aa24..6281a49ca 100644 --- a/src/Files/CiftiBrainordinateDataSeriesFile.h +++ b/src/Files/CiftiBrainordinateDataSeriesFile.h @@ -54,7 +54,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; CiftiConnectivityMatrixDenseDynamicFile* getConnectivityMatrixDenseDynamicFile(); diff --git a/src/Files/CiftiBrainordinateScalarFile.cxx b/src/Files/CiftiBrainordinateScalarFile.cxx index 9d69de418..10a118a29 100644 --- a/src/Files/CiftiBrainordinateScalarFile.cxx +++ b/src/Files/CiftiBrainordinateScalarFile.cxx @@ -262,7 +262,7 @@ CiftiBrainordinateScalarFile::setLineSeriesChartingEnabled(const int32_t tabInde * Chart types supported by this file. */ void -CiftiBrainordinateScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiBrainordinateScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -296,7 +296,7 @@ CiftiBrainordinateScalarFile::loadLineSeriesChartDataForSurfaceNode(const Struct // data)) { // const int64_t numData = static_cast(data.size()); // -// chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // for (int64_t i = 0; i < numData; i++) { diff --git a/src/Files/CiftiBrainordinateScalarFile.h b/src/Files/CiftiBrainordinateScalarFile.h index 75ca3e1ee..39a4e5cfc 100644 --- a/src/Files/CiftiBrainordinateScalarFile.h +++ b/src/Files/CiftiBrainordinateScalarFile.h @@ -59,7 +59,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; private: CiftiBrainordinateScalarFile(const CiftiBrainordinateScalarFile&); diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.cxx b/src/Files/CiftiConnectivityMatrixParcelFile.cxx index 0615f552e..058ddc810 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.cxx +++ b/src/Files/CiftiConnectivityMatrixParcelFile.cxx @@ -325,10 +325,10 @@ CiftiConnectivityMatrixParcelFile::setMatrixChartingEnabled(const int32_t tabInd * Chart types supported by this file. */ void -CiftiConnectivityMatrixParcelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiConnectivityMatrixParcelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.h b/src/Files/CiftiConnectivityMatrixParcelFile.h index eece5eb4a..3dd0d0b26 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.h +++ b/src/Files/CiftiConnectivityMatrixParcelFile.h @@ -70,7 +70,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelLabelFile.cxx b/src/Files/CiftiParcelLabelFile.cxx index 803b308a3..edcdeb7b6 100644 --- a/src/Files/CiftiParcelLabelFile.cxx +++ b/src/Files/CiftiParcelLabelFile.cxx @@ -297,10 +297,10 @@ CiftiParcelLabelFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelLabelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelLabelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiParcelLabelFile.h b/src/Files/CiftiParcelLabelFile.h index 339dfcbd2..6e93804b5 100644 --- a/src/Files/CiftiParcelLabelFile.h +++ b/src/Files/CiftiParcelLabelFile.h @@ -58,7 +58,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelScalarFile.cxx b/src/Files/CiftiParcelScalarFile.cxx index 6e48c5e3b..fe48341e4 100644 --- a/src/Files/CiftiParcelScalarFile.cxx +++ b/src/Files/CiftiParcelScalarFile.cxx @@ -124,7 +124,7 @@ CiftiParcelScalarFile::isLineSeriesChartingSupported() const * Chart types supported by this file. */ void -CiftiParcelScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -174,7 +174,7 @@ CiftiParcelScalarFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum // data)) { // const int64_t numData = static_cast(data.size()); // -// chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // for (int64_t i = 0; i < numData; i++) { @@ -393,10 +393,10 @@ CiftiParcelScalarFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelScalarFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelScalarFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiParcelScalarFile.h b/src/Files/CiftiParcelScalarFile.h index c7a59869f..fdd4adc7e 100644 --- a/src/Files/CiftiParcelScalarFile.h +++ b/src/Files/CiftiParcelScalarFile.h @@ -56,7 +56,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; @@ -78,7 +78,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelSeriesFile.cxx b/src/Files/CiftiParcelSeriesFile.cxx index 31a45b7f1..3c1688374 100644 --- a/src/Files/CiftiParcelSeriesFile.cxx +++ b/src/Files/CiftiParcelSeriesFile.cxx @@ -107,7 +107,7 @@ CiftiParcelSeriesFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -167,12 +167,12 @@ CiftiParcelSeriesFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum // } // // if (dataSeriesFlag) { -// chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // } // else if (timeSeriesFlag) { -// chartData = new ChartDataCartesian(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, +// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // } diff --git a/src/Files/CiftiParcelSeriesFile.h b/src/Files/CiftiParcelSeriesFile.h index e9c10bdb6..45e18def8 100644 --- a/src/Files/CiftiParcelSeriesFile.h +++ b/src/Files/CiftiParcelSeriesFile.h @@ -51,7 +51,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; private: CiftiParcelSeriesFile(const CiftiParcelSeriesFile&); diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index 841cc71c8..ee58dbbe7 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -372,10 +372,10 @@ CiftiScalarDataSeriesFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiScalarDataSeriesFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiScalarDataSeriesFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); + chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } /** @@ -442,11 +442,11 @@ CiftiScalarDataSeriesFile::loadLineSeriesChartDataForRow(const int32_t rowIndex) const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiSeriesMap& seriesMap = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); - ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; AString timeUnitsString; switch (seriesMap.getUnit()) { case CiftiSeriesMap::HERTZ: - chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; + chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); @@ -455,11 +455,11 @@ CiftiScalarDataSeriesFile::loadLineSeriesChartDataForRow(const int32_t rowIndex) CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: - chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; + chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; break; } - if (chartDataType != ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); @@ -528,7 +528,7 @@ CiftiScalarDataSeriesFile::isLineSeriesChartingSupported() const * Chart types supported by this file. */ void -CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); @@ -541,7 +541,7 @@ CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; @@ -92,7 +92,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForRow(const int32_t rowIndex); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/MetricFile.cxx b/src/Files/MetricFile.cxx index dd9f3c678..7284c5355 100644 --- a/src/Files/MetricFile.cxx +++ b/src/Files/MetricFile.cxx @@ -475,7 +475,7 @@ MetricFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -MetricFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +MetricFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/MetricFile.h b/src/Files/MetricFile.h index eedd1ea2d..110d7e284 100644 --- a/src/Files/MetricFile.h +++ b/src/Files/MetricFile.h @@ -90,7 +90,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index ccf606ee6..d054eb6bf 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -2081,7 +2081,7 @@ VolumeFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -VolumeFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +VolumeFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index f1dffa016..d834eef89 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -355,7 +355,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; }; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 6aecc4aac..9a80ed756 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1405,23 +1405,23 @@ BrainBrowserWindowToolBar::updateToolBar() ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartDataType(browserTabContent->getTabNumber())) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: showChartAttributesWidget = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: showChartAttributesWidget = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index e11d9e4a6..6c3cc9474 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -133,22 +133,22 @@ BrainBrowserWindowToolBarChartAttributes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); switch (chartType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } @@ -173,12 +173,12 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); switch (chartType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { ChartableMatrixInterface* matrixInterface = modelChart->getChartableMatrixParcelFileSelectionModel(tabIndex)->getSelectedFileOfType(); if (matrixInterface != NULL) { @@ -186,7 +186,7 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); @@ -198,11 +198,11 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx index a516c1a5e..ec0fdcbf1 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx @@ -277,22 +277,22 @@ BrainBrowserWindowToolBarChartAxes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); switch (chartType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index 776f296bb..ac94a2b4a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -59,18 +59,18 @@ m_parentToolBar(parentToolBar) QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); - std::vector allChartTypes; - ChartDataTypeEnum::getAllEnums(allChartTypes); + std::vector allChartTypes; + ChartVersionOneDataTypeEnum::getAllEnums(allChartTypes); - for (std::vector::iterator chartIter = allChartTypes.begin(); + for (std::vector::iterator chartIter = allChartTypes.begin(); chartIter != allChartTypes.end(); chartIter++) { - const ChartDataTypeEnum::Enum ct = *chartIter; - if (ct == ChartDataTypeEnum::CHART_DATA_TYPE_INVALID) { + const ChartVersionOneDataTypeEnum::Enum ct = *chartIter; + if (ct == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { continue; } - QRadioButton* rb = new QRadioButton(ChartDataTypeEnum::toGuiName(ct)); + QRadioButton* rb = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ct)); m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); @@ -82,13 +82,13 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); radioButtonLayout->addStretch(); -// m_chartMatrixLayerTypeRadioButton = new QRadioButton(ChartDataTypeEnum::toGuiName(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER)); +// m_chartMatrixLayerTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER)); // -// m_chartMatrixSeriesTypeRadioButton = new QRadioButton(ChartDataTypeEnum::toGuiName(ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES)); +// m_chartMatrixSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES)); // -// m_chartDataSeriesTypeRadioButton = new QRadioButton(ChartDataTypeEnum::toGuiName(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES)); +// m_chartDataSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES)); // -// m_chartTimeSeriesTypeRadioButton = new QRadioButton(ChartDataTypeEnum::toGuiName(ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES)); +// m_chartTimeSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES)); QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), @@ -124,21 +124,21 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) { CaretAssertVectorIndex(m_chartTypeRadioButtons, buttonIndex); - ChartDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; + ChartVersionOneDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; -// ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; +// ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; // // if (m_chartDataSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; +// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; // } // else if (m_chartMatrixLayerTypeRadioButton->isChecked()) { -// chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; +// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; // } // else if (m_chartTimeSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; +// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; // } // else if (m_chartMatrixSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; +// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; // } // else { // CaretAssertMessage(0, "Has a new chart radio button been added?"); @@ -172,15 +172,15 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartDataType(tabIndex); - std::vector validChartDataTypes; + std::vector validChartDataTypes; chartModel->getValidChartDataTypes(validChartDataTypes); - for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); + for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); buttIter != m_chartTypeRadioButtons.end(); buttIter++) { - ChartDataTypeEnum::Enum chartType = buttIter->first; + ChartVersionOneDataTypeEnum::Enum chartType = buttIter->first; QRadioButton* radioButton = buttIter->second; const bool validTypeFlag = (std::find(validChartDataTypes.begin(), @@ -197,25 +197,25 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC // bool matrixLayerValidFlag = false; // bool matrixSeriesValidFlag = false; // bool timeSeriesValidFlag = false; -// for (std::vector::iterator iter = validChartDataTypes.begin(); +// for (std::vector::iterator iter = validChartDataTypes.begin(); // iter != validChartDataTypes.end(); // iter++) { // switch (*iter) { -// case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // matrixLayerValidFlag = true; // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // matrixSeriesValidFlag = true; // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // dataSeriesValidFlag = true; // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // CaretAssertToDoFatal(); // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // timeSeriesValidFlag = true; // break; // } @@ -226,21 +226,21 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC // m_chartTimeSeriesTypeRadioButton->setEnabled(timeSeriesValidFlag); // // switch (chartType) { -// case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // m_chartMatrixLayerTypeRadioButton->setChecked(true); // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // m_chartMatrixSeriesTypeRadioButton->setChecked(true); // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // m_chartDataSeriesTypeRadioButton->setChecked(true); // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // CaretAssertToDoFatal(); // break; -// case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // m_chartTimeSeriesTypeRadioButton->setChecked(true); // break; // } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.h b/src/GuiQt/BrainBrowserWindowToolBarChartType.h index eebf96f2f..1ccd667a5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.h @@ -26,7 +26,7 @@ class QButtonGroup; class QRadioButton; #include "BrainBrowserWindowToolBarComponent.h" -#include "ChartDataTypeEnum.h" +#include "ChartVersionOneDataTypeEnum.h" namespace caret { @@ -59,7 +59,7 @@ namespace caret { BrainBrowserWindowToolBar* m_parentToolBar; - std::vector > m_chartTypeRadioButtons; + std::vector > m_chartTypeRadioButtons; QButtonGroup* m_chartTypeButtonGroup; diff --git a/src/GuiQt/ChartHistoryViewController.cxx b/src/GuiQt/ChartHistoryViewController.cxx index 9c1c60b93..53e64c3af 100644 --- a/src/GuiQt/ChartHistoryViewController.cxx +++ b/src/GuiQt/ChartHistoryViewController.cxx @@ -439,19 +439,19 @@ ChartHistoryViewController::getSelectedChartModelAndTab(ChartModel* &chartModelO ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartDataType(tabIndexOut)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModelOut = modelChart->getSelectedDataSeriesChartModel(tabIndexOut); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModelOut = modelChart->getSelectedFrequencySeriesChartModel(tabIndexOut); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModelOut = modelChart->getSelectedTimeSeriesChartModel(tabIndexOut); break; } diff --git a/src/GuiQt/ChartLinesSelectionViewController.cxx b/src/GuiQt/ChartLinesSelectionViewController.cxx index 9e7e7a053..bc30debd9 100644 --- a/src/GuiQt/ChartLinesSelectionViewController.cxx +++ b/src/GuiQt/ChartLinesSelectionViewController.cxx @@ -136,7 +136,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); @@ -144,19 +144,19 @@ ChartLinesSelectionViewController::updateSelectionViewController() bool validFlag = false; switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: validFlag = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: validFlag = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: validFlag = true; break; } @@ -164,7 +164,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() if (validFlag) { std::vector chartableLineSeriesFilesVector; - const ChartDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + const ChartVersionOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); brain->getAllChartableLineSeriesDataFilesForChartDataType(chartDataType, chartableLineSeriesFilesVector); diff --git a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx index ce268fc41..499b843b7 100644 --- a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx @@ -334,13 +334,13 @@ ChartMatrixParcelSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); } - if (chartDataType == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { updateMatrixParcelChartWidget(brain, modelChart, browserTabIndex); @@ -820,9 +820,9 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartDataType(browserTabIndexOut)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); @@ -839,7 +839,7 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); @@ -856,11 +856,11 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } diff --git a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx index 8d036071e..26ec73b13 100644 --- a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx @@ -242,13 +242,13 @@ ChartMatrixSeriesSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); } - if (chartDataType == ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; @@ -354,9 +354,9 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartDataType(browserTabIndexOut)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); @@ -373,7 +373,7 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); @@ -390,11 +390,11 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } diff --git a/src/GuiQt/ChartSelectionViewController.cxx b/src/GuiQt/ChartSelectionViewController.cxx index e59da9d7f..abc022755 100644 --- a/src/GuiQt/ChartSelectionViewController.cxx +++ b/src/GuiQt/ChartSelectionViewController.cxx @@ -108,28 +108,28 @@ ChartSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartDataTypeEnum::Enum chartDataType = ChartDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); } switch (chartDataType) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: m_mode = MODE_MATRIX_LAYER; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: m_mode = MODE_MATRIX_SERIES; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_mode = MODE_BRAINORDINATE; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_mode = MODE_BRAINORDINATE; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_mode = MODE_BRAINORDINATE; break; } diff --git a/src/GuiQt/ChartToolBoxViewController.cxx b/src/GuiQt/ChartToolBoxViewController.cxx index b5566c04d..8a3c0204f 100644 --- a/src/GuiQt/ChartToolBoxViewController.cxx +++ b/src/GuiQt/ChartToolBoxViewController.cxx @@ -121,19 +121,19 @@ ChartToolBoxViewController::receiveEvent(Event* event) if (chartModel != NULL) { switch (chartModel->getChartDataType()) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: historyWidgetValid = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: historyWidgetValid = true; break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: historyWidgetValid = true; break; } @@ -171,19 +171,19 @@ ChartToolBoxViewController::getSelectedChartModel() if (modelChart != NULL) { const int32_t browserTabIndex = browserTabContent->getTabNumber(); switch (modelChart->getSelectedChartDataType(browserTabIndex)) { - case ChartDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = modelChart->getSelectedDataSeriesChartModel(browserTabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = modelChart->getSelectedFrequencySeriesChartModel(browserTabIndex); break; - case ChartDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = modelChart->getSelectedTimeSeriesChartModel(browserTabIndex); break; } -- GitLab From ee4ba82cebc9fa58b0e5886ac13a97a56be135ed Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Dec 2016 15:27:40 -0600 Subject: [PATCH 178/755] Added option for equality operator to CommandClassCreate. --- src/Commands/CommandClassCreate.cxx | 51 +++++++++++++++++++++++++++-- src/Commands/CommandClassCreate.h | 2 ++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/Commands/CommandClassCreate.cxx b/src/Commands/CommandClassCreate.cxx index 3801c01c7..00139c4eb 100644 --- a/src/Commands/CommandClassCreate.cxx +++ b/src/Commands/CommandClassCreate.cxx @@ -55,16 +55,22 @@ CommandClassCreate::getHelpInformation(const AString& /*programName*/) "\n" "Usage: \n" " [-copy] \n" + " [-equal] \n" " [-event-class ]\n" " [-event-listener] \n" " [-no-parent] \n" " [-parent ] \n" + " [-scene] \n" + " [-scene-sub-class] \n" "\n" "\n" "Options: \n" " -copy\n" " Adds copy constructor and assignment operator\n" " \n" + " -equal\n" + " Adds equality operator.\n" + " \n" " -event-class \n" " When creating an Event subclass, using this\n" " option will automatically set the parent\n" @@ -124,6 +130,7 @@ CommandClassCreate::executeOperation(ProgramParameters& parameters) AString eventTypeEnumName; bool hasCopyAndAssignment = false; + bool hasEqualityOperator = false; bool hasEventListener = false; bool hasScenes = false; bool hasScenesSubClass = false; @@ -133,6 +140,9 @@ CommandClassCreate::executeOperation(ProgramParameters& parameters) if (param == "-copy") { hasCopyAndAssignment = true; } + else if (param == "-equal") { + hasEqualityOperator = true; + } else if (param == "-event-class") { eventTypeEnumName = parameters.nextString("Event Type Enum Name"); if (eventTypeEnumName.contains("::") == false) { @@ -218,6 +228,7 @@ CommandClassCreate::executeOperation(ProgramParameters& parameters) ifndefName, ifdefNameStaticDeclarations, hasCopyAndAssignment, + hasEqualityOperator, hasEventListener, hasScenes, hasScenesSubClass); @@ -228,6 +239,7 @@ CommandClassCreate::executeOperation(ProgramParameters& parameters) eventTypeEnumName, ifdefNameStaticDeclarations, hasCopyAndAssignment, + hasEqualityOperator, hasEventListener, hasScenes, hasScenesSubClass); @@ -248,6 +260,8 @@ CommandClassCreate::executeOperation(ProgramParameters& parameters) * Name for "infdef" of static declarations. * @param hasCopyAndAssignment * Has copy constructor and assignment operator. + * @param hasEqualityOperator + * Class implements equality operator * @param hasEventListener * Class implements the EventListener interface * @param hasSceneInterface @@ -260,9 +274,10 @@ void CommandClassCreate::createHeaderFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, - const AString& ifndefName, - const AString& ifdefNameStaticDeclaration, + const AString& ifndefName, + const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, + const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving) @@ -337,6 +352,11 @@ CommandClassCreate::createHeaderFile(const AString& outputFileName, // t += (" public:\n"); } + if (hasEqualityOperator) { + t += (" bool operator==(const " + className + "& obj) const;\n"); + t += (" \n"); + } + t += ("\n"); t += (" " + getNewMethodsString() + "\n"); t += ("\n"); @@ -440,6 +460,8 @@ CommandClassCreate::createHeaderFile(const AString& outputFileName, * Name for "infdef" of static declarations. * @param hasCopyAndAssignment * Has copy constructor and assignment operator. + * @param hasEqualityOperator + * Class implements equality operator * @param hasEventListener * Class implements the EventListener interface * @param hasSceneInterface @@ -453,8 +475,9 @@ CommandClassCreate::createImplementationFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, const AString& eventTypeEnumName, - const AString& ifdefNameStaticDeclaration, + const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, + const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving) @@ -578,6 +601,28 @@ CommandClassCreate::createImplementationFile(const AString& outputFileName, t += ("\n"); } + if (hasEqualityOperator) { + t += ("/**\n"); + t += (" * Equality operator.\n"); + t += (" * @param obj\n"); + t += (" * Instance compared to this for equality.\n"); + t += (" * @return \n"); + t += (" * True if this instance and 'obj' instance are considered equal.\n"); + t += (" */\n"); + t += ("bool\n"); + t += ("" + className + "::operator==(const " + className + "& obj) const\n"); + t += ("{\n"); + t += (" if (this == &obj) {\n"); + t += (" return true; \n"); + t += (" }\n"); + t += ("\n"); + t += (" /* perform equality testing HERE and return true if equal ! */\n"); + t += ("\n"); + t += (" return false; \n"); + t += ("}\n"); + t += ("\n"); + } + if (derivedFromClassName == "CaretObject") { t += ("/**\n"); t += (" * Get a description of this object's content.\n"); diff --git a/src/Commands/CommandClassCreate.h b/src/Commands/CommandClassCreate.h index b935e28e1..17c6086a7 100644 --- a/src/Commands/CommandClassCreate.h +++ b/src/Commands/CommandClassCreate.h @@ -57,6 +57,7 @@ namespace caret { const AString& ifdefName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, + const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving); @@ -67,6 +68,7 @@ namespace caret { const AString& eventTypeEnumName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, + const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving); -- GitLab From 835fc8c8f312d9d69ee196dd563d97f75072ab38 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Jan 2017 15:39:14 -0600 Subject: [PATCH 179/755] Continuing charting redesign --- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- src/Brain/BrowserTabContent.cxx | 20 +- src/Brain/CMakeLists.txt | 2 - src/Brain/ChartOverlay.cxx | 139 +++-- src/Brain/ChartOverlay.h | 40 +- src/Brain/ChartOverlaySet.cxx | 12 +- src/Brain/ChartOverlaySet.h | 6 +- src/Brain/ChartOverlaySetArray.cxx | 105 +++- src/Brain/ChartOverlaySetArray.h | 15 +- src/Brain/ModelChart.cxx | 254 +++++++-- src/Brain/ModelChart.h | 29 +- src/Charting/CMakeLists.txt | 14 + src/Charting/ChartTwoCompoundDataType.cxx | 360 +++++++++++++ src/Charting/ChartTwoCompoundDataType.h | 123 +++++ src/Charting/ChartTwoData.cxx | 332 ++++++++++++ src/Charting/ChartTwoData.h | 143 +++++ src/Charting/ChartTwoDataCartesian.cxx | 492 ++++++++++++++++++ src/Charting/ChartTwoDataCartesian.h | 124 +++++ src/Charting/ChartTwoDataCartesianHistory.cxx | 374 +++++++++++++ src/Charting/ChartTwoDataCartesianHistory.h | 116 +++++ src/Charting/ChartTwoDataTypeEnum.cxx | 384 ++++++++++++++ src/Charting/ChartTwoDataTypeEnum.h | 110 ++++ .../ChartTwoMatrixViewingTypeEnum.cxx} | 105 ++-- .../ChartTwoMatrixViewingTypeEnum.h} | 26 +- src/Files/CMakeLists.txt | 2 + src/Files/CaretMappableDataFile.cxx | 319 +++++++++++- src/Files/CaretMappableDataFile.h | 26 +- src/Files/ChartableTwoInterface.cxx | 53 ++ src/Files/ChartableTwoInterface.h | 126 +++++ src/Files/LabelDrawingProperties.cxx | 61 ++- src/Files/LabelDrawingProperties.h | 11 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- ...ainBrowserWindowToolBarChartAttributes.cxx | 4 +- .../BrainBrowserWindowToolBarChartAxes.cxx | 2 +- .../BrainBrowserWindowToolBarChartType.cxx | 6 +- src/GuiQt/ChartHistoryViewController.cxx | 2 +- .../ChartLinesSelectionViewController.cxx | 4 +- ...artMatrixParcelSelectionViewController.cxx | 4 +- ...artMatrixSeriesSelectionViewController.cxx | 4 +- src/GuiQt/ChartOverlayViewController.h | 2 +- src/GuiQt/ChartSelectionViewController.cxx | 2 +- src/GuiQt/ChartToolBoxViewController.cxx | 2 +- 42 files changed, 3696 insertions(+), 263 deletions(-) create mode 100644 src/Charting/ChartTwoCompoundDataType.cxx create mode 100644 src/Charting/ChartTwoCompoundDataType.h create mode 100644 src/Charting/ChartTwoData.cxx create mode 100644 src/Charting/ChartTwoData.h create mode 100644 src/Charting/ChartTwoDataCartesian.cxx create mode 100644 src/Charting/ChartTwoDataCartesian.h create mode 100644 src/Charting/ChartTwoDataCartesianHistory.cxx create mode 100644 src/Charting/ChartTwoDataCartesianHistory.h create mode 100644 src/Charting/ChartTwoDataTypeEnum.cxx create mode 100644 src/Charting/ChartTwoDataTypeEnum.h rename src/{Brain/MatrixViewingTypeEnum.cxx => Charting/ChartTwoMatrixViewingTypeEnum.cxx} (67%) rename src/{Brain/MatrixViewingTypeEnum.h => Charting/ChartTwoMatrixViewingTypeEnum.h} (79%) create mode 100644 src/Files/ChartableTwoInterface.cxx create mode 100644 src/Files/ChartableTwoInterface.h diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 82791c94b..466ad6e4f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5283,7 +5283,7 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const int32_t tabIndex = browserTabContent->getTabNumber(); ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); SelectionItemDataTypeEnum::Enum selectionItemDataType = SelectionItemDataTypeEnum::INVALID; int32_t scalarDataSeriesMapIndex = -1; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index b0bc2dc7d..586cfbdce 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1303,7 +1303,7 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo if (modelChart != NULL) { CaretDataFileSelectionModel* fileModel = NULL; - switch (modelChart->getSelectedChartDataType(m_tabNumber)) { + switch (modelChart->getSelectedChartOneDataType(m_tabNumber)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: @@ -1313,12 +1313,12 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -1452,7 +1452,7 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetSelectedChartDataType(m_tabNumber)) { + switch (modelChart->getSelectedChartOneDataType(m_tabNumber)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: @@ -1462,12 +1462,12 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -2390,11 +2390,11 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { @@ -2506,11 +2506,11 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index fa1606c42..c7e160509 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -138,7 +138,6 @@ IdentifiedItem.h IdentifiedItemNode.h IdentifiedItemVoxel.h ImageDepthPositionEnum.h -MatrixViewingTypeEnum.h Model.h ModelChart.h ModelSurface.h @@ -279,7 +278,6 @@ IdentifiedItem.cxx IdentifiedItemNode.cxx IdentifiedItemVoxel.cxx ImageDepthPositionEnum.cxx -MatrixViewingTypeEnum.cxx Model.cxx ModelChart.cxx ModelSurface.cxx diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index cf156ef8b..2ba74b977 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -26,10 +26,6 @@ #include "AnnotationColorBar.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" -#include "ChartableLineSeriesBrainordinateInterface.h" -#include "ChartableLineSeriesRowColumnInterface.h" -#include "ChartableMatrixParcelInterface.h" -#include "ChartableMatrixSeriesInterface.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" @@ -48,30 +44,35 @@ using namespace caret; /** * Constructor. + * + * @param chartDataType + * Type of charts allowed in this overlay + * @param overlayIndex + * Index of this overlay. */ -ChartOverlay::ChartOverlay(const ChartVersionOneDataTypeEnum::Enum chartDataType) +ChartOverlay::ChartOverlay(const ChartTwoDataTypeEnum::Enum chartDataType, + const int32_t overlayIndex) : CaretObject(), -m_chartDataType(chartDataType) +m_chartDataType(chartDataType), +m_overlayIndex(overlayIndex) { - m_name = "Overlay "; + // m_chartCompoundDataType + m_name = "Overlay " + AString::number(overlayIndex + 1); m_enabled = true; m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; - m_matrixViewingType = MatrixViewingTypeEnum::MATRIX_VIEW_FULL; - m_colorBar = new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL); + m_colorBar = std::unique_ptr(new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL)); m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); m_selectedMapFile = NULL; m_selectedMapIndex = -1; m_allMapsSelectedFlag = false; - m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_enabled", &m_enabled); m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); - m_sceneAssistant->add("m_matrixViewingType", - &m_matrixViewingType); - m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar); + m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar.get()); m_sceneAssistant->add("m_allMapsSelectedFlag", &m_allMapsSelectedFlag); // EventManager::get()->addEventListener(this, @@ -83,9 +84,7 @@ m_chartDataType(chartDataType) */ ChartOverlay::~ChartOverlay() { - delete m_colorBar; EventManager::get()->removeAllEventsFromListener(this); - delete m_sceneAssistant; } @@ -106,18 +105,6 @@ ChartOverlay::receiveEvent(Event* event) // } } -/** - * Set the number of this overlay. - * - * @param overlayIndex - * Index for this overlay. - */ -void -ChartOverlay::setOverlayNumber(const int32_t overlayIndex) -{ - m_name = "Overlay " + AString::number(overlayIndex + 1); -} - /** * Get a description of this object's content. * @return String describing this object's content. @@ -163,6 +150,24 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co } } +/** + * Set the compound chart type for charts displayed in this overlay. + * MUST match data type for this chart unless invalid. + * Note that overlay index zero, allows any chart type. + * + * @param chartCompoundDataType + * Type of charts for display in this overlay. + */ +void +ChartOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) +{ + if (chartCompoundDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { + CaretAssert(m_chartDataType == chartCompoundDataType.getChartDataType()); + } + m_chartCompoundDataType = chartCompoundDataType; +} + + /** * @return Enabled status for this surface overlay. */ @@ -203,7 +208,6 @@ ChartOverlay::copyData(const ChartOverlay* overlay) m_enabled = overlay->m_enabled; m_mapYokingGroup = overlay->m_mapYokingGroup; - m_matrixViewingType = overlay->m_matrixViewingType; *m_colorBar = *overlay->m_colorBar; @@ -212,21 +216,19 @@ ChartOverlay::copyData(const ChartOverlay* overlay) } /** - * Swap the data from the given overlay to this overlay. + * Swap my data with data from the given overlay. * @param overlay - * Overlay from which data is transferred. + * Overlay from which data is swapped. */ void ChartOverlay::swapData(ChartOverlay* overlay) { - ChartOverlay* swapOverlay = new ChartOverlay(m_chartDataType); - + std::unique_ptr swapOverlay = std::unique_ptr(new ChartOverlay(overlay->m_chartDataType, + overlay->m_overlayIndex)); swapOverlay->copyData(overlay); overlay->copyData(this); - copyData(swapOverlay); - - delete swapOverlay; + copyData(swapOverlay.get()); } /** @@ -256,7 +258,7 @@ ChartOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) AnnotationColorBar* ChartOverlay::getColorBar() { - return m_colorBar; + return m_colorBar.get(); } /** @@ -265,28 +267,7 @@ ChartOverlay::getColorBar() const AnnotationColorBar* ChartOverlay::getColorBar() const { - return m_colorBar; -} - -/** - * @return The matrix viewing type. - */ -MatrixViewingTypeEnum::Enum -ChartOverlay::getMatrixViewingType() const -{ - return m_matrixViewingType; -} - -/** - * Set the matrix viewing type. - * - * @param matrixViewingType - * new value. - */ -void -ChartOverlay::setMatrixViewingType(const MatrixViewingTypeEnum::Enum matrixViewingType) -{ - m_matrixViewingType = matrixViewingType; + return m_colorBar.get(); } /** @@ -342,24 +323,34 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, /* * Use only those data files that meet criteria. */ - for (std::vector::iterator iter = allDataFiles.begin(); - iter != allDataFiles.end(); - iter++) { - CaretMappableDataFile* mapFile = *iter; + for (auto mapFile : allDataFiles) { +// for (std::vector::iterator iter = allDataFiles.begin(); +// iter != allDataFiles.end(); +// iter++) { +// CaretMappableDataFile* mapFile = *iter; bool useIt = false; + + std::vector chartCompoundDataTypes; + mapFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - ChartableLineSeriesInterface* lineChartFile = dynamic_cast(mapFile); - ChartableMatrixSeriesInterface* matrixChartFile = dynamic_cast(mapFile); - if (m_overlayIndex > 0) { - if ((lineChartFile != NULL) - || (matrixChartFile != NULL)) { - useIt = true; - } - } - else { - if ((lineChartFile != NULL) - || (matrixChartFile != NULL)) { - useIt = true; + for (auto& compoundType : chartCompoundDataTypes) { + if (m_chartDataType == compoundType.getChartDataType()) { + if (m_overlayIndex == 0) { + /* + * The first overlay displays all files that match the + * enumerated chart type + */ + useIt = true; + } + else { + if (m_chartCompoundDataType == compoundType) { + /* + * If not the first overlay, the enumerated type + * and dimensions must also match + */ + useIt = true; + } + } } } diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index d905cebae..0b72d7b56 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -24,10 +24,9 @@ #include "CaretObject.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartTwoCompoundDataType.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" -#include "MatrixViewingTypeEnum.h" #include "SceneableInterface.h" @@ -40,13 +39,14 @@ namespace caret { class ChartOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlay(const ChartVersionOneDataTypeEnum::Enum chartDataType); + ChartOverlay(const ChartTwoDataTypeEnum::Enum chartDataType, + const int32_t overlayIndex); virtual ~ChartOverlay(); - AString getName() const; + void setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType); - void setOverlayNumber(const int32_t overlayIndex); + AString getName() const; virtual AString toString() const; @@ -68,10 +68,6 @@ namespace caret { const AnnotationColorBar* getColorBar() const; - MatrixViewingTypeEnum::Enum getMatrixViewingType() const; - - void setMatrixViewingType(const MatrixViewingTypeEnum::Enum matrixViewingType); - void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut); @@ -111,34 +107,36 @@ namespace caret { ChartOverlay& operator=(const ChartOverlay&); - SceneClassAssistant* m_sceneAssistant; + /** Enumerated Type of charts allowed in this overlay */ + const ChartTwoDataTypeEnum::Enum m_chartDataType; + + /** Index of this overlay (DO NOT COPY)*/ + const int32_t m_overlayIndex; + + std::unique_ptr m_sceneAssistant; - const ChartVersionOneDataTypeEnum::Enum m_chartDataType; + /** Current 'compound chart type' of charts allowed in this overlay */ + ChartTwoCompoundDataType m_chartCompoundDataType; /** Name of overlay (DO NOT COPY)*/ AString m_name; - /** Index of this overlay (DO NOT COPY)*/ - int32_t m_overlayIndex; - /** enabled status */ - mutable bool m_enabled; + mutable bool m_enabled = true; /** map yoking group */ MapYokingGroupEnum::Enum m_mapYokingGroup; - MatrixViewingTypeEnum::Enum m_matrixViewingType; - /** The color bar displayed in the graphics window */ - AnnotationColorBar* m_colorBar; + std::unique_ptr m_colorBar; /** selected mappable file */ - CaretMappableDataFile* m_selectedMapFile; + CaretMappableDataFile* m_selectedMapFile = NULL; /** selected map index */ - int32_t m_selectedMapIndex; + int32_t m_selectedMapIndex = -1; - bool m_allMapsSelectedFlag; + bool m_allMapsSelectedFlag = false; // ADD_NEW_MEMBERS_HERE diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx index 2d01eb0a0..4c82cb707 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartOverlaySet.cxx @@ -43,8 +43,15 @@ using namespace caret; /** * Constructor. + * + * @param chartDataType + * Type of charts allowed in this overlay + * @param name + * Name of the overlay set. + * @param tabIndex + * Index of tab in which this overlay set is used. */ -ChartOverlaySet::ChartOverlaySet(const ChartVersionOneDataTypeEnum::Enum chartDataType, +ChartOverlaySet::ChartOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex) : CaretObject(), @@ -59,7 +66,8 @@ m_tabIndex(tabIndex) &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - m_overlays[i] = new ChartOverlay(m_chartDataType); + m_overlays[i] = new ChartOverlay(m_chartDataType, + i); } // EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); // EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartOverlaySet.h index d1b970112..4cebafaf6 100644 --- a/src/Brain/ChartOverlaySet.h +++ b/src/Brain/ChartOverlaySet.h @@ -23,7 +23,7 @@ #include "BrainConstants.h" #include "CaretObject.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" @@ -36,7 +36,7 @@ namespace caret { class ChartOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlaySet(const ChartVersionOneDataTypeEnum::Enum chartDataType, + ChartOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex); @@ -110,7 +110,7 @@ namespace caret { ChartOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; - const ChartVersionOneDataTypeEnum::Enum m_chartDataType; + const ChartTwoDataTypeEnum::Enum m_chartDataType; const AString m_name; diff --git a/src/Brain/ChartOverlaySetArray.cxx b/src/Brain/ChartOverlaySetArray.cxx index 677e77afd..2a948ac36 100644 --- a/src/Brain/ChartOverlaySetArray.cxx +++ b/src/Brain/ChartOverlaySetArray.cxx @@ -25,10 +25,11 @@ #include "BrainConstants.h" #include "CaretAssert.h" +#include "ChartOverlaySet.h" #include "EventBrowserTabDelete.h" #include "EventManager.h" -#include "ChartOverlaySet.h" - +#include "SceneClass.h" +#include "SceneClassArray.h" using namespace caret; @@ -42,19 +43,24 @@ using namespace caret; /** * Constructor. * + * @param chartDataType + * Type of charts allowed in this overlay * @param name * Name of model using this chart overlay set. This name is displayed * if there is an attempt to yoke models with incompatible chart overlays. */ -ChartOverlaySetArray::ChartOverlaySetArray(const AString& name) +ChartOverlaySetArray::ChartOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, + const AString& name) : CaretObject(), +EventListenerInterface(), +SceneableInterface(), m_name(name) { - m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartOverlaySets[i] = new ChartOverlaySet(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, - name, - i); + m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); + for (int32_t tabIndex = 0; tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; tabIndex++) { + m_chartOverlaySets[tabIndex] = new ChartOverlaySet(chartDataType, + name, + tabIndex); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); @@ -97,17 +103,17 @@ ChartOverlaySetArray::getNumberOfChartOverlaySets() /** * Get the chart overlay set at the given index. * - * @param indx - * Index of chart overlay set. + * @param tabIndex + * Index of chart overlay tab. * @return * Overlay set at given index. */ ChartOverlaySet* -ChartOverlaySetArray::getChartOverlaySet(const int32_t indx) +ChartOverlaySetArray::getChartOverlaySet(const int32_t tabIndex) { - CaretAssertVectorIndex(m_chartOverlaySets, indx); + CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); - return m_chartOverlaySets[indx]; + return m_chartOverlaySets[tabIndex]; } /** @@ -170,3 +176,76 @@ ChartOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, destinationChartOverlaySet->copyOverlaySet(sourceChartOverlaySet); } +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartOverlaySetArray", + 1); + + const int32_t numOverlaySetsToSave = getNumberOfChartOverlaySets(); + + std::vector overlaySetVector; + for (int i = 0; i < numOverlaySetsToSave; i++) { + overlaySetVector.push_back(m_chartOverlaySets[i]->saveToScene(sceneAttributes, + "m_chartOverlaySet")); + } + + SceneClassArray* overlaySetArray = new SceneClassArray("m_chartOverlaySets", + overlaySetVector); + sceneClass->addChild(overlaySetArray); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartOverlaySetArray::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + + const SceneClassArray* overlaySetArray = sceneClass->getClassArray("m_chartOverlaySets"); + if (overlaySetArray != NULL) { + const int32_t numOverlaySets = std::min(overlaySetArray->getNumberOfArrayElements(), + (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); + for (int32_t i = 0; i < numOverlaySets; i++) { + m_chartOverlaySets[i]->restoreFromScene(sceneAttributes, + overlaySetArray->getClassAtIndex(i)); + } + } + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Brain/ChartOverlaySetArray.h b/src/Brain/ChartOverlaySetArray.h index 44bb8f3c0..5e134c25a 100644 --- a/src/Brain/ChartOverlaySetArray.h +++ b/src/Brain/ChartOverlaySetArray.h @@ -23,17 +23,18 @@ #include "CaretObject.h" - +#include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" -#include "Overlay.h" +#include "SceneableInterface.h" namespace caret { class ChartOverlaySet; - class ChartOverlaySetArray : public CaretObject, public EventListenerInterface { + class ChartOverlaySetArray : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlaySetArray(const AString& name); + ChartOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, + const AString& name); virtual ~ChartOverlaySetArray(); @@ -45,6 +46,12 @@ namespace caret { void copyChartOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); private: ChartOverlaySetArray(const ChartOverlaySetArray&); diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 98f0cbd85..ebe5083df 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -39,11 +39,14 @@ #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" +#include "ChartOverlay.h" +#include "ChartOverlaySet.h" #include "ChartOverlaySetArray.h" #include "ChartingVersionEnum.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGetAll.h" +#include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "ModelChart.h" @@ -71,13 +74,21 @@ ModelChart::ModelChart(Brain* brain) Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); - m_chartOverlaySetArray = new ChartOverlaySetArray("Chart View"); + m_histogramChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, + "Histogram Chart Overlays")); + m_matrixChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + "Matrix Chart Overlays")); + m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + "Line Series Chart Overlays")); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); } + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_histogramChartOverlaySetArray", "ChartOverlaySetArray", m_histogramChartOverlaySetArray.get()); initializeCharts(); @@ -90,7 +101,6 @@ ModelChart::ModelChart(Brain* brain) */ ModelChart::~ModelChart() { - delete m_chartOverlaySetArray; delete m_overlaySetArray; EventManager::get()->removeAllEventsFromListener(this); @@ -109,7 +119,8 @@ void ModelChart::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectedChartDataType[i] = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_selectedChartOneDataType[i] = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_selectedChartTwoDataType[i] = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; m_chartModelDataSeries[i] = new ChartModelDataSeries(); m_chartModelDataSeries[i]->getLeftAxis()->setText("Value"); @@ -764,7 +775,7 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr validChartDataIDs); sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", - m_selectedChartDataType, + m_selectedChartOneDataType, tabIndices); /* @@ -857,7 +868,7 @@ ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttrib sceneClass); sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", - m_selectedChartDataType); + m_selectedChartOneDataType); /* * Restore matrix chart models from scene. @@ -914,7 +925,7 @@ ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttrib sceneClass); sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", - m_selectedChartDataType); + m_selectedChartOneDataType); /* * Restore matrix chart models from scene. @@ -980,7 +991,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, const int32_t tabIndex = *tabIter; ChartModel* chartModel = NULL; - switch (getSelectedChartDataType(tabIndex)) { + switch (getSelectedChartOneDataType(tabIndex)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: @@ -1607,7 +1618,7 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const { ChartModel* chartModel = NULL; - switch (getSelectedChartDataType(tabIndex)) { + switch (getSelectedChartOneDataType(tabIndex)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: @@ -1693,7 +1704,7 @@ ModelChart::copyTabContent(const int32_t sourceTabIndex, m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); - m_selectedChartDataType[destinationTabIndex] = m_selectedChartDataType[sourceTabIndex]; + m_selectedChartOneDataType[destinationTabIndex] = m_selectedChartOneDataType[sourceTabIndex]; *m_chartModelDataSeries[destinationTabIndex] = *m_chartModelDataSeries[sourceTabIndex]; *m_chartModelFrequencySeries[destinationTabIndex] = *m_chartModelFrequencySeries[sourceTabIndex]; *m_chartModelTimeSeries[destinationTabIndex] = *m_chartModelTimeSeries[sourceTabIndex]; @@ -1710,13 +1721,13 @@ ModelChart::copyTabContent(const int32_t sourceTabIndex, * Type of data for chart. */ void -ModelChart::setSelectedChartDataType(const int32_t tabIndex, +ModelChart::setSelectedChartOneDataType(const int32_t tabIndex, const ChartVersionOneDataTypeEnum::Enum dataType) { - CaretAssertArrayIndex(m_selectedChartDataType, + CaretAssertArrayIndex(m_selectedChartOneDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - m_selectedChartDataType[tabIndex] = dataType; + m_selectedChartOneDataType[tabIndex] = dataType; } /** @@ -1726,7 +1737,7 @@ ModelChart::setSelectedChartDataType(const int32_t tabIndex, * Output containing valid chart data types. */ void -ModelChart::getValidChartDataTypes(std::vector& validChartDataTypesOut) const +ModelChart::getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); @@ -1868,18 +1879,18 @@ ModelChart::getValidChartDataTypes(std::vector validChartDataTypes; - getValidChartDataTypes(validChartDataTypes); + getValidChartOneDataTypes(validChartDataTypes); if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartDataType) == validChartDataTypes.end()) { @@ -1965,9 +1976,197 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const /* * Selected type may have changed due to loaded files changing */ - m_selectedChartDataType[tabIndex] = chartDataType; + m_selectedChartOneDataType[tabIndex] = chartDataType; + + return chartDataType; +} + +/** + * Set the type of chart selected in the given tab. + * + * @param tabIndex + * Index of tab. + * @param dataType + * Type of data for chart. + */ +void +ModelChart::setSelectedChartDataType(const int32_t tabIndex, + const ChartTwoDataTypeEnum::Enum dataType) +{ + CaretAssertArrayIndex(m_selectedChartTwoDataType, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + m_selectedChartTwoDataType[tabIndex] = dataType; +} + +/** + * Get the valid chart data types based upon the currently loaded files. + * + * @param validChartDataTypesOut + * Output containing valid chart data types. + */ +void +ModelChart::getValidChartDataTypes(std::vector& validChartDataTypesOut) const +{ + validChartDataTypesOut.clear(); + + /** + * Get the data files. + */ + std::vector allDataFiles; + EventCaretMappableDataFilesGet eventGetMapDataFiles; + EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); + eventGetMapDataFiles.getAllFiles(allDataFiles); + + std::set chartTypeSet; + + for (auto mapFile : allDataFiles) { + std::vector fileChartTypes; + mapFile->getSupportedChartDataTypes(fileChartTypes); + + chartTypeSet.insert(fileChartTypes.begin(), + fileChartTypes.end()); + } + + validChartDataTypesOut.insert(validChartDataTypesOut.end(), + chartTypeSet.begin(), + chartTypeSet.end()); +} + +/** + * Get the type of chart selected in the given tab. + * + * @param tabIndex + * Index of tab. + * @return + * Chart type in the given tab. + */ +ChartTwoDataTypeEnum::Enum +ModelChart::getSelectedChartDataType(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_selectedChartDataType, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + ChartTwoDataTypeEnum::Enum chartDataType = m_selectedChartTwoDataType[tabIndex]; + + std::vector validChartDataTypes; + getValidChartDataTypes(validChartDataTypes); + + /* + * Test if selected chart type is still valid + */ + if (std::find(validChartDataTypes.begin(), + validChartDataTypes.end(), + chartDataType) == validChartDataTypes.end()) { + chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + } + + /* + * Find a valid chart type? + */ + if (chartDataType == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if ( ! validChartDataTypes.empty()) { + CaretAssertVectorIndex(validChartDataTypes, 0); + chartDataType = validChartDataTypes[0]; + } + } + m_selectedChartTwoDataType[tabIndex] = chartDataType; return chartDataType; + +// /* +// * Verify that the selected chart data type is valid. +// */ +// std::vector validChartDataTypes; +// getValidChartOneDataTypes(validChartDataTypes); +// if (std::find(validChartDataTypes.begin(), +// validChartDataTypes.end(), +// chartDataType) == validChartDataTypes.end()) { +// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; +// } +// +// /* +// * If selected chart data type is invalid, find a valid chart type, +// * preferably one that contains data. +// */ +// if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// if ( ! validChartDataTypes.empty()) { +// /* +// * Will become the the first valid chart data type that contains +// * data (if there is one) +// */ +// ChartVersionOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; +// +// /* +// * Loop through all chart types (some or all valid charts +// * types may not contain data until the user commands loading of data) +// */ +// std::vector allChartDataTypes; +// ChartVersionOneDataTypeEnum::getAllEnums(allChartDataTypes); +// for (std::vector::iterator iter = allChartDataTypes.begin(); +// iter != allChartDataTypes.end(); +// iter++) { +// const ChartVersionOneDataTypeEnum::Enum cdt = *iter; +// if (std::find(validChartDataTypes.begin(), +// validChartDataTypes.end(), +// cdt) != validChartDataTypes.end()) { +// if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataType = cdt; +// } +// +// switch (cdt) { +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; +// } +// break; +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; +// } +// break; +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { +// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; +// } +// } +// break; +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { +// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; +// } +// } +// break; +// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { +// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; +// } +// } +// break; +// } +// } +// } +// +// if (chartDataTypeWithValidData != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataType = chartDataTypeWithValidData; +// } +// else if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataType = validChartDataTypes[0]; +// } +// } +// } +// +// /* +// * Selected type may have changed due to loaded files changing +// */ +// m_selectedChartDataType[tabIndex] = chartDataType; +// +// return chartDataType; } /** @@ -2170,22 +2369,19 @@ ModelChart::getChartOverlaySet(const int tabIndex) ChartOverlaySet* chartOverlaySet = NULL; switch (getSelectedChartDataType(tabIndex)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + chartOverlaySet = m_histogramChartOverlaySetArray->getChartOverlaySet(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartOverlaySet(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + chartOverlaySet = m_matrixChartOverlaySetArray->getChartOverlaySet(tabIndex); break; } - - chartOverlaySet = m_chartOverlaySetArray->getChartOverlaySet(tabIndex); - + return chartOverlaySet; } diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 63254614d..3dc8b0ebe 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -28,6 +28,7 @@ #include #include +#include "ChartTwoDataTypeEnum.h" #include "ChartVersionOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" @@ -94,13 +95,20 @@ namespace caret { virtual void receiveEvent(Event* event); - void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; + void getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const; - ChartVersionOneDataTypeEnum::Enum getSelectedChartDataType(const int32_t tabIndex) const; + ChartVersionOneDataTypeEnum::Enum getSelectedChartOneDataType(const int32_t tabIndex) const; - void setSelectedChartDataType(const int32_t tabIndex, + void setSelectedChartOneDataType(const int32_t tabIndex, const ChartVersionOneDataTypeEnum::Enum dataType); + void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; + + ChartTwoDataTypeEnum::Enum getSelectedChartDataType(const int32_t tabIndex) const; + + void setSelectedChartDataType(const int32_t tabIndex, + const ChartTwoDataTypeEnum::Enum dataType); + ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex); const ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex) const; @@ -178,9 +186,18 @@ namespace caret { /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; - ChartOverlaySetArray* m_chartOverlaySetArray; + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_histogramChartOverlaySetArray; + + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_lineSeriesChartOverlaySetArray; + + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_matrixChartOverlaySetArray; + + mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - mutable ChartVersionOneDataTypeEnum::Enum m_selectedChartDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + mutable ChartVersionOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ ChartModelDataSeries* m_chartModelDataSeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; @@ -206,7 +223,7 @@ namespace caret { CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - SceneClassAssistant* m_sceneAssistant; + std::unique_ptr m_sceneAssistant; }; } // namespace diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 3730296ae..0205af6f0 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -38,6 +38,13 @@ ChartSelectionModeEnum.h ChartVersionOneDataTypeEnum.h ChartingVersionEnum.h +ChartTwoCompoundDataType.h +ChartTwoData.h +ChartTwoDataCartesian.h +ChartTwoDataCartesianHistory.h +ChartTwoDataTypeEnum.h +ChartTwoMatrixViewingTypeEnum.h + ChartAxis.cxx ChartAxisCartesian.cxx ChartAxisLocationEnum.cxx @@ -60,6 +67,13 @@ ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx ChartVersionOneDataTypeEnum.cxx ChartingVersionEnum.cxx + +ChartTwoCompoundDataType.cxx +ChartTwoData.cxx +ChartTwoDataCartesian.cxx +ChartTwoDataCartesianHistory.cxx +ChartTwoDataTypeEnum.cxx +ChartTwoMatrixViewingTypeEnum.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx new file mode 100644 index 000000000..65bc31d9f --- /dev/null +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -0,0 +1,360 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ +#include "ChartTwoCompoundDataType.h" +#undef __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoCompoundDataType + * \brief Compound type for type of chart + * \ingroup Charting + * + * A compound type for matching chart types. + * Equality is determined using several pieces of information. + */ + +/** + * Constructor. It is best to use the "new instance" methods. + * + * @param chartDataType + * Chart data type. + * @param lineChartUnitsAxisX + * Line chart x-axis units. + * @param lineChartNumberOfElementsAxisX + * Line chart x-axis number of elements. + * @param matrixNumberOfRows + * Matrix number of rows. + * @param matrixNumberOfColumns + * Matrix number of columns. + */ +ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX, + const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns) +: CaretObject() +{ + initializeChartTwoCompoundDataType(); + + m_chartDataType = chartDataType; + m_lineChartUnitsAxisX = lineChartUnitsAxisX; + m_lineChartNumberOfElementsAxisX = lineChartNumberOfElementsAxisX; + m_matrixNumberOfRows = matrixNumberOfRows; + m_matrixNumberOfColumns = matrixNumberOfColumns; +} + +/** + * Default constructor of invalid instance. + */ +ChartTwoCompoundDataType::ChartTwoCompoundDataType() +{ + initializeChartTwoCompoundDataType(); +} + +/** + * Destructor. + */ +ChartTwoCompoundDataType::~ChartTwoCompoundDataType() +{ + delete m_sceneAssistant; +} + +/** + * @return A new instance for a histogram chart. + */ +ChartTwoCompoundDataType +ChartTwoCompoundDataType::newInstanceForHistogram() +{ + return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + 0, + 0, + 0); +} + +/** + * @return A new instance for a line-series chart. + */ +ChartTwoCompoundDataType +ChartTwoCompoundDataType::newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX) +{ + return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + lineChartUnitsAxisX, + lineChartNumberOfElementsAxisX, + 0, + 0); +} + +/** + * @return A new instance for a matrix chart. + */ +ChartTwoCompoundDataType +ChartTwoCompoundDataType::newInstanceForMatrix(const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns) +{ + return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + 0, + matrixNumberOfRows, + matrixNumberOfColumns); +} + + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj) +: CaretObject(obj) +{ + initializeChartTwoCompoundDataType(); + this->copyHelperChartTwoCompoundDataType(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoCompoundDataType& +ChartTwoCompoundDataType::operator=(const ChartTwoCompoundDataType& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperChartTwoCompoundDataType(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoCompoundDataType::copyHelperChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj) +{ + m_chartDataType = obj.m_chartDataType; + m_lineChartUnitsAxisX = obj.m_lineChartUnitsAxisX; + m_lineChartNumberOfElementsAxisX = obj.m_lineChartNumberOfElementsAxisX; + m_matrixNumberOfRows = obj.m_matrixNumberOfRows; + m_matrixNumberOfColumns = obj.m_matrixNumberOfColumns; +} + +/** + * Initialize an invalid instance of this class. + */ +void +ChartTwoCompoundDataType::initializeChartTwoCompoundDataType() +{ + m_chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_lineChartUnitsAxisX = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + m_lineChartNumberOfElementsAxisX = 0; + m_matrixNumberOfRows = 0; + m_matrixNumberOfColumns = 0; + + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_chartDataType", + &m_chartDataType); + m_sceneAssistant->add("m_lineChartUnitsAxisX", + &m_lineChartUnitsAxisX); + m_sceneAssistant->add("m_lineChartNumberOfElementsAxisX", + &m_lineChartNumberOfElementsAxisX); + m_sceneAssistant->add("m_matrixNumberOfRows", + &m_matrixNumberOfRows); + m_sceneAssistant->add("m_matrixNumberOfColumns", + &m_matrixNumberOfColumns); +} + + +/** + * Equality operator. + * + * Charts must be same type. + * Line charts must be same units OR same number of elements in X-axis. + * Matrix charts must have same number of rows and columns. + * + * @param obj + * Instance compared to this for equality. + * @return + * True if this instance and 'obj' instance are considered equal. + */ +bool +ChartTwoCompoundDataType::operator==(const ChartTwoCompoundDataType& obj) const +{ + if (this == &obj) { + return true; + } + + if (m_chartDataType == obj.m_chartDataType) { + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + return true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + return true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { + if (m_lineChartUnitsAxisX == obj.m_lineChartUnitsAxisX) { + return true; + } + if (m_lineChartNumberOfElementsAxisX == obj.m_lineChartNumberOfElementsAxisX) { + return true; + } + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + if ((m_matrixNumberOfRows == obj.m_matrixNumberOfRows) + && (m_matrixNumberOfColumns == obj.m_matrixNumberOfColumns)) { + return true; + } + break; + } + } + + return false; +} + +/** + * @return Type of chart data. + */ +ChartTwoDataTypeEnum::Enum +ChartTwoCompoundDataType::getChartDataType() const +{ + return m_chartDataType; +} + +/** + * @return Line chart X-axis units. + */ +ChartAxisUnitsEnum::Enum +ChartTwoCompoundDataType::getLineChartUnitsAxisX() const +{ + return m_lineChartUnitsAxisX; +} + +/** + * @return Line chart number of element in the X-axis. + */ +int32_t +ChartTwoCompoundDataType::getLineChartNumberOfElementsAxisX() const +{ + return m_lineChartNumberOfElementsAxisX; +} + +/** + * @return Matrix number of rows. + */ +int32_t +ChartTwoCompoundDataType::getMatrixNumberOfRows() const +{ + return m_matrixNumberOfRows; +} + +/** + * @return Matrix number of columns. + */ +int32_t +ChartTwoCompoundDataType::getMatrixNumberOfColumns() const +{ + return m_matrixNumberOfColumns; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartTwoCompoundDataType::toString() const +{ + return "ChartTwoCompoundDataType"; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoCompoundDataType::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoCompoundDataType", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoCompoundDataType::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Charting/ChartTwoCompoundDataType.h b/src/Charting/ChartTwoCompoundDataType.h new file mode 100644 index 000000000..93aaaafa7 --- /dev/null +++ b/src/Charting/ChartTwoCompoundDataType.h @@ -0,0 +1,123 @@ +#ifndef __CHART_TWO_COMPOUND_DATA_TYPE_H__ +#define __CHART_TWO_COMPOUND_DATA_TYPE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" +#include "ChartAxisUnitsEnum.h" +#include "ChartTwoDataTypeEnum.h" +#include "SceneableInterface.h" + + +namespace caret { + class SceneClassAssistant; + + class ChartTwoCompoundDataType : public CaretObject, public SceneableInterface { + + public: + ChartTwoCompoundDataType(); + + ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX, + const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns); + + static ChartTwoCompoundDataType newInstanceForHistogram(); + + static ChartTwoCompoundDataType newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX); + + static ChartTwoCompoundDataType newInstanceForMatrix(const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns); + + + virtual ~ChartTwoCompoundDataType(); + + ChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj); + + ChartTwoCompoundDataType& operator=(const ChartTwoCompoundDataType& obj); + + bool operator==(const ChartTwoCompoundDataType& obj) const; + + ChartTwoDataTypeEnum::Enum getChartDataType() const; + + ChartAxisUnitsEnum::Enum getLineChartUnitsAxisX() const; + + int32_t getLineChartNumberOfElementsAxisX() const; + + int32_t getMatrixNumberOfRows() const; + + int32_t getMatrixNumberOfColumns() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj); + + void initializeChartTwoCompoundDataType(); + + SceneClassAssistant* m_sceneAssistant; + + ChartTwoDataTypeEnum::Enum m_chartDataType; + + ChartAxisUnitsEnum::Enum m_lineChartUnitsAxisX; + + int32_t m_lineChartNumberOfElementsAxisX; + + int32_t m_matrixNumberOfRows; + + int32_t m_matrixNumberOfColumns; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ + // +#endif // __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ + +} // namespace +#endif //__CHART_TWO_COMPOUND_DATA_TYPE_H__ diff --git a/src/Charting/ChartTwoData.cxx b/src/Charting/ChartTwoData.cxx new file mode 100644 index 000000000..8a29942cc --- /dev/null +++ b/src/Charting/ChartTwoData.cxx @@ -0,0 +1,332 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_DATA_DECLARE__ +#include "ChartTwoData.h" +#undef __CHART_TWO_DATA_DECLARE__ + +#include "CaretAssert.h" +#include "ChartTwoDataCartesian.h" +#include "ChartDataSource.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" +#include "SystemUtilities.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoData + * \brief Base class for chart data. + * \ingroup Charting + */ + +/** + * Constructor. + * + * @param chartDataType + * Type of chart data. + */ +ChartTwoData::ChartTwoData(const ChartTwoDataTypeEnum::Enum chartDataType) +: CaretObjectTracksModification(), +SceneableInterface(), +m_chartDataType(chartDataType) +{ + initializeMembersChartTwoData(); +} + +/** + * Destructor. + */ +ChartTwoData::~ChartTwoData() +{ + delete m_sceneAssistant; + delete m_chartDataSource; +} + +/** + * Initialize members of a new instance. + */ +void +ChartTwoData::initializeMembersChartTwoData() +{ + m_chartDataSource = new ChartDataSource(); + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_selectionStatus[i] = true; + } + m_uniqueIdentifier = SystemUtilities::createUniqueID(); + + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_chartDataSource", + "ChartDataSource", + m_chartDataSource); + m_sceneAssistant->addTabIndexedBooleanArray("m_selectionStatus", + m_selectionStatus); + m_sceneAssistant->add("m_uniqueIdentifier", + &m_uniqueIdentifier); +} + + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoData::ChartTwoData(const ChartTwoData& obj) +: CaretObjectTracksModification(obj), +SceneableInterface(obj), +m_chartDataType(obj.m_chartDataType) +{ + initializeMembersChartTwoData(); + + this->copyHelperChartTwoData(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoData& +ChartTwoData::operator=(const ChartTwoData& obj) +{ + if (this != &obj) { + CaretObjectTracksModification::operator=(obj); + this->copyHelperChartTwoData(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoData::copyHelperChartTwoData(const ChartTwoData& obj) +{ + CaretAssert(0); + m_chartDataType = obj.m_chartDataType; + *m_chartDataSource = *obj.m_chartDataSource; + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_selectionStatus[i] = obj.m_selectionStatus[i]; + } +} + +/** + * Create a new instance of a chart for the given data type. + * + * @param chartDataType + * Type of chart data. + * @return + * Pointer to new instance. + */ +ChartTwoData* +ChartTwoData::newChartTwoDataForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) +{ + ChartTwoData* chartData = NULL; + + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + CaretAssert(0); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + CaretAssert(0); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + CaretAssert(0); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + chartData = new ChartTwoDataCartesian(chartDataType, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + break; + } + + return chartData; +} + + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoData::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoData", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + saveSubClassDataToScene(sceneAttributes, + sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoData::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + restoreSubClassDataFromScene(sceneAttributes, + sceneClass); +} + + +/** + * @return The chart data type. + */ +ChartTwoDataTypeEnum::Enum +ChartTwoData::getChartDataType() const +{ + return m_chartDataType; +} + +/** + * @return The source of the chart data (const method). + */ +const ChartDataSource* +ChartTwoData::getChartDataSource() const +{ + return m_chartDataSource; +} + +/** + * @return The source of the chart data. + */ +ChartDataSource* +ChartTwoData::getChartDataSource() +{ + return m_chartDataSource; +} + +/** + * @return The selection status in the given tab + * @param tabIndex + * Index of the tab. + */ +bool +ChartTwoData::isSelected(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + return m_selectionStatus[tabIndex]; +} + +/** + * Set the selection status. + * + * @param selectionStatus + * New selection status. + */ +void +ChartTwoData::setSelected(const int32_t tabIndex, + const bool selectionStatus) +{ + CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + m_selectionStatus[tabIndex] = selectionStatus; + + /* + * When selection status is true, + * notify parent. + */ +// if (m_selectionStatus[tabIndex]) { +// if (m_parentChartModel != NULL) { +// m_parentChartModel->childChartTwoDataSelectionChanged(this); +// } +// } +} + +/** + * Copy the selection status for all tabs from the given chart data to me. + * + * @param copyFrom + * Chart data from which selection status is copied. + */ +void +ChartTwoData::copySelectionStatusForAllTabs(const ChartTwoData* copyFrom) +{ + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_selectionStatus[i] = copyFrom->m_selectionStatus[i]; + } +} + + +/** + * @return The Unique Identifier (UUID). + */ +AString +ChartTwoData::getUniqueIdentifier() const +{ + return m_uniqueIdentifier; +} + +/** + * Set the unique identifier. + * + * @param uniqueIdentifier + * The new unique identifier. + */ +void +ChartTwoData::setUniqueIdentifier(const AString& uniqueIdentifier) +{ + m_uniqueIdentifier = uniqueIdentifier; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartTwoData::toString() const +{ + return "ChartTwoData"; +} + diff --git a/src/Charting/ChartTwoData.h b/src/Charting/ChartTwoData.h new file mode 100644 index 000000000..13f2a55a6 --- /dev/null +++ b/src/Charting/ChartTwoData.h @@ -0,0 +1,143 @@ +#ifndef __CHART_TWO_DATA_H__ +#define __CHART_TWO_DATA_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "BrainConstants.h" +#include "CaretObjectTracksModification.h" +#include "ChartTwoDataTypeEnum.h" +#include "SceneableInterface.h" + + +namespace caret { + + class ChartDataSource; + class SceneClassAssistant; + + class ChartTwoData : public CaretObjectTracksModification, public SceneableInterface { + + public: + static ChartTwoData* newChartTwoDataForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType); + + virtual ~ChartTwoData(); + + /** + * At times a copy of chart data will be needed BUT it must be + * the proper subclass so copy constructor and assignment operator + * will function when this abstract, base class is used. Each + * subclass will override this method so that the returned class + * is of the proper type. + * + * @return Copy of this instance that is the actual subclass. + */ + virtual ChartTwoData* clone() const = 0; + + ChartTwoDataTypeEnum::Enum getChartDataType() const; + + const ChartDataSource* getChartDataSource() const; + + ChartDataSource* getChartDataSource(); + + bool isSelected(const int32_t tabIndex) const; + + void setSelected(const int32_t tabIndex, + const bool selectionStatus); + + void clearSelected(); + + AString getUniqueIdentifier() const; + + void setUniqueIdentifier(const AString& uniqueIdentifier); + + void copySelectionStatusForAllTabs(const ChartTwoData* copyFrom); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + protected: + ChartTwoData(const ChartTwoDataTypeEnum::Enum chartDataType); + + ChartTwoData(const ChartTwoData& obj); + + ChartTwoData& operator=(const ChartTwoData& obj); + + /** + * Save subclass data to the scene. sceneClass + * will be valid and any scene data should be added to it. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. + */ + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) = 0; + + /** + * Restore file data from the scene. The scene class + * will be valid and any scene data may be obtained from it. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) = 0; + + private: + void initializeMembersChartTwoData(); + + void copyHelperChartTwoData(const ChartTwoData& obj); + + SceneClassAssistant* m_sceneAssistant; + + ChartTwoDataTypeEnum::Enum m_chartDataType; + + ChartDataSource* m_chartDataSource; + + bool m_selectionStatus[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + AString m_uniqueIdentifier; + + // ADD_NEW_MEMBERS_HERE + }; + +#ifdef __CHART_TWO_DATA_DECLARE__ + // +#endif // __CHART_TWO_DATA_DECLARE__ + +} // namespace +#endif //__CHART_TWO_DATA_H__ diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx new file mode 100644 index 000000000..e84a5b2e3 --- /dev/null +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -0,0 +1,492 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_DATA_CARTESIAN_DECLARE__ +#include "ChartTwoDataCartesian.h" +#undef __CHART_TWO_DATA_CARTESIAN_DECLARE__ + +#include + +#include + +#include "CaretAssert.h" +#include "ChartPoint.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoDataCartesian + * \brief Chart cartesian data. + * \ingroup Charting + */ + +/** + * Constructor. + * + * @param chartDataType + * Type of chart data model. + * @param dataAxisUnitsX + * Data units for X-axis. + * @param dataAxisUnitsY + * Data units for Y-axis. + */ +ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, + const ChartAxisUnitsEnum::Enum dataAxisUnitsX, + const ChartAxisUnitsEnum::Enum dataAxisUnitsY) +: ChartTwoData(chartDataType), +m_dataAxisUnitsX(dataAxisUnitsX), +m_dataAxisUnitsY(dataAxisUnitsY) +{ + initializeMembersChartTwoDataCartesian(); +} + +/** + * Destructor. + */ +ChartTwoDataCartesian::~ChartTwoDataCartesian() +{ + removeAllPoints(); + + delete m_sceneAssistant; +} + +/** + * Initialize members of a new instance. + */ +void +ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() +{ + m_boundsValid = false; + m_color = CaretColorEnum::RED; + m_timeStartInSecondsAxisX = 0.0; + m_timeStepInSecondsAxisX = 1.0; + + std::vector colorEnums; + CaretColorEnum::getColorEnums(colorEnums); + const int32_t numCaretColors = static_cast(colorEnums.size()); + + bool colorFound = false; + while ( ! colorFound) { + ChartTwoDataCartesian::caretColorIndex++; + if (ChartTwoDataCartesian::caretColorIndex >= numCaretColors) { + ChartTwoDataCartesian::caretColorIndex = 0; + } + + if (colorEnums[ChartTwoDataCartesian::caretColorIndex] == CaretColorEnum::BLACK) { + /* do not use black */ + } + else if (colorEnums[ChartTwoDataCartesian::caretColorIndex] == CaretColorEnum::WHITE) { + /* do not use white */ + } + else { + m_color = colorEnums[ChartTwoDataCartesian::caretColorIndex]; + colorFound = true; + } + } + + m_sceneAssistant = new SceneClassAssistant(); + + m_sceneAssistant->add("m_dataAxisUnitsX", + &m_dataAxisUnitsX); + m_sceneAssistant->add("m_dataAxisUnitsY", + &m_dataAxisUnitsY); + m_sceneAssistant->add("m_color", + &m_color); + m_sceneAssistant->add("m_timeStartInSecondsAxisX", + &m_timeStartInSecondsAxisX); + m_sceneAssistant->add("m_timeStepInSecondsAxisX", + &m_timeStepInSecondsAxisX); +} + +/** + * Remove all points in the model. + */ +void +ChartTwoDataCartesian::removeAllPoints() +{ + for (std::vector::const_iterator iter = m_points.begin(); + iter != m_points.end(); + iter++) { + delete *iter; + } + m_points.clear(); + + m_boundsValid = false; +} + +/** + * At times a copy of chart data will be needed BUT it must be + * the proper subclass so copy constructor and assignment operator + * will no function when this abstract, base class is used. Each + * subclass will override this method so that the returned class + * is of the proper type. + * + * @return Copy of this instance that is the actual subclass. + */ +ChartTwoData* +ChartTwoDataCartesian::clone() const +{ + ChartTwoDataCartesian* cloneCopy = new ChartTwoDataCartesian(*this); + return cloneCopy; +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataCartesian& obj) +: ChartTwoData(obj), +m_dataAxisUnitsX(obj.m_dataAxisUnitsX), +m_dataAxisUnitsY(obj.m_dataAxisUnitsY) +{ + initializeMembersChartTwoDataCartesian(); + this->copyHelperChartTwoDataCartesian(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoDataCartesian& +ChartTwoDataCartesian::operator=(const ChartTwoDataCartesian& obj) +{ + if (this != &obj) { + ChartTwoData::operator=(obj); + this->copyHelperChartTwoDataCartesian(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj) +{ + CaretAssert(0); + m_dataAxisUnitsX = obj.m_dataAxisUnitsX; + m_dataAxisUnitsY = obj.m_dataAxisUnitsY; + + removeAllPoints(); + + for (std::vector::const_iterator iter = obj.m_points.begin(); + iter != obj.m_points.end(); + iter++) { + const ChartPoint* cp = *iter; + m_points.push_back(new ChartPoint(*cp)); + } + + m_boundsValid = false; + m_color = obj.m_color; + m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; + m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; +} + +/** + * Add a point. + * + * @param x + * X-coordinate. + * @param y + * Y-coordinate. + */ +void +ChartTwoDataCartesian::addPoint(const float x, + const float y) +{ + m_points.push_back(new ChartPoint(x, y)); + m_boundsValid = false; +} + +/** + * @return Number of points. + */ +int32_t +ChartTwoDataCartesian::getNumberOfPoints() const +{ + return m_points.size(); +} + +/** + * Get the point at the given index. + * + * @param pointIndex + * Index of point. + * @return + * Point at the given index. + */ +const ChartPoint* +ChartTwoDataCartesian::getPointAtIndex(const int32_t pointIndex) const +{ + CaretAssertVectorIndex(m_points, pointIndex); + return m_points[pointIndex]; +} + +/** + * Get the bounds of all of the points. + * + * @param xMinimumOut + * Minimum X-coordinate of all points. + * @param xMaximumOut + * Maximum X-coordinate of all points. + * @param yMinimumOut + * Minimum Y-coordinate of all points. + * @param yMaximumOut + * Maximum Y-coordinate of all points. + */ +void +ChartTwoDataCartesian::getBounds(float& xMinimumOut, + float& xMaximumOut, + float& yMinimumOut, + float& yMaximumOut) const +{ + if (! m_boundsValid) { + float xMin = 0.0; + float xMax = 0.0; + float yMin = 0.0; + float yMax = 0.0; + float zMin = 0.0; + float zMax = 0.0; + const int32_t numPoints = getNumberOfPoints(); + if (numPoints > 0) { + xMin = std::numeric_limits::max(); + xMax = -std::numeric_limits::max(); + yMin = std::numeric_limits::max(); + yMax = -std::numeric_limits::max(); + for (int32_t i = 0; i < numPoints; i++) { + const float* xy = getPointAtIndex(i)->getXY(); + const float x = xy[0]; + const float y = xy[1]; + if (x < xMin) xMin = x; + if (x > xMax) xMax = x; + if (y < yMin) yMin = y; + if (y > yMax) yMax = y; + } + + m_boundsValid = true; + } + + m_bounds[0] = xMin; + m_bounds[1] = xMax; + m_bounds[2] = yMin; + m_bounds[3] = yMax; + m_bounds[4] = zMin; + m_bounds[5] = zMax; + } + + xMinimumOut = m_bounds[0]; + xMaximumOut = m_bounds[1]; + yMinimumOut = m_bounds[2]; + yMaximumOut = m_bounds[3]; +} + +/** + * @return The time start in seconds for the X-Axis (Valid when + * the X-axis is time) + */ +float +ChartTwoDataCartesian::getTimeStartInSecondsAxisX() const +{ + return m_timeStartInSecondsAxisX; +} + +/** + * Set the time start in seconds for the X-Axis (Valid when + * the X-axis is time) + * + * @param timeStartInSecondsAxisX + * Time of first point in the X-axis. + */ +void +ChartTwoDataCartesian::setTimeStartInSecondsAxisX(const float timeStartInSecondsAxisX) +{ + m_timeStartInSecondsAxisX = timeStartInSecondsAxisX; +} + +/** + * @return The time step in seconds for the X-Axis (Valid when + * the X-axis is time) + */ +float +ChartTwoDataCartesian::getTimeStepInSecondsAxisX() const +{ + return m_timeStepInSecondsAxisX; +} + +/** + * Set the time step in seconds for the X-Axis (Valid when + * the X-axis is time) + * + * @param timeStepInSecondsAxisX + * Number of seconds between consecutive points in X-axis. + */ +void +ChartTwoDataCartesian::setTimeStepInSecondsAxisX(const float timeStepInSecondsAxisX) +{ + m_timeStepInSecondsAxisX = timeStepInSecondsAxisX; +} + +/** + * @return Data units for X axis + */ +ChartAxisUnitsEnum::Enum +ChartTwoDataCartesian::getDataAxisUnitsX() +{ + return m_dataAxisUnitsX; +} + +/** + * @return Data units for Y axis + */ +ChartAxisUnitsEnum::Enum +ChartTwoDataCartesian::getDataAxisUnitsY() +{ + return m_dataAxisUnitsY; +} + +/** + * @return Color for chart + */ +CaretColorEnum::Enum +ChartTwoDataCartesian::getColor() const +{ + return m_color; +} + +/** + * Set the color for the chart. + * + * @param color + * New color for chart. + */ +void +ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) +{ + m_color = color; +} + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartTwoDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + SceneClass* chartDataCartesian = new SceneClass("chartDataCartesian", + "ChartTwoDataCartesian", + 1); + + m_sceneAssistant->saveMembers(sceneAttributes, + chartDataCartesian); + + const int32_t numPoints2D = getNumberOfPoints(); + if (numPoints2D > 0) { + chartDataCartesian->addInteger("numberOfPoints2D", + numPoints2D); + + AString pointString; + pointString.reserve(numPoints2D * 2 * 10); + QTextStream textStream(&pointString, + QIODevice::WriteOnly); + + for (int32_t i = 0; i < numPoints2D; i++) { + const float* xy = m_points[i]->getXY(); + textStream << xy[0] << " " << xy[1] << " "; + } + + chartDataCartesian->addString("points2D", + pointString); + } + + sceneClass->addClass(chartDataCartesian); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartTwoDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + removeAllPoints(); + + const SceneClass* chartDataCartesian = sceneClass->getClass("chartDataCartesian"); + if (chartDataCartesian == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, chartDataCartesian); + + const int32_t numPoints2D = chartDataCartesian->getIntegerValue("numberOfPoints2D", + -1); + + if (numPoints2D > 0) { + AString pointString = chartDataCartesian->getStringValue("points2D", + ""); + if ( ! pointString.isEmpty()) { + float x, y; + QTextStream textStream(&pointString, + QIODevice::ReadOnly); + for (int32_t i = 0; i < numPoints2D; i++) { + if (textStream.atEnd()) { + sceneAttributes->addToErrorMessage("Tried to read " + + AString::number(numPoints2D) + + " but only got " + + AString::number(i)); + break; + } + + textStream >> x; + textStream >> y; + m_points.push_back(new ChartPoint(x, y)); + } + } + } +} + diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h new file mode 100644 index 000000000..c891c9a53 --- /dev/null +++ b/src/Charting/ChartTwoDataCartesian.h @@ -0,0 +1,124 @@ +#ifndef __CHART_TWO_DATA_CARTESIAN_H__ +#define __CHART_TWO_DATA_CARTESIAN_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretColorEnum.h" +#include "ChartAxisUnitsEnum.h" +#include "ChartTwoData.h" + + + +namespace caret { + + class ChartPoint; + + class ChartTwoDataCartesian : public ChartTwoData { + + public: + ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, + const ChartAxisUnitsEnum::Enum dataAxisUnitsX, + const ChartAxisUnitsEnum::Enum dataAxisUnitsY); + + virtual ~ChartTwoDataCartesian(); + + virtual ChartTwoData* clone() const; + + void addPoint(const float x, + const float y); + + int32_t getNumberOfPoints() const; + + const ChartPoint* getPointAtIndex(const int32_t pointIndex) const; + + void getBounds(float& xMinimumOut, + float& xMaximumOut, + float& yMinimumOut, + float& yMaximumOut) const; + + ChartAxisUnitsEnum::Enum getDataAxisUnitsX(); + + ChartAxisUnitsEnum::Enum getDataAxisUnitsY(); + + CaretColorEnum::Enum getColor() const; + + void setColor(const CaretColorEnum::Enum color); + + float getTimeStartInSecondsAxisX() const; + + void setTimeStartInSecondsAxisX(const float timeStart); + + float getTimeStepInSecondsAxisX() const; + + void setTimeStepInSecondsAxisX(const float timeStep); + + // ADD_NEW_METHODS_HERE + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + private: + ChartTwoDataCartesian(const ChartTwoDataCartesian& obj); + + ChartTwoDataCartesian& operator=(const ChartTwoDataCartesian& obj); + + void copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj); + + void initializeMembersChartTwoDataCartesian(); + + void removeAllPoints(); + + std::vector m_points; + + mutable float m_bounds[6]; + + mutable bool m_boundsValid; + + ChartAxisUnitsEnum::Enum m_dataAxisUnitsX; + + ChartAxisUnitsEnum::Enum m_dataAxisUnitsY; + + CaretColorEnum::Enum m_color; + + float m_timeStartInSecondsAxisX; + + float m_timeStepInSecondsAxisX; + + static int32_t caretColorIndex; + + SceneClassAssistant* m_sceneAssistant; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_DATA_CARTESIAN_DECLARE__ + int32_t ChartTwoDataCartesian::caretColorIndex = 0; +#endif // __CHART_TWO_DATA_CARTESIAN_DECLARE__ + +} // namespace +#endif //__CHART_TWO_DATA_CARTESIAN_H__ diff --git a/src/Charting/ChartTwoDataCartesianHistory.cxx b/src/Charting/ChartTwoDataCartesianHistory.cxx new file mode 100644 index 000000000..eda539cc5 --- /dev/null +++ b/src/Charting/ChartTwoDataCartesianHistory.cxx @@ -0,0 +1,374 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ +#include "ChartTwoDataCartesianHistory.h" +#undef __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ + +#include "CaretAssert.h" +#include "ChartTwoDataCartesian.h" +#include "SceneAttributes.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoDataCartesianHistory + * \brief Contains history of Cartesian Charts + * \ingroup Charting + */ + +/** + * Constructor. + */ +ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory() +: CaretObjectTracksModification() +{ + initializeInstance(); +} + +/** + * Destructor. + */ +ChartTwoDataCartesianHistory::~ChartTwoDataCartesianHistory() +{ + clearHistory(); + delete m_sceneAssistant; +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj) +: CaretObjectTracksModification(obj) +{ + initializeInstance(); + this->copyHelperChartTwoDataCartesianHistory(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoDataCartesianHistory& +ChartTwoDataCartesianHistory::operator=(const ChartTwoDataCartesianHistory& obj) +{ + if (this != &obj) { + CaretObjectTracksModification::operator=(obj); + this->copyHelperChartTwoDataCartesianHistory(obj); + } + return *this; +} + +/** + * Initialize an instance of this class. + */ +void +ChartTwoDataCartesianHistory::initializeInstance() +{ + const int32_t defaultHistoryCount = 5; + + m_sceneAssistant = new SceneClassAssistant(); + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_displayCountInTab[i] = defaultHistoryCount; + } + + m_sceneAssistant->add("m_defaultColor", + &m_defaultColor); + m_sceneAssistant->addTabIndexedIntegerArray("m_displayCountInTab", m_displayCountInTab); +} + + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoDataCartesianHistory::copyHelperChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj) +{ + clearHistory(); + + for (const auto item : m_chartHistory) { + ChartTwoData* chartData = item->clone(); + ChartTwoDataCartesian* cartData = dynamic_cast(chartData); + CaretAssert(cartData); + + addHistoryItem(cartData); + } + + m_defaultColor = obj.m_defaultColor; + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_displayCountInTab[i] = obj.m_displayCountInTab[i]; + } +} + +/** + * @return The default color. + */ +CaretColorEnum::Enum +ChartTwoDataCartesianHistory::getDefaultColor() const +{ + return m_defaultColor; +} + +/** + * Set the default color. + * + * @param defaultColor New value for default color. + */ +void +ChartTwoDataCartesianHistory::setDefaultColor(const CaretColorEnum::Enum defaultColor) +{ + if (defaultColor != m_defaultColor) { + m_defaultColor = defaultColor; + setModified(); + } +} + +/** + * @return Count of items for display in tab. + * + * @param tabIndex + * Index of tab. + */ +int32_t +ChartTwoDataCartesianHistory::getDisplayCountInTab(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_displayCountInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + return m_displayCountInTab[tabIndex]; +} + +/** + * Set count of items for display in tab. + * + * @param tabIndex + * Index of tab. + * @param count + * New value for count. + */ +void +ChartTwoDataCartesianHistory::setDisplayCountInTab(const int32_t tabIndex, + const int count) +{ + CaretAssertArrayIndex(m_displayCountInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + if (count != m_displayCountInTab[tabIndex]) { + m_displayCountInTab[tabIndex] = count; + setModified(); + } +} + +/** + * @return Count of items in history. + */ +int32_t ChartTwoDataCartesianHistory::getHistoryCount() +{ + return m_chartHistory.size(); +} + +/** + * Add a history item. This instance takes ownership of the item + * and will delete it. Default color is assigned to item. + * + * @param historyItem + * Added to history. + */ +void +ChartTwoDataCartesianHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) +{ + CaretAssert(historyItem); + historyItem->setColor(m_defaultColor); + m_chartHistory.push_front(historyItem); +} + +/** + * @return History item at the given index. + * + * @param index + * Index of the item. + */ +ChartTwoDataCartesian* +ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) +{ + CaretAssertVectorIndex(m_chartHistory, index); + return m_chartHistory[index]; +} + +/** + * @return History item at the given index (const method). + * + * @param index + * Index of the item. + */ +const ChartTwoDataCartesian* +ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) const +{ + CaretAssertVectorIndex(m_chartHistory, index); + return m_chartHistory[index]; +} + +/** + * @return Clear the history. + */ +void +ChartTwoDataCartesianHistory::clearHistory() +{ + for (auto item : m_chartHistory) { + delete item; + } + m_chartHistory.clear(); +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartTwoDataCartesianHistory::toString() const +{ + return "ChartTwoDataCartesianHistory"; +} + +/** + * @return Is this instance modified? + */ +bool +ChartTwoDataCartesianHistory::isModified() const +{ + if (CaretObjectTracksModification::isModified()) { + return true; + } + + for (const auto item : m_chartHistory) { + if (item->isModified()) { + return true; + } + } + + return false; +} + +/** + * Clear modified status for this instance. + */ +void +ChartTwoDataCartesianHistory::clearModified() +{ + for (const auto item : m_chartHistory) { + item->clearModified(); + } +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoDataCartesianHistory::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoDataCartesianHistory", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + /* + * Save chart history + */ + SceneObjectMapIntegerKey* chartHistoryMap = new SceneObjectMapIntegerKey("m_chartHistoryMap", + SceneObjectDataTypeEnum::SCENE_CLASS); + const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); + for (auto tabIndex : tabIndices) { + CaretAssertVectorIndex(m_chartHistory, tabIndex); + chartHistoryMap->addClass(tabIndex, + m_chartHistory[tabIndex]->saveToScene(sceneAttributes, + "m_chartHistory")); + } + sceneClass->addChild(chartHistoryMap); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoDataCartesianHistory::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + clearHistory(); + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + /* + * Restore chart matrix properties + */ + const SceneObjectMapIntegerKey* chartHistoryMap = sceneClass->getMapIntegerKey("m_chartHistoryMap"); + if (chartHistoryMap != NULL) { + const std::vector tabIndices = chartHistoryMap->getKeys(); + for (auto tabIndex : tabIndices) { + const SceneClass* sceneClass = chartHistoryMap->classValue(tabIndex); + CaretAssertVectorIndex(m_chartHistory, tabIndex); + m_chartHistory[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); + } + } + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Charting/ChartTwoDataCartesianHistory.h b/src/Charting/ChartTwoDataCartesianHistory.h new file mode 100644 index 000000000..83dfb863b --- /dev/null +++ b/src/Charting/ChartTwoDataCartesianHistory.h @@ -0,0 +1,116 @@ +#ifndef __CHART_TWO_DATA_CARTESIAN_HISTORY_H__ +#define __CHART_TWO_DATA_CARTESIAN_HISTORY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "BrainConstants.h" +#include "CaretColorEnum.h" +#include "CaretObjectTracksModification.h" + +#include "SceneableInterface.h" + + +namespace caret { + class ChartTwoDataCartesian; + class SceneClassAssistant; + + class ChartTwoDataCartesianHistory : public CaretObjectTracksModification, public SceneableInterface { + + public: + ChartTwoDataCartesianHistory(); + + virtual ~ChartTwoDataCartesianHistory(); + + ChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj); + + ChartTwoDataCartesianHistory& operator=(const ChartTwoDataCartesianHistory& obj); + + CaretColorEnum::Enum getDefaultColor() const; + + void setDefaultColor(const CaretColorEnum::Enum defaultColor); + + int32_t getDisplayCountInTab(const int32_t tabIndex) const; + + void setDisplayCountInTab(const int32_t tabIndex, + const int count); + + int32_t getHistoryCount(); + + void addHistoryItem(ChartTwoDataCartesian* historyItem); + + ChartTwoDataCartesian* getHistoryItem(const int32_t index); + + const ChartTwoDataCartesian* getHistoryItem(const int32_t index) const; + + void clearHistory(); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const override; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) override; + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + virtual bool isModified() const override; + + virtual void clearModified() override; + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj); + + void initializeInstance(); + + SceneClassAssistant* m_sceneAssistant = NULL; + + std::deque m_chartHistory; + + CaretColorEnum::Enum m_defaultColor = CaretColorEnum::BLUE; + + int32_t m_displayCountInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ + // +#endif // __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ + +} // namespace +#endif //__CHART_TWO_DATA_CARTESIAN_HISTORY_H__ diff --git a/src/Charting/ChartTwoDataTypeEnum.cxx b/src/Charting/ChartTwoDataTypeEnum.cxx new file mode 100644 index 000000000..9bac88d38 --- /dev/null +++ b/src/Charting/ChartTwoDataTypeEnum.cxx @@ -0,0 +1,384 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ +#include "ChartTwoDataTypeEnum.h" +#undef __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoDataTypeEnum + * \brief ChartDrawingType + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartDrawingTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartDrawingTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoDataTypeEnum.h" + * + * Instatiate: + * m_chartDrawingTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartDrawingTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartDrawingTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartDrawingTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartDrawingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoDataTypeEnum::Enum VARIABLE = m_chartDrawingTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoDataTypeEnum::ChartTwoDataTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoDataTypeEnum::~ChartTwoDataTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoDataTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_INVALID, + "CHART_DATA_TYPE_INVALID", + "Invalid")); + + enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_HISTOGRAM, + "CHART_DATA_TYPE_HISTOGRAM", + "Histogram")); + + enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_LINE_SERIES, + "CHART_DATA_TYPE_LINE_SERIES", + "Line Series")); + + enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_MATRIX, + "CHART_DATA_TYPE_MATRIX", + "Matrix")); + + /* If this fails (chart types change), update value for NUMBER_OF_CHART_DATA_TYPES */ + CaretAssertMessage(enumData.size() == NUMBER_OF_CHART_DATA_TYPES, + "Have chart types changed?"); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoDataTypeEnum* +ChartTwoDataTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoDataTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoDataTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoDataTypeEnum::Enum +ChartTwoDataTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoDataTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoDataTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoDataTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoDataTypeEnum::Enum +ChartTwoDataTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoDataTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoDataTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoDataTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoDataTypeEnum::Enum +ChartTwoDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoDataTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoDataTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoDataTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoDataTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoDataTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoDataTypeEnum.h b/src/Charting/ChartTwoDataTypeEnum.h new file mode 100644 index 000000000..af3b482a5 --- /dev/null +++ b/src/Charting/ChartTwoDataTypeEnum.h @@ -0,0 +1,110 @@ +#ifndef __CHART_TWO_DATA_TYPE_ENUM_H__ +#define __CHART_TWO_DATA_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoDataTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Invalid */ + CHART_DATA_TYPE_INVALID, + /** Histogram */ + CHART_DATA_TYPE_HISTOGRAM, + /** Line Series */ + CHART_DATA_TYPE_LINE_SERIES, + /** Matrix */ + CHART_DATA_TYPE_MATRIX + }; + + + ~ChartTwoDataTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + + static const int32_t NUMBER_OF_CHART_DATA_TYPES = 4; + +private: + ChartTwoDataTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoDataTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ +std::vector ChartTwoDataTypeEnum::enumData; +bool ChartTwoDataTypeEnum::initializedFlag = false; +int32_t ChartTwoDataTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_DATA_TYPE_ENUM_H__ diff --git a/src/Brain/MatrixViewingTypeEnum.cxx b/src/Charting/ChartTwoMatrixViewingTypeEnum.cxx similarity index 67% rename from src/Brain/MatrixViewingTypeEnum.cxx rename to src/Charting/ChartTwoMatrixViewingTypeEnum.cxx index ef03cf01f..24f0a5944 100644 --- a/src/Brain/MatrixViewingTypeEnum.cxx +++ b/src/Charting/ChartTwoMatrixViewingTypeEnum.cxx @@ -20,9 +20,10 @@ /*LICENSE_END*/ #include -#define __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ -#include "MatrixViewingTypeEnum.h" -#undef __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ + +#define __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +#include "ChartTwoMatrixViewingTypeEnum.h" +#undef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,10 +31,8 @@ using namespace caret; /** - * \class caret::MatrixViewingTypeEnum - * \brief - * - * + * \class caret::ChartTwoMatrixViewingTypeEnum + * \brief Types of viewing for matrix. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -51,21 +50,21 @@ using namespace caret; * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "MatrixViewingTypeEnum.h" + * #include "ChartTwoMatrixViewingTypeEnum.h" * * Instatiate: * m_matrixViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_matrixViewingTypeEnumComboBox->setup(); + * m_matrixViewingTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_matrixViewingTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(matrixViewingTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const MatrixViewingTypeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); + * const ChartTwoMatrixViewingTypeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); * */ @@ -80,7 +79,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -MatrixViewingTypeEnum::MatrixViewingTypeEnum(const Enum enumValue, +ChartTwoMatrixViewingTypeEnum::ChartTwoMatrixViewingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -93,7 +92,7 @@ MatrixViewingTypeEnum::MatrixViewingTypeEnum(const Enum enumValue, /** * Destructor. */ -MatrixViewingTypeEnum::~MatrixViewingTypeEnum() +ChartTwoMatrixViewingTypeEnum::~ChartTwoMatrixViewingTypeEnum() { } @@ -101,26 +100,26 @@ MatrixViewingTypeEnum::~MatrixViewingTypeEnum() * Initialize the enumerated metadata. */ void -MatrixViewingTypeEnum::initialize() +ChartTwoMatrixViewingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_FULL, + enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_FULL, "MATRIX_VIEW_FULL", "Matrix View Full")); - enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, "MATRIX_VIEW_FULL_NO_DIAGONAL", "Matrix View Full No Diagonal")); - enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, "MATRIX_VIEW_LOWER_NO_DIAGONAL", "Matrix View Lower No Diagonal")); - enumData.push_back(MatrixViewingTypeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, "MATRIX_VIEW_UPPER_NO_DIAGONAL", "Matrix View Upper No Diagonal")); } @@ -132,14 +131,14 @@ MatrixViewingTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const MatrixViewingTypeEnum* -MatrixViewingTypeEnum::findData(const Enum enumValue) +const ChartTwoMatrixViewingTypeEnum* +ChartTwoMatrixViewingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const MatrixViewingTypeEnum* d = &enumData[i]; + const ChartTwoMatrixViewingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -156,10 +155,10 @@ MatrixViewingTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -MatrixViewingTypeEnum::toName(Enum enumValue) { +ChartTwoMatrixViewingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -173,18 +172,18 @@ MatrixViewingTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -MatrixViewingTypeEnum::Enum -MatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) +ChartTwoMatrixViewingTypeEnum::Enum +ChartTwoMatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const MatrixViewingTypeEnum& d = *iter; + const ChartTwoMatrixViewingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -196,7 +195,7 @@ MatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); } return enumValue; } @@ -209,10 +208,10 @@ MatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) * String representing enumerated value. */ AString -MatrixViewingTypeEnum::toGuiName(Enum enumValue) { +ChartTwoMatrixViewingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -226,18 +225,18 @@ MatrixViewingTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -MatrixViewingTypeEnum::Enum -MatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +ChartTwoMatrixViewingTypeEnum::Enum +ChartTwoMatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const MatrixViewingTypeEnum& d = *iter; + const ChartTwoMatrixViewingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -249,7 +248,7 @@ MatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); } return enumValue; } @@ -261,10 +260,10 @@ MatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) * Integer code for data type. */ int32_t -MatrixViewingTypeEnum::toIntegerCode(Enum enumValue) +ChartTwoMatrixViewingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const MatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -279,18 +278,18 @@ MatrixViewingTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -MatrixViewingTypeEnum::Enum -MatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +ChartTwoMatrixViewingTypeEnum::Enum +ChartTwoMatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = MatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const MatrixViewingTypeEnum& enumInstance = *iter; + const ChartTwoMatrixViewingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -302,7 +301,7 @@ MatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidO *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); } return enumValue; } @@ -315,13 +314,13 @@ MatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidO * A vector that is OUTPUT containing all of the enumerated values. */ void -MatrixViewingTypeEnum::getAllEnums(std::vector& allEnums) +ChartTwoMatrixViewingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -337,16 +336,16 @@ MatrixViewingTypeEnum::getAllEnums(std::vector& all * If true, the names are sorted in alphabetical order. */ void -MatrixViewingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +ChartTwoMatrixViewingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(MatrixViewingTypeEnum::toName(iter->enumValue)); + allNames.push_back(ChartTwoMatrixViewingTypeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -363,16 +362,16 @@ MatrixViewingTypeEnum::getAllNames(std::vector& allNames, const bool is * If true, the names are sorted in alphabetical order. */ void -MatrixViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +ChartTwoMatrixViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(MatrixViewingTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(ChartTwoMatrixViewingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Brain/MatrixViewingTypeEnum.h b/src/Charting/ChartTwoMatrixViewingTypeEnum.h similarity index 79% rename from src/Brain/MatrixViewingTypeEnum.h rename to src/Charting/ChartTwoMatrixViewingTypeEnum.h index df54d4c7c..34a4a90c4 100644 --- a/src/Brain/MatrixViewingTypeEnum.h +++ b/src/Charting/ChartTwoMatrixViewingTypeEnum.h @@ -1,5 +1,5 @@ -#ifndef __MATRIX_VIEWING_TYPE_ENUM_H__ -#define __MATRIX_VIEWING_TYPE_ENUM_H__ +#ifndef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ +#define __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class MatrixViewingTypeEnum { +class ChartTwoMatrixViewingTypeEnum { public: /** @@ -45,7 +45,7 @@ public: MATRIX_VIEW_UPPER_NO_DIAGONAL }; - ~MatrixViewingTypeEnum(); + ~ChartTwoMatrixViewingTypeEnum(); static AString toName(Enum enumValue); @@ -66,14 +66,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - MatrixViewingTypeEnum(const Enum enumValue, + ChartTwoMatrixViewingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const MatrixViewingTypeEnum* findData(const Enum enumValue); + static const ChartTwoMatrixViewingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -97,11 +97,11 @@ private: AString guiName; }; -#ifdef __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ -std::vector MatrixViewingTypeEnum::enumData; -bool MatrixViewingTypeEnum::initializedFlag = false; -int32_t MatrixViewingTypeEnum::integerCodeCounter = 0; -#endif // __MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +#ifdef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +std::vector ChartTwoMatrixViewingTypeEnum::enumData; +bool ChartTwoMatrixViewingTypeEnum::initializedFlag = false; +int32_t ChartTwoMatrixViewingTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ } // namespace -#endif //__MATRIX_VIEWING_TYPE_ENUM_H__ +#endif //__CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 6547df948..5be32a6e7 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -44,6 +44,7 @@ ChartableLineSeriesRowColumnInterface.h ChartableMatrixInterface.h ChartableMatrixParcelInterface.h ChartableMatrixSeriesInterface.h +ChartableTwoInterface.h CiftiBrainordinateDataSeriesFile.h CiftiBrainordinateLabelFile.h CiftiBrainordinateScalarFile.h @@ -161,6 +162,7 @@ CaretSparseFile.cxx CaretVolumeExtension.cxx ChartableLineSeriesInterface.cxx ChartableMatrixInterface.cxx +ChartableTwoInterface.cxx CiftiBrainordinateDataSeriesFile.cxx CiftiBrainordinateLabelFile.cxx CiftiBrainordinateScalarFile.cxx diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index d9827d5cb..19bcf23bd 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -27,6 +27,7 @@ #include "CaretLogger.h" #include "ChartDataCartesian.h" +#include "ChartTwoDataCartesianHistory.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" @@ -53,7 +54,7 @@ using namespace caret; CaretMappableDataFile::CaretMappableDataFile(const DataFileTypeEnum::Enum dataFileType) : CaretDataFile(dataFileType) { - m_labelDrawingProperties.grabNew(new LabelDrawingProperties()); + initializeCaretMappableDataFileInstance(); } /** @@ -72,11 +73,13 @@ CaretMappableDataFile::~CaretMappableDataFile() CaretMappableDataFile::CaretMappableDataFile(const CaretMappableDataFile& cmdf) : CaretDataFile(cmdf) { + initializeCaretMappableDataFileInstance(); + this->copyCaretMappableDataFile(cmdf); } /** - * Constructor. + * Assignment operator. * @param cmdf * Instance that is assigned to this. * @return @@ -92,12 +95,26 @@ CaretMappableDataFile::operator=(const CaretMappableDataFile& cmdf) return *this; } +/** + * Initialize a new instance. + */ +void +CaretMappableDataFile::initializeCaretMappableDataFileInstance() +{ + m_labelDrawingProperties = std::unique_ptr(new LabelDrawingProperties()); + + m_lineChartHistory = std::unique_ptr(new ChartTwoDataCartesianHistory()); +} + + /** * Assists with copying instances of this class. */ void -CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& /*cmdf*/) +CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& cmdf) { + setPaletteNormalizationMode(cmdf.getPaletteNormalizationMode()); + *m_labelDrawingProperties = *cmdf.m_labelDrawingProperties; } // note: method is documented in header file @@ -297,6 +314,8 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute sceneClass); + sceneClass->addClass(m_lineChartHistory->saveToScene(sceneAttributes, + "m_lineChartHistory")); sceneClass->addClass(m_labelDrawingProperties->saveToScene(sceneAttributes, "m_labelDrawingProperties")); @@ -385,6 +404,9 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr m_labelDrawingProperties->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelDrawingProperties")); + m_lineChartHistory->restoreFromScene(sceneAttributes, + sceneClass->getClass("m_lineChartHistory")); + if (isMappedWithPalette()) { /* * Palette normalization was no longer saved to scenes after @@ -996,7 +1018,7 @@ CaretMappableDataFile::isMedialWallLabelInMapLabelTable(const int32_t mapIndex) LabelDrawingProperties* CaretMappableDataFile::getLabelDrawingProperties() { - return m_labelDrawingProperties; + return m_labelDrawingProperties.get(); } /** @@ -1006,7 +1028,7 @@ CaretMappableDataFile::getLabelDrawingProperties() const LabelDrawingProperties* CaretMappableDataFile::getLabelDrawingProperties() const { - return m_labelDrawingProperties; + return m_labelDrawingProperties.get(); } /** @@ -1071,3 +1093,290 @@ const CiftiXML CaretMappableDataFile::getCiftiXML() const return CiftiXML(); } +/** + * @return The CaretMappableDataFile that implements this interface. + */ +CaretMappableDataFile* +CaretMappableDataFile::getAsCaretMappableDataFile() +{ + return this; +} + +/** + * @return The CaretMappableDataFile that implements this interface. + */ +const CaretMappableDataFile* +CaretMappableDataFile::getAsCaretMappableDataFile() const +{ + return this; +} + + +/** + * Does this file support any type of charting? + */ +bool +CaretMappableDataFile::isChartingSupported() const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + return ( ! chartCompoundDataTypes.empty()); +} + +/** + * Test for support of the given chart data type. + * + * @param chartDataType + * Type of chart data. + * @return + * True if the chart data type is supported, else false. + */ +bool +CaretMappableDataFile::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const +{ + std::vector chartDataTypes; + getSupportedChartDataTypes(chartDataTypes); + + if (std::find(chartDataTypes.begin(), + chartDataTypes.end(), + chartDataType) != chartDataTypes.end()) { + return true; + } + + return false; +} + +/** + * Test for support of the given chart compound data type. + * + * @param chartCompoundDataType + * Type of chart compound data. + * @return + * True if the chart compound data type is supported, else false. + */ +bool +CaretMappableDataFile::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + for (auto& ccdt : chartCompoundDataTypes) { + if (ccdt == chartCompoundDataType) { + return true; + } + } + + return false; +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +CaretMappableDataFile::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const +{ + chartDataTypesOut.clear(); + + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + for (auto& ccdt : chartCompoundDataTypes) { + chartDataTypesOut.push_back(ccdt.getChartDataType()); + } +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +CaretMappableDataFile::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const +{ + chartCompoundDataTypesOut.clear(); + + bool hasHistogramFlag = false; + bool hasBrainordinateLineSeriesFlag = false; + bool hasNoMapsLineSeriesFlag = false; + bool hasMatrixFlag = false; + + switch (getDataFileType()) { + case DataFileTypeEnum::CONNECTIVITY_DENSE: + hasHistogramFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + hasHistogramFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + hasHistogramFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + hasHistogramFlag = true; + hasMatrixFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + hasHistogramFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + hasMatrixFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + hasMatrixFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + hasHistogramFlag = true; + hasNoMapsLineSeriesFlag = true; + hasMatrixFlag = true; + break; + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + hasHistogramFlag = true; + hasBrainordinateLineSeriesFlag = true; + break; + } + + if (hasHistogramFlag) { + if (getNumberOfMaps() > 0) { + chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); + } + } + + if (hasBrainordinateLineSeriesFlag) { + if (getNumberOfMaps() > 1) { + const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); + ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + switch (mapUnits) { + case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: + CaretAssert(0); + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: + break; + } + const int32_t numMaps = getNumberOfMaps(); + chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, + numMaps)); + } + } + + if (hasNoMapsLineSeriesFlag) { + const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); + CaretAssert(ciftiMapFile); + std::vector dims; + ciftiMapFile->getMapDimensions(dims); + CaretAssertVectorIndex(dims, 1); + const int32_t numCols = dims[0]; + //const int32_t numRows = dims[1]; + + if (numCols > 1) { + const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); + ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + switch (mapUnits) { + case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: + CaretAssert(0); + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: + break; + } + chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, + numCols)); + } + } + + if (hasMatrixFlag) { + const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); + CaretAssert(ciftiMapFile); + std::vector dims; + ciftiMapFile->getMapDimensions(dims); + CaretAssertVectorIndex(dims, 1); + const int32_t numCols = dims[0]; + const int32_t numRows = dims[1]; + + chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, + numCols)); + } +} + +/** + * @return Charting history if this file charts to lines. + */ +ChartTwoDataCartesianHistory* +CaretMappableDataFile::getLineSeriesChartingHistory() +{ + return m_lineChartHistory.get(); +} + + diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index a28b378af..4d0b2c3c3 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -21,9 +21,11 @@ */ /*LICENSE_END*/ +#include #include "CaretDataFile.h" #include "ChartVersionOneDataTypeEnum.h" +#include "ChartableTwoInterface.h" #include "CaretPointer.h" #include "NiftiEnums.h" #include "PaletteNormalizationModeEnum.h" @@ -32,6 +34,7 @@ namespace caret { class ChartDataCartesian; class CiftiXML; + class ChartTwoDataCartesianHistory; class FastStatistics; class GiftiMetaData; class GiftiLabelTable; @@ -55,7 +58,7 @@ namespace caret { * Note that Caret5 used the term 'column'. */ - class CaretMappableDataFile : public CaretDataFile { + class CaretMappableDataFile : public CaretDataFile, public ChartableTwoInterface { public: CaretMappableDataFile(const DataFileTypeEnum::Enum dataFileType); @@ -451,10 +454,28 @@ namespace caret { /* documented in cxx file. */ bool isModified() const; + void initializeCaretMappableDataFileInstance(); + LabelDrawingProperties* getLabelDrawingProperties(); const LabelDrawingProperties* getLabelDrawingProperties() const; + virtual CaretMappableDataFile* getAsCaretMappableDataFile() override; + + virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const override; + + virtual bool isChartingSupported() const override; + + virtual bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const override; + + virtual bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const override; + + virtual void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const override; + + virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const override; + + virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() override; + protected: CaretMappableDataFile(const CaretMappableDataFile&); @@ -474,8 +495,9 @@ namespace caret { void copyCaretMappableDataFile(const CaretMappableDataFile&); - CaretPointer m_labelDrawingProperties; + std::unique_ptr m_labelDrawingProperties; + std::unique_ptr m_lineChartHistory; }; #ifdef __CARET_MAPPABLE_DATA_FILE_DECLARE__ diff --git a/src/Files/ChartableTwoInterface.cxx b/src/Files/ChartableTwoInterface.cxx new file mode 100644 index 000000000..d8b2ab537 --- /dev/null +++ b/src/Files/ChartableTwoInterface.cxx @@ -0,0 +1,53 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_INTERFACE_DECLARE__ +#include "ChartableTwoInterface.h" +#undef __CHARTABLE_TWO_INTERFACE_DECLARE__ + +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoInterface + * \brief Interface for files that are chartable. + * \ingroup Files + */ + +/** + * Constructor. + */ +ChartableTwoInterface::ChartableTwoInterface() +{ + +} + +/** + * Destructor. + */ +ChartableTwoInterface::~ChartableTwoInterface() +{ +} + diff --git a/src/Files/ChartableTwoInterface.h b/src/Files/ChartableTwoInterface.h new file mode 100644 index 000000000..cc4a23127 --- /dev/null +++ b/src/Files/ChartableTwoInterface.h @@ -0,0 +1,126 @@ +#ifndef __CHARTABLE_TWO_INTERFACE_H__ +#define __CHARTABLE_TWO_INTERFACE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "ChartTwoCompoundDataType.h" +#include "ChartTwoDataTypeEnum.h" + +namespace caret { + + class CaretMappableDataFile; + class ChartTwoDataCartesianHistory; + + class ChartableTwoInterface { + + public: + ChartableTwoInterface(); + + virtual ~ChartableTwoInterface(); + + /** + * @return The CaretMappableDataFile that implements this interface. + */ + virtual CaretMappableDataFile* getAsCaretMappableDataFile() = 0; + + /** + * @return The CaretMappableDataFile that implements this interface. + */ + virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const = 0; + + /** + * Does this file support any type of charting? + */ + virtual bool isChartingSupported() const = 0; + + /** + * Test for support of the given chart data type. + * + * @param chartDataType + * Type of chart data. + * @return + * True if the chart data type is supported, else false. + */ + virtual bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const = 0; + + /** + * Test for support of the given chart compound data type. + * + * @param chartCompoundDataType + * Type of chart compound data. + * @return + * True if the chart compound data type is supported, else false. + */ + virtual bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const = 0; + + /** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ + virtual void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const = 0; + + /** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ + virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const = 0; + +// /** +// * @return Is line series charting enabled for this file in the given tab? +// */ +// virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const = 0; +// +// /** +// * Set charting enabled for this file in the given tab +// * +// * @param enabled +// * New status for charting enabled. +// */ +// virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, +// const bool enabled) = 0; + + /** + * @return Charting history if this file charts to lines. + */ + virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; + + // ADD_NEW_METHODS_HERE + + private: + ChartableTwoInterface(const ChartableTwoInterface&); + + ChartableTwoInterface& operator=(const ChartableTwoInterface&); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_INTERFACE_DECLARE__ + // +#endif // __CHARTABLE_TWO_INTERFACE_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_INTERFACE_H__ diff --git a/src/Files/LabelDrawingProperties.cxx b/src/Files/LabelDrawingProperties.cxx index fc1cd16d2..4eb4a487a 100644 --- a/src/Files/LabelDrawingProperties.cxx +++ b/src/Files/LabelDrawingProperties.cxx @@ -42,11 +42,57 @@ using namespace caret; */ LabelDrawingProperties::LabelDrawingProperties() : CaretObject() +{ + initializeInstance(); +} + +/** + * Destructor. + */ +LabelDrawingProperties::~LabelDrawingProperties() +{ + delete m_sceneAssistant; +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +LabelDrawingProperties::LabelDrawingProperties(const LabelDrawingProperties& obj) +: CaretObject(obj) +{ + initializeInstance(); + copyHelper(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +LabelDrawingProperties& +LabelDrawingProperties::operator=(const LabelDrawingProperties& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelper(obj); + } + return *this; +} + +/** + * Initialize an instance of this class. + */ +void +LabelDrawingProperties::initializeInstance() { m_drawingType = LabelDrawingTypeEnum::DRAW_FILLED; m_outlineColor = CaretColorEnum::BLACK; m_drawMedialWallFilled = true; - + m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_drawingType", &m_drawingType); @@ -56,15 +102,20 @@ LabelDrawingProperties::LabelDrawingProperties() &m_drawMedialWallFilled); } + /** - * Destructor. + * Helps with copying an object of this type. + * @param obj + * Object that is copied. */ -LabelDrawingProperties::~LabelDrawingProperties() +void +LabelDrawingProperties::copyHelper(const LabelDrawingProperties& obj) { - delete m_sceneAssistant; + m_drawingType = obj.m_drawingType; + m_outlineColor = obj.m_outlineColor; + m_drawMedialWallFilled = obj.m_drawMedialWallFilled; } - /** * @return The drawing type. */ diff --git a/src/Files/LabelDrawingProperties.h b/src/Files/LabelDrawingProperties.h index 68c2f2b53..1a928e465 100644 --- a/src/Files/LabelDrawingProperties.h +++ b/src/Files/LabelDrawingProperties.h @@ -39,6 +39,10 @@ namespace caret { virtual ~LabelDrawingProperties(); + LabelDrawingProperties(const LabelDrawingProperties&); + + LabelDrawingProperties& operator=(const LabelDrawingProperties&); + LabelDrawingTypeEnum::Enum getDrawingType() const; void setDrawingType(const LabelDrawingTypeEnum::Enum drawingType); @@ -75,9 +79,10 @@ namespace caret { // const SceneClass* sceneClass) = 0; private: - LabelDrawingProperties(const LabelDrawingProperties&); - - LabelDrawingProperties& operator=(const LabelDrawingProperties&); + + void initializeInstance(); + + void copyHelper(const LabelDrawingProperties& obj); SceneClassAssistant* m_sceneAssistant; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 9a80ed756..7708c500f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1404,7 +1404,7 @@ BrainBrowserWindowToolBar::updateToolBar() ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); if (modelChart != NULL) { - switch (modelChart->getSelectedChartDataType(browserTabContent->getTabNumber())) { + switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index 6c3cc9474..64a12c50f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -133,7 +133,7 @@ BrainBrowserWindowToolBarChartAttributes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: @@ -173,7 +173,7 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx index ec0fdcbf1..0f431e3bb 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx @@ -277,7 +277,7 @@ BrainBrowserWindowToolBarChartAxes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index ac94a2b4a..4178a4aef 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -148,7 +148,7 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelChart* chartModel = btc->getDisplayedChartModel(); const int32_t tabIndex = btc->getTabNumber(); - chartModel->setSelectedChartDataType(tabIndex, + chartModel->setSelectedChartOneDataType(tabIndex, chartDataType); //updateContent(btc); @@ -172,10 +172,10 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartDataType(tabIndex); + const ChartVersionOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartOneDataType(tabIndex); std::vector validChartDataTypes; - chartModel->getValidChartDataTypes(validChartDataTypes); + chartModel->getValidChartOneDataTypes(validChartDataTypes); for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); buttIter != m_chartTypeRadioButtons.end(); diff --git a/src/GuiQt/ChartHistoryViewController.cxx b/src/GuiQt/ChartHistoryViewController.cxx index 53e64c3af..cc613dcbf 100644 --- a/src/GuiQt/ChartHistoryViewController.cxx +++ b/src/GuiQt/ChartHistoryViewController.cxx @@ -438,7 +438,7 @@ ChartHistoryViewController::getSelectedChartModelAndTab(ChartModel* &chartModelO ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - switch (modelChart->getSelectedChartDataType(tabIndexOut)) { + switch (modelChart->getSelectedChartOneDataType(tabIndexOut)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: diff --git a/src/GuiQt/ChartLinesSelectionViewController.cxx b/src/GuiQt/ChartLinesSelectionViewController.cxx index bc30debd9..509f066d4 100644 --- a/src/GuiQt/ChartLinesSelectionViewController.cxx +++ b/src/GuiQt/ChartLinesSelectionViewController.cxx @@ -139,7 +139,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } bool validFlag = false; @@ -164,7 +164,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() if (validFlag) { std::vector chartableLineSeriesFilesVector; - const ChartVersionOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + const ChartVersionOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); brain->getAllChartableLineSeriesDataFilesForChartDataType(chartDataType, chartableLineSeriesFilesVector); diff --git a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx index 499b843b7..8946970a1 100644 --- a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx @@ -337,7 +337,7 @@ ChartMatrixParcelSelectionViewController::updateSelectionViewController() ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { @@ -819,7 +819,7 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - switch (modelChart->getSelectedChartDataType(browserTabIndexOut)) { + switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: diff --git a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx index 26ec73b13..5b6520f2c 100644 --- a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx @@ -245,7 +245,7 @@ ChartMatrixSeriesSelectionViewController::updateSelectionViewController() ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { @@ -353,7 +353,7 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - switch (modelChart->getSelectedChartDataType(browserTabIndexOut)) { + switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: diff --git a/src/GuiQt/ChartOverlayViewController.h b/src/GuiQt/ChartOverlayViewController.h index 9c30eb56c..01fb14563 100644 --- a/src/GuiQt/ChartOverlayViewController.h +++ b/src/GuiQt/ChartOverlayViewController.h @@ -23,7 +23,7 @@ #include - +#include class QAction; class QCheckBox; diff --git a/src/GuiQt/ChartSelectionViewController.cxx b/src/GuiQt/ChartSelectionViewController.cxx index abc022755..57933bb14 100644 --- a/src/GuiQt/ChartSelectionViewController.cxx +++ b/src/GuiQt/ChartSelectionViewController.cxx @@ -111,7 +111,7 @@ ChartSelectionViewController::updateSelectionViewController() ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { - chartDataType = modelChart->getSelectedChartDataType(browserTabIndex); + chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } switch (chartDataType) { diff --git a/src/GuiQt/ChartToolBoxViewController.cxx b/src/GuiQt/ChartToolBoxViewController.cxx index 8a3c0204f..2938ace15 100644 --- a/src/GuiQt/ChartToolBoxViewController.cxx +++ b/src/GuiQt/ChartToolBoxViewController.cxx @@ -170,7 +170,7 @@ ChartToolBoxViewController::getSelectedChartModel() ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { const int32_t browserTabIndex = browserTabContent->getTabNumber(); - switch (modelChart->getSelectedChartDataType(browserTabIndex)) { + switch (modelChart->getSelectedChartOneDataType(browserTabIndex)) { case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -- GitLab From de7e3a5b5ee00c63078c8d2b17b6df33028d8b18 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Jan 2017 15:49:19 -0600 Subject: [PATCH 180/755] Renamed ChartVersionOneDataTypeEnum to ChartOneDataTypeEnum. --- src/Brain/Brain.cxx | 4 +- src/Brain/Brain.h | 6 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 14 +- src/Brain/BrowserTabContent.cxx | 40 +-- src/Brain/ModelChart.cxx | 306 +++++++++--------- src/Brain/ModelChart.h | 10 +- src/Charting/CMakeLists.txt | 4 +- src/Charting/ChartData.cxx | 18 +- src/Charting/ChartData.h | 10 +- src/Charting/ChartDataCartesian.cxx | 2 +- src/Charting/ChartDataCartesian.h | 2 +- src/Charting/ChartModel.cxx | 4 +- src/Charting/ChartModel.h | 8 +- src/Charting/ChartModelCartesian.cxx | 4 +- src/Charting/ChartModelCartesian.h | 2 +- src/Charting/ChartModelDataSeries.cxx | 2 +- src/Charting/ChartModelFrequencySeries.cxx | 2 +- src/Charting/ChartModelTimeSeries.cxx | 2 +- ...aTypeEnum.cxx => ChartOneDataTypeEnum.cxx} | 100 +++--- ...eDataTypeEnum.h => ChartOneDataTypeEnum.h} | 16 +- src/Files/CaretMappableDataFile.cxx | 16 +- src/Files/CaretMappableDataFile.h | 4 +- src/Files/ChartableLineSeriesInterface.cxx | 4 +- src/Files/ChartableLineSeriesInterface.h | 6 +- src/Files/ChartableMatrixInterface.cxx | 4 +- src/Files/ChartableMatrixInterface.h | 6 +- .../CiftiBrainordinateDataSeriesFile.cxx | 2 +- src/Files/CiftiBrainordinateDataSeriesFile.h | 2 +- src/Files/CiftiBrainordinateScalarFile.cxx | 4 +- src/Files/CiftiBrainordinateScalarFile.h | 2 +- .../CiftiConnectivityMatrixParcelFile.cxx | 4 +- src/Files/CiftiConnectivityMatrixParcelFile.h | 2 +- src/Files/CiftiParcelLabelFile.cxx | 4 +- src/Files/CiftiParcelLabelFile.h | 2 +- src/Files/CiftiParcelScalarFile.cxx | 8 +- src/Files/CiftiParcelScalarFile.h | 4 +- src/Files/CiftiParcelSeriesFile.cxx | 6 +- src/Files/CiftiParcelSeriesFile.h | 2 +- src/Files/CiftiScalarDataSeriesFile.cxx | 18 +- src/Files/CiftiScalarDataSeriesFile.h | 4 +- src/Files/MetricFile.cxx | 2 +- src/Files/MetricFile.h | 2 +- src/Files/VolumeFile.cxx | 2 +- src/Files/VolumeFile.h | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 12 +- ...ainBrowserWindowToolBarChartAttributes.cxx | 28 +- .../BrainBrowserWindowToolBarChartAxes.cxx | 14 +- .../BrainBrowserWindowToolBarChartType.cxx | 66 ++-- .../BrainBrowserWindowToolBarChartType.h | 4 +- src/GuiQt/ChartHistoryViewController.cxx | 12 +- .../ChartLinesSelectionViewController.cxx | 16 +- ...artMatrixParcelSelectionViewController.cxx | 16 +- ...artMatrixSeriesSelectionViewController.cxx | 16 +- src/GuiQt/ChartSelectionViewController.cxx | 14 +- src/GuiQt/ChartToolBoxViewController.cxx | 24 +- 55 files changed, 445 insertions(+), 445 deletions(-) rename src/Charting/{ChartVersionOneDataTypeEnum.cxx => ChartOneDataTypeEnum.cxx} (70%) rename src/Charting/{ChartVersionOneDataTypeEnum.h => ChartOneDataTypeEnum.h} (87%) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index f7cc9d89a..80e888c6a 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -3445,7 +3445,7 @@ Brain::getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); @@ -3542,7 +3542,7 @@ Brain::getAllChartableMatrixDataFiles(std::vector& ch * Contains all chartable data files upon exit. */ void -Brain::getAllChartableMatrixDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, +Brain::getAllChartableMatrixDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index 6e933b945..dbf781a51 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -25,7 +25,7 @@ #include #include "CaretObject.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" @@ -321,14 +321,14 @@ namespace caret { void getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const; - void getAllChartableLineSeriesDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, + void getAllChartableLineSeriesDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; void getAllChartableBrainordinateDataFilesWithChartingEnabled(std::vector& chartableDataFilesOut) const; void getAllChartableMatrixDataFiles(std::vector& chartableDataFilesOut) const; - void getAllChartableMatrixDataFilesForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType, + void getAllChartableMatrixDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; AString getCurrentDirectory() const; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 466ad6e4f..82f9bc9ec 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5283,34 +5283,34 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const int32_t tabIndex = browserTabContent->getTabNumber(); ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); + const ChartOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); SelectionItemDataTypeEnum::Enum selectionItemDataType = SelectionItemDataTypeEnum::INVALID; int32_t scalarDataSeriesMapIndex = -1; switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = chartModel->getSelectedDataSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_DATA_SERIES; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = chartModel->getSelectedFrequencySeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_FREQUENCY_SERIES; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = chartModel->getSelectedTimeSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_TIME_SERIES; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* matrixFileSelector = chartModel->getChartableMatrixParcelFileSelectionModel(tabIndex); matrixChartFile = matrixFileSelector->getSelectedFileOfType(); selectionItemDataType = SelectionItemDataTypeEnum::CHART_MATRIX; } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = chartModel->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 586cfbdce..e611016a8 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1304,21 +1304,21 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo CaretDataFileSelectionModel* fileModel = NULL; switch (modelChart->getSelectedChartOneDataType(m_tabNumber)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -1453,21 +1453,21 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetSelectedChartOneDataType(m_tabNumber)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } @@ -2390,11 +2390,11 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { @@ -2506,11 +2506,11 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } - if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index ebe5083df..e167d864b 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -119,7 +119,7 @@ void ModelChart::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectedChartOneDataType[i] = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_selectedChartOneDataType[i] = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; m_selectedChartTwoDataType[i] = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; m_chartModelDataSeries[i] = new ChartModelDataSeries(); @@ -374,13 +374,13 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, { CaretAssert(chartData); - const ChartVersionOneDataTypeEnum::Enum chartDataDataType = chartData->getChartDataType(); + const ChartOneDataTypeEnum::Enum chartDataDataType = chartData->getChartDataType(); switch (chartDataDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -395,7 +395,7 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_dataSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -410,7 +410,7 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_frequencySeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); @@ -425,10 +425,10 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, m_timeSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; } } @@ -774,7 +774,7 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr tabIndices, validChartDataIDs); - sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartOneDataType, tabIndices); @@ -867,7 +867,7 @@ ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttrib restoreVersionOneChartModelsFromScene(sceneAttributes, sceneClass); - sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartOneDataType); /* @@ -924,7 +924,7 @@ ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttrib restoreVersionTwoChartModelsFromScene(sceneAttributes, sceneClass); - sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", + sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartOneDataType); /* @@ -992,19 +992,19 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, ChartModel* chartModel = NULL; switch (getSelectedChartOneDataType(tabIndex)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = getSelectedDataSeriesChartModel(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = getSelectedTimeSeriesChartModel(tabIndex); break; } @@ -1020,7 +1020,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, "ChartClassContainer", 1); chartClassContainer->addInteger("tabIndex", tabIndex); - chartClassContainer->addEnumeratedType("chartDataType", + chartClassContainer->addEnumeratedType("chartDataType", chartModel->getChartDataType()); chartClassContainer->addClass(chartModelClass); @@ -1054,7 +1054,7 @@ ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, SceneClass* chartDataContainer = new SceneClass("chartDataContainer", "ChartDataContainer", 1); - chartDataContainer->addEnumeratedType("chartDataType", + chartDataContainer->addEnumeratedType("chartDataType", chartData->getChartDataType()); chartDataContainer->addClass(chartDataClass); @@ -1094,34 +1094,34 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); if (chartClassContainer != NULL) { const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", - ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", + ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); if ((tabIndex >= 0) - && (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartModelClass != NULL)) { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; @@ -1141,10 +1141,10 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); if (chartDataContainer != NULL) { - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", - ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", + ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); - if ((chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) + if ((chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartDataClass != NULL)) { ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); CaretAssert(chartData); @@ -1221,30 +1221,30 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt QSharedPointer chartPointer = *rcdIter; switch (chartPointer->getChartDataType()) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_dataSeriesChartData.push_back(cartChartPointer); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_frequencySeriesChartData.push_back(cartChartPointer); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); @@ -1280,34 +1280,34 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); if (chartClassContainer != NULL) { const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", - ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", + ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); if ((tabIndex >= 0) - && (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) + && (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartModelClass != NULL)) { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; @@ -1327,10 +1327,10 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); if (chartDataContainer != NULL) { - const ChartVersionOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", - ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID); + const ChartOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", + ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); - if ((chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) + if ((chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartDataClass != NULL)) { ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); CaretAssert(chartData); @@ -1407,30 +1407,30 @@ ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAt QSharedPointer chartPointer = *rcdIter; switch (chartPointer->getChartDataType()) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_dataSeriesChartData.push_back(cartChartPointer); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_frequencySeriesChartData.push_back(cartChartPointer); } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); @@ -1459,7 +1459,7 @@ ModelChart::loadCartesianChartWhenRestoringScene(const ChartData* chartData) const ChartDataCartesian* cartesianChart = dynamic_cast(chartData); if (cartesianChart != NULL) { - const ChartVersionOneDataTypeEnum::Enum chartDataType = cartesianChart->getChartDataType(); + const ChartOneDataTypeEnum::Enum chartDataType = cartesianChart->getChartDataType(); std::vector chartableDataFiles; m_brain->getAllChartableLineSeriesDataFiles(chartableDataFiles); @@ -1619,9 +1619,9 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, { ChartModel* chartModel = NULL; switch (getSelectedChartOneDataType(tabIndex)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* sm = m_chartableMatrixFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); @@ -1632,7 +1632,7 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* sm = m_chartableMatrixSeriesFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); @@ -1643,13 +1643,13 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = const_cast(getSelectedDataSeriesChartModel(tabIndex)); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = const_cast(getSelectedFrequencySeriesChartModel(tabIndex)); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = const_cast(getSelectedTimeSeriesChartModel(tabIndex)); break; } @@ -1658,7 +1658,7 @@ ModelChart::getDescriptionOfContent(const int32_t tabIndex, if (chartModel != NULL) { descriptionOut.addLine("Chart Type: " - + ChartVersionOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); + + ChartOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); descriptionOut.pushIndentation(); @@ -1722,7 +1722,7 @@ ModelChart::copyTabContent(const int32_t sourceTabIndex, */ void ModelChart::setSelectedChartOneDataType(const int32_t tabIndex, - const ChartVersionOneDataTypeEnum::Enum dataType) + const ChartOneDataTypeEnum::Enum dataType) { CaretAssertArrayIndex(m_selectedChartOneDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, @@ -1737,7 +1737,7 @@ ModelChart::setSelectedChartOneDataType(const int32_t tabIndex, * Output containing valid chart data types. */ void -ModelChart::getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const +ModelChart::getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); @@ -1755,27 +1755,27 @@ ModelChart::getValidChartOneDataTypes(std::vector chartDataTypes; + std::vector chartDataTypes; chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); - for (std::vector::iterator typeIter = chartDataTypes.begin(); + for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { - const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; + const ChartOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: haveDataSeries = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: haveFrequencySeries = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: haveTimeSeries = true; break; } @@ -1791,27 +1791,27 @@ ModelChart::getValidChartOneDataTypes(std::vector chartDataTypes; +// std::vector chartDataTypes; // chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); // -// for (std::vector::iterator typeIter = chartDataTypes.begin(); +// for (std::vector::iterator typeIter = chartDataTypes.begin(); // typeIter != chartDataTypes.end(); // typeIter++) { -// const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; +// const ChartOneDataTypeEnum::Enum cdt = *typeIter; // switch (cdt) { -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // haveDataSeries = true; // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // haveFrequencySeries = true; // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // haveTimeSeries = true; // break; // } @@ -1826,46 +1826,46 @@ ModelChart::getValidChartOneDataTypes(std::vector chartDataTypes; + std::vector chartDataTypes; chartFile->getSupportedMatrixChartDataTypes(chartDataTypes); - for (std::vector::iterator typeIter = chartDataTypes.begin(); + for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { - const ChartVersionOneDataTypeEnum::Enum cdt = *typeIter; + const ChartOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: haveMatrixLayers = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: haveMatrixSeries = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } } if (haveDataSeries) { - validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); + validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); } if (haveFrequencySeries) { - validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); + validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); } if (haveMatrixLayers) { - validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } if (haveMatrixSeries) { - validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); + validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } if (haveTimeSeries) { - validChartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); } } @@ -1878,85 +1878,85 @@ ModelChart::getValidChartOneDataTypes(std::vector validChartDataTypes; + std::vector validChartDataTypes; getValidChartOneDataTypes(validChartDataTypes); if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartDataType) == validChartDataTypes.end()) { - chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; } /* * If selected chart data type is invalid, find a valid chart type, * preferably one that contains data. */ - if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { if ( ! validChartDataTypes.empty()) { /* * Will become the the first valid chart data type that contains * data (if there is one) */ - ChartVersionOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; /* * Loop through all chart types (some or all valid charts * types may not contain data until the user commands loading of data) */ - std::vector allChartDataTypes; - ChartVersionOneDataTypeEnum::getAllEnums(allChartDataTypes); - for (std::vector::iterator iter = allChartDataTypes.begin(); + std::vector allChartDataTypes; + ChartOneDataTypeEnum::getAllEnums(allChartDataTypes); + for (std::vector::iterator iter = allChartDataTypes.begin(); iter != allChartDataTypes.end(); iter++) { - const ChartVersionOneDataTypeEnum::Enum cdt = *iter; + const ChartOneDataTypeEnum::Enum cdt = *iter; if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), cdt) != validChartDataTypes.end()) { - if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = cdt; } switch (cdt) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; + if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; + if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { - if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { - chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; + if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; } } break; @@ -1964,10 +1964,10 @@ ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const } } - if (chartDataTypeWithValidData != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataTypeWithValidData != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = chartDataTypeWithValidData; } - else if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + else if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = validChartDataTypes[0]; } } @@ -2077,74 +2077,74 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const // /* // * Verify that the selected chart data type is valid. // */ -// std::vector validChartDataTypes; +// std::vector validChartDataTypes; // getValidChartOneDataTypes(validChartDataTypes); // if (std::find(validChartDataTypes.begin(), // validChartDataTypes.end(), // chartDataType) == validChartDataTypes.end()) { -// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; +// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; // } // // /* // * If selected chart data type is invalid, find a valid chart type, // * preferably one that contains data. // */ -// if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { // if ( ! validChartDataTypes.empty()) { // /* // * Will become the the first valid chart data type that contains // * data (if there is one) // */ -// ChartVersionOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; +// ChartOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; // // /* // * Loop through all chart types (some or all valid charts // * types may not contain data until the user commands loading of data) // */ -// std::vector allChartDataTypes; -// ChartVersionOneDataTypeEnum::getAllEnums(allChartDataTypes); -// for (std::vector::iterator iter = allChartDataTypes.begin(); +// std::vector allChartDataTypes; +// ChartOneDataTypeEnum::getAllEnums(allChartDataTypes); +// for (std::vector::iterator iter = allChartDataTypes.begin(); // iter != allChartDataTypes.end(); // iter++) { -// const ChartVersionOneDataTypeEnum::Enum cdt = *iter; +// const ChartOneDataTypeEnum::Enum cdt = *iter; // if (std::find(validChartDataTypes.begin(), // validChartDataTypes.end(), // cdt) != validChartDataTypes.end()) { -// if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { // chartDataType = cdt; // } // // switch (cdt) { -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; // } // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; // } // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; +// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; // } // } // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; +// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; // } // } // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; +// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; // } // } // break; @@ -2152,10 +2152,10 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const // } // } // -// if (chartDataTypeWithValidData != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// if (chartDataTypeWithValidData != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { // chartDataType = chartDataTypeWithValidData; // } -// else if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { +// else if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { // chartDataType = validChartDataTypes[0]; // } // } diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 3dc8b0ebe..54c03e098 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -29,7 +29,7 @@ #include #include "ChartTwoDataTypeEnum.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "Model.h" @@ -95,12 +95,12 @@ namespace caret { virtual void receiveEvent(Event* event); - void getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const; + void getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const; - ChartVersionOneDataTypeEnum::Enum getSelectedChartOneDataType(const int32_t tabIndex) const; + ChartOneDataTypeEnum::Enum getSelectedChartOneDataType(const int32_t tabIndex) const; void setSelectedChartOneDataType(const int32_t tabIndex, - const ChartVersionOneDataTypeEnum::Enum dataType); + const ChartOneDataTypeEnum::Enum dataType); void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; @@ -197,7 +197,7 @@ namespace caret { mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - mutable ChartVersionOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + mutable ChartOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ ChartModelDataSeries* m_chartModelDataSeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 0205af6f0..bec3d0b1e 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -35,7 +35,7 @@ ChartModelTimeSeries.h ChartPoint.h ChartScaleAutoRanging.h ChartSelectionModeEnum.h -ChartVersionOneDataTypeEnum.h +ChartOneDataTypeEnum.h ChartingVersionEnum.h ChartTwoCompoundDataType.h @@ -65,7 +65,7 @@ ChartModelTimeSeries.cxx ChartPoint.cxx ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx -ChartVersionOneDataTypeEnum.cxx +ChartOneDataTypeEnum.cxx ChartingVersionEnum.cxx ChartTwoCompoundDataType.cxx diff --git a/src/Charting/ChartData.cxx b/src/Charting/ChartData.cxx index 1d63c0988..4f2281e6a 100644 --- a/src/Charting/ChartData.cxx +++ b/src/Charting/ChartData.cxx @@ -46,7 +46,7 @@ using namespace caret; * @param chartDataType * Type of chart model. */ -ChartData::ChartData(const ChartVersionOneDataTypeEnum::Enum chartDataType) +ChartData::ChartData(const ChartOneDataTypeEnum::Enum chartDataType) : CaretObject(), SceneableInterface(), m_chartDataType(chartDataType) @@ -143,30 +143,30 @@ ChartData::copyHelperChartData(const ChartData& obj) * Pointer to new instance. */ ChartData* -ChartData::newChartDataForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType) +ChartData::newChartDataForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType) { ChartData* chartData = NULL; switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); @@ -233,7 +233,7 @@ ChartData::restoreFromScene(const SceneAttributes* sceneAttributes, /** * @return The chart data model type. */ -ChartVersionOneDataTypeEnum::Enum +ChartOneDataTypeEnum::Enum ChartData::getChartDataType() const { return m_chartDataType; diff --git a/src/Charting/ChartData.h b/src/Charting/ChartData.h index e291cbef5..25fc3ac35 100644 --- a/src/Charting/ChartData.h +++ b/src/Charting/ChartData.h @@ -23,7 +23,7 @@ #include "BrainConstants.h" #include "CaretObject.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "SceneableInterface.h" @@ -35,7 +35,7 @@ namespace caret { class ChartData : public CaretObject, public SceneableInterface { public: - static ChartData* newChartDataForChartDataType(const ChartVersionOneDataTypeEnum::Enum chartDataType); + static ChartData* newChartDataForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType); virtual ~ChartData(); @@ -50,7 +50,7 @@ namespace caret { */ virtual ChartData* clone() const = 0; - ChartVersionOneDataTypeEnum::Enum getChartDataType() const; + ChartOneDataTypeEnum::Enum getChartDataType() const; const ChartDataSource* getChartDataSource() const; @@ -80,7 +80,7 @@ namespace caret { virtual AString toString() const; protected: - ChartData(const ChartVersionOneDataTypeEnum::Enum chartDataType); + ChartData(const ChartOneDataTypeEnum::Enum chartDataType); ChartData(const ChartData& obj); @@ -124,7 +124,7 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - ChartVersionOneDataTypeEnum::Enum m_chartDataType; + ChartOneDataTypeEnum::Enum m_chartDataType; ChartDataSource* m_chartDataSource; diff --git a/src/Charting/ChartDataCartesian.cxx b/src/Charting/ChartDataCartesian.cxx index 3ca8cfb18..f18338d3b 100644 --- a/src/Charting/ChartDataCartesian.cxx +++ b/src/Charting/ChartDataCartesian.cxx @@ -52,7 +52,7 @@ using namespace caret; * @param dataAxisUnitsY * Data units for Y-axis. */ -ChartDataCartesian::ChartDataCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, +ChartDataCartesian::ChartDataCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartData(chartDataType), diff --git a/src/Charting/ChartDataCartesian.h b/src/Charting/ChartDataCartesian.h index 878a5b993..f61ff9f8e 100644 --- a/src/Charting/ChartDataCartesian.h +++ b/src/Charting/ChartDataCartesian.h @@ -34,7 +34,7 @@ namespace caret { class ChartDataCartesian : public ChartData { public: - ChartDataCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, + ChartDataCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); diff --git a/src/Charting/ChartModel.cxx b/src/Charting/ChartModel.cxx index 2d35b8bf0..517b3ed1c 100644 --- a/src/Charting/ChartModel.cxx +++ b/src/Charting/ChartModel.cxx @@ -55,7 +55,7 @@ using namespace caret; * @param chartSelectionMode * The selection mode. */ -ChartModel::ChartModel(const ChartVersionOneDataTypeEnum::Enum chartDataType, +ChartModel::ChartModel(const ChartOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode) : CaretObject(), SceneableInterface(), @@ -244,7 +244,7 @@ ChartModel::copyHelperChartModel(const ChartModel& obj) /** * @return The chart data type. */ -ChartVersionOneDataTypeEnum::Enum +ChartOneDataTypeEnum::Enum ChartModel::getChartDataType() const { return m_chartDataType; diff --git a/src/Charting/ChartModel.h b/src/Charting/ChartModel.h index b42bba6b4..5e2bdb362 100644 --- a/src/Charting/ChartModel.h +++ b/src/Charting/ChartModel.h @@ -26,7 +26,7 @@ #include #include "CaretObject.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "ChartSelectionModeEnum.h" #include "SceneableInterface.h" @@ -40,7 +40,7 @@ namespace caret { class ChartModel : public CaretObject, public SceneableInterface { public: - ChartModel(const ChartVersionOneDataTypeEnum::Enum chartDataType, + ChartModel(const ChartOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode); ChartModel(const ChartModel&); @@ -51,7 +51,7 @@ namespace caret { void removeChartData(); - ChartVersionOneDataTypeEnum::Enum getChartDataType() const; + ChartOneDataTypeEnum::Enum getChartDataType() const; ChartSelectionModeEnum::Enum getChartSelectionMode() const; @@ -160,7 +160,7 @@ namespace caret { void updateUsingMaximumNumberOfChartDatasToDisplay(); - ChartVersionOneDataTypeEnum::Enum m_chartDataType; + ChartOneDataTypeEnum::Enum m_chartDataType; ChartSelectionModeEnum::Enum m_chartSelectionMode; diff --git a/src/Charting/ChartModelCartesian.cxx b/src/Charting/ChartModelCartesian.cxx index fcaf53acb..7ec8d011e 100644 --- a/src/Charting/ChartModelCartesian.cxx +++ b/src/Charting/ChartModelCartesian.cxx @@ -54,7 +54,7 @@ using namespace caret; * @param dataAxisUnitsY * Units for the Y-axis. */ -ChartModelCartesian::ChartModelCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, +ChartModelCartesian::ChartModelCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartModel(chartDataType, @@ -170,7 +170,7 @@ ChartModelCartesian::getAverageChartDataForDisplay(const int32_t tabIndex) const std::vector xValue; std::vector ySum; int64_t averageCounter = 0; - ChartVersionOneDataTypeEnum::Enum firstChartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum firstChartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; bool firstFlag = true; for (std::vector::const_iterator iter = allData.begin(); diff --git a/src/Charting/ChartModelCartesian.h b/src/Charting/ChartModelCartesian.h index e2d0204ec..6d2b3a136 100644 --- a/src/Charting/ChartModelCartesian.h +++ b/src/Charting/ChartModelCartesian.h @@ -32,7 +32,7 @@ namespace caret { class ChartModelCartesian : public ChartModel { public: - ChartModelCartesian(const ChartVersionOneDataTypeEnum::Enum chartDataType, + ChartModelCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); diff --git a/src/Charting/ChartModelDataSeries.cxx b/src/Charting/ChartModelDataSeries.cxx index 031f50b00..7c4774bf5 100644 --- a/src/Charting/ChartModelDataSeries.cxx +++ b/src/Charting/ChartModelDataSeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelDataSeries::ChartModelDataSeries() -: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +: ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartModelFrequencySeries.cxx b/src/Charting/ChartModelFrequencySeries.cxx index 96bfc279c..8532548fb 100644 --- a/src/Charting/ChartModelFrequencySeries.cxx +++ b/src/Charting/ChartModelFrequencySeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelFrequencySeries::ChartModelFrequencySeries() -: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, +: ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartModelTimeSeries.cxx b/src/Charting/ChartModelTimeSeries.cxx index d49803e36..2f16104e4 100644 --- a/src/Charting/ChartModelTimeSeries.cxx +++ b/src/Charting/ChartModelTimeSeries.cxx @@ -38,7 +38,7 @@ using namespace caret; * Constructor. */ ChartModelTimeSeries::ChartModelTimeSeries() -: ChartModelCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, +: ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { diff --git a/src/Charting/ChartVersionOneDataTypeEnum.cxx b/src/Charting/ChartOneDataTypeEnum.cxx similarity index 70% rename from src/Charting/ChartVersionOneDataTypeEnum.cxx rename to src/Charting/ChartOneDataTypeEnum.cxx index 273c47d96..8a1781185 100644 --- a/src/Charting/ChartVersionOneDataTypeEnum.cxx +++ b/src/Charting/ChartOneDataTypeEnum.cxx @@ -21,7 +21,7 @@ #include #define __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #undef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,7 +30,7 @@ using namespace caret; /** - * \class caret::ChartVersionOneDataTypeEnum + * \class caret::ChartOneDataTypeEnum * \brief Enumerated type for type of VERSION ONE chart data. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate @@ -49,21 +49,21 @@ using namespace caret; * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "ChartVersionOneDataTypeEnum.h" + * #include "ChartOneDataTypeEnum.h" * * Instatiate: * m_chartDataTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_chartDataTypeEnumComboBox->setup(); + * m_chartDataTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDataTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDataTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_chartDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_chartDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const ChartVersionOneDataTypeEnum::Enum VARIABLE = m_chartDataTypeEnumComboBox->getSelectedItem(); + * const ChartOneDataTypeEnum::Enum VARIABLE = m_chartDataTypeEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -ChartVersionOneDataTypeEnum::ChartVersionOneDataTypeEnum(const Enum enumValue, +ChartOneDataTypeEnum::ChartOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,7 +91,7 @@ ChartVersionOneDataTypeEnum::ChartVersionOneDataTypeEnum(const Enum enumValue, /** * Destructor. */ -ChartVersionOneDataTypeEnum::~ChartVersionOneDataTypeEnum() +ChartOneDataTypeEnum::~ChartOneDataTypeEnum() { } @@ -99,34 +99,34 @@ ChartVersionOneDataTypeEnum::~ChartVersionOneDataTypeEnum() * Initialize the enumerated metadata. */ void -ChartVersionOneDataTypeEnum::initialize() +ChartOneDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_INVALID, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_INVALID, "CHART_DATA_TYPE_INVALID", "Invalid")); - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_DATA_SERIES, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_DATA_SERIES, "CHART_DATA_TYPE_LINE_DATA_SERIES", "Data Series")); - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, "CHART_DATA_TYPE_LINE_FREQUENCY_SERIES", "Frequency Series")); - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_LINE_TIME_SERIES, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_TIME_SERIES, "CHART_DATA_TYPE_LINE_TIME_SERIES", "Time Series")); - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_LAYER, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_LAYER, "CHART_DATA_TYPE_MATRIX_LAYER", "Matrix - Layer")); - enumData.push_back(ChartVersionOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_SERIES, + enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_SERIES, "CHART_DATA_TYPE_MATRIX_SERIES", "Matrix - Series")); } @@ -138,14 +138,14 @@ ChartVersionOneDataTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const ChartVersionOneDataTypeEnum* -ChartVersionOneDataTypeEnum::findData(const Enum enumValue) +const ChartOneDataTypeEnum* +ChartOneDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const ChartVersionOneDataTypeEnum* d = &enumData[i]; + const ChartOneDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -162,10 +162,10 @@ ChartVersionOneDataTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -ChartVersionOneDataTypeEnum::toName(Enum enumValue) { +ChartOneDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); + const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -179,8 +179,8 @@ ChartVersionOneDataTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -ChartVersionOneDataTypeEnum::Enum -ChartVersionOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) +ChartOneDataTypeEnum::Enum +ChartOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); @@ -199,12 +199,12 @@ ChartVersionOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) } bool validFlag = false; - Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartVersionOneDataTypeEnum& d = *iter; + const ChartOneDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -216,7 +216,7 @@ ChartVersionOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } @@ -229,10 +229,10 @@ ChartVersionOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) * String representing enumerated value. */ AString -ChartVersionOneDataTypeEnum::toGuiName(Enum enumValue) { +ChartOneDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); + const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -246,8 +246,8 @@ ChartVersionOneDataTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -ChartVersionOneDataTypeEnum::Enum -ChartVersionOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) +ChartOneDataTypeEnum::Enum +ChartOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); @@ -257,12 +257,12 @@ ChartVersionOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValid } bool validFlag = false; - Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartVersionOneDataTypeEnum& d = *iter; + const ChartOneDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -274,7 +274,7 @@ ChartVersionOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValid *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } @@ -286,10 +286,10 @@ ChartVersionOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValid * Integer code for data type. */ int32_t -ChartVersionOneDataTypeEnum::toIntegerCode(Enum enumValue) +ChartOneDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartVersionOneDataTypeEnum* enumInstance = findData(enumValue); + const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -304,18 +304,18 @@ ChartVersionOneDataTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -ChartVersionOneDataTypeEnum::Enum -ChartVersionOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +ChartOneDataTypeEnum::Enum +ChartOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartVersionOneDataTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartVersionOneDataTypeEnum& enumInstance = *iter; + const ChartOneDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -327,7 +327,7 @@ ChartVersionOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* is *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartVersionOneDataTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } @@ -340,13 +340,13 @@ ChartVersionOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* is * A vector that is OUTPUT containing all of the enumerated values. */ void -ChartVersionOneDataTypeEnum::getAllEnums(std::vector& allEnums) +ChartOneDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -362,16 +362,16 @@ ChartVersionOneDataTypeEnum::getAllEnums(std::vector& allNames, const bool isSorted) +ChartOneDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(ChartVersionOneDataTypeEnum::toName(iter->enumValue)); + allNames.push_back(ChartOneDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -388,16 +388,16 @@ ChartVersionOneDataTypeEnum::getAllNames(std::vector& allNames, const b * If true, the names are sorted in alphabetical order. */ void -ChartVersionOneDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +ChartOneDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(ChartVersionOneDataTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(ChartOneDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Charting/ChartVersionOneDataTypeEnum.h b/src/Charting/ChartOneDataTypeEnum.h similarity index 87% rename from src/Charting/ChartVersionOneDataTypeEnum.h rename to src/Charting/ChartOneDataTypeEnum.h index c9cff0afa..7eb40fe04 100644 --- a/src/Charting/ChartVersionOneDataTypeEnum.h +++ b/src/Charting/ChartOneDataTypeEnum.h @@ -28,7 +28,7 @@ namespace caret { -class ChartVersionOneDataTypeEnum { +class ChartOneDataTypeEnum { public: /** @@ -50,7 +50,7 @@ public: }; - ~ChartVersionOneDataTypeEnum(); + ~ChartOneDataTypeEnum(); static AString toName(Enum enumValue); @@ -71,14 +71,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - ChartVersionOneDataTypeEnum(const Enum enumValue, + ChartOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const ChartVersionOneDataTypeEnum* findData(const Enum enumValue); + static const ChartOneDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -103,9 +103,9 @@ private: }; #ifdef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ -std::vector ChartVersionOneDataTypeEnum::enumData; -bool ChartVersionOneDataTypeEnum::initializedFlag = false; -int32_t ChartVersionOneDataTypeEnum::integerCodeCounter = 0; +std::vector ChartOneDataTypeEnum::enumData; +bool ChartOneDataTypeEnum::initializedFlag = false; +int32_t ChartOneDataTypeEnum::integerCodeCounter = 0; #endif // __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ } // namespace diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 19bcf23bd..0faf8b567 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -903,12 +903,12 @@ CaretMappableDataFile::helpCreateCartesianChartData(const std::vector& da ChartDataCartesian* chartData = NULL; if (timeSeriesFlag) { - chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, + chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } else { - chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, + chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } @@ -958,29 +958,29 @@ CaretMappableDataFile::helpCreateCartesianChartData(const std::vector& da * Chart types supported by this file. */ void -CaretMappableDataFile::helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CaretMappableDataFile::helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); switch (getMapIntervalUnits()) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: CaretLogSevere("Units - PPM not supported"); CaretAssertMessage(0, "Units - PPM not supported"); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; } } diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 4d0b2c3c3..316d88971 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -24,7 +24,7 @@ #include #include "CaretDataFile.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "ChartableTwoInterface.h" #include "CaretPointer.h" #include "NiftiEnums.h" @@ -483,7 +483,7 @@ namespace caret { ChartDataCartesian* helpCreateCartesianChartData(const std::vector& data); - void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); diff --git a/src/Files/ChartableLineSeriesInterface.cxx b/src/Files/ChartableLineSeriesInterface.cxx index 7f8b97990..efe73d88a 100644 --- a/src/Files/ChartableLineSeriesInterface.cxx +++ b/src/Files/ChartableLineSeriesInterface.cxx @@ -42,9 +42,9 @@ using namespace caret; * True if chart data type is supported by the file, else false. */ bool -ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const +ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const { - std::vector validTypes; + std::vector validTypes; getSupportedLineSeriesChartDataTypes(validTypes); if (std::find(validTypes.begin(), diff --git a/src/Files/ChartableLineSeriesInterface.h b/src/Files/ChartableLineSeriesInterface.h index 73b6ed589..f31e91c2c 100644 --- a/src/Files/ChartableLineSeriesInterface.h +++ b/src/Files/ChartableLineSeriesInterface.h @@ -21,7 +21,7 @@ */ /*LICENSE_END*/ -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "StructureEnum.h" namespace caret { @@ -76,9 +76,9 @@ namespace caret { * @param chartDataTypesOut * Chart types supported by this file. */ - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const = 0; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const = 0; - bool isLineSeriesChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const; + bool isLineSeriesChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const; private: // ChartableLineSeriesInterface(const ChartableLineSeriesInterface&); diff --git a/src/Files/ChartableMatrixInterface.cxx b/src/Files/ChartableMatrixInterface.cxx index ca855ba15..5d2d3cc7c 100644 --- a/src/Files/ChartableMatrixInterface.cxx +++ b/src/Files/ChartableMatrixInterface.cxx @@ -43,9 +43,9 @@ using namespace caret; * True if chart data type is supported by the file, else false. */ bool -ChartableMatrixInterface::isMatrixChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const +ChartableMatrixInterface::isMatrixChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const { - std::vector validTypes; + std::vector validTypes; getSupportedMatrixChartDataTypes(validTypes); if (std::find(validTypes.begin(), diff --git a/src/Files/ChartableMatrixInterface.h b/src/Files/ChartableMatrixInterface.h index 3720efcbc..fe6f45841 100644 --- a/src/Files/ChartableMatrixInterface.h +++ b/src/Files/ChartableMatrixInterface.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ #include "CaretColorEnum.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "CiftiParcelColoringModeEnum.h" #include "YokingGroupEnum.h" @@ -155,9 +155,9 @@ namespace caret { * @param chartDataTypesOut * Chart types supported by this file. */ - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const = 0; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const = 0; - bool isMatrixChartDataTypeSupported(const ChartVersionOneDataTypeEnum::Enum chartDataType) const; + bool isMatrixChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/CiftiBrainordinateDataSeriesFile.cxx b/src/Files/CiftiBrainordinateDataSeriesFile.cxx index 54861fc84..fa07560f2 100644 --- a/src/Files/CiftiBrainordinateDataSeriesFile.cxx +++ b/src/Files/CiftiBrainordinateDataSeriesFile.cxx @@ -297,7 +297,7 @@ CiftiBrainordinateDataSeriesFile::loadLineSeriesChartDataForVoxelAtCoordinate(co * Chart types supported by this file. */ void -CiftiBrainordinateDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiBrainordinateDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/CiftiBrainordinateDataSeriesFile.h b/src/Files/CiftiBrainordinateDataSeriesFile.h index 6281a49ca..33f8f20bc 100644 --- a/src/Files/CiftiBrainordinateDataSeriesFile.h +++ b/src/Files/CiftiBrainordinateDataSeriesFile.h @@ -54,7 +54,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; CiftiConnectivityMatrixDenseDynamicFile* getConnectivityMatrixDenseDynamicFile(); diff --git a/src/Files/CiftiBrainordinateScalarFile.cxx b/src/Files/CiftiBrainordinateScalarFile.cxx index 10a118a29..3ef05d4fe 100644 --- a/src/Files/CiftiBrainordinateScalarFile.cxx +++ b/src/Files/CiftiBrainordinateScalarFile.cxx @@ -262,7 +262,7 @@ CiftiBrainordinateScalarFile::setLineSeriesChartingEnabled(const int32_t tabInde * Chart types supported by this file. */ void -CiftiBrainordinateScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiBrainordinateScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -296,7 +296,7 @@ CiftiBrainordinateScalarFile::loadLineSeriesChartDataForSurfaceNode(const Struct // data)) { // const int64_t numData = static_cast(data.size()); // -// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // for (int64_t i = 0; i < numData; i++) { diff --git a/src/Files/CiftiBrainordinateScalarFile.h b/src/Files/CiftiBrainordinateScalarFile.h index 39a4e5cfc..21d4aaa98 100644 --- a/src/Files/CiftiBrainordinateScalarFile.h +++ b/src/Files/CiftiBrainordinateScalarFile.h @@ -59,7 +59,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; private: CiftiBrainordinateScalarFile(const CiftiBrainordinateScalarFile&); diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.cxx b/src/Files/CiftiConnectivityMatrixParcelFile.cxx index 058ddc810..a081908da 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.cxx +++ b/src/Files/CiftiConnectivityMatrixParcelFile.cxx @@ -325,10 +325,10 @@ CiftiConnectivityMatrixParcelFile::setMatrixChartingEnabled(const int32_t tabInd * Chart types supported by this file. */ void -CiftiConnectivityMatrixParcelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiConnectivityMatrixParcelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.h b/src/Files/CiftiConnectivityMatrixParcelFile.h index 3dd0d0b26..f98f645b0 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.h +++ b/src/Files/CiftiConnectivityMatrixParcelFile.h @@ -70,7 +70,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelLabelFile.cxx b/src/Files/CiftiParcelLabelFile.cxx index edcdeb7b6..413cf7caa 100644 --- a/src/Files/CiftiParcelLabelFile.cxx +++ b/src/Files/CiftiParcelLabelFile.cxx @@ -297,10 +297,10 @@ CiftiParcelLabelFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelLabelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelLabelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiParcelLabelFile.h b/src/Files/CiftiParcelLabelFile.h index 6e93804b5..8f78fdf9b 100644 --- a/src/Files/CiftiParcelLabelFile.h +++ b/src/Files/CiftiParcelLabelFile.h @@ -58,7 +58,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelScalarFile.cxx b/src/Files/CiftiParcelScalarFile.cxx index fe48341e4..9ba5844ba 100644 --- a/src/Files/CiftiParcelScalarFile.cxx +++ b/src/Files/CiftiParcelScalarFile.cxx @@ -124,7 +124,7 @@ CiftiParcelScalarFile::isLineSeriesChartingSupported() const * Chart types supported by this file. */ void -CiftiParcelScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -174,7 +174,7 @@ CiftiParcelScalarFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum // data)) { // const int64_t numData = static_cast(data.size()); // -// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // for (int64_t i = 0; i < numData; i++) { @@ -393,10 +393,10 @@ CiftiParcelScalarFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelScalarFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelScalarFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** diff --git a/src/Files/CiftiParcelScalarFile.h b/src/Files/CiftiParcelScalarFile.h index fdd4adc7e..836b77559 100644 --- a/src/Files/CiftiParcelScalarFile.h +++ b/src/Files/CiftiParcelScalarFile.h @@ -56,7 +56,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; @@ -78,7 +78,7 @@ namespace caret { virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); - virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; diff --git a/src/Files/CiftiParcelSeriesFile.cxx b/src/Files/CiftiParcelSeriesFile.cxx index 3c1688374..9c4fd8a3c 100644 --- a/src/Files/CiftiParcelSeriesFile.cxx +++ b/src/Files/CiftiParcelSeriesFile.cxx @@ -107,7 +107,7 @@ CiftiParcelSeriesFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiParcelSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiParcelSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } @@ -167,12 +167,12 @@ CiftiParcelSeriesFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum // } // // if (dataSeriesFlag) { -// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, +// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // } // else if (timeSeriesFlag) { -// chartData = new ChartDataCartesian(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, +// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // } diff --git a/src/Files/CiftiParcelSeriesFile.h b/src/Files/CiftiParcelSeriesFile.h index 45e18def8..a2677b504 100644 --- a/src/Files/CiftiParcelSeriesFile.h +++ b/src/Files/CiftiParcelSeriesFile.h @@ -51,7 +51,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; private: CiftiParcelSeriesFile(const CiftiParcelSeriesFile&); diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index ee58dbbe7..bd6b078c3 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -372,10 +372,10 @@ CiftiScalarDataSeriesFile::setMatrixChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -CiftiScalarDataSeriesFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const +CiftiScalarDataSeriesFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); - chartDataTypesOut.push_back(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); + chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } /** @@ -442,11 +442,11 @@ CiftiScalarDataSeriesFile::loadLineSeriesChartDataForRow(const int32_t rowIndex) const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiSeriesMap& seriesMap = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); - ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; AString timeUnitsString; switch (seriesMap.getUnit()) { case CiftiSeriesMap::HERTZ: - chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; + chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); @@ -455,11 +455,11 @@ CiftiScalarDataSeriesFile::loadLineSeriesChartDataForRow(const int32_t rowIndex) CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: - chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; + chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; break; } - if (chartDataType != ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); @@ -528,7 +528,7 @@ CiftiScalarDataSeriesFile::isLineSeriesChartingSupported() const * Chart types supported by this file. */ void -CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); @@ -541,7 +541,7 @@ CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; @@ -92,7 +92,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForRow(const int32_t rowIndex); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/MetricFile.cxx b/src/Files/MetricFile.cxx index 7284c5355..98b2409b2 100644 --- a/src/Files/MetricFile.cxx +++ b/src/Files/MetricFile.cxx @@ -475,7 +475,7 @@ MetricFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -MetricFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +MetricFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/MetricFile.h b/src/Files/MetricFile.h index 110d7e284..8106ea2ba 100644 --- a/src/Files/MetricFile.h +++ b/src/Files/MetricFile.h @@ -90,7 +90,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index d054eb6bf..49711eaa1 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -2081,7 +2081,7 @@ VolumeFile::setLineSeriesChartingEnabled(const int32_t tabIndex, * Chart types supported by this file. */ void -VolumeFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const +VolumeFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index d834eef89..5a745baa4 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -355,7 +355,7 @@ namespace caret { virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); - virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; }; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 7708c500f..2bdeca84f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1405,23 +1405,23 @@ BrainBrowserWindowToolBar::updateToolBar() ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: showChartAttributesWidget = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: showChartAttributesWidget = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: showChartAxesWidget = true; showChartAttributesWidget = true; break; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index 64a12c50f..e157247f5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -133,22 +133,22 @@ BrainBrowserWindowToolBarChartAttributes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); + const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } @@ -173,12 +173,12 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); + const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { ChartableMatrixInterface* matrixInterface = modelChart->getChartableMatrixParcelFileSelectionModel(tabIndex)->getSelectedFileOfType(); if (matrixInterface != NULL) { @@ -186,7 +186,7 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); @@ -198,11 +198,11 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx index 0f431e3bb..9f3887261 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx @@ -277,22 +277,22 @@ BrainBrowserWindowToolBarChartAxes::getCartesianChart() if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); + const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index 4178a4aef..3f479cec7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -59,18 +59,18 @@ m_parentToolBar(parentToolBar) QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); - std::vector allChartTypes; - ChartVersionOneDataTypeEnum::getAllEnums(allChartTypes); + std::vector allChartTypes; + ChartOneDataTypeEnum::getAllEnums(allChartTypes); - for (std::vector::iterator chartIter = allChartTypes.begin(); + for (std::vector::iterator chartIter = allChartTypes.begin(); chartIter != allChartTypes.end(); chartIter++) { - const ChartVersionOneDataTypeEnum::Enum ct = *chartIter; - if (ct == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { + const ChartOneDataTypeEnum::Enum ct = *chartIter; + if (ct == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { continue; } - QRadioButton* rb = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ct)); + QRadioButton* rb = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ct)); m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); @@ -82,13 +82,13 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); radioButtonLayout->addStretch(); -// m_chartMatrixLayerTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER)); +// m_chartMatrixLayerTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER)); // -// m_chartMatrixSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES)); +// m_chartMatrixSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES)); // -// m_chartDataSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES)); +// m_chartDataSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES)); // -// m_chartTimeSeriesTypeRadioButton = new QRadioButton(ChartVersionOneDataTypeEnum::toGuiName(ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES)); +// m_chartTimeSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES)); QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), @@ -124,21 +124,21 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) { CaretAssertVectorIndex(m_chartTypeRadioButtons, buttonIndex); - ChartVersionOneDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; + ChartOneDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; -// ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; +// ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; // // if (m_chartDataSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; +// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; // } // else if (m_chartMatrixLayerTypeRadioButton->isChecked()) { -// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; +// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; // } // else if (m_chartTimeSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; +// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; // } // else if (m_chartMatrixSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; +// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; // } // else { // CaretAssertMessage(0, "Has a new chart radio button been added?"); @@ -172,15 +172,15 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartVersionOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartOneDataType(tabIndex); + const ChartOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartOneDataType(tabIndex); - std::vector validChartDataTypes; + std::vector validChartDataTypes; chartModel->getValidChartOneDataTypes(validChartDataTypes); - for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); + for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); buttIter != m_chartTypeRadioButtons.end(); buttIter++) { - ChartVersionOneDataTypeEnum::Enum chartType = buttIter->first; + ChartOneDataTypeEnum::Enum chartType = buttIter->first; QRadioButton* radioButton = buttIter->second; const bool validTypeFlag = (std::find(validChartDataTypes.begin(), @@ -197,25 +197,25 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC // bool matrixLayerValidFlag = false; // bool matrixSeriesValidFlag = false; // bool timeSeriesValidFlag = false; -// for (std::vector::iterator iter = validChartDataTypes.begin(); +// for (std::vector::iterator iter = validChartDataTypes.begin(); // iter != validChartDataTypes.end(); // iter++) { // switch (*iter) { -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // matrixLayerValidFlag = true; // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // matrixSeriesValidFlag = true; // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // dataSeriesValidFlag = true; // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // CaretAssertToDoFatal(); // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // timeSeriesValidFlag = true; // break; // } @@ -226,21 +226,21 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC // m_chartTimeSeriesTypeRadioButton->setEnabled(timeSeriesValidFlag); // // switch (chartType) { -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: // m_chartMatrixLayerTypeRadioButton->setChecked(true); // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: // m_chartMatrixSeriesTypeRadioButton->setChecked(true); // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: // m_chartDataSeriesTypeRadioButton->setChecked(true); // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: // CaretAssertToDoFatal(); // break; -// case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: // m_chartTimeSeriesTypeRadioButton->setChecked(true); // break; // } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.h b/src/GuiQt/BrainBrowserWindowToolBarChartType.h index 1ccd667a5..f468511be 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.h @@ -26,7 +26,7 @@ class QButtonGroup; class QRadioButton; #include "BrainBrowserWindowToolBarComponent.h" -#include "ChartVersionOneDataTypeEnum.h" +#include "ChartOneDataTypeEnum.h" namespace caret { @@ -59,7 +59,7 @@ namespace caret { BrainBrowserWindowToolBar* m_parentToolBar; - std::vector > m_chartTypeRadioButtons; + std::vector > m_chartTypeRadioButtons; QButtonGroup* m_chartTypeButtonGroup; diff --git a/src/GuiQt/ChartHistoryViewController.cxx b/src/GuiQt/ChartHistoryViewController.cxx index cc613dcbf..89d42473b 100644 --- a/src/GuiQt/ChartHistoryViewController.cxx +++ b/src/GuiQt/ChartHistoryViewController.cxx @@ -439,19 +439,19 @@ ChartHistoryViewController::getSelectedChartModelAndTab(ChartModel* &chartModelO ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(tabIndexOut)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModelOut = modelChart->getSelectedDataSeriesChartModel(tabIndexOut); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModelOut = modelChart->getSelectedFrequencySeriesChartModel(tabIndexOut); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModelOut = modelChart->getSelectedTimeSeriesChartModel(tabIndexOut); break; } diff --git a/src/GuiQt/ChartLinesSelectionViewController.cxx b/src/GuiQt/ChartLinesSelectionViewController.cxx index 509f066d4..76c21e2b1 100644 --- a/src/GuiQt/ChartLinesSelectionViewController.cxx +++ b/src/GuiQt/ChartLinesSelectionViewController.cxx @@ -136,7 +136,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); @@ -144,19 +144,19 @@ ChartLinesSelectionViewController::updateSelectionViewController() bool validFlag = false; switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: validFlag = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: validFlag = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: validFlag = true; break; } @@ -164,7 +164,7 @@ ChartLinesSelectionViewController::updateSelectionViewController() if (validFlag) { std::vector chartableLineSeriesFilesVector; - const ChartVersionOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); + const ChartOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); brain->getAllChartableLineSeriesDataFilesForChartDataType(chartDataType, chartableLineSeriesFilesVector); diff --git a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx index 8946970a1..856f89e90 100644 --- a/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx @@ -334,13 +334,13 @@ ChartMatrixParcelSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } - if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { + if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { updateMatrixParcelChartWidget(brain, modelChart, browserTabIndex); @@ -820,9 +820,9 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); @@ -839,7 +839,7 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); @@ -856,11 +856,11 @@ ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } diff --git a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx index 5b6520f2c..c12b7f224 100644 --- a/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx +++ b/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx @@ -242,13 +242,13 @@ ChartMatrixSeriesSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } - if (chartDataType == ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { + if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; @@ -354,9 +354,9 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); @@ -373,7 +373,7 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); @@ -390,11 +390,11 @@ ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappa } } break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } diff --git a/src/GuiQt/ChartSelectionViewController.cxx b/src/GuiQt/ChartSelectionViewController.cxx index 57933bb14..c60622986 100644 --- a/src/GuiQt/ChartSelectionViewController.cxx +++ b/src/GuiQt/ChartSelectionViewController.cxx @@ -108,28 +108,28 @@ ChartSelectionViewController::updateSelectionViewController() } const int32_t browserTabIndex = browserTabContent->getTabNumber(); - ChartVersionOneDataTypeEnum::Enum chartDataType = ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } switch (chartDataType) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: m_mode = MODE_MATRIX_LAYER; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: m_mode = MODE_MATRIX_SERIES; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_mode = MODE_BRAINORDINATE; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_mode = MODE_BRAINORDINATE; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_mode = MODE_BRAINORDINATE; break; } diff --git a/src/GuiQt/ChartToolBoxViewController.cxx b/src/GuiQt/ChartToolBoxViewController.cxx index 2938ace15..f345685bb 100644 --- a/src/GuiQt/ChartToolBoxViewController.cxx +++ b/src/GuiQt/ChartToolBoxViewController.cxx @@ -121,19 +121,19 @@ ChartToolBoxViewController::receiveEvent(Event* event) if (chartModel != NULL) { switch (chartModel->getChartDataType()) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: historyWidgetValid = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: historyWidgetValid = true; break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: historyWidgetValid = true; break; } @@ -171,19 +171,19 @@ ChartToolBoxViewController::getSelectedChartModel() if (modelChart != NULL) { const int32_t browserTabIndex = browserTabContent->getTabNumber(); switch (modelChart->getSelectedChartOneDataType(browserTabIndex)) { - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = modelChart->getSelectedDataSeriesChartModel(browserTabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = modelChart->getSelectedFrequencySeriesChartModel(browserTabIndex); break; - case ChartVersionOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = modelChart->getSelectedTimeSeriesChartModel(browserTabIndex); break; } -- GitLab From f639f63d40eafebf8e4851d589a62a7444088822 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Jan 2017 12:42:43 -0600 Subject: [PATCH 181/755] Continuing new charting. First implementation of Charting Layer controls. --- src/Brain/ChartOverlay.cxx | 65 +++++++- src/Brain/ChartOverlay.h | 9 +- src/Brain/ChartOverlaySet.cxx | 33 +++- src/Brain/ChartOverlaySet.h | 4 + src/Brain/ModelChart.cxx | 24 +++ src/Brain/ModelChart.h | 2 + src/Charting/ChartTwoCompoundDataType.cxx | 29 +++- src/Files/CaretMappableDataFile.cxx | 32 +++- src/Files/CaretMappableDataFile.h | 3 + src/Files/ChartableTwoInterface.h | 15 ++ src/GuiQt/BrainBrowserWindowToolBar.cxx | 28 +++- src/GuiQt/BrainBrowserWindowToolBar.h | 5 + .../BrainBrowserWindowToolBarChartTwoType.cxx | 157 ++++++++++++++++++ .../BrainBrowserWindowToolBarChartTwoType.h | 73 ++++++++ src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/ChartOverlayViewController.cxx | 17 +- 16 files changed, 478 insertions(+), 21 deletions(-) create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index 2ba74b977..3d72023dc 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -26,6 +26,7 @@ #include "AnnotationColorBar.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" +#include "ChartOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" @@ -50,15 +51,24 @@ using namespace caret; * @param overlayIndex * Index of this overlay. */ -ChartOverlay::ChartOverlay(const ChartTwoDataTypeEnum::Enum chartDataType, +ChartOverlay::ChartOverlay(ChartOverlaySet* parentChartOverlaySet, + const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t overlayIndex) : CaretObject(), +m_parentChartOverlaySet(parentChartOverlaySet), m_chartDataType(chartDataType), m_overlayIndex(overlayIndex) { + if (overlayIndex > 0) { + CaretAssert(m_parentChartOverlaySet == NULL); + } + else { + CaretAssert(m_parentChartOverlaySet); + } + // m_chartCompoundDataType m_name = "Overlay " + AString::number(overlayIndex + 1); - m_enabled = true; + m_enabled = (m_overlayIndex == 0); m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_colorBar = std::unique_ptr(new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL)); @@ -150,9 +160,18 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co } } +/** + * Get the chart compound data type + */ +ChartTwoCompoundDataType +ChartOverlay::getChartTwoCompoundDataType() const +{ + return m_chartCompoundDataType; +} + /** * Set the compound chart type for charts displayed in this overlay. - * MUST match data type for this chart unless invalid. + * MUST match simplae data type for this chart unless invalid. * Note that overlay index zero, allows any chart type. * * @param chartCompoundDataType @@ -161,13 +180,19 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co void ChartOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) { + if (m_overlayIndex == 0) { + CaretAssertMessage(0, "ChartOverlay::setChartTwoCompoundDataType() should not be called " + " for first overlay"); + return; + } +// do for overlay zero ?? + if (chartCompoundDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { CaretAssert(m_chartDataType == chartCompoundDataType.getChartDataType()); } m_chartCompoundDataType = chartCompoundDataType; } - /** * @return Enabled status for this surface overlay. */ @@ -201,8 +226,9 @@ ChartOverlay::copyData(const ChartOverlay* overlay) /* * These members are not copied since they * identify the overlay: - * name - * overlayIndex + * m_parentChartOverlaySet + * m_name + * m_overlayIndex * */ m_enabled = overlay->m_enabled; @@ -223,7 +249,8 @@ ChartOverlay::copyData(const ChartOverlay* overlay) void ChartOverlay::swapData(ChartOverlay* overlay) { - std::unique_ptr swapOverlay = std::unique_ptr(new ChartOverlay(overlay->m_chartDataType, + std::unique_ptr swapOverlay = std::unique_ptr(new ChartOverlay(m_parentChartOverlaySet, + overlay->m_chartDataType, overlay->m_overlayIndex)); swapOverlay->copyData(overlay); @@ -337,7 +364,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, if (m_chartDataType == compoundType.getChartDataType()) { if (m_overlayIndex == 0) { /* - * The first overlay displays all files that match the + * The first overlay displays ALL files that match the * enumerated chart type */ useIt = true; @@ -422,6 +449,20 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, // selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); } + + /* + * Update the compound data type if this is the FIRST OVERLAY + */ + if (m_overlayIndex == 0) { + if (m_selectedMapFile != NULL) { + m_selectedMapFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, + m_chartCompoundDataType); + } + CaretAssert(m_parentChartOverlaySet); + m_parentChartOverlaySet->firstOverlaySelectionChanged(); + } + //If selected type changes, need to update other overlays in the overlay set with + //the selected data type} } /** @@ -450,6 +491,14 @@ ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; // } } + + /* + * By calling getSelectionData(), it will validate the + * selected file + */ + CaretMappableDataFile* filePointer = NULL; + int32_t mapIndex = -1; + getSelectionData(filePointer, mapIndex); } /** diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index 0b72d7b56..33460603e 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -33,17 +33,21 @@ namespace caret { class AnnotationColorBar; class CaretMappableDataFile; + class ChartOverlaySet; class PlainTextStringBuilder; class SceneClassAssistant; class ChartOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlay(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartOverlay(ChartOverlaySet* parentChartOverlaySet, + const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t overlayIndex); virtual ~ChartOverlay(); + ChartTwoCompoundDataType getChartTwoCompoundDataType() const; + void setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType); AString getName() const; @@ -107,6 +111,9 @@ namespace caret { ChartOverlay& operator=(const ChartOverlay&); + /** Parent chart overlay set (only used by first overlay in the set */ + ChartOverlaySet* m_parentChartOverlaySet; + /** Enumerated Type of charts allowed in this overlay */ const ChartTwoDataTypeEnum::Enum m_chartDataType; diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx index 4c82cb707..0e3cf1987 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartOverlaySet.cxx @@ -66,7 +66,10 @@ m_tabIndex(tabIndex) &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - m_overlays[i] = new ChartOverlay(m_chartDataType, + /* use "this" as parent only for first chart overlay */ + ChartOverlaySet* me = ((i > 0) ? NULL : this); + m_overlays[i] = new ChartOverlay(me, + m_chartDataType, i); } // EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); @@ -94,6 +97,7 @@ void ChartOverlaySet::copyOverlaySet(const ChartOverlaySet* overlaySet) { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->copyData(overlaySet->getOverlay(i)); } m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; @@ -285,6 +289,7 @@ ChartOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) if (m_numberOfDisplayedOverlays > BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays--; for (int32_t i = overlayIndex; i < m_numberOfDisplayedOverlays; i++) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i+1); m_overlays[i]->copyData(m_overlays[i+1]); } } @@ -302,6 +307,7 @@ void ChartOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) { if (overlayIndex > 0) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1]); } } @@ -319,6 +325,7 @@ ChartOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) { const int32_t nextOverlayIndex = overlayIndex + 1; if (nextOverlayIndex < m_numberOfDisplayedOverlays) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, nextOverlayIndex); m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex]); } } @@ -466,6 +473,28 @@ ChartOverlaySet::initializeOverlays() // } } +/** + * Called by first overlay when the first overlay's selection changes. + * All other overlays are set to use the same chart compound data type + * so that the charts in the tab are compatible + */ +void +ChartOverlaySet::firstOverlaySelectionChanged() +{ + ChartTwoCompoundDataType cdt = m_overlays[0]->getChartTwoCompoundDataType(); + + std::cout << qPrintable("Chart Overlay in tab " + + AString::number(m_tabIndex + 1) + + ":\n" + + cdt.toString()) << std::endl; + + for (int32_t i = 1; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); + m_overlays[i]->setChartTwoCompoundDataType(cdt); + } +} + + /** * Reset the yoking status of all overlays to off. */ @@ -473,6 +502,7 @@ void ChartOverlaySet::resetOverlayYokingToOff() { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); } } @@ -570,6 +600,7 @@ ChartOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, const int32_t numOverlays = std::min(overlayClassArray->getNumberOfArrayElements(), (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); for (int32_t i = 0; i < numOverlays; i++) { + CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->restoreFromScene(sceneAttributes, overlayClassArray->getClassAtIndex(i)); } diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartOverlaySet.h index 4cebafaf6..2caeb8725 100644 --- a/src/Brain/ChartOverlaySet.h +++ b/src/Brain/ChartOverlaySet.h @@ -106,6 +106,8 @@ namespace caret { ChartOverlaySet& operator=(const ChartOverlaySet&); + void firstOverlaySelectionChanged(); + SceneClassAssistant* m_sceneAssistant; ChartOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; @@ -119,6 +121,8 @@ namespace caret { int32_t m_numberOfDisplayedOverlays; // ADD_NEW_MEMBERS_HERE + + friend class ChartOverlay; }; diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index e167d864b..a6813638c 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -1981,6 +1981,8 @@ ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const return chartDataType; } + + /** * Set the type of chart selected in the given tab. * @@ -2169,6 +2171,28 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const // return chartDataType; } +/** + * Update the chart overlay sets. + * + * @param tabIndex + * Index of the tab. + */ +void +ModelChart::updateChartOverlaySets(const int32_t tabIndex) +{ + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + switch (m_selectedChartTwoDataType[tabIndex]) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } +} + /** * Get the data series chart model selected in the given tab. * diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 54c03e098..1f45479ec 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -158,6 +158,8 @@ namespace caret { const ChartModelTimeSeries* getSelectedTimeSeriesChartModelHelper(const int32_t tabIndex) const; + void updateChartOverlaySets(const int32_t tabIndex); + void saveChartModelsToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass, const std::vector& tabIndices, diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index 65bc31d9f..68108b467 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -299,7 +299,34 @@ ChartTwoCompoundDataType::getMatrixNumberOfColumns() const AString ChartTwoCompoundDataType::toString() const { - return "ChartTwoCompoundDataType"; + const AString indent = " "; + AString text = ("type=" + + ChartTwoDataTypeEnum::toName(m_chartDataType)); + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + text.appendWithNewLine(indent + + "x=units=" + + ChartAxisUnitsEnum::toName(m_lineChartUnitsAxisX)); + text.appendWithNewLine(indent + + "x-elements=" + + AString::number(m_lineChartNumberOfElementsAxisX)); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + text.appendWithNewLine(indent + + "rows=" + + AString::number(m_matrixNumberOfRows)); + text.appendWithNewLine(indent + + "columns=" + + AString::number(m_matrixNumberOfColumns)); + break; + } + + return text; } /** diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 0faf8b567..09bbabcb0 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1233,7 +1233,7 @@ CaretMappableDataFile::getSupportedChartCompoundDataTypes(std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + for (auto& cdt : chartCompoundDataTypes) { + if (cdt.getChartDataType() == chartDataType) { + chartCompoundDataTypeOut = cdt; + return true; + } + } + + /* default constructor is invalid data type */ + chartCompoundDataTypeOut = ChartTwoCompoundDataType(); + return false; +} + /** * @return Charting history if this file charts to lines. */ diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 316d88971..912d0d0a1 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -474,6 +474,9 @@ namespace caret { virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const override; + virtual bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; + virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() override; protected: diff --git a/src/Files/ChartableTwoInterface.h b/src/Files/ChartableTwoInterface.h index cc4a23127..3b6b1065b 100644 --- a/src/Files/ChartableTwoInterface.h +++ b/src/Files/ChartableTwoInterface.h @@ -88,6 +88,21 @@ namespace caret { */ virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const = 0; + /** + * Get the chart compound data type supported by this file that uses the given + * chart data type. + * + * @param chartDataType + * The chart data type. + * @param chartCompoundDataTypeOut + * Output with the chart compound data type. + * @return + * True if there is output chart compound data type is valid. + * False if output chart compound data type is invalid OR if chartDataType is invalid. + */ + virtual bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const = 0; + // /** // * @return Is line series charting enabled for this file in the given tab? // */ diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 2bdeca84f..e1bdc1870 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -55,6 +55,7 @@ #include "BrainBrowserWindowToolBar.h" #include "BrainBrowserWindowToolBarChartAttributes.h" #include "BrainBrowserWindowToolBarChartAxes.h" +#include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" #include "BrainBrowserWindowToolBarClipping.h" #include "BrainBrowserWindowToolBarSlicePlane.h" @@ -330,6 +331,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->chartAxesWidget = createChartAxesWidget(); this->chartAttributesWidget = createChartAttributesWidget(); this->chartTypeWidget = createChartTypeWidget(); + this->chartTwoTypeWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); this->volumeIndicesWidget = this->createVolumeIndicesWidget(); this->modeWidget = this->createModeWidget(); @@ -366,6 +368,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolbarWidgetLayout->addWidget(this->chartTypeWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartTwoTypeWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartAxesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); @@ -1442,6 +1446,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->singleSurfaceSelectionWidget->setVisible(false); this->surfaceMontageSelectionWidget->setVisible(false); this->chartTypeWidget->setVisible(false); + this->chartTwoTypeWidget->setVisible(false); this->chartAxesWidget->setVisible(false); this->chartAttributesWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); @@ -1456,6 +1461,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->singleSurfaceSelectionWidget->setVisible(showSingleSurfaceOptionsWidget); this->surfaceMontageSelectionWidget->setVisible(showSurfaceMontageOptionsWidget); this->chartTypeWidget->setVisible(showChartTypeWidget); + this->chartTwoTypeWidget->setVisible(showChartTypeWidget); this->chartAxesWidget->setVisible(showChartAxesWidget); this->chartAttributesWidget->setVisible(showChartAttributesWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); @@ -2628,7 +2634,7 @@ QWidget* BrainBrowserWindowToolBar::createChartTypeWidget() { m_chartTypeToolBarComponent = new BrainBrowserWindowToolBarChartType(this); - QWidget* w = this->createToolWidget("Chart Type", + QWidget* w = this->createToolWidget("Chart Type (OLD)", m_chartTypeToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, @@ -2637,6 +2643,25 @@ BrainBrowserWindowToolBar::createChartTypeWidget() return w; } +/** + * Create the chart type two widget. + * + * @return + * Widget containing the chart options. + */ +QWidget* +BrainBrowserWindowToolBar::createChartTypeTwoWidget() +{ + m_chartTwoTypeToolBarComponent = new BrainBrowserWindowToolBarChartTwoType(this); + QWidget* w = this->createToolWidget("Chart Type", + m_chartTwoTypeToolBarComponent, + WIDGET_PLACEMENT_LEFT, + WIDGET_PLACEMENT_TOP, + 100); + w->setVisible(false); + return w; +} + /** * Update the chart type widget. * @@ -2651,6 +2676,7 @@ BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabCo } m_chartTypeToolBarComponent->updateContent(browserTabContent); + m_chartTwoTypeToolBarComponent->updateContent(browserTabContent); } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index e8659c2ff..a95174f40 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -52,6 +52,7 @@ namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; + class BrainBrowserWindowToolBarChartTwoType; class BrainBrowserWindowToolBarChartType; class BrainBrowserWindowToolBarClipping; class BrainBrowserWindowToolBarSlicePlane; @@ -142,6 +143,7 @@ namespace caret { QWidget* createChartAxesWidget(); QWidget* createChartAttributesWidget(); QWidget* createChartTypeWidget(); + QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); QWidget* createSurfaceMontageOptionsWidget(); QWidget* createClippingOptionsWidget(); @@ -181,6 +183,7 @@ namespace caret { QWidget* volumeMontageWidget; QWidget* volumePlaneWidget; QWidget* chartTypeWidget; + QWidget* chartTwoTypeWidget; QWidget* chartAxesWidget; QWidget* chartAttributesWidget; @@ -350,6 +353,7 @@ namespace caret { private: BrainBrowserWindowToolBarChartAxes* m_chartAxisToolBarComponent; + BrainBrowserWindowToolBarChartTwoType* m_chartTwoTypeToolBarComponent; BrainBrowserWindowToolBarChartType* m_chartTypeToolBarComponent; BrainBrowserWindowToolBarChartAttributes* m_chartAttributesToolBarComponent; BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; @@ -385,6 +389,7 @@ namespace caret { private: friend class BrainBrowserWindow; friend class BrainBrowserWindowToolBarChartAxes; + friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; friend class BrainBrowserWindowToolBarClipping; friend class BrainBrowserWindowToolBarComponent; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx new file mode 100644 index 000000000..dea26ba7c --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx @@ -0,0 +1,157 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ +#include "BrainBrowserWindowToolBarChartTwoType.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ + +#include +#include +#include + +#include "BrowserTabContent.h" +#include "BrainBrowserWindowToolBar.h" +#include "CaretAssert.h" +#include "ChartModel.h" +#include "EnumComboBoxTemplate.h" +#include "ModelChart.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarChartTwoType + * \brief Chart Component of Brain Browser Window ToolBar + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parentToolBar + * parent toolbar. + */ +BrainBrowserWindowToolBarChartTwoType::BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar) +: BrainBrowserWindowToolBarComponent(parentToolBar), +m_parentToolBar(parentToolBar) +{ + m_chartTypeButtonGroup = new QButtonGroup(this); + + QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); + + std::vector allChartTypes; + ChartTwoDataTypeEnum::getAllEnums(allChartTypes); + + for (auto ct : allChartTypes) { + if (ct == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { + continue; + } + + QRadioButton* rb = new QRadioButton(ChartTwoDataTypeEnum::toGuiName(ct)); + m_chartTypeButtonGroup->addButton(rb, + m_chartTypeRadioButtons.size()); + + radioButtonLayout->addWidget(rb); + + m_chartTypeRadioButtons.push_back(std::make_pair(ct, rb)); + } + + WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); + radioButtonLayout->addStretch(); + + QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), + this, SLOT(chartTypeRadioButtonClicked(int))); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarChartTwoType::~BrainBrowserWindowToolBarChartTwoType() +{ +} + +/** + * Called when a radio button is clicked. + * + * @param buttonIndex + * Index of button that is clicked. + */ +void +BrainBrowserWindowToolBarChartTwoType::chartTypeRadioButtonClicked(int buttonIndex) +{ + CaretAssertVectorIndex(m_chartTypeRadioButtons, buttonIndex); + + ChartTwoDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; + + m_parentToolBar->getTabContentFromSelectedTab(); + BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); + ModelChart* chartModel = btc->getDisplayedChartModel(); + const int32_t tabIndex = btc->getTabNumber(); + chartModel->setSelectedChartDataType(tabIndex, + chartDataType); + + //updateContent(btc); + + invalidateColoringAndUpdateGraphicsWindow(); + m_parentToolBar->updateUserInterface(); +} + +/** + * Update content of this tool bar component. + * + * @param browserTabContent + * Content of the browser tab. + */ +void +BrainBrowserWindowToolBarChartTwoType::updateContent(BrowserTabContent* browserTabContent) +{ + m_chartTypeButtonGroup->blockSignals(true); + + + const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); + if (chartModel != NULL) { + const int32_t tabIndex = browserTabContent->getTabNumber(); + const ChartTwoDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartDataType(tabIndex); + + std::vector validChartDataTypes; + chartModel->getValidChartDataTypes(validChartDataTypes); + + for (auto chartTypeButton : m_chartTypeRadioButtons) { + ChartTwoDataTypeEnum::Enum chartType = chartTypeButton.first; + QRadioButton* radioButton = chartTypeButton.second; + + const bool validTypeFlag = (std::find(validChartDataTypes.begin(), + validChartDataTypes.end(), + chartType) != validChartDataTypes.end()); + radioButton->setEnabled(validTypeFlag); + + if (chartType == selectedChartType) { + radioButton->setChecked(true); + } + } + + } + + m_chartTypeButtonGroup->blockSignals(false); +} + diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h new file mode 100644 index 000000000..b784137f6 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h @@ -0,0 +1,73 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +class QAbstractButton; +class QButtonGroup; +class QRadioButton; + +#include "BrainBrowserWindowToolBarComponent.h" +#include "ChartTwoDataTypeEnum.h" + +namespace caret { + + class EnumComboBoxTemplate; + + class BrainBrowserWindowToolBarChartTwoType : public BrainBrowserWindowToolBarComponent { + Q_OBJECT + + public: + BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar); + + virtual ~BrainBrowserWindowToolBarChartTwoType(); + + virtual void updateContent(BrowserTabContent* browserTabContent); + + private slots: + void chartTypeRadioButtonClicked(int buttonIndex); + + private: + BrainBrowserWindowToolBarChartTwoType(const BrainBrowserWindowToolBarChartTwoType&); + + BrainBrowserWindowToolBarChartTwoType& operator=(const BrainBrowserWindowToolBarChartTwoType&); + + public: + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + BrainBrowserWindowToolBar* m_parentToolBar; + + std::vector > m_chartTypeRadioButtons; + + QButtonGroup* m_chartTypeButtonGroup; + }; + + +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 38ec68383..5ee7d0c52 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -73,6 +73,7 @@ ELSE() BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h + BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h BrainBrowserWindowToolBarComponent.h @@ -256,6 +257,7 @@ BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h +BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h BrainBrowserWindowToolBarComponent.h @@ -463,6 +465,7 @@ BrainBrowserWindowOrientedToolBox.cxx BrainBrowserWindowToolBar.cxx BrainBrowserWindowToolBarChartAttributes.cxx BrainBrowserWindowToolBarChartAxes.cxx +BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx BrainBrowserWindowToolBarComponent.cxx diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartOverlayViewController.cxx index 9f5951298..42f42867a 100644 --- a/src/GuiQt/ChartOverlayViewController.cxx +++ b/src/GuiQt/ChartOverlayViewController.cxx @@ -288,15 +288,16 @@ ChartOverlayViewController::fileComboBoxSelected(int indx) updateOverlaySettingsEditor(); updateViewController(m_chartOverlay); updateGraphicsWindow(); + updateUserInterface(); - if (file != NULL) { - if (file->isVolumeMappable()) { - /* - * Need to update slice indices/coords in toolbar. - */ - EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); - } - } +// if (file != NULL) { +// if (file->isVolumeMappable()) { +// /* +// * Need to update slice indices/coords in toolbar. +// */ +// EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); +// } +// } } /** -- GitLab From 65d031962c866dbab1bad3e660d67e1f6467e402 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 12 Jan 2017 16:30:00 -0600 Subject: [PATCH 182/755] Continuing charting development. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 485 +++++++++++++ .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 105 +++ .../BrainOpenGLChartTwoDrawingInterface.h | 83 +++ src/Brain/BrainOpenGLFixedPipeline.cxx | 17 + src/Brain/BrainOpenGLFixedPipeline.h | 1 + src/Brain/CMakeLists.txt | 3 + src/Brain/ChartOverlay.cxx | 89 ++- src/Brain/ChartOverlay.h | 2 + src/Brain/ModelChart.cxx | 4 +- src/Charting/CMakeLists.txt | 6 + .../ChartTwoHistogramContentTypeEnum.cxx | 373 ++++++++++ .../ChartTwoHistogramContentTypeEnum.h | 104 +++ .../ChartTwoLineSeriesContentTypeEnum.cxx | 377 ++++++++++ .../ChartTwoLineSeriesContentTypeEnum.h | 106 +++ .../ChartTwoMatrixContentTypeEnum.cxx | 376 ++++++++++ src/Charting/ChartTwoMatrixContentTypeEnum.h | 106 +++ src/Common/DeveloperFlagsEnum.cxx | 8 + src/Common/DeveloperFlagsEnum.h | 3 +- src/Files/CMakeLists.txt | 13 + src/Files/CaretMappableDataFile.cxx | 652 +++++++++--------- src/Files/CaretMappableDataFile.h | 22 +- .../ChartableTwoFileDelegateBaseChart.cxx | 247 +++++++ src/Files/ChartableTwoFileDelegateBaseChart.h | 108 +++ ...ChartableTwoFileDelegateHistogramChart.cxx | 117 ++++ .../ChartableTwoFileDelegateHistogramChart.h | 73 ++ ...hartableTwoFileDelegateLineSeriesChart.cxx | 115 +++ .../ChartableTwoFileDelegateLineSeriesChart.h | 74 ++ .../ChartableTwoFileDelegateMatrixChart.cxx | 334 +++++++++ .../ChartableTwoFileDelegateMatrixChart.h | 76 ++ src/Files/ChartableTwoInterface.cxx | 550 ++++++++++++++- src/Files/ChartableTwoInterface.h | 111 ++- .../CiftiConnectivityMatrixParcelFile.cxx | 4 +- src/Files/CiftiMappableDataFile.h | 2 + 33 files changed, 4308 insertions(+), 438 deletions(-) create mode 100644 src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx create mode 100644 src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h create mode 100644 src/Brain/BrainOpenGLChartTwoDrawingInterface.h create mode 100644 src/Charting/ChartTwoHistogramContentTypeEnum.cxx create mode 100644 src/Charting/ChartTwoHistogramContentTypeEnum.h create mode 100644 src/Charting/ChartTwoLineSeriesContentTypeEnum.cxx create mode 100644 src/Charting/ChartTwoLineSeriesContentTypeEnum.h create mode 100644 src/Charting/ChartTwoMatrixContentTypeEnum.cxx create mode 100644 src/Charting/ChartTwoMatrixContentTypeEnum.h create mode 100644 src/Files/ChartableTwoFileDelegateBaseChart.cxx create mode 100644 src/Files/ChartableTwoFileDelegateBaseChart.h create mode 100644 src/Files/ChartableTwoFileDelegateHistogramChart.cxx create mode 100644 src/Files/ChartableTwoFileDelegateHistogramChart.h create mode 100644 src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx create mode 100644 src/Files/ChartableTwoFileDelegateLineSeriesChart.h create mode 100644 src/Files/ChartableTwoFileDelegateMatrixChart.cxx create mode 100644 src/Files/ChartableTwoFileDelegateMatrixChart.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx new file mode 100644 index 000000000..07f432c3a --- /dev/null +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -0,0 +1,485 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ +#include "BrainOpenGLChartTwoDrawingFixedPipeline.h" +#undef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ + +#include "Brain.h" +#include "BrainOpenGLFixedPipeline.h" +#include "BrainOpenGLTextRenderInterface.h" +#include "CaretAssert.h" +#include "ChartMatrixScaleModeEnum.h" +#include "ChartOverlay.h" +#include "ChartOverlaySet.h" +using namespace caret; + + + +/** + * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline + * \brief Drawing of version two charts. + * \ingroup Brain + */ + +/** + * Constructor. + */ +BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline() +: BrainOpenGLChartTwoDrawingInterface() +{ + +} + +/** + * Destructor. + */ +BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipeline() +{ +} + +/** + * Draw charts from a chart overlay. + * + * @param brain + * Brain. + * @param fixedPipelineDrawing + * The fixed pipeline OpenGL drawing. + * @param textRenderer + * Text rendering. + * @param chartOverlaySet + * Chart overlay set that is drawn. + * @param selectionItemDataType + * Selected data type. + * @param viewport + * Viewport for the chart. + * @param tabIndex + * Index of the tab. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrainOpenGLTextRenderInterface* textRenderer, + ChartOverlaySet* chartOverlaySet, + const SelectionItemDataTypeEnum::Enum selectionItemDataType, + const int32_t viewport[4], + const int32_t tabIndex) +{ + m_brain = brain; + m_fixedPipelineDrawing = fixedPipelineDrawing; + m_textRenderer = textRenderer; + m_chartOverlaySet = chartOverlaySet; + m_selectionItemDataType = selectionItemDataType; + m_viewport[0] = viewport[0]; + m_viewport[1] = viewport[1]; + m_viewport[2] = viewport[2]; + m_viewport[3] = viewport[3]; + m_tabIndex = tabIndex; + + + /* + * Check for a 'selection' type mode + */ + m_identificationModeFlag = false; + switch (m_fixedPipelineDrawing->mode) { + case BrainOpenGLFixedPipeline::MODE_DRAWING: + break; + case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: + CaretAssertToDoWarning(); + return; +// if (chartDataSeriesID->isEnabledForSelection() +// || chartFrequencySeriesID->isEnabledForSelection() +// || chartTimeSeriesID->isEnabledForSelection()) { +// m_identificationModeFlag = true; +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// else { +// return; +// } + break; + case BrainOpenGLFixedPipeline::MODE_PROJECTION: + return; + break; + } + + saveStateOfOpenGL(); + + resetIdentification(); + + const int32_t numberOfOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); + if (numberOfOverlays > 0) { + ChartOverlay* topOverlay = chartOverlaySet->getOverlay(0); + if (topOverlay->isEnabled()) { + CaretMappableDataFile* cmdf = NULL; + int32_t mapIndex = -1; + topOverlay->getSelectionData(cmdf, mapIndex); + if (cmdf != NULL) { + const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartDataType(); + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + drawMatrixChart(); + break; + } + } + } + for (int32_t iOverlay = (numberOfOverlays -1); iOverlay >= 0; iOverlay--) { + + } + } + + if (m_identificationModeFlag) { + processIdentification(); + } + + restoreStateOfOpenGL(); +} + +/** + * Draw a matrix chart. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() +{ + glViewport(m_viewport[0], + m_viewport[1], + m_viewport[2], + m_viewport[3]); + + bool applyTransformationsFlag = false; + float panningXY[2] = { 0.0, 0.0 }; + float zooming = 1.0; + float cellWidth = 1.0; + float cellHeight = 1.0; + + /* + * Setup width/height of area in which matrix is drawn with a + * small margin along all of the edges + */ + float margin = 10.0; + if ((m_viewport[2] < (margin * 3.0)) + || (m_viewport[3] < (margin * 3.0))) { + margin = 0.0; + } + const float graphicsWidth = m_viewport[2] - (margin * 2.0); + const float graphicsHeight = m_viewport[3] - (margin * 2.0); + + /* + * First overlay is ALWAYS ON and since all matrices must have + * same number of rows/columns, use first matrix for rows/columns + */ + const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); + CaretAssert(numberOfOverlays > 0); + const ChartOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); + CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); + const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); + const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); + if ((numberOfRows > 0) + && (numberOfCols > 0)) { + cellWidth = graphicsWidth / numberOfCols; + cellHeight = graphicsHeight / numberOfRows; + } + else { + return; + } + + /* + * Set the width and neight of each matrix cell. + */ + //ChartMatrixDisplayProperties* matrixProperties = chartMatrixInterface->getChartMatrixDisplayProperties(m_tabIndex); + //CaretAssert(matrixProperties); + const ChartMatrixScaleModeEnum::Enum scaleMode = ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO; // matrixProperties->getScaleMode(); + switch (scaleMode) { + case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: + /* + * Auto scale 'fills' the matrix region + * and updates the width and height in the + * matrix properties for use in manual mode. + * There is NO zooming or panning for Auto scale. + */ + //cellWidth = graphicsWidth / numberOfCols; + //cellHeight = graphicsHeight / numberOfRows; + + //matrixProperties->setCellWidth(cellWidth); + //matrixProperties->setCellHeight(cellHeight); + break; + case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: + /* + * Use the cell width and height for manual mode + * and allow both panning and zooming. + */ + //cellWidth = matrixProperties->getCellWidth(); + //cellHeight = matrixProperties->getCellHeight(); + + //matrixProperties->getViewPanning(panningXY); + //zooming = matrixProperties->getViewZooming(); + //applyTransformationsFlag = true; + break; + } + /* + * Set the coordinates for the area in which the matrix is drawn. + */ + const float xMin = -margin; + const float xMax = graphicsWidth + margin; + const float yMin = -margin; + const float yMax = graphicsHeight + margin; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(xMin, xMax, + yMin, yMax, + -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (applyTransformationsFlag) { + glTranslatef(panningXY[0], + panningXY[1], + 0.0); + + const float chartWidth = cellWidth * numberOfCols; + const float chartHeight = cellHeight * numberOfRows; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(zooming, + zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { + const ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + if (chartOverlay->isEnabled()) { + const ChartTwoCompoundDataType cdt = chartOverlay->getChartTwoCompoundDataType(); + CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); + const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); + const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); + if ((numberOfRows > 0) + && (numberOfCols > 0)) { + /* + * Auto scale 'fills' the matrix region + * and updates the width and height in the + * matrix properties for use in manual mode. + * There is NO zooming or panning for Auto scale. + */ + cellWidth = graphicsWidth / numberOfCols; + cellHeight = graphicsHeight / numberOfRows; + } + } + } +} + + +/** + * Save the state of OpenGL. + * Copied from Qt's qgl.cpp, qt_save_gl_state(). + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::saveStateOfOpenGL() +{ + glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glShadeModel(GL_FLAT); + glDisable(GL_LIGHTING); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); +} + +/** + * Restore the state of OpenGL. + * Copied from Qt's qgl.cpp, qt_restore_gl_state(). + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() +{ + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + glPopClientAttrib(); + +} + +/** + * Reset identification. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() +{ + m_identificationIndices.clear(); + + if (m_identificationModeFlag) { + const int32_t estimatedNumberOfItems = 1000; + m_identificationIndices.reserve(estimatedNumberOfItems); + } +} + +/** + * Process identification. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::processIdentification() +{ + CaretAssertToDoWarning(); + +// int32_t identifiedItemIndex; +// float depth = -1.0; +// +// if (m_chartModelDataSeriesBeingDrawnForIdentification != NULL) { +// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// identifiedItemIndex, +// depth); +// if (identifiedItemIndex >= 0) { +// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; +// const int32_t chartDataIndex = m_identificationIndices[idIndex]; +// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; +// +// SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); +// if (chartDataSeriesID->isOtherScreenDepthCloserToViewer(depth)) { +// ChartDataCartesian* chartDataCartesian = +// dynamic_cast(m_chartModelDataSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); +// CaretAssert(chartDataCartesian); +// chartDataSeriesID->setChart(m_chartModelDataSeriesBeingDrawnForIdentification, +// chartDataCartesian, +// chartLineIndex); +// +// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); +// const float lineXYZ[3] = { +// chartPoint->getX(), +// chartPoint->getY(), +// 0.0 +// }; +// +// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartDataSeriesID, +// lineXYZ); +// } +// } +// } +// else if (m_chartModelFrequencySeriesBeingDrawnForIdentification != NULL) { +// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// identifiedItemIndex, +// depth); +// if (identifiedItemIndex >= 0) { +// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; +// const int32_t chartDataIndex = m_identificationIndices[idIndex]; +// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; +// +// SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); +// if (chartFrequencySeriesID->isOtherScreenDepthCloserToViewer(depth)) { +// ChartDataCartesian* chartDataCartesian = +// dynamic_cast(m_chartModelFrequencySeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); +// CaretAssert(chartDataCartesian); +// chartFrequencySeriesID->setChart(m_chartModelFrequencySeriesBeingDrawnForIdentification, +// chartDataCartesian, +// chartLineIndex); +// +// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); +// const float lineXYZ[3] = { +// chartPoint->getX(), +// chartPoint->getY(), +// 0.0 +// }; +// +// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartFrequencySeriesID, +// lineXYZ); +// } +// } +// } +// else if (m_chartModelTimeSeriesBeingDrawnForIdentification != NULL) { +// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// identifiedItemIndex, +// depth); +// if (identifiedItemIndex >= 0) { +// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; +// const int32_t chartDataIndex = m_identificationIndices[idIndex]; +// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; +// +// SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); +// if (chartTimeSeriesID->isOtherScreenDepthCloserToViewer(depth)) { +// ChartDataCartesian* chartDataCartesian = +// dynamic_cast(m_chartModelTimeSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); +// CaretAssert(chartDataCartesian); +// chartTimeSeriesID->setChart(m_chartModelTimeSeriesBeingDrawnForIdentification, +// chartDataCartesian, +// chartLineIndex); +// +// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); +// const float lineXYZ[3] = { +// chartPoint->getX(), +// chartPoint->getY(), +// 0.0 +// }; +// +// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartTimeSeriesID, +// lineXYZ); +// } +// } +// } +// else if (m_chartableMatrixInterfaceBeingDrawnForIdentification != NULL) { +// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartableMatrixSelectionTypeForIdentification, +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// identifiedItemIndex, +// depth); +// if (identifiedItemIndex >= 0) { +// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; +// const int32_t rowIndex = m_identificationIndices[idIndex]; +// const int32_t columnIndex = m_identificationIndices[idIndex + 1]; +// +// SelectionItemChartMatrix* chartMatrixID = m_brain->getSelectionManager()->getChartMatrixIdentification(); +// if (chartMatrixID->isOtherScreenDepthCloserToViewer(depth)) { +// chartMatrixID->setChartMatrix(m_chartableMatrixInterfaceBeingDrawnForIdentification, +// rowIndex, +// columnIndex); +// } +// } +// } +} diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h new file mode 100644 index 000000000..0e039d7e0 --- /dev/null +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -0,0 +1,105 @@ +#ifndef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ +#define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "BrainOpenGLChartTwoDrawingInterface.h" + + + +namespace caret { + + class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { + + public: + BrainOpenGLChartTwoDrawingFixedPipeline(); + + virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); + + virtual void drawChartOverlaySet(Brain* brain, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrainOpenGLTextRenderInterface* textRenderer, + ChartOverlaySet* chartOverlaySet, + const SelectionItemDataTypeEnum::Enum selectionItemDataType, + const int32_t viewport[4], + const int32_t tabIndex) override; + + // ADD_NEW_METHODS_HERE + + private: +// class Margins { +// public: +// Margins(const double defaultSize) { +// m_bottom = defaultSize; +// m_left = defaultSize; +// m_right = defaultSize; +// m_top = defaultSize; +// } +// +// double m_bottom; +// double m_left; +// double m_right; +// double m_top; +// }; + + BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); + + BrainOpenGLChartTwoDrawingFixedPipeline& operator=(const BrainOpenGLChartTwoDrawingFixedPipeline&); + + void restoreStateOfOpenGL(); + + void saveStateOfOpenGL(); + + void resetIdentification(); + + void processIdentification(); + + void drawMatrixChart(); + + Brain* m_brain; + + BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; + + BrainOpenGLTextRenderInterface* m_textRenderer; + + ChartOverlaySet* m_chartOverlaySet; + + SelectionItemDataTypeEnum::Enum m_selectionItemDataType; + + int32_t m_viewport[4]; + + int32_t m_tabIndex; + + std::vector m_identificationIndices; + + bool m_identificationModeFlag; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ + // +#endif // __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ + +} // namespace +#endif //__BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h new file mode 100644 index 000000000..2736481a0 --- /dev/null +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -0,0 +1,83 @@ +#ifndef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ +#define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + + +#include "SelectionItemDataTypeEnum.h" + +namespace caret { + + class Brain; + class BrainOpenGLFixedPipeline; + class BrainOpenGLTextRenderInterface; + class ChartOverlaySet; + + class BrainOpenGLChartTwoDrawingInterface { + + public: + BrainOpenGLChartTwoDrawingInterface() { } + + virtual ~BrainOpenGLChartTwoDrawingInterface() { } + + /** + * Draw charts from a chart overlay. + * + * @param brain + * Brain. + * @param fixedPipelineDrawing + * The fixed pipeline OpenGL drawing. + * @param viewport + * Viewport for the chart. + * @param textRenderer + * Text rendering. + * @param chartOverlaySet + * Chart overlay set that is drawn. + * @param selectionItemDataType + * Selected data type. + * @param tabIndex + * Index of the tab. + */ + virtual void drawChartOverlaySet(Brain* brain, + BrainOpenGLFixedPipeline* fixedPipelineDrawing, + BrainOpenGLTextRenderInterface* textRenderer, + ChartOverlaySet* chartOverlaySet, + const SelectionItemDataTypeEnum::Enum selectionItemDataType, + const int32_t viewport[4], + const int32_t tabIndex) = 0; + + + // ADD_NEW_METHODS_HERE + + private: + BrainOpenGLChartTwoDrawingInterface(const BrainOpenGLChartTwoDrawingInterface&); + + BrainOpenGLChartTwoDrawingInterface& operator=(const BrainOpenGLChartTwoDrawingInterface&); + + // ADD_NEW_MEMBERS_HERE + + }; + + +} // namespace +#endif //__BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 82f9bc9ec..5256e476d 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -43,6 +43,7 @@ #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLChartDrawingFixedPipeline.h" +#include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLTextureManager.h" #include "BrainOpenGLVolumeObliqueSliceDrawing.h" @@ -68,6 +69,7 @@ #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" +#include "ChartOverlaySet.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" @@ -5277,10 +5279,25 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, ModelChart* chartModel, const int32_t viewport[4]) { + CaretAssert(browserTabContent); CaretAssert(chartModel); const int32_t tabIndex = browserTabContent->getTabNumber(); + + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING)) { + BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; + + chartDrawing.drawChartOverlaySet(m_brain, + this, + getTextRenderer(), + chartModel->getChartOverlaySet(tabIndex), + SelectionItemDataTypeEnum::CHART_DATA_SERIES, + viewport, + tabIndex); + return; + } + ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; const ChartOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 3934f166a..808449efc 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -623,6 +623,7 @@ namespace caret { friend class BrainOpenGLAnnotationDrawingFixedPipeline; friend class BrainOpenGLChartDrawingFixedPipeline; + friend class BrainOpenGLChartTwoDrawingFixedPipeline; friend class BrainOpenGLVolumeObliqueSliceDrawing; friend class BrainOpenGLVolumeSliceDrawing; friend class OldBrainOpenGLVolumeSliceDrawing; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index c7e160509..7a48b5b5c 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -59,6 +59,8 @@ BrainOpenGL.h BrainOpenGLAnnotationDrawingFixedPipeline.h BrainOpenGLChartDrawingInterface.h BrainOpenGLChartDrawingFixedPipeline.h +BrainOpenGLChartTwoDrawingFixedPipeline.h +BrainOpenGLChartTwoDrawingInterface.h BrainOpenGLFixedPipeline.h BrainOpenGLPrimitiveDrawing.h BrainOpenGLShape.h @@ -202,6 +204,7 @@ Brain.cxx BrainOpenGL.cxx BrainOpenGLAnnotationDrawingFixedPipeline.cxx BrainOpenGLChartDrawingFixedPipeline.cxx +BrainOpenGLChartTwoDrawingFixedPipeline.cxx BrainOpenGLFixedPipeline.cxx BrainOpenGLPrimitiveDrawing.cxx BrainOpenGLShape.cxx diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index 3d72023dc..1e83acf5f 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -25,7 +25,9 @@ #include "AnnotationColorBar.h" #include "CaretAssert.h" +#include "CaretLogger.h" #include "CaretMappableDataFile.h" +#include "ChartableTwoInterface.h" #include "ChartOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" @@ -160,6 +162,15 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co } } +/** + * @return The chart data type for this chart overlay. + */ +ChartTwoDataTypeEnum::Enum +ChartOverlay::getChartDataType() const +{ + return m_chartDataType; +} + /** * Get the chart compound data type */ @@ -199,6 +210,13 @@ ChartOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartC bool ChartOverlay::isEnabled() const { + /* + * First overlay is ALWAYS enabled + */ + if (m_overlayIndex == 0) { + return true; + } + return m_enabled; } @@ -210,6 +228,13 @@ ChartOverlay::isEnabled() const void ChartOverlay::setEnabled(const bool enabled) { + if (m_overlayIndex == 0) { + if ( ! enabled) { + CaretAssertMessage(0, "Request to disable first overlay should NEVER happen"); + CaretLogSevere("Request to disable first overlay should NEVER happen"); + return; + } + } m_enabled = enabled; } @@ -231,7 +256,13 @@ ChartOverlay::copyData(const ChartOverlay* overlay) * m_overlayIndex * */ - m_enabled = overlay->m_enabled; + + /* + * NEVER disable the first overlay + */ + if (m_overlayIndex > 0) { + m_enabled = overlay->m_enabled; + } m_mapYokingGroup = overlay->m_mapYokingGroup; @@ -351,38 +382,38 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, * Use only those data files that meet criteria. */ for (auto mapFile : allDataFiles) { -// for (std::vector::iterator iter = allDataFiles.begin(); -// iter != allDataFiles.end(); -// iter++) { -// CaretMappableDataFile* mapFile = *iter; - bool useIt = false; - - std::vector chartCompoundDataTypes; - mapFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - - for (auto& compoundType : chartCompoundDataTypes) { - if (m_chartDataType == compoundType.getChartDataType()) { - if (m_overlayIndex == 0) { - /* - * The first overlay displays ALL files that match the - * enumerated chart type - */ - useIt = true; - } - else { - if (m_chartCompoundDataType == compoundType) { + CaretAssert(mapFile); + ChartableTwoInterface* chartingFile = dynamic_cast(mapFile); + if (chartingFile != NULL) { + bool useIt = false; + + std::vector chartCompoundDataTypes; + chartingFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + for (auto& compoundType : chartCompoundDataTypes) { + if (m_chartDataType == compoundType.getChartDataType()) { + if (m_overlayIndex == 0) { /* - * If not the first overlay, the enumerated type - * and dimensions must also match + * The first overlay displays ALL files that match the + * enumerated chart type */ useIt = true; } + else { + if (m_chartCompoundDataType == compoundType) { + /* + * If not the first overlay, the enumerated type + * and dimensions must also match + */ + useIt = true; + } + } } } - } - - if (useIt) { - mapFilesOut.push_back(mapFile); + + if (useIt) { + mapFilesOut.push_back(mapFile); + } } } @@ -455,7 +486,9 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, */ if (m_overlayIndex == 0) { if (m_selectedMapFile != NULL) { - m_selectedMapFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, + ChartableTwoInterface* chartFile = dynamic_cast(m_selectedMapFile); + CaretAssert(chartFile); + chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, m_chartCompoundDataType); } CaretAssert(m_parentChartOverlaySet); diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index 33460603e..a9bf88da2 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -46,6 +46,8 @@ namespace caret { virtual ~ChartOverlay(); + ChartTwoDataTypeEnum::Enum getChartDataType() const; + ChartTwoCompoundDataType getChartTwoCompoundDataType() const; void setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType); diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index a6813638c..4b39327f3 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -33,6 +33,7 @@ #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartableLineSeriesRowColumnInterface.h" #include "ChartableMatrixInterface.h" +#include "ChartableTwoInterface.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" @@ -2023,8 +2024,9 @@ ModelChart::getValidChartDataTypes(std::vector& vali std::set chartTypeSet; for (auto mapFile : allDataFiles) { + ChartableTwoInterface* chartFile = dynamic_cast(mapFile); std::vector fileChartTypes; - mapFile->getSupportedChartDataTypes(fileChartTypes); + chartFile->getSupportedChartDataTypes(fileChartTypes); chartTypeSet.insert(fileChartTypes.begin(), fileChartTypes.end()); diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index bec3d0b1e..923fc8643 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -43,6 +43,9 @@ ChartTwoData.h ChartTwoDataCartesian.h ChartTwoDataCartesianHistory.h ChartTwoDataTypeEnum.h +ChartTwoHistogramContentTypeEnum.h +ChartTwoLineSeriesContentTypeEnum.h +ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixViewingTypeEnum.h ChartAxis.cxx @@ -73,6 +76,9 @@ ChartTwoData.cxx ChartTwoDataCartesian.cxx ChartTwoDataCartesianHistory.cxx ChartTwoDataTypeEnum.cxx +ChartTwoHistogramContentTypeEnum.cxx +ChartTwoLineSeriesContentTypeEnum.cxx +ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixViewingTypeEnum.cxx ) diff --git a/src/Charting/ChartTwoHistogramContentTypeEnum.cxx b/src/Charting/ChartTwoHistogramContentTypeEnum.cxx new file mode 100644 index 000000000..395828fe3 --- /dev/null +++ b/src/Charting/ChartTwoHistogramContentTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ +#include "ChartTwoHistogramContentTypeEnum.h" +#undef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoHistogramContentTypeEnum + * \brief Type of content for histograms. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoHistogramContentTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoHistogramContentTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoHistogramContentTypeEnum.h" + * + * Instatiate: + * m_chartTwoHistogramContentTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoHistogramContentTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoHistogramContentTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoHistogramContentTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoHistogramContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoHistogramContentTypeEnum::Enum VARIABLE = m_chartTwoHistogramContentTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoHistogramContentTypeEnum::ChartTwoHistogramContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoHistogramContentTypeEnum::~ChartTwoHistogramContentTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoHistogramContentTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoHistogramContentTypeEnum(HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, + "HISTOGRAM_CONTENT_TYPE_UNSUPPORTED", + "Unsupported")); + + enumData.push_back(ChartTwoHistogramContentTypeEnum(HISTOGRAM_CONTENT_TYPE_MAP_DATA, + "HISTOGRAM_CONTENT_TYPE_MAP_DATA", + "Map Data")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoHistogramContentTypeEnum* +ChartTwoHistogramContentTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoHistogramContentTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoHistogramContentTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoHistogramContentTypeEnum::Enum +ChartTwoHistogramContentTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramContentTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoHistogramContentTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoHistogramContentTypeEnum::Enum +ChartTwoHistogramContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramContentTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoHistogramContentTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoHistogramContentTypeEnum::Enum +ChartTwoHistogramContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramContentTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoHistogramContentTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoHistogramContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoHistogramContentTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoHistogramContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoHistogramContentTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoHistogramContentTypeEnum.h b/src/Charting/ChartTwoHistogramContentTypeEnum.h new file mode 100644 index 000000000..dff74c9de --- /dev/null +++ b/src/Charting/ChartTwoHistogramContentTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ +#define __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoHistogramContentTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Unsupported */ + HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, + /** Map Data Content */ + HISTOGRAM_CONTENT_TYPE_MAP_DATA + }; + + + ~ChartTwoHistogramContentTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoHistogramContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoHistogramContentTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ +std::vector ChartTwoHistogramContentTypeEnum::enumData; +bool ChartTwoHistogramContentTypeEnum::initializedFlag = false; +int32_t ChartTwoHistogramContentTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ diff --git a/src/Charting/ChartTwoLineSeriesContentTypeEnum.cxx b/src/Charting/ChartTwoLineSeriesContentTypeEnum.cxx new file mode 100644 index 000000000..51bbae99b --- /dev/null +++ b/src/Charting/ChartTwoLineSeriesContentTypeEnum.cxx @@ -0,0 +1,377 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ +#include "ChartTwoLineSeriesContentTypeEnum.h" +#undef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoLineSeriesContentTypeEnum + * \brief Type of content for line series charting. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoLineSeriesContentTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoLineSeriesContentTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoLineSeriesContentTypeEnum.h" + * + * Instatiate: + * m_chartTwoLineSeriesContentTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoLineSeriesContentTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoLineSeriesContentTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoLineSeriesContentTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoLineSeriesContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoLineSeriesContentTypeEnum::Enum VARIABLE = m_chartTwoLineSeriesContentTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoLineSeriesContentTypeEnum::ChartTwoLineSeriesContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoLineSeriesContentTypeEnum::~ChartTwoLineSeriesContentTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoLineSeriesContentTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_UNSUPPORTED, + "LINE_SERIES_CONTENT_UNSUPPORTED", + "Unsupported")); + + enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_BRAINORDINATE_DATA, + "LINE_SERIES_CONTENT_BRAINORDINATE_DATA", + "Brainordinate Data")); + + enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_ROW_SCALAR_DATA, + "LINE_SERIES_CONTENT_ROW_SCALAR_DATA", + "Row Scalar Data")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoLineSeriesContentTypeEnum* +ChartTwoLineSeriesContentTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoLineSeriesContentTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoLineSeriesContentTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoLineSeriesContentTypeEnum::Enum +ChartTwoLineSeriesContentTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoLineSeriesContentTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoLineSeriesContentTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoLineSeriesContentTypeEnum::Enum +ChartTwoLineSeriesContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoLineSeriesContentTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoLineSeriesContentTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoLineSeriesContentTypeEnum::Enum +ChartTwoLineSeriesContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoLineSeriesContentTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoLineSeriesContentTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoLineSeriesContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoLineSeriesContentTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoLineSeriesContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoLineSeriesContentTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoLineSeriesContentTypeEnum.h b/src/Charting/ChartTwoLineSeriesContentTypeEnum.h new file mode 100644 index 000000000..525ada68f --- /dev/null +++ b/src/Charting/ChartTwoLineSeriesContentTypeEnum.h @@ -0,0 +1,106 @@ +#ifndef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ +#define __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoLineSeriesContentTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Unsupported */ + LINE_SERIES_CONTENT_UNSUPPORTED, + /** Brainordinate Data Content */ + LINE_SERIES_CONTENT_BRAINORDINATE_DATA, + /** Row Scalars Content */ + LINE_SERIES_CONTENT_ROW_SCALAR_DATA + }; + + + ~ChartTwoLineSeriesContentTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoLineSeriesContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoLineSeriesContentTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ +std::vector ChartTwoLineSeriesContentTypeEnum::enumData; +bool ChartTwoLineSeriesContentTypeEnum::initializedFlag = false; +int32_t ChartTwoLineSeriesContentTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ diff --git a/src/Charting/ChartTwoMatrixContentTypeEnum.cxx b/src/Charting/ChartTwoMatrixContentTypeEnum.cxx new file mode 100644 index 000000000..7f4afc873 --- /dev/null +++ b/src/Charting/ChartTwoMatrixContentTypeEnum.cxx @@ -0,0 +1,376 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ +#include "ChartTwoMatrixContentTypeEnum.h" +#undef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoMatrixContentTypeEnum + * \brief Type of content for matrix charting. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoMatrixDataTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoMatrixDataTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoMatrixContentTypeEnum.h" + * + * Instatiate: + * m_chartTwoMatrixDataTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoMatrixDataTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoMatrixDataTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoMatrixDataTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoMatrixDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoMatrixContentTypeEnum::Enum VARIABLE = m_chartTwoMatrixDataTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoMatrixContentTypeEnum::ChartTwoMatrixContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoMatrixContentTypeEnum::~ChartTwoMatrixContentTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoMatrixContentTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_UNSUPPORTED, + "MATRIX_CONTENT_UNSUPPORTED", + "Unsupported")); + + enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_BRAINORDINATE_MAPPABLE, + "MATRIX_CONTENT_BRAINORDINATE_MAPPABLE", + "Brainordinate Mappable")); + + enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_SERIES, + "MATRIX_CONTENT_SERIES", + "Series")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoMatrixContentTypeEnum* +ChartTwoMatrixContentTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoMatrixContentTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoMatrixContentTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoMatrixContentTypeEnum::Enum +ChartTwoMatrixContentTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixContentTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoMatrixContentTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoMatrixContentTypeEnum::Enum +ChartTwoMatrixContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixContentTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoMatrixContentTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoMatrixContentTypeEnum::Enum +ChartTwoMatrixContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixContentTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoMatrixContentTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoMatrixContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoMatrixContentTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoMatrixContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoMatrixContentTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoMatrixContentTypeEnum.h b/src/Charting/ChartTwoMatrixContentTypeEnum.h new file mode 100644 index 000000000..5f2f70bf7 --- /dev/null +++ b/src/Charting/ChartTwoMatrixContentTypeEnum.h @@ -0,0 +1,106 @@ +#ifndef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ +#define __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoMatrixContentTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Unsupported */ + MATRIX_CONTENT_UNSUPPORTED, + /** Brainordinate mappable content */ + MATRIX_CONTENT_BRAINORDINATE_MAPPABLE, + /** Series content */ + MATRIX_CONTENT_SERIES + }; + + + ~ChartTwoMatrixContentTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoMatrixContentTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoMatrixContentTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ +std::vector ChartTwoMatrixContentTypeEnum::enumData; +bool ChartTwoMatrixContentTypeEnum::initializedFlag = false; +int32_t ChartTwoMatrixContentTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 2da2da524..6e3f17024 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -95,6 +95,9 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, case DEVELOPER_FLAG_UNUSED: this->flagStatus = false; break; + case DEVELOPER_FLAG_NEW_CHARTING: + this->flagStatus = false; + break; } } @@ -119,6 +122,11 @@ DeveloperFlagsEnum::initialize() enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, "DEVELOPER_FLAG_UNUSED", "Developer flag unused")); + + + enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_CHARTING, + "DEVELOPER_FLAG_NEW_CHARTING", + "Developer flag New Charting")); } /** diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index 29de8d76c..3a56879cf 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -35,7 +35,8 @@ public: * Enumerated values. */ enum Enum { - DEVELOPER_FLAG_UNUSED + DEVELOPER_FLAG_UNUSED, + DEVELOPER_FLAG_NEW_CHARTING }; ~DeveloperFlagsEnum(); diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 5be32a6e7..983dbae42 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -44,7 +44,14 @@ ChartableLineSeriesRowColumnInterface.h ChartableMatrixInterface.h ChartableMatrixParcelInterface.h ChartableMatrixSeriesInterface.h + ChartableTwoInterface.h + +ChartableTwoFileDelegateBaseChart.h +ChartableTwoFileDelegateHistogramChart.h +ChartableTwoFileDelegateLineSeriesChart.h +ChartableTwoFileDelegateMatrixChart.h + CiftiBrainordinateDataSeriesFile.h CiftiBrainordinateLabelFile.h CiftiBrainordinateScalarFile.h @@ -163,6 +170,12 @@ CaretVolumeExtension.cxx ChartableLineSeriesInterface.cxx ChartableMatrixInterface.cxx ChartableTwoInterface.cxx + +ChartableTwoFileDelegateBaseChart.cxx +ChartableTwoFileDelegateHistogramChart.cxx +ChartableTwoFileDelegateLineSeriesChart.cxx +ChartableTwoFileDelegateMatrixChart.cxx + CiftiBrainordinateDataSeriesFile.cxx CiftiBrainordinateLabelFile.cxx CiftiBrainordinateScalarFile.cxx diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 09bbabcb0..8ad751c39 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1083,330 +1083,328 @@ CaretMappableDataFile::isMappedWithRGBA() const return false; } -bool CaretMappableDataFile::hasCiftiXML() const -{ - return false; -} - -const CiftiXML CaretMappableDataFile::getCiftiXML() const -{ - return CiftiXML(); -} - -/** - * @return The CaretMappableDataFile that implements this interface. - */ -CaretMappableDataFile* -CaretMappableDataFile::getAsCaretMappableDataFile() -{ - return this; -} - -/** - * @return The CaretMappableDataFile that implements this interface. - */ -const CaretMappableDataFile* -CaretMappableDataFile::getAsCaretMappableDataFile() const -{ - return this; -} - - -/** - * Does this file support any type of charting? - */ -bool -CaretMappableDataFile::isChartingSupported() const -{ - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - - return ( ! chartCompoundDataTypes.empty()); -} - -/** - * Test for support of the given chart data type. - * - * @param chartDataType - * Type of chart data. - * @return - * True if the chart data type is supported, else false. - */ -bool -CaretMappableDataFile::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const -{ - std::vector chartDataTypes; - getSupportedChartDataTypes(chartDataTypes); - - if (std::find(chartDataTypes.begin(), - chartDataTypes.end(), - chartDataType) != chartDataTypes.end()) { - return true; - } - - return false; -} - -/** - * Test for support of the given chart compound data type. - * - * @param chartCompoundDataType - * Type of chart compound data. - * @return - * True if the chart compound data type is supported, else false. - */ -bool -CaretMappableDataFile::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const -{ - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - - for (auto& ccdt : chartCompoundDataTypes) { - if (ccdt == chartCompoundDataType) { - return true; - } - } - - return false; -} - -/** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ -void -CaretMappableDataFile::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const -{ - chartDataTypesOut.clear(); - - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - - for (auto& ccdt : chartCompoundDataTypes) { - chartDataTypesOut.push_back(ccdt.getChartDataType()); - } -} - -/** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ -void -CaretMappableDataFile::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const -{ - chartCompoundDataTypesOut.clear(); - - bool hasHistogramFlag = false; - bool hasBrainordinateLineSeriesFlag = false; - bool hasNoMapsLineSeriesFlag = false; - bool hasMatrixFlag = false; - - switch (getDataFileType()) { - case DataFileTypeEnum::CONNECTIVITY_DENSE: - hasHistogramFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: - hasHistogramFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: - hasHistogramFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL: - hasHistogramFlag = true; - hasMatrixFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: - hasHistogramFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: - //hasMatrixFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - hasMatrixFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - break; - case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: - hasHistogramFlag = true; - hasNoMapsLineSeriesFlag = true; - hasMatrixFlag = true; - break; - case DataFileTypeEnum::ANNOTATION: - break; - case DataFileTypeEnum::BORDER: - break; - case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: - break; - case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: - break; - case DataFileTypeEnum::FOCI: - break; - case DataFileTypeEnum::IMAGE: - break; - case DataFileTypeEnum::LABEL: - break; - case DataFileTypeEnum::METRIC: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - break; - case DataFileTypeEnum::PALETTE: - break; - case DataFileTypeEnum::RGBA: - break; - case DataFileTypeEnum::SCENE: - break; - case DataFileTypeEnum::SPECIFICATION: - break; - case DataFileTypeEnum::SURFACE: - break; - case DataFileTypeEnum::UNKNOWN: - break; - case DataFileTypeEnum::VOLUME: - hasHistogramFlag = true; - hasBrainordinateLineSeriesFlag = true; - break; - } - - if (hasHistogramFlag) { - if (getNumberOfMaps() > 0) { - chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); - } - } - - if (hasBrainordinateLineSeriesFlag) { - if (getNumberOfMaps() > 1) { - const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); - ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; - switch (mapUnits) { - case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: - CaretAssert(0); - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: - break; - } - const int32_t numMaps = getNumberOfMaps(); - chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, - numMaps)); - } - } - - if (hasNoMapsLineSeriesFlag) { - const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); - CaretAssert(ciftiMapFile); - std::vector dims; - ciftiMapFile->getMapDimensions(dims); - CaretAssertVectorIndex(dims, 1); - const int32_t numCols = dims[0]; - //const int32_t numRows = dims[1]; - - if (numCols > 1) { - const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); - ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; - switch (mapUnits) { - case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: - CaretAssert(0); - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: - break; - } - chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, - numCols)); - } - } - - if (hasMatrixFlag) { - const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); - CaretAssert(ciftiMapFile); - std::vector dims; - ciftiMapFile->getMapDimensions(dims); - CaretAssertVectorIndex(dims, 1); - const int32_t numCols = dims[0]; - const int32_t numRows = dims[1]; - - chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, - numCols)); - } -} - -/** - * Get the chart compound data type supported by this file that uses the given - * chart data type. - * - * @param chartDataType - * The chart data type. - * @param chartCompoundDataTypeOut - * Output with the chart compound data type. - * @return - * True if there is output chart compound data type is valid. - * False if output chart compound data type is invalid OR if chartDataType is invalid. - */ -bool -CaretMappableDataFile::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - ChartTwoCompoundDataType& chartCompoundDataTypeOut) const -{ - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - for (auto& cdt : chartCompoundDataTypes) { - if (cdt.getChartDataType() == chartDataType) { - chartCompoundDataTypeOut = cdt; - return true; - } - } - - /* default constructor is invalid data type */ - chartCompoundDataTypeOut = ChartTwoCompoundDataType(); - return false; -} - -/** - * @return Charting history if this file charts to lines. - */ -ChartTwoDataCartesianHistory* -CaretMappableDataFile::getLineSeriesChartingHistory() -{ - return m_lineChartHistory.get(); -} - - +//bool CaretMappableDataFile::hasCiftiXML() const +//{ +// return false; +//} +// +//const CiftiXML CaretMappableDataFile::getCiftiXML() const +//{ +// return CiftiXML(); +//} +// +///** +// * @return The CaretMappableDataFile that implements this interface. +// */ +//CaretMappableDataFile* +//CaretMappableDataFile::getAsCaretMappableDataFile() +//{ +// return this; +//} +// +///** +// * @return The CaretMappableDataFile that implements this interface. +// */ +//const CaretMappableDataFile* +//CaretMappableDataFile::getAsCaretMappableDataFile() const +//{ +// return this; +//} +// +// +///** +// * Does this file support any type of charting? +// */ +//bool +//CaretMappableDataFile::isChartingSupported() const +//{ +// std::vector chartCompoundDataTypes; +// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); +// +// return ( ! chartCompoundDataTypes.empty()); +//} +// +///** +// * Test for support of the given chart data type. +// * +// * @param chartDataType +// * Type of chart data. +// * @return +// * True if the chart data type is supported, else false. +// */ +//bool +//CaretMappableDataFile::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const +//{ +// std::vector chartDataTypes; +// getSupportedChartDataTypes(chartDataTypes); +// +// if (std::find(chartDataTypes.begin(), +// chartDataTypes.end(), +// chartDataType) != chartDataTypes.end()) { +// return true; +// } +// +// return false; +//} +// +///** +// * Test for support of the given chart compound data type. +// * +// * @param chartCompoundDataType +// * Type of chart compound data. +// * @return +// * True if the chart compound data type is supported, else false. +// */ +//bool +//CaretMappableDataFile::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const +//{ +// std::vector chartCompoundDataTypes; +// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); +// +// for (auto& ccdt : chartCompoundDataTypes) { +// if (ccdt == chartCompoundDataType) { +// return true; +// } +// } +// +// return false; +//} +// +///** +// * Get chart data types supported by this file. +// * +// * @param chartDataTypesOut +// * Output containing all chart data types supported by this data file. +// */ +//void +//CaretMappableDataFile::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const +//{ +// chartDataTypesOut.clear(); +// +// std::vector chartCompoundDataTypes; +// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); +// +// for (auto& ccdt : chartCompoundDataTypes) { +// chartDataTypesOut.push_back(ccdt.getChartDataType()); +// } +//} +// +///** +// * Get chart data types supported by this file. +// * +// * @param chartDataTypesOut +// * Output containing all chart data types supported by this data file. +// */ +//void +//CaretMappableDataFile::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const +//{ +// chartCompoundDataTypesOut.clear(); +// +// bool hasHistogramFlag = false; +// bool hasBrainordinateLineSeriesFlag = false; +// bool hasNoMapsLineSeriesFlag = false; +// bool hasMatrixFlag = false; +// +// switch (getDataFileType()) { +// case DataFileTypeEnum::CONNECTIVITY_DENSE: +// hasHistogramFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: +// hasHistogramFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: +// hasHistogramFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL: +// hasHistogramFlag = true; +// hasMatrixFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: +// hasHistogramFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: +// //hasMatrixFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// hasMatrixFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// break; +// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: +// hasHistogramFlag = true; +// hasNoMapsLineSeriesFlag = true; +// hasMatrixFlag = true; +// break; +// case DataFileTypeEnum::ANNOTATION: +// break; +// case DataFileTypeEnum::BORDER: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: +// break; +// case DataFileTypeEnum::FOCI: +// break; +// case DataFileTypeEnum::IMAGE: +// break; +// case DataFileTypeEnum::LABEL: +// break; +// case DataFileTypeEnum::METRIC: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// break; +// case DataFileTypeEnum::PALETTE: +// break; +// case DataFileTypeEnum::RGBA: +// break; +// case DataFileTypeEnum::SCENE: +// break; +// case DataFileTypeEnum::SPECIFICATION: +// break; +// case DataFileTypeEnum::SURFACE: +// break; +// case DataFileTypeEnum::UNKNOWN: +// break; +// case DataFileTypeEnum::VOLUME: +// hasHistogramFlag = true; +// hasBrainordinateLineSeriesFlag = true; +// break; +// } +// +// if (hasHistogramFlag) { +// if (getNumberOfMaps() > 0) { +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); +// } +// } +// +// if (hasBrainordinateLineSeriesFlag) { +// if (getNumberOfMaps() > 1) { +// const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// const int32_t numMaps = getNumberOfMaps(); +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numMaps)); +// } +// } +// +// if (hasNoMapsLineSeriesFlag) { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// //const int32_t numRows = dims[1]; +// +// if (numCols > 1) { +// const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numCols)); +// } +// } +// +// if (hasMatrixFlag) { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// const int32_t numRows = dims[1]; +// +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, +// numCols)); +// } +//} +// +///** +// * Get the chart compound data type supported by this file that uses the given +// * chart data type. +// * +// * @param chartDataType +// * The chart data type. +// * @param chartCompoundDataTypeOut +// * Output with the chart compound data type. +// * @return +// * True if there is output chart compound data type is valid. +// * False if output chart compound data type is invalid OR if chartDataType is invalid. +// */ +//bool +//CaretMappableDataFile::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, +// ChartTwoCompoundDataType& chartCompoundDataTypeOut) const +//{ +// std::vector chartCompoundDataTypes; +// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); +// for (auto& cdt : chartCompoundDataTypes) { +// if (cdt.getChartDataType() == chartDataType) { +// chartCompoundDataTypeOut = cdt; +// return true; +// } +// } +// +// /* default constructor is invalid data type */ +// chartCompoundDataTypeOut = ChartTwoCompoundDataType(); +// return false; +//} +// +///** +// * @return Charting history if this file charts to lines. +// */ +//ChartTwoDataCartesianHistory* +//CaretMappableDataFile::getLineSeriesChartingHistory() +//{ +// return m_lineChartHistory.get(); +//} diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 912d0d0a1..894ebd17b 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -25,7 +25,6 @@ #include "CaretDataFile.h" #include "ChartOneDataTypeEnum.h" -#include "ChartableTwoInterface.h" #include "CaretPointer.h" #include "NiftiEnums.h" #include "PaletteNormalizationModeEnum.h" @@ -58,7 +57,7 @@ namespace caret { * Note that Caret5 used the term 'column'. */ - class CaretMappableDataFile : public CaretDataFile, public ChartableTwoInterface { + class CaretMappableDataFile : public CaretDataFile { public: CaretMappableDataFile(const DataFileTypeEnum::Enum dataFileType); @@ -460,25 +459,6 @@ namespace caret { const LabelDrawingProperties* getLabelDrawingProperties() const; - virtual CaretMappableDataFile* getAsCaretMappableDataFile() override; - - virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const override; - - virtual bool isChartingSupported() const override; - - virtual bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const override; - - virtual bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const override; - - virtual void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const override; - - virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const override; - - virtual bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; - - virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() override; - protected: CaretMappableDataFile(const CaretMappableDataFile&); diff --git a/src/Files/ChartableTwoFileDelegateBaseChart.cxx b/src/Files/ChartableTwoFileDelegateBaseChart.cxx new file mode 100644 index 000000000..2ae467dda --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateBaseChart.cxx @@ -0,0 +1,247 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ +#include "ChartableTwoFileDelegateBaseChart.h" +#undef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "EventManager.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileDelegateBaseChart + * \brief Base class for File Charting Delegates. + * \ingroup Files + * + * The first version of charting used interfaces for each + * charting type. This required some files to subclass + * several interfaces and significant modification to any + * class that supported charting. + * + * The reasons for using this 'delegate' are to avoid + * extensive modifications to many file classes and to + * avoid name clashes with the version one of charting. + * Some of the original charting needs to be preserved + * to support loading of older scenes. + */ + +#include "CaretMappableDataFile.h" +#include "CiftiMappableDataFile.h" + +/** + * Constructor. + * + * @param chartType + * Type of chart provided by this delegate. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileDelegateBaseChart::ChartableTwoFileDelegateBaseChart(const ChartTwoDataTypeEnum::Enum chartType, + CaretMappableDataFile* parentCaretMappableDataFile) +: CaretObject(), +m_chartType(chartType), +m_parentCaretMappableDataFile(parentCaretMappableDataFile) +{ + CaretAssert(m_chartType != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID); + CaretAssert(m_parentCaretMappableDataFile); + + /* will be NULL if file is not a cifti mappable file */ + m_parentCiftiMappableDataFile = dynamic_cast(m_parentCaretMappableDataFile); + + m_sceneAssistant = new SceneClassAssistant(); + +// EventManager::get()->addEventListener(this, EventTypeEnum::); +} + +//ChartableTwoFileDelegateBaseChart::ChartableTwoFileDelegateBaseChart() +//{ +// +//} + +/** + * Destructor. + */ +ChartableTwoFileDelegateBaseChart::~ChartableTwoFileDelegateBaseChart() +{ + EventManager::get()->removeAllEventsFromListener(this); + delete m_sceneAssistant; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartableTwoFileDelegateBaseChart::toString() const +{ + return "ChartableTwoFileDelegateBaseChart"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartableTwoFileDelegateBaseChart::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + +/** + * @return The CaretMappableDataFile that provided this delegate. + */ +CaretMappableDataFile* +ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() +{ + return m_parentCaretMappableDataFile; +} + +/** + * @return The CaretMappableDataFile that provided this delegate. + */ +const CaretMappableDataFile* +ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() const +{ + return m_parentCaretMappableDataFile; +} + +/** + * @return The CiftiMappableDataFile that provided this delegate. + * NULL is returned if not a CiftiMappableDataFile. + */ +CiftiMappableDataFile* +ChartableTwoFileDelegateBaseChart::getCiftiMappableDataFile() +{ + return m_parentCiftiMappableDataFile; +} + +/** + * @return The CiftiMappableDataFile that provided this delegate. + * NULL is returned if not a CiftiMappableDataFile. + */ +const CiftiMappableDataFile* +ChartableTwoFileDelegateBaseChart::getCiftiMappableDataFile() const +{ + return m_parentCiftiMappableDataFile; +} + +ChartTwoDataTypeEnum::Enum +ChartableTwoFileDelegateBaseChart::getChartDataType() const +{ + return m_chartType; +} + +/** + * @return Chart compound data type supported by subclass. + */ +ChartTwoCompoundDataType +ChartableTwoFileDelegateBaseChart::getChartCompoundDataType() const +{ + CaretAssertMessage((m_compoundChartDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID), + "Data type is invalid, was updateChartCompoundDataTypeAfterFileChanges() called by " + "implementing class."); + return m_compoundChartDataType; +} + +/** + * Set the chart compound data type. Subclasses of this base class MUST + * call this method whenever the content of the delegatee file changes. + * + * @param compoundChartDataType + * Updated chart compound data type. Its basic data type MUST + * match the data type passed to the constructor. + */ +void +ChartableTwoFileDelegateBaseChart::updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) +{ + CaretAssert(m_chartType == compoundChartDataType.getChartDataType()); + + m_compoundChartDataType = compoundChartDataType; +} + + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartableTwoFileDelegateBaseChart::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartableTwoFileDelegateBaseChart", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + saveSubClassDataToScene(sceneAttributes, + sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartableTwoFileDelegateBaseChart::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + restoreSubClassDataFromScene(sceneAttributes, + sceneClass); + +} + diff --git a/src/Files/ChartableTwoFileDelegateBaseChart.h b/src/Files/ChartableTwoFileDelegateBaseChart.h new file mode 100644 index 000000000..3968feafa --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateBaseChart.h @@ -0,0 +1,108 @@ +#ifndef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ +#define __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretObject.h" +#include "ChartTwoCompoundDataType.h" +#include "EventListenerInterface.h" +#include "SceneableInterface.h" + + +namespace caret { + class CaretMappableDataFile; + class CiftiMappableDataFile; + class SceneClassAssistant; + + class ChartableTwoFileDelegateBaseChart : public CaretObject, public EventListenerInterface, public SceneableInterface { + + protected: + ChartableTwoFileDelegateBaseChart(const ChartTwoDataTypeEnum::Enum chartType, + CaretMappableDataFile* parentCaretMappableDataFile); + + public: + virtual ~ChartableTwoFileDelegateBaseChart(); + + CaretMappableDataFile* getCaretMappableDataFile(); + + const CaretMappableDataFile* getCaretMappableDataFile() const; + + CiftiMappableDataFile* getCiftiMappableDataFile(); + + const CiftiMappableDataFile* getCiftiMappableDataFile() const; + + ChartTwoDataTypeEnum::Enum getChartDataType() const; + + ChartTwoCompoundDataType getChartCompoundDataType() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const override; + + virtual void receiveEvent(Event* event) override; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) override; + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + + + + + + protected: + void updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType); + + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) = 0; + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) = 0; + + private: + ChartableTwoFileDelegateBaseChart() = delete; + + ChartableTwoFileDelegateBaseChart(const ChartableTwoFileDelegateBaseChart&); + + ChartableTwoFileDelegateBaseChart& operator=(const ChartableTwoFileDelegateBaseChart&); + + const ChartTwoDataTypeEnum::Enum m_chartType; + + CaretMappableDataFile* m_parentCaretMappableDataFile; + + CiftiMappableDataFile* m_parentCiftiMappableDataFile; + + SceneClassAssistant* m_sceneAssistant; + + ChartTwoCompoundDataType m_compoundChartDataType; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ + // +#endif // __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ diff --git a/src/Files/ChartableTwoFileDelegateHistogramChart.cxx b/src/Files/ChartableTwoFileDelegateHistogramChart.cxx new file mode 100644 index 000000000..735a14af0 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateHistogramChart.cxx @@ -0,0 +1,117 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ +#include "ChartableTwoFileDelegateHistogramChart.h" +#undef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileDelegateHistogramChart + * \brief Implementation of base chart delegate for histogram charts. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param histogramContentType + * Content of histogram. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileDelegateHistogramChart::ChartableTwoFileDelegateHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, + CaretMappableDataFile* parentCaretMappableDataFile) +: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, + parentCaretMappableDataFile), +m_histogramContentType(histogramContentType) +{ + CaretAssert(m_histogramContentType != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED); + m_sceneAssistant = new SceneClassAssistant(); + +} + +/** + * Destructor. + */ +ChartableTwoFileDelegateHistogramChart::~ChartableTwoFileDelegateHistogramChart() +{ + delete m_sceneAssistant; +} + +/** + * @return Content type of histogram. + */ +ChartTwoHistogramContentTypeEnum::Enum +ChartableTwoFileDelegateHistogramChart::getHistogramContentType() const +{ + return m_histogramContentType; +} + + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartableTwoFileDelegateHistogramChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartableTwoFileDelegateHistogramChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + diff --git a/src/Files/ChartableTwoFileDelegateHistogramChart.h b/src/Files/ChartableTwoFileDelegateHistogramChart.h new file mode 100644 index 000000000..19ed4b474 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateHistogramChart.h @@ -0,0 +1,73 @@ +#ifndef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ +#define __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "ChartableTwoFileDelegateBaseChart.h" +#include "ChartTwoHistogramContentTypeEnum.h" + + +namespace caret { + + class ChartableTwoFileDelegateHistogramChart : public ChartableTwoFileDelegateBaseChart { + + public: + ChartableTwoFileDelegateHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, + CaretMappableDataFile* parentCaretMappableDataFile); + + virtual ~ChartableTwoFileDelegateHistogramChart(); + + ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; + + // ADD_NEW_METHODS_HERE + + + + + + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + private: + ChartableTwoFileDelegateHistogramChart(const ChartableTwoFileDelegateHistogramChart&); + + ChartableTwoFileDelegateHistogramChart& operator=(const ChartableTwoFileDelegateHistogramChart&); + + SceneClassAssistant* m_sceneAssistant; + + const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ + // +#endif // __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ diff --git a/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx b/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx new file mode 100644 index 000000000..72f3a7e0a --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx @@ -0,0 +1,115 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ +#include "ChartableTwoFileDelegateLineSeriesChart.h" +#undef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileDelegateLineSeriesChart + * \brief Implementation of base chart delegate for line series charts. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param lineSeriesContentType + * Content type of the line series data. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileDelegateLineSeriesChart::ChartableTwoFileDelegateLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, + CaretMappableDataFile* parentCaretMappableDataFile) +: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + parentCaretMappableDataFile), +m_lineSeriesContentType(lineSeriesContentType) +{ + CaretAssert(m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED); + m_sceneAssistant = new SceneClassAssistant(); + +} + +/** + * Destructor. + */ +ChartableTwoFileDelegateLineSeriesChart::~ChartableTwoFileDelegateLineSeriesChart() +{ + delete m_sceneAssistant; +} + +/** + * @return Content type of the line series data. + */ +ChartTwoLineSeriesContentTypeEnum::Enum +ChartableTwoFileDelegateLineSeriesChart::getLineSeriesContentType() const +{ + return m_lineSeriesContentType; +} + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartableTwoFileDelegateLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartableTwoFileDelegateLineSeriesChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + diff --git a/src/Files/ChartableTwoFileDelegateLineSeriesChart.h b/src/Files/ChartableTwoFileDelegateLineSeriesChart.h new file mode 100644 index 000000000..a64a802ae --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateLineSeriesChart.h @@ -0,0 +1,74 @@ +#ifndef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ +#define __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "ChartableTwoFileDelegateBaseChart.h" +#include "ChartTwoLineSeriesContentTypeEnum.h" + + +namespace caret { + + class ChartableTwoFileDelegateLineSeriesChart : public ChartableTwoFileDelegateBaseChart { + + public: + ChartableTwoFileDelegateLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, + CaretMappableDataFile* parentCaretMappableDataFile); + + virtual ~ChartableTwoFileDelegateLineSeriesChart(); + + ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; + + + // ADD_NEW_METHODS_HERE + + + + + + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + private: + ChartableTwoFileDelegateLineSeriesChart(const ChartableTwoFileDelegateLineSeriesChart&); + + ChartableTwoFileDelegateLineSeriesChart& operator=(const ChartableTwoFileDelegateLineSeriesChart&); + + SceneClassAssistant* m_sceneAssistant; + + const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ + // +#endif // __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ diff --git a/src/Files/ChartableTwoFileDelegateMatrixChart.cxx b/src/Files/ChartableTwoFileDelegateMatrixChart.cxx new file mode 100644 index 000000000..8f437d9c7 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateMatrixChart.cxx @@ -0,0 +1,334 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ +#include "ChartableTwoFileDelegateMatrixChart.h" +#undef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "CiftiConnectivityMatrixParcelFile.h" +#include "CiftiParcelLabelFile.h" +#include "CiftiParcelReordering.h" +#include "CiftiParcelScalarFile.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileDelegateMatrixChart + * \brief Implementation of base chart delegate for matrix charts. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param matrixContentType + * Content type of the matrix. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileDelegateMatrixChart::ChartableTwoFileDelegateMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, + CaretMappableDataFile* parentCaretMappableDataFile) +: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + parentCaretMappableDataFile), +m_matrixContentType(matrixContentType) +{ + CaretAssert(m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED); + m_sceneAssistant = new SceneClassAssistant(); + +} + +/** + * Destructor. + */ +ChartableTwoFileDelegateMatrixChart::~ChartableTwoFileDelegateMatrixChart() +{ + delete m_sceneAssistant; +} + +/** + * @return Content type of the matrix. + */ +ChartTwoMatrixContentTypeEnum::Enum +ChartableTwoFileDelegateMatrixChart::getMatrixContentType() const +{ + return m_matrixContentType; +} + +/** + * Get the matrix dimensions. + * + * @param numberOfRowsOut + * Number of rows in the matrix. + * @param numberOfColumnsOut + * Number of rows in the matrix. + */ +void +ChartableTwoFileDelegateMatrixChart::getMatrixDimensions(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut) const +{ + numberOfRowsOut = 0; + numberOfColumnsOut = 0; + + if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { + return; + } + + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, + numberOfColumnsOut); +} + +/** + * Get the matrix RGBA coloring for this matrix data creator. + * + * @param numberOfRowsOut + * Number of rows in the coloring matrix. + * @param numberOfColumnsOut + * Number of rows in the coloring matrix. + * @param rgbaOut + * RGBA coloring output with number of elements + * (numberOfRowsOut * numberOfColumnsOut * 4). + * @return + * True if data output data is valid, else false. + */ +bool +ChartableTwoFileDelegateMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut, + std::vector& rgbaOut) const +{ + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + + bool useMapFileHelperFlag = false; + bool useMatrixFileHelperFlag = false; + + std::vector parcelReorderedRowIndices; + + switch (ciftiMapFile->getDataFileType()) { + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + { + useMatrixFileHelperFlag = true; + + const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(ciftiMapFile); + CaretAssert(parcelConnFile); + if (parcelConnFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + { + useMapFileHelperFlag = true; + + const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); + CaretAssert(parcelLabelFile); + if (parcelLabelFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + { + useMapFileHelperFlag = true; + + const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); + CaretAssert(parcelScalarFile); + if (parcelScalarFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + useMatrixFileHelperFlag = true; + break; + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + } + + if (( ! useMapFileHelperFlag) + && ( ! useMatrixFileHelperFlag)) { + CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); + return false; + } + + bool validDataFlag = false; + if (useMapFileHelperFlag) { + validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, + numberOfColumnsOut, + parcelReorderedRowIndices, + rgbaOut); + } + else if (useMatrixFileHelperFlag) { + validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, + numberOfColumnsOut, + parcelReorderedRowIndices, + rgbaOut); + } + switch (m_matrixContentType) { + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: + break; + } + + return validDataFlag; +} + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartableTwoFileDelegateMatrixChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartableTwoFileDelegateMatrixChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + diff --git a/src/Files/ChartableTwoFileDelegateMatrixChart.h b/src/Files/ChartableTwoFileDelegateMatrixChart.h new file mode 100644 index 000000000..4df13d254 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegateMatrixChart.h @@ -0,0 +1,76 @@ +#ifndef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ +#define __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "ChartTwoMatrixContentTypeEnum.h" +#include "ChartableTwoFileDelegateBaseChart.h" + +namespace caret { + + class ChartableTwoFileDelegateMatrixChart : public ChartableTwoFileDelegateBaseChart { + + public: + ChartableTwoFileDelegateMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, + CaretMappableDataFile* parentCaretMappableDataFile); + + virtual ~ChartableTwoFileDelegateMatrixChart(); + + ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; + + void getMatrixDimensions(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut) const; + + bool getMatrixDataRGBA(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut, + std::vector& rgbaOut) const; + // ADD_NEW_METHODS_HERE + + + + + + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + private: + ChartableTwoFileDelegateMatrixChart(const ChartableTwoFileDelegateMatrixChart&); + + ChartableTwoFileDelegateMatrixChart& operator=(const ChartableTwoFileDelegateMatrixChart&); + + SceneClassAssistant* m_sceneAssistant; + + const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ + // +#endif // __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ diff --git a/src/Files/ChartableTwoInterface.cxx b/src/Files/ChartableTwoInterface.cxx index d8b2ab537..670e49b94 100644 --- a/src/Files/ChartableTwoInterface.cxx +++ b/src/Files/ChartableTwoInterface.cxx @@ -25,19 +25,32 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" - +#include "CiftiConnectivityMatrixParcelFile.h" +#include "CiftiMappableDataFile.h" +#include "CiftiParcelLabelFile.h" +#include "CiftiParcelReordering.h" +#include "CiftiParcelScalarFile.h" using namespace caret; /** * \class caret::ChartableTwoInterface - * \brief Interface for files that are chartable. + * \brief Interface for files that are chartable. Contains functionality but no data. * \ingroup Files */ /** * Constructor. + * + * @param type of matrix (if any) supported by implementing file. + * + * @param histogramContentType + * Type of histogram chart supported (or not supported) by implementing file. + * @param lineSeriesContentType + * Type of line series chart supported (or not supported) by implementing file. + * @param matrixContentType + * Type of matrix chart supported (or not supported) by implementing file. */ ChartableTwoInterface::ChartableTwoInterface() { @@ -51,3 +64,536 @@ ChartableTwoInterface::~ChartableTwoInterface() { } +///** +// * @return The CaretMappableDataFile that implements this interface. +// * NULL is returned if not a CaretMappableDataFile. +// */ +//CaretMappableDataFile* +//ChartableTwoInterface::getAsCaretMappableDataFile() +//{ +// return dynamic_cast(this); +//} +// +///** +// * @return The CaretMappableDataFile that implements this interface. +// * NULL is returned if not a CaretMappableDataFile. +// */ +//const CaretMappableDataFile* +//ChartableTwoInterface::getAsCaretMappableDataFile() const +//{ +// return dynamic_cast(this); +//} +// +///** +// * @return The CiftiMappableDataFile that implements this interface. +// * NULL is returned if not a CiftiMappableDataFile. +// */ +//CiftiMappableDataFile* +//ChartableTwoInterface::getAsCiftiMappableDataFile() +//{ +// return dynamic_cast(this); +//} +// +///** +// * @return The CiftiMappableDataFile that implements this interface. +// * NULL is returned if not a CiftiMappableDataFile. +// */ +//const CiftiMappableDataFile* +//ChartableTwoInterface::getAsCiftiMappableDataFile() const +//{ +// return dynamic_cast(this); +//} + +/** + * Does this file support any type of charting? + */ +bool +ChartableTwoInterface::isChartingSupported() const +{ + std::vector chartDataTypes; + getSupportedChartDataTypes(chartDataTypes); + + return ( ! chartDataTypes.empty()); +} + +/** + * Test for support of the given chart data type. + * + * @param chartDataType + * Type of chart data. + * @return + * True if the chart data type is supported, else false. + */ +bool +ChartableTwoInterface::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const +{ + std::vector chartDataTypes; + getSupportedChartDataTypes(chartDataTypes); + + if (std::find(chartDataTypes.begin(), + chartDataTypes.end(), + chartDataType) != chartDataTypes.end()) { + return true; + } + + return false; +} + +/** + * Test for support of the given chart compound data type. + * + * @param chartCompoundDataType + * Type of chart compound data. + * @return + * True if the chart compound data type is supported, else false. + */ +bool +ChartableTwoInterface::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + for (auto& ccdt : chartCompoundDataTypes) { + if (ccdt == chartCompoundDataType) { + return true; + } + } + + return false; +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +ChartableTwoInterface::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const +{ + chartDataTypesOut.clear(); + + if (getHistogramChartDelegate() != NULL) { + chartDataTypesOut.push_back(getHistogramChartDelegate()->getChartDataType()); + } + if (getLineSeriesChartDelegate() != NULL) { + chartDataTypesOut.push_back(getLineSeriesChartDelegate()->getChartDataType()); + } + if (getMatrixChartDelegate() != NULL) { + chartDataTypesOut.push_back(getMatrixChartDelegate()->getChartDataType()); + } + + CaretAssertMessage((! chartDataTypesOut.empty()), + "Why is this interface implemented if implementing file does not support charts?"); +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +ChartableTwoInterface::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const +{ + chartCompoundDataTypesOut.clear(); + + + if (getHistogramChartDelegate() != NULL) { + chartCompoundDataTypesOut.push_back(getHistogramChartDelegate()->getChartCompoundDataType()); + } + if (getLineSeriesChartDelegate() != NULL) { + chartCompoundDataTypesOut.push_back(getLineSeriesChartDelegate()->getChartCompoundDataType()); + } + if (getMatrixChartDelegate() != NULL) { + chartCompoundDataTypesOut.push_back(getMatrixChartDelegate()->getChartCompoundDataType()); + } + + +// const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); +// if (cmdf == NULL) { +// return; +// } +// +// switch (m_histogramContentType) { +// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: +// break; +// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: +// if (cmdf->getNumberOfMaps() > 0) { +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); +// } +// break; +// } +// +// switch (m_lineSeriesContentType) { +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: +// if (cmdf->getNumberOfMaps() > 1) { +// const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// const int32_t numMaps = cmdf->getNumberOfMaps(); +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numMaps)); +// } +// break; +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: +// { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// const int32_t numRows = dims[1]; +// +// if ((numRows > 0) +// && (numCols > 1)) { +// const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numCols)); +// } +// } break; +// } +// +// switch (m_matrixContentType) { +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: +// { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// const int32_t numRows = dims[1]; +// +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, +// numCols)); +// } break; +// } +} + +/** + * Get the chart compound data type supported by this file that uses the given + * chart data type. + * + * @param chartDataType + * The chart data type. + * @param chartCompoundDataTypeOut + * Output with the chart compound data type. + * @return + * True if there is output chart compound data type is valid. + * False if output chart compound data type is invalid OR if chartDataType is invalid. + */ +bool +ChartableTwoInterface::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + for (auto& cdt : chartCompoundDataTypes) { + if (cdt.getChartDataType() == chartDataType) { + chartCompoundDataTypeOut = cdt; + return true; + } + } + + /* default constructor is invalid data type */ + chartCompoundDataTypeOut = ChartTwoCompoundDataType(); + return false; +} + + +///** +// * @return The content type for histograms. +// */ +//ChartTwoHistogramContentTypeEnum::Enum ChartableTwoInterface::getHistogramContentType() const +//{ +// return m_histogramContentType; +//} +// +///** +// * @return The content type for line series. +// */ +//ChartTwoLineSeriesContentTypeEnum::Enum ChartableTwoInterface::getLineSeriesContentType() const +//{ +// return m_lineSeriesContentType; +//} +// +///** +// * @return The content type for matrix. +// */ +//ChartTwoMatrixContentTypeEnum::Enum ChartableTwoInterface::getMatrixContentType() const +//{ +// return m_matrixContentType; +//} +// +// +///** +// * Get the matrix dimensions. +// * +// * @param numberOfRowsOut +// * Number of rows in the matrix. +// * @param numberOfColumnsOut +// * Number of rows in the matrix. +// */ +//void +//ChartableTwoInterface::getTwoMatrixDimensions(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut) const +//{ +// if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { +// numberOfRowsOut = 0; +// numberOfColumnsOut = 0; +// return; +// } +// +// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); +// CaretAssert(ciftiMapFile); +// CaretAssertToDoFatal(); +//// ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, +//// numberOfColumnsOut); +// // std::vector dims; +// // ciftiMapFile->getMapDimensions(dims); +// // CaretAssertVectorIndex(dims, 1); +// // numberOfRowsOut = dims[0]; +// // numberOfColumnsOut = dims[1]; +//} +// +///** +// * Get the matrix RGBA coloring for this matrix data creator. +// * +// * @param numberOfRowsOut +// * Number of rows in the coloring matrix. +// * @param numberOfColumnsOut +// * Number of rows in the coloring matrix. +// * @param rgbaOut +// * RGBA coloring output with number of elements +// * (numberOfRowsOut * numberOfColumnsOut * 4). +// * @return +// * True if data output data is valid, else false. +// */ +//bool +//ChartableTwoInterface::getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut, +// std::vector& rgbaOut) const +//{ +// const CaretMappableDataFile* mapFile = getAsCaretMappableDataFile(); +// CaretAssert(mapFile); +// +// bool useMapFileHelperFlag = false; +// bool useMatrixFileHelperFlag = false; +// +// std::vector parcelReorderedRowIndices; +// +// switch (mapFile->getDataFileType()) { +// case DataFileTypeEnum::CONNECTIVITY_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL: +// { +// useMatrixFileHelperFlag = true; +// +// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(mapFile); +// CaretAssert(parcelConnFile); +// if (parcelConnFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(mapFile); +// CaretAssert(parcelLabelFile); +// if (parcelLabelFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(mapFile); +// CaretAssert(parcelScalarFile); +// if (parcelScalarFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: +// useMatrixFileHelperFlag = true; +// break; +// case DataFileTypeEnum::ANNOTATION: +// break; +// case DataFileTypeEnum::BORDER: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: +// break; +// case DataFileTypeEnum::FOCI: +// break; +// case DataFileTypeEnum::IMAGE: +// break; +// case DataFileTypeEnum::LABEL: +// break; +// case DataFileTypeEnum::METRIC: +// break; +// case DataFileTypeEnum::PALETTE: +// break; +// case DataFileTypeEnum::RGBA: +// break; +// case DataFileTypeEnum::SCENE: +// break; +// case DataFileTypeEnum::SPECIFICATION: +// break; +// case DataFileTypeEnum::SURFACE: +// break; +// case DataFileTypeEnum::UNKNOWN: +// break; +// case DataFileTypeEnum::VOLUME: +// break; +// } +// +// if (( ! useMapFileHelperFlag) +// && ( ! useMatrixFileHelperFlag)) { +// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); +// return false; +// } +// +// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); +// CaretAssert(ciftiMapFile); +// +// +// bool validDataFlag = false; +// if (useMapFileHelperFlag) { +// CaretAssertToDoFatal(); +//// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, +//// numberOfColumnsOut, +//// parcelReorderedRowIndices, +//// rgbaOut); +// } +// else if (useMatrixFileHelperFlag) { +// CaretAssertToDoFatal(); +//// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, +//// numberOfColumnsOut, +//// parcelReorderedRowIndices, +//// rgbaOut); +// } +// switch (m_matrixContentType) { +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: +// break; +// } +// +// return validDataFlag; +//} + diff --git a/src/Files/ChartableTwoInterface.h b/src/Files/ChartableTwoInterface.h index 3b6b1065b..3168f2068 100644 --- a/src/Files/ChartableTwoInterface.h +++ b/src/Files/ChartableTwoInterface.h @@ -24,11 +24,17 @@ #include "ChartTwoCompoundDataType.h" #include "ChartTwoDataTypeEnum.h" +#include "ChartableTwoFileDelegateHistogramChart.h" +#include "ChartableTwoFileDelegateLineSeriesChart.h" +#include "ChartableTwoFileDelegateMatrixChart.h" +#include "ChartTwoLineSeriesContentTypeEnum.h" +#include "ChartTwoMatrixContentTypeEnum.h" namespace caret { class CaretMappableDataFile; class ChartTwoDataCartesianHistory; + class CiftiMappableDataFile; class ChartableTwoInterface { @@ -37,71 +43,57 @@ namespace caret { virtual ~ChartableTwoInterface(); - /** - * @return The CaretMappableDataFile that implements this interface. - */ virtual CaretMappableDataFile* getAsCaretMappableDataFile() = 0; - /** - * @return The CaretMappableDataFile that implements this interface. - */ virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const = 0; - /** - * Does this file support any type of charting? - */ - virtual bool isChartingSupported() const = 0; + virtual ChartableTwoFileDelegateHistogramChart* getHistogramChartDelegate() = 0; - /** - * Test for support of the given chart data type. - * - * @param chartDataType - * Type of chart data. - * @return - * True if the chart data type is supported, else false. - */ - virtual bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const = 0; + virtual const ChartableTwoFileDelegateHistogramChart* getHistogramChartDelegate() const = 0; - /** - * Test for support of the given chart compound data type. - * - * @param chartCompoundDataType - * Type of chart compound data. - * @return - * True if the chart compound data type is supported, else false. - */ - virtual bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const = 0; + virtual ChartableTwoFileDelegateLineSeriesChart* getLineSeriesChartDelegate() = 0; - /** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ - virtual void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const = 0; + virtual const ChartableTwoFileDelegateLineSeriesChart* getLineSeriesChartDelegate() const = 0; - /** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ - virtual void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const = 0; + virtual ChartableTwoFileDelegateMatrixChart* getMatrixChartDelegate() = 0; - /** - * Get the chart compound data type supported by this file that uses the given - * chart data type. - * - * @param chartDataType - * The chart data type. - * @param chartCompoundDataTypeOut - * Output with the chart compound data type. - * @return - * True if there is output chart compound data type is valid. - * False if output chart compound data type is invalid OR if chartDataType is invalid. - */ - virtual bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - ChartTwoCompoundDataType& chartCompoundDataTypeOut) const = 0; + virtual const ChartableTwoFileDelegateMatrixChart* getMatrixChartDelegate() const = 0; + + bool isChartingSupported() const; + + bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; + + bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; + + void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const; + + void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; + + bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; + + + /* IMPLEMENT ABOVE NON-VIRTUAL METHODS USING THE VIRTUAL METHODS */ + + /* METHODS NO LONGER NEEDED ??? */ + +// CiftiMappableDataFile* getAsCiftiMappableDataFile(); +// +// const CiftiMappableDataFile* getAsCiftiMappableDataFile() const; +// +// +// ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; +// +// ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; +// +// ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; +// +// void getTwoMatrixDimensions(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut) const; +// +// bool getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut, +// std::vector& rgbaOut) const; // /** // * @return Is line series charting enabled for this file in the given tab? @@ -120,7 +112,7 @@ namespace caret { /** * @return Charting history if this file charts to lines. */ - virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; + //virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; // ADD_NEW_METHODS_HERE @@ -129,6 +121,11 @@ namespace caret { ChartableTwoInterface& operator=(const ChartableTwoInterface&); +// const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; +// +// const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; +// +// const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.cxx b/src/Files/CiftiConnectivityMatrixParcelFile.cxx index a081908da..1f69edefa 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.cxx +++ b/src/Files/CiftiConnectivityMatrixParcelFile.cxx @@ -58,7 +58,9 @@ using namespace caret; * Constructor. */ CiftiConnectivityMatrixParcelFile::CiftiConnectivityMatrixParcelFile() -: CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL) +: CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL), +ChartableMatrixParcelInterface(), +EventListenerInterface() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 69ce9c372..50797c201 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -757,6 +757,8 @@ namespace caret { static const int32_t CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI = 1; private: + friend class ChartableTwoFileDelegate; + friend class ChartableTwoFileDelegateMatrixChart; // std::vector m_ciftiDimensions; -- GitLab From d823483d62e6867193a4fe9c72dc6447fb8069b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 17 Jan 2017 15:00:15 -0600 Subject: [PATCH 183/755] Continuing charting development with emphasis of a 'charting delegate' for any file that supports charting. --- .../ChartTwoMatrixContentTypeEnum.cxx | 6 +- src/Charting/ChartTwoMatrixContentTypeEnum.h | 4 +- src/Files/CMakeLists.txt | 18 +- ...hart.cxx => ChartableTwoFileBaseChart.cxx} | 42 +- ...aseChart.h => ChartableTwoFileBaseChart.h} | 34 +- src/Files/ChartableTwoFileDelegate.cxx | 869 ++++++++++++++++++ src/Files/ChartableTwoFileDelegate.h | 164 ++++ ...hartableTwoFileDelegateLineSeriesChart.cxx | 115 --- .../ChartableTwoFileDelegateMatrixChart.cxx | 334 ------- ...cxx => ChartableTwoFileHistogramChart.cxx} | 47 +- ...art.h => ChartableTwoFileHistogramChart.h} | 30 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 210 +++++ ...rt.h => ChartableTwoFileLineSeriesChart.h} | 30 +- src/Files/ChartableTwoFileMatrixChart.cxx | 379 ++++++++ ...xChart.h => ChartableTwoFileMatrixChart.h} | 30 +- src/Files/ChartableTwoInterface.h | 18 +- src/Files/CiftiMappableDataFile.cxx | 182 ++++ src/Files/CiftiMappableDataFile.h | 6 +- 18 files changed, 1963 insertions(+), 555 deletions(-) rename src/Files/{ChartableTwoFileDelegateBaseChart.cxx => ChartableTwoFileBaseChart.cxx} (80%) rename src/Files/{ChartableTwoFileDelegateBaseChart.h => ChartableTwoFileBaseChart.h} (75%) create mode 100644 src/Files/ChartableTwoFileDelegate.cxx create mode 100644 src/Files/ChartableTwoFileDelegate.h delete mode 100644 src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx delete mode 100644 src/Files/ChartableTwoFileDelegateMatrixChart.cxx rename src/Files/{ChartableTwoFileDelegateHistogramChart.cxx => ChartableTwoFileHistogramChart.cxx} (65%) rename src/Files/{ChartableTwoFileDelegateHistogramChart.h => ChartableTwoFileHistogramChart.h} (67%) create mode 100644 src/Files/ChartableTwoFileLineSeriesChart.cxx rename src/Files/{ChartableTwoFileDelegateLineSeriesChart.h => ChartableTwoFileLineSeriesChart.h} (67%) create mode 100644 src/Files/ChartableTwoFileMatrixChart.cxx rename src/Files/{ChartableTwoFileDelegateMatrixChart.h => ChartableTwoFileMatrixChart.h} (72%) diff --git a/src/Charting/ChartTwoMatrixContentTypeEnum.cxx b/src/Charting/ChartTwoMatrixContentTypeEnum.cxx index 7f4afc873..8eccff679 100644 --- a/src/Charting/ChartTwoMatrixContentTypeEnum.cxx +++ b/src/Charting/ChartTwoMatrixContentTypeEnum.cxx @@ -114,9 +114,9 @@ ChartTwoMatrixContentTypeEnum::initialize() "MATRIX_CONTENT_BRAINORDINATE_MAPPABLE", "Brainordinate Mappable")); - enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_SERIES, - "MATRIX_CONTENT_SERIES", - "Series")); + enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_SCALARS, + "MATRIX_CONTENT_SCALARS", + "Scalars")); } /** diff --git a/src/Charting/ChartTwoMatrixContentTypeEnum.h b/src/Charting/ChartTwoMatrixContentTypeEnum.h index 5f2f70bf7..436277db7 100644 --- a/src/Charting/ChartTwoMatrixContentTypeEnum.h +++ b/src/Charting/ChartTwoMatrixContentTypeEnum.h @@ -39,8 +39,8 @@ public: MATRIX_CONTENT_UNSUPPORTED, /** Brainordinate mappable content */ MATRIX_CONTENT_BRAINORDINATE_MAPPABLE, - /** Series content */ - MATRIX_CONTENT_SERIES + /** Scalar content */ + MATRIX_CONTENT_SCALARS }; diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 983dbae42..022f43713 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -47,10 +47,11 @@ ChartableMatrixSeriesInterface.h ChartableTwoInterface.h -ChartableTwoFileDelegateBaseChart.h -ChartableTwoFileDelegateHistogramChart.h -ChartableTwoFileDelegateLineSeriesChart.h -ChartableTwoFileDelegateMatrixChart.h +ChartableTwoFileDelegate.h +ChartableTwoFileBaseChart.h +ChartableTwoFileHistogramChart.h +ChartableTwoFileLineSeriesChart.h +ChartableTwoFileMatrixChart.h CiftiBrainordinateDataSeriesFile.h CiftiBrainordinateLabelFile.h @@ -171,10 +172,11 @@ ChartableLineSeriesInterface.cxx ChartableMatrixInterface.cxx ChartableTwoInterface.cxx -ChartableTwoFileDelegateBaseChart.cxx -ChartableTwoFileDelegateHistogramChart.cxx -ChartableTwoFileDelegateLineSeriesChart.cxx -ChartableTwoFileDelegateMatrixChart.cxx +ChartableTwoFileDelegate.cxx +ChartableTwoFileBaseChart.cxx +ChartableTwoFileHistogramChart.cxx +ChartableTwoFileLineSeriesChart.cxx +ChartableTwoFileMatrixChart.cxx CiftiBrainordinateDataSeriesFile.cxx CiftiBrainordinateLabelFile.cxx diff --git a/src/Files/ChartableTwoFileDelegateBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx similarity index 80% rename from src/Files/ChartableTwoFileDelegateBaseChart.cxx rename to src/Files/ChartableTwoFileBaseChart.cxx index 2ae467dda..e1c18b303 100644 --- a/src/Files/ChartableTwoFileDelegateBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ -#include "ChartableTwoFileDelegateBaseChart.h" -#undef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ +#define __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ +#include "ChartableTwoFileBaseChart.h" +#undef __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ #include "CaretAssert.h" #include "EventManager.h" @@ -33,7 +33,7 @@ using namespace caret; /** - * \class caret::ChartableTwoFileDelegateBaseChart + * \class caret::ChartableTwoFileBaseChart * \brief Base class for File Charting Delegates. * \ingroup Files * @@ -60,9 +60,9 @@ using namespace caret; * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. */ -ChartableTwoFileDelegateBaseChart::ChartableTwoFileDelegateBaseChart(const ChartTwoDataTypeEnum::Enum chartType, +ChartableTwoFileBaseChart::ChartableTwoFileBaseChart(const ChartTwoDataTypeEnum::Enum chartType, CaretMappableDataFile* parentCaretMappableDataFile) -: CaretObject(), +: CaretObjectTracksModification(), m_chartType(chartType), m_parentCaretMappableDataFile(parentCaretMappableDataFile) { @@ -77,7 +77,7 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) // EventManager::get()->addEventListener(this, EventTypeEnum::); } -//ChartableTwoFileDelegateBaseChart::ChartableTwoFileDelegateBaseChart() +//ChartableTwoFileBaseChart::ChartableTwoFileBaseChart() //{ // //} @@ -85,7 +85,7 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) /** * Destructor. */ -ChartableTwoFileDelegateBaseChart::~ChartableTwoFileDelegateBaseChart() +ChartableTwoFileBaseChart::~ChartableTwoFileBaseChart() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; @@ -96,9 +96,9 @@ ChartableTwoFileDelegateBaseChart::~ChartableTwoFileDelegateBaseChart() * @return String describing this object's content. */ AString -ChartableTwoFileDelegateBaseChart::toString() const +ChartableTwoFileBaseChart::toString() const { - return "ChartableTwoFileDelegateBaseChart"; + return "ChartableTwoFileBaseChart"; } /** @@ -108,7 +108,7 @@ ChartableTwoFileDelegateBaseChart::toString() const * An event for which this instance is listening. */ void -ChartableTwoFileDelegateBaseChart::receiveEvent(Event* event) +ChartableTwoFileBaseChart::receiveEvent(Event* event) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); @@ -122,7 +122,7 @@ ChartableTwoFileDelegateBaseChart::receiveEvent(Event* event) * @return The CaretMappableDataFile that provided this delegate. */ CaretMappableDataFile* -ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() +ChartableTwoFileBaseChart::getCaretMappableDataFile() { return m_parentCaretMappableDataFile; } @@ -131,7 +131,7 @@ ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() * @return The CaretMappableDataFile that provided this delegate. */ const CaretMappableDataFile* -ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() const +ChartableTwoFileBaseChart::getCaretMappableDataFile() const { return m_parentCaretMappableDataFile; } @@ -141,7 +141,7 @@ ChartableTwoFileDelegateBaseChart::getCaretMappableDataFile() const * NULL is returned if not a CiftiMappableDataFile. */ CiftiMappableDataFile* -ChartableTwoFileDelegateBaseChart::getCiftiMappableDataFile() +ChartableTwoFileBaseChart::getCiftiMappableDataFile() { return m_parentCiftiMappableDataFile; } @@ -151,13 +151,13 @@ ChartableTwoFileDelegateBaseChart::getCiftiMappableDataFile() * NULL is returned if not a CiftiMappableDataFile. */ const CiftiMappableDataFile* -ChartableTwoFileDelegateBaseChart::getCiftiMappableDataFile() const +ChartableTwoFileBaseChart::getCiftiMappableDataFile() const { return m_parentCiftiMappableDataFile; } ChartTwoDataTypeEnum::Enum -ChartableTwoFileDelegateBaseChart::getChartDataType() const +ChartableTwoFileBaseChart::getChartDataType() const { return m_chartType; } @@ -166,7 +166,7 @@ ChartableTwoFileDelegateBaseChart::getChartDataType() const * @return Chart compound data type supported by subclass. */ ChartTwoCompoundDataType -ChartableTwoFileDelegateBaseChart::getChartCompoundDataType() const +ChartableTwoFileBaseChart::getChartCompoundDataType() const { CaretAssertMessage((m_compoundChartDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID), "Data type is invalid, was updateChartCompoundDataTypeAfterFileChanges() called by " @@ -183,7 +183,7 @@ ChartableTwoFileDelegateBaseChart::getChartCompoundDataType() const * match the data type passed to the constructor. */ void -ChartableTwoFileDelegateBaseChart::updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) +ChartableTwoFileBaseChart::updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) { CaretAssert(m_chartType == compoundChartDataType.getChartDataType()); @@ -203,11 +203,11 @@ ChartableTwoFileDelegateBaseChart::updateChartCompoundDataTypeAfterFileChanges(c * Name of instance in the scene. */ SceneClass* -ChartableTwoFileDelegateBaseChart::saveToScene(const SceneAttributes* sceneAttributes, +ChartableTwoFileBaseChart::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, - "ChartableTwoFileDelegateBaseChart", + "ChartableTwoFileBaseChart", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -230,7 +230,7 @@ ChartableTwoFileDelegateBaseChart::saveToScene(const SceneAttributes* sceneAttri * sceneClass from which model specific information is obtained. */ void -ChartableTwoFileDelegateBaseChart::restoreFromScene(const SceneAttributes* sceneAttributes, +ChartableTwoFileBaseChart::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { diff --git a/src/Files/ChartableTwoFileDelegateBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h similarity index 75% rename from src/Files/ChartableTwoFileDelegateBaseChart.h rename to src/Files/ChartableTwoFileBaseChart.h index 3968feafa..5024a2238 100644 --- a/src/Files/ChartableTwoFileDelegateBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -1,5 +1,5 @@ -#ifndef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ -#define __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ +#ifndef __CHARTABLE_TWO_FILE_BASE_CHART_H__ +#define __CHARTABLE_TWO_FILE_BASE_CHART_H__ /*LICENSE_START*/ /* @@ -21,7 +21,7 @@ */ /*LICENSE_END*/ -#include "CaretObject.h" +#include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" @@ -32,14 +32,24 @@ namespace caret { class CiftiMappableDataFile; class SceneClassAssistant; - class ChartableTwoFileDelegateBaseChart : public CaretObject, public EventListenerInterface, public SceneableInterface { + class ChartableTwoFileBaseChart : public CaretObjectTracksModification, public EventListenerInterface, public SceneableInterface { protected: - ChartableTwoFileDelegateBaseChart(const ChartTwoDataTypeEnum::Enum chartType, + ChartableTwoFileBaseChart(const ChartTwoDataTypeEnum::Enum chartType, CaretMappableDataFile* parentCaretMappableDataFile); public: - virtual ~ChartableTwoFileDelegateBaseChart(); + virtual ~ChartableTwoFileBaseChart(); + + /** + * @return Is this charting valid ? + */ + virtual bool isValid() const = 0; + + /** + * @return Is this charting empty (no data at this time) + */ + virtual bool isEmpty() const = 0; CaretMappableDataFile* getCaretMappableDataFile(); @@ -80,11 +90,11 @@ namespace caret { const SceneClass* sceneClass) = 0; private: - ChartableTwoFileDelegateBaseChart() = delete; + ChartableTwoFileBaseChart() = delete; - ChartableTwoFileDelegateBaseChart(const ChartableTwoFileDelegateBaseChart&); + ChartableTwoFileBaseChart(const ChartableTwoFileBaseChart&); - ChartableTwoFileDelegateBaseChart& operator=(const ChartableTwoFileDelegateBaseChart&); + ChartableTwoFileBaseChart& operator=(const ChartableTwoFileBaseChart&); const ChartTwoDataTypeEnum::Enum m_chartType; @@ -100,9 +110,9 @@ namespace caret { }; -#ifdef __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ +#ifdef __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ // -#endif // __CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_DECLARE__ +#endif // __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ } // namespace -#endif //__CHARTABLE_TWO_FILE_DELEGATE_BASE_CHART_H__ +#endif //__CHARTABLE_TWO_FILE_BASE_CHART_H__ diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx new file mode 100644 index 000000000..fd608a439 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -0,0 +1,869 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ +#include "ChartableTwoFileDelegate.h" +#undef __CHARTABLE_TWO_INTERFACE_DECLARE__ + +#include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" +#include "CiftiConnectivityMatrixParcelFile.h" +#include "CiftiMappableDataFile.h" +#include "CiftiParcelLabelFile.h" +#include "CiftiParcelReordering.h" +#include "CiftiParcelScalarFile.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileDelegate + * \brief Interface for files that are chartable. Contains functionality but no data. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param type of matrix (if any) supported by implementing file. + * + * @param caretMappableDataFile + * Caret Mappable Data File this delegate charts. + * @param histogramChart + * Histogram charting for Caret Mappable Data File (NULL if histogram charting not supported). + * @param lineSeriesChart + * Line series charting for Caret Mappable Data File (NULL if line series charting not supported). + * @param matrixChart + * Matrix charting for Caret Mappable Data File (NULL if matrix charting not supported). + */ +ChartableTwoFileDelegate::ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile) +: CaretObjectTracksModification(), +SceneableInterface(), +m_caretMappableDataFile(caretMappableDataFile) +{ + CaretAssert(m_caretMappableDataFile); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + + clear(); +} + +/** + * Destructor. + */ +ChartableTwoFileDelegate::~ChartableTwoFileDelegate() +{ +} + +/** + * Update after the file has been read or content has changed. + */ +void +ChartableTwoFileDelegate::updateAfterFileChanged() +{ + CaretAssert(m_caretMappableDataFile); + + ChartTwoHistogramContentTypeEnum::Enum histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED; + ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; + ChartTwoMatrixContentTypeEnum::Enum matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; + + switch (m_caretMappableDataFile->getDataFileType()) { + case DataFileTypeEnum::CONNECTIVITY_DENSE: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA; + matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS; + break; + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + break; + + } + + m_histogramCharting = std::unique_ptr(new ChartableTwoFileHistogramChart(histogramType, + m_caretMappableDataFile)); + + m_lineSeriesCharting = std::unique_ptr(new ChartableTwoFileLineSeriesChart(lineSeriesType, + m_caretMappableDataFile)); + + m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(matrixType, + m_caretMappableDataFile)); +} + +/** + * Clear the content. + */ +void +ChartableTwoFileDelegate::clear() +{ + m_histogramCharting = std::unique_ptr(new ChartableTwoFileHistogramChart(ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, + m_caretMappableDataFile)); + + m_lineSeriesCharting = std::unique_ptr(new ChartableTwoFileLineSeriesChart(ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED, + m_caretMappableDataFile)); + + m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED, + m_caretMappableDataFile)); +} + +/** + * Clear the modification status of this instance. + */ +void +ChartableTwoFileDelegate::clearModified() +{ + m_histogramCharting->clearModified(); + m_lineSeriesCharting->clearModified(); + m_matrixCharting->clearModified(); +} + +/** + * @return True if this instance is modified, else false. + */ +bool +ChartableTwoFileDelegate::isModified() const +{ + if (m_histogramCharting->isModified()) { + return true; + } + if (m_matrixCharting->isModified()) { + return true; + } + if (m_lineSeriesCharting->isModified()) { + return true; + } + + return false; +} + +/** + * @return The CaretMappableDataFile that implements this interface. + * NULL is returned if not a CaretMappableDataFile. + */ +CaretMappableDataFile* +ChartableTwoFileDelegate::getCaretMappableDataFile() +{ + return m_caretMappableDataFile; +} + +/** + * @return The CaretMappableDataFile that implements this interface. + * NULL is returned if not a CaretMappableDataFile. + */ +const CaretMappableDataFile* +ChartableTwoFileDelegate::getCaretMappableDataFile() const +{ + return m_caretMappableDataFile; +} + +ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() +{ + return m_histogramCharting.get(); +} + +const ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() const +{ + return m_histogramCharting.get(); +} + +ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() +{ + return m_lineSeriesCharting.get(); +} + +const ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() const +{ + return m_lineSeriesCharting.get(); +} + +ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() +{ + return m_matrixCharting.get(); +} + +const ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() const +{ + return m_matrixCharting.get(); +} + +///** +// * @return The CiftiMappableDataFile that implements this interface. +// * NULL is returned if not a CiftiMappableDataFile. +// */ +//CiftiMappableDataFile* +//ChartableTwoFileDelegate::getAsCiftiMappableDataFile() +//{ +// return dynamic_cast(this); +//} +// +///** +// * @return The CiftiMappableDataFile that implements this interface. +// * NULL is returned if not a CiftiMappableDataFile. +// */ +//const CiftiMappableDataFile* +//ChartableTwoFileDelegate::getAsCiftiMappableDataFile() const +//{ +// return dynamic_cast(this); +//} + +/** + * Does this file support any type of charting? + */ +bool +ChartableTwoFileDelegate::isChartingSupported() const +{ + std::vector chartDataTypes; + getSupportedChartDataTypes(chartDataTypes); + + return ( ! chartDataTypes.empty()); +} + +/** + * Test for support of the given chart data type. + * + * @param chartDataType + * Type of chart data. + * @return + * True if the chart data type is supported, else false. + */ +bool +ChartableTwoFileDelegate::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const +{ + std::vector chartDataTypes; + getSupportedChartDataTypes(chartDataTypes); + + if (std::find(chartDataTypes.begin(), + chartDataTypes.end(), + chartDataType) != chartDataTypes.end()) { + return true; + } + + return false; +} + +/** + * Test for support of the given chart compound data type. + * + * @param chartCompoundDataType + * Type of chart compound data. + * @return + * True if the chart compound data type is supported, else false. + */ +bool +ChartableTwoFileDelegate::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + + for (auto& ccdt : chartCompoundDataTypes) { + if (ccdt == chartCompoundDataType) { + return true; + } + } + + return false; +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +ChartableTwoFileDelegate::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const +{ + chartDataTypesOut.clear(); + + if (m_histogramCharting != NULL) { + chartDataTypesOut.push_back(m_histogramCharting->getChartDataType()); + } + if (m_lineSeriesCharting!= NULL) { + chartDataTypesOut.push_back(m_lineSeriesCharting->getChartDataType()); + } + if (m_matrixCharting != NULL) { + chartDataTypesOut.push_back(m_matrixCharting->getChartDataType()); + } + + CaretAssertMessage((! chartDataTypesOut.empty()), + "Why is this delegate used if parent file does not support charts?"); +} + +/** + * Get chart data types supported by this file. + * + * @param chartDataTypesOut + * Output containing all chart data types supported by this data file. + */ +void +ChartableTwoFileDelegate::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const +{ + chartCompoundDataTypesOut.clear(); + + + if (m_histogramCharting != NULL) { + chartCompoundDataTypesOut.push_back(m_histogramCharting->getChartCompoundDataType()); + } + if (m_lineSeriesCharting != NULL) { + chartCompoundDataTypesOut.push_back(m_lineSeriesCharting->getChartCompoundDataType()); + } + if (m_matrixCharting != NULL) { + chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartCompoundDataType()); + } + + CaretAssertMessage((! chartCompoundDataTypesOut.empty()), + "Why is this delegate used if parent file does not support charts?"); + +// const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); +// if (cmdf == NULL) { +// return; +// } +// +// switch (m_histogramContentType) { +// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: +// break; +// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: +// if (cmdf->getNumberOfMaps() > 0) { +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); +// } +// break; +// } +// +// switch (m_lineSeriesContentType) { +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: +// if (cmdf->getNumberOfMaps() > 1) { +// const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// const int32_t numMaps = cmdf->getNumberOfMaps(); +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numMaps)); +// } +// break; +// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: +// { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// const int32_t numRows = dims[1]; +// +// if ((numRows > 0) +// && (numCols > 1)) { +// const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); +// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; +// switch (mapUnits) { +// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: +// CaretAssert(0); +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: +// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; +// break; +// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: +// break; +// } +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, +// numCols)); +// } +// } break; +// } +// +// switch (m_matrixContentType) { +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: +// { +// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); +// CaretAssert(ciftiMapFile); +// std::vector dims; +// ciftiMapFile->getMapDimensions(dims); +// CaretAssertVectorIndex(dims, 1); +// const int32_t numCols = dims[0]; +// const int32_t numRows = dims[1]; +// +// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, +// numCols)); +// } break; +// } +} + +/** + * Get the chart compound data type supported by this file that uses the given + * chart data type. + * + * @param chartDataType + * The chart data type. + * @param chartCompoundDataTypeOut + * Output with the chart compound data type. + * @return + * True if there is output chart compound data type is valid. + * False if output chart compound data type is invalid OR if chartDataType is invalid. + */ +bool +ChartableTwoFileDelegate::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const +{ + std::vector chartCompoundDataTypes; + getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + for (auto& cdt : chartCompoundDataTypes) { + if (cdt.getChartDataType() == chartDataType) { + chartCompoundDataTypeOut = cdt; + return true; + } + } + + /* default constructor is invalid data type */ + chartCompoundDataTypeOut = ChartTwoCompoundDataType(); + return false; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartableTwoFileDelegate::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartableTwoFileDelegate", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + if (m_histogramCharting != NULL) { + sceneClass->addClass(m_histogramCharting->saveToScene(sceneAttributes, + "m_histogramCharting")); + sceneClass->addClass(m_lineSeriesCharting->saveToScene(sceneAttributes, + "m_lineSeriesCharting")); + sceneClass->addClass(m_matrixCharting->saveToScene(sceneAttributes, + "m_matrixCharting")); + } + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartableTwoFileDelegate::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + const SceneClass* histogramClass = sceneClass->getClass("m_histogramCharting"); + if (histogramClass != NULL) { + CaretAssert(m_histogramCharting); + m_histogramCharting->restoreFromScene(sceneAttributes, + histogramClass); + } + + const SceneClass* lineSeriesClass = sceneClass->getClass("m_lineSeriesCharting"); + if (lineSeriesClass != NULL) { + CaretAssert(m_lineSeriesCharting); + m_lineSeriesCharting->restoreFromScene(sceneAttributes, + lineSeriesClass); + } + + const SceneClass* matrixClass = sceneClass->getClass("m_matrixCharting"); + if (matrixClass != NULL) { + CaretAssert(m_matrixCharting); + m_matrixCharting->restoreFromScene(sceneAttributes, + matrixClass); + } +} + + +///** +// * @return The content type for histograms. +// */ +//ChartTwoHistogramContentTypeEnum::Enum ChartableTwoFileDelegate::getHistogramContentType() const +//{ +// return m_histogramContentType; +//} +// +///** +// * @return The content type for line series. +// */ +//ChartTwoLineSeriesContentTypeEnum::Enum ChartableTwoFileDelegate::getLineSeriesContentType() const +//{ +// return m_lineSeriesContentType; +//} +// +///** +// * @return The content type for matrix. +// */ +//ChartTwoMatrixContentTypeEnum::Enum ChartableTwoFileDelegate::getMatrixContentType() const +//{ +// return m_matrixContentType; +//} +// +// +///** +// * Get the matrix dimensions. +// * +// * @param numberOfRowsOut +// * Number of rows in the matrix. +// * @param numberOfColumnsOut +// * Number of rows in the matrix. +// */ +//void +//ChartableTwoFileDelegate::getTwoMatrixDimensions(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut) const +//{ +// if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { +// numberOfRowsOut = 0; +// numberOfColumnsOut = 0; +// return; +// } +// +// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); +// CaretAssert(ciftiMapFile); +// CaretAssertToDoFatal(); +//// ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, +//// numberOfColumnsOut); +// // std::vector dims; +// // ciftiMapFile->getMapDimensions(dims); +// // CaretAssertVectorIndex(dims, 1); +// // numberOfRowsOut = dims[0]; +// // numberOfColumnsOut = dims[1]; +//} +// +///** +// * Get the matrix RGBA coloring for this matrix data creator. +// * +// * @param numberOfRowsOut +// * Number of rows in the coloring matrix. +// * @param numberOfColumnsOut +// * Number of rows in the coloring matrix. +// * @param rgbaOut +// * RGBA coloring output with number of elements +// * (numberOfRowsOut * numberOfColumnsOut * 4). +// * @return +// * True if data output data is valid, else false. +// */ +//bool +//ChartableTwoFileDelegate::getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut, +// std::vector& rgbaOut) const +//{ +// const CaretMappableDataFile* mapFile = getAsCaretMappableDataFile(); +// CaretAssert(mapFile); +// +// bool useMapFileHelperFlag = false; +// bool useMatrixFileHelperFlag = false; +// +// std::vector parcelReorderedRowIndices; +// +// switch (mapFile->getDataFileType()) { +// case DataFileTypeEnum::CONNECTIVITY_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL: +// { +// useMatrixFileHelperFlag = true; +// +// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(mapFile); +// CaretAssert(parcelConnFile); +// if (parcelConnFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(mapFile); +// CaretAssert(parcelLabelFile); +// if (parcelLabelFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(mapFile); +// CaretAssert(parcelScalarFile); +// if (parcelScalarFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: +// useMatrixFileHelperFlag = true; +// break; +// case DataFileTypeEnum::ANNOTATION: +// break; +// case DataFileTypeEnum::BORDER: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: +// break; +// case DataFileTypeEnum::FOCI: +// break; +// case DataFileTypeEnum::IMAGE: +// break; +// case DataFileTypeEnum::LABEL: +// break; +// case DataFileTypeEnum::METRIC: +// break; +// case DataFileTypeEnum::PALETTE: +// break; +// case DataFileTypeEnum::RGBA: +// break; +// case DataFileTypeEnum::SCENE: +// break; +// case DataFileTypeEnum::SPECIFICATION: +// break; +// case DataFileTypeEnum::SURFACE: +// break; +// case DataFileTypeEnum::UNKNOWN: +// break; +// case DataFileTypeEnum::VOLUME: +// break; +// } +// +// if (( ! useMapFileHelperFlag) +// && ( ! useMatrixFileHelperFlag)) { +// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); +// return false; +// } +// +// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); +// CaretAssert(ciftiMapFile); +// +// +// bool validDataFlag = false; +// if (useMapFileHelperFlag) { +// CaretAssertToDoFatal(); +//// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, +//// numberOfColumnsOut, +//// parcelReorderedRowIndices, +//// rgbaOut); +// } +// else if (useMatrixFileHelperFlag) { +// CaretAssertToDoFatal(); +//// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, +//// numberOfColumnsOut, +//// parcelReorderedRowIndices, +//// rgbaOut); +// } +// switch (m_matrixContentType) { +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: +// break; +// } +// +// return validDataFlag; +//} + diff --git a/src/Files/ChartableTwoFileDelegate.h b/src/Files/ChartableTwoFileDelegate.h new file mode 100644 index 000000000..1f89556a1 --- /dev/null +++ b/src/Files/ChartableTwoFileDelegate.h @@ -0,0 +1,164 @@ +#ifndef __CHARTABLE_TWO_FILE_DELEGATE_H__ +#define __CHARTABLE_TWO_FILE_DELEGATE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2016 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretObjectTracksModification.h" +#include "ChartTwoCompoundDataType.h" +#include "ChartTwoDataTypeEnum.h" +#include "SceneableInterface.h" + +namespace caret { + + class CaretMappableDataFile; + //class ChartTwoDataCartesianHistory; + class ChartableTwoFileHistogramChart; + class ChartableTwoFileLineSeriesChart; + class ChartableTwoFileMatrixChart; + class CiftiMappableDataFile; + + class ChartableTwoFileDelegate : public CaretObjectTracksModification, public SceneableInterface { + + private: + ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile); + + public: + virtual ~ChartableTwoFileDelegate(); + + void updateAfterFileChanged(); + + // do not make this virtual since called from constructor + void clear(); + + virtual void clearModified() override; + + virtual bool isModified() const override; + + CaretMappableDataFile* getCaretMappableDataFile(); + + const CaretMappableDataFile* getCaretMappableDataFile() const; + + ChartableTwoFileHistogramChart* getHistogramCharting(); + + const ChartableTwoFileHistogramChart* getHistogramCharting() const; + + ChartableTwoFileLineSeriesChart* getLineSeriesCharting(); + + const ChartableTwoFileLineSeriesChart* getLineSeriesCharting() const; + + ChartableTwoFileMatrixChart* getMatrixCharting(); + + const ChartableTwoFileMatrixChart* getMatrixCharting() const; + + bool isChartingSupported() const; + + bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; + + bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; + + void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const; + + void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; + + bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; + + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) override; + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + /* IMPLEMENT ABOVE NON-VIRTUAL METHODS USING THE VIRTUAL METHODS */ + + /* METHODS NO LONGER NEEDED ??? */ + +// CiftiMappableDataFile* getAsCiftiMappableDataFile(); +// +// const CiftiMappableDataFile* getAsCiftiMappableDataFile() const; +// +// +// ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; +// +// ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; +// +// ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; +// +// void getTwoMatrixDimensions(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut) const; +// +// bool getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, +// int32_t& numberOfColumnsOut, +// std::vector& rgbaOut) const; + +// /** +// * @return Is line series charting enabled for this file in the given tab? +// */ +// virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const = 0; +// +// /** +// * Set charting enabled for this file in the given tab +// * +// * @param enabled +// * New status for charting enabled. +// */ +// virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, +// const bool enabled) = 0; + + /** + * @return Charting history if this file charts to lines. + */ + //virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; + + // ADD_NEW_METHODS_HERE + + private: + ChartableTwoFileDelegate(const ChartableTwoFileDelegate&); + + ChartableTwoFileDelegate& operator=(const ChartableTwoFileDelegate&); + + std::unique_ptr m_sceneAssistant; + + /** points to parent caret mappable data file */ + CaretMappableDataFile* m_caretMappableDataFile = NULL; + + std::unique_ptr m_histogramCharting; + + std::unique_ptr m_lineSeriesCharting; + + std::unique_ptr m_matrixCharting; + +// const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; +// +// const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; +// +// const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ + // +#endif // __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ + +} // namespace +#endif //__CHARTABLE_TWO_FILE_DELEGATE_H__ diff --git a/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx b/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx deleted file mode 100644 index 72f3a7e0a..000000000 --- a/src/Files/ChartableTwoFileDelegateLineSeriesChart.cxx +++ /dev/null @@ -1,115 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ -#include "ChartableTwoFileDelegateLineSeriesChart.h" -#undef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ - -#include "CaretAssert.h" -#include "SceneClass.h" -#include "SceneClassAssistant.h" - -using namespace caret; - - - -/** - * \class caret::ChartableTwoFileDelegateLineSeriesChart - * \brief Implementation of base chart delegate for line series charts. - * \ingroup Files - */ - -/** - * Constructor. - * - * @param lineSeriesContentType - * Content type of the line series data. - * @param parentCaretMappableDataFile - * Parent caret mappable data file that this delegate supports. - */ -ChartableTwoFileDelegateLineSeriesChart::ChartableTwoFileDelegateLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, - CaretMappableDataFile* parentCaretMappableDataFile) -: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, - parentCaretMappableDataFile), -m_lineSeriesContentType(lineSeriesContentType) -{ - CaretAssert(m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED); - m_sceneAssistant = new SceneClassAssistant(); - -} - -/** - * Destructor. - */ -ChartableTwoFileDelegateLineSeriesChart::~ChartableTwoFileDelegateLineSeriesChart() -{ - delete m_sceneAssistant; -} - -/** - * @return Content type of the line series data. - */ -ChartTwoLineSeriesContentTypeEnum::Enum -ChartableTwoFileDelegateLineSeriesChart::getLineSeriesContentType() const -{ - return m_lineSeriesContentType; -} - -/** - * Save subclass data to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass to which data members should be added. Will always - * be valid (non-NULL). - */ -void -ChartableTwoFileDelegateLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) -{ - m_sceneAssistant->saveMembers(sceneAttributes, - sceneClass); -} - -/** - * Restore file data from the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass for the instance of a class that implements - * this interface. Will NEVER be NULL. - */ -void -ChartableTwoFileDelegateLineSeriesChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); -} - diff --git a/src/Files/ChartableTwoFileDelegateMatrixChart.cxx b/src/Files/ChartableTwoFileDelegateMatrixChart.cxx deleted file mode 100644 index 8f437d9c7..000000000 --- a/src/Files/ChartableTwoFileDelegateMatrixChart.cxx +++ /dev/null @@ -1,334 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ -#include "ChartableTwoFileDelegateMatrixChart.h" -#undef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ - -#include "CaretAssert.h" -#include "CiftiConnectivityMatrixParcelFile.h" -#include "CiftiParcelLabelFile.h" -#include "CiftiParcelReordering.h" -#include "CiftiParcelScalarFile.h" -#include "SceneClass.h" -#include "SceneClassAssistant.h" - -using namespace caret; - - - -/** - * \class caret::ChartableTwoFileDelegateMatrixChart - * \brief Implementation of base chart delegate for matrix charts. - * \ingroup Files - */ - -/** - * Constructor. - * - * @param matrixContentType - * Content type of the matrix. - * @param parentCaretMappableDataFile - * Parent caret mappable data file that this delegate supports. - */ -ChartableTwoFileDelegateMatrixChart::ChartableTwoFileDelegateMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, - CaretMappableDataFile* parentCaretMappableDataFile) -: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, - parentCaretMappableDataFile), -m_matrixContentType(matrixContentType) -{ - CaretAssert(m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED); - m_sceneAssistant = new SceneClassAssistant(); - -} - -/** - * Destructor. - */ -ChartableTwoFileDelegateMatrixChart::~ChartableTwoFileDelegateMatrixChart() -{ - delete m_sceneAssistant; -} - -/** - * @return Content type of the matrix. - */ -ChartTwoMatrixContentTypeEnum::Enum -ChartableTwoFileDelegateMatrixChart::getMatrixContentType() const -{ - return m_matrixContentType; -} - -/** - * Get the matrix dimensions. - * - * @param numberOfRowsOut - * Number of rows in the matrix. - * @param numberOfColumnsOut - * Number of rows in the matrix. - */ -void -ChartableTwoFileDelegateMatrixChart::getMatrixDimensions(int32_t& numberOfRowsOut, - int32_t& numberOfColumnsOut) const -{ - numberOfRowsOut = 0; - numberOfColumnsOut = 0; - - if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { - return; - } - - const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); - CaretAssert(ciftiMapFile); - ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, - numberOfColumnsOut); -} - -/** - * Get the matrix RGBA coloring for this matrix data creator. - * - * @param numberOfRowsOut - * Number of rows in the coloring matrix. - * @param numberOfColumnsOut - * Number of rows in the coloring matrix. - * @param rgbaOut - * RGBA coloring output with number of elements - * (numberOfRowsOut * numberOfColumnsOut * 4). - * @return - * True if data output data is valid, else false. - */ -bool -ChartableTwoFileDelegateMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, - int32_t& numberOfColumnsOut, - std::vector& rgbaOut) const -{ - const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); - CaretAssert(ciftiMapFile); - - bool useMapFileHelperFlag = false; - bool useMatrixFileHelperFlag = false; - - std::vector parcelReorderedRowIndices; - - switch (ciftiMapFile->getDataFileType()) { - case DataFileTypeEnum::CONNECTIVITY_DENSE: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: - break; - case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL: - { - useMatrixFileHelperFlag = true; - - const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(ciftiMapFile); - CaretAssert(parcelConnFile); - if (parcelConnFile != NULL) { - CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; - int32_t parcelLabelFileMapIndex = -1; - bool reorderingEnabledFlag = false; - - std::vector parcelLabelFiles; - parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, - parcelLabelReorderingFile, - parcelLabelFileMapIndex, - reorderingEnabledFlag); - - if (reorderingEnabledFlag) { - const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, - parcelLabelFileMapIndex); - if (parcelReordering != NULL) { - parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); - } - } - } - } - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: - { - useMapFileHelperFlag = true; - - const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); - CaretAssert(parcelLabelFile); - if (parcelLabelFile != NULL) { - CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; - int32_t parcelLabelFileMapIndex = -1; - bool reorderingEnabledFlag = false; - - std::vector parcelLabelFiles; - parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, - parcelLabelReorderingFile, - parcelLabelFileMapIndex, - reorderingEnabledFlag); - - if (reorderingEnabledFlag) { - const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, - parcelLabelFileMapIndex); - if (parcelReordering != NULL) { - parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); - } - } - } - } - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: - { - useMapFileHelperFlag = true; - - const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); - CaretAssert(parcelScalarFile); - if (parcelScalarFile != NULL) { - CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; - int32_t parcelLabelFileMapIndex = -1; - bool reorderingEnabledFlag = false; - - std::vector parcelLabelFiles; - parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, - parcelLabelReorderingFile, - parcelLabelFileMapIndex, - reorderingEnabledFlag); - - if (reorderingEnabledFlag) { - const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, - parcelLabelFileMapIndex); - if (parcelReordering != NULL) { - parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); - } - } - } - } - break; - case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: - break; - case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: - useMatrixFileHelperFlag = true; - break; - case DataFileTypeEnum::ANNOTATION: - break; - case DataFileTypeEnum::BORDER: - break; - case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: - break; - case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: - break; - case DataFileTypeEnum::FOCI: - break; - case DataFileTypeEnum::IMAGE: - break; - case DataFileTypeEnum::LABEL: - break; - case DataFileTypeEnum::METRIC: - break; - case DataFileTypeEnum::PALETTE: - break; - case DataFileTypeEnum::RGBA: - break; - case DataFileTypeEnum::SCENE: - break; - case DataFileTypeEnum::SPECIFICATION: - break; - case DataFileTypeEnum::SURFACE: - break; - case DataFileTypeEnum::UNKNOWN: - break; - case DataFileTypeEnum::VOLUME: - break; - } - - if (( ! useMapFileHelperFlag) - && ( ! useMatrixFileHelperFlag)) { - CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); - return false; - } - - bool validDataFlag = false; - if (useMapFileHelperFlag) { - validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, - numberOfColumnsOut, - parcelReorderedRowIndices, - rgbaOut); - } - else if (useMatrixFileHelperFlag) { - validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, - numberOfColumnsOut, - parcelReorderedRowIndices, - rgbaOut); - } - switch (m_matrixContentType) { - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: - break; - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: - break; - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: - break; - } - - return validDataFlag; -} - -/** - * Save subclass data to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass to which data members should be added. Will always - * be valid (non-NULL). - */ -void -ChartableTwoFileDelegateMatrixChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) -{ - m_sceneAssistant->saveMembers(sceneAttributes, - sceneClass); -} - -/** - * Restore file data from the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass for the instance of a class that implements - * this interface. Will NEVER be NULL. - */ -void -ChartableTwoFileDelegateMatrixChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); -} - diff --git a/src/Files/ChartableTwoFileDelegateHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx similarity index 65% rename from src/Files/ChartableTwoFileDelegateHistogramChart.cxx rename to src/Files/ChartableTwoFileHistogramChart.cxx index 735a14af0..271f4b6ac 100644 --- a/src/Files/ChartableTwoFileDelegateHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ -#include "ChartableTwoFileDelegateHistogramChart.h" -#undef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ +#define __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ +#include "ChartableTwoFileHistogramChart.h" +#undef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" @@ -33,7 +33,7 @@ using namespace caret; /** - * \class caret::ChartableTwoFileDelegateHistogramChart + * \class caret::ChartableTwoFileHistogramChart * \brief Implementation of base chart delegate for histogram charts. * \ingroup Files */ @@ -46,21 +46,27 @@ using namespace caret; * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. */ -ChartableTwoFileDelegateHistogramChart::ChartableTwoFileDelegateHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, +ChartableTwoFileHistogramChart::ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, CaretMappableDataFile* parentCaretMappableDataFile) -: ChartableTwoFileDelegateBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, +: ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, parentCaretMappableDataFile), m_histogramContentType(histogramContentType) { - CaretAssert(m_histogramContentType != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED); m_sceneAssistant = new SceneClassAssistant(); + switch (m_histogramContentType) { + case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: + break; + case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram()); + break; + } } /** * Destructor. */ -ChartableTwoFileDelegateHistogramChart::~ChartableTwoFileDelegateHistogramChart() +ChartableTwoFileHistogramChart::~ChartableTwoFileHistogramChart() { delete m_sceneAssistant; } @@ -69,11 +75,30 @@ ChartableTwoFileDelegateHistogramChart::~ChartableTwoFileDelegateHistogramChart( * @return Content type of histogram. */ ChartTwoHistogramContentTypeEnum::Enum -ChartableTwoFileDelegateHistogramChart::getHistogramContentType() const +ChartableTwoFileHistogramChart::getHistogramContentType() const { return m_histogramContentType; } +/** + * @return Is this charting valid ? + */ +bool +ChartableTwoFileHistogramChart::isValid() const +{ + return (m_histogramContentType != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED); +} + +/** + * @retrurn Is this charting empty (no data at this time) + */ +bool +ChartableTwoFileHistogramChart::isEmpty() const +{ + CaretAssertToDoWarning(); + return false; +} + /** * Save subclass data to the scene. @@ -88,7 +113,7 @@ ChartableTwoFileDelegateHistogramChart::getHistogramContentType() const * be valid (non-NULL). */ void -ChartableTwoFileDelegateHistogramChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +ChartableTwoFileHistogramChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, @@ -108,7 +133,7 @@ ChartableTwoFileDelegateHistogramChart::saveSubClassDataToScene(const SceneAttri * this interface. Will NEVER be NULL. */ void -ChartableTwoFileDelegateHistogramChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +ChartableTwoFileHistogramChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, diff --git a/src/Files/ChartableTwoFileDelegateHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h similarity index 67% rename from src/Files/ChartableTwoFileDelegateHistogramChart.h rename to src/Files/ChartableTwoFileHistogramChart.h index 19ed4b474..299ebf36f 100644 --- a/src/Files/ChartableTwoFileDelegateHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -1,5 +1,5 @@ -#ifndef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ -#define __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ +#ifndef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ +#define __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ /*LICENSE_START*/ /* @@ -22,22 +22,26 @@ /*LICENSE_END*/ -#include "ChartableTwoFileDelegateBaseChart.h" +#include "ChartableTwoFileBaseChart.h" #include "ChartTwoHistogramContentTypeEnum.h" namespace caret { - class ChartableTwoFileDelegateHistogramChart : public ChartableTwoFileDelegateBaseChart { + class ChartableTwoFileHistogramChart : public ChartableTwoFileBaseChart { public: - ChartableTwoFileDelegateHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, + ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, CaretMappableDataFile* parentCaretMappableDataFile); - virtual ~ChartableTwoFileDelegateHistogramChart(); + virtual ~ChartableTwoFileHistogramChart(); ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; + virtual bool isValid() const override; + + virtual bool isEmpty() const override; + // ADD_NEW_METHODS_HERE @@ -47,15 +51,15 @@ namespace caret { protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); + SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); + const SceneClass* sceneClass) override; private: - ChartableTwoFileDelegateHistogramChart(const ChartableTwoFileDelegateHistogramChart&); + ChartableTwoFileHistogramChart(const ChartableTwoFileHistogramChart&); - ChartableTwoFileDelegateHistogramChart& operator=(const ChartableTwoFileDelegateHistogramChart&); + ChartableTwoFileHistogramChart& operator=(const ChartableTwoFileHistogramChart&); SceneClassAssistant* m_sceneAssistant; @@ -65,9 +69,9 @@ namespace caret { }; -#ifdef __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ +#ifdef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ // -#endif // __CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_DECLARE__ +#endif // __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ } // namespace -#endif //__CHARTABLE_TWO_FILE_DELEGATE_HISTOGRAM_CHART_H__ +#endif //__CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx new file mode 100644 index 000000000..0183f99f9 --- /dev/null +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -0,0 +1,210 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ +#include "ChartableTwoFileLineSeriesChart.h" +#undef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "CiftiMappableDataFile.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileLineSeriesChart + * \brief Implementation of base chart delegate for line series charts. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param lineSeriesContentType + * Content type of the line series data. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileLineSeriesChart::ChartableTwoFileLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, + CaretMappableDataFile* parentCaretMappableDataFile) +: ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + parentCaretMappableDataFile), +m_lineSeriesContentType(lineSeriesContentType) +{ + m_sceneAssistant = new SceneClassAssistant(); + + ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + int32_t xAxisNumberOfElements = -1; + + CaretMappableDataFile* cmdf = getCaretMappableDataFile(); + CaretAssert(cmdf); + + switch (lineSeriesContentType) { + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: + if (cmdf->getNumberOfMaps() > 1) { + const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + switch (mapUnits) { + case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: + CaretAssert(0); + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: + break; + } + xAxisNumberOfElements = cmdf->getNumberOfMaps(); + } + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + { + const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); + CaretAssert(ciftiMapFile); + std::vector dims; + ciftiMapFile->getMapDimensions(dims); + CaretAssertVectorIndex(dims, 1); + const int32_t numCols = dims[0]; + const int32_t numRows = dims[1]; + + if ((numRows > 0) + && (numCols > 1)) { + const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); + ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + switch (mapUnits) { + case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: + CaretAssert(0); + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: + break; + } + xAxisNumberOfElements = numCols; + } + } break; + } + + if (xAxisNumberOfElements > 0) { + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, + xAxisNumberOfElements)); + } +} + +/** + * Destructor. + */ +ChartableTwoFileLineSeriesChart::~ChartableTwoFileLineSeriesChart() +{ + delete m_sceneAssistant; +} + +/** + * @return Content type of the line series data. + */ +ChartTwoLineSeriesContentTypeEnum::Enum +ChartableTwoFileLineSeriesChart::getLineSeriesContentType() const +{ + return m_lineSeriesContentType; +} + +/** + * @return Is this charting valid ? + */ +bool +ChartableTwoFileLineSeriesChart::isValid() const +{ + return (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED); +} + +/** + * @retrurn Is this charting empty (no data at this time) + */ +bool +ChartableTwoFileLineSeriesChart::isEmpty() const +{ + CaretAssertToDoWarning(); + return false; +} +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartableTwoFileLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartableTwoFileLineSeriesChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + diff --git a/src/Files/ChartableTwoFileDelegateLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h similarity index 67% rename from src/Files/ChartableTwoFileDelegateLineSeriesChart.h rename to src/Files/ChartableTwoFileLineSeriesChart.h index a64a802ae..3c6c120b5 100644 --- a/src/Files/ChartableTwoFileDelegateLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -1,5 +1,5 @@ -#ifndef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ -#define __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ +#ifndef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ +#define __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ /*LICENSE_START*/ /* @@ -22,22 +22,26 @@ /*LICENSE_END*/ -#include "ChartableTwoFileDelegateBaseChart.h" +#include "ChartableTwoFileBaseChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" namespace caret { - class ChartableTwoFileDelegateLineSeriesChart : public ChartableTwoFileDelegateBaseChart { + class ChartableTwoFileLineSeriesChart : public ChartableTwoFileBaseChart { public: - ChartableTwoFileDelegateLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, + ChartableTwoFileLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, CaretMappableDataFile* parentCaretMappableDataFile); - virtual ~ChartableTwoFileDelegateLineSeriesChart(); + virtual ~ChartableTwoFileLineSeriesChart(); ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; + virtual bool isValid() const override; + + virtual bool isEmpty() const override; + // ADD_NEW_METHODS_HERE @@ -48,15 +52,15 @@ namespace caret { protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); + SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); + const SceneClass* sceneClass) override; private: - ChartableTwoFileDelegateLineSeriesChart(const ChartableTwoFileDelegateLineSeriesChart&); + ChartableTwoFileLineSeriesChart(const ChartableTwoFileLineSeriesChart&); - ChartableTwoFileDelegateLineSeriesChart& operator=(const ChartableTwoFileDelegateLineSeriesChart&); + ChartableTwoFileLineSeriesChart& operator=(const ChartableTwoFileLineSeriesChart&); SceneClassAssistant* m_sceneAssistant; @@ -66,9 +70,9 @@ namespace caret { }; -#ifdef __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ +#ifdef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ // -#endif // __CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_DECLARE__ +#endif // __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ } // namespace -#endif //__CHARTABLE_TWO_FILE_DELEGATE_LINE_SERIES_CHART_H__ +#endif //__CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx new file mode 100644 index 000000000..fbb17e7ee --- /dev/null +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -0,0 +1,379 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ +#include "ChartableTwoFileMatrixChart.h" +#undef __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ + +#include "CaretAssert.h" +#include "CiftiConnectivityMatrixParcelFile.h" +#include "CiftiParcelLabelFile.h" +#include "CiftiParcelReordering.h" +#include "CiftiParcelScalarFile.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartableTwoFileMatrixChart + * \brief Implementation of base chart delegate for matrix charts. + * \ingroup Files + */ + +/** + * Constructor. + * + * @param matrixContentType + * Content type of the matrix. + * @param parentCaretMappableDataFile + * Parent caret mappable data file that this delegate supports. + */ +ChartableTwoFileMatrixChart::ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, + CaretMappableDataFile* parentCaretMappableDataFile) +: ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + parentCaretMappableDataFile), +m_matrixContentType(matrixContentType) +{ + m_sceneAssistant = new SceneClassAssistant(); + + int32_t numRows = 0; + int32_t numCols = 0; + + if (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { + CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + ciftiMapFile->helpMapFileGetMatrixDimensions(numRows, + numCols); + if ((numRows > 0) + || (numCols > 0)) { + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, + numCols)); + } + } +} + +/** + * Destructor. + */ +ChartableTwoFileMatrixChart::~ChartableTwoFileMatrixChart() +{ + delete m_sceneAssistant; +} + +/** + * @return Content type of the matrix. + */ +ChartTwoMatrixContentTypeEnum::Enum +ChartableTwoFileMatrixChart::getMatrixContentType() const +{ + return m_matrixContentType; +} + +/** + * @return Is this charting valid ? + */ +bool +ChartableTwoFileMatrixChart::isValid() const +{ + return (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED); +} + +/** + * @retrurn Is this charting empty (no data at this time) + */ +bool +ChartableTwoFileMatrixChart::isEmpty() const +{ + int32_t numRows = 0; + int32_t numCols = 0; + getMatrixDimensions(numRows, + numCols); + if ((numRows > 0) + || (numCols > 0)) { + return false; + } + + return true; +} + +/** + * Get the matrix dimensions. + * + * @param numberOfRowsOut + * Number of rows in the matrix. + * @param numberOfColumnsOut + * Number of rows in the matrix. + */ +void +ChartableTwoFileMatrixChart::getMatrixDimensions(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut) const +{ + numberOfRowsOut = 0; + numberOfColumnsOut = 0; + + if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { + return; + } + + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, + numberOfColumnsOut); +} + +/** + * Get the matrix RGBA coloring for this matrix data creator. + * + * @param numberOfRowsOut + * Number of rows in the coloring matrix. + * @param numberOfColumnsOut + * Number of rows in the coloring matrix. + * @param rgbaOut + * RGBA coloring output with number of elements + * (numberOfRowsOut * numberOfColumnsOut * 4). + * @return + * True if data output data is valid, else false. + */ +bool +ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut, + std::vector& rgbaOut) const +{ + + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + + return ciftiMapFile->getMatrixForChartingRGBA(numberOfRowsOut, + numberOfColumnsOut, + rgbaOut); + +// bool useMapFileHelperFlag = false; +// bool useMatrixFileHelperFlag = false; +// +// std::vector parcelReorderedRowIndices; +// +// switch (ciftiMapFile->getDataFileType()) { +// case DataFileTypeEnum::CONNECTIVITY_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: +// break; +// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL: +// { +// useMatrixFileHelperFlag = true; +// +// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(ciftiMapFile); +// CaretAssert(parcelConnFile); +// if (parcelConnFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); +// CaretAssert(parcelLabelFile); +// if (parcelLabelFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: +// { +// useMapFileHelperFlag = true; +// +// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); +// CaretAssert(parcelScalarFile); +// if (parcelScalarFile != NULL) { +// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; +// int32_t parcelLabelFileMapIndex = -1; +// bool reorderingEnabledFlag = false; +// +// std::vector parcelLabelFiles; +// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, +// parcelLabelReorderingFile, +// parcelLabelFileMapIndex, +// reorderingEnabledFlag); +// +// if (reorderingEnabledFlag) { +// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, +// parcelLabelFileMapIndex); +// if (parcelReordering != NULL) { +// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); +// } +// } +// } +// } +// break; +// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: +// break; +// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: +// useMatrixFileHelperFlag = true; +// break; +// case DataFileTypeEnum::ANNOTATION: +// break; +// case DataFileTypeEnum::BORDER: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: +// break; +// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: +// break; +// case DataFileTypeEnum::FOCI: +// break; +// case DataFileTypeEnum::IMAGE: +// break; +// case DataFileTypeEnum::LABEL: +// break; +// case DataFileTypeEnum::METRIC: +// break; +// case DataFileTypeEnum::PALETTE: +// break; +// case DataFileTypeEnum::RGBA: +// break; +// case DataFileTypeEnum::SCENE: +// break; +// case DataFileTypeEnum::SPECIFICATION: +// break; +// case DataFileTypeEnum::SURFACE: +// break; +// case DataFileTypeEnum::UNKNOWN: +// break; +// case DataFileTypeEnum::VOLUME: +// break; +// } +// +// if (( ! useMapFileHelperFlag) +// && ( ! useMatrixFileHelperFlag)) { +// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); +// return false; +// } +// +// bool validDataFlag = false; +// if (useMapFileHelperFlag) { +// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, +// numberOfColumnsOut, +// parcelReorderedRowIndices, +// rgbaOut); +// } +// else if (useMatrixFileHelperFlag) { +// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, +// numberOfColumnsOut, +// parcelReorderedRowIndices, +// rgbaOut); +// } +// switch (m_matrixContentType) { +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: +// break; +// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: +// break; +// } +// +// return validDataFlag; +} + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartableTwoFileMatrixChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartableTwoFileMatrixChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + diff --git a/src/Files/ChartableTwoFileDelegateMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h similarity index 72% rename from src/Files/ChartableTwoFileDelegateMatrixChart.h rename to src/Files/ChartableTwoFileMatrixChart.h index 4df13d254..a635889b9 100644 --- a/src/Files/ChartableTwoFileDelegateMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -1,5 +1,5 @@ -#ifndef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ -#define __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ +#ifndef __CHARTABLE_TWO_FILE_MATRIX_CHART_H__ +#define __CHARTABLE_TWO_FILE_MATRIX_CHART_H__ /*LICENSE_START*/ /* @@ -22,20 +22,24 @@ /*LICENSE_END*/ #include "ChartTwoMatrixContentTypeEnum.h" -#include "ChartableTwoFileDelegateBaseChart.h" +#include "ChartableTwoFileBaseChart.h" namespace caret { - class ChartableTwoFileDelegateMatrixChart : public ChartableTwoFileDelegateBaseChart { + class ChartableTwoFileMatrixChart : public ChartableTwoFileBaseChart { public: - ChartableTwoFileDelegateMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, + ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, CaretMappableDataFile* parentCaretMappableDataFile); - virtual ~ChartableTwoFileDelegateMatrixChart(); + virtual ~ChartableTwoFileMatrixChart(); ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; + virtual bool isValid() const override; + + virtual bool isEmpty() const override; + void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; @@ -51,15 +55,15 @@ namespace caret { protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); + SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); + const SceneClass* sceneClass) override; private: - ChartableTwoFileDelegateMatrixChart(const ChartableTwoFileDelegateMatrixChart&); + ChartableTwoFileMatrixChart(const ChartableTwoFileMatrixChart&); - ChartableTwoFileDelegateMatrixChart& operator=(const ChartableTwoFileDelegateMatrixChart&); + ChartableTwoFileMatrixChart& operator=(const ChartableTwoFileMatrixChart&); SceneClassAssistant* m_sceneAssistant; @@ -68,9 +72,9 @@ namespace caret { }; -#ifdef __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ +#ifdef __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ // -#endif // __CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_DECLARE__ +#endif // __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ } // namespace -#endif //__CHARTABLE_TWO_FILE_DELEGATE_MATRIX_CHART_H__ +#endif //__CHARTABLE_TWO_FILE_MATRIX_CHART_H__ diff --git a/src/Files/ChartableTwoInterface.h b/src/Files/ChartableTwoInterface.h index 3168f2068..f54010790 100644 --- a/src/Files/ChartableTwoInterface.h +++ b/src/Files/ChartableTwoInterface.h @@ -24,9 +24,9 @@ #include "ChartTwoCompoundDataType.h" #include "ChartTwoDataTypeEnum.h" -#include "ChartableTwoFileDelegateHistogramChart.h" -#include "ChartableTwoFileDelegateLineSeriesChart.h" -#include "ChartableTwoFileDelegateMatrixChart.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" #include "ChartTwoMatrixContentTypeEnum.h" @@ -47,17 +47,17 @@ namespace caret { virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const = 0; - virtual ChartableTwoFileDelegateHistogramChart* getHistogramChartDelegate() = 0; + virtual ChartableTwoFileHistogramChart* getHistogramChartDelegate() = 0; - virtual const ChartableTwoFileDelegateHistogramChart* getHistogramChartDelegate() const = 0; + virtual const ChartableTwoFileHistogramChart* getHistogramChartDelegate() const = 0; - virtual ChartableTwoFileDelegateLineSeriesChart* getLineSeriesChartDelegate() = 0; + virtual ChartableTwoFileLineSeriesChart* getLineSeriesChartDelegate() = 0; - virtual const ChartableTwoFileDelegateLineSeriesChart* getLineSeriesChartDelegate() const = 0; + virtual const ChartableTwoFileLineSeriesChart* getLineSeriesChartDelegate() const = 0; - virtual ChartableTwoFileDelegateMatrixChart* getMatrixChartDelegate() = 0; + virtual ChartableTwoFileMatrixChart* getMatrixChartDelegate() = 0; - virtual const ChartableTwoFileDelegateMatrixChart* getMatrixChartDelegate() const = 0; + virtual const ChartableTwoFileMatrixChart* getMatrixChartDelegate() const = 0; bool isChartingSupported() const; diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 0b12ecc10..e34ea5612 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -30,10 +30,13 @@ #include "ChartDataCartesian.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" +#include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiFile.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiParcelLabelFile.h" +#include "CiftiParcelReordering.h" +#include "CiftiParcelScalarFile.h" #include "CaretTemporaryFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" @@ -1443,6 +1446,185 @@ CiftiMappableDataFile::getMatrixRGBA(std::vector &rgba, } } +/** + * Get the matrix RGBA coloring for this matrix data creator. + * + * @param numberOfRowsOut + * Number of rows in the coloring matrix. + * @param numberOfColumnsOut + * Number of rows in the coloring matrix. + * @param rgbaOut + * RGBA coloring output with number of elements + * (numberOfRowsOut * numberOfColumnsOut * 4). + * @return + * True if data output data is valid, else false. + */ +bool +CiftiMappableDataFile::getMatrixForChartingRGBA(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut, + std::vector& rgbaOut) const +{ + bool useMapFileHelperFlag = false; + bool useMatrixFileHelperFlag = false; + + std::vector parcelReorderedRowIndices; + + switch (getDataFileType()) { + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + { + useMatrixFileHelperFlag = true; + + const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(this); + CaretAssert(parcelConnFile); + if (parcelConnFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + { + useMapFileHelperFlag = true; + + const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(this); + CaretAssert(parcelLabelFile); + if (parcelLabelFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + { + useMapFileHelperFlag = true; + + const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(this); + CaretAssert(parcelScalarFile); + if (parcelScalarFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + + std::vector parcelLabelFiles; + parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + useMatrixFileHelperFlag = true; + break; + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + } + + if (( ! useMapFileHelperFlag) + && ( ! useMatrixFileHelperFlag)) { + CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); + return false; + } + + bool validDataFlag = false; + if (useMapFileHelperFlag) { + validDataFlag = helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, + numberOfColumnsOut, + parcelReorderedRowIndices, + rgbaOut); + } + else if (useMatrixFileHelperFlag) { + validDataFlag = helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, + numberOfColumnsOut, + parcelReorderedRowIndices, + rgbaOut); + } + + return validDataFlag; +} + /** * Get the dimensions of the file (rows and columns). * diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 50797c201..dcb2ac462 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -476,6 +476,10 @@ namespace caret { virtual void getMatrixRGBA(std::vector& rgba, PaletteFile *paletteFile); + bool getMatrixForChartingRGBA(int32_t& numberOfRowsOut, + int32_t& numberOfColumnsOut, + std::vector& rgbaOut) const; + virtual void getFileData(std::vector& data) const; const CiftiFile* getCiftiFile() const { return m_ciftiFile; } @@ -758,7 +762,7 @@ namespace caret { private: friend class ChartableTwoFileDelegate; - friend class ChartableTwoFileDelegateMatrixChart; + friend class ChartableTwoFileMatrixChart; // std::vector m_ciftiDimensions; -- GitLab From a8baee6b646dd199bc9d89029f7f3f3eb8a7beb4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 18 Jan 2017 15:51:59 -0600 Subject: [PATCH 184/755] Continuing charting development. A 'charting delegate' has been completed. Selection of chart overlays using the charting delegate has is functioning for all chart data types. --- src/Brain/ChartOverlay.cxx | 19 ++++-- src/Brain/ChartOverlaySet.cxx | 32 +++++++-- src/Brain/ChartOverlaySet.h | 2 + src/Brain/ModelChart.cxx | 4 +- src/Charting/ChartTwoCompoundDataType.cxx | 66 +++++++++++++----- src/Charting/ChartTwoCompoundDataType.h | 15 ++-- src/Files/CMakeLists.txt | 3 - src/Files/CaretMappableDataFile.cxx | 27 +++----- src/Files/CaretMappableDataFile.h | 16 +++-- src/Files/ChartableTwoFileDelegate.cxx | 21 +++--- src/Files/ChartableTwoFileDelegate.h | 3 +- src/Files/ChartableTwoFileHistogramChart.cxx | 12 +++- src/Files/ChartableTwoFileLineSeriesChart.cxx | 51 ++++++++++---- src/Files/ChartableTwoFileLineSeriesChart.h | 13 +++- src/Files/ChartableTwoFileMatrixChart.cxx | 17 +++-- src/Files/ChartableTwoFileMatrixChart.h | 3 +- src/Files/CiftiMappableDataFile.cxx | 27 ++++++++ src/Files/GiftiTypeFile.cxx | 1 + src/Files/VolumeFile.cxx | 1 + src/GuiQt/ChartOverlayViewController.cxx | 68 ++++++++++++++----- 20 files changed, 289 insertions(+), 112 deletions(-) diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index 1e83acf5f..cde8f9f74 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -27,7 +27,10 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" -#include "ChartableTwoInterface.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" #include "ChartOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" @@ -146,6 +149,7 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co me->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { + descriptionOut.addLine("Overlay Index: " + AString::number(m_overlayIndex)); descriptionOut.addLine("File: "+ mapFile->getFileNameNoPath()); if (mapFile->hasMapAttributes()) { @@ -157,6 +161,12 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co + mapFile->getMapName(mapIndex)); } } + + const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + ChartTwoCompoundDataType cdt; + chartDelegate->getChartCompoundDataTypeForChartDataType(getChartDataType(), + cdt); + descriptionOut.addLine(cdt.toString()); } } } @@ -383,8 +393,8 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, */ for (auto mapFile : allDataFiles) { CaretAssert(mapFile); - ChartableTwoInterface* chartingFile = dynamic_cast(mapFile); - if (chartingFile != NULL) { + ChartableTwoFileDelegate* chartingFile = mapFile->getChartingDelegate(); + if (chartingFile->isChartingSupported()) { bool useIt = false; std::vector chartCompoundDataTypes; @@ -456,6 +466,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, if (mapTypeFile->getNumberOfMaps() > 0) { m_selectedMapFile = mapTypeFile; m_selectedMapIndex = 0; + break; } } } @@ -486,7 +497,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, */ if (m_overlayIndex == 0) { if (m_selectedMapFile != NULL) { - ChartableTwoInterface* chartFile = dynamic_cast(m_selectedMapFile); + ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartFile); chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, m_chartCompoundDataType); diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx index 0e3cf1987..2219b7a92 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartOverlaySet.cxx @@ -168,9 +168,9 @@ ChartOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) if (getOverlay(i)->isEnabled()) { descriptionOut.pushIndentation(); - descriptionOut.addLine("Overlay " - + AString::number(i + 1) - + ": "); +// descriptionOut.addLine("Overlay " +// + AString::number(i + 1) +// + ": "); descriptionOut.pushIndentation(); getOverlay(i)->getDescriptionOfContent(descriptionOut); @@ -481,17 +481,35 @@ ChartOverlaySet::initializeOverlays() void ChartOverlaySet::firstOverlaySelectionChanged() { + if (m_inFirstOverlayChangedMethodFlag) { + return; + } + + m_inFirstOverlayChangedMethodFlag = true; + ChartTwoCompoundDataType cdt = m_overlays[0]->getChartTwoCompoundDataType(); - std::cout << qPrintable("Chart Overlay in tab " - + AString::number(m_tabIndex + 1) - + ":\n" - + cdt.toString()) << std::endl; + + + +// std::cout << qPrintable("First Chart Overlay in tab " +// + AString::number(m_tabIndex + 1) +// + ":\n" +// + cdt.toString()) << std::endl; for (int32_t i = 1; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->setChartTwoCompoundDataType(cdt); +// if (m_overlays[i]->isEnabled()) { +// std::cout << " Overlay " << i << qPrintable(m_overlays[i]->toString()) << std::endl; +// } } + + PlainTextStringBuilder description; + getDescriptionOfContent(description); + std::cout << "First Overlay Changed: " << qPrintable(description.getText()) << std::endl; + + m_inFirstOverlayChangedMethodFlag = false; } diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartOverlaySet.h index 2caeb8725..8bab08ed8 100644 --- a/src/Brain/ChartOverlaySet.h +++ b/src/Brain/ChartOverlaySet.h @@ -120,6 +120,8 @@ namespace caret { int32_t m_numberOfDisplayedOverlays; + bool m_inFirstOverlayChangedMethodFlag = false; + // ADD_NEW_MEMBERS_HERE friend class ChartOverlay; diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 4b39327f3..9808bf431 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -33,7 +33,7 @@ #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartableLineSeriesRowColumnInterface.h" #include "ChartableMatrixInterface.h" -#include "ChartableTwoInterface.h" +#include "ChartableTwoFileDelegate.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" @@ -2024,7 +2024,7 @@ ModelChart::getValidChartDataTypes(std::vector& vali std::set chartTypeSet; for (auto mapFile : allDataFiles) { - ChartableTwoInterface* chartFile = dynamic_cast(mapFile); + ChartableTwoFileDelegate* chartFile = mapFile->getChartingDelegate(); std::vector fileChartTypes; chartFile->getSupportedChartDataTypes(fileChartTypes); diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index 68108b467..2438a4fad 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -45,6 +45,8 @@ using namespace caret; * * @param chartDataType * Chart data type. + * @param histogramNumberOfBuckets + * Number of bins in the histogram. * @param lineChartUnitsAxisX * Line chart x-axis units. * @param lineChartNumberOfElementsAxisX @@ -55,15 +57,17 @@ using namespace caret; * Matrix number of columns. */ ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, - const int32_t lineChartNumberOfElementsAxisX, - const int32_t matrixNumberOfRows, - const int32_t matrixNumberOfColumns) + const int32_t histogramNumberOfBuckets, + const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX, + const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns) : CaretObject() { initializeChartTwoCompoundDataType(); m_chartDataType = chartDataType; + m_histogramNumberOfBuckets = histogramNumberOfBuckets; m_lineChartUnitsAxisX = lineChartUnitsAxisX; m_lineChartNumberOfElementsAxisX = lineChartNumberOfElementsAxisX; m_matrixNumberOfRows = matrixNumberOfRows; @@ -88,43 +92,59 @@ ChartTwoCompoundDataType::~ChartTwoCompoundDataType() /** * @return A new instance for a histogram chart. + * + * @param histogramNumberOfBins + * Number of bins in the histogram. */ ChartTwoCompoundDataType -ChartTwoCompoundDataType::newInstanceForHistogram() +ChartTwoCompoundDataType::newInstanceForHistogram(const int32_t histogramNumberOfBins) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - 0, - 0, - 0); + histogramNumberOfBins, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + 0, + 0, + 0); } /** * @return A new instance for a line-series chart. + * + * @param lineChartUnitsAxisX + * Line chart x-axis units. + * @param lineChartNumberOfElementsAxisX + * Line chart x-axis number of elements. */ ChartTwoCompoundDataType ChartTwoCompoundDataType::newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, - lineChartUnitsAxisX, - lineChartNumberOfElementsAxisX, - 0, - 0); + 0, + lineChartUnitsAxisX, + lineChartNumberOfElementsAxisX, + 0, + 0); } /** * @return A new instance for a matrix chart. + * + * @param matrixNumberOfRows + * Matrix number of rows. + * @param matrixNumberOfColumns + * Matrix number of columns. */ ChartTwoCompoundDataType ChartTwoCompoundDataType::newInstanceForMatrix(const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - 0, - matrixNumberOfRows, - matrixNumberOfColumns); + 0, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + 0, + matrixNumberOfRows, + matrixNumberOfColumns); } @@ -256,6 +276,15 @@ ChartTwoCompoundDataType::getChartDataType() const return m_chartDataType; } +/** + * @return Histogram number of buckets. + */ +int32_t +ChartTwoCompoundDataType::getHistogramNumberOfBuckets() const +{ + return m_histogramNumberOfBuckets; +} + /** * @return Line chart X-axis units. */ @@ -307,6 +336,9 @@ ChartTwoCompoundDataType::toString() const case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + text.appendWithNewLine(indent + + "buckets=" + + QString::number(m_histogramNumberOfBuckets)); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: text.appendWithNewLine(indent diff --git a/src/Charting/ChartTwoCompoundDataType.h b/src/Charting/ChartTwoCompoundDataType.h index 93aaaafa7..913c6adc7 100644 --- a/src/Charting/ChartTwoCompoundDataType.h +++ b/src/Charting/ChartTwoCompoundDataType.h @@ -37,12 +37,13 @@ namespace caret { ChartTwoCompoundDataType(); ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, - const int32_t lineChartNumberOfElementsAxisX, - const int32_t matrixNumberOfRows, - const int32_t matrixNumberOfColumns); + const int32_t histogramNumberOfBuckets, + const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const int32_t lineChartNumberOfElementsAxisX, + const int32_t matrixNumberOfRows, + const int32_t matrixNumberOfColumns); - static ChartTwoCompoundDataType newInstanceForHistogram(); + static ChartTwoCompoundDataType newInstanceForHistogram(const int32_t histogramNumberOfBuckets); static ChartTwoCompoundDataType newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX); @@ -61,6 +62,8 @@ namespace caret { ChartTwoDataTypeEnum::Enum getChartDataType() const; + int32_t getHistogramNumberOfBuckets() const; + ChartAxisUnitsEnum::Enum getLineChartUnitsAxisX() const; int32_t getLineChartNumberOfElementsAxisX() const; @@ -103,6 +106,8 @@ namespace caret { ChartTwoDataTypeEnum::Enum m_chartDataType; + int32_t m_histogramNumberOfBuckets; + ChartAxisUnitsEnum::Enum m_lineChartUnitsAxisX; int32_t m_lineChartNumberOfElementsAxisX; diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 022f43713..b43b924f7 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -45,8 +45,6 @@ ChartableMatrixInterface.h ChartableMatrixParcelInterface.h ChartableMatrixSeriesInterface.h -ChartableTwoInterface.h - ChartableTwoFileDelegate.h ChartableTwoFileBaseChart.h ChartableTwoFileHistogramChart.h @@ -170,7 +168,6 @@ CaretSparseFile.cxx CaretVolumeExtension.cxx ChartableLineSeriesInterface.cxx ChartableMatrixInterface.cxx -ChartableTwoInterface.cxx ChartableTwoFileDelegate.cxx ChartableTwoFileBaseChart.cxx diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 8ad751c39..0499edd43 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -102,8 +102,6 @@ void CaretMappableDataFile::initializeCaretMappableDataFileInstance() { m_labelDrawingProperties = std::unique_ptr(new LabelDrawingProperties()); - - m_lineChartHistory = std::unique_ptr(new ChartTwoDataCartesianHistory()); } @@ -314,8 +312,6 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute sceneClass); - sceneClass->addClass(m_lineChartHistory->saveToScene(sceneAttributes, - "m_lineChartHistory")); sceneClass->addClass(m_labelDrawingProperties->saveToScene(sceneAttributes, "m_labelDrawingProperties")); @@ -404,9 +400,6 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr m_labelDrawingProperties->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelDrawingProperties")); - m_lineChartHistory->restoreFromScene(sceneAttributes, - sceneClass->getClass("m_lineChartHistory")); - if (isMappedWithPalette()) { /* * Palette normalization was no longer saved to scenes after @@ -1083,16 +1076,16 @@ CaretMappableDataFile::isMappedWithRGBA() const return false; } -//bool CaretMappableDataFile::hasCiftiXML() const -//{ -// return false; -//} -// -//const CiftiXML CaretMappableDataFile::getCiftiXML() const -//{ -// return CiftiXML(); -//} -// +bool CaretMappableDataFile::hasCiftiXML() const +{ + return false; +} + +const CiftiXML CaretMappableDataFile::getCiftiXML() const +{ + return CiftiXML(); +} + ///** // * @return The CaretMappableDataFile that implements this interface. // */ diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 894ebd17b..0671bf2b5 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -26,14 +26,14 @@ #include "CaretDataFile.h" #include "ChartOneDataTypeEnum.h" #include "CaretPointer.h" +#include "CiftiXML.h" #include "NiftiEnums.h" #include "PaletteNormalizationModeEnum.h" namespace caret { class ChartDataCartesian; - class CiftiXML; - class ChartTwoDataCartesianHistory; + class ChartableTwoFileDelegate; class FastStatistics; class GiftiMetaData; class GiftiLabelTable; @@ -451,7 +451,9 @@ namespace caret { virtual const CiftiXML getCiftiXML() const; /* documented in cxx file. */ - bool isModified() const; + virtual bool isModified() const override; + + virtual void clearModified() override; void initializeCaretMappableDataFileInstance(); @@ -459,6 +461,10 @@ namespace caret { const LabelDrawingProperties* getLabelDrawingProperties() const; + ChartableTwoFileDelegate* getChartingDelegate(); + + const ChartableTwoFileDelegate* getChartingDelegate() const; + protected: CaretMappableDataFile(const CaretMappableDataFile&); @@ -468,6 +474,8 @@ namespace caret { void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + void updateChartingDelegate(); + virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); @@ -480,7 +488,7 @@ namespace caret { std::unique_ptr m_labelDrawingProperties; - std::unique_ptr m_lineChartHistory; + mutable std::unique_ptr m_chartingDelegate; }; #ifdef __CARET_MAPPABLE_DATA_FILE_DECLARE__ diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index fd608a439..b640842b2 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -164,8 +164,10 @@ ChartableTwoFileDelegate::updateAfterFileChanged() case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: - histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; - lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + if ( ! m_caretMappableDataFile->isMappedWithLabelTable()) { + histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; + lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + } break; } @@ -178,6 +180,8 @@ ChartableTwoFileDelegate::updateAfterFileChanged() m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(matrixType, m_caretMappableDataFile)); + + clearModified(); } /** @@ -374,9 +378,6 @@ ChartableTwoFileDelegate::getSupportedChartDataTypes(std::vectorgetChartDataType()); } - - CaretAssertMessage((! chartDataTypesOut.empty()), - "Why is this delegate used if parent file does not support charts?"); } /** @@ -390,20 +391,16 @@ ChartableTwoFileDelegate::getSupportedChartCompoundDataTypes(std::vectorgetHistogramContentType() != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_histogramCharting->getChartCompoundDataType()); } - if (m_lineSeriesCharting != NULL) { + if (m_lineSeriesCharting->getLineSeriesContentType() != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_lineSeriesCharting->getChartCompoundDataType()); } - if (m_matrixCharting != NULL) { + if (m_matrixCharting->getMatrixContentType() != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartCompoundDataType()); } - CaretAssertMessage((! chartCompoundDataTypesOut.empty()), - "Why is this delegate used if parent file does not support charts?"); - // const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); // if (cmdf == NULL) { // return; diff --git a/src/Files/ChartableTwoFileDelegate.h b/src/Files/ChartableTwoFileDelegate.h index 1f89556a1..c98cc0511 100644 --- a/src/Files/ChartableTwoFileDelegate.h +++ b/src/Files/ChartableTwoFileDelegate.h @@ -37,10 +37,9 @@ namespace caret { class ChartableTwoFileDelegate : public CaretObjectTracksModification, public SceneableInterface { - private: + public: ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile); - public: virtual ~ChartableTwoFileDelegate(); void updateAfterFileChanged(); diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 271f4b6ac..f242b34f3 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -25,6 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" +#include "Histogram.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -58,9 +59,18 @@ m_histogramContentType(histogramContentType) case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: break; case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram()); break; } + + int32_t histogramNumberOfBuckets = 0; + CaretMappableDataFile* cmdf = getCaretMappableDataFile(); + if (cmdf->getNumberOfMaps() > 0) { + const Histogram* histogram = cmdf->getMapHistogram(0); + if (histogram != NULL) { + histogramNumberOfBuckets = histogram->getNumberOfBuckets(); + } + } + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram(histogramNumberOfBuckets)); } /** diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 0183f99f9..85177aedd 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -24,13 +24,12 @@ #undef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ #include "CaretAssert.h" +#include "ChartTwoDataCartesianHistory.h" #include "CiftiMappableDataFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; - - /** * \class caret::ChartableTwoFileLineSeriesChart @@ -52,10 +51,10 @@ ChartableTwoFileLineSeriesChart::ChartableTwoFileLineSeriesChart(const ChartTwoL parentCaretMappableDataFile), m_lineSeriesContentType(lineSeriesContentType) { - m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; - int32_t xAxisNumberOfElements = -1; + int32_t xAxisNumberOfElements = 0; CaretMappableDataFile* cmdf = getCaretMappableDataFile(); CaretAssert(cmdf); @@ -91,7 +90,7 @@ m_lineSeriesContentType(lineSeriesContentType) break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: { - const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); std::vector dims; ciftiMapFile->getMapDimensions(dims); @@ -102,7 +101,7 @@ m_lineSeriesContentType(lineSeriesContentType) if ((numRows > 0) && (numCols > 1)) { const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); - ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; switch (mapUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; @@ -126,11 +125,21 @@ m_lineSeriesContentType(lineSeriesContentType) } } break; } - - if (xAxisNumberOfElements > 0) { - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, - xAxisNumberOfElements)); + + m_lineChartHistory = std::unique_ptr(new ChartTwoDataCartesianHistory()); + m_sceneAssistant->add("m_lineChartHistory", + "ChartTwoDataCartesianHistory", + m_lineChartHistory.get()); + + /* + * Must have two or more elements + */ + if (xAxisNumberOfElements <= 1) { + m_lineSeriesContentType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; } + + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, + xAxisNumberOfElements)); } /** @@ -138,7 +147,6 @@ m_lineSeriesContentType(lineSeriesContentType) */ ChartableTwoFileLineSeriesChart::~ChartableTwoFileLineSeriesChart() { - delete m_sceneAssistant; } /** @@ -150,6 +158,25 @@ ChartableTwoFileLineSeriesChart::getLineSeriesContentType() const return m_lineSeriesContentType; } +/** + * @return History of line charts. + */ +ChartTwoDataCartesianHistory* +ChartableTwoFileLineSeriesChart::getHistory() +{ + return m_lineChartHistory.get(); +} + +/** + * @return History of line charts (const method) + */ +const ChartTwoDataCartesianHistory* +ChartableTwoFileLineSeriesChart::getHistory() const +{ + return m_lineChartHistory.get(); +} + + /** * @return Is this charting valid ? */ @@ -165,7 +192,7 @@ ChartableTwoFileLineSeriesChart::isValid() const bool ChartableTwoFileLineSeriesChart::isEmpty() const { - CaretAssertToDoWarning(); + CaretAssertToDoWarning(); // use history??? return false; } /** diff --git a/src/Files/ChartableTwoFileLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h index 3c6c120b5..d210729b8 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -21,13 +21,14 @@ */ /*LICENSE_END*/ - #include "ChartableTwoFileBaseChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" namespace caret { + class ChartTwoDataCartesianHistory; + class ChartableTwoFileLineSeriesChart : public ChartableTwoFileBaseChart { public: @@ -38,6 +39,10 @@ namespace caret { ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; + ChartTwoDataCartesianHistory* getHistory(); + + const ChartTwoDataCartesianHistory* getHistory() const; + virtual bool isValid() const override; virtual bool isEmpty() const override; @@ -62,9 +67,11 @@ namespace caret { ChartableTwoFileLineSeriesChart& operator=(const ChartableTwoFileLineSeriesChart&); - SceneClassAssistant* m_sceneAssistant; + std::unique_ptr m_sceneAssistant; - const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; + ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; + + std::unique_ptr m_lineChartHistory; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index fbb17e7ee..35051c193 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -65,12 +65,19 @@ m_matrixContentType(matrixContentType) CaretAssert(ciftiMapFile); ciftiMapFile->helpMapFileGetMatrixDimensions(numRows, numCols); - if ((numRows > 0) - || (numCols > 0)) { - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, - numCols)); - } } + + if ((numRows > 0) + && (numCols > 0)) { + /* OK */ + } + else { + m_matrixContentType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; + } + + + updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, + numCols)); } /** diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index a635889b9..c632c786e 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -67,7 +67,8 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; + ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index e34ea5612..479943859 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -960,6 +960,31 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) } break; } + + /* + * Special case for scalar data series that does NOT map to brainordinates + */ + if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + const CiftiSeriesMap& map = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); + CiftiSeriesMap::Unit units = map.getUnit(); + switch (units) { + case CiftiSeriesMap::HERTZ: + m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_HZ; + break; + case CiftiSeriesMap::METER: + CaretLogWarning("CIFTI Units METER not implemented"); + break; + case CiftiSeriesMap::RADIAN: + CaretLogWarning("CIFTI Units RADIAN not implemented"); + break; + case CiftiSeriesMap::SECOND: + m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_SEC; + break; + } + m_mappingTimeStart = map.getStart(); + m_mappingTimeStep = map.getStep(); + } + /* * May not have mappings to voxels */ @@ -1020,6 +1045,8 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) validateKeysAndLabels(); validateAfterFileReading(); + + updateChartingDelegate(); } /** diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 87dd314cf..73355552e 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -151,6 +151,7 @@ GiftiTypeFile::readFile(const AString& filename) this->giftiFile->readFile(filename); this->validateDataArraysAfterReading(); this->clearModified(); + updateChartingDelegate(); } /** diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 49711eaa1..7d512e0c3 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -288,6 +288,7 @@ void VolumeFile::readFile(const AString& filename) } m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); + updateChartingDelegate(); /* * This will update the map name/label hierarchy diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartOverlayViewController.cxx index 42f42867a..e99266a00 100644 --- a/src/GuiQt/ChartOverlayViewController.cxx +++ b/src/GuiQt/ChartOverlayViewController.cxx @@ -562,11 +562,27 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) CaretMappableDataFile* selectedFile = NULL; //AString selectedMapUniqueID = ""; int32_t selectedMapIndex = -1; + bool enableMapSelectionControlsFlag = false; + if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(dataFiles, selectedFile, //selectedMapUniqueID, selectedMapIndex); + + const ChartTwoDataTypeEnum::Enum chartDataType = m_chartOverlay->getChartDataType(); + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + enableMapSelectionControlsFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + } std::vector displayNames; @@ -600,12 +616,14 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) int32_t numberOfMaps = 0; m_mapNameComboBox->blockSignals(true); m_mapNameComboBox->clear(); - if (selectedFile != NULL) { - numberOfMaps = selectedFile->getNumberOfMaps(); - for (int32_t i = 0; i < numberOfMaps; i++) { - m_mapNameComboBox->addItem(selectedFile->getMapName(i)); + if (enableMapSelectionControlsFlag) { + if (selectedFile != NULL) { + numberOfMaps = selectedFile->getNumberOfMaps(); + for (int32_t i = 0; i < numberOfMaps; i++) { + m_mapNameComboBox->addItem(selectedFile->getMapName(i)); + } + m_mapNameComboBox->setCurrentIndex(selectedMapIndex); } - m_mapNameComboBox->setCurrentIndex(selectedMapIndex); } m_mapNameComboBox->blockSignals(false); @@ -613,26 +631,36 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) * Load the map index spin box that ranges [1, N]. */ m_mapIndexSpinBox->blockSignals(true); - m_mapIndexSpinBox->setRange(1, numberOfMaps); - if (selectedFile != NULL) { - m_mapIndexSpinBox->setValue(selectedMapIndex + 1); + if (enableMapSelectionControlsFlag) { + m_mapIndexSpinBox->setRange(1, numberOfMaps); + if (selectedFile != NULL) { + m_mapIndexSpinBox->setValue(selectedMapIndex + 1); + } + } + else { + m_mapIndexSpinBox->setRange(0, 0); + m_mapIndexSpinBox->setValue(0); } m_mapIndexSpinBox->blockSignals(false); /* * Update enable check box */ - Qt::CheckState checkState = Qt::Unchecked; + Qt::CheckState enabledCheckState = Qt::Unchecked; + bool allMapsCheckedFlag = false; + MapYokingGroupEnum::Enum mapYoking = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; if (m_chartOverlay != NULL) { if (m_chartOverlay->isEnabled()) { - checkState = Qt::Checked; + enabledCheckState = Qt::Checked; } + allMapsCheckedFlag = m_chartOverlay->isAllMapsSelected(); + mapYoking = m_chartOverlay->getMapYokingGroup(); } - m_enabledCheckBox->setCheckState(checkState); + m_enabledCheckBox->setCheckState(enabledCheckState); - m_mapYokingGroupComboBox->setMapYokingGroup(m_chartOverlay->getMapYokingGroup()); + m_mapYokingGroupComboBox->setMapYokingGroup(mapYoking); - m_allMapsCheckBox->setChecked(m_chartOverlay->isAllMapsSelected()); + m_allMapsCheckBox->setChecked(allMapsCheckedFlag); m_colorBarAction->blockSignals(true); @@ -694,17 +722,23 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) /* * Make sure items are enabled at the appropriate time + * Note: First overlay is ALWAYS on enabled checkbox is not selectable by user */ - m_enabledCheckBox->setEnabled(haveFile); + m_enabledCheckBox->setEnabled(haveFile + && (m_chartOverlayIndex > 0)); + m_enabledCheckBox->setVisible(m_chartOverlayIndex > 0); m_settingsAction->setEnabled(true); m_colorBarAction->setEnabled(dataIsMappedWithPalette); m_constructionAction->setEnabled(true); m_historyAction->setEnabled(haveMultipleMaps); m_mapFileComboBox->setEnabled(haveFile); m_mapYokingGroupComboBox->getWidget()->setEnabled(haveYoking); - m_allMapsCheckBox->setEnabled(haveMultipleMaps); - m_mapIndexSpinBox->setEnabled(haveMultipleMaps); - m_mapNameComboBox->setEnabled(haveFile); + m_allMapsCheckBox->setEnabled(haveMultipleMaps + && enableMapSelectionControlsFlag); + m_mapIndexSpinBox->setEnabled(haveMultipleMaps + && enableMapSelectionControlsFlag); + m_mapNameComboBox->setEnabled(haveFile + && enableMapSelectionControlsFlag); } /** -- GitLab From 815df27fc49390c7d8204bc3b40f70a582a87a7d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 19 Jan 2017 16:25:50 -0600 Subject: [PATCH 185/755] Continuing new charting: Able to draw matrices with zooming and panning. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 589 +++++++++++++++++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 32 +- .../BrainOpenGLChartTwoDrawingInterface.h | 10 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 29 +- src/Brain/BrowserTabContent.cxx | 43 ++ src/Brain/BrowserTabContent.h | 3 + src/Common/DeveloperFlagsEnum.cxx | 8 +- src/Common/DeveloperFlagsEnum.h | 2 +- src/Files/ChartableMatrixSeriesInterface.h | 2 +- src/Files/CiftiScalarDataSeriesFile.cxx | 2 +- src/Files/CiftiScalarDataSeriesFile.h | 2 +- 11 files changed, 673 insertions(+), 49 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 07f432c3a..5c21dddcf 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -27,9 +27,26 @@ #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretAssert.h" +#include "CaretLogger.h" +#include "CaretPreferences.h" #include "ChartMatrixScaleModeEnum.h" #include "ChartOverlay.h" #include "ChartOverlaySet.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileMatrixChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "CiftiMappableConnectivityMatrixDataFile.h" +#include "CiftiParcelLabelFile.h" +#include "CiftiParcelScalarFile.h" +#include "CiftiScalarDataSeriesFile.h" +#include "ConnectivityDataLoaded.h" +#include "EventCaretMappableDataFileMapsViewedInOverlays.h" +#include "EventManager.h" + +#include "IdentificationWithColor.h" +#include "SessionManager.h" + using namespace caret; @@ -46,7 +63,7 @@ using namespace caret; BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline() : BrainOpenGLChartTwoDrawingInterface() { - + m_preferences = SessionManager::get()->getCaretPreferences(); } /** @@ -65,6 +82,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * The fixed pipeline OpenGL drawing. * @param textRenderer * Text rendering. + * @param translation + * The chart's translation. + * @param zooming + * The chart's zooming. * @param chartOverlaySet * Chart overlay set that is drawn. * @param selectionItemDataType @@ -78,6 +99,8 @@ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, + const float translation[3], + const float zooming, ChartOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], @@ -86,6 +109,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_brain = brain; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = textRenderer; + m_translation[0] = translation[0]; + m_translation[1] = translation[1]; + m_translation[2] = translation[2]; + m_zooming = zooming; m_chartOverlaySet = chartOverlaySet; m_selectionItemDataType = selectionItemDataType; m_viewport[0] = viewport[0]; @@ -169,9 +196,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() m_viewport[2], m_viewport[3]); - bool applyTransformationsFlag = false; - float panningXY[2] = { 0.0, 0.0 }; - float zooming = 1.0; + bool applyTransformationsFlag = true; +// float panningXY[2] = { 0.0, 0.0 }; +// float zooming = 1.0; float cellWidth = 1.0; float cellHeight = 1.0; @@ -258,8 +285,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() glLoadIdentity(); if (applyTransformationsFlag) { - glTranslatef(panningXY[0], - panningXY[1], + glTranslatef(m_translation[0], + m_translation[1], 0.0); const float chartWidth = cellWidth * numberOfCols; @@ -269,36 +296,518 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() glTranslatef(halfWidth, halfHeight, 0.0); - glScalef(zooming, - zooming, + glScalef(m_zooming, + m_zooming, 1.0); glTranslatef(-halfWidth, -halfHeight, 0.0); } + /* + * For testing + */ + glColor3f(1.0, 0.0, 0.0); + glBegin(GL_LINES); + glVertex2f(xMin, yMin); + glVertex2f(xMax, yMax); + glEnd(); + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - const ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); - if (chartOverlay->isEnabled()) { - const ChartTwoCompoundDataType cdt = chartOverlay->getChartTwoCompoundDataType(); - CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); - const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); - const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); - if ((numberOfRows > 0) - && (numberOfCols > 0)) { - /* - * Auto scale 'fills' the matrix region - * and updates the width and height in the - * matrix properties for use in manual mode. - * There is NO zooming or panning for Auto scale. - */ - cellWidth = graphicsWidth / numberOfCols; - cellHeight = graphicsHeight / numberOfRows; + ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + if ( ! chartOverlay->isEnabled()) { + continue; + } + + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = 1; + chartOverlay->getSelectionData(mapFile, + mapIndex); + if (mapFile == NULL) { + continue; + } + + const ChartableTwoFileMatrixChart* matrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); + int32_t overlayRows = 0; + int32_t overlayColumns = 0; + matrixChart->getMatrixDimensions(overlayRows, + overlayColumns); + + /* + * All matrices must have same rows/columns + */ + if ((overlayRows == numberOfRows) + && (overlayColumns == numberOfCols)) { + drawMatrixChartGrid(matrixChart, + ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL, + //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL, + //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL, + //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL, + cellWidth, + cellHeight, + m_zooming); + } + } +} + +/** + * Get highlighting of rows or columns for a matrix. + * + * @param matrixChart + * Matrix chart that is drawn. + * @param rowIndicesOut + * Output with row indices for highlighting. + * @param columnIndicesOut + * Output with column indices for highlighting. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, + std::set& rowIndicesOut, + std::set& columnIndicesOut) const +{ + const CiftiMappableDataFile* ciftiMapFile = matrixChart->getCiftiMappableDataFile(); + const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); + if (connMapFile != NULL) { + const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); + if (connDataLoaded != NULL) { + int64_t loadedRowIndex = -1; + int64_t loadedColumnIndex = -1; + connDataLoaded->getRowColumnLoading(loadedRowIndex, + loadedColumnIndex); + if (loadedRowIndex >= 0) { + rowIndicesOut.insert(loadedRowIndex); + } + else if (loadedColumnIndex >= 0) { + columnIndicesOut.insert(loadedColumnIndex); } } } + + const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); + if (parcelScalarFile != NULL) { + EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); + EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); + } + + const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); + if (parcelLabelFile != NULL) { + EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); + EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); + } + + const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); + if (scalarDataSeriesFile != NULL) { + const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(m_tabIndex); + if (scalarDataSeriesMapIndex >= 0) { + rowIndicesOut.insert(scalarDataSeriesMapIndex); + } + } } +/* + * Draw a matrix chart. + * + * @param matrixChart + * Matrix chart that is drawn. + * @param chartViewingType + * Type of chart viewing. + * @param cellWidth + * Width of cell. + * @param cellHeight + * Height of cell. + * @param zooming + * Current zooming. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartGrid(const ChartableTwoFileMatrixChart* matrixChart, + const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, + const float cellWidth, + const float cellHeight, + const float zooming) +{ + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + std::vector matrixRGBA; + if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, + numberOfColumns, + matrixRGBA)) { + CaretLogWarning("Matrix RGBA invalid"); + return; + } + + CaretAssertToDoWarning(); // need to set these + bool displayGridLinesFlag = true; + bool highlightSelectedRowColumnFlag = true; + + + std::set selectedColumnIndices; + std::set selectedRowIndices; + getMatrixHighlighting(matrixChart, + selectedRowIndices, + selectedColumnIndices); + + uint8_t highlightRGBByte[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); + const float highlightRGB[3] = { + highlightRGBByte[0] / 255.0, + highlightRGBByte[1] / 255.0, + highlightRGBByte[2] / 255.0 + }; + + int32_t rgbaOffset = 0; + std::vector quadVerticesXYZ; + quadVerticesXYZ.reserve(numberOfRows * numberOfColumns * 3); + std::vector quadVerticesFloatRGBA; + quadVerticesFloatRGBA.reserve(numberOfRows * numberOfColumns * 4); + std::vector quadVerticesByteRGBA; + quadVerticesByteRGBA.reserve(numberOfRows * numberOfColumns * 4); + + float cellY = (numberOfRows - 1) * cellHeight; + for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { + float cellX = 0; + for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { + CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); + const float* rgba = &matrixRGBA[rgbaOffset]; + rgbaOffset += 4; + + bool drawCellFlag = true; + if (chartViewingType != ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL) { + if (numberOfRows == numberOfColumns) { + drawCellFlag = false; + switch (chartViewingType) { + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < columnIndex) { + drawCellFlag = true; + } + break; + } + } + else { + drawCellFlag = true; + switch (chartViewingType) { + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + break; + case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + break; + } + } + } + + if (drawCellFlag) { + uint8_t idRGBA[4]; + if (m_identificationModeFlag) { + addToChartMatrixIdentification(rowIndex, + columnIndex, + idRGBA); + } + + if (m_identificationModeFlag) { + quadVerticesByteRGBA.push_back(idRGBA[0]); + quadVerticesByteRGBA.push_back(idRGBA[1]); + quadVerticesByteRGBA.push_back(idRGBA[2]); + quadVerticesByteRGBA.push_back(idRGBA[3]); + } + else { + quadVerticesFloatRGBA.push_back(rgba[0]); + quadVerticesFloatRGBA.push_back(rgba[1]); + quadVerticesFloatRGBA.push_back(rgba[2]); + quadVerticesFloatRGBA.push_back(rgba[3]); + } + quadVerticesXYZ.push_back(cellX); + quadVerticesXYZ.push_back(cellY); + quadVerticesXYZ.push_back(0.0); + + if (m_identificationModeFlag) { + quadVerticesByteRGBA.push_back(idRGBA[0]); + quadVerticesByteRGBA.push_back(idRGBA[1]); + quadVerticesByteRGBA.push_back(idRGBA[2]); + quadVerticesByteRGBA.push_back(idRGBA[3]); + } + else { + quadVerticesFloatRGBA.push_back(rgba[0]); + quadVerticesFloatRGBA.push_back(rgba[1]); + quadVerticesFloatRGBA.push_back(rgba[2]); + quadVerticesFloatRGBA.push_back(rgba[3]); + } + quadVerticesXYZ.push_back(cellX + cellWidth); + quadVerticesXYZ.push_back(cellY); + quadVerticesXYZ.push_back(0.0); + + if (m_identificationModeFlag) { + quadVerticesByteRGBA.push_back(idRGBA[0]); + quadVerticesByteRGBA.push_back(idRGBA[1]); + quadVerticesByteRGBA.push_back(idRGBA[2]); + quadVerticesByteRGBA.push_back(idRGBA[3]); + } + else { + quadVerticesFloatRGBA.push_back(rgba[0]); + quadVerticesFloatRGBA.push_back(rgba[1]); + quadVerticesFloatRGBA.push_back(rgba[2]); + quadVerticesFloatRGBA.push_back(rgba[3]); + } + quadVerticesXYZ.push_back(cellX + cellWidth); + quadVerticesXYZ.push_back(cellY + cellHeight); + quadVerticesXYZ.push_back(0.0); + + if (m_identificationModeFlag) { + quadVerticesByteRGBA.push_back(idRGBA[0]); + quadVerticesByteRGBA.push_back(idRGBA[1]); + quadVerticesByteRGBA.push_back(idRGBA[2]); + quadVerticesByteRGBA.push_back(idRGBA[3]); + } + else { + quadVerticesFloatRGBA.push_back(rgba[0]); + quadVerticesFloatRGBA.push_back(rgba[1]); + quadVerticesFloatRGBA.push_back(rgba[2]); + quadVerticesFloatRGBA.push_back(rgba[3]); + } + quadVerticesXYZ.push_back(cellX); + quadVerticesXYZ.push_back(cellY + cellHeight); + quadVerticesXYZ.push_back(0.0); + } + + cellX += cellWidth; + } + + cellY -= cellHeight; + } + + /* + * Draw the matrix elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); + glColor4ubv(&quadVerticesByteRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + else { + /* + * Enable alpha blending so voxels that are not drawn from higher layers + * allow voxels from lower layers to be seen. + */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); + glColor4fv(&quadVerticesFloatRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + + glDisable(GL_BLEND); + + + /* + * Drawn an outline around the matrix elements. + */ + if (displayGridLinesFlag) { + uint8_t gridLineColorBytes[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); + float gridLineColorFloats[4]; + CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, + gridLineColorFloats); + gridLineColorFloats[3] = 1.0; + std::vector outlineRGBA; + outlineRGBA.reserve(numberQuadVertices * 4); + for (int32_t i = 0; i < numberQuadVertices; i++) { + outlineRGBA.push_back(gridLineColorFloats[0]); + outlineRGBA.push_back(gridLineColorFloats[1]); + outlineRGBA.push_back(gridLineColorFloats[2]); + outlineRGBA.push_back(gridLineColorFloats[3]); + } + + glPolygonMode(GL_FRONT, GL_LINE); + glLineWidth(1.0); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(outlineRGBA, i*4 + 3); + glColor4fv(&outlineRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + + if ( (! selectedRowIndices.empty()) + && highlightSelectedRowColumnFlag) { + std::vector rowXYZ; + std::vector rowRGBA; + + for (std::set::iterator rowIter = selectedRowIndices.begin(); + rowIter != selectedRowIndices.end(); + rowIter ++) { + const float rowIndex = * rowIter; + const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; + + + rowXYZ.push_back(0.0); + rowXYZ.push_back(rowY); + rowXYZ.push_back(0.0); + rowRGBA.push_back(highlightRGB[0]); + rowRGBA.push_back(highlightRGB[1]); + rowRGBA.push_back(highlightRGB[2]); + rowRGBA.push_back(1.0); + + rowXYZ.push_back(0.0); + rowXYZ.push_back(rowY + cellHeight); + rowXYZ.push_back(0.0); + rowRGBA.push_back(highlightRGB[0]); + rowRGBA.push_back(highlightRGB[1]); + rowRGBA.push_back(highlightRGB[2]); + rowRGBA.push_back(1.0); + + rowXYZ.push_back(numberOfColumns * cellWidth); + rowXYZ.push_back(rowY + cellHeight); + rowXYZ.push_back(0.0); + rowRGBA.push_back(highlightRGB[0]); + rowRGBA.push_back(highlightRGB[1]); + rowRGBA.push_back(highlightRGB[2]); + rowRGBA.push_back(1.0); + + + rowXYZ.push_back(numberOfColumns * cellWidth); + rowXYZ.push_back(rowY); + rowXYZ.push_back(0.0); + rowRGBA.push_back(highlightRGB[0]); + rowRGBA.push_back(highlightRGB[1]); + rowRGBA.push_back(highlightRGB[2]); + rowRGBA.push_back(1.0); + } + + CaretAssert((rowXYZ.size() / 3) == (rowRGBA.size() / 4)); + + const int32_t numberOfVertices = static_cast(rowXYZ.size() / 3); + const int32_t numberOfQuads = numberOfVertices / 4; + CaretAssert((numberOfQuads * 4) == numberOfVertices); + + /* + * As cells get larger, increase linewidth for selected row + */ + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + + for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { + glBegin(GL_LINE_LOOP); + for (int32_t iVert = 0; iVert < 4; iVert++) { + const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); + CaretAssertVectorIndex(rowRGBA, rgbaOffset + 3); + glColor4fv(&rowRGBA[rgbaOffset]); + + const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); + CaretAssertVectorIndex(rowXYZ, xyzOffset + 2); + glVertex3fv(&rowXYZ[xyzOffset]); + } + glEnd(); + } + glLineWidth(1.0); + } + + if ( (! selectedColumnIndices.empty()) + && highlightSelectedRowColumnFlag) { + std::vector columnXYZ; + std::vector columnRGBA; + + for (std::set::iterator colIter = selectedColumnIndices.begin(); + colIter != selectedColumnIndices.end(); + colIter++) { + const float columnIndex = *colIter; + const float colX = columnIndex * cellWidth; + + columnXYZ.push_back(colX); + columnXYZ.push_back(0.0); + columnXYZ.push_back(0.0); + columnRGBA.push_back(highlightRGB[0]); + columnRGBA.push_back(highlightRGB[1]); + columnRGBA.push_back(highlightRGB[2]); + columnRGBA.push_back(1.0); + + columnXYZ.push_back(colX + cellWidth); + columnXYZ.push_back(0.0); + columnXYZ.push_back(0.0); + columnRGBA.push_back(highlightRGB[0]); + columnRGBA.push_back(highlightRGB[1]); + columnRGBA.push_back(highlightRGB[2]); + columnRGBA.push_back(1.0); + + columnXYZ.push_back(colX + cellWidth); + columnXYZ.push_back(numberOfRows * cellHeight); + columnXYZ.push_back(0.0); + columnRGBA.push_back(highlightRGB[0]); + columnRGBA.push_back(highlightRGB[1]); + columnRGBA.push_back(highlightRGB[2]); + columnRGBA.push_back(1.0); + + + columnXYZ.push_back(colX); + columnXYZ.push_back(numberOfRows * cellHeight); + columnXYZ.push_back(0.0); + columnRGBA.push_back(highlightRGB[0]); + columnRGBA.push_back(highlightRGB[1]); + columnRGBA.push_back(highlightRGB[2]); + columnRGBA.push_back(1.0); + } + + CaretAssert((columnXYZ.size() / 3) == (columnRGBA.size() / 4)); + + const int32_t numberOfVertices = static_cast(columnXYZ.size() / 3); + const int32_t numberOfQuads = numberOfVertices / 4; + CaretAssert((numberOfQuads * 4) == numberOfVertices); + + /* + * As cells get larger, increase linewidth for selected row + */ + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + + for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { + glBegin(GL_LINE_LOOP); + for (int32_t iVert = 0; iVert < 4; iVert++) { + const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); + CaretAssertVectorIndex(columnRGBA, rgbaOffset + 3); + glColor4fv(&columnRGBA[rgbaOffset]); + + const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); + CaretAssertVectorIndex(columnXYZ, xyzOffset + 2); + glVertex3fv(&columnXYZ[xyzOffset]); + } + glEnd(); + } + glLineWidth(1.0); + } + + glPolygonMode(GL_FRONT, GL_FILL); + } +} /** * Save the state of OpenGL. @@ -324,6 +833,36 @@ BrainOpenGLChartTwoDrawingFixedPipeline::saveStateOfOpenGL() glDisable(GL_BLEND); } +/** + * Add an item for matrix identification. + * + * @param matrixRowIndex + * Index of the row + * @param matrixColumnIndex + * Index of the column + * @param rgbaForColorIdentificationOut + * Encoded identification in RGBA color OUTPUT + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::addToChartMatrixIdentification(const int32_t matrixRowIndex, + const int32_t matrixColumnIndex, + uint8_t rgbaForColorIdentificationOut[4]) +{ + const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; + + m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, + m_selectionItemDataType, + idIndex); + rgbaForColorIdentificationOut[3] = 255; + + /* + * If these items change, need to update reset and + * processing of identification. + */ + m_identificationIndices.push_back(matrixRowIndex); + m_identificationIndices.push_back(matrixColumnIndex); +} + /** * Restore the state of OpenGL. * Copied from Qt's qgl.cpp, qt_restore_gl_state(). @@ -464,7 +1003,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processIdentification() // } // } // else if (m_chartableMatrixInterfaceBeingDrawnForIdentification != NULL) { -// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartableMatrixSelectionTypeForIdentification, +// m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, // m_fixedPipelineDrawing->mouseX, // m_fixedPipelineDrawing->mouseY, // identifiedItemIndex, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 0e039d7e0..a232ea39a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -21,13 +21,15 @@ */ /*LICENSE_END*/ - +#include #include "BrainOpenGLChartTwoDrawingInterface.h" - - +#include "ChartTwoMatrixViewingTypeEnum.h" namespace caret { + class CaretPreferences; + class ChartableTwoFileMatrixChart; + class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { public: @@ -38,6 +40,8 @@ namespace caret { virtual void drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, + const float translation[3], + const float zooming, ChartOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], @@ -73,8 +77,21 @@ namespace caret { void processIdentification(); + void addToChartMatrixIdentification(const int32_t matrixRowIndex, + const int32_t matrixColumnIndex, + uint8_t rgbaForColorIdentification[4]); void drawMatrixChart(); + void drawMatrixChartGrid(const ChartableTwoFileMatrixChart* matrixChart, + const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, + const float cellWidth, + const float cellHeight, + const float zooming); + + void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, + std::set& rowIndicesOut, + std::set& columnIndicesOut) const; + Brain* m_brain; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; @@ -89,10 +106,19 @@ namespace caret { int32_t m_tabIndex; + float m_translation[3]; + + float m_zooming; + std::vector m_identificationIndices; + CaretPreferences* m_preferences; + bool m_identificationModeFlag; + static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; + static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 2736481a0..5df3b1fd2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -47,20 +47,26 @@ namespace caret { * Brain. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. - * @param viewport - * Viewport for the chart. * @param textRenderer * Text rendering. + * @param translation + * The chart's translation. + * @param zooming + * The chart's zooming. * @param chartOverlaySet * Chart overlay set that is drawn. * @param selectionItemDataType * Selected data type. + * @param viewport + * Viewport for the chart. * @param tabIndex * Index of the tab. */ virtual void drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, + const float translation[3], + const float zooming, ChartOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 5256e476d..5addb65bb 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5285,17 +5285,24 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const int32_t tabIndex = browserTabContent->getTabNumber(); - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING)) { - BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; - - chartDrawing.drawChartOverlaySet(m_brain, - this, - getTextRenderer(), - chartModel->getChartOverlaySet(tabIndex), - SelectionItemDataTypeEnum::CHART_DATA_SERIES, - viewport, - tabIndex); - return; + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { + if (m_windowIndex == 0) { + float translation[3]; + browserTabContent->getTranslation(translation); + BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; + const float zooming = browserTabContent->getScaling(); + + chartDrawing.drawChartOverlaySet(m_brain, + this, + getTextRenderer(), + translation, + zooming, + chartModel->getChartOverlaySet(tabIndex), + SelectionItemDataTypeEnum::CHART_DATA_SERIES, + viewport, + tabIndex); + return; + } } ChartModelCartesian* cartesianChart = NULL; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index e611016a8..5fd54ba5d 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -125,6 +125,7 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_flatSurfaceViewingTransformation = new ViewingTransformations(); m_viewingTransformation = new ViewingTransformations(); m_volumeSliceViewingTransformation = new ViewingTransformationsVolume(); + m_chartMatrixViewingTranformation = new ViewingTransformations(); m_wholeBrainSurfaceSettings = new WholeBrainSurfaceSettings(); @@ -169,6 +170,10 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) "ViewingTransformations", m_volumeSliceViewingTransformation); + m_sceneClassAssistant->add("m_chartMatrixViewingTranformation", + "ViewingTransformations", + m_chartMatrixViewingTranformation); + m_sceneClassAssistant->add("m_volumeSliceSettings", "VolumeSliceSettings", m_volumeSliceSettings); @@ -219,6 +224,7 @@ BrowserTabContent::~BrowserTabContent() delete m_cerebellumViewingTransformation; delete m_viewingTransformation; delete m_volumeSliceViewingTransformation; + delete m_chartMatrixViewingTranformation; delete m_obliqueVolumeRotationMatrix; delete m_surfaceModelSelector; @@ -273,6 +279,7 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) *m_flatSurfaceViewingTransformation = *tabToClone->m_flatSurfaceViewingTransformation; *m_viewingTransformation = *tabToClone->m_viewingTransformation; *m_volumeSliceViewingTransformation = *tabToClone->m_volumeSliceViewingTransformation; + *m_chartMatrixViewingTranformation = *tabToClone->m_chartMatrixViewingTranformation; *m_volumeSliceSettings = *tabToClone->m_volumeSliceSettings; *m_wholeBrainSurfaceSettings = *tabToClone->m_wholeBrainSurfaceSettings; @@ -1744,6 +1751,9 @@ BrowserTabContent::getViewingTransformation() else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } + else if (isChartDisplayed()) { + return m_chartMatrixViewingTranformation; + } return m_viewingTransformation; } @@ -1759,6 +1769,9 @@ BrowserTabContent::getViewingTransformation() const else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } + else if (isChartDisplayed()) { + return m_chartMatrixViewingTranformation; + } return m_viewingTransformation; } @@ -2412,6 +2425,15 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, matrixProperties->setViewZooming(scaling); } } + + float scaling = getViewingTransformation()->getScaling(); + if (mouseDY != 0.0) { + scaling *= (1.0f + (mouseDY * 0.01)); + } + if (scaling < 0.01) { + scaling = 0.01; + } + getViewingTransformation()->setScaling(scaling); } else { float scaling = getViewingTransformation()->getScaling(); @@ -2525,6 +2547,16 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon matrixProperties->setViewPanning(translation); } } + + /** Charting "two" */ + { + float translation[3]; + m_chartMatrixViewingTranformation->getTranslation(translation); + translation[0] += mouseDX; + translation[1] += mouseDY; + translation[2] = 0; // NO Z-translation + m_chartMatrixViewingTranformation->setTranslation(translation); + } } else if (isCerebellumDisplayed()) { const float screenDX = mouseDX; @@ -2733,6 +2765,15 @@ BrowserTabContent::getTransformationsForOpenGLDrawing(const ProjectionViewTypeEn return; } + if (isChartDisplayed()) { + m_chartMatrixViewingTranformation->getTranslation(translationOut); + Matrix4x4 matrix; + matrix.identity(); + matrix.getMatrixForOpenGL(rotationMatrixOut); + scalingOut = m_chartMatrixViewingTranformation->getScaling(); + return; + } + /* * Surfaces may need a modification to the rotation matrix * dependent upon the projection view type. @@ -3957,6 +3998,7 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; + *m_chartMatrixViewingTranformation = *btc->m_chartMatrixViewingTranformation; *m_volumeSliceSettings = *btc->m_volumeSliceSettings; *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; @@ -4007,6 +4049,7 @@ BrowserTabContent::updateYokedBrowserTabs() *btc->m_flatSurfaceViewingTransformation = *m_flatSurfaceViewingTransformation; *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; + *btc->m_chartMatrixViewingTranformation = *m_chartMatrixViewingTranformation; *btc->m_volumeSliceSettings = *m_volumeSliceSettings; *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index c8e9d28f8..6580d4392 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -488,6 +488,9 @@ namespace caret { /** Transformation for volume slices viewing */ ViewingTransformationsVolume* m_volumeSliceViewingTransformation; + /** Transformation for matrix chart viewing */ + ViewingTransformations* m_chartMatrixViewingTranformation; + /** Volume slice settings for volume slices */ VolumeSliceSettings* m_volumeSliceSettings; diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 6e3f17024..061c814e7 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -95,7 +95,7 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, case DEVELOPER_FLAG_UNUSED: this->flagStatus = false; break; - case DEVELOPER_FLAG_NEW_CHARTING: + case DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1: this->flagStatus = false; break; } @@ -124,9 +124,9 @@ DeveloperFlagsEnum::initialize() "Developer flag unused")); - enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_CHARTING, - "DEVELOPER_FLAG_NEW_CHARTING", - "Developer flag New Charting")); + enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1, + "DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1", + "Draw with New Charting in Window 1")); } /** diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index 3a56879cf..abcff15da 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -36,7 +36,7 @@ public: */ enum Enum { DEVELOPER_FLAG_UNUSED, - DEVELOPER_FLAG_NEW_CHARTING + DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1 }; ~DeveloperFlagsEnum(); diff --git a/src/Files/ChartableMatrixSeriesInterface.h b/src/Files/ChartableMatrixSeriesInterface.h index 1a8fe334c..7e11a5596 100644 --- a/src/Files/ChartableMatrixSeriesInterface.h +++ b/src/Files/ChartableMatrixSeriesInterface.h @@ -40,7 +40,7 @@ namespace caret { virtual void setMatrixRowColumnMapYokingGroup(const int32_t tabIndex, const MapYokingGroupEnum::Enum yokingType) = 0; - virtual int32_t getSelectedMapIndex(const int32_t tabIndex) = 0; + virtual int32_t getSelectedMapIndex(const int32_t tabIndex) const = 0; virtual void setSelectedMapIndex(const int32_t tabIndex, const int32_t mapIndex) = 0; diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index bd6b078c3..26564b1b2 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -183,7 +183,7 @@ CiftiScalarDataSeriesFile::setMatrixRowColumnMapYokingGroup(const int32_t tabInd * Selected map index in the given tab. */ int32_t -CiftiScalarDataSeriesFile::getSelectedMapIndex(const int32_t tabIndex) +CiftiScalarDataSeriesFile::getSelectedMapIndex(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedMapIndices, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_selectedMapIndices[tabIndex]; diff --git a/src/Files/CiftiScalarDataSeriesFile.h b/src/Files/CiftiScalarDataSeriesFile.h index a704da071..3e28c69fa 100644 --- a/src/Files/CiftiScalarDataSeriesFile.h +++ b/src/Files/CiftiScalarDataSeriesFile.h @@ -48,7 +48,7 @@ namespace caret { virtual void setMatrixRowColumnMapYokingGroup(const int32_t tabIndex, const MapYokingGroupEnum::Enum yokingType); - virtual int32_t getSelectedMapIndex(const int32_t tabIndex); + virtual int32_t getSelectedMapIndex(const int32_t tabIndex) const override; virtual void setSelectedMapIndex(const int32_t tabIndex, const int32_t mapIndex); -- GitLab From 0cf4db8d095385310e90d0d2d38c23cbd6d9f232 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 20 Jan 2017 16:35:25 -0600 Subject: [PATCH 186/755] Added a "Chart Orientation" group to the toolbar. It allows one to reset the view of a chart or use a custom view with a chart. --- src/Common/DeveloperFlagsEnum.cxx | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 94 +++++++++- src/GuiQt/BrainBrowserWindowToolBar.h | 9 +- ...inBrowserWindowToolBarChartOrientation.cxx | 165 ++++++++++++++++++ ...rainBrowserWindowToolBarChartOrientation.h | 68 ++++++++ .../BrainBrowserWindowToolBarComponent.h | 1 + src/GuiQt/CMakeLists.txt | 3 + 7 files changed, 333 insertions(+), 9 deletions(-) create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 061c814e7..1acb5d130 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -96,7 +96,7 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, this->flagStatus = false; break; case DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1: - this->flagStatus = false; + this->flagStatus = true; break; } } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index e1bdc1870..cea456122 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -55,6 +55,7 @@ #include "BrainBrowserWindowToolBar.h" #include "BrainBrowserWindowToolBarChartAttributes.h" #include "BrainBrowserWindowToolBarChartAxes.h" +#include "BrainBrowserWindowToolBarChartOrientation.h" #include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" #include "BrainBrowserWindowToolBarClipping.h" @@ -70,6 +71,7 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "CursorDisplayScoped.h" +#include "DeveloperFlagsEnum.h" #include "DisplayPropertiesBorders.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabGet.h" @@ -330,8 +332,9 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->orientationWidget = this->createOrientationWidget(); this->chartAxesWidget = createChartAxesWidget(); this->chartAttributesWidget = createChartAttributesWidget(); + this->chartOrientationWidget = createChartOrientationWidget(); this->chartTypeWidget = createChartTypeWidget(); - this->chartTwoTypeWidget = createChartTypeTwoWidget(); + this->chartTypeTwoWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); this->volumeIndicesWidget = this->createVolumeIndicesWidget(); this->modeWidget = this->createModeWidget(); @@ -368,10 +371,12 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolbarWidgetLayout->addWidget(this->chartTypeWidget, 0, Qt::AlignLeft); - this->toolbarWidgetLayout->addWidget(this->chartTwoTypeWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartTypeTwoWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartAxesWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartOrientationWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->modeWidget, 0, Qt::AlignLeft); @@ -1376,6 +1381,7 @@ BrainBrowserWindowToolBar::updateToolBar() bool showChartAxesWidget = false; bool showChartTypeWidget = false; bool showChartAttributesWidget = false; + bool showChartOrientationWidget = false; bool showModeWidget = true; bool showWindowWidget = true; @@ -1408,6 +1414,7 @@ BrainBrowserWindowToolBar::updateToolBar() ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); if (modelChart != NULL) { + showChartOrientationWidget = true; switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -1446,9 +1453,10 @@ BrainBrowserWindowToolBar::updateToolBar() this->singleSurfaceSelectionWidget->setVisible(false); this->surfaceMontageSelectionWidget->setVisible(false); this->chartTypeWidget->setVisible(false); - this->chartTwoTypeWidget->setVisible(false); + this->chartTypeTwoWidget->setVisible(false); this->chartAxesWidget->setVisible(false); this->chartAttributesWidget->setVisible(false); + this->chartOrientationWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); this->volumePlaneWidget->setVisible(false); this->volumeMontageWidget->setVisible(false); @@ -1461,9 +1469,10 @@ BrainBrowserWindowToolBar::updateToolBar() this->singleSurfaceSelectionWidget->setVisible(showSingleSurfaceOptionsWidget); this->surfaceMontageSelectionWidget->setVisible(showSurfaceMontageOptionsWidget); this->chartTypeWidget->setVisible(showChartTypeWidget); - this->chartTwoTypeWidget->setVisible(showChartTypeWidget); + this->chartTypeTwoWidget->setVisible(showChartTypeWidget); this->chartAxesWidget->setVisible(showChartAxesWidget); this->chartAttributesWidget->setVisible(showChartAttributesWidget); + this->chartOrientationWidget->setVisible(showChartOrientationWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); @@ -1522,8 +1531,10 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab this->updateSingleSurfaceOptionsWidget(browserTabContent); this->updateSurfaceMontageOptionsWidget(browserTabContent); this->updateChartTypeWidget(browserTabContent); + this->updateChartTypeTwoWidget(browserTabContent); this->updateChartAxesWidget(browserTabContent); this->updateChartAttributesWidget(browserTabContent); + this->updateChartOrientationWidget(browserTabContent); this->updateVolumeMontageWidget(browserTabContent); this->updateVolumePlaneWidget(browserTabContent); this->updateModeWidget(browserTabContent); @@ -2643,6 +2654,32 @@ BrainBrowserWindowToolBar::createChartTypeWidget() return w; } +/** + * Update the chart type widget. + * + * @param browserTabContent + * The active model display (may be NULL). + */ +void +BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabContent) +{ + if (this->chartTypeWidget->isHidden()) { + return; + } + + m_chartTypeToolBarComponent->updateContent(browserTabContent); + + if (this->browserWindowIndex == 0) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { + this->chartTypeWidget->setEnabled(false); + } + else { + this->chartTypeWidget->setEnabled(true); + } + } +} + + /** * Create the chart type two widget. * @@ -2669,14 +2706,22 @@ BrainBrowserWindowToolBar::createChartTypeTwoWidget() * The active model display (may be NULL). */ void -BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabContent) +BrainBrowserWindowToolBar::updateChartTypeTwoWidget(BrowserTabContent* browserTabContent) { - if (this->chartTypeWidget->isHidden()) { + if (this->chartTypeTwoWidget->isHidden()) { return; } - m_chartTypeToolBarComponent->updateContent(browserTabContent); m_chartTwoTypeToolBarComponent->updateContent(browserTabContent); + + if (this->browserWindowIndex == 0) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { + this->chartTypeTwoWidget->setEnabled(true); + } + else { + this->chartTypeTwoWidget->setEnabled(false); + } + } } /** @@ -2748,6 +2793,41 @@ BrainBrowserWindowToolBar::updateChartAttributesWidget(BrowserTabContent* browse m_chartAttributesToolBarComponent->updateContent(browserTabContent); } +/** + * Create the chart orientation widget. + * + * @return + * Widget containing the chart orientation. + */ +QWidget* +BrainBrowserWindowToolBar::createChartOrientationWidget() +{ + m_chartOrientationToolBarComponent = new BrainBrowserWindowToolBarChartOrientation(this); + QWidget* w = this->createToolWidget("Orientation", + m_chartOrientationToolBarComponent, + WIDGET_PLACEMENT_LEFT, + WIDGET_PLACEMENT_TOP, + 100); + w->setVisible(false); + return w; +} + +/** + * Update the chart orientation widget. + * + * @param browserTabContent + * The active model display (may be NULL). + */ +void +BrainBrowserWindowToolBar::updateChartOrientationWidget(BrowserTabContent* browserTabContent) +{ + if (this->chartOrientationWidget->isHidden()) { + return; + } + m_chartOrientationToolBarComponent->updateContent(browserTabContent); +} + + /** * Create the single surface options widget. * diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index a95174f40..1036906a8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -52,6 +52,7 @@ namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; + class BrainBrowserWindowToolBarChartOrientation; class BrainBrowserWindowToolBarChartTwoType; class BrainBrowserWindowToolBarChartType; class BrainBrowserWindowToolBarClipping; @@ -142,6 +143,7 @@ namespace caret { QAction* tabAspectRatioLockedAction); QWidget* createChartAxesWidget(); QWidget* createChartAttributesWidget(); + QWidget* createChartOrientationWidget(); QWidget* createChartTypeWidget(); QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); @@ -160,7 +162,9 @@ namespace caret { void updateSurfaceMontageOptionsWidget(BrowserTabContent* browserTabContent); void updateChartAxesWidget(BrowserTabContent* browserTabContent); void updateChartAttributesWidget(BrowserTabContent* browserTabContent); + void updateChartOrientationWidget(BrowserTabContent* browserTabContent); void updateChartTypeWidget(BrowserTabContent* browserTabContent); + void updateChartTypeTwoWidget(BrowserTabContent* browserTabContent); void updateVolumeMontageWidget(BrowserTabContent* browserTabContent); void updateVolumePlaneWidget(BrowserTabContent* browserTabContent); void updateClippingOptionsWidget(BrowserTabContent* browserTabContent); @@ -183,9 +187,10 @@ namespace caret { QWidget* volumeMontageWidget; QWidget* volumePlaneWidget; QWidget* chartTypeWidget; - QWidget* chartTwoTypeWidget; + QWidget* chartTypeTwoWidget; QWidget* chartAxesWidget; QWidget* chartAttributesWidget; + QWidget* chartOrientationWidget; WuQWidgetObjectGroup* viewWidgetGroup; WuQWidgetObjectGroup* orientationWidgetGroup; @@ -356,6 +361,7 @@ namespace caret { BrainBrowserWindowToolBarChartTwoType* m_chartTwoTypeToolBarComponent; BrainBrowserWindowToolBarChartType* m_chartTypeToolBarComponent; BrainBrowserWindowToolBarChartAttributes* m_chartAttributesToolBarComponent; + BrainBrowserWindowToolBarChartOrientation* m_chartOrientationToolBarComponent; BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; BrainBrowserWindowToolBarClipping* m_clippingToolBarComponent; @@ -389,6 +395,7 @@ namespace caret { private: friend class BrainBrowserWindow; friend class BrainBrowserWindowToolBarChartAxes; + friend class BrainBrowserWindowToolBarChartOrientation; friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; friend class BrainBrowserWindowToolBarClipping; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx new file mode 100644 index 000000000..0d29d9fe7 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx @@ -0,0 +1,165 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ +#include "BrainBrowserWindowToolBarChartOrientation.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ + +#include +#include + +#include "BrainBrowserWindowToolBar.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretPreferences.h" +#include "EventManager.h" +#include "ModelChart.h" +#include "SessionManager.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarChartOrientation + * \brief Toolbar component for chart orientation. + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +BrainBrowserWindowToolBarChartOrientation::BrainBrowserWindowToolBarChartOrientation(BrainBrowserWindowToolBar* parentToolBar) +: BrainBrowserWindowToolBarComponent(parentToolBar) +{ + m_orientationResetToolButtonAction = WuQtUtilities::createAction("Reset", + "Reset the view to remove any panning or zooming", + this, + this, + SLOT(orientationResetToolButtonTriggered(bool))); + + const QString customToolTip = ("Pressing the \"Custom\" button displays a dialog for creating and editing orientations.\n" + "Note that custom orientations are stored in your Workbench's preferences and thus\n" + "will be availble in any concurrent or future instances of Workbench."); + m_customViewAction = WuQtUtilities::createAction("Custom", + customToolTip, + this, + this, + SLOT(customViewActionTriggered())); + + + QToolButton* orientationResetToolButton = new QToolButton(); + orientationResetToolButton->setDefaultAction(m_orientationResetToolButtonAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(orientationResetToolButton); + + m_orientationCustomViewSelectToolButton = new QToolButton(); + m_orientationCustomViewSelectToolButton->setDefaultAction(m_customViewAction); + m_orientationCustomViewSelectToolButton->setSizePolicy(QSizePolicy::Minimum, + QSizePolicy::Fixed); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_orientationCustomViewSelectToolButton); + + QVBoxLayout* layout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); + layout->addWidget(orientationResetToolButton, 0, Qt::AlignHCenter); + layout->addWidget(m_orientationCustomViewSelectToolButton, 0, Qt::AlignHCenter); + + setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarChartOrientation::~BrainBrowserWindowToolBarChartOrientation() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Update content of this tool bar component. + * + * @param browserTabContent + * Content of the browser tab. + */ +void +BrainBrowserWindowToolBarChartOrientation::updateContent(BrowserTabContent* /*browserTabContent*/) +{ +} + +/** + * Called when orientation reset button is pressed. + */ +void +BrainBrowserWindowToolBarChartOrientation::orientationResetToolButtonTriggered(bool /*checked*/) +{ + BrowserTabContent* btc = this->getTabContentFromSelectedTab(); + btc->resetView(); + this->updateGraphicsWindow(); + this->updateOtherYokedWindows(); +} + +/** + * Called when custom view is triggered and displays Custom View Menu. + */ +void +BrainBrowserWindowToolBarChartOrientation::customViewActionTriggered() +{ + m_parentToolBar->customViewActionTriggered(); +// CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); +// prefs->readCustomViews(); +// const std::vector > customViewNameAndComments = prefs->getCustomViewNamesAndComments(); +// +// QMenu menu; +// +// QAction* editAction = menu.addAction("Create and Edit..."); +// editAction->setToolTip("Add and delete Custom Views.\n" +// "Edit model transformations."); +// +// const int32_t numViews = static_cast(customViewNameAndComments.size()); +// if (numViews > 0) { +// menu.addSeparator(); +// } +// for (int32_t i = 0; i < numViews; i++) { +// QAction* action = menu.addAction(customViewNameAndComments[i].first); +// action->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customViewNameAndComments[i].second)); +// } +// +// QAction* selectedAction = menu.exec(QCursor::pos()); +// if (selectedAction != NULL) { +// if (selectedAction == editAction) { +// BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); +// GuiManager::get()->processShowCustomViewDialog(bbw); +// } +// else { +// const AString customViewName = selectedAction->text(); +// +// ModelTransform modelTransform; +// if (prefs->getCustomView(customViewName, modelTransform)) { +// BrowserTabContent* btc = this->getTabContentFromSelectedTab(); +// btc->setTransformationsFromModelTransform(modelTransform); +// this->updateGraphicsWindow(); +// this->updateOtherYokedWindows(); +// } +// } +// } +} + diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h b/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h new file mode 100644 index 000000000..c5427a7d0 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h @@ -0,0 +1,68 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "BrainBrowserWindowToolBarComponent.h" + +class QToolButton; + +namespace caret { + + class BrainBrowserWindowToolBarChartOrientation : public BrainBrowserWindowToolBarComponent { + Q_OBJECT + + public: + BrainBrowserWindowToolBarChartOrientation(BrainBrowserWindowToolBar* parentToolBar); + + virtual ~BrainBrowserWindowToolBarChartOrientation(); + + virtual void updateContent(BrowserTabContent* browserTabContent); + + // ADD_NEW_METHODS_HERE + + private slots: + void customViewActionTriggered(); + + void orientationResetToolButtonTriggered(bool /*checked*/); + + private: + BrainBrowserWindowToolBarChartOrientation(const BrainBrowserWindowToolBarChartOrientation&); + + BrainBrowserWindowToolBarChartOrientation& operator=(const BrainBrowserWindowToolBarChartOrientation&); + + QAction* m_orientationResetToolButtonAction; + + QAction* m_customViewAction; + + QToolButton* m_orientationCustomViewSelectToolButton; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarComponent.h b/src/GuiQt/BrainBrowserWindowToolBarComponent.h index 64b982c8c..9bdd62d3b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarComponent.h +++ b/src/GuiQt/BrainBrowserWindowToolBarComponent.h @@ -78,6 +78,7 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + friend class BrainBrowserWindowToolBarChartOrientation; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 5ee7d0c52..f1bd62dab 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -73,6 +73,7 @@ ELSE() BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h + BrainBrowserWindowToolBarChartOrientation.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -257,6 +258,7 @@ BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h +BrainBrowserWindowToolBarChartOrientation.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -465,6 +467,7 @@ BrainBrowserWindowOrientedToolBox.cxx BrainBrowserWindowToolBar.cxx BrainBrowserWindowToolBarChartAttributes.cxx BrainBrowserWindowToolBarChartAxes.cxx +BrainBrowserWindowToolBarChartOrientation.cxx BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx -- GitLab From 55843886918794cafccbe60f4883f61df69e103e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Jan 2017 15:46:27 -0600 Subject: [PATCH 187/755] Continuing new charting development. Changed toolbar groups so that the group name (at bottom; eg: 'Chart Orientation') allows newlines for names that are long to avoid using excess horizontal space. When the 'Draw with new charting in window 1' developer flag is on, show new charting controls in toolbar and toolbox and hide old charting controls. --- .../BrainBrowserWindowOrientedToolBox.cxx | 23 +++- src/GuiQt/BrainBrowserWindowToolBar.cxx | 112 +++++++++--------- src/GuiQt/BrainBrowserWindowToolBar.h | 2 + 3 files changed, 80 insertions(+), 57 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 44b061b68..1d5bb9ff6 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -42,6 +42,7 @@ #include "ChartableMatrixInterface.h" #include "ChartToolBoxViewController.h" #include "CiftiConnectivityMatrixViewController.h" +#include "DeveloperFlagsEnum.h" #include "EventBrowserWindowContentGet.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" @@ -649,7 +650,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) int defaultTabIndex = -1; bool enableLayers = true; bool enableVolumeSurfaceOutline = false; - bool enableCharts = false; + bool enableOldCharts = false; + bool enableNewCharts = false; EventBrowserWindowContentGet browserContentEvent(m_browserWindowIndex); EventManager::get()->sendEvent(browserContentEvent.getPointer()); BrowserTabContent* windowContent = browserContentEvent.getSelectedBrowserTabContent(); @@ -674,14 +676,26 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) & haveVolumes); break; case ModelTypeEnum::MODEL_TYPE_CHART: - defaultTabIndex = m_chartTabIndex; + if (m_browserWindowIndex == 0) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { + defaultTabIndex = m_chartOverlayTabIndex; + enableNewCharts = true; + } + else { + defaultTabIndex = m_chartTabIndex; + enableOldCharts = true; + } + } + else { + defaultTabIndex = m_chartTabIndex; + enableOldCharts = true; + } enableLayers = false; enableVolumeSurfaceOutline = false; haveBorders = false; haveFibers = false; haveFoci = false; haveLabels = false; - enableCharts = true; break; } } @@ -699,7 +713,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) * NOTE: Order is important so that overlay tab is * automatically selected. */ - if (m_chartTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartTabIndex, enableCharts); + if (m_chartTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartTabIndex, enableOldCharts); + if (m_chartOverlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartOverlayTabIndex, enableNewCharts); if (m_connectivityTabIndex >= 0) m_tabWidget->setTabEnabled(m_connectivityTabIndex, haveConnFiles); if (m_volumeSurfaceOutlineTabIndex >= 0) m_tabWidget->setTabEnabled(m_volumeSurfaceOutlineTabIndex, enableVolumeSurfaceOutline); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index cea456122..500299c69 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -155,6 +155,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->isContructorFinished = false; this->isDestructionInProgress = false; + m_chartingTwoFlag = false; this->viewOrientationLeftIcon = NULL; this->viewOrientationRightIcon = NULL; @@ -1365,6 +1366,16 @@ BrainBrowserWindowToolBar::updateToolBar() this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); + /* + * Use new charting in 1st window and old charting in other windows? + */ + m_chartingTwoFlag = false; + if (this->browserWindowIndex == 0) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { + m_chartingTwoFlag = true; + } + } + BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); const ModelTypeEnum::Enum viewModel = this->updateViewWidget(browserTabContent); @@ -1378,10 +1389,11 @@ BrainBrowserWindowToolBar::updateToolBar() bool showVolumePlaneWidget = false; bool showVolumeMontageWidget = false; - bool showChartAxesWidget = false; - bool showChartTypeWidget = false; - bool showChartAttributesWidget = false; - bool showChartOrientationWidget = false; + bool showChartOneAxesWidget = false; + bool showChartOneTypeWidget = false; + bool showChartTwoTypeWidget = false; + bool showChartOneAttributesWidget = false; + bool showChartTwoOrientationWidget = false; bool showModeWidget = true; bool showWindowWidget = true; @@ -1409,33 +1421,43 @@ BrainBrowserWindowToolBar::updateToolBar() break; case ModelTypeEnum::MODEL_TYPE_CHART: { - showChartTypeWidget = true; + if (m_chartingTwoFlag) { + showChartTwoTypeWidget = true; + } + else { + showChartOneTypeWidget = true; + } + showClippingOptionsWidget = false; ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); if (modelChart != NULL) { - showChartOrientationWidget = true; - switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { - case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - showChartAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - showChartAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - showChartAxesWidget = true; - showChartAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: - showChartAxesWidget = true; - showChartAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: - showChartAxesWidget = true; - showChartAttributesWidget = true; - break; + if (m_chartingTwoFlag) { + showChartTwoOrientationWidget = true; + } + else { + switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; + } } } } @@ -1468,11 +1490,11 @@ BrainBrowserWindowToolBar::updateToolBar() this->wholeBrainSurfaceOptionsWidget->setVisible(showWholeBrainSurfaceOptionsWidget); this->singleSurfaceSelectionWidget->setVisible(showSingleSurfaceOptionsWidget); this->surfaceMontageSelectionWidget->setVisible(showSurfaceMontageOptionsWidget); - this->chartTypeWidget->setVisible(showChartTypeWidget); - this->chartTypeTwoWidget->setVisible(showChartTypeWidget); - this->chartAxesWidget->setVisible(showChartAxesWidget); - this->chartAttributesWidget->setVisible(showChartAttributesWidget); - this->chartOrientationWidget->setVisible(showChartOrientationWidget); + this->chartTypeWidget->setVisible(showChartOneTypeWidget); + this->chartTypeTwoWidget->setVisible(showChartTwoTypeWidget); + this->chartAxesWidget->setVisible(showChartOneAxesWidget); + this->chartAttributesWidget->setVisible(showChartOneAttributesWidget); + this->chartOrientationWidget->setVisible(showChartTwoOrientationWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); @@ -2668,15 +2690,6 @@ BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabCo } m_chartTypeToolBarComponent->updateContent(browserTabContent); - - if (this->browserWindowIndex == 0) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { - this->chartTypeWidget->setEnabled(false); - } - else { - this->chartTypeWidget->setEnabled(true); - } - } } @@ -2713,15 +2726,6 @@ BrainBrowserWindowToolBar::updateChartTypeTwoWidget(BrowserTabContent* browserTa } m_chartTwoTypeToolBarComponent->updateContent(browserTabContent); - - if (this->browserWindowIndex == 0) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { - this->chartTypeTwoWidget->setEnabled(true); - } - else { - this->chartTypeTwoWidget->setEnabled(false); - } - } } /** @@ -2803,7 +2807,7 @@ QWidget* BrainBrowserWindowToolBar::createChartOrientationWidget() { m_chartOrientationToolBarComponent = new BrainBrowserWindowToolBarChartOrientation(this); - QWidget* w = this->createToolWidget("Orientation", + QWidget* w = this->createToolWidget("Chart
Orientation", m_chartOrientationToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, @@ -3035,7 +3039,8 @@ BrainBrowserWindowToolBar::updateVolumePlaneWidget(BrowserTabContent* browserTab * a descriptive label added. * * @param name - * Name for the descriptive labe. + * Name for the descriptive label. For a multi-line label, + * separate the lines with an HTML "
" tag. * @param childWidget * Child widget that is in the tool widget. * @param verticalBarPlacement @@ -3052,7 +3057,8 @@ BrainBrowserWindowToolBar::createToolWidget(const QString& name, const WidgetPlacement contentPlacement, const int /*horizontalStretching*/) { - QLabel* nameLabel = new QLabel("" + name + ""); + QLabel* nameLabel = new QLabel("

" + name + "
"); + nameLabel->setFixedHeight(nameLabel->sizeHint().height()); QWidget* w = new QWidget(); QGridLayout* layout = new QGridLayout(w); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 1036906a8..b743e367e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -416,6 +416,8 @@ namespace caret { bool isContructorFinished; bool isDestructionInProgress; + + bool m_chartingTwoFlag; }; } -- GitLab From d3d1bdf4019c648e018ff5fbab634ac27e62ae0a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 25 Jan 2017 14:30:06 -0600 Subject: [PATCH 188/755] Continuing charting development. Matrix viewing is mostly working --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 155 +++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 8 +- src/Brain/CMakeLists.txt | 2 - src/Brain/ChartOverlay.cxx | 612 +++++++++++++++--- src/Brain/ChartOverlay.h | 32 +- src/Brain/ChartOverlaySet.cxx | 4 +- src/Charting/CMakeLists.txt | 2 + .../ChartTwoMatrixLoadingDimensionEnum.cxx | 372 +++++++++++ .../ChartTwoMatrixLoadingDimensionEnum.h | 104 +++ src/Files/CMakeLists.txt | 2 + src/Files/ChartableTwoFileDelegate.cxx | 14 +- src/Files/ChartableTwoFileMatrixChart.cxx | 217 ++++++- src/Files/ChartableTwoFileMatrixChart.h | 30 +- ...etMappableDataFileMapsViewedInOverlays.cxx | 0 ...aretMappableDataFileMapsViewedInOverlays.h | 0 src/GuiQt/ChartOverlaySetViewController.cxx | 45 +- src/GuiQt/ChartOverlaySetViewController.h | 5 + src/GuiQt/ChartOverlayViewController.cxx | 335 +++++----- src/GuiQt/ChartOverlayViewController.h | 10 +- 19 files changed, 1580 insertions(+), 369 deletions(-) create mode 100644 src/Charting/ChartTwoMatrixLoadingDimensionEnum.cxx create mode 100644 src/Charting/ChartTwoMatrixLoadingDimensionEnum.h rename src/{Brain => Files}/EventCaretMappableDataFileMapsViewedInOverlays.cxx (100%) rename src/{Brain => Files}/EventCaretMappableDataFileMapsViewedInOverlays.h (100%) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 5c21dddcf..cf9765072 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -37,12 +37,12 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" -#include "CiftiParcelLabelFile.h" -#include "CiftiParcelScalarFile.h" -#include "CiftiScalarDataSeriesFile.h" -#include "ConnectivityDataLoaded.h" -#include "EventCaretMappableDataFileMapsViewedInOverlays.h" -#include "EventManager.h" +//#include "CiftiParcelLabelFile.h" +//#include "CiftiParcelScalarFile.h" +//#include "CiftiScalarDataSeriesFile.h" +//#include "ConnectivityDataLoaded.h" +//#include "EventCaretMappableDataFileMapsViewedInOverlays.h" +//#include "EventManager.h" #include "IdentificationWithColor.h" #include "SessionManager.h" @@ -338,7 +338,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() */ if ((overlayRows == numberOfRows) && (overlayColumns == numberOfCols)) { - drawMatrixChartGrid(matrixChart, + drawMatrixChartContent(matrixChart, ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL, //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL, //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL, @@ -350,61 +350,61 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() } } -/** - * Get highlighting of rows or columns for a matrix. - * - * @param matrixChart - * Matrix chart that is drawn. - * @param rowIndicesOut - * Output with row indices for highlighting. - * @param columnIndicesOut - * Output with column indices for highlighting. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, - std::set& rowIndicesOut, - std::set& columnIndicesOut) const -{ - const CiftiMappableDataFile* ciftiMapFile = matrixChart->getCiftiMappableDataFile(); - const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); - if (connMapFile != NULL) { - const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); - if (connDataLoaded != NULL) { - int64_t loadedRowIndex = -1; - int64_t loadedColumnIndex = -1; - connDataLoaded->getRowColumnLoading(loadedRowIndex, - loadedColumnIndex); - if (loadedRowIndex >= 0) { - rowIndicesOut.insert(loadedRowIndex); - } - else if (loadedColumnIndex >= 0) { - columnIndicesOut.insert(loadedColumnIndex); - } - } - } - - const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); - if (parcelScalarFile != NULL) { - EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); - EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); - } - - const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); - if (parcelLabelFile != NULL) { - EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); - EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); - } - - const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); - if (scalarDataSeriesFile != NULL) { - const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(m_tabIndex); - if (scalarDataSeriesMapIndex >= 0) { - rowIndicesOut.insert(scalarDataSeriesMapIndex); - } - } -} +///** +// * Get highlighting of rows or columns for a matrix. +// * +// * @param matrixChart +// * Matrix chart that is drawn. +// * @param rowIndicesOut +// * Output with row indices for highlighting. +// * @param columnIndicesOut +// * Output with column indices for highlighting. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, +// std::set& rowIndicesOut, +// std::set& columnIndicesOut) const +//{ +// const CiftiMappableDataFile* ciftiMapFile = matrixChart->getCiftiMappableDataFile(); +// const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); +// if (connMapFile != NULL) { +// const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); +// if (connDataLoaded != NULL) { +// int64_t loadedRowIndex = -1; +// int64_t loadedColumnIndex = -1; +// connDataLoaded->getRowColumnLoading(loadedRowIndex, +// loadedColumnIndex); +// if (loadedRowIndex >= 0) { +// rowIndicesOut.insert(loadedRowIndex); +// } +// else if (loadedColumnIndex >= 0) { +// columnIndicesOut.insert(loadedColumnIndex); +// } +// } +// } +// +// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); +// if (parcelScalarFile != NULL) { +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); +// } +// +// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); +// if (parcelLabelFile != NULL) { +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); +// } +// +// const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); +// if (scalarDataSeriesFile != NULL) { +// const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(m_tabIndex); +// if (scalarDataSeriesMapIndex >= 0) { +// rowIndicesOut.insert(scalarDataSeriesMapIndex); +// } +// } +//} /* * Draw a matrix chart. @@ -421,7 +421,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::getMatrixHighlighting(const ChartableTw * Current zooming. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartGrid(const ChartableTwoFileMatrixChart* matrixChart, +BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, @@ -438,15 +438,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartGrid(const ChartableTwoF } CaretAssertToDoWarning(); // need to set these - bool displayGridLinesFlag = true; - bool highlightSelectedRowColumnFlag = true; + bool displayGridLinesFlag = false; + const bool highlightSelectedRowColumnFlag = true; - std::set selectedColumnIndices; - std::set selectedRowIndices; - getMatrixHighlighting(matrixChart, - selectedRowIndices, - selectedColumnIndices); + std::vector selectedColumnIndices; + std::vector selectedRowIndices; + ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; + matrixChart->getSelectedRowColumnIndices(m_tabIndex, + selectedRowColumnDimension, + selectedRowIndices, + selectedColumnIndices); +// getMatrixHighlighting(matrixChart +// selectedRowIndices, +// selectedColumnIndices); uint8_t highlightRGBByte[3]; m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); @@ -663,10 +668,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartGrid(const ChartableTwoF std::vector rowXYZ; std::vector rowRGBA; - for (std::set::iterator rowIter = selectedRowIndices.begin(); - rowIter != selectedRowIndices.end(); - rowIter ++) { - const float rowIndex = * rowIter; + for (auto rowIndex : selectedRowIndices) { const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; @@ -737,10 +739,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartGrid(const ChartableTwoF std::vector columnXYZ; std::vector columnRGBA; - for (std::set::iterator colIter = selectedColumnIndices.begin(); - colIter != selectedColumnIndices.end(); - colIter++) { - const float columnIndex = *colIter; + for (auto columnIndex : selectedColumnIndices) { const float colX = columnIndex * cellWidth; columnXYZ.push_back(colX); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index a232ea39a..49c45d36d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -82,15 +82,15 @@ namespace caret { uint8_t rgbaForColorIdentification[4]); void drawMatrixChart(); - void drawMatrixChartGrid(const ChartableTwoFileMatrixChart* matrixChart, + void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, const float zooming); - void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, - std::set& rowIndicesOut, - std::set& columnIndicesOut) const; +// void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, +// std::set& rowIndicesOut, +// std::set& columnIndicesOut) const; Brain* m_brain; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 7a48b5b5c..c4dc788ac 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -109,7 +109,6 @@ EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h EventBrowserTabNew.h -EventCaretMappableDataFileMapsViewedInOverlays.h EventDataFileAdd.h EventDataFileDelete.h EventDataFileRead.h @@ -251,7 +250,6 @@ EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx EventBrowserTabNew.cxx -EventCaretMappableDataFileMapsViewedInOverlays.cxx EventDataFileAdd.cxx EventDataFileDelete.cxx EventDataFileRead.cxx diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index cde8f9f74..b5159e58a 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -51,6 +51,8 @@ using namespace caret; /** * Constructor. * + * @param parentChartOverlaySet + * Parent of this chart overlay set. * @param chartDataType * Type of charts allowed in this overlay * @param overlayIndex @@ -64,12 +66,7 @@ m_parentChartOverlaySet(parentChartOverlaySet), m_chartDataType(chartDataType), m_overlayIndex(overlayIndex) { - if (overlayIndex > 0) { - CaretAssert(m_parentChartOverlaySet == NULL); - } - else { - CaretAssert(m_parentChartOverlaySet); - } + CaretAssert(m_parentChartOverlaySet); // m_chartCompoundDataType m_name = "Overlay " + AString::number(overlayIndex + 1); @@ -80,15 +77,15 @@ m_overlayIndex(overlayIndex) m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); m_selectedMapFile = NULL; - m_selectedMapIndex = -1; - m_allMapsSelectedFlag = false; + m_selectedHistogramMapIndex = -1; + m_allHistogramMapsSelectedFlag = false; m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_enabled", &m_enabled); m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar.get()); - m_sceneAssistant->add("m_allMapsSelectedFlag", &m_allMapsSelectedFlag); + m_sceneAssistant->add("m_allHistogramMapsSelectedFlag", &m_allHistogramMapsSelectedFlag); // EventManager::get()->addEventListener(this, // EventTypeEnum::EVENT_OVERLAY_VALIDATE); @@ -279,7 +276,8 @@ ChartOverlay::copyData(const ChartOverlay* overlay) *m_colorBar = *overlay->m_colorBar; m_selectedMapFile = overlay->m_selectedMapFile; - m_selectedMapIndex = overlay->m_selectedMapIndex; + m_selectedHistogramMapIndex = overlay->m_selectedHistogramMapIndex; + m_allHistogramMapsSelectedFlag = overlay->m_allHistogramMapsSelectedFlag; } /** @@ -299,6 +297,51 @@ ChartOverlay::swapData(ChartOverlay* overlay) copyData(swapOverlay.get()); } +/** + * Is history supported ? + */ +bool +ChartOverlay::isHistorySupported() const +{ + bool supportedFlag = false; + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + supportedFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + return supportedFlag; +} + +/** + * Is map yoking supported ? + */ +bool +ChartOverlay::isMapYokingSupported() const +{ + bool supportedFlag = false; + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + supportedFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + supportedFlag = true; + break; + } + return true; +} + /** * @return Selected map yoking group. */ @@ -349,10 +392,9 @@ ChartOverlay::getColorBar() const */ void ChartOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) + int32_t& selectedMapIndexOut) const { std::vector mapFiles; - getSelectionData(mapFiles, selectedMapFileOut, selectedMapIndexOut); @@ -366,19 +408,258 @@ ChartOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. - * @param selectedMapUniqueIDOut - * UniqueID of selected map. + * @param selectedFileMapNamesOut + * Map names from selected file. + * @param selectedMapIndexOut + * Index of selected map in the selected file. + */ +void +ChartOverlay::getSelectionData(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + std::vector& selectedFileMapNamesOut, + int32_t& selectedMapIndexOut) const +{ + getSelectionDataPrivate(mapFilesOut, + selectedMapFileOut, + &selectedFileMapNamesOut, + selectedMapIndexOut); + +// CaretAssertToDoFatal(); +// selectedFileMapNamesOut.clear(); +// +// getSelectionData(mapFilesOut, +// selectedMapFileOut, +// selectedMapIndexOut); +// +// if (selectedMapFileOut == NULL) { +// return; +// } +// +// switch (m_chartDataType) { +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: +// { +// const int32_t numMaps = selectedMapFileOut->getNumberOfMaps(); +// for (int32_t i = 0; i < numMaps; i++) { +// selectedFileMapNamesOut.push_back(selectedMapFileOut->getMapName(i)); +// } +// } +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: +// { +// ChartableTwoFileDelegate* chartDelegate = selectedMapFileOut->getChartingDelegate(); +// const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); +// CaretAssert(matrixChart); +// int32_t numRows = 0; +// int32_t numCols = 0; +// matrixChart->getMatrixDimensions(numRows, numCols); +// for (int32_t i = 0; i < numRows; i++) { +// selectedFileMapNamesOut.push_back("Row " + QString::number(i + 1)); +// } +// } +// break; +// } +} + +/** + * Return the selection information. This method is typically + * called to update the user-interface. + * + * @param mapFilesOut + * Contains all map files that can be selected. + * @param selectedMapFileOut + * The selected map file. May be NULL. * @param selectedMapIndexOut * Index of selected map in the selected file. */ void ChartOverlay::getSelectionData(std::vector& mapFilesOut, - CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) + CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut) const +{ + getSelectionDataPrivate(mapFilesOut, + selectedMapFileOut, + NULL, + selectedMapIndexOut); +} + +///** +// * Return the selection information. This method is typically +// * called to update the user-interface. +// * +// * @param mapFilesOut +// * Contains all map files that can be selected. +// * @param selectedMapFileOut +// * The selected map file. May be NULL. +// * @param selectedMapIndexOut +// * Index of selected map in the selected file. +// */ +//void +//ChartOverlay::getSelectionData(std::vector& mapFilesOut, +// CaretMappableDataFile* &selectedMapFileOut, +// int32_t& selectedMapIndexOut) +//{ +// mapFilesOut.clear(); +// selectedMapFileOut = NULL; +// selectedMapIndexOut = -1; +// +// /** +// * Get the data files. +// */ +// std::vector allDataFiles; +// EventCaretMappableDataFilesGet eventGetMapDataFiles; +// EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); +// eventGetMapDataFiles.getAllFiles(allDataFiles); +// +// /* +// * Use only those data files that meet criteria. +// */ +// for (auto mapFile : allDataFiles) { +// CaretAssert(mapFile); +// ChartableTwoFileDelegate* chartingFile = mapFile->getChartingDelegate(); +// if (chartingFile->isChartingSupported()) { +// bool useIt = false; +// +// std::vector chartCompoundDataTypes; +// chartingFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); +// +// for (auto& compoundType : chartCompoundDataTypes) { +// if (m_chartDataType == compoundType.getChartDataType()) { +// if (m_overlayIndex == 0) { +// /* +// * The first overlay displays ALL files that match the +// * enumerated chart type +// */ +// useIt = true; +// } +// else { +// if (m_chartCompoundDataType == compoundType) { +// /* +// * If not the first overlay, the enumerated type +// * and dimensions must also match +// */ +// useIt = true; +// } +// } +// } +// } +// +// if (useIt) { +// mapFilesOut.push_back(mapFile); +// } +// } +// } +// +// /* +// * Does selected data file still no longer exist? +// */ +// if (std::find(mapFilesOut.begin(), +// mapFilesOut.end(), +// m_selectedMapFile) == mapFilesOut.end()) { +// /* +// * Invalidate seleted file and disable yoking since +// * the selected file will change. +// */ +// m_selectedMapFile = NULL; +// m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; +// } +// +// /* +// * If selected data file is valid, see if selected +// * map is still valid. If not, use first map. +// */ +// if (m_selectedMapFile != NULL) { +// if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { +// m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; +// } +// if (m_selectedMapIndex < 0) { +// m_selectedMapIndex = 0; +// } +// } +// else { +// /* +// * Use first map in first file that has one or more maps. +// */ +// if (m_selectedMapFile == NULL) { +// if (mapFilesOut.empty() == false) { +// for (std::vector::iterator iter = mapFilesOut.begin(); +// iter != mapFilesOut.end(); +// iter++) { +// CaretMappableDataFile* mapTypeFile = *iter; +// if (mapTypeFile->getNumberOfMaps() > 0) { +// m_selectedMapFile = mapTypeFile; +// m_selectedMapIndex = 0; +// break; +// } +// } +// } +// } +// } +// +// selectedMapFileOut = m_selectedMapFile; +// if (selectedMapFileOut != NULL) { +// // /* +// // * Update for overlay yoking +// // */ +// // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { +// // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); +// // if ((yokeMapIndex >= 0) +// // && (yokeMapIndex < selectedMapFileOut->getNumberOfMaps())) { +// // m_selectedMapIndex = yokeMapIndex; +// // } +// // else if (yokeMapIndex >= selectedMapFileOut->getNumberOfMaps()) { +// // m_selectedMapIndex = selectedMapFileOut->getNumberOfMaps() - 1; +// // } +// // } +// // +// selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); +// } +// +// /* +// * Update the compound data type if this is the FIRST OVERLAY +// */ +// if (m_overlayIndex == 0) { +// if (m_selectedMapFile != NULL) { +// ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); +// CaretAssert(chartFile); +// chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, +// m_chartCompoundDataType); +// } +// CaretAssert(m_parentChartOverlaySet); +// m_parentChartOverlaySet->firstOverlaySelectionChanged(); +// } +// //If selected type changes, need to update other overlays in the overlay set with +// //the selected data type} +//} + +/** + * Return the selection information. This method is typically + * called to update the user-interface. + * + * @param mapFilesOut + * Contains all map files that can be selected. + * @param selectedMapFileOut + * The selected map file. May be NULL. + * @param selectedFileMapNamesOut + * Optional output, if not NULL, with map names + * @param selectedMapIndexOut + * Index of selected map in the selected file. + */ +void +ChartOverlay::getSelectionDataPrivate(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + std::vector* selectedFileMapNamesOut, + int32_t& selectedMapIndexOut) const { mapFilesOut.clear(); selectedMapFileOut = NULL; selectedMapIndexOut = -1; + if (selectedFileMapNamesOut != NULL) { + selectedFileMapNamesOut->clear(); + } /** * Get the data files. @@ -441,66 +722,177 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } +// /* +// * If selected data file is valid, see if selected +// * map is still valid. If not, use first map. +// */ +// if (m_selectedMapFile != NULL) { +// if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { +// m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; +// } +// if (m_selectedMapIndex < 0) { +// m_selectedMapIndex = 0; +// } +// } +// else { +// /* +// * Use first map in first file that has one or more maps. +// */ +// if (m_selectedMapFile == NULL) { +// if (mapFilesOut.empty() == false) { +// for (std::vector::iterator iter = mapFilesOut.begin(); +// iter != mapFilesOut.end(); +// iter++) { +// CaretMappableDataFile* mapTypeFile = *iter; +// if (mapTypeFile->getNumberOfMaps() > 0) { +// m_selectedMapFile = mapTypeFile; +// m_selectedMapIndex = 0; +// break; +// } +// } +// } +// } +// } + /* - * If selected data file is valid, see if selected - * map is still valid. If not, use first map. + * If no file selected, select the first valid file */ - if (m_selectedMapFile != NULL) { - if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { - m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; - } - if (m_selectedMapIndex < 0) { - m_selectedMapIndex = 0; + if (m_selectedMapFile == NULL) { + if ( ! mapFilesOut.empty()) { + for (std::vector::iterator iter = mapFilesOut.begin(); + iter != mapFilesOut.end(); + iter++) { + CaretMappableDataFile* mapTypeFile = *iter; + m_selectedMapFile = mapTypeFile; + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + m_selectedHistogramMapIndex = 0; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + break; + } } } - else { - /* - * Use first map in first file that has one or more maps. - */ - if (m_selectedMapFile == NULL) { - if (mapFilesOut.empty() == false) { - for (std::vector::iterator iter = mapFilesOut.begin(); - iter != mapFilesOut.end(); - iter++) { - CaretMappableDataFile* mapTypeFile = *iter; - if (mapTypeFile->getNumberOfMaps() > 0) { - m_selectedMapFile = mapTypeFile; - m_selectedMapIndex = 0; + + if (m_selectedMapFile != NULL) { + int32_t numMaps = 0; + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { + numMaps = m_selectedMapFile->getNumberOfMaps(); + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(m_selectedMapFile->getMapName(i)); + } + } + if (m_selectedHistogramMapIndex >= numMaps) { + m_selectedHistogramMapIndex = numMaps - 1; + } + if (m_selectedHistogramMapIndex < 0) { + m_selectedHistogramMapIndex = 0; + } + selectedMapIndexOut = m_selectedHistogramMapIndex; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + { + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); + CaretAssert(matrixChart); + int32_t numRows = 0; + int32_t numCols = 0; + matrixChart->getMatrixDimensions(numRows, numCols); + + ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; + std::vector columnIndices; + std::vector rowIndices; + matrixChart->getSelectedRowColumnIndices(m_parentChartOverlaySet->m_tabIndex, + rowColumnDimension, + rowIndices, + columnIndices); + + AString namePrefix; + switch (rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + numMaps = numCols; + namePrefix = "Column "; + if ( ! columnIndices.empty()) { + selectedMapIndexOut = columnIndices[0]; + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + numMaps = numRows; + namePrefix = "Row "; + if ( ! rowIndices.empty()) { + selectedMapIndexOut = rowIndices[0]; + } break; + } + + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); } } + + } + break; } + +// /* +// * If selected data file is valid, see if selected +// * map is still valid. If not, use first map. +// */ +// if (m_selectedMapFile != NULL) { +// if (m_selectedHistogramMapIndex >= numMaps) { +// m_selectedHistogramMapIndex = numMaps - 1; +// } +// if (m_selectedHistogramMapIndex < 0) { +// m_selectedHistogramMapIndex = 0; +// } +// } } - + selectedMapFileOut = m_selectedMapFile; - if (selectedMapFileOut != NULL) { - // /* - // * Update for overlay yoking - // */ - // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); - // if ((yokeMapIndex >= 0) - // && (yokeMapIndex < selectedMapFileOut->getNumberOfMaps())) { - // m_selectedMapIndex = yokeMapIndex; - // } - // else if (yokeMapIndex >= selectedMapFileOut->getNumberOfMaps()) { - // m_selectedMapIndex = selectedMapFileOut->getNumberOfMaps() - 1; - // } - // } - // - selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); - } +// if (selectedMapFileOut != NULL) { +// // /* +// // * Update for overlay yoking +// // */ +// // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { +// // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); +// // if ((yokeMapIndex >= 0) +// // && (yokeMapIndex < numMaps)) { +// // m_selectedMapIndex = yokeMapIndex; +// // } +// // else if (yokeMapIndex >= numMaps) { +// // m_selectedMapIndex = numMaps - 1; +// // } +// // } +// // +// selectedMapIndexOut = m_selectedHistogramMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); +// } /* * Update the compound data type if this is the FIRST OVERLAY */ if (m_overlayIndex == 0) { if (m_selectedMapFile != NULL) { - ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); + const ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartFile); chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, - m_chartCompoundDataType); + m_chartCompoundDataType); } CaretAssert(m_parentChartOverlaySet); m_parentChartOverlaySet->firstOverlaySelectionChanged(); @@ -513,45 +905,117 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, * Set the selected map file and map. * @param selectedMapFile * File that is selected. - * @param selectedMapName - * Map name that is selected. + * @param selectedMapIndex + * Index of map for selection. If invalid, try the current map + * index if it is valid. Otherwise, use the first map index. */ void ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex) { m_selectedMapFile = selectedMapFile; - m_selectedMapIndex = selectedMapIndex; - - if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - if (m_selectedMapFile == NULL) { - m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + if (m_selectedMapFile != NULL) { + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + if (selectedMapIndex >= 0) { + m_selectedHistogramMapIndex = selectedMapIndex; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + { + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + CaretAssert(chartDelegate); + ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); + CaretAssert(matrixChart); + matrixChart->setSelectedRowColumnIndex(m_parentChartOverlaySet->m_tabIndex, + selectedMapIndex); + } + break; + } + + if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + if (m_selectedMapFile == NULL) { + m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + } + // if (selectedMapFile != NULL) { + // MapYokingGroupEnum::setSelectedMapIndex(m_mapYokingGroup, + // selectedMapIndex); + // } + // else { + // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + // } } - // if (selectedMapFile != NULL) { - // MapYokingGroupEnum::setSelectedMapIndex(m_mapYokingGroup, - // selectedMapIndex); - // } - // else { - // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; - // } } + /* * By calling getSelectionData(), it will validate the - * selected file + * selected file and map index and update if needed + * (such as a valid map index). */ CaretMappableDataFile* filePointer = NULL; int32_t mapIndex = -1; getSelectionData(filePointer, mapIndex); } +/* + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + */ +/** + * @return Is the all maps supported? + */ +bool +ChartOverlay::isAllMapsSupported() const +{ + bool supportedFlag = false; + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { + CaretMappableDataFile* cmdf = NULL; + int32_t mapIndex = 0; + + getSelectionData(cmdf, + mapIndex); + + if (cmdf != NULL) { + if (cmdf->getNumberOfMaps() > 1) { + supportedFlag = true; + } + } + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + return supportedFlag; +} + /** * @return All maps selected. */ bool ChartOverlay::isAllMapsSelected() const { - return m_allMapsSelectedFlag; + return m_allHistogramMapsSelectedFlag; } /** @@ -563,7 +1027,7 @@ ChartOverlay::isAllMapsSelected() const void ChartOverlay::setAllMapsSelected(const bool status) { - m_allMapsSelectedFlag = status; + m_allHistogramMapsSelectedFlag = status; } diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index a9bf88da2..167386f6c 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -66,6 +66,10 @@ namespace caret { void swapData(ChartOverlay* overlay); + bool isHistorySupported() const; + + bool isMapYokingSupported() const; + MapYokingGroupEnum::Enum getMapYokingGroup() const; void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); @@ -76,14 +80,21 @@ namespace caret { void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut); + std::vector& selectedFileMapNamesOut, + int32_t& selectedMapIndexOut) const; + + void getSelectionData(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + int32_t& selectedMapIndexOut) const; void getSelectionData(CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut); + int32_t& selectedMapIndexOut) const; void setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex); + bool isAllMapsSupported() const; + bool isAllMapsSelected() const; void setAllMapsSelected(const bool status); @@ -113,6 +124,11 @@ namespace caret { ChartOverlay& operator=(const ChartOverlay&); + void getSelectionDataPrivate(std::vector& mapFilesOut, + CaretMappableDataFile* &selectedMapFileOut, + std::vector* selectedFileMapNamesOut, + int32_t& selectedMapIndexOut) const; + /** Parent chart overlay set (only used by first overlay in the set */ ChartOverlaySet* m_parentChartOverlaySet; @@ -125,7 +141,7 @@ namespace caret { std::unique_ptr m_sceneAssistant; /** Current 'compound chart type' of charts allowed in this overlay */ - ChartTwoCompoundDataType m_chartCompoundDataType; + mutable ChartTwoCompoundDataType m_chartCompoundDataType; /** Name of overlay (DO NOT COPY)*/ AString m_name; @@ -134,18 +150,18 @@ namespace caret { mutable bool m_enabled = true; /** map yoking group */ - MapYokingGroupEnum::Enum m_mapYokingGroup; + mutable MapYokingGroupEnum::Enum m_mapYokingGroup; /** The color bar displayed in the graphics window */ std::unique_ptr m_colorBar; /** selected mappable file */ - CaretMappableDataFile* m_selectedMapFile = NULL; + mutable CaretMappableDataFile* m_selectedMapFile = NULL; - /** selected map index */ - int32_t m_selectedMapIndex = -1; + /** histogram selected map index */ + mutable int32_t m_selectedHistogramMapIndex = -1; - bool m_allMapsSelectedFlag = false; + bool m_allHistogramMapsSelectedFlag = false; // ADD_NEW_MEMBERS_HERE diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartOverlaySet.cxx index 2219b7a92..44e19bb11 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartOverlaySet.cxx @@ -66,9 +66,7 @@ m_tabIndex(tabIndex) &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - /* use "this" as parent only for first chart overlay */ - ChartOverlaySet* me = ((i > 0) ? NULL : this); - m_overlays[i] = new ChartOverlay(me, + m_overlays[i] = new ChartOverlay(this, m_chartDataType, i); } diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 923fc8643..7d01c5539 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -46,6 +46,7 @@ ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h +ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixViewingTypeEnum.h ChartAxis.cxx @@ -79,6 +80,7 @@ ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx +ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixViewingTypeEnum.cxx ) diff --git a/src/Charting/ChartTwoMatrixLoadingDimensionEnum.cxx b/src/Charting/ChartTwoMatrixLoadingDimensionEnum.cxx new file mode 100644 index 000000000..e365596f3 --- /dev/null +++ b/src/Charting/ChartTwoMatrixLoadingDimensionEnum.cxx @@ -0,0 +1,372 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ +#include "ChartTwoMatrixLoadingDimensionEnum.h" +#undef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoMatrixLoadingDimensionEnum + * \brief Enumerated type for loading matrix data by row or column + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_ChartTwoMatrixLoadingDimensionEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void ChartTwoMatrixLoadingDimensionEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoMatrixLoadingDimensionEnum.h" + * + * Instatiate: + * m_ChartTwoMatrixLoadingDimensionEnumComboBox = new EnumComboBoxTemplate(this); + * m_ChartTwoMatrixLoadingDimensionEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_ChartTwoMatrixLoadingDimensionEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(ChartTwoMatrixLoadingDimensionEnumComboBoxItemActivated())); + * + * Update the selection: + * m_ChartTwoMatrixLoadingDimensionEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoMatrixLoadingDimensionEnum::Enum VARIABLE = m_ChartTwoMatrixLoadingDimensionEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoMatrixLoadingDimensionEnum::ChartTwoMatrixLoadingDimensionEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoMatrixLoadingDimensionEnum::~ChartTwoMatrixLoadingDimensionEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoMatrixLoadingDimensionEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_ROW, + "CHART_MATRIX_LOADING_BY_ROW", + "Row")); + + enumData.push_back(ChartTwoMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_COLUMN, + "CHART_MATRIX_LOADING_BY_COLUMN", + "Column")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoMatrixLoadingDimensionEnum* +ChartTwoMatrixLoadingDimensionEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoMatrixLoadingDimensionEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoMatrixLoadingDimensionEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoMatrixLoadingDimensionEnum::Enum +ChartTwoMatrixLoadingDimensionEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixLoadingDimensionEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoMatrixLoadingDimensionEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoMatrixLoadingDimensionEnum::Enum +ChartTwoMatrixLoadingDimensionEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixLoadingDimensionEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoMatrixLoadingDimensionEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoMatrixLoadingDimensionEnum::Enum +ChartTwoMatrixLoadingDimensionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoMatrixLoadingDimensionEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoMatrixLoadingDimensionEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoMatrixLoadingDimensionEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoMatrixLoadingDimensionEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoMatrixLoadingDimensionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoMatrixLoadingDimensionEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoMatrixLoadingDimensionEnum.h b/src/Charting/ChartTwoMatrixLoadingDimensionEnum.h new file mode 100644 index 000000000..758ca595f --- /dev/null +++ b/src/Charting/ChartTwoMatrixLoadingDimensionEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ +#define __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoMatrixLoadingDimensionEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Load data from column */ + CHART_MATRIX_LOADING_BY_COLUMN, + /** Load data from row */ + CHART_MATRIX_LOADING_BY_ROW + }; + + + ~ChartTwoMatrixLoadingDimensionEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoMatrixLoadingDimensionEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoMatrixLoadingDimensionEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ +std::vector ChartTwoMatrixLoadingDimensionEnum::enumData; +bool ChartTwoMatrixLoadingDimensionEnum::initializedFlag = false; +int32_t ChartTwoMatrixLoadingDimensionEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index b43b924f7..0b3bcce7e 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -72,6 +72,7 @@ CiftiParcelScalarFile.h CiftiScalarDataSeriesFile.h ConnectivityDataLoaded.h ControlPointFile.h +EventCaretMappableDataFileMapsViewedInOverlays.h EventCaretMappableDataFilesGet.h EventChartMatrixParcelYokingValidation.h EventGetDisplayedDataFiles.h @@ -196,6 +197,7 @@ CiftiParcelScalarFile.cxx CiftiScalarDataSeriesFile.cxx ConnectivityDataLoaded.cxx ControlPointFile.cxx +EventCaretMappableDataFileMapsViewedInOverlays.cxx EventCaretMappableDataFilesGet.cxx EventChartMatrixParcelYokingValidation.cxx EventGetDisplayedDataFiles.cxx diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index b640842b2..1d2200722 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -90,6 +90,8 @@ ChartableTwoFileDelegate::updateAfterFileChanged() ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; ChartTwoMatrixContentTypeEnum::Enum matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; + std::vector validMatrixRowColumnSelectionDimensions; + switch (m_caretMappableDataFile->getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_DENSE: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; @@ -113,17 +115,21 @@ ChartableTwoFileDelegate::updateAfterFileChanged() case DataFileTypeEnum::CONNECTIVITY_PARCEL: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; @@ -132,6 +138,7 @@ ChartableTwoFileDelegate::updateAfterFileChanged() case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS; + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); break; case DataFileTypeEnum::ANNOTATION: break; @@ -179,7 +186,8 @@ ChartableTwoFileDelegate::updateAfterFileChanged() m_caretMappableDataFile)); m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(matrixType, - m_caretMappableDataFile)); + m_caretMappableDataFile, + validMatrixRowColumnSelectionDimensions)); clearModified(); } @@ -196,8 +204,10 @@ ChartableTwoFileDelegate::clear() m_lineSeriesCharting = std::unique_ptr(new ChartableTwoFileLineSeriesChart(ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED, m_caretMappableDataFile)); + std::vector validMatrixRowColumnSelectionDimensions; m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED, - m_caretMappableDataFile)); + m_caretMappableDataFile, + validMatrixRowColumnSelectionDimensions)); } /** diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 35051c193..1a0731e6a 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -28,6 +28,10 @@ #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" +#include "CiftiScalarDataSeriesFile.h" +#include "ConnectivityDataLoaded.h" +#include "EventCaretMappableDataFileMapsViewedInOverlays.h" +#include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -48,12 +52,16 @@ using namespace caret; * Content type of the matrix. * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. + * @param validRowColumnSelectionDimensions + * Valid row/column selection dimensions for loading and selection. */ ChartableTwoFileMatrixChart::ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, - CaretMappableDataFile* parentCaretMappableDataFile) + CaretMappableDataFile* parentCaretMappableDataFile, + std::vector& validRowColumnSelectionDimensions) : ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, parentCaretMappableDataFile), -m_matrixContentType(matrixContentType) +m_matrixContentType(matrixContentType), +m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) { m_sceneAssistant = new SceneClassAssistant(); @@ -78,6 +86,15 @@ m_matrixContentType(matrixContentType) updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, numCols)); + + m_rowColumnDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + if ( ! m_validRowColumnSelectionDimensions.empty()) { + CaretAssertVectorIndex(m_validRowColumnSelectionDimensions, 0); + m_rowColumnDimension = m_validRowColumnSelectionDimensions[0]; + } + + m_sceneAssistant->add("m_rowColumnDimension", + &m_rowColumnDimension); } /** @@ -344,6 +361,202 @@ ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, // return validDataFlag; } +/** + * @return The selected row/column dimension. + */ +ChartTwoMatrixLoadingDimensionEnum::Enum +ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const +{ + return m_rowColumnDimension; +} + +/** + * Set the selected row/column dimension. + * + * @param rowColumnDimension + * New value for row/column dimension + */ +void +ChartableTwoFileMatrixChart::setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension) +{ + if (m_rowColumnDimension != rowColumnDimension) { + m_rowColumnDimension = rowColumnDimension; + setModified(); + } +} + +/** + * Get the valid row/column dimensions. + * + * @param validRowColumnSelectionDimensionsOut + * Output with valid row/column dimensions for selection. + */ +void +ChartableTwoFileMatrixChart::getValidRowColumnSelectionDimensions(std::vector& validRowColumnSelectionDimensionsOut) const +{ + validRowColumnSelectionDimensionsOut = m_validRowColumnSelectionDimensions; +} + +/** + * @param tabIndex + * Index of the tab. + * @param rowColumnDimensionOut + * Indices if indices are for rows or columns. + * @param rowIndicesOut + * Output with row indices selected. + * @param columnIndicesOut + * Output with column indices selected. + */ +void +ChartableTwoFileMatrixChart::getSelectedRowColumnIndices(const int32_t tabIndex, + ChartTwoMatrixLoadingDimensionEnum::Enum& rowColumnDimensionOut, + std::vector& rowIndicesOut, + std::vector& columnIndicesOut) const +{ + rowColumnDimensionOut = m_rowColumnDimension; + rowIndicesOut.clear(); + columnIndicesOut.clear(); + + std::set rowIndicesSet; + std::set columnIndicesSet; + + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); + if (connMapFile != NULL) { + const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); + if (connDataLoaded != NULL) { + int64_t loadedRowIndex = -1; + int64_t loadedColumnIndex = -1; + connDataLoaded->getRowColumnLoading(loadedRowIndex, + loadedColumnIndex); + switch (m_rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + if (loadedColumnIndex >= 0) { + columnIndicesSet.insert(loadedColumnIndex); + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + if (loadedRowIndex >= 0) { + rowIndicesSet.insert(loadedRowIndex); + } + break; + } + } + } + + const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); + if (parcelScalarFile != NULL) { + EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); + EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { + columnIndicesSet.insert(indx); + } + } + + const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); + if (parcelLabelFile != NULL) { + EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); + EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { + columnIndicesSet.insert(indx); + } + } + + const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); + if (scalarDataSeriesFile != NULL) { + const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(tabIndex); + if (scalarDataSeriesMapIndex >= 0) { + rowIndicesSet.insert(scalarDataSeriesMapIndex); + } + } + + rowIndicesOut.insert(rowIndicesOut.end(), + rowIndicesSet.begin(), + rowIndicesSet.end()); + columnIndicesOut.insert(columnIndicesOut.end(), + columnIndicesSet.begin(), + columnIndicesSet.end()); +} + +/** + * Set the row or column index using the currently selected row/column dimension. + * + * @param tabIndex + * Index of tab. + * @param rowColumnIndex + * New row/column index. + */ +void +ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, + const int32_t rowColumnIndex) +{ + /* + * Ignore an invalid row/column index. It may occur when the chart overlay + * is changed. + */ + if (rowColumnIndex < 0) { + return; + } + + CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); + if (connMapFile != NULL) { + /* + * Load data for the row/column. + * Invalidating coloring results in the necessary update of brainordinate coloring. + */ + int32_t numRows = -1; + int32_t numCols = -1; + getMatrixDimensions(numRows, numCols); + switch (m_rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numCols)) { + connMapFile->loadDataForColumnIndex(rowColumnIndex); + connMapFile->invalidateColoringInAllMaps(); + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRows)) { + connMapFile->loadDataForRowIndex(rowColumnIndex); + connMapFile->invalidateColoringInAllMaps(); + } + break; + } + } + + CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); + if (parcelScalarFile != NULL) { + CaretAssertToDoWarning(); +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { +// columnIndicesSet.insert(indx); +// } + } + + const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); + if (parcelLabelFile != NULL) { +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { +// columnIndicesSet.insert(indx); +// } + } + + CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); + if (scalarDataSeriesFile != NULL) { + CaretAssertToDoWarning(); + scalarDataSeriesFile->setSelectedMapIndex(tabIndex, + rowColumnIndex); +// const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(tabIndex); +// if (scalarDataSeriesMapIndex >= 0) { +// rowIndicesSet.insert(scalarDataSeriesMapIndex); +// } + } +} + /** * Save subclass data to the scene. * diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index c632c786e..9eae3d245 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -22,6 +22,7 @@ /*LICENSE_END*/ #include "ChartTwoMatrixContentTypeEnum.h" +#include "ChartTwoMatrixLoadingDimensionEnum.h" #include "ChartableTwoFileBaseChart.h" namespace caret { @@ -30,7 +31,8 @@ namespace caret { public: ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, - CaretMappableDataFile* parentCaretMappableDataFile); + CaretMappableDataFile* parentCaretMappableDataFile, + std::vector& validRowColumnSelectionDimensions); virtual ~ChartableTwoFileMatrixChart(); @@ -46,14 +48,24 @@ namespace caret { bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; + // ADD_NEW_METHODS_HERE - - - - - - protected: + ChartTwoMatrixLoadingDimensionEnum::Enum getSelectedRowColumnDimension() const; + + void setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension); + + void getValidRowColumnSelectionDimensions(std::vector& validRowColumnSelectionDimensionOut) const; + + void getSelectedRowColumnIndices(const int32_t tabIndex, + ChartTwoMatrixLoadingDimensionEnum::Enum& rowColumnDimensionOut, + std::vector& rowIndicesOut, + std::vector& columnIndicesOut) const; + + void setSelectedRowColumnIndex(const int32_t tabIndex, + const int32_t rowColumnIndex); + + protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; @@ -69,6 +81,10 @@ namespace caret { ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; + const std::vector m_validRowColumnSelectionDimensions; + + ChartTwoMatrixLoadingDimensionEnum::Enum m_rowColumnDimension; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/EventCaretMappableDataFileMapsViewedInOverlays.cxx b/src/Files/EventCaretMappableDataFileMapsViewedInOverlays.cxx similarity index 100% rename from src/Brain/EventCaretMappableDataFileMapsViewedInOverlays.cxx rename to src/Files/EventCaretMappableDataFileMapsViewedInOverlays.cxx diff --git a/src/Brain/EventCaretMappableDataFileMapsViewedInOverlays.h b/src/Files/EventCaretMappableDataFileMapsViewedInOverlays.h similarity index 100% rename from src/Brain/EventCaretMappableDataFileMapsViewedInOverlays.h rename to src/Files/EventCaretMappableDataFileMapsViewedInOverlays.h diff --git a/src/GuiQt/ChartOverlaySetViewController.cxx b/src/GuiQt/ChartOverlaySetViewController.cxx index 72ebe5ffe..4f9f03269 100644 --- a/src/GuiQt/ChartOverlaySetViewController.cxx +++ b/src/GuiQt/ChartOverlaySetViewController.cxx @@ -36,6 +36,7 @@ #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" +#include "ChartOverlay.h" #include "ChartOverlaySet.h" #include "ChartOverlayViewController.h" #include "EventGraphicsUpdateOneWindow.h" @@ -96,7 +97,6 @@ m_browserWindowIndex(browserWindowIndex) this, SLOT(processMoveOverlayDown(const int32_t))); } - if (orientation == Qt::Horizontal) { static const int COLUMN_ON = 0; static const int COLUMN_SETTINGS_EDIT = 1; @@ -126,8 +126,8 @@ m_browserWindowIndex(browserWindowIndex) QLabel* fileLabel = new QLabel("File"); QLabel* yokeLabel = new QLabel("Yoke"); QLabel* allMapsLabel = new QLabel("All"); - QLabel* mapIndexLabel = new QLabel("Map Index"); - QLabel* mapNameLabel = new QLabel("Map Name"); + m_mapRowOrColumnIndexLabel = new QLabel("Map Index"); + m_mapRowOrColumnNameLabel = new QLabel("Map Name"); int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); @@ -136,8 +136,8 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, row, COLUMN_YOKE, Qt::AlignHCenter); gridLayout->addWidget(allMapsLabel, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); - gridLayout->addWidget(mapIndexLabel, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); - gridLayout->addWidget(mapNameLabel, row, COLUMN_MAP_NAME, Qt::AlignHCenter); + gridLayout->addWidget(m_mapRowOrColumnIndexLabel, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); + gridLayout->addWidget(m_mapRowOrColumnNameLabel, row, COLUMN_MAP_NAME, Qt::AlignHCenter); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { row = gridLayout->rowCount(); @@ -150,10 +150,10 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_historyToolButton, row, COLUMN_HISTORY, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); - glg->addWidget(covc->m_mapYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); + glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); - glg->addWidget(covc->m_mapIndexSpinBox, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); - glg->addWidget(covc->m_mapNameComboBox, row, COLUMN_MAP_NAME); + glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); + glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, COLUMN_MAP_NAME); } } else { @@ -204,11 +204,11 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 3); row++; - glg->addWidget(covc->m_mapYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); + glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); // glg->addWidget(covc->m_historyToolButton, row, ROW_TWO_COLUMN_HISTORY, 1, 2, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 3, Qt::AlignRight); - glg->addWidget(covc->m_mapIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); - glg->addWidget(covc->m_mapNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); + glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); + glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); } } @@ -290,6 +290,29 @@ ChartOverlaySetViewController::updateViewController() CaretAssertVectorIndex(m_chartOverlayGridLayoutGroups, i); m_chartOverlayGridLayoutGroups[i]->setVisible(displayOverlay); } + + const ChartOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); + if (primaryOverlay != NULL) { + AString mapRowOrColumnName = "Map"; + switch (primaryOverlay->getChartDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + mapRowOrColumnName = "Row"; + break; + } + + if (m_mapRowOrColumnIndexLabel != NULL) { + m_mapRowOrColumnIndexLabel->setText(mapRowOrColumnName+ " Index"); + } + if (m_mapRowOrColumnNameLabel != NULL) { + m_mapRowOrColumnNameLabel->setText(mapRowOrColumnName + " Name"); + } + } } /** diff --git a/src/GuiQt/ChartOverlaySetViewController.h b/src/GuiQt/ChartOverlaySetViewController.h index 26b90e826..50b727d5b 100644 --- a/src/GuiQt/ChartOverlaySetViewController.h +++ b/src/GuiQt/ChartOverlaySetViewController.h @@ -26,6 +26,7 @@ #include "EventListenerInterface.h" +class QLabel; class QScrollArea; namespace caret { @@ -79,6 +80,10 @@ namespace caret { QScrollArea* m_scrollArea; + QLabel* m_mapRowOrColumnIndexLabel = NULL; + + QLabel* m_mapRowOrColumnNameLabel = NULL; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartOverlayViewController.cxx index e99266a00..c2977cdfc 100644 --- a/src/GuiQt/ChartOverlayViewController.cxx +++ b/src/GuiQt/ChartOverlayViewController.cxx @@ -40,6 +40,10 @@ using namespace caret; #include "AnnotationColorBar.h" #include "CaretMappableDataFile.h" #include "ChartOverlay.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" @@ -136,7 +140,7 @@ m_chartOverlay(NULL) m_colorBarToolButton = new QToolButton(); m_colorBarToolButton->setDefaultAction(m_colorBarAction); - /* + /* * Construction Tool Button */ QIcon constructionIcon; @@ -189,13 +193,13 @@ m_chartOverlay(NULL) "\n" "If the SAME FILE is in yoked in multiple overlays,\n" "the overlay enabled statuses are synchronized.\n"); - m_mapYokingGroupComboBox = new MapYokingGroupComboBox(this); - m_mapYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); - m_mapYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); + m_mapRowOrColumnYokingGroupComboBox = new MapYokingGroupComboBox(this); + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); #ifdef CARET_OS_MACOSX - m_mapYokingGroupComboBox->getWidget()->setFixedWidth(m_mapYokingGroupComboBox->getWidget()->sizeHint().width() - 20); + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setFixedWidth(m_mapRowOrColumnYokingGroupComboBox->getWidget()->sizeHint().width() - 20); #endif // CARET_OS_MACOSX - QObject::connect(m_mapYokingGroupComboBox, SIGNAL(itemActivated()), + QObject::connect(m_mapRowOrColumnYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokingGroupActivated())); /* @@ -210,23 +214,28 @@ m_chartOverlay(NULL) this, SLOT(allMapsCheckBoxClicked(bool))); /* - * Map Index Spin Box + * Map/Row/Column Index Spin Box */ - m_mapIndexSpinBox = WuQFactory::newSpinBox(); - QObject::connect(m_mapIndexSpinBox, SIGNAL(valueChanged(int)), - this, SLOT(mapIndexSpinBoxValueChanged(int))); - m_mapIndexSpinBox->setToolTip("Select map by its index"); + m_mapRowOrColumnIndexSpinBox = WuQFactory::newSpinBox(); + QObject::connect(m_mapRowOrColumnIndexSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(mapRowOrColumnIndexSpinBoxValueChanged(int))); + m_mapRowOrColumnIndexSpinBox->setToolTip("Select map/row/column by its index"); + m_mapRowOrColumnIndexSpinBox->setRange(0, 9999); // fix size for 4 digits + m_mapRowOrColumnIndexSpinBox->setFixedSize(m_mapRowOrColumnIndexSpinBox->sizeHint()); +// m_mapRowOrColumnIndexSpinBox->setSizePolicy(QSizePolicy::Fixed, +// QSizePolicy::Fixed); + m_mapRowOrColumnIndexSpinBox->setRange(0, 0); /* - * Map Name Combo Box + * Map/Row/Column Name Combo Box */ - m_mapNameComboBox = WuQFactory::newComboBox(); - m_mapNameComboBox->setMinimumWidth(minComboBoxWidth); - m_mapNameComboBox->setMaximumWidth(maxComboBoxWidth); - QObject::connect(m_mapNameComboBox, SIGNAL(activated(int)), - this, SLOT(mapNameComboBoxSelected(int))); - m_mapNameComboBox->setToolTip("Select map by its name"); - m_mapNameComboBox->setSizeAdjustPolicy(comboSizePolicy); + m_mapRowOrColumnNameComboBox = WuQFactory::newComboBox(); + m_mapRowOrColumnNameComboBox->setMinimumWidth(minComboBoxWidth); + m_mapRowOrColumnNameComboBox->setMaximumWidth(maxComboBoxWidth); + QObject::connect(m_mapRowOrColumnNameComboBox, SIGNAL(activated(int)), + this, SLOT(mapRowOrColumnNameComboBoxSelected(int))); + m_mapRowOrColumnNameComboBox->setToolTip("Select map/row/column by its name"); + m_mapRowOrColumnNameComboBox->setSizeAdjustPolicy(comboSizePolicy); } /** @@ -276,19 +285,20 @@ ChartOverlayViewController::fileComboBoxSelected(int indx) void* pointer = m_mapFileComboBox->itemData(indx).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; - m_chartOverlay->setSelectionData(file, 0); + m_chartOverlay->setSelectionData(file, -1); - validateYokingSelection(); + // DO NOT DO HERE validateYokingSelection(); //validateYokingSelection(overlay->getYokingGroup()); // not needed with call to validateYokingSelection: this->updateViewController(this->overlay); // called inside validateYokingSelection(); this->updateUserInterfaceAndGraphicsWindow(); - updateOverlaySettingsEditor(); updateViewController(m_chartOverlay); + m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateGraphicsWindow(); updateUserInterface(); + updateOverlaySettingsEditor(); // if (file != NULL) { // if (file->isVolumeMappable()) { @@ -306,7 +316,7 @@ ChartOverlayViewController::fileComboBoxSelected(int indx) * Index of selection. */ void -ChartOverlayViewController::mapIndexSpinBoxValueChanged(int indx) +ChartOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) { if (m_chartOverlay == NULL) { @@ -339,12 +349,12 @@ ChartOverlayViewController::mapIndexSpinBoxValueChanged(int indx) /* * Need to update map name combo box. */ - m_mapNameComboBox->blockSignals(true); + m_mapRowOrColumnNameComboBox->blockSignals(true); if ((overlayIndex >= 0) - && (overlayIndex < m_mapNameComboBox->count())) { - m_mapNameComboBox->setCurrentIndex(overlayIndex); + && (overlayIndex < m_mapRowOrColumnNameComboBox->count())) { + m_mapRowOrColumnNameComboBox->setCurrentIndex(overlayIndex); } - m_mapNameComboBox->blockSignals(false); + m_mapRowOrColumnNameComboBox->blockSignals(false); this->updateUserInterface(); this->updateGraphicsWindow(); @@ -358,7 +368,7 @@ ChartOverlayViewController::mapIndexSpinBoxValueChanged(int indx) * Index of selection. */ void -ChartOverlayViewController::mapNameComboBoxSelected(int indx) +ChartOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) { if (m_chartOverlay == NULL) { return; @@ -386,9 +396,9 @@ ChartOverlayViewController::mapNameComboBoxSelected(int indx) * Need to update map index spin box. * Note that the map index spin box ranges [1, N]. */ - m_mapIndexSpinBox->blockSignals(true); - m_mapIndexSpinBox->setValue(indx + 1); - m_mapIndexSpinBox->blockSignals(false); + m_mapRowOrColumnIndexSpinBox->blockSignals(true); + m_mapRowOrColumnIndexSpinBox->setValue(indx); + m_mapRowOrColumnIndexSpinBox->blockSignals(false); this->updateUserInterface(); this->updateGraphicsWindow(); @@ -468,7 +478,7 @@ ChartOverlayViewController::allMapsCheckBoxClicked(bool status) void ChartOverlayViewController::validateYokingSelection() { - m_mapYokingGroupComboBox->validateYokingChange(m_chartOverlay); + m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateViewController(m_chartOverlay); updateGraphicsWindow(); //EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); @@ -480,7 +490,7 @@ ChartOverlayViewController::validateYokingSelection() void ChartOverlayViewController::yokingGroupActivated() { - MapYokingGroupEnum::Enum yokingGroup = m_mapYokingGroupComboBox->getMapYokingGroup(); + MapYokingGroupEnum::Enum yokingGroup = m_mapRowOrColumnYokingGroupComboBox->getMapYokingGroup(); /* * Has yoking group changed? @@ -531,6 +541,9 @@ ChartOverlayViewController::historyActionTriggered(bool) m_chartOverlay->getSelectionData(mapFile, mapIndex); + std::cout << "History button clicked. Enabled=" + << qPrintable(AString::fromBool(m_chartOverlay->isHistorySupported())) << std::endl; + CaretAssertToDoWarning(); // if (mapFile != NULL) { // EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, @@ -553,46 +566,54 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) { m_chartOverlay = chartOverlay; - m_mapFileComboBox->clear(); /* * Get the selection information for the overlay. */ std::vector dataFiles; CaretMappableDataFile* selectedFile = NULL; - //AString selectedMapUniqueID = ""; + std::vector selectedFileMapNames; int32_t selectedMapIndex = -1; - bool enableMapSelectionControlsFlag = false; - if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(dataFiles, - selectedFile, - //selectedMapUniqueID, - selectedMapIndex); - - const ChartTwoDataTypeEnum::Enum chartDataType = m_chartOverlay->getChartDataType(); - switch (chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - enableMapSelectionControlsFlag = true; - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - break; - } - + selectedFile, + selectedFileMapNames, + selectedMapIndex); } + /* + * Setup names of file for display in combo box + */ std::vector displayNames; FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(dataFiles, displayNames); CaretAssert(dataFiles.size() == displayNames.size()); + /* + * Update tooltips with full path to file and name of map + * as names may be too long to fit into combo boxes + */ + AString fileComboBoxToolTip("Select file for this overlay"); + AString nameComboBoxToolTip("Select map by its name"); + if (selectedFile != NULL) { + FileInformation fileInfo(selectedFile->getFileName()); + fileComboBoxToolTip.append(":\n" + + fileInfo.getFileName() + + "\n" + + fileInfo.getPathName() + + "\n\n" + + "Copy File Name/Path to Clipboard with Construction Menu"); + + nameComboBoxToolTip.append(":\n" + + m_mapRowOrColumnNameComboBox->currentText()); + } + m_mapFileComboBox->setToolTip(fileComboBoxToolTip); + m_mapRowOrColumnNameComboBox->setToolTip(nameComboBoxToolTip); + /* * Load the file selection combo box. */ + m_mapFileComboBox->clear(); int32_t selectedFileIndex = -1; const int32_t numFiles = static_cast(dataFiles.size()); for (int32_t i = 0; i < numFiles; i++) { @@ -611,134 +632,108 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) } /* - * Load the map selection combo box + * Load the map name selection combo box and map index spin box */ - int32_t numberOfMaps = 0; - m_mapNameComboBox->blockSignals(true); - m_mapNameComboBox->clear(); - if (enableMapSelectionControlsFlag) { - if (selectedFile != NULL) { - numberOfMaps = selectedFile->getNumberOfMaps(); - for (int32_t i = 0; i < numberOfMaps; i++) { - m_mapNameComboBox->addItem(selectedFile->getMapName(i)); - } - m_mapNameComboBox->setCurrentIndex(selectedMapIndex); + m_mapRowOrColumnNameComboBox->setEnabled(false); + m_mapRowOrColumnNameComboBox->blockSignals(true); + m_mapRowOrColumnNameComboBox->clear(); + m_mapRowOrColumnIndexSpinBox->setEnabled(false); + m_mapRowOrColumnIndexSpinBox->blockSignals(true); + m_mapRowOrColumnIndexSpinBox->setRange(0, 0); + m_mapRowOrColumnIndexSpinBox->setValue(0); + const int32_t numberOfMaps = static_cast(selectedFileMapNames.size()); + if (numberOfMaps > 0) { + m_mapRowOrColumnNameComboBox->setEnabled(true); + m_mapRowOrColumnIndexSpinBox->setEnabled(true); + + for (int32_t i = 0; i < numberOfMaps; i++) { + CaretAssertVectorIndex(selectedFileMapNames, i); + m_mapRowOrColumnNameComboBox->addItem(selectedFileMapNames[i]); } + m_mapRowOrColumnNameComboBox->setCurrentIndex(selectedMapIndex); + m_mapRowOrColumnIndexSpinBox->setRange(0, numberOfMaps - 1); + m_mapRowOrColumnIndexSpinBox->setValue(selectedMapIndex); } - m_mapNameComboBox->blockSignals(false); + m_mapRowOrColumnNameComboBox->blockSignals(false); + m_mapRowOrColumnIndexSpinBox->blockSignals(false); + + const bool validOverlayAndFileFlag = ((m_chartOverlay != NULL) + && (selectedFile != NULL)); /* - * Load the map index spin box that ranges [1, N]. + * Update enabled checkbox */ - m_mapIndexSpinBox->blockSignals(true); - if (enableMapSelectionControlsFlag) { - m_mapIndexSpinBox->setRange(1, numberOfMaps); - if (selectedFile != NULL) { - m_mapIndexSpinBox->setValue(selectedMapIndex + 1); + m_enabledCheckBox->setEnabled(false); + m_enabledCheckBox->setChecked(false); + if (validOverlayAndFileFlag) { + /* + * First overlay is ALWAYS ENABLED and HIDDEN + */ + if (m_chartOverlayIndex == 0) { + m_enabledCheckBox->setVisible(false); + } + else { + m_enabledCheckBox->setEnabled(true); + m_enabledCheckBox->setChecked(m_chartOverlay->isEnabled()); } } - else { - m_mapIndexSpinBox->setRange(0, 0); - m_mapIndexSpinBox->setValue(0); - } - m_mapIndexSpinBox->blockSignals(false); + /* - * Update enable check box + * Update yoking */ - Qt::CheckState enabledCheckState = Qt::Unchecked; - bool allMapsCheckedFlag = false; - MapYokingGroupEnum::Enum mapYoking = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; - if (m_chartOverlay != NULL) { - if (m_chartOverlay->isEnabled()) { - enabledCheckState = Qt::Checked; + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(false); + m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); + if (validOverlayAndFileFlag) { + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(true); + if (m_chartOverlay->isMapYokingSupported()) { + m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(m_chartOverlay->getMapYokingGroup()); } - allMapsCheckedFlag = m_chartOverlay->isAllMapsSelected(); - mapYoking = m_chartOverlay->getMapYokingGroup(); } - m_enabledCheckBox->setCheckState(enabledCheckState); - - m_mapYokingGroupComboBox->setMapYokingGroup(mapYoking); - - m_allMapsCheckBox->setChecked(allMapsCheckedFlag); - - m_colorBarAction->blockSignals(true); - m_colorBarAction->setChecked(m_chartOverlay->getColorBar()->isDisplayed()); - m_colorBarAction->blockSignals(false); - - const bool haveFile = (selectedFile != NULL); - bool haveMultipleMaps = false; - bool dataIsMappedWithPalette = false; - bool dataIsMappedWithLabelTable = false; - bool dataIsMappedWithRGBA = false; - bool haveOpacity = false; - if (haveFile) { - dataIsMappedWithPalette = selectedFile->isMappedWithPalette(); - dataIsMappedWithLabelTable = selectedFile->isMappedWithLabelTable(); - dataIsMappedWithRGBA = selectedFile->isMappedWithRGBA(); - haveMultipleMaps = (selectedFile->getNumberOfMaps() > 1); - haveOpacity = (dataIsMappedWithLabelTable - || dataIsMappedWithPalette - || dataIsMappedWithRGBA); - } - - /** - * Yoking is enabled when either: - * (1) The file maps to both surface and volumes - * (2) The file has multiple maps. + /* + * Update all maps */ - bool haveYoking = false; - if (haveFile) { - if (selectedFile->isSurfaceMappable() - && selectedFile->isVolumeMappable()) { - haveYoking = true; - } - if (haveMultipleMaps) { - haveYoking = true; + m_allMapsCheckBox->setEnabled(false); + m_allMapsCheckBox->setChecked(false); + if (validOverlayAndFileFlag) { + m_allMapsCheckBox->setEnabled(m_chartOverlay->isAllMapsSupported()); + if (m_chartOverlay->isAllMapsSupported()) { + m_allMapsCheckBox->setChecked(m_chartOverlay->isAllMapsSelected()); } } /* - * Update tooltips with full path to file and name of map - * as names may be too long to fit into combo boxes + * Update settings (wrench) button */ - AString fileComboBoxToolTip("Select file for this overlay"); - AString nameComboBoxToolTip("Select map by its name"); - if (selectedFile != NULL) { - FileInformation fileInfo(selectedFile->getFileName()); - fileComboBoxToolTip.append(":\n" - + fileInfo.getFileName() - + "\n" - + fileInfo.getPathName() - + "\n\n" - + "Copy File Name/Path to Clipboard with Construction Menu"); - - nameComboBoxToolTip.append(":\n" - + m_mapNameComboBox->currentText()); + m_settingsAction->setEnabled(validOverlayAndFileFlag); + + /* + * Update color bar button + */ + m_colorBarAction->blockSignals(true); + m_colorBarAction->setEnabled(false); + m_colorBarAction->setChecked(false); + if (validOverlayAndFileFlag) { + if (selectedFile->isMappedWithPalette()) { + m_colorBarAction->setEnabled(true); + m_colorBarAction->setChecked(m_chartOverlay->getColorBar()->isDisplayed()); + } } - m_mapFileComboBox->setToolTip(fileComboBoxToolTip); - m_mapNameComboBox->setToolTip(nameComboBoxToolTip); + m_colorBarAction->blockSignals(false); /* - * Make sure items are enabled at the appropriate time - * Note: First overlay is ALWAYS on enabled checkbox is not selectable by user + * Update construction button */ - m_enabledCheckBox->setEnabled(haveFile - && (m_chartOverlayIndex > 0)); - m_enabledCheckBox->setVisible(m_chartOverlayIndex > 0); - m_settingsAction->setEnabled(true); - m_colorBarAction->setEnabled(dataIsMappedWithPalette); m_constructionAction->setEnabled(true); - m_historyAction->setEnabled(haveMultipleMaps); - m_mapFileComboBox->setEnabled(haveFile); - m_mapYokingGroupComboBox->getWidget()->setEnabled(haveYoking); - m_allMapsCheckBox->setEnabled(haveMultipleMaps - && enableMapSelectionControlsFlag); - m_mapIndexSpinBox->setEnabled(haveMultipleMaps - && enableMapSelectionControlsFlag); - m_mapNameComboBox->setEnabled(haveFile - && enableMapSelectionControlsFlag); + + /* + * Update history button + */ + m_historyAction->setEnabled(false); + if (validOverlayAndFileFlag) { + m_historyAction->setEnabled(m_chartOverlay->isHistorySupported()); + } } /** @@ -757,12 +752,12 @@ ChartOverlayViewController::updateUserInterfaceAndGraphicsWindow() void ChartOverlayViewController::updateUserInterface() { - if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { +// if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); - } - else { - EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).getPointer()); - } +// } +// else { +// EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).getPointer()); +// } } /** @@ -771,12 +766,12 @@ ChartOverlayViewController::updateUserInterface() void ChartOverlayViewController::updateGraphicsWindow() { - if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { +// if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } - else { - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); - } +// } +// else { +// EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); +// } } /** @@ -1046,13 +1041,7 @@ ChartOverlayViewController::createHistoryPixmap(QWidget* widget) painter->drawLine(QPointF(centerX, centerY), QPointF(centerY, twelveOClockY)); -// painter->drawLine(QLineF(xStart, -// y, -// xEnd, -// y)); - return pixmap; - } diff --git a/src/GuiQt/ChartOverlayViewController.h b/src/GuiQt/ChartOverlayViewController.h index 01fb14563..daf578fa3 100644 --- a/src/GuiQt/ChartOverlayViewController.h +++ b/src/GuiQt/ChartOverlayViewController.h @@ -67,9 +67,9 @@ namespace caret { private slots: void fileComboBoxSelected(int); - void mapNameComboBoxSelected(int); + void mapRowOrColumnNameComboBoxSelected(int); - void mapIndexSpinBoxValueChanged(int); + void mapRowOrColumnIndexSpinBoxValueChanged(int); void enabledCheckBoxClicked(bool); @@ -144,13 +144,13 @@ namespace caret { QComboBox* m_mapFileComboBox; - MapYokingGroupComboBox* m_mapYokingGroupComboBox; + MapYokingGroupComboBox* m_mapRowOrColumnYokingGroupComboBox; QCheckBox* m_allMapsCheckBox; - QSpinBox* m_mapIndexSpinBox; + QSpinBox* m_mapRowOrColumnIndexSpinBox; - QComboBox* m_mapNameComboBox; + QComboBox* m_mapRowOrColumnNameComboBox; QToolButton* m_constructionToolButton; -- GitLab From 60f10853d413f1c9f0dfd388488b30a5d32af411 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 27 Jan 2017 12:37:00 -0600 Subject: [PATCH 189/755] Continuing charting development. Matrix viewing including selection of full, upper half, lower half matrix view is functional using the 'matrix triangular' button in the chart overlay toolbox. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 292 ++++++++++++++++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 38 ++- src/Brain/ChartOverlay.cxx | 47 +++ src/Brain/ChartOverlay.h | 8 + src/Charting/CMakeLists.txt | 4 +- ...artTwoMatrixTriangularViewingModeEnum.cxx} | 108 +++---- ...ChartTwoMatrixTriangularViewingModeEnum.h} | 26 +- src/GuiQt/ChartOverlaySetViewController.cxx | 26 +- src/GuiQt/ChartOverlayViewController.cxx | 201 +++++++++++- src/GuiQt/ChartOverlayViewController.h | 17 + 10 files changed, 639 insertions(+), 128 deletions(-) rename src/Charting/{ChartTwoMatrixViewingTypeEnum.cxx => ChartTwoMatrixTriangularViewingModeEnum.cxx} (63%) rename src/Charting/{ChartTwoMatrixViewingTypeEnum.h => ChartTwoMatrixTriangularViewingModeEnum.h} (75%) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index cf9765072..ae2c3caa2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -37,13 +37,6 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" -//#include "CiftiParcelLabelFile.h" -//#include "CiftiParcelScalarFile.h" -//#include "CiftiScalarDataSeriesFile.h" -//#include "ConnectivityDataLoaded.h" -//#include "EventCaretMappableDataFileMapsViewedInOverlays.h" -//#include "EventManager.h" - #include "IdentificationWithColor.h" #include "SessionManager.h" @@ -164,6 +157,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + drawHistogramChart(); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; @@ -185,6 +179,233 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); } +/** + * Draw histogram charts. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() +{ + /* + * Check for a 'selection' type mode + */ + m_identificationModeFlag = false; + switch (m_fixedPipelineDrawing->mode) { + case BrainOpenGLFixedPipeline::MODE_DRAWING: + break; + case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: +// if (chartDataSeriesID->isEnabledForSelection() +// || chartFrequencySeriesID->isEnabledForSelection() +// || chartTimeSeriesID->isEnabledForSelection()) { +// m_identificationModeFlag = true; +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// else { + CaretAssertToDoWarning(); + return; +// } + break; + case BrainOpenGLFixedPipeline::MODE_PROJECTION: + return; + break; + } + + saveStateOfOpenGL(); + + resetIdentification(); + + const int32_t vpX = m_viewport[0]; + const int32_t vpY = m_viewport[1]; + const int32_t vpWidth = m_viewport[2]; + const int32_t vpHeight = m_viewport[3]; + + int32_t chartGraphicsDrawingViewport[4] = { + vpX, + vpY, + vpWidth, + vpHeight + }; + + +// /* +// * Margin is region around the chart in which +// * the axes legends, values, and ticks are drawn. +// */ + const double marginSize = 30; + Margins margins(marginSize); +// +// double width, height; +// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); +// margins.m_left = std::max(margins.m_left, width); +// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); +// margins.m_right = std::max(margins.m_right, width); +// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); +// margins.m_top = std::max(margins.m_top, height); +// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); +// margins.m_bottom = std::max(margins.m_bottom, height); +// +// if (margins.m_left > marginSize) margins.m_left += 10; +// if (margins.m_right > marginSize) margins.m_right += 10; +// +// /* +// * Ensure that there is sufficient space for the axes data display. +// */ +// if ((vpWidth > (marginSize * 3)) +// && (vpHeight > (marginSize * 3))) { +// +// /* Draw legends and grids */ +// drawChartAxis(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// textRenderer, +// cartesianChart->getLeftAxis()); +// +// drawChartAxis(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// textRenderer, +// cartesianChart->getRightAxis()); +// +// drawChartAxis(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// textRenderer, +// cartesianChart->getBottomAxis()); +// +// drawChartAxis(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// textRenderer, +// cartesianChart->getTopAxis()); +// +// +// drawChartGraphicsBoxAndSetViewport(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// chartGraphicsDrawingViewport); +// } + + glViewport(chartGraphicsDrawingViewport[0], + chartGraphicsDrawingViewport[1], + chartGraphicsDrawingViewport[2], + chartGraphicsDrawingViewport[3]); + + + const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); + CaretAssert(numberOfOverlays > 0); + const ChartOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); + CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + + /* + * Get extent of histogram data + */ + CaretAssertToDoWarning(); // extent of all displayed histograms + float xMin = 0.0; + float xMax = 100.0; + float yMin = 0.0; + float yMax = 100.0; + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { + ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + if ( ! chartOverlay->isEnabled()) { + continue; + } + + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = 1; + chartOverlay->getSelectionData(mapFile, + mapIndex); + if (mapFile == NULL) { + continue; + } + + const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + if (histogramChart->isValid()) { + } + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(xMin, xMax, + yMin, yMax, + -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = true; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { + ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + if ( ! chartOverlay->isEnabled()) { + continue; + } + + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = 1; + chartOverlay->getSelectionData(mapFile, + mapIndex); + if (mapFile == NULL) { + continue; + } + + const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + if (histogramChart->isValid()) { + drawHistogramChartContent(histogramChart); + } + } + + /* + * Process selection + */ + if (m_identificationModeFlag) { + processIdentification(); + } + + restoreStateOfOpenGL(); + +} + +/* + * Draw the given histogram chart. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart) +{ + std::cout << "DRAW HISTOGRAM" << std::endl; +} + + /** * Draw a matrix chart. */ @@ -304,15 +525,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() 0.0); } - /* - * For testing - */ - glColor3f(1.0, 0.0, 0.0); - glBegin(GL_LINES); - glVertex2f(xMin, yMin); - glVertex2f(xMax, yMax); - glEnd(); - for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -339,10 +551,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() if ((overlayRows == numberOfRows) && (overlayColumns == numberOfCols)) { drawMatrixChartContent(matrixChart, - ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL, - //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL, - //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL, - //ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL, + chartOverlay->getMatrixTriangularViewingMode(), + //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL, + //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL, + //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL, + //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL, cellWidth, cellHeight, m_zooming); @@ -422,7 +635,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, - const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, + const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, const float zooming) @@ -436,6 +649,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT CaretLogWarning("Matrix RGBA invalid"); return; } + if ((numberOfRows <= 0) + || (numberOfColumns <= 0)) { + return; + } CaretAssertToDoWarning(); // need to set these bool displayGridLinesFlag = false; @@ -478,23 +695,23 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rgbaOffset += 4; bool drawCellFlag = true; - if (chartViewingType != ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL) { + if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { if (numberOfRows == numberOfColumns) { drawCellFlag = false; switch (chartViewingType) { - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: if (rowIndex != columnIndex) { drawCellFlag = true; } break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: if (rowIndex > columnIndex) { drawCellFlag = true; } break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: if (rowIndex < columnIndex) { drawCellFlag = true; } @@ -502,15 +719,28 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } } else { - drawCellFlag = true; + drawCellFlag = false; + const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); + const int32_t diagonalRow = static_cast(slope * columnIndex); + switch (chartViewingType) { - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + drawCellFlag = true; break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != diagonalRow) { + drawCellFlag = true; + } break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > diagonalRow) { + drawCellFlag = true; + } break; - case ChartTwoMatrixViewingTypeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < diagonalRow) { + drawCellFlag = true; + } break; } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 49c45d36d..ca06ed965 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -23,11 +23,13 @@ #include #include "BrainOpenGLChartTwoDrawingInterface.h" -#include "ChartTwoMatrixViewingTypeEnum.h" +#include "ChartTwoMatrixTriangularViewingModeEnum.h" namespace caret { class CaretPreferences; + class ChartableTwoFileHistogramChart; + class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { @@ -50,20 +52,20 @@ namespace caret { // ADD_NEW_METHODS_HERE private: -// class Margins { -// public: -// Margins(const double defaultSize) { -// m_bottom = defaultSize; -// m_left = defaultSize; -// m_right = defaultSize; -// m_top = defaultSize; -// } -// -// double m_bottom; -// double m_left; -// double m_right; -// double m_top; -// }; + class Margins { + public: + Margins(const double defaultSize) { + m_bottom = defaultSize; + m_left = defaultSize; + m_right = defaultSize; + m_top = defaultSize; + } + + double m_bottom; + double m_left; + double m_right; + double m_top; + }; BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); @@ -83,10 +85,14 @@ namespace caret { void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, - const ChartTwoMatrixViewingTypeEnum::Enum chartViewingType, + const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, const float zooming); + + void drawHistogramChart(); + + void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart); // void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, // std::set& rowIndicesOut, diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartOverlay.cxx index b5159e58a..7d6635e86 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartOverlay.cxx @@ -76,6 +76,8 @@ m_overlayIndex(overlayIndex) m_colorBar = std::unique_ptr(new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL)); m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); + m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; + m_selectedMapFile = NULL; m_selectedHistogramMapIndex = -1; m_allHistogramMapsSelectedFlag = false; @@ -85,6 +87,9 @@ m_overlayIndex(overlayIndex) m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar.get()); + m_sceneAssistant->add("m_matrixTriangularViewingMode", + &m_matrixTriangularViewingMode); + m_sceneAssistant->add("m_selectedHistogramMapIndex", &m_selectedHistogramMapIndex); m_sceneAssistant->add("m_allHistogramMapsSelectedFlag", &m_allHistogramMapsSelectedFlag); // EventManager::get()->addEventListener(this, @@ -274,6 +279,7 @@ ChartOverlay::copyData(const ChartOverlay* overlay) m_mapYokingGroup = overlay->m_mapYokingGroup; *m_colorBar = *overlay->m_colorBar; + m_matrixTriangularViewingMode = overlay->m_matrixTriangularViewingMode; m_selectedMapFile = overlay->m_selectedMapFile; m_selectedHistogramMapIndex = overlay->m_selectedHistogramMapIndex; @@ -1030,6 +1036,47 @@ ChartOverlay::setAllMapsSelected(const bool status) m_allHistogramMapsSelectedFlag = status; } +/** + * @return The matrix triangular viewing mode. + */ +ChartTwoMatrixTriangularViewingModeEnum::Enum +ChartOverlay::getMatrixTriangularViewingMode() const +{ + return m_matrixTriangularViewingMode; +} + +/** + * Set the matrix triangular viewing mode. + * + * @param mode + * New triangular viewing mode. + */ +void +ChartOverlay::setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode) +{ + m_matrixTriangularViewingMode = mode; +} + +/** + * @return Is the matrix triangular view mode supported? + */ +bool +ChartOverlay::isMatrixTriangularViewingModeSupported() const +{ + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + return true; + break; + } + + return false; +} /** * Save information specific to this type of model to the scene. diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartOverlay.h index 167386f6c..e9b1fbbf6 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartOverlay.h @@ -25,6 +25,7 @@ #include "CaretObject.h" #include "ChartTwoCompoundDataType.h" +#include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "SceneableInterface.h" @@ -78,6 +79,12 @@ namespace caret { const AnnotationColorBar* getColorBar() const; + ChartTwoMatrixTriangularViewingModeEnum::Enum getMatrixTriangularViewingMode() const; + + void setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode); + + bool isMatrixTriangularViewingModeSupported() const; + void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, @@ -163,6 +170,7 @@ namespace caret { bool m_allHistogramMapsSelectedFlag = false; + ChartTwoMatrixTriangularViewingModeEnum::Enum m_matrixTriangularViewingMode; // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 7d01c5539..633db68c4 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -47,7 +47,7 @@ ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixLoadingDimensionEnum.h -ChartTwoMatrixViewingTypeEnum.h +ChartTwoMatrixTriangularViewingModeEnum.h ChartAxis.cxx ChartAxisCartesian.cxx @@ -81,7 +81,7 @@ ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixLoadingDimensionEnum.cxx -ChartTwoMatrixViewingTypeEnum.cxx +ChartTwoMatrixTriangularViewingModeEnum.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) diff --git a/src/Charting/ChartTwoMatrixViewingTypeEnum.cxx b/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.cxx similarity index 63% rename from src/Charting/ChartTwoMatrixViewingTypeEnum.cxx rename to src/Charting/ChartTwoMatrixTriangularViewingModeEnum.cxx index 24f0a5944..0f91af4d7 100644 --- a/src/Charting/ChartTwoMatrixViewingTypeEnum.cxx +++ b/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.cxx @@ -21,9 +21,9 @@ #include -#define __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ -#include "ChartTwoMatrixViewingTypeEnum.h" -#undef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +#define __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ +#include "ChartTwoMatrixTriangularViewingModeEnum.h" +#undef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -31,7 +31,7 @@ using namespace caret; /** - * \class caret::ChartTwoMatrixViewingTypeEnum + * \class caret::ChartTwoMatrixTriangularViewingModeEnum * \brief Types of viewing for matrix. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate @@ -50,21 +50,21 @@ using namespace caret; * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "ChartTwoMatrixViewingTypeEnum.h" + * #include "ChartTwoMatrixTriangularViewingModeEnum.h" * * Instatiate: * m_matrixViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_matrixViewingTypeEnumComboBox->setup(); + * m_matrixViewingTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_matrixViewingTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(matrixViewingTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const ChartTwoMatrixViewingTypeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); + * const ChartTwoMatrixTriangularViewingModeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); * */ @@ -79,7 +79,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -ChartTwoMatrixViewingTypeEnum::ChartTwoMatrixViewingTypeEnum(const Enum enumValue, +ChartTwoMatrixTriangularViewingModeEnum::ChartTwoMatrixTriangularViewingModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -92,7 +92,7 @@ ChartTwoMatrixViewingTypeEnum::ChartTwoMatrixViewingTypeEnum(const Enum enumValu /** * Destructor. */ -ChartTwoMatrixViewingTypeEnum::~ChartTwoMatrixViewingTypeEnum() +ChartTwoMatrixTriangularViewingModeEnum::~ChartTwoMatrixTriangularViewingModeEnum() { } @@ -100,28 +100,28 @@ ChartTwoMatrixViewingTypeEnum::~ChartTwoMatrixViewingTypeEnum() * Initialize the enumerated metadata. */ void -ChartTwoMatrixViewingTypeEnum::initialize() +ChartTwoMatrixTriangularViewingModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_FULL, + enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_FULL, "MATRIX_VIEW_FULL", - "Matrix View Full")); + "Full")); - enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, "MATRIX_VIEW_FULL_NO_DIAGONAL", - "Matrix View Full No Diagonal")); + "Full No Diagonal")); - enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, "MATRIX_VIEW_LOWER_NO_DIAGONAL", - "Matrix View Lower No Diagonal")); + "Lower No Diagonal")); - enumData.push_back(ChartTwoMatrixViewingTypeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, + enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, "MATRIX_VIEW_UPPER_NO_DIAGONAL", - "Matrix View Upper No Diagonal")); + "Upper No Diagonal")); } /** @@ -131,14 +131,14 @@ ChartTwoMatrixViewingTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const ChartTwoMatrixViewingTypeEnum* -ChartTwoMatrixViewingTypeEnum::findData(const Enum enumValue) +const ChartTwoMatrixTriangularViewingModeEnum* +ChartTwoMatrixTriangularViewingModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const ChartTwoMatrixViewingTypeEnum* d = &enumData[i]; + const ChartTwoMatrixTriangularViewingModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -155,10 +155,10 @@ ChartTwoMatrixViewingTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -ChartTwoMatrixViewingTypeEnum::toName(Enum enumValue) { +ChartTwoMatrixTriangularViewingModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -172,18 +172,18 @@ ChartTwoMatrixViewingTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -ChartTwoMatrixViewingTypeEnum::Enum -ChartTwoMatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) +ChartTwoMatrixTriangularViewingModeEnum::Enum +ChartTwoMatrixTriangularViewingModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoMatrixViewingTypeEnum& d = *iter; + const ChartTwoMatrixTriangularViewingModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -195,7 +195,7 @@ ChartTwoMatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } @@ -208,10 +208,10 @@ ChartTwoMatrixViewingTypeEnum::fromName(const AString& name, bool* isValidOut) * String representing enumerated value. */ AString -ChartTwoMatrixViewingTypeEnum::toGuiName(Enum enumValue) { +ChartTwoMatrixTriangularViewingModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -225,18 +225,18 @@ ChartTwoMatrixViewingTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -ChartTwoMatrixViewingTypeEnum::Enum -ChartTwoMatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +ChartTwoMatrixTriangularViewingModeEnum::Enum +ChartTwoMatrixTriangularViewingModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoMatrixViewingTypeEnum& d = *iter; + const ChartTwoMatrixTriangularViewingModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -248,7 +248,7 @@ ChartTwoMatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValid *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } @@ -260,10 +260,10 @@ ChartTwoMatrixViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValid * Integer code for data type. */ int32_t -ChartTwoMatrixViewingTypeEnum::toIntegerCode(Enum enumValue) +ChartTwoMatrixTriangularViewingModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoMatrixViewingTypeEnum* enumInstance = findData(enumValue); + const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -278,18 +278,18 @@ ChartTwoMatrixViewingTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -ChartTwoMatrixViewingTypeEnum::Enum -ChartTwoMatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +ChartTwoMatrixTriangularViewingModeEnum::Enum +ChartTwoMatrixTriangularViewingModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoMatrixViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoMatrixViewingTypeEnum& enumInstance = *iter; + const ChartTwoMatrixTriangularViewingModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -301,7 +301,7 @@ ChartTwoMatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixViewingTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } @@ -314,13 +314,13 @@ ChartTwoMatrixViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* * A vector that is OUTPUT containing all of the enumerated values. */ void -ChartTwoMatrixViewingTypeEnum::getAllEnums(std::vector& allEnums) +ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -336,16 +336,16 @@ ChartTwoMatrixViewingTypeEnum::getAllEnums(std::vector& allNames, const bool isSorted) +ChartTwoMatrixTriangularViewingModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(ChartTwoMatrixViewingTypeEnum::toName(iter->enumValue)); + allNames.push_back(ChartTwoMatrixTriangularViewingModeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -362,16 +362,16 @@ ChartTwoMatrixViewingTypeEnum::getAllNames(std::vector& allNames, const * If true, the names are sorted in alphabetical order. */ void -ChartTwoMatrixViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +ChartTwoMatrixTriangularViewingModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(ChartTwoMatrixViewingTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(ChartTwoMatrixTriangularViewingModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Charting/ChartTwoMatrixViewingTypeEnum.h b/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.h similarity index 75% rename from src/Charting/ChartTwoMatrixViewingTypeEnum.h rename to src/Charting/ChartTwoMatrixTriangularViewingModeEnum.h index 34a4a90c4..ae942295f 100644 --- a/src/Charting/ChartTwoMatrixViewingTypeEnum.h +++ b/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.h @@ -1,5 +1,5 @@ -#ifndef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ -#define __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ +#ifndef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ +#define __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class ChartTwoMatrixViewingTypeEnum { +class ChartTwoMatrixTriangularViewingModeEnum { public: /** @@ -45,7 +45,7 @@ public: MATRIX_VIEW_UPPER_NO_DIAGONAL }; - ~ChartTwoMatrixViewingTypeEnum(); + ~ChartTwoMatrixTriangularViewingModeEnum(); static AString toName(Enum enumValue); @@ -66,14 +66,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - ChartTwoMatrixViewingTypeEnum(const Enum enumValue, + ChartTwoMatrixTriangularViewingModeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const ChartTwoMatrixViewingTypeEnum* findData(const Enum enumValue); + static const ChartTwoMatrixTriangularViewingModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -97,11 +97,11 @@ private: AString guiName; }; -#ifdef __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ -std::vector ChartTwoMatrixViewingTypeEnum::enumData; -bool ChartTwoMatrixViewingTypeEnum::initializedFlag = false; -int32_t ChartTwoMatrixViewingTypeEnum::integerCodeCounter = 0; -#endif // __CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_DECLARE__ +#ifdef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ +std::vector ChartTwoMatrixTriangularViewingModeEnum::enumData; +bool ChartTwoMatrixTriangularViewingModeEnum::initializedFlag = false; +int32_t ChartTwoMatrixTriangularViewingModeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ } // namespace -#endif //__CHART_TWO_MATRIX_VIEWING_TYPE_ENUM_H__ +#endif //__CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ diff --git a/src/GuiQt/ChartOverlaySetViewController.cxx b/src/GuiQt/ChartOverlaySetViewController.cxx index 4f9f03269..b203deee5 100644 --- a/src/GuiQt/ChartOverlaySetViewController.cxx +++ b/src/GuiQt/ChartOverlaySetViewController.cxx @@ -103,17 +103,19 @@ m_browserWindowIndex(browserWindowIndex) static const int COLUMN_SETTINGS_COLOR_BAR = 2; static const int COLUMN_SETTINGS_CONSTRUCTION = 3; static const int COLUMN_HISTORY = 4; - static const int COLUMN_FILE = 5; - static const int COLUMN_YOKE = 6; - static const int COLUMN_MAP_INDEX = 7; - static const int COLUMN_ALL_MAPS = 8; - static const int COLUMN_MAP_NAME = 9; + static const int COLUMN_MATRIX_VIEW = 5; + static const int COLUMN_FILE = 6; + static const int COLUMN_YOKE = 7; + static const int COLUMN_MAP_INDEX = 8; + static const int COLUMN_ALL_MAPS = 9; + static const int COLUMN_MAP_NAME = 10; gridLayout->setColumnStretch(COLUMN_ON, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_COLOR_BAR, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); gridLayout->setColumnStretch(COLUMN_HISTORY, 0); + gridLayout->setColumnStretch(COLUMN_MATRIX_VIEW, 0); gridLayout->setColumnStretch(COLUMN_FILE, 100); gridLayout->setColumnStretch(COLUMN_YOKE, 0); gridLayout->setColumnStretch(COLUMN_ALL_MAPS, 0); @@ -149,6 +151,7 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_colorBarToolButton, row, COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_historyToolButton, row, COLUMN_HISTORY, Qt::AlignHCenter); + glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, COLUMN_MATRIX_VIEW, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); @@ -162,8 +165,9 @@ m_browserWindowIndex(browserWindowIndex) static const int ROW_ONE_COLUMN_SETTINGS_COLOR_BAR = 2; static const int ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION = 3; static const int ROW_ONE_COLUMN_HISTORY = 4; - static const int ROW_ONE_COLUMN_FILE_LABEL = 5; - static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 6; + static const int ROW_ONE_COLUMN_MATRIX_VIEW = 5; + static const int ROW_ONE_COLUMN_FILE_LABEL = 6; + static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 7; static const int ROW_TWO_COLUMN_YOKE = 0; static const int ROW_TWO_COLUMN_ALL_MAPS = 3; @@ -176,7 +180,8 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); - gridLayout->setColumnStretch(6, 100); + gridLayout->setColumnStretch(6, 0); + gridLayout->setColumnStretch(7, 100); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; @@ -200,8 +205,9 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_colorBarToolButton, row, ROW_ONE_COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_historyToolButton, row, ROW_ONE_COLUMN_HISTORY, Qt::AlignHCenter); - glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL); - glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 3); + glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, ROW_ONE_COLUMN_MATRIX_VIEW, Qt::AlignHCenter); + glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL, Qt::AlignHCenter); + glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 2); row++; glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartOverlayViewController.cxx index c2977cdfc..564db2d22 100644 --- a/src/GuiQt/ChartOverlayViewController.cxx +++ b/src/GuiQt/ChartOverlayViewController.cxx @@ -146,7 +146,7 @@ m_chartOverlay(NULL) QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", constructionIcon); - m_constructionAction = WuQtUtilities::createAction("M", + m_constructionAction = WuQtUtilities::createAction("C", "Add/Move/Remove Layers", this); if (constructionIconValid) { @@ -162,7 +162,7 @@ m_chartOverlay(NULL) * History button */ m_historyToolButton = new QToolButton(); - m_historyAction = WuQtUtilities::createAction("", + m_historyAction = WuQtUtilities::createAction("H", "Show history for line chart file", this, this, @@ -172,6 +172,19 @@ m_chartOverlay(NULL) m_historyToolButton->setDefaultAction(m_historyAction); //m_historyToolButton->setIconSize(historyPixmap.size()); + /* + * Matrix triangular view mode button + */ + m_matrixTriangularViewModeAction = WuQtUtilities::createAction("M", + "Matrix triangular view", + this); + m_matrixTriangularViewModeToolButton = new QToolButton(); + QMenu* matrixTriangularViewModeMenu = createMatrixTriangularViewModeMenu(m_matrixTriangularViewModeToolButton); + m_matrixTriangularViewModeAction->setMenu(matrixTriangularViewModeMenu); + m_matrixTriangularViewModeToolButton->setDefaultAction(m_matrixTriangularViewModeAction); + m_matrixTriangularViewModeToolButton->setPopupMode(QToolButton::InstantPopup); + + /* * Map file Selection Check Box */ @@ -734,8 +747,55 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) if (validOverlayAndFileFlag) { m_historyAction->setEnabled(m_chartOverlay->isHistorySupported()); } + + /* + * Update matrix triangular view mode + */ + m_matrixTriangularViewModeAction->setEnabled(false); + if (validOverlayAndFileFlag) { + if (m_chartOverlay->isMatrixTriangularViewingModeSupported()) { + m_matrixTriangularViewModeAction->setEnabled(true); + const ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = m_chartOverlay->getMatrixTriangularViewingMode(); + + for (auto& mvmd : m_matrixViewMenuData) { + if (std::get<0>(mvmd) == viewMode) { + std::get<1>(mvmd)->setChecked(true); + updateMatrixTriangularViewModeAction(viewMode); + break; + } + } + } + } } +/** + * Update the matrix triangular view mode button. + * + * @param matrixViewMode + * Matrix triangular view mode. + */ +void +ChartOverlayViewController::updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) +{ + CaretAssert(m_matrixTriangularViewModeAction); + m_matrixTriangularViewModeAction->blockSignals(true); + for (auto& mvmd : m_matrixViewMenuData) { + if (std::get<0>(mvmd) == matrixViewMode) { + QPixmap pixmap = std::get<2>(mvmd); + if ( ! pixmap.isNull()) { + m_matrixTriangularViewModeAction->setIcon(pixmap); + m_matrixTriangularViewModeAction->setText(""); + } + else { + m_matrixTriangularViewModeAction->setText("M"); + } + break; + } + } + m_matrixTriangularViewModeAction->blockSignals(false); +} + + /** * Update graphics and GUI after selections made */ @@ -774,6 +834,62 @@ ChartOverlayViewController::updateGraphicsWindow() // } } +/** + * Create the matrix triangular view mode menu. + * @param parent + * Parent widget. + */ +QMenu* +ChartOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent) +{ + std::vector allViewModes; + ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(allViewModes); + + QMenu* menu = new QMenu(parent); + QObject::connect(menu, &QMenu::triggered, + this, &ChartOverlayViewController::menuMatrixTriangularViewModeTriggered); +// QObject::connect(menu, SIGNAL(triggered(QAction*)), +// this, SLOT(menuMatrixTriangularViewModeTriggered(QAction* action))); + + QActionGroup* actionGroup = new QActionGroup(this); + actionGroup->setExclusive(true); + + for (auto viewMode: allViewModes) { + QAction* action = menu->addAction(ChartTwoMatrixTriangularViewingModeEnum::toGuiName(viewMode)); + action->setCheckable(true); + action->setData((int)ChartTwoMatrixTriangularViewingModeEnum::toIntegerCode(viewMode)); + QPixmap pixmap = createMatrixTriangularViewModePixmap(menu, viewMode); + action->setIcon(pixmap); + actionGroup->addAction(action); + + m_matrixViewMenuData.push_back(std::make_tuple(viewMode, action, pixmap)); + } + + return menu; +} + +/** + * Called when an item is selected on matrix triangular view mode menu. + * + * @action + * Action of menu item selected. + */ +void +ChartOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* action) +{ + const QVariant itemData = action->data(); + CaretAssert(itemData.isValid()); + bool valid = false; + ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = ChartTwoMatrixTriangularViewingModeEnum::fromIntegerCode(itemData.toInt(), &valid); + + if (valid) { + m_chartOverlay->setMatrixTriangularViewingMode(viewMode); + updateMatrixTriangularViewModeAction(viewMode); + this->updateGraphicsWindow(); + } +} + + /** * Create the construction menu. * @param parent @@ -997,6 +1113,87 @@ ChartOverlayViewController::menuReloadFileTriggered() } } +/** + * Create a matrix view mode pixmap. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @param matrixViewMode + * Matrix view mode represented by the icon. + * @return + * Pixmap for matrix view mode. + */ +QPixmap +ChartOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* widget, + const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) +{ + CaretAssert(widget); + + /* + * Create a small, square pixmap that will contain + * the foreground color around the pixmap's perimeter. + */ + const qreal iconSize = 24.0; + const qreal minValue = 2.0; + const qreal maxValue = iconSize - minValue; + const QPointF bottomLeft(minValue, minValue); + const QPointF bottomRight(maxValue, minValue); + const QPointF topRight(maxValue, maxValue); + const QPointF topLeft(minValue, maxValue); + + QPixmap pixmap(static_cast(iconSize), + static_cast(iconSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, + pixmap); + + QPen pen = painter->pen(); + pen.setWidthF(2.0); + painter->setPen(pen); + + QPolygonF polygon; + switch (matrixViewMode) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + { + polygon.push_back(bottomLeft); + polygon.push_back(bottomRight); + polygon.push_back(topRight); + polygon.push_back(topLeft); + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + { + polygon.push_back(bottomLeft); + polygon.push_back(bottomRight); + polygon.push_back(topRight); + polygon.push_back(topLeft); + + painter->drawLine(topLeft, bottomRight); + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + { + polygon.push_back(bottomLeft); + polygon.push_back(bottomRight); + polygon.push_back(topLeft); + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + { + polygon.push_back(bottomRight); + polygon.push_back(topRight); + polygon.push_back(topLeft); + } + break; + } + + + painter->drawPolygon(polygon); + + return pixmap; +} + + /** * Create a history pixmap. * diff --git a/src/GuiQt/ChartOverlayViewController.h b/src/GuiQt/ChartOverlayViewController.h index daf578fa3..37c4035ac 100644 --- a/src/GuiQt/ChartOverlayViewController.h +++ b/src/GuiQt/ChartOverlayViewController.h @@ -25,6 +25,8 @@ #include #include +#include "ChartTwoMatrixTriangularViewingModeEnum.h" + class QAction; class QCheckBox; class QComboBox; @@ -101,6 +103,8 @@ namespace caret { void menuConstructionAboutToShow(); + void menuMatrixTriangularViewModeTriggered(QAction* action); + private: ChartOverlayViewController(const ChartOverlayViewController&); @@ -114,12 +118,19 @@ namespace caret { QMenu* createConstructionMenu(QWidget* parent); + QMenu* createMatrixTriangularViewModeMenu(QWidget* widget); + void validateYokingSelection(); void updateOverlaySettingsEditor(); QPixmap createHistoryPixmap(QWidget* widget); + QPixmap createMatrixTriangularViewModePixmap(QWidget* widget, + const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); + + void updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); + const int32_t m_browserWindowIndex; const int32_t m_chartOverlayIndex; @@ -142,6 +153,12 @@ namespace caret { QAction* m_historyAction; + QToolButton* m_matrixTriangularViewModeToolButton; + + QAction* m_matrixTriangularViewModeAction; + + std::vector> m_matrixViewMenuData; + QComboBox* m_mapFileComboBox; MapYokingGroupComboBox* m_mapRowOrColumnYokingGroupComboBox; -- GitLab From d23fbd4ef7bbc61cb13107f13ef3f4b18aa22e2c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 30 Jan 2017 12:59:15 -0600 Subject: [PATCH 190/755] Continuing charting development. Added attributes control for matrix: zoom percentages, show grid lines, show selected rows/columns. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 129 ++++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 16 +- .../BrainOpenGLChartTwoDrawingInterface.h | 8 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 3 +- src/Brain/BrowserTabContent.cxx | 6 +- src/Brain/BrowserTabContent.h | 6 +- src/Brain/CMakeLists.txt | 12 +- .../{ChartOverlay.cxx => ChartTwoOverlay.cxx} | 102 ++-- .../{ChartOverlay.h => ChartTwoOverlay.h} | 28 +- ...tOverlaySet.cxx => ChartTwoOverlaySet.cxx} | 70 +-- ...ChartOverlaySet.h => ChartTwoOverlaySet.h} | 36 +- ...tArray.cxx => ChartTwoOverlaySetArray.cxx} | 44 +- ...aySetArray.h => ChartTwoOverlaySetArray.h} | 26 +- src/Brain/Model.cxx | 4 +- src/Brain/Model.h | 6 +- src/Brain/ModelChart.cxx | 174 +++--- src/Brain/ModelChart.h | 31 +- src/Charting/CMakeLists.txt | 2 + .../ChartTwoMatrixDisplayProperties.cxx | 295 ++++++++++ .../ChartTwoMatrixDisplayProperties.h | 114 ++++ src/GuiQt/AnnotationCoordinateWidget.cxx | 2 +- .../BrainBrowserWindowOrientedToolBox.cxx | 4 +- src/GuiQt/BrainBrowserWindowOrientedToolBox.h | 4 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 71 ++- src/GuiQt/BrainBrowserWindowToolBar.h | 18 +- ...BrowserWindowToolBarChartTwoAttributes.cxx | 512 ++++++++++++++++++ ...inBrowserWindowToolBarChartTwoAttributes.h | 143 +++++ ...owserWindowToolBarChartTwoOrientation.cxx} | 18 +- ...BrowserWindowToolBarChartTwoOrientation.h} | 20 +- .../BrainBrowserWindowToolBarChartTwoType.cxx | 6 +- .../BrainBrowserWindowToolBarComponent.h | 2 +- src/GuiQt/CMakeLists.txt | 21 +- ...x => ChartTwoOverlaySetViewController.cxx} | 58 +- ...r.h => ChartTwoOverlaySetViewController.h} | 26 +- ....cxx => ChartTwoOverlayViewController.cxx} | 76 +-- ...ller.h => ChartTwoOverlayViewController.h} | 28 +- ...ventOverlaySettingsEditorDialogRequest.cxx | 2 +- .../EventOverlaySettingsEditorDialogRequest.h | 10 +- src/GuiQt/MapYokingGroupComboBox.cxx | 4 +- src/GuiQt/MapYokingGroupComboBox.h | 4 +- 40 files changed, 1713 insertions(+), 428 deletions(-) rename src/Brain/{ChartOverlay.cxx => ChartTwoOverlay.cxx} (92%) rename src/Brain/{ChartOverlay.h => ChartTwoOverlay.h} (90%) rename src/Brain/{ChartOverlaySet.cxx => ChartTwoOverlaySet.cxx} (91%) rename src/Brain/{ChartOverlaySet.h => ChartTwoOverlaySet.h} (78%) rename src/Brain/{ChartOverlaySetArray.cxx => ChartTwoOverlaySetArray.cxx} (83%) rename src/Brain/{ChartOverlaySetArray.h => ChartTwoOverlaySetArray.h} (73%) create mode 100644 src/Charting/ChartTwoMatrixDisplayProperties.cxx create mode 100644 src/Charting/ChartTwoMatrixDisplayProperties.h create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h rename src/GuiQt/{BrainBrowserWindowToolBarChartOrientation.cxx => BrainBrowserWindowToolBarChartTwoOrientation.cxx} (88%) rename src/GuiQt/{BrainBrowserWindowToolBarChartOrientation.h => BrainBrowserWindowToolBarChartTwoOrientation.h} (65%) rename src/GuiQt/{ChartOverlaySetViewController.cxx => ChartTwoOverlaySetViewController.cxx} (89%) rename src/GuiQt/{ChartOverlaySetViewController.h => ChartTwoOverlaySetViewController.h} (73%) rename src/GuiQt/{ChartOverlayViewController.cxx => ChartTwoOverlayViewController.cxx} (94%) rename src/GuiQt/{ChartOverlayViewController.h => ChartTwoOverlayViewController.h} (86%) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index ae2c3caa2..1130723df 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -30,14 +30,16 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartMatrixScaleModeEnum.h" -#include "ChartOverlay.h" -#include "ChartOverlaySet.h" +#include "ChartTwoMatrixDisplayProperties.h" +#include "ChartTwoOverlay.h" +#include "ChartTwoOverlaySet.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "IdentificationWithColor.h" +#include "ModelChart.h" #include "SessionManager.h" using namespace caret; @@ -71,6 +73,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * * @param brain * Brain. + * @parm chartModel + * The chart model in the window. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param textRenderer @@ -90,16 +94,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, + ModelChart* chartModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], const float zooming, - ChartOverlaySet* chartOverlaySet, + ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], const int32_t tabIndex) { m_brain = brain; + m_chartModel = chartModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = textRenderer; m_translation[0] = translation[0]; @@ -146,7 +152,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, const int32_t numberOfOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); if (numberOfOverlays > 0) { - ChartOverlay* topOverlay = chartOverlaySet->getOverlay(0); + ChartTwoOverlay* topOverlay = chartOverlaySet->getOverlay(0); if (topOverlay->isEnabled()) { CaretMappableDataFile* cmdf = NULL; int32_t mapIndex = -1; @@ -302,7 +308,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); - const ChartOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); @@ -315,7 +321,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() float yMin = 0.0; float yMax = 100.0; for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { continue; } @@ -365,7 +371,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() } for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { continue; } @@ -441,7 +447,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() */ const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); - const ChartOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); @@ -458,6 +464,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() /* * Set the width and neight of each matrix cell. */ + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + CaretAssert(matrixProperties); + const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; + const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; + if ((cellWidthZoom > 0.0) + && (cellHeightZoom > 0.0)) { + cellWidth *= cellWidthZoom; + cellHeight *= cellHeightZoom; + } + + //ChartMatrixDisplayProperties* matrixProperties = chartMatrixInterface->getChartMatrixDisplayProperties(m_tabIndex); //CaretAssert(matrixProperties); const ChartMatrixScaleModeEnum::Enum scaleMode = ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO; // matrixProperties->getScaleMode(); @@ -526,7 +543,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() } for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - ChartOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { continue; } @@ -654,9 +671,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT return; } - CaretAssertToDoWarning(); // need to set these - bool displayGridLinesFlag = false; - const bool highlightSelectedRowColumnFlag = true; + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + CaretAssert(matrixProperties); + + bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); + const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); std::vector selectedColumnIndices; @@ -666,6 +685,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT selectedRowColumnDimension, selectedRowIndices, selectedColumnIndices); + std::map columnRangesForRow; + for (int32_t rowIndex : selectedRowIndices) { + columnRangesForRow[rowIndex] = RowColumnMinMax(); + } + const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); + + std::map rowRangesForColumn; + for (int32_t columnIndex : selectedColumnIndices) { + rowRangesForColumn[columnIndex] = RowColumnMinMax(); + } + const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); + // getMatrixHighlighting(matrixChart // selectedRowIndices, // selectedColumnIndices); @@ -747,6 +778,30 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } if (drawCellFlag) { + if (haveSelectedRowsFlag) { + std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); + if (minMaxIter != columnRangesForRow.end()) { + if (columnIndex < minMaxIter->second.m_min) { + minMaxIter->second.m_min = columnIndex; + } + if (columnIndex > minMaxIter->second.m_max) { + minMaxIter->second.m_max = columnIndex; + } + } + } + + if (haveSelectedColumnsFlag) { + std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); + if (minMaxIter != rowRangesForColumn.end()) { + if (rowIndex < minMaxIter->second.m_min) { + minMaxIter->second.m_min = rowIndex; + } + if (rowIndex > minMaxIter->second.m_max) { + minMaxIter->second.m_max = rowIndex; + } + } + } + uint8_t idRGBA[4]; if (m_identificationModeFlag) { addToChartMatrixIdentification(rowIndex, @@ -901,8 +956,24 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT for (auto rowIndex : selectedRowIndices) { const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; + int32_t minColumn = 0; + int32_t maxColumn = numberOfColumns; + if (haveSelectedRowsFlag) { + std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); + if (minMaxIter != columnRangesForRow.end()) { + const int32_t minValue = minMaxIter->second.m_min; + const int32_t rowMaxColumn = minMaxIter->second.m_max; + if (minValue < rowMaxColumn) { + minColumn = minValue; + maxColumn = rowMaxColumn + 1; + } + } + } - rowXYZ.push_back(0.0); + const float minX = minColumn * cellWidth; + const float maxX = maxColumn * cellWidth; + + rowXYZ.push_back(minX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); @@ -910,7 +981,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); - rowXYZ.push_back(0.0); + rowXYZ.push_back(minX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); @@ -918,7 +989,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); - rowXYZ.push_back(numberOfColumns * cellWidth); + rowXYZ.push_back(maxX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); @@ -927,7 +998,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowRGBA.push_back(1.0); - rowXYZ.push_back(numberOfColumns * cellWidth); + rowXYZ.push_back(maxX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); @@ -972,8 +1043,26 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT for (auto columnIndex : selectedColumnIndices) { const float colX = columnIndex * cellWidth; + int32_t minRow = 0; + int32_t maxRow = numberOfRows; + if (haveSelectedColumnsFlag) { + std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); + if (minMaxIter != rowRangesForColumn.end()) { + const int32_t minValue = minMaxIter->second.m_min; + const int32_t maxValue = minMaxIter->second.m_max; + if (minValue < maxValue) { + minRow = minValue; + maxRow = maxValue + 1; + } + } + } + + const float minY = minRow * cellHeight; + const float maxY = maxRow * cellHeight; + + columnXYZ.push_back(colX); - columnXYZ.push_back(0.0); + columnXYZ.push_back(minY); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); @@ -981,7 +1070,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); - columnXYZ.push_back(0.0); + columnXYZ.push_back(minY); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); @@ -989,7 +1078,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); - columnXYZ.push_back(numberOfRows * cellHeight); + columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); @@ -998,7 +1087,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnXYZ.push_back(colX); - columnXYZ.push_back(numberOfRows * cellHeight); + columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index ca06ed965..3437d3d5a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -31,6 +31,7 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; + class ModelChart; class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { @@ -40,11 +41,12 @@ namespace caret { virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, + ModelChart* chartModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], const float zooming, - ChartOverlaySet* chartOverlaySet, + ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], const int32_t tabIndex) override; @@ -66,6 +68,14 @@ namespace caret { double m_right; double m_top; }; + + class RowColumnMinMax { + public: + RowColumnMinMax() { } + + int32_t m_min = 9999999; + int32_t m_max = -9999999; + }; BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); @@ -100,11 +110,13 @@ namespace caret { Brain* m_brain; + ModelChart* m_chartModel; + BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; BrainOpenGLTextRenderInterface* m_textRenderer; - ChartOverlaySet* m_chartOverlaySet; + ChartTwoOverlaySet* m_chartOverlaySet; SelectionItemDataTypeEnum::Enum m_selectionItemDataType; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 5df3b1fd2..d1e15f254 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -31,7 +31,8 @@ namespace caret { class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; - class ChartOverlaySet; + class ChartTwoOverlaySet; + class ModelChart; class BrainOpenGLChartTwoDrawingInterface { @@ -45,6 +46,8 @@ namespace caret { * * @param brain * Brain. + * @param chartModel + * The chart model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param textRenderer @@ -63,11 +66,12 @@ namespace caret { * Index of the tab. */ virtual void drawChartOverlaySet(Brain* brain, + ModelChart* chartModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], const float zooming, - ChartOverlaySet* chartOverlaySet, + ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], const int32_t tabIndex) = 0; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 5addb65bb..70c7f2e6f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -69,7 +69,7 @@ #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" -#include "ChartOverlaySet.h" +#include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" @@ -5293,6 +5293,7 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const float zooming = browserTabContent->getScaling(); chartDrawing.drawChartOverlaySet(m_brain, + chartModel, this, getTextRenderer(), translation, diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 5fd54ba5d..1039c8f9f 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -40,7 +40,7 @@ #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartModelDataSeries.h" -#include "ChartOverlaySet.h" +#include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "ClippingPlaneGroup.h" @@ -858,7 +858,7 @@ BrowserTabContent::getOverlaySet() const /** * @return Overlay set for this tab. */ -ChartOverlaySet* +ChartTwoOverlaySet* BrowserTabContent::getChartOverlaySet() { Model* model = getModelForDisplay(); @@ -871,7 +871,7 @@ BrowserTabContent::getChartOverlaySet() /** * @return Overlay set for this tab. */ -const ChartOverlaySet* +const ChartTwoOverlaySet* BrowserTabContent::getChartOverlaySet() const { const Model* model = getModelForDisplay(); diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 6580d4392..91aabf9ce 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -43,7 +43,7 @@ namespace caret { class BrainOpenGLViewportContent; class CaretDataFile; class CaretMappableDataFile; - class ChartOverlaySet; + class ChartTwoOverlaySet; class ClippingPlaneGroup; class Matrix4x4; class ModelChart; @@ -94,9 +94,9 @@ namespace caret { const OverlaySet* getOverlaySet() const; - ChartOverlaySet* getChartOverlaySet(); + ChartTwoOverlaySet* getChartOverlaySet(); - const ChartOverlaySet* getChartOverlaySet() const; + const ChartTwoOverlaySet* getChartOverlaySet() const; int32_t getTabNumber() const; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index c4dc788ac..74b058a30 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -81,9 +81,9 @@ BrowserTabContent.h CaretDataFileSelectionModel.h CaretMappableDataFileAndMapSelectionModel.h CaretOpenGLInclude.h -ChartOverlay.h -ChartOverlaySet.h -ChartOverlaySetArray.h +ChartTwoOverlay.h +ChartTwoOverlaySet.h +ChartTwoOverlaySetArray.h ChartingDataManager.h CiftiConnectivityMatrixDataFileManager.h CiftiFiberTrajectoryManager.h @@ -223,9 +223,9 @@ BrainStructureNodeAttributes.cxx BrowserTabContent.cxx CaretDataFileSelectionModel.cxx CaretMappableDataFileAndMapSelectionModel.cxx -ChartOverlay.cxx -ChartOverlaySet.cxx -ChartOverlaySetArray.cxx +ChartTwoOverlay.cxx +ChartTwoOverlaySet.cxx +ChartTwoOverlaySetArray.cxx ChartingDataManager.cxx CiftiConnectivityMatrixDataFileManager.cxx CiftiFiberTrajectoryManager.cxx diff --git a/src/Brain/ChartOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx similarity index 92% rename from src/Brain/ChartOverlay.cxx rename to src/Brain/ChartTwoOverlay.cxx index 7d6635e86..bf9426035 100644 --- a/src/Brain/ChartOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __CHART_OVERLAY_DECLARE__ -#include "ChartOverlay.h" -#undef __CHART_OVERLAY_DECLARE__ +#define __CHART_TWO_OVERLAY_DECLARE__ +#include "ChartTwoOverlay.h" +#undef __CHART_TWO_OVERLAY_DECLARE__ #include "AnnotationColorBar.h" #include "CaretAssert.h" @@ -31,7 +31,7 @@ #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" -#include "ChartOverlaySet.h" +#include "ChartTwoOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" @@ -43,7 +43,7 @@ using namespace caret; /** - * \class caret::ChartOverlay + * \class caret::ChartTwoOverlay * \brief Overlay for charts. * \ingroup Brain */ @@ -51,22 +51,22 @@ using namespace caret; /** * Constructor. * - * @param parentChartOverlaySet + * @param parentChartTwoOverlaySet * Parent of this chart overlay set. * @param chartDataType * Type of charts allowed in this overlay * @param overlayIndex * Index of this overlay. */ -ChartOverlay::ChartOverlay(ChartOverlaySet* parentChartOverlaySet, +ChartTwoOverlay::ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t overlayIndex) : CaretObject(), -m_parentChartOverlaySet(parentChartOverlaySet), +m_parentChartTwoOverlaySet(parentChartTwoOverlaySet), m_chartDataType(chartDataType), m_overlayIndex(overlayIndex) { - CaretAssert(m_parentChartOverlaySet); + CaretAssert(m_parentChartTwoOverlaySet); // m_chartCompoundDataType m_name = "Overlay " + AString::number(overlayIndex + 1); @@ -99,7 +99,7 @@ m_overlayIndex(overlayIndex) /** * Destructor. */ -ChartOverlay::~ChartOverlay() +ChartTwoOverlay::~ChartTwoOverlay() { EventManager::get()->removeAllEventsFromListener(this); } @@ -112,7 +112,7 @@ ChartOverlay::~ChartOverlay() * An event for which this instance is listening. */ void -ChartOverlay::receiveEvent(Event* event) +ChartTwoOverlay::receiveEvent(Event* event) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); @@ -127,7 +127,7 @@ ChartOverlay::receiveEvent(Event* event) * @return String describing this object's content. */ AString -ChartOverlay::toString() const +ChartTwoOverlay::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); @@ -141,9 +141,9 @@ ChartOverlay::toString() const * Description of the window's content. */ void -ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const +ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { - ChartOverlay* me = const_cast(this); + ChartTwoOverlay* me = const_cast(this); if (me != NULL) { if (me->isEnabled()) { CaretMappableDataFile* mapFile = NULL; @@ -178,7 +178,7 @@ ChartOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) co * @return The chart data type for this chart overlay. */ ChartTwoDataTypeEnum::Enum -ChartOverlay::getChartDataType() const +ChartTwoOverlay::getChartDataType() const { return m_chartDataType; } @@ -187,7 +187,7 @@ ChartOverlay::getChartDataType() const * Get the chart compound data type */ ChartTwoCompoundDataType -ChartOverlay::getChartTwoCompoundDataType() const +ChartTwoOverlay::getChartTwoCompoundDataType() const { return m_chartCompoundDataType; } @@ -201,10 +201,10 @@ ChartOverlay::getChartTwoCompoundDataType() const * Type of charts for display in this overlay. */ void -ChartOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) +ChartTwoOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) { if (m_overlayIndex == 0) { - CaretAssertMessage(0, "ChartOverlay::setChartTwoCompoundDataType() should not be called " + CaretAssertMessage(0, "ChartTwoOverlay::setChartTwoCompoundDataType() should not be called " " for first overlay"); return; } @@ -220,7 +220,7 @@ ChartOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartC * @return Enabled status for this surface overlay. */ bool -ChartOverlay::isEnabled() const +ChartTwoOverlay::isEnabled() const { /* * First overlay is ALWAYS enabled @@ -238,7 +238,7 @@ ChartOverlay::isEnabled() const * New status. */ void -ChartOverlay::setEnabled(const bool enabled) +ChartTwoOverlay::setEnabled(const bool enabled) { if (m_overlayIndex == 0) { if ( ! enabled) { @@ -256,14 +256,14 @@ ChartOverlay::setEnabled(const bool enabled) * Overlay from which data is transferred. */ void -ChartOverlay::copyData(const ChartOverlay* overlay) +ChartTwoOverlay::copyData(const ChartTwoOverlay* overlay) { CaretAssert(overlay); /* * These members are not copied since they * identify the overlay: - * m_parentChartOverlaySet + * m_parentChartTwoOverlaySet * m_name * m_overlayIndex * @@ -292,9 +292,9 @@ ChartOverlay::copyData(const ChartOverlay* overlay) * Overlay from which data is swapped. */ void -ChartOverlay::swapData(ChartOverlay* overlay) +ChartTwoOverlay::swapData(ChartTwoOverlay* overlay) { - std::unique_ptr swapOverlay = std::unique_ptr(new ChartOverlay(m_parentChartOverlaySet, + std::unique_ptr swapOverlay = std::unique_ptr(new ChartTwoOverlay(m_parentChartTwoOverlaySet, overlay->m_chartDataType, overlay->m_overlayIndex)); swapOverlay->copyData(overlay); @@ -307,7 +307,7 @@ ChartOverlay::swapData(ChartOverlay* overlay) * Is history supported ? */ bool -ChartOverlay::isHistorySupported() const +ChartTwoOverlay::isHistorySupported() const { bool supportedFlag = false; @@ -329,7 +329,7 @@ ChartOverlay::isHistorySupported() const * Is map yoking supported ? */ bool -ChartOverlay::isMapYokingSupported() const +ChartTwoOverlay::isMapYokingSupported() const { bool supportedFlag = false; @@ -352,7 +352,7 @@ ChartOverlay::isMapYokingSupported() const * @return Selected map yoking group. */ MapYokingGroupEnum::Enum -ChartOverlay::getMapYokingGroup() const +ChartTwoOverlay::getMapYokingGroup() const { return m_mapYokingGroup; } @@ -364,7 +364,7 @@ ChartOverlay::getMapYokingGroup() const * New value for map yoking group. */ void -ChartOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) +ChartTwoOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) { m_mapYokingGroup = mapYokingGroup; } @@ -373,7 +373,7 @@ ChartOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) * @return The color bar displayed in graphics window. */ AnnotationColorBar* -ChartOverlay::getColorBar() +ChartTwoOverlay::getColorBar() { return m_colorBar.get(); } @@ -382,7 +382,7 @@ ChartOverlay::getColorBar() * @return The color bar displayed in graphics window (const method). */ const AnnotationColorBar* -ChartOverlay::getColorBar() const +ChartTwoOverlay::getColorBar() const { return m_colorBar.get(); } @@ -397,7 +397,7 @@ ChartOverlay::getColorBar() const * Index of selected map in the selected file. */ void -ChartOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, +ChartTwoOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut) const { std::vector mapFiles; @@ -420,7 +420,7 @@ ChartOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, * Index of selected map in the selected file. */ void -ChartOverlay::getSelectionData(std::vector& mapFilesOut, +ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, int32_t& selectedMapIndexOut) const @@ -482,7 +482,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, * Index of selected map in the selected file. */ void -ChartOverlay::getSelectionData(std::vector& mapFilesOut, +ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut) const { @@ -504,7 +504,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, // * Index of selected map in the selected file. // */ //void -//ChartOverlay::getSelectionData(std::vector& mapFilesOut, +//ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, // CaretMappableDataFile* &selectedMapFileOut, // int32_t& selectedMapIndexOut) //{ @@ -634,8 +634,8 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, // chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, // m_chartCompoundDataType); // } -// CaretAssert(m_parentChartOverlaySet); -// m_parentChartOverlaySet->firstOverlaySelectionChanged(); +// CaretAssert(m_parentChartTwoOverlaySet); +// m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); // } // //If selected type changes, need to update other overlays in the overlay set with // //the selected data type} @@ -655,7 +655,7 @@ ChartOverlay::getSelectionData(std::vector& mapFilesOut, * Index of selected map in the selected file. */ void -ChartOverlay::getSelectionDataPrivate(std::vector& mapFilesOut, +ChartTwoOverlay::getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector* selectedFileMapNamesOut, int32_t& selectedMapIndexOut) const @@ -823,7 +823,7 @@ ChartOverlay::getSelectionDataPrivate(std::vector& mapFi ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; std::vector columnIndices; std::vector rowIndices; - matrixChart->getSelectedRowColumnIndices(m_parentChartOverlaySet->m_tabIndex, + matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, rowColumnDimension, rowIndices, columnIndices); @@ -900,8 +900,8 @@ ChartOverlay::getSelectionDataPrivate(std::vector& mapFi chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, m_chartCompoundDataType); } - CaretAssert(m_parentChartOverlaySet); - m_parentChartOverlaySet->firstOverlaySelectionChanged(); + CaretAssert(m_parentChartTwoOverlaySet); + m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); } //If selected type changes, need to update other overlays in the overlay set with //the selected data type} @@ -916,7 +916,7 @@ ChartOverlay::getSelectionDataPrivate(std::vector& mapFi * index if it is valid. Otherwise, use the first map index. */ void -ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, +ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex) { m_selectedMapFile = selectedMapFile; @@ -937,7 +937,7 @@ ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, CaretAssert(chartDelegate); ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); CaretAssert(matrixChart); - matrixChart->setSelectedRowColumnIndex(m_parentChartOverlaySet->m_tabIndex, + matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, selectedMapIndex); } break; @@ -984,7 +984,7 @@ ChartOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, * @return Is the all maps supported? */ bool -ChartOverlay::isAllMapsSupported() const +ChartTwoOverlay::isAllMapsSupported() const { bool supportedFlag = false; @@ -1019,7 +1019,7 @@ ChartOverlay::isAllMapsSupported() const * @return All maps selected. */ bool -ChartOverlay::isAllMapsSelected() const +ChartTwoOverlay::isAllMapsSelected() const { return m_allHistogramMapsSelectedFlag; } @@ -1031,7 +1031,7 @@ ChartOverlay::isAllMapsSelected() const * New status. */ void -ChartOverlay::setAllMapsSelected(const bool status) +ChartTwoOverlay::setAllMapsSelected(const bool status) { m_allHistogramMapsSelectedFlag = status; } @@ -1040,7 +1040,7 @@ ChartOverlay::setAllMapsSelected(const bool status) * @return The matrix triangular viewing mode. */ ChartTwoMatrixTriangularViewingModeEnum::Enum -ChartOverlay::getMatrixTriangularViewingMode() const +ChartTwoOverlay::getMatrixTriangularViewingMode() const { return m_matrixTriangularViewingMode; } @@ -1052,7 +1052,7 @@ ChartOverlay::getMatrixTriangularViewingMode() const * New triangular viewing mode. */ void -ChartOverlay::setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode) +ChartTwoOverlay::setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode) { m_matrixTriangularViewingMode = mode; } @@ -1061,7 +1061,7 @@ ChartOverlay::setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewi * @return Is the matrix triangular view mode supported? */ bool -ChartOverlay::isMatrixTriangularViewingModeSupported() const +ChartTwoOverlay::isMatrixTriangularViewingModeSupported() const { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: @@ -1090,11 +1090,11 @@ ChartOverlay::isMatrixTriangularViewingModeSupported() const * Name of instance in the scene. */ SceneClass* -ChartOverlay::saveToScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlay::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, - "ChartOverlay", + "ChartTwoOverlay", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -1118,7 +1118,7 @@ ChartOverlay::saveToScene(const SceneAttributes* sceneAttributes, * sceneClass from which model specific information is obtained. */ void -ChartOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { diff --git a/src/Brain/ChartOverlay.h b/src/Brain/ChartTwoOverlay.h similarity index 90% rename from src/Brain/ChartOverlay.h rename to src/Brain/ChartTwoOverlay.h index e9b1fbbf6..a4368eb66 100644 --- a/src/Brain/ChartOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -1,5 +1,5 @@ -#ifndef __CHART_OVERLAY_H__ -#define __CHART_OVERLAY_H__ +#ifndef __CHART_TWO_OVERLAY_H__ +#define __CHART_TWO_OVERLAY_H__ /*LICENSE_START*/ /* @@ -34,18 +34,18 @@ namespace caret { class AnnotationColorBar; class CaretMappableDataFile; - class ChartOverlaySet; + class ChartTwoOverlaySet; class PlainTextStringBuilder; class SceneClassAssistant; - class ChartOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { + class ChartTwoOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlay(ChartOverlaySet* parentChartOverlaySet, + ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t overlayIndex); - virtual ~ChartOverlay(); + virtual ~ChartTwoOverlay(); ChartTwoDataTypeEnum::Enum getChartDataType() const; @@ -63,9 +63,9 @@ namespace caret { void setEnabled(const bool enabled); - void copyData(const ChartOverlay* overlay); + void copyData(const ChartTwoOverlay* overlay); - void swapData(ChartOverlay* overlay); + void swapData(ChartTwoOverlay* overlay); bool isHistorySupported() const; @@ -127,9 +127,9 @@ namespace caret { // const SceneClass* sceneClass) = 0; private: - ChartOverlay(const ChartOverlay&); + ChartTwoOverlay(const ChartTwoOverlay&); - ChartOverlay& operator=(const ChartOverlay&); + ChartTwoOverlay& operator=(const ChartTwoOverlay&); void getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, @@ -137,7 +137,7 @@ namespace caret { int32_t& selectedMapIndexOut) const; /** Parent chart overlay set (only used by first overlay in the set */ - ChartOverlaySet* m_parentChartOverlaySet; + ChartTwoOverlaySet* m_parentChartTwoOverlaySet; /** Enumerated Type of charts allowed in this overlay */ const ChartTwoDataTypeEnum::Enum m_chartDataType; @@ -175,9 +175,9 @@ namespace caret { }; -#ifdef __CHART_OVERLAY_DECLARE__ +#ifdef __CHART_TWO_OVERLAY_DECLARE__ // -#endif // __CHART_OVERLAY_DECLARE__ +#endif // __CHART_TWO_OVERLAY_DECLARE__ } // namespace -#endif //__CHART_OVERLAY_H__ +#endif //__CHART_TWO_OVERLAY_H__ diff --git a/src/Brain/ChartOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx similarity index 91% rename from src/Brain/ChartOverlaySet.cxx rename to src/Brain/ChartTwoOverlaySet.cxx index 44e19bb11..1eea38dd9 100644 --- a/src/Brain/ChartOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -19,12 +19,12 @@ */ /*LICENSE_END*/ -#define __CHART_OVERLAY_SET_DECLARE__ -#include "ChartOverlaySet.h" -#undef __CHART_OVERLAY_SET_DECLARE__ +#define __CHART_TWO_OVERLAY_SET_DECLARE__ +#include "ChartTwoOverlaySet.h" +#undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "CaretAssert.h" -#include "ChartOverlay.h" +#include "ChartTwoOverlay.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" @@ -36,7 +36,7 @@ using namespace caret; /** - * \class caret::ChartOverlaySet + * \class caret::ChartTwoOverlaySet * \brief A set of chart overlays. * \ingroup Brain */ @@ -51,7 +51,7 @@ using namespace caret; * @param tabIndex * Index of tab in which this overlay set is used. */ -ChartOverlaySet::ChartOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, +ChartTwoOverlaySet::ChartTwoOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex) : CaretObject(), @@ -66,7 +66,7 @@ m_tabIndex(tabIndex) &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - m_overlays[i] = new ChartOverlay(this, + m_overlays[i] = new ChartTwoOverlay(this, m_chartDataType, i); } @@ -77,7 +77,7 @@ m_tabIndex(tabIndex) /** * Destructor. */ -ChartOverlaySet::~ChartOverlaySet() +ChartTwoOverlaySet::~ChartTwoOverlaySet() { EventManager::get()->removeAllEventsFromListener(this); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { @@ -92,7 +92,7 @@ ChartOverlaySet::~ChartOverlaySet() * Overlay set that is copied. */ void -ChartOverlaySet::copyOverlaySet(const ChartOverlaySet* overlaySet) +ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); @@ -104,8 +104,8 @@ ChartOverlaySet::copyOverlaySet(const ChartOverlaySet* overlaySet) /** * @return Returns the top-most overlay regardless of its enabled status. */ -ChartOverlay* -ChartOverlaySet::getPrimaryOverlay() +ChartTwoOverlay* +ChartTwoOverlaySet::getPrimaryOverlay() { return m_overlays[0]; } @@ -114,8 +114,8 @@ ChartOverlaySet::getPrimaryOverlay() * @return Returns the underlay which is the lowest * displayed overlay. */ -ChartOverlay* -ChartOverlaySet::getUnderlay() +ChartTwoOverlay* +ChartTwoOverlaySet::getUnderlay() { return m_overlays[getNumberOfDisplayedOverlays() - 1]; } @@ -126,8 +126,8 @@ ChartOverlaySet::getUnderlay() * Index of the overlay. * @return Overlay at the given index. */ -const ChartOverlay* -ChartOverlaySet::getOverlay(const int32_t overlayNumber) const +const ChartTwoOverlay* +ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) const { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, @@ -141,8 +141,8 @@ ChartOverlaySet::getOverlay(const int32_t overlayNumber) const * Index of the overlay. * @return Overlay at the given index. */ -ChartOverlay* -ChartOverlaySet::getOverlay(const int32_t overlayNumber) +ChartTwoOverlay* +ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, @@ -157,7 +157,7 @@ ChartOverlaySet::getOverlay(const int32_t overlayNumber) * Description of the window's content. */ void -ChartOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const +ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Overlay Set"); @@ -186,7 +186,7 @@ ChartOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) * this method has no effect. */ void -ChartOverlaySet::addDisplayedOverlay() +ChartTwoOverlaySet::addDisplayedOverlay() { m_numberOfDisplayedOverlays++; if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { @@ -198,7 +198,7 @@ ChartOverlaySet::addDisplayedOverlay() * @return Returns the number of displayed overlays. */ int32_t -ChartOverlaySet::getNumberOfDisplayedOverlays() const +ChartTwoOverlaySet::getNumberOfDisplayedOverlays() const { return m_numberOfDisplayedOverlays; } @@ -209,7 +209,7 @@ ChartOverlaySet::getNumberOfDisplayedOverlays() const * Number of overlays for display. */ void -ChartOverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays) +ChartTwoOverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays) { const int32_t oldNumberOfDisplayedOverlays = m_numberOfDisplayedOverlays; m_numberOfDisplayedOverlays = numberOfDisplayedOverlays; @@ -239,7 +239,7 @@ ChartOverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOve * Index of overlay for which an overlay is added below */ void -ChartOverlaySet::insertOverlayAbove(const int32_t overlayIndex) +ChartTwoOverlaySet::insertOverlayAbove(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; @@ -256,7 +256,7 @@ ChartOverlaySet::insertOverlayAbove(const int32_t overlayIndex) * Index of overlay for which an overlay is added above */ void -ChartOverlaySet::insertOverlayBelow(const int32_t overlayIndex) +ChartTwoOverlaySet::insertOverlayBelow(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; @@ -277,7 +277,7 @@ ChartOverlaySet::insertOverlayBelow(const int32_t overlayIndex) * Index of overlay for removal from display. */ void -ChartOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) +ChartTwoOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, @@ -302,7 +302,7 @@ ChartOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) * Index of overlay that is to be moved up. */ void -ChartOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) +ChartTwoOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) { if (overlayIndex > 0) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); @@ -319,7 +319,7 @@ ChartOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) * Index of overlay that is to be moved down. */ void -ChartOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) +ChartTwoOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) { const int32_t nextOverlayIndex = overlayIndex + 1; if (nextOverlayIndex < m_numberOfDisplayedOverlays) { @@ -332,7 +332,7 @@ ChartOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) * Initialize the overlays. */ void -ChartOverlaySet::initializeOverlays() +ChartTwoOverlaySet::initializeOverlays() { // bool isMatchToVolumeUnderlay = false; // bool isMatchToVolumeOverlays = false; @@ -477,7 +477,7 @@ ChartOverlaySet::initializeOverlays() * so that the charts in the tab are compatible */ void -ChartOverlaySet::firstOverlaySelectionChanged() +ChartTwoOverlaySet::firstOverlaySelectionChanged() { if (m_inFirstOverlayChangedMethodFlag) { return; @@ -515,7 +515,7 @@ ChartOverlaySet::firstOverlaySelectionChanged() * Reset the yoking status of all overlays to off. */ void -ChartOverlaySet::resetOverlayYokingToOff() +ChartTwoOverlaySet::resetOverlayYokingToOff() { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); @@ -528,9 +528,9 @@ ChartOverlaySet::resetOverlayYokingToOff() * @return String describing this object's content. */ AString -ChartOverlaySet::toString() const +ChartTwoOverlaySet::toString() const { - return "ChartOverlaySet"; + return "ChartTwoOverlaySet"; } /** @@ -540,7 +540,7 @@ ChartOverlaySet::toString() const * An event for which this instance is listening. */ void -ChartOverlaySet::receiveEvent(Event* event) +ChartTwoOverlaySet::receiveEvent(Event* event) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); @@ -562,11 +562,11 @@ ChartOverlaySet::receiveEvent(Event* event) * Name of instance in the scene. */ SceneClass* -ChartOverlaySet::saveToScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlaySet::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, - "ChartOverlaySet", + "ChartTwoOverlaySet", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -601,7 +601,7 @@ ChartOverlaySet::saveToScene(const SceneAttributes* sceneAttributes, * sceneClass from which model specific information is obtained. */ void -ChartOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { diff --git a/src/Brain/ChartOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h similarity index 78% rename from src/Brain/ChartOverlaySet.h rename to src/Brain/ChartTwoOverlaySet.h index 8bab08ed8..5922f0a00 100644 --- a/src/Brain/ChartOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -1,5 +1,5 @@ -#ifndef __CHART_OVERLAY_SET_H__ -#define __CHART_OVERLAY_SET_H__ +#ifndef __CHART_TWO_OVERLAY_SET_H__ +#define __CHART_TWO_OVERLAY_SET_H__ /*LICENSE_START*/ /* @@ -29,28 +29,28 @@ namespace caret { - class ChartOverlay; + class ChartTwoOverlay; class PlainTextStringBuilder; class SceneClassAssistant; - class ChartOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { + class ChartTwoOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex); - virtual ~ChartOverlaySet(); + virtual ~ChartTwoOverlaySet(); - void copyOverlaySet(const ChartOverlaySet* overlaySet); + void copyOverlaySet(const ChartTwoOverlaySet* overlaySet); - ChartOverlay* getPrimaryOverlay(); + ChartTwoOverlay* getPrimaryOverlay(); - ChartOverlay* getUnderlay(); + ChartTwoOverlay* getUnderlay(); - ChartOverlay* getOverlay(const int32_t overlayNumber); + ChartTwoOverlay* getOverlay(const int32_t overlayNumber); - const ChartOverlay* getOverlay(const int32_t overlayNumber) const; + const ChartTwoOverlay* getOverlay(const int32_t overlayNumber) const; void addDisplayedOverlay(); @@ -102,15 +102,15 @@ namespace caret { // const SceneClass* sceneClass) = 0; private: - ChartOverlaySet(const ChartOverlaySet&); + ChartTwoOverlaySet(const ChartTwoOverlaySet&); - ChartOverlaySet& operator=(const ChartOverlaySet&); + ChartTwoOverlaySet& operator=(const ChartTwoOverlaySet&); void firstOverlaySelectionChanged(); SceneClassAssistant* m_sceneAssistant; - ChartOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; + ChartTwoOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; const ChartTwoDataTypeEnum::Enum m_chartDataType; @@ -124,13 +124,13 @@ namespace caret { // ADD_NEW_MEMBERS_HERE - friend class ChartOverlay; + friend class ChartTwoOverlay; }; -#ifdef __CHART_OVERLAY_SET_DECLARE__ +#ifdef __CHART_TWO_OVERLAY_SET_DECLARE__ // -#endif // __CHART_OVERLAY_SET_DECLARE__ +#endif // __CHART_TWO_OVERLAY_SET_DECLARE__ } // namespace -#endif //__CHART_OVERLAY_SET_H__ +#endif //__CHART_TWO_OVERLAY_SET_H__ diff --git a/src/Brain/ChartOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx similarity index 83% rename from src/Brain/ChartOverlaySetArray.cxx rename to src/Brain/ChartTwoOverlaySetArray.cxx index 2a948ac36..b24ccbe4a 100644 --- a/src/Brain/ChartOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -19,13 +19,13 @@ */ /*LICENSE_END*/ -#define __OVERLAY_SET_ARRAY_DECLARE__ -#include "ChartOverlaySetArray.h" -#undef __OVERLAY_SET_ARRAY_DECLARE__ +#define __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ +#include "ChartTwoOverlaySetArray.h" +#undef __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ #include "BrainConstants.h" #include "CaretAssert.h" -#include "ChartOverlaySet.h" +#include "ChartTwoOverlaySet.h" #include "EventBrowserTabDelete.h" #include "EventManager.h" #include "SceneClass.h" @@ -35,7 +35,7 @@ using namespace caret; /** - * \class caret::ChartOverlaySetArray + * \class caret::ChartTwoOverlaySetArray * \brief Maintains an array of chart overlay sets for use with a model * \ingroup Brain */ @@ -49,7 +49,7 @@ using namespace caret; * Name of model using this chart overlay set. This name is displayed * if there is an attempt to yoke models with incompatible chart overlays. */ -ChartOverlaySetArray::ChartOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, +ChartTwoOverlaySetArray::ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name) : CaretObject(), EventListenerInterface(), @@ -58,7 +58,7 @@ m_name(name) { m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t tabIndex = 0; tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; tabIndex++) { - m_chartOverlaySets[tabIndex] = new ChartOverlaySet(chartDataType, + m_chartOverlaySets[tabIndex] = new ChartTwoOverlaySet(chartDataType, name, tabIndex); } @@ -69,11 +69,11 @@ m_name(name) /** * Destructor. */ -ChartOverlaySetArray::~ChartOverlaySetArray() +ChartTwoOverlaySetArray::~ChartTwoOverlaySetArray() { EventManager::get()->removeAllEventsFromListener(this); - for (std::vector::iterator iter =m_chartOverlaySets.begin(); + for (std::vector::iterator iter =m_chartOverlaySets.begin(); iter !=m_chartOverlaySets.end(); iter++) { delete *iter; @@ -86,16 +86,16 @@ ChartOverlaySetArray::~ChartOverlaySetArray() * @return String describing this object's content. */ AString -ChartOverlaySetArray::toString() const +ChartTwoOverlaySetArray::toString() const { - return "ChartOverlaySetArray"; + return "ChartTwoOverlaySetArray"; } /** * @return The number of chart overlay sets. */ int32_t -ChartOverlaySetArray::getNumberOfChartOverlaySets() +ChartTwoOverlaySetArray::getNumberOfChartOverlaySets() { return m_chartOverlaySets.size(); } @@ -108,8 +108,8 @@ ChartOverlaySetArray::getNumberOfChartOverlaySets() * @return * Overlay set at given index. */ -ChartOverlaySet* -ChartOverlaySetArray::getChartOverlaySet(const int32_t tabIndex) +ChartTwoOverlaySet* +ChartTwoOverlaySetArray::getChartOverlaySet(const int32_t tabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); @@ -120,7 +120,7 @@ ChartOverlaySetArray::getChartOverlaySet(const int32_t tabIndex) * Initialize the chart overlay selections. */ void -ChartOverlaySetArray::initializeOverlaySelections() +ChartTwoOverlaySetArray::initializeOverlaySelections() { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { CaretAssertVectorIndex(m_chartOverlaySets, iTab); @@ -136,7 +136,7 @@ ChartOverlaySetArray::initializeOverlaySelections() * An event for which this instance is listening. */ void -ChartOverlaySetArray::receiveEvent(Event* event) +ChartTwoOverlaySetArray::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { EventBrowserTabDelete* deleteTabEvent = dynamic_cast(event); @@ -165,14 +165,14 @@ ChartOverlaySetArray::receiveEvent(Event* event) * Destination to which tab content is copied. */ void -ChartOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, +ChartTwoOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, sourceTabIndex); CaretAssertVectorIndex(m_chartOverlaySets, destinationTabIndex); - const ChartOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; - ChartOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; + const ChartTwoOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; + ChartTwoOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; destinationChartOverlaySet->copyOverlaySet(sourceChartOverlaySet); } @@ -188,11 +188,11 @@ ChartOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, * Name of instance in the scene. */ SceneClass* -ChartOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, - "ChartOverlaySetArray", + "ChartTwoOverlaySetArray", 1); const int32_t numOverlaySetsToSave = getNumberOfChartOverlaySets(); @@ -226,7 +226,7 @@ ChartOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, * sceneClass from which model specific information is obtained. */ void -ChartOverlaySetArray::restoreFromScene(const SceneAttributes* sceneAttributes, +ChartTwoOverlaySetArray::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { diff --git a/src/Brain/ChartOverlaySetArray.h b/src/Brain/ChartTwoOverlaySetArray.h similarity index 73% rename from src/Brain/ChartOverlaySetArray.h rename to src/Brain/ChartTwoOverlaySetArray.h index 5e134c25a..7dfa44d13 100644 --- a/src/Brain/ChartOverlaySetArray.h +++ b/src/Brain/ChartTwoOverlaySetArray.h @@ -1,5 +1,5 @@ -#ifndef __CHART_OVERLAY_SET_ARRAY_H__ -#define __CHART_OVERLAY_SET_ARRAY_H__ +#ifndef __CHART_TWO_OVERLAY_SET_ARRAY_H__ +#define __CHART_TWO_OVERLAY_SET_ARRAY_H__ /*LICENSE_START*/ /* @@ -28,19 +28,19 @@ #include "SceneableInterface.h" namespace caret { - class ChartOverlaySet; + class ChartTwoOverlaySet; - class ChartOverlaySetArray : public CaretObject, public EventListenerInterface, public SceneableInterface { + class ChartTwoOverlaySetArray : public CaretObject, public EventListenerInterface, public SceneableInterface { public: - ChartOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, + ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name); - virtual ~ChartOverlaySetArray(); + virtual ~ChartTwoOverlaySetArray(); int32_t getNumberOfChartOverlaySets(); - ChartOverlaySet* getChartOverlaySet(const int32_t indx); + ChartTwoOverlaySet* getChartOverlaySet(const int32_t indx); void initializeOverlaySelections(); @@ -53,9 +53,9 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: - ChartOverlaySetArray(const ChartOverlaySetArray&); + ChartTwoOverlaySetArray(const ChartTwoOverlaySetArray&); - ChartOverlaySetArray& operator=(const ChartOverlaySetArray&); + ChartTwoOverlaySetArray& operator=(const ChartTwoOverlaySetArray&); public: @@ -74,12 +74,12 @@ namespace caret { AString m_name; /** The chart overlay sets */ - std::vectorm_chartOverlaySets; + std::vectorm_chartOverlaySets; }; -#ifdef __OVERLAY_SET_ARRAY_DECLARE__ +#ifdef __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ // -#endif // __OVERLAY_SET_ARRAY_DECLARE__ +#endif // __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ } // namespace -#endif //__CHART_OVERLAY_SET_ARRAY_H__ +#endif //__CHART_TWO_OVERLAY_SET_ARRAY_H__ diff --git a/src/Brain/Model.cxx b/src/Brain/Model.cxx index bc5c53562..3d56b6623 100644 --- a/src/Brain/Model.cxx +++ b/src/Brain/Model.cxx @@ -124,7 +124,7 @@ Model::initializeSelectedSurfaces() * @return * Chart overlay set or NULL if not valid for this model. */ -ChartOverlaySet* +ChartTwoOverlaySet* Model::getChartOverlaySet(const int /*tabIndex*/) { return NULL; @@ -138,7 +138,7 @@ Model::getChartOverlaySet(const int /*tabIndex*/) * @return * Chart overlay set or NULL if not valid for this model. */ -const ChartOverlaySet* +const ChartTwoOverlaySet* Model::getChartOverlaySet(const int /*tabIndex*/) const { return NULL; diff --git a/src/Brain/Model.h b/src/Brain/Model.h index 872296a07..390824d7b 100644 --- a/src/Brain/Model.h +++ b/src/Brain/Model.h @@ -28,7 +28,7 @@ namespace caret { class Brain; - class ChartOverlaySet; + class ChartTwoOverlaySet; class OverlaySet; class PlainTextStringBuilder; @@ -67,9 +67,9 @@ namespace caret { virtual const OverlaySet* getOverlaySet(const int tabIndex) const = 0; - virtual ChartOverlaySet* getChartOverlaySet(const int tabIndex); + virtual ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex); - virtual const ChartOverlaySet* getChartOverlaySet(const int tabIndex) const; + virtual const ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex) const; virtual void initializeSelectedSurfaces(); diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 9808bf431..72aae679a 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -40,9 +40,10 @@ #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" -#include "ChartOverlay.h" -#include "ChartOverlaySet.h" -#include "ChartOverlaySetArray.h" +#include "ChartTwoMatrixDisplayProperties.h" +#include "ChartTwoOverlay.h" +#include "ChartTwoOverlaySet.h" +#include "ChartTwoOverlaySetArray.h" #include "ChartingVersionEnum.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" @@ -75,21 +76,22 @@ ModelChart::ModelChart(Brain* brain) Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); - m_histogramChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, + m_histogramChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, "Histogram Chart Overlays")); - m_matrixChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + m_matrixChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, "Matrix Chart Overlays")); - m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, "Line Series Chart Overlays")); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); + m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); } m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); - m_sceneAssistant->add("m_histogramChartOverlaySetArray", "ChartOverlaySetArray", m_histogramChartOverlaySetArray.get()); + m_sceneAssistant->add("m_histogramChartOverlaySetArray", "ChartTwoOverlaySetArray", m_histogramChartOverlaySetArray.get()); initializeCharts(); @@ -113,6 +115,9 @@ ModelChart::~ModelChart() delete m_chartableMatrixSeriesFileSelectionModel[i]; m_chartableMatrixSeriesFileSelectionModel[i] = NULL; + + delete m_chartTwoMatrixDisplayProperties[i]; + m_chartTwoMatrixDisplayProperties[i] = NULL; } } @@ -750,7 +755,7 @@ ModelChart::initializeOverlays() } /** - * Save information specific to this type of model to the scene. + * Save version one charting information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types @@ -760,13 +765,10 @@ ModelChart::initializeOverlays() * @param sceneClass * SceneClass to which model specific information is added. */ -void -ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) +void +ModelChart::saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) { - sceneClass->addEnumeratedType("chartingVersion", - ChartingVersionEnum::CHARTING_VERSION_TWO); - std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); std::set validChartDataIDs; @@ -776,9 +778,9 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr validChartDataIDs); sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", - m_selectedChartOneDataType, - tabIndices); - + m_selectedChartOneDataType, + tabIndices); + /* * Save matrix chart models to scene. */ @@ -800,7 +802,7 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr * Save matrix series chart models to scene. */ SceneObjectMapIntegerKey* matrixSeriesSceneMap = new SceneObjectMapIntegerKey("chartableMatrixSeriesFileSelectionModelMap", - SceneObjectDataTypeEnum::SCENE_CLASS); + SceneObjectDataTypeEnum::SCENE_CLASS); std::vector matrixSeriesSelectionVector; for (std::vector::const_iterator tabIter = tabIndices.begin(); @@ -809,11 +811,61 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr const int32_t tabIndex = *tabIter; matrixSeriesSceneMap->addClass(tabIndex, m_chartableMatrixSeriesFileSelectionModel[tabIndex]->saveToScene(sceneAttributes, - "m_chartableMatrixSeriesFileSelectionModel")); + "m_chartableMatrixSeriesFileSelectionModel")); } sceneClass->addChild(matrixSeriesSceneMap); } +/** + * Save version two charting information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param sceneClass + * SceneClass to which model specific information is added. + */ +void +ModelChart::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + CaretAssertToDoFatal(); +} + + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param sceneClass + * SceneClass to which model specific information is added. + */ +void +ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + const ChartingVersionEnum::Enum chartingVersion = ChartingVersionEnum::CHARTING_VERSION_TWO; + sceneClass->addEnumeratedType("chartingVersion", + chartingVersion); + + switch (chartingVersion) { + case ChartingVersionEnum::CHARTING_VERSION_ONE: + saveVersionOneModelSpecificInformationToScene(sceneAttributes, + sceneClass); + break; + case ChartingVersionEnum::CHARTING_VERSION_TWO: + saveVersionTwoModelSpecificInformationToScene(sceneAttributes, + sceneClass); + break; + } +} + /** * Restore information specific to the type of model from the scene. * @@ -924,41 +976,7 @@ ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttrib */ restoreVersionTwoChartModelsFromScene(sceneAttributes, sceneClass); - - sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", - m_selectedChartOneDataType); - - /* - * Restore matrix chart models from scene. - */ - const SceneObjectMapIntegerKey* matrixSceneMap = sceneClass->getMapIntegerKey("chartableMatrixFileSelectionModelMap"); - if (matrixSceneMap != NULL) { - const std::vector tabIndices = matrixSceneMap->getKeys(); - for (std::vector::const_iterator tabIter = tabIndices.begin(); - tabIter != tabIndices.end(); - tabIter++) { - const int32_t tabIndex = *tabIter; - const SceneClass* sceneClass = matrixSceneMap->classValue(tabIndex); - m_chartableMatrixFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); - } - } - - /* - * Restore matrix chart series models from scene. - */ - const SceneObjectMapIntegerKey* matrixSeriesSceneMap = sceneClass->getMapIntegerKey("chartableMatrixSeriesFileSelectionModelMap"); - if (matrixSeriesSceneMap != NULL) { - const std::vector tabIndices = matrixSeriesSceneMap->getKeys(); - for (std::vector::const_iterator tabIter = tabIndices.begin(); - tabIter != tabIndices.end(); - tabIter++) { - const int32_t tabIndex = *tabIter; - const SceneClass* sceneClass = matrixSeriesSceneMap->classValue(tabIndex); - m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); - } - } + CaretAssertToDoFatal(); } /** @@ -1993,7 +2011,7 @@ ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const * Type of data for chart. */ void -ModelChart::setSelectedChartDataType(const int32_t tabIndex, +ModelChart::setSelectedChartTwoDataType(const int32_t tabIndex, const ChartTwoDataTypeEnum::Enum dataType) { CaretAssertArrayIndex(m_selectedChartTwoDataType, @@ -2009,7 +2027,7 @@ ModelChart::setSelectedChartDataType(const int32_t tabIndex, * Output containing valid chart data types. */ void -ModelChart::getValidChartDataTypes(std::vector& validChartDataTypesOut) const +ModelChart::getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); @@ -2046,7 +2064,7 @@ ModelChart::getValidChartDataTypes(std::vector& vali * Chart type in the given tab. */ ChartTwoDataTypeEnum::Enum -ModelChart::getSelectedChartDataType(const int32_t tabIndex) const +ModelChart::getSelectedChartTwoDataType(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedChartDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, @@ -2054,7 +2072,7 @@ ModelChart::getSelectedChartDataType(const int32_t tabIndex) const ChartTwoDataTypeEnum::Enum chartDataType = m_selectedChartTwoDataType[tabIndex]; std::vector validChartDataTypes; - getValidChartDataTypes(validChartDataTypes); + getValidChartTwoDataTypes(validChartDataTypes); /* * Test if selected chart type is still valid @@ -2381,6 +2399,36 @@ ModelChart::getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex) return m_chartableMatrixSeriesFileSelectionModel[tabIndex]; } +/** + * @return The chart matrix display properties for the given tab. + * + * @param tabIndex + * The tab index. + */ +ChartTwoMatrixDisplayProperties* +ModelChart::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) +{ + CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_chartTwoMatrixDisplayProperties[tabIndex]; +} + +/** + * @return The chart matrix display properties for the given tab. + * + * @param tabIndex + * The tab index. + */ +const ChartTwoMatrixDisplayProperties* +ModelChart::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_chartTwoMatrixDisplayProperties[tabIndex]; +} + /** * Get the chart overlay set for this model. * @@ -2389,12 +2437,12 @@ ModelChart::getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex) * @return * Chart overlay set or NULL if not valid for this model. */ -ChartOverlaySet* +ChartTwoOverlaySet* ModelChart::getChartOverlaySet(const int tabIndex) { - ChartOverlaySet* chartOverlaySet = NULL; + ChartTwoOverlaySet* chartOverlaySet = NULL; - switch (getSelectedChartDataType(tabIndex)) { + switch (getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: @@ -2419,12 +2467,12 @@ ModelChart::getChartOverlaySet(const int tabIndex) * @return * Chart overlay set or NULL if not valid for this model. */ -const ChartOverlaySet* +const ChartTwoOverlaySet* ModelChart::getChartOverlaySet(const int tabIndex) const { ModelChart* nonConstModelChart = const_cast(this); CaretAssert(nonConstModelChart); - const ChartOverlaySet* chartOverlaySet = nonConstModelChart->getChartOverlaySet(tabIndex); + const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartOverlaySet(tabIndex); return chartOverlaySet; } diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 1f45479ec..2e269152a 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -49,7 +49,8 @@ namespace caret { class ChartModelDataSeries; class ChartModelFrequencySeries; class ChartModelTimeSeries; - class ChartOverlaySetArray; + class ChartTwoMatrixDisplayProperties; + class ChartTwoOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; class OverlaySetArray; @@ -89,9 +90,13 @@ namespace caret { const OverlaySet* getOverlaySet(const int tabIndex) const; - virtual ChartOverlaySet* getChartOverlaySet(const int tabIndex); + ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex); - virtual const ChartOverlaySet* getChartOverlaySet(const int tabIndex) const; + const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const; + + virtual ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex); + + virtual const ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex) const; virtual void receiveEvent(Event* event); @@ -102,11 +107,11 @@ namespace caret { void setSelectedChartOneDataType(const int32_t tabIndex, const ChartOneDataTypeEnum::Enum dataType); - void getValidChartDataTypes(std::vector& validChartDataTypesOut) const; + void getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const; - ChartTwoDataTypeEnum::Enum getSelectedChartDataType(const int32_t tabIndex) const; + ChartTwoDataTypeEnum::Enum getSelectedChartTwoDataType(const int32_t tabIndex) const; - void setSelectedChartDataType(const int32_t tabIndex, + void setSelectedChartTwoDataType(const int32_t tabIndex, const ChartTwoDataTypeEnum::Enum dataType); ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex); @@ -179,6 +184,12 @@ namespace caret { ChartData* loadCartesianChartWhenRestoringScene(const ChartData* chartData); + virtual void saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + void restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); @@ -189,14 +200,16 @@ namespace caret { OverlaySetArray* m_overlaySetArray; /** Chart Overlay sets for XX data type */ - std::unique_ptr m_histogramChartOverlaySetArray; + std::unique_ptr m_histogramChartOverlaySetArray; /** Chart Overlay sets for XX data type */ - std::unique_ptr m_lineSeriesChartOverlaySetArray; + std::unique_ptr m_lineSeriesChartOverlaySetArray; /** Chart Overlay sets for XX data type */ - std::unique_ptr m_matrixChartOverlaySetArray; + std::unique_ptr m_matrixChartOverlaySetArray; + ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; mutable ChartOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 633db68c4..f6978bfcd 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -46,6 +46,7 @@ ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h +ChartTwoMatrixDisplayProperties.h ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h @@ -80,6 +81,7 @@ ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx +ChartTwoMatrixDisplayProperties.cxx ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx ) diff --git a/src/Charting/ChartTwoMatrixDisplayProperties.cxx b/src/Charting/ChartTwoMatrixDisplayProperties.cxx new file mode 100644 index 000000000..62c4e6539 --- /dev/null +++ b/src/Charting/ChartTwoMatrixDisplayProperties.cxx @@ -0,0 +1,295 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ +#include "ChartTwoMatrixDisplayProperties.h" +#undef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ + +#include "CaretAssert.h" +#include "EventManager.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoMatrixDisplayProperties + * \brief Display properties for version two of Matrix charting. + * \ingroup Charting + */ + +/** + * Constructor. + */ +ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties() +: CaretObject() +{ + initializeInstance(); +} + +/** + * Destructor. + */ +ChartTwoMatrixDisplayProperties::~ChartTwoMatrixDisplayProperties() +{ + EventManager::get()->removeAllEventsFromListener(this); + delete m_sceneAssistant; +} + +/** + * Initialize a new instance of this class. + */ +void +ChartTwoMatrixDisplayProperties::initializeInstance() +{ + resetPropertiesToDefault(); + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_cellPercentageZoomWidth", + &m_cellPercentageZoomWidth); + m_sceneAssistant->add("m_cellPercentageZoomHeight", + &m_cellPercentageZoomHeight); + m_sceneAssistant->add("m_displayGridLinesFlag", + &m_displayGridLinesFlag); + m_sceneAssistant->add("m_highlightSelectedRowColumnFlag", + &m_highlightSelectedRowColumnFlag); + + // EventManager::get()->addEventListener(this, EventTypeEnum::); +} + + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj) +: CaretObject(obj) +{ + initializeInstance(); + + this->copyHelperChartTwoMatrixDisplayProperties(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoMatrixDisplayProperties& +ChartTwoMatrixDisplayProperties::operator=(const ChartTwoMatrixDisplayProperties& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperChartTwoMatrixDisplayProperties(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoMatrixDisplayProperties::copyHelperChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj) +{ + m_cellPercentageZoomWidth = obj.m_cellPercentageZoomWidth; + m_cellPercentageZoomHeight = obj.m_cellPercentageZoomHeight; + m_displayGridLinesFlag = obj.m_displayGridLinesFlag; + m_highlightSelectedRowColumnFlag = obj.m_highlightSelectedRowColumnFlag; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartTwoMatrixDisplayProperties::toString() const +{ + return "ChartTwoMatrixDisplayProperties"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartTwoMatrixDisplayProperties::receiveEvent(Event* event) +{ +} + +/** + * Reset the display properties to their default values. + */ +void +ChartTwoMatrixDisplayProperties::resetPropertiesToDefault() +{ + m_cellPercentageZoomWidth = 100.0; + m_cellPercentageZoomHeight = 100.0; + m_highlightSelectedRowColumnFlag = true; + m_displayGridLinesFlag = true; +} + +/** + * @return Display grid lines status. + */ +bool +ChartTwoMatrixDisplayProperties::isGridLinesDisplayed() const +{ + return m_displayGridLinesFlag; +} + +/** + * Set the grid lines display status. + * + * @param displayGridLines + * New status for display of grid lines. + */ +void +ChartTwoMatrixDisplayProperties::setGridLinesDisplayed(const bool displayGridLines) +{ + m_displayGridLinesFlag = displayGridLines; +} + +/** + * @return highlight selected row/column status. + */ +bool +ChartTwoMatrixDisplayProperties::isSelectedRowColumnHighlighted() const +{ + return m_highlightSelectedRowColumnFlag; +} + +/** + * Set the row/column highlighting status. + * + * @param highlightStatus + * New highlighting status. + */ +void +ChartTwoMatrixDisplayProperties::setSelectedRowColumnHighlighted(const bool highlightStatus) +{ + m_highlightSelectedRowColumnFlag = highlightStatus; +} + +/** + * @return The cell percentage zoom width. + */ +float +ChartTwoMatrixDisplayProperties::getCellPercentageZoomWidth() const +{ + return m_cellPercentageZoomWidth; +} + +/** + * Set the cell percentage zoom width. + * + * @param cellPercentageZoomWidth + * New value for cell percentage zoom width. + */ +void +ChartTwoMatrixDisplayProperties::setCellPercentageZoomWidth(const float cellPercentageZoomWidth) +{ + m_cellPercentageZoomWidth = cellPercentageZoomWidth; +} + +/** + * @return The cell percentage zoom height. + */ +float +ChartTwoMatrixDisplayProperties::getCellPercentageZoomHeight() const +{ + return m_cellPercentageZoomHeight; +} + +/** + * Set the cell percentage zoom height. + * + * @param cellPercentageZoomHeight + * New value for cell percentage zoom height. + */ +void ChartTwoMatrixDisplayProperties::setCellPercentageZoomHeight(const float cellPercentageZoomHeight) +{ + m_cellPercentageZoomHeight = cellPercentageZoomHeight; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoMatrixDisplayProperties::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoMatrixDisplayProperties", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoMatrixDisplayProperties::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Charting/ChartTwoMatrixDisplayProperties.h b/src/Charting/ChartTwoMatrixDisplayProperties.h new file mode 100644 index 000000000..19a9c75e5 --- /dev/null +++ b/src/Charting/ChartTwoMatrixDisplayProperties.h @@ -0,0 +1,114 @@ +#ifndef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ +#define __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +#include "EventListenerInterface.h" +#include "SceneableInterface.h" + + +namespace caret { + class SceneClassAssistant; + + class ChartTwoMatrixDisplayProperties : public CaretObject, public EventListenerInterface, public SceneableInterface { + + public: + ChartTwoMatrixDisplayProperties(); + + virtual ~ChartTwoMatrixDisplayProperties(); + + ChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj); + + ChartTwoMatrixDisplayProperties& operator=(const ChartTwoMatrixDisplayProperties& obj); + + bool isGridLinesDisplayed() const; + + void setGridLinesDisplayed(const bool displayGridLines); + + void resetPropertiesToDefault(); + + bool isSelectedRowColumnHighlighted() const; + + void setSelectedRowColumnHighlighted(const bool highlightStatus); + + float getCellPercentageZoomWidth() const; + + void setCellPercentageZoomWidth(const float cellPercentageZoomWidth); + + float getCellPercentageZoomHeight() const; + + void setCellPercentageZoomHeight(const float cellPercentageZoomHeight); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj); + + void initializeInstance(); + + SceneClassAssistant* m_sceneAssistant; + + float m_cellPercentageZoomHeight; + + float m_cellPercentageZoomWidth; + + bool m_highlightSelectedRowColumnFlag; + + bool m_displayGridLinesFlag; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ + // +#endif // __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ + +} // namespace +#endif //__CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 0a8d3414b..b5027158a 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -454,7 +454,7 @@ AnnotationCoordinateWidget::valueChanged() if (updateUserInterfaceFlag) { EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, m_browserWindowIndex, - (ChartOverlay*)NULL, + (ChartTwoOverlay*)NULL, NULL, -1).getPointer()); } diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index 1d5bb9ff6..b85ba76d7 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -38,7 +38,7 @@ #include "CaretDataFile.h" #include "CaretPreferences.h" #include "ChartableLineSeriesBrainordinateInterface.h" -#include "ChartOverlaySetViewController.h" +#include "ChartTwoOverlaySetViewController.h" #include "ChartableMatrixInterface.h" #include "ChartToolBoxViewController.h" #include "CiftiConnectivityMatrixViewController.h" @@ -150,7 +150,7 @@ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32 "Layers"); } if (isOverlayToolBox) { - m_chartOverlaySetViewController = new ChartOverlaySetViewController(orientation, + m_chartOverlaySetViewController = new ChartTwoOverlaySetViewController(orientation, browserWindowIndex, this); m_chartOverlayTabIndex = addToTabWidget(m_chartOverlaySetViewController, diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h index 8df423c23..727f5b9e4 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.h +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.h @@ -33,7 +33,7 @@ class QTabWidget; namespace caret { class AnnotationSelectionViewController; class BorderSelectionViewController; - class ChartOverlaySetViewController; + class ChartTwoOverlaySetViewController; class ChartToolBoxViewController; class CiftiConnectivityMatrixViewController; class FiberOrientationSelectionViewController; @@ -86,7 +86,7 @@ namespace caret { BorderSelectionViewController* m_borderSelectionViewController; - ChartOverlaySetViewController* m_chartOverlaySetViewController; + ChartTwoOverlaySetViewController* m_chartOverlaySetViewController; CiftiConnectivityMatrixViewController* m_connectivityMatrixViewController; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 500299c69..264839d7d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -55,7 +55,8 @@ #include "BrainBrowserWindowToolBar.h" #include "BrainBrowserWindowToolBarChartAttributes.h" #include "BrainBrowserWindowToolBarChartAxes.h" -#include "BrainBrowserWindowToolBarChartOrientation.h" +#include "BrainBrowserWindowToolBarChartTwoAttributes.h" +#include "BrainBrowserWindowToolBarChartTwoOrientation.h" #include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" #include "BrainBrowserWindowToolBarClipping.h" @@ -333,7 +334,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->orientationWidget = this->createOrientationWidget(); this->chartAxesWidget = createChartAxesWidget(); this->chartAttributesWidget = createChartAttributesWidget(); - this->chartOrientationWidget = createChartOrientationWidget(); + this->chartTwoOrientationWidget = createChartTwoOrientationWidget(); + this->chartTwoAttributesWidget = createChartTwoAttributesWidget(); this->chartTypeWidget = createChartTypeWidget(); this->chartTypeTwoWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); @@ -376,7 +378,9 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolbarWidgetLayout->addWidget(this->chartAxesWidget, 0, Qt::AlignLeft); - this->toolbarWidgetLayout->addWidget(this->chartOrientationWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartTwoOrientationWidget, 0, Qt::AlignLeft); + + this->toolbarWidgetLayout->addWidget(this->chartTwoAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); @@ -1394,6 +1398,7 @@ BrainBrowserWindowToolBar::updateToolBar() bool showChartTwoTypeWidget = false; bool showChartOneAttributesWidget = false; bool showChartTwoOrientationWidget = false; + bool showChartTwoAttributesWidget = false; bool showModeWidget = true; bool showWindowWidget = true; @@ -1434,6 +1439,7 @@ BrainBrowserWindowToolBar::updateToolBar() if (modelChart != NULL) { if (m_chartingTwoFlag) { showChartTwoOrientationWidget = true; + showChartTwoAttributesWidget = true; } else { switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { @@ -1478,7 +1484,8 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartTypeTwoWidget->setVisible(false); this->chartAxesWidget->setVisible(false); this->chartAttributesWidget->setVisible(false); - this->chartOrientationWidget->setVisible(false); + this->chartTwoOrientationWidget->setVisible(false); + this->chartTwoAttributesWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); this->volumePlaneWidget->setVisible(false); this->volumeMontageWidget->setVisible(false); @@ -1494,7 +1501,8 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartTypeTwoWidget->setVisible(showChartTwoTypeWidget); this->chartAxesWidget->setVisible(showChartOneAxesWidget); this->chartAttributesWidget->setVisible(showChartOneAttributesWidget); - this->chartOrientationWidget->setVisible(showChartTwoOrientationWidget); + this->chartTwoOrientationWidget->setVisible(showChartTwoOrientationWidget); + this->chartTwoAttributesWidget->setVisible(showChartTwoAttributesWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); @@ -1556,7 +1564,8 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab this->updateChartTypeTwoWidget(browserTabContent); this->updateChartAxesWidget(browserTabContent); this->updateChartAttributesWidget(browserTabContent); - this->updateChartOrientationWidget(browserTabContent); + this->updateChartTwoOrientationWidget(browserTabContent); + this->updateChartTwoAttributesWidget(browserTabContent); this->updateVolumeMontageWidget(browserTabContent); this->updateVolumePlaneWidget(browserTabContent); this->updateModeWidget(browserTabContent); @@ -2798,17 +2807,17 @@ BrainBrowserWindowToolBar::updateChartAttributesWidget(BrowserTabContent* browse } /** - * Create the chart orientation widget. + * Create the chart two orientation widget. * * @return - * Widget containing the chart orientation. + * Widget containing the two chart orientation. */ QWidget* -BrainBrowserWindowToolBar::createChartOrientationWidget() +BrainBrowserWindowToolBar::createChartTwoOrientationWidget() { - m_chartOrientationToolBarComponent = new BrainBrowserWindowToolBarChartOrientation(this); + m_chartTwoOrientationToolBarComponent = new BrainBrowserWindowToolBarChartTwoOrientation(this); QWidget* w = this->createToolWidget("Chart
Orientation", - m_chartOrientationToolBarComponent, + m_chartTwoOrientationToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); @@ -2823,12 +2832,46 @@ BrainBrowserWindowToolBar::createChartOrientationWidget() * The active model display (may be NULL). */ void -BrainBrowserWindowToolBar::updateChartOrientationWidget(BrowserTabContent* browserTabContent) +BrainBrowserWindowToolBar::updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent) +{ + if (this->chartTwoOrientationWidget->isHidden()) { + return; + } + m_chartTwoOrientationToolBarComponent->updateContent(browserTabContent); +} + +/** + * Create the chart two attributes widget. + * + * @return + * Widget containing the chart two attributes. + */ +QWidget* +BrainBrowserWindowToolBar::createChartTwoAttributesWidget() +{ + this->m_chartTwoAttributesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAttributes(this); + QWidget* w = this->createToolWidget("Chart
Attributes", + this->m_chartTwoAttributesToolBarComponent, + WIDGET_PLACEMENT_LEFT, + WIDGET_PLACEMENT_TOP, + 100); + w->setVisible(false); + return w; +} + +/** + * Update the chart attributes widget. + * + * @param browserTabContent + * The active model display (may be NULL). + */ +void +BrainBrowserWindowToolBar::updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent) { - if (this->chartOrientationWidget->isHidden()) { + if (this->chartTwoAttributesWidget->isHidden()) { return; } - m_chartOrientationToolBarComponent->updateContent(browserTabContent); + m_chartTwoAttributesToolBarComponent->updateContent(browserTabContent); } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index b743e367e..b87c51e40 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -52,8 +52,9 @@ namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; - class BrainBrowserWindowToolBarChartOrientation; + class BrainBrowserWindowToolBarChartTwoOrientation; class BrainBrowserWindowToolBarChartTwoType; + class BrainBrowserWindowToolBarChartTwoAttributes; class BrainBrowserWindowToolBarChartType; class BrainBrowserWindowToolBarClipping; class BrainBrowserWindowToolBarSlicePlane; @@ -143,7 +144,8 @@ namespace caret { QAction* tabAspectRatioLockedAction); QWidget* createChartAxesWidget(); QWidget* createChartAttributesWidget(); - QWidget* createChartOrientationWidget(); + QWidget* createChartTwoOrientationWidget(); + QWidget* createChartTwoAttributesWidget(); QWidget* createChartTypeWidget(); QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); @@ -162,7 +164,8 @@ namespace caret { void updateSurfaceMontageOptionsWidget(BrowserTabContent* browserTabContent); void updateChartAxesWidget(BrowserTabContent* browserTabContent); void updateChartAttributesWidget(BrowserTabContent* browserTabContent); - void updateChartOrientationWidget(BrowserTabContent* browserTabContent); + void updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent); + void updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent); void updateChartTypeWidget(BrowserTabContent* browserTabContent); void updateChartTypeTwoWidget(BrowserTabContent* browserTabContent); void updateVolumeMontageWidget(BrowserTabContent* browserTabContent); @@ -190,7 +193,8 @@ namespace caret { QWidget* chartTypeTwoWidget; QWidget* chartAxesWidget; QWidget* chartAttributesWidget; - QWidget* chartOrientationWidget; + QWidget* chartTwoOrientationWidget; + QWidget* chartTwoAttributesWidget; WuQWidgetObjectGroup* viewWidgetGroup; WuQWidgetObjectGroup* orientationWidgetGroup; @@ -361,7 +365,8 @@ namespace caret { BrainBrowserWindowToolBarChartTwoType* m_chartTwoTypeToolBarComponent; BrainBrowserWindowToolBarChartType* m_chartTypeToolBarComponent; BrainBrowserWindowToolBarChartAttributes* m_chartAttributesToolBarComponent; - BrainBrowserWindowToolBarChartOrientation* m_chartOrientationToolBarComponent; + BrainBrowserWindowToolBarChartTwoOrientation* m_chartTwoOrientationToolBarComponent; + BrainBrowserWindowToolBarChartTwoAttributes* m_chartTwoAttributesToolBarComponent; BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; BrainBrowserWindowToolBarClipping* m_clippingToolBarComponent; @@ -395,7 +400,8 @@ namespace caret { private: friend class BrainBrowserWindow; friend class BrainBrowserWindowToolBarChartAxes; - friend class BrainBrowserWindowToolBarChartOrientation; + friend class BrainBrowserWindowToolBarChartTwoOrientation; + friend class BrainBrowserWindowToolBarChartTwoAttributes; friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; friend class BrainBrowserWindowToolBarClipping; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx new file mode 100644 index 000000000..e686f97be --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -0,0 +1,512 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include +#include +#include +#include +#include + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ +#include "BrainBrowserWindowToolBarChartTwoAttributes.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ + +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretDataFile.h" +#include "CaretDataFileSelectionModel.h" +#include "EnumComboBoxTemplate.h" +#include "CaretMappableDataFile.h" +#include "CaretMappableDataFileAndMapSelectionModel.h" +#include "ChartTwoMatrixDisplayProperties.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "ModelChart.h" +#include "WuQFactory.h" +#include "WuQWidgetObjectGroup.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarChartTwoAttributes + * \brief Controls for chart attributes. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parentToolBar + * The parent toolbar. + */ +BrainBrowserWindowToolBarChartTwoAttributes::BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar) +: BrainBrowserWindowToolBarComponent(parentToolBar) +{ + m_cartesianChartAttributesWidget = new CartesianChartTwoAttributesWidget(this); + + m_matrixChartTwoAttributesWidget = new MatrixChartTwoAttributesWidget(this); + + m_stackedWidget = new QStackedWidget(); + m_stackedWidget->addWidget(m_cartesianChartAttributesWidget); + m_stackedWidget->addWidget(m_matrixChartTwoAttributesWidget); + + QVBoxLayout* layout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); + layout->addWidget(m_stackedWidget); + layout->addStretch(); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarChartTwoAttributes::~BrainBrowserWindowToolBarChartTwoAttributes() +{ +} + +/** + * Update content of this tool bar component. + * + * @param browserTabContent + * Content of the browser tab. + */ +void +BrainBrowserWindowToolBarChartTwoAttributes::updateContent(BrowserTabContent* browserTabContent) +{ + if (browserTabContent != NULL) { + ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + const int32_t tabIndex = browserTabContent->getTabNumber(); + if (modelChart != NULL) { + switch (modelChart->getSelectedChartTwoDataType(tabIndex)) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + m_stackedWidget->setCurrentWidget(m_matrixChartTwoAttributesWidget); + m_matrixChartTwoAttributesWidget->updateContent(); + break; + } + } + } + +// ChartModelCartesian* cartesianChart = getCartesianChart(); +// ChartTwoMatrixDisplayProperties* matrixProperties = getChartableMatrixDisplayProperties(); +// +// if (cartesianChart != NULL) { +// m_stackedWidget->setCurrentWidget(m_cartesianChartAttributesWidget); +// m_cartesianChartAttributesWidget->updateContent(); +// m_stackedWidget->setEnabled(true); +// } +// else if (matrixProperties) { +// m_stackedWidget->setCurrentWidget(m_matrixChartAttributesWidget); +// m_matrixChartAttributesWidget->updateContent(); +// m_stackedWidget->setEnabled(true); +// } +// else { +// m_stackedWidget->setEnabled(false); +// } +} + +///** +// * @return Cartesian chart in this widget. Returned value will +// * be NULL if the chart (or no chart) is not a Cartesian Chart. +// */ +//ChartModelCartesian* +//BrainBrowserWindowToolBarChartTwoAttributes::getCartesianChart() +//{ +// ChartModelCartesian* cartesianChart = NULL; +// +// BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); +// if (browserTabContent != NULL) { +// ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); +// +// if (modelChart != NULL) { +// const int32_t tabIndex = browserTabContent->getTabNumber(); +// const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); +// +// switch (chartType) { +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); +// break; +// } +// } +// } +// +// return cartesianChart; +//} + +/** + * @return Matrix chart interface in this widget. Returned value will + * be NULL if the chart (or no chart) is not a Matrix Chart. + */ +ChartTwoMatrixDisplayProperties* +BrainBrowserWindowToolBarChartTwoAttributes::getChartableTwoMatrixDisplayProperties() +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = NULL; + + BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); + if (browserTabContent != NULL) { + ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + matrixDisplayProperties = modelChart->getChartTwoMatrixDisplayProperties(browserTabContent->getTabNumber()); +// +// if (modelChart != NULL) { +// const int32_t tabIndex = browserTabContent->getTabNumber(); +// const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); +// +// switch (chartType) { +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// { +// ChartableMatrixInterface* matrixInterface = modelChart->getChartableMatrixParcelFileSelectionModel(tabIndex)->getSelectedFileOfType(); +// if (matrixInterface != NULL) { +// matrixDisplayProperties = matrixInterface->getChartTwoMatrixDisplayProperties(tabIndex); +// } +// } +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// { +// CaretDataFileSelectionModel* fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(tabIndex); +// CaretDataFile* caretFile = fileModel->getSelectedFile(); +// if (caretFile != NULL) { +// ChartableMatrixInterface* matrixInterface = dynamic_cast(caretFile); +// if (matrixInterface != NULL) { +// matrixDisplayProperties = matrixInterface->getChartTwoMatrixDisplayProperties(tabIndex); +// } +// } +// } +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// break; +// } +// } + } + + return matrixDisplayProperties; +} + + +/** + * Update the graphics. + */ +void +BrainBrowserWindowToolBarChartTwoAttributes::updateGraphics() +{ + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + + + + +/* ===========================================================================*/ + +/** + * \class caret::CartesianChartTwoAttributesWidget + * \brief Controls for cartesian chart attributes. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param brainBrowserWindowToolBarChartAttributes + * The parent attributes widget. + */ +CartesianChartTwoAttributesWidget::CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes) +: QWidget(brainBrowserWindowToolBarChartAttributes) +{ + m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; + + QLabel* cartesianLineWidthLabel = new QLabel("Line width "); + m_cartesianLineWidthDoubleSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, + 10000.0, + 0.1, + 1, + this, + SLOT(cartesianLineWidthValueChanged(double))); + m_cartesianLineWidthDoubleSpinBox->setFixedWidth(65); + + QGridLayout* gridLayout = new QGridLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(0, 100); + gridLayout->addWidget(cartesianLineWidthLabel, 0, 0); + gridLayout->addWidget(m_cartesianLineWidthDoubleSpinBox, 0, 1); + + this->setFixedSize(this->sizeHint()); +} + +/** + * Destructor. + */ +CartesianChartTwoAttributesWidget::~CartesianChartTwoAttributesWidget() +{ + +} + +/** + * Update the content of this widget. + */ +void +CartesianChartTwoAttributesWidget::updateContent() +{ +// ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); +// if (chart != NULL) { +// m_cartesianLineWidthDoubleSpinBox->blockSignals(true); +// m_cartesianLineWidthDoubleSpinBox->setValue(chart->getLineWidth()); +// m_cartesianLineWidthDoubleSpinBox->blockSignals(false); +// } +} + +/** + * Called when the cartesian line width is changed. + * + * @param value + * New value for line width. + */ +void +CartesianChartTwoAttributesWidget::cartesianLineWidthValueChanged(double value) +{ +// ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); +// if (chart != NULL) { +// chart->setLineWidth(value); +// +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// } +} + + + + +/* ===========================================================================*/ + + + +/** + * \class caret::MatrixChartTwoAttributesWidget + * \brief Controls for matrix chart attributes. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param brainBrowserWindowToolBarChartAttributes + * The parent attributes widget. + */ +MatrixChartTwoAttributesWidget::MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes) +: QWidget(brainBrowserWindowToolBarChartAttributes), +EventListenerInterface() +{ + m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; + + QLabel* cellWidthLabel = new QLabel("Cell Width"); + const float minPercent = 1.0; + const float maxPercent = 100000.0; + m_cellWidthPercentageSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minPercent, + maxPercent, + 1.0, + 1, + this, + SLOT(cellWidthPercentageSpinBoxValueChanged(double))); + m_cellWidthPercentageSpinBox->setKeyboardTracking(true); + m_cellWidthPercentageSpinBox->setSuffix("%"); + + QLabel* cellHeightLabel = new QLabel("Cell Height"); + m_cellHeightPercentageSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minPercent, + maxPercent, + 1.0, + 1, + this, + SLOT(cellHeightPercentageSpinBoxValueChanged(double))); + m_cellHeightPercentageSpinBox->setKeyboardTracking(true); + m_cellHeightPercentageSpinBox->setSuffix("%"); + + WuQtUtilities::matchWidgetWidths(m_cellHeightPercentageSpinBox, + m_cellWidthPercentageSpinBox); + + m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); + QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), + this, SLOT(highlightSelectionCheckBoxClicked(bool))); + + m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); + QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), + this, SLOT(displayGridLinesCheckBoxClicked(bool))); + + m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); + m_manualWidgetsGroup->add(m_cellWidthPercentageSpinBox); + m_manualWidgetsGroup->add(m_cellHeightPercentageSpinBox); + m_manualWidgetsGroup->add(m_displayGridLinesCheckBox); + + const int32_t COLUMN_LABEL = 0; + const int32_t COLUMN_WIDGET = 1; + + QGridLayout* gridLayout = new QGridLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); + int32_t rowIndex = gridLayout->rowCount(); + gridLayout->addWidget(cellWidthLabel, rowIndex, COLUMN_LABEL); + gridLayout->addWidget(m_cellWidthPercentageSpinBox, rowIndex, COLUMN_WIDGET); + rowIndex++; + gridLayout->addWidget(cellHeightLabel, rowIndex, COLUMN_LABEL); + gridLayout->addWidget(m_cellHeightPercentageSpinBox, rowIndex, COLUMN_WIDGET); + rowIndex++; + gridLayout->addWidget(m_highlightSelectionCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); + rowIndex++; + gridLayout->addWidget(m_displayGridLinesCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); + rowIndex++; + + this->setFixedSize(this->sizeHint()); +} + +/** + * Destructor. + */ +MatrixChartTwoAttributesWidget::~MatrixChartTwoAttributesWidget() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event. + * + * @param event + * The event. + */ +void +MatrixChartTwoAttributesWidget::receiveEvent(Event* event) +{ +} + + +/** + * Update the content of this widget. + */ +void +MatrixChartTwoAttributesWidget::updateContent() +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); + if (matrixDisplayProperties != NULL) { + m_cellWidthPercentageSpinBox->blockSignals(true); + m_cellWidthPercentageSpinBox->setValue(matrixDisplayProperties->getCellPercentageZoomWidth()); + m_cellWidthPercentageSpinBox->blockSignals(false); + + m_cellHeightPercentageSpinBox->blockSignals(true); + m_cellHeightPercentageSpinBox->setValue(matrixDisplayProperties->getCellPercentageZoomHeight()); + m_cellHeightPercentageSpinBox->blockSignals(false); + + m_highlightSelectionCheckBox->blockSignals(true); + m_highlightSelectionCheckBox->setChecked(matrixDisplayProperties->isSelectedRowColumnHighlighted()); + m_highlightSelectionCheckBox->blockSignals(false); + + m_displayGridLinesCheckBox->blockSignals(true); + m_displayGridLinesCheckBox->setChecked(matrixDisplayProperties->isGridLinesDisplayed()); + m_displayGridLinesCheckBox->blockSignals(false); + } +} + +/** + * Called when the cell width spin box value is changed. + * + * @param value + * New value for cell width. + */ +void +MatrixChartTwoAttributesWidget::cellWidthPercentageSpinBoxValueChanged(double value) +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); + if (matrixDisplayProperties != NULL) { + matrixDisplayProperties->setCellPercentageZoomWidth(value); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + } +} + +/** + * Called when the cell height spin box value is changed. + * + * @param value + * New value for cell height. + */ +void +MatrixChartTwoAttributesWidget::cellHeightPercentageSpinBoxValueChanged(double value) +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); + if (matrixDisplayProperties != NULL) { + matrixDisplayProperties->setCellPercentageZoomHeight(value); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + } +} + +/** + * Called when the show selection check box is checked. + * + * @param checked + * New checked status. + */ +void +MatrixChartTwoAttributesWidget::highlightSelectionCheckBoxClicked(bool checked) +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); + if (matrixDisplayProperties != NULL) { + matrixDisplayProperties->setSelectedRowColumnHighlighted(checked); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + } +} + +/** + * Called when the display grid lines check box is checked. + * + * @param checked + * New checked status. + */ +void +MatrixChartTwoAttributesWidget::displayGridLinesCheckBoxClicked(bool checked) +{ + ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); + if (matrixDisplayProperties != NULL) { + matrixDisplayProperties->setGridLinesDisplayed(checked); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + } +} + + diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h new file mode 100644 index 000000000..d72aed964 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h @@ -0,0 +1,143 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "BrainBrowserWindowToolBarComponent.h" +#include "EventListenerInterface.h" + +class QCheckBox; +class QDoubleSpinBox; +class QStackedWidget; + +namespace caret { + + class CartesianChartTwoAttributesWidget; + class ChartTwoMatrixDisplayProperties; + class EnumComboBoxTemplate; + class MatrixChartTwoAttributesWidget; + class WuQWidgetObjectGroup; + + class BrainBrowserWindowToolBarChartTwoAttributes : public BrainBrowserWindowToolBarComponent { + Q_OBJECT + + public: + BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar); + + virtual ~BrainBrowserWindowToolBarChartTwoAttributes(); + + virtual void updateContent(BrowserTabContent* browserTabContent); + + // ADD_NEW_METHODS_HERE + + private: + BrainBrowserWindowToolBarChartTwoAttributes(const BrainBrowserWindowToolBarChartTwoAttributes&); + + BrainBrowserWindowToolBarChartTwoAttributes& operator=(const BrainBrowserWindowToolBarChartTwoAttributes&); + + //ChartModelCartesian* getCartesianChart(); + + ChartTwoMatrixDisplayProperties* getChartableTwoMatrixDisplayProperties(); + + void updateGraphics(); + + CartesianChartTwoAttributesWidget* m_cartesianChartAttributesWidget; + + MatrixChartTwoAttributesWidget* m_matrixChartTwoAttributesWidget; + + QStackedWidget* m_stackedWidget; + + // ADD_NEW_MEMBERS_HERE + + friend class CartesianChartTwoAttributesWidget; + friend class MatrixChartTwoAttributesWidget; + }; + + /* + * While this should be a private class in the class above + * Qt's meta-object compiler (moc) does not allow it to be. + */ + class CartesianChartTwoAttributesWidget : public QWidget { + Q_OBJECT + + public: + CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes); + + ~CartesianChartTwoAttributesWidget(); + + virtual void updateContent(); + + private slots: + void cartesianLineWidthValueChanged(double value); + + private: + BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; + + QDoubleSpinBox* m_cartesianLineWidthDoubleSpinBox; + + }; + + /* + * While this should be a private class in the class above + * Qt's meta-object compiler (moc) does not allow it to be. + */ + class MatrixChartTwoAttributesWidget : public QWidget, public EventListenerInterface { + Q_OBJECT + + public: + MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes); + + ~MatrixChartTwoAttributesWidget(); + + virtual void receiveEvent(Event* event); + + virtual void updateContent(); + + private slots: + void cellWidthPercentageSpinBoxValueChanged(double value); + + void cellHeightPercentageSpinBoxValueChanged(double value); + + void highlightSelectionCheckBoxClicked(bool checked); + + void displayGridLinesCheckBoxClicked(bool checked); + + private: + BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; + + QDoubleSpinBox* m_cellWidthPercentageSpinBox; + + QDoubleSpinBox* m_cellHeightPercentageSpinBox; + + QCheckBox* m_highlightSelectionCheckBox; + + QCheckBox* m_displayGridLinesCheckBox; + + WuQWidgetObjectGroup* m_manualWidgetsGroup; + + }; +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx similarity index 88% rename from src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx rename to src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx index 0d29d9fe7..8e049c139 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ -#include "BrainBrowserWindowToolBarChartOrientation.h" -#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ +#include "BrainBrowserWindowToolBarChartTwoOrientation.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ #include #include @@ -40,7 +40,7 @@ using namespace caret; /** - * \class caret::BrainBrowserWindowToolBarChartOrientation + * \class caret::BrainBrowserWindowToolBarChartTwoOrientation * \brief Toolbar component for chart orientation. * \ingroup GuiQt */ @@ -48,7 +48,7 @@ using namespace caret; /** * Constructor. */ -BrainBrowserWindowToolBarChartOrientation::BrainBrowserWindowToolBarChartOrientation(BrainBrowserWindowToolBar* parentToolBar) +BrainBrowserWindowToolBarChartTwoOrientation::BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar) { m_orientationResetToolButtonAction = WuQtUtilities::createAction("Reset", @@ -89,7 +89,7 @@ BrainBrowserWindowToolBarChartOrientation::BrainBrowserWindowToolBarChartOrienta /** * Destructor. */ -BrainBrowserWindowToolBarChartOrientation::~BrainBrowserWindowToolBarChartOrientation() +BrainBrowserWindowToolBarChartTwoOrientation::~BrainBrowserWindowToolBarChartTwoOrientation() { EventManager::get()->removeAllEventsFromListener(this); } @@ -101,7 +101,7 @@ BrainBrowserWindowToolBarChartOrientation::~BrainBrowserWindowToolBarChartOrient * Content of the browser tab. */ void -BrainBrowserWindowToolBarChartOrientation::updateContent(BrowserTabContent* /*browserTabContent*/) +BrainBrowserWindowToolBarChartTwoOrientation::updateContent(BrowserTabContent* /*browserTabContent*/) { } @@ -109,7 +109,7 @@ BrainBrowserWindowToolBarChartOrientation::updateContent(BrowserTabContent* /*br * Called when orientation reset button is pressed. */ void -BrainBrowserWindowToolBarChartOrientation::orientationResetToolButtonTriggered(bool /*checked*/) +BrainBrowserWindowToolBarChartTwoOrientation::orientationResetToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->resetView(); @@ -121,7 +121,7 @@ BrainBrowserWindowToolBarChartOrientation::orientationResetToolButtonTriggered(b * Called when custom view is triggered and displays Custom View Menu. */ void -BrainBrowserWindowToolBarChartOrientation::customViewActionTriggered() +BrainBrowserWindowToolBarChartTwoOrientation::customViewActionTriggered() { m_parentToolBar->customViewActionTriggered(); // CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h similarity index 65% rename from src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h rename to src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h index c5427a7d0..6890f2700 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartOrientation.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h @@ -1,5 +1,5 @@ -#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ -#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ /*LICENSE_START*/ /* @@ -28,13 +28,13 @@ class QToolButton; namespace caret { - class BrainBrowserWindowToolBarChartOrientation : public BrainBrowserWindowToolBarComponent { + class BrainBrowserWindowToolBarChartTwoOrientation : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: - BrainBrowserWindowToolBarChartOrientation(BrainBrowserWindowToolBar* parentToolBar); + BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar); - virtual ~BrainBrowserWindowToolBarChartOrientation(); + virtual ~BrainBrowserWindowToolBarChartTwoOrientation(); virtual void updateContent(BrowserTabContent* browserTabContent); @@ -46,9 +46,9 @@ namespace caret { void orientationResetToolButtonTriggered(bool /*checked*/); private: - BrainBrowserWindowToolBarChartOrientation(const BrainBrowserWindowToolBarChartOrientation&); + BrainBrowserWindowToolBarChartTwoOrientation(const BrainBrowserWindowToolBarChartTwoOrientation&); - BrainBrowserWindowToolBarChartOrientation& operator=(const BrainBrowserWindowToolBarChartOrientation&); + BrainBrowserWindowToolBarChartTwoOrientation& operator=(const BrainBrowserWindowToolBarChartTwoOrientation&); QAction* m_orientationResetToolButtonAction; @@ -60,9 +60,9 @@ namespace caret { }; -#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ // -#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_DECLARE__ +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ } // namespace -#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ORIENTATION_H__ +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx index dea26ba7c..aaa1112a8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx @@ -107,7 +107,7 @@ BrainBrowserWindowToolBarChartTwoType::chartTypeRadioButtonClicked(int buttonInd BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelChart* chartModel = btc->getDisplayedChartModel(); const int32_t tabIndex = btc->getTabNumber(); - chartModel->setSelectedChartDataType(tabIndex, + chartModel->setSelectedChartTwoDataType(tabIndex, chartDataType); //updateContent(btc); @@ -131,10 +131,10 @@ BrainBrowserWindowToolBarChartTwoType::updateContent(BrowserTabContent* browserT const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartTwoDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartDataType(tabIndex); + const ChartTwoDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartTwoDataType(tabIndex); std::vector validChartDataTypes; - chartModel->getValidChartDataTypes(validChartDataTypes); + chartModel->getValidChartTwoDataTypes(validChartDataTypes); for (auto chartTypeButton : m_chartTypeRadioButtons) { ChartTwoDataTypeEnum::Enum chartType = chartTypeButton.first; diff --git a/src/GuiQt/BrainBrowserWindowToolBarComponent.h b/src/GuiQt/BrainBrowserWindowToolBarComponent.h index 9bdd62d3b..03496f2ec 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarComponent.h +++ b/src/GuiQt/BrainBrowserWindowToolBarComponent.h @@ -78,7 +78,7 @@ namespace caret { // ADD_NEW_MEMBERS_HERE - friend class BrainBrowserWindowToolBarChartOrientation; + friend class BrainBrowserWindowToolBarChartTwoOrientation; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index f1bd62dab..4f7a592ad 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -73,7 +73,8 @@ ELSE() BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h - BrainBrowserWindowToolBarChartOrientation.h + BrainBrowserWindowToolBarChartTwoOrientation.h + BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -97,8 +98,8 @@ ELSE() ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h - ChartOverlaySetViewController.h - ChartOverlayViewController.h + ChartTwoOverlaySetViewController.h + ChartTwoOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h @@ -258,7 +259,8 @@ BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h -BrainBrowserWindowToolBarChartOrientation.h +BrainBrowserWindowToolBarChartTwoOrientation.h +BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -282,8 +284,8 @@ ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h -ChartOverlaySetViewController.h -ChartOverlayViewController.h +ChartTwoOverlaySetViewController.h +ChartTwoOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h @@ -467,7 +469,8 @@ BrainBrowserWindowOrientedToolBox.cxx BrainBrowserWindowToolBar.cxx BrainBrowserWindowToolBarChartAttributes.cxx BrainBrowserWindowToolBarChartAxes.cxx -BrainBrowserWindowToolBarChartOrientation.cxx +BrainBrowserWindowToolBarChartTwoOrientation.cxx +BrainBrowserWindowToolBarChartTwoAttributes.cxx BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx @@ -491,8 +494,8 @@ ChartHistoryViewController.cxx ChartLinesSelectionViewController.cxx ChartMatrixParcelSelectionViewController.cxx ChartMatrixSeriesSelectionViewController.cxx -ChartOverlaySetViewController.cxx -ChartOverlayViewController.cxx +ChartTwoOverlaySetViewController.cxx +ChartTwoOverlayViewController.cxx ChartSelectionViewController.cxx ChartToolBoxViewController.cxx CiftiConnectivityMatrixViewController.cxx diff --git a/src/GuiQt/ChartOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx similarity index 89% rename from src/GuiQt/ChartOverlaySetViewController.cxx rename to src/GuiQt/ChartTwoOverlaySetViewController.cxx index b203deee5..5380b6b4d 100644 --- a/src/GuiQt/ChartOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -20,7 +20,7 @@ /*LICENSE_END*/ #define __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ -#include "ChartOverlaySetViewController.h" +#include "ChartTwoOverlaySetViewController.h" #undef __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ #include @@ -36,9 +36,9 @@ #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" -#include "ChartOverlay.h" -#include "ChartOverlaySet.h" -#include "ChartOverlayViewController.h" +#include "ChartTwoOverlay.h" +#include "ChartTwoOverlaySet.h" +#include "ChartTwoOverlayViewController.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" @@ -52,7 +52,7 @@ using namespace caret; /** - * \class caret::ChartOverlaySetViewController + * \class caret::ChartTwoOverlaySetViewController * \brief View controller for a chart overlay set * \ingroup GuiQt */ @@ -66,7 +66,7 @@ using namespace caret; * @param parent * Parent widget. */ -ChartOverlaySetViewController::ChartOverlaySetViewController(const Qt::Orientation orientation, +ChartTwoOverlaySetViewController::ChartTwoOverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), @@ -77,7 +77,7 @@ m_browserWindowIndex(browserWindowIndex) WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - ChartOverlayViewController* ovc = new ChartOverlayViewController(orientation, + ChartTwoOverlayViewController* ovc = new ChartTwoOverlayViewController(orientation, m_browserWindowIndex, i, this); @@ -143,7 +143,7 @@ m_browserWindowIndex(browserWindowIndex) for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { row = gridLayout->rowCount(); - ChartOverlayViewController* covc = m_chartOverlayViewControllers[i]; + ChartTwoOverlayViewController* covc = m_chartOverlayViewControllers[i]; WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; glg->addWidget(covc->m_enabledCheckBox, row, COLUMN_ON, Qt::AlignHCenter); @@ -197,7 +197,7 @@ m_browserWindowIndex(browserWindowIndex) row++; } - ChartOverlayViewController* covc = m_chartOverlayViewControllers[i]; + ChartTwoOverlayViewController* covc = m_chartOverlayViewControllers[i]; QLabel* fileLabel = new QLabel("File"); glg->addWidget(covc->m_enabledCheckBox, row, ROW_ONE_COLUMN_ON, Qt::AlignHCenter); @@ -240,7 +240,7 @@ m_browserWindowIndex(browserWindowIndex) /** * Destructor. */ -ChartOverlaySetViewController::~ChartOverlaySetViewController() +ChartTwoOverlaySetViewController::~ChartTwoOverlaySetViewController() { EventManager::get()->removeAllEventsFromListener(this); } @@ -252,7 +252,7 @@ ChartOverlaySetViewController::~ChartOverlaySetViewController() * An event for which this instance is listening. */ void -ChartOverlaySetViewController::receiveEvent(Event* event) +ChartTwoOverlaySetViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = @@ -272,9 +272,9 @@ ChartOverlaySetViewController::receiveEvent(Event* event) * Update this overlay set view controller using the given overlay set. */ void -ChartOverlaySetViewController::updateViewController() +ChartTwoOverlaySetViewController::updateViewController() { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet == NULL) { return; } @@ -283,7 +283,7 @@ ChartOverlaySetViewController::updateViewController() const int32_t numberOfDisplayedOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { - ChartOverlay* chartOverlay = NULL; + ChartTwoOverlay* chartOverlay = NULL; if (chartOverlaySet != NULL) { chartOverlay = chartOverlaySet->getOverlay(i); } @@ -297,7 +297,7 @@ ChartOverlaySetViewController::updateViewController() m_chartOverlayGridLayoutGroups[i]->setVisible(displayOverlay); } - const ChartOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); + const ChartTwoOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); if (primaryOverlay != NULL) { AString mapRowOrColumnName = "Map"; switch (primaryOverlay->getChartDataType()) { @@ -324,10 +324,10 @@ ChartOverlaySetViewController::updateViewController() /** * @return The overlay set in this view controller. */ -ChartOverlaySet* -ChartOverlaySetViewController::getChartOverlaySet() +ChartTwoOverlaySet* +ChartTwoOverlaySetViewController::getChartOverlaySet() { - ChartOverlaySet* chartOverlaySet = NULL; + ChartTwoOverlaySet* chartOverlaySet = NULL; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent != NULL) { @@ -343,9 +343,9 @@ ChartOverlaySetViewController::getChartOverlaySet() * Index of overlay that will have an overlay added above it. */ void -ChartOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) +ChartTwoOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayAbove(overlayIndex); this->updateColoringAndGraphics(); @@ -358,9 +358,9 @@ ChartOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex * Index of overlay that will have an overlay added below it. */ void -ChartOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) +ChartTwoOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayBelow(overlayIndex); this->updateColoringAndGraphics(); @@ -373,9 +373,9 @@ ChartOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex * Index of overlay that will be removed */ void -ChartOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) +ChartTwoOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->removeDisplayedOverlay(overlayIndex); this->updateColoringAndGraphics(); @@ -388,9 +388,9 @@ ChartOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) * Index of overlay that will be removed */ void -ChartOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) +ChartTwoOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayDown(overlayIndex); this->updateColoringAndGraphics(); @@ -403,9 +403,9 @@ ChartOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex * Index of overlay that will be removed */ void -ChartOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) +ChartTwoOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) { - ChartOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayUp(overlayIndex); this->updateColoringAndGraphics(); @@ -416,7 +416,7 @@ ChartOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) * Update surface coloring and graphics after overlay changes. */ void -ChartOverlaySetViewController::updateColoringAndGraphics() +ChartTwoOverlaySetViewController::updateColoringAndGraphics() { this->updateViewController(); diff --git a/src/GuiQt/ChartOverlaySetViewController.h b/src/GuiQt/ChartTwoOverlaySetViewController.h similarity index 73% rename from src/GuiQt/ChartOverlaySetViewController.h rename to src/GuiQt/ChartTwoOverlaySetViewController.h index 50b727d5b..58dd1338f 100644 --- a/src/GuiQt/ChartOverlaySetViewController.h +++ b/src/GuiQt/ChartTwoOverlaySetViewController.h @@ -1,5 +1,5 @@ -#ifndef __CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ -#define __CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ +#ifndef __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ +#define __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* @@ -30,20 +30,20 @@ class QLabel; class QScrollArea; namespace caret { - class ChartOverlaySet; - class ChartOverlayViewController; + class ChartTwoOverlaySet; + class ChartTwoOverlayViewController; class WuQGridLayoutGroup; - class ChartOverlaySetViewController : public QWidget, public EventListenerInterface { + class ChartTwoOverlaySetViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: - ChartOverlaySetViewController(const Qt::Orientation orientation, + ChartTwoOverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent = 0); - virtual ~ChartOverlaySetViewController(); + virtual ~ChartTwoOverlaySetViewController(); // ADD_NEW_METHODS_HERE @@ -62,11 +62,11 @@ namespace caret { void processMoveOverlayUp(const int32_t overlayIndex); private: - ChartOverlaySetViewController(const ChartOverlaySetViewController&); + ChartTwoOverlaySetViewController(const ChartTwoOverlaySetViewController&); - ChartOverlaySetViewController& operator=(const ChartOverlaySetViewController&); + ChartTwoOverlaySetViewController& operator=(const ChartTwoOverlaySetViewController&); - ChartOverlaySet* getChartOverlaySet(); + ChartTwoOverlaySet* getChartOverlaySet(); void updateViewController(); @@ -74,7 +74,7 @@ namespace caret { const int32_t m_browserWindowIndex; - std::vector m_chartOverlayViewControllers; + std::vector m_chartOverlayViewControllers; std::vector m_chartOverlayGridLayoutGroups; @@ -88,9 +88,9 @@ namespace caret { }; -#ifdef __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ +#ifdef __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ // #endif // __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ } // namespace -#endif //__CHART_OVERLAY_SET_VIEW_CONTROLLER_H__ +#endif //__CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ diff --git a/src/GuiQt/ChartOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx similarity index 94% rename from src/GuiQt/ChartOverlayViewController.cxx rename to src/GuiQt/ChartTwoOverlayViewController.cxx index 564db2d22..c0ac5df01 100644 --- a/src/GuiQt/ChartOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ -#include "ChartOverlayViewController.h" -#undef __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ +#define __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ +#include "ChartTwoOverlayViewController.h" +#undef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ #include #include @@ -39,7 +39,7 @@ using namespace caret; #include "AnnotationColorBar.h" #include "CaretMappableDataFile.h" -#include "ChartOverlay.h" +#include "ChartTwoOverlay.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" @@ -61,7 +61,7 @@ using namespace caret; #include "WuQtUtilities.h" /** - * \class caret::ChartOverlayViewController + * \class caret::ChartTwoOverlayViewController * \brief View controller for a chart overlay * \ingroup GuiQt */ @@ -78,7 +78,7 @@ using namespace caret; * @param parent * The parent widget. */ -ChartOverlayViewController::ChartOverlayViewController(const Qt::Orientation orientation, +ChartTwoOverlayViewController::ChartTwoOverlayViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const int32_t chartOverlayIndex, QObject* parent) @@ -254,7 +254,7 @@ m_chartOverlay(NULL) /** * Destructor. */ -ChartOverlayViewController::~ChartOverlayViewController() +ChartTwoOverlayViewController::~ChartTwoOverlayViewController() { } @@ -262,7 +262,7 @@ ChartOverlayViewController::~ChartOverlayViewController() * If this overlay ins an overlay settings editor, update its content */ void -ChartOverlayViewController::updateOverlaySettingsEditor() +ChartTwoOverlayViewController::updateOverlaySettingsEditor() { if (m_chartOverlay == NULL) { return; @@ -290,7 +290,7 @@ ChartOverlayViewController::updateOverlaySettingsEditor() * Index of selection. */ void -ChartOverlayViewController::fileComboBoxSelected(int indx) +ChartTwoOverlayViewController::fileComboBoxSelected(int indx) { if (m_chartOverlay == NULL) { return; @@ -329,7 +329,7 @@ ChartOverlayViewController::fileComboBoxSelected(int indx) * Index of selection. */ void -ChartOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) +ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) { if (m_chartOverlay == NULL) { @@ -381,7 +381,7 @@ ChartOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) * Index of selection. */ void -ChartOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) +ChartTwoOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) { if (m_chartOverlay == NULL) { return; @@ -425,7 +425,7 @@ ChartOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) * Checked status */ void -ChartOverlayViewController::enabledCheckBoxClicked(bool checked) +ChartTwoOverlayViewController::enabledCheckBoxClicked(bool checked) { if (m_chartOverlay == NULL) { return; @@ -457,7 +457,7 @@ ChartOverlayViewController::enabledCheckBoxClicked(bool checked) * New status. */ void -ChartOverlayViewController::colorBarActionTriggered(bool status) +ChartTwoOverlayViewController::colorBarActionTriggered(bool status) { if (m_chartOverlay == NULL) { return; @@ -474,7 +474,7 @@ ChartOverlayViewController::colorBarActionTriggered(bool status) * New status. */ void -ChartOverlayViewController::allMapsCheckBoxClicked(bool status) +ChartTwoOverlayViewController::allMapsCheckBoxClicked(bool status) { if (m_chartOverlay == NULL) { return; @@ -489,7 +489,7 @@ ChartOverlayViewController::allMapsCheckBoxClicked(bool status) * Validate yoking when there are changes made to the overlay. */ void -ChartOverlayViewController::validateYokingSelection() +ChartTwoOverlayViewController::validateYokingSelection() { m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateViewController(m_chartOverlay); @@ -501,7 +501,7 @@ ChartOverlayViewController::validateYokingSelection() * Called when the yoking group is changed. */ void -ChartOverlayViewController::yokingGroupActivated() +ChartTwoOverlayViewController::yokingGroupActivated() { MapYokingGroupEnum::Enum yokingGroup = m_mapRowOrColumnYokingGroupComboBox->getMapYokingGroup(); @@ -519,7 +519,7 @@ ChartOverlayViewController::yokingGroupActivated() * Called when the settings action is selected. */ void -ChartOverlayViewController::settingsActionTriggered() +ChartTwoOverlayViewController::settingsActionTriggered() { if (m_chartOverlay == NULL) { return; @@ -543,7 +543,7 @@ ChartOverlayViewController::settingsActionTriggered() * Called when the history action is selected. */ void -ChartOverlayViewController::historyActionTriggered(bool) +ChartTwoOverlayViewController::historyActionTriggered(bool) { if (m_chartOverlay == NULL) { return; @@ -575,7 +575,7 @@ ChartOverlayViewController::historyActionTriggered(bool) * Overlay that is used in this view controller. */ void -ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) +ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverlay) { m_chartOverlay = chartOverlay; @@ -775,7 +775,7 @@ ChartOverlayViewController::updateViewController(ChartOverlay* chartOverlay) * Matrix triangular view mode. */ void -ChartOverlayViewController::updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) +ChartTwoOverlayViewController::updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) { CaretAssert(m_matrixTriangularViewModeAction); m_matrixTriangularViewModeAction->blockSignals(true); @@ -800,7 +800,7 @@ ChartOverlayViewController::updateMatrixTriangularViewModeAction(const ChartTwoM * Update graphics and GUI after selections made */ void -ChartOverlayViewController::updateUserInterfaceAndGraphicsWindow() +ChartTwoOverlayViewController::updateUserInterfaceAndGraphicsWindow() { updateUserInterface(); updateGraphicsWindow(); @@ -810,7 +810,7 @@ ChartOverlayViewController::updateUserInterfaceAndGraphicsWindow() * Update graphics and GUI after selections made */ void -ChartOverlayViewController::updateUserInterface() +ChartTwoOverlayViewController::updateUserInterface() { // if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); @@ -824,7 +824,7 @@ ChartOverlayViewController::updateUserInterface() * Update graphics after selections made */ void -ChartOverlayViewController::updateGraphicsWindow() +ChartTwoOverlayViewController::updateGraphicsWindow() { // if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); @@ -840,14 +840,14 @@ ChartOverlayViewController::updateGraphicsWindow() * Parent widget. */ QMenu* -ChartOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent) +ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent) { std::vector allViewModes; ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(allViewModes); QMenu* menu = new QMenu(parent); QObject::connect(menu, &QMenu::triggered, - this, &ChartOverlayViewController::menuMatrixTriangularViewModeTriggered); + this, &ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered); // QObject::connect(menu, SIGNAL(triggered(QAction*)), // this, SLOT(menuMatrixTriangularViewModeTriggered(QAction* action))); @@ -875,7 +875,7 @@ ChartOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent) * Action of menu item selected. */ void -ChartOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* action) +ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* action) { const QVariant itemData = action->data(); CaretAssert(itemData.isValid()); @@ -896,7 +896,7 @@ ChartOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* actio * Parent widget. */ QMenu* -ChartOverlayViewController::createConstructionMenu(QWidget* parent) +ChartTwoOverlayViewController::createConstructionMenu(QWidget* parent) { QMenu* menu = new QMenu(parent); QObject::connect(menu, SIGNAL(aboutToShow()), @@ -950,7 +950,7 @@ ChartOverlayViewController::createConstructionMenu(QWidget* parent) * Called when construction menu is about to be displayed. */ void -ChartOverlayViewController::menuConstructionAboutToShow() +ChartTwoOverlayViewController::menuConstructionAboutToShow() { if (m_chartOverlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; @@ -978,7 +978,7 @@ ChartOverlayViewController::menuConstructionAboutToShow() * Add an overlay above this overlay. */ void -ChartOverlayViewController::menuAddOverlayAboveTriggered() +ChartTwoOverlayViewController::menuAddOverlayAboveTriggered() { emit requestAddOverlayAbove(m_chartOverlayIndex); } @@ -987,7 +987,7 @@ ChartOverlayViewController::menuAddOverlayAboveTriggered() * Add an overlay below this overlay. */ void -ChartOverlayViewController::menuAddOverlayBelowTriggered() +ChartTwoOverlayViewController::menuAddOverlayBelowTriggered() { emit requestAddOverlayBelow(m_chartOverlayIndex); } @@ -996,7 +996,7 @@ ChartOverlayViewController::menuAddOverlayBelowTriggered() * Remove this overlay. */ void -ChartOverlayViewController::menuRemoveOverlayTriggered() +ChartTwoOverlayViewController::menuRemoveOverlayTriggered() { emit requestRemoveOverlay(m_chartOverlayIndex); } @@ -1005,7 +1005,7 @@ ChartOverlayViewController::menuRemoveOverlayTriggered() * Move this overlay down. */ void -ChartOverlayViewController::menuMoveOverlayDownTriggered() +ChartTwoOverlayViewController::menuMoveOverlayDownTriggered() { emit requestMoveOverlayDown(m_chartOverlayIndex); } @@ -1014,7 +1014,7 @@ ChartOverlayViewController::menuMoveOverlayDownTriggered() * Move this overlay down. */ void -ChartOverlayViewController::menuMoveOverlayUpTriggered() +ChartTwoOverlayViewController::menuMoveOverlayUpTriggered() { emit requestMoveOverlayUp(m_chartOverlayIndex); } @@ -1023,7 +1023,7 @@ ChartOverlayViewController::menuMoveOverlayUpTriggered() * Copy the file name to the clip board. */ void -ChartOverlayViewController::menuCopyFileNameToClipBoard() +ChartTwoOverlayViewController::menuCopyFileNameToClipBoard() { if (m_chartOverlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; @@ -1042,7 +1042,7 @@ ChartOverlayViewController::menuCopyFileNameToClipBoard() * Copy the map name to the clip board. */ void -ChartOverlayViewController::menuCopyMapNameToClipBoard() +ChartTwoOverlayViewController::menuCopyMapNameToClipBoard() { if (m_chartOverlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; @@ -1064,7 +1064,7 @@ ChartOverlayViewController::menuCopyMapNameToClipBoard() * Reload the file in the overlay. */ void -ChartOverlayViewController::menuReloadFileTriggered() +ChartTwoOverlayViewController::menuReloadFileTriggered() { if (m_chartOverlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; @@ -1125,7 +1125,7 @@ ChartOverlayViewController::menuReloadFileTriggered() * Pixmap for matrix view mode. */ QPixmap -ChartOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* widget, +ChartTwoOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* widget, const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) { CaretAssert(widget); @@ -1204,7 +1204,7 @@ ChartOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* widget * Pixmap for history. */ QPixmap -ChartOverlayViewController::createHistoryPixmap(QWidget* widget) +ChartTwoOverlayViewController::createHistoryPixmap(QWidget* widget) { CaretAssert(widget); diff --git a/src/GuiQt/ChartOverlayViewController.h b/src/GuiQt/ChartTwoOverlayViewController.h similarity index 86% rename from src/GuiQt/ChartOverlayViewController.h rename to src/GuiQt/ChartTwoOverlayViewController.h index 37c4035ac..518dff29d 100644 --- a/src/GuiQt/ChartOverlayViewController.h +++ b/src/GuiQt/ChartTwoOverlayViewController.h @@ -1,5 +1,5 @@ -#ifndef __CHART_OVERLAY_VIEW_CONTROLLER_H__ -#define __CHART_OVERLAY_VIEW_CONTROLLER_H__ +#ifndef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ +#define __CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* @@ -36,23 +36,23 @@ class QSpinBox; class QToolButton; namespace caret { - class ChartOverlay; + class ChartTwoOverlay; class MapYokingGroupComboBox; class WuQGridLayoutGroup; - class ChartOverlayViewController : public QObject { + class ChartTwoOverlayViewController : public QObject { Q_OBJECT public: - ChartOverlayViewController(const Qt::Orientation orientation, + ChartTwoOverlayViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const int32_t chartOverlayIndex, QObject* parent); - virtual ~ChartOverlayViewController(); + virtual ~ChartTwoOverlayViewController(); - void updateViewController(ChartOverlay* overlay); + void updateViewController(ChartTwoOverlay* overlay); // ADD_NEW_METHODS_HERE signals: @@ -106,9 +106,9 @@ namespace caret { void menuMatrixTriangularViewModeTriggered(QAction* action); private: - ChartOverlayViewController(const ChartOverlayViewController&); + ChartTwoOverlayViewController(const ChartTwoOverlayViewController&); - ChartOverlayViewController& operator=(const ChartOverlayViewController&); + ChartTwoOverlayViewController& operator=(const ChartTwoOverlayViewController&); void updateUserInterfaceAndGraphicsWindow(); @@ -135,7 +135,7 @@ namespace caret { const int32_t m_chartOverlayIndex; - ChartOverlay* m_chartOverlay; + ChartTwoOverlay* m_chartOverlay; QCheckBox* m_enabledCheckBox; @@ -177,12 +177,12 @@ namespace caret { // ADD_NEW_MEMBERS_HERE - friend class ChartOverlaySetViewController; + friend class ChartTwoOverlaySetViewController; }; -#ifdef __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ +#ifdef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ // -#endif // __CHART_OVERLAY_VIEW_CONTROLLER_DECLARE__ +#endif // __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ } // namespace -#endif //__CHART_OVERLAY_VIEW_CONTROLLER_H__ +#endif //__CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx index 94eacf504..3104f4570 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx @@ -73,7 +73,7 @@ m_mode(mode) */ EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, - ChartOverlay* chartOverlay, + ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, const int32_t mapIndex) : Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h index 01ede0829..fa704c4d1 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h @@ -27,7 +27,7 @@ namespace caret { class CaretMappableDataFile; - class ChartOverlay; + class ChartTwoOverlay; class Overlay; /// Event for showing edit map scalar color mapping editor @@ -47,7 +47,7 @@ namespace caret { EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, - ChartOverlay* chartOverlay, + ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, const int32_t mapIndex); @@ -86,12 +86,12 @@ namespace caret { /** * @return The chart overlay for the editor. */ - ChartOverlay* getChartOverlay() { return m_chartOverlay; } + ChartTwoOverlay* getChartOverlay() { return m_chartOverlay; } /** * @return The overlay for the editor. */ - const ChartOverlay* getChartOverlay() const { return m_chartOverlay; } + const ChartTwoOverlay* getChartOverlay() const { return m_chartOverlay; } private: EventOverlaySettingsEditorDialogRequest(const EventOverlaySettingsEditorDialogRequest&); @@ -108,7 +108,7 @@ namespace caret { Overlay* m_overlay; /** Chart Overlay for editor. */ - ChartOverlay* m_chartOverlay; + ChartTwoOverlay* m_chartOverlay; /** Map file containing map whose color palette is edited */ CaretMappableDataFile* m_mapFile; diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index e235398d5..9b161f58b 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -25,7 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" -#include "ChartOverlay.h" +#include "ChartTwoOverlay.h" #include "ChartableMatrixSeriesInterface.h" #include "CiftiScalarDataSeriesFile.h" #include "EnumComboBoxTemplate.h" @@ -203,7 +203,7 @@ MapYokingGroupComboBox::validateYokingChange(Overlay* overlay) * Chart overlay whose yoking changes. */ void -MapYokingGroupComboBox::validateYokingChange(ChartOverlay* chartOverlay) +MapYokingGroupComboBox::validateYokingChange(ChartTwoOverlay* chartOverlay) { const MapYokingGroupEnum::Enum previousMapYokingGroup = chartOverlay->getMapYokingGroup(); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); diff --git a/src/GuiQt/MapYokingGroupComboBox.h b/src/GuiQt/MapYokingGroupComboBox.h index b0858cdbb..b2dffe916 100644 --- a/src/GuiQt/MapYokingGroupComboBox.h +++ b/src/GuiQt/MapYokingGroupComboBox.h @@ -27,7 +27,7 @@ namespace caret { class CaretMappableDataFile; - class ChartOverlay; + class ChartTwoOverlay; class ChartableMatrixSeriesInterface; class EnumComboBoxTemplate; class Overlay; @@ -51,7 +51,7 @@ namespace caret { void validateYokingChange(Overlay* overlay); - void validateYokingChange(ChartOverlay* chartOverlay); + void validateYokingChange(ChartTwoOverlay* chartOverlay); // ADD_NEW_METHODS_HERE -- GitLab From 913a2f70e313a30a780e7e9204b517c9188d3bf1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 30 Jan 2017 14:45:14 -0600 Subject: [PATCH 191/755] Continuing charting development: Renamed a number of methods to indicate that they are for use with Charting Version Two. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 6 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- src/Brain/BrowserTabContent.cxx | 8 +- src/Brain/BrowserTabContent.h | 4 +- src/Brain/ChartTwoOverlay.cxx | 16 +- src/Brain/ChartTwoOverlay.h | 2 +- src/Brain/ChartTwoOverlaySetArray.cxx | 2 +- src/Brain/ChartTwoOverlaySetArray.h | 2 +- src/Brain/Model.cxx | 4 +- src/Brain/Model.h | 4 +- src/Brain/ModelChart.cxx | 14 +- src/Brain/ModelChart.h | 4 +- src/Charting/ChartTwoCompoundDataType.cxx | 2 +- src/Charting/ChartTwoCompoundDataType.h | 2 +- src/Charting/ChartTwoData.cxx | 2 +- src/Charting/ChartTwoData.h | 2 +- src/Files/ChartableTwoFileBaseChart.cxx | 13 +- src/Files/ChartableTwoFileBaseChart.h | 6 +- src/Files/ChartableTwoFileDelegate.cxx | 70 +- src/Files/ChartableTwoFileDelegate.h | 12 +- src/Files/ChartableTwoFileHistogramChart.cxx | 2 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 2 +- src/Files/ChartableTwoFileMatrixChart.cxx | 2 +- src/Files/ChartableTwoInterface.cxx | 599 ------------------ src/Files/ChartableTwoInterface.h | 138 ---- .../ChartTwoOverlaySetViewController.cxx | 18 +- src/GuiQt/ChartTwoOverlaySetViewController.h | 2 +- .../EventOverlaySettingsEditorDialogRequest.h | 4 +- 28 files changed, 117 insertions(+), 827 deletions(-) delete mode 100644 src/Files/ChartableTwoInterface.cxx delete mode 100644 src/Files/ChartableTwoInterface.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 1130723df..a2edef94b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -158,7 +158,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, int32_t mapIndex = -1; topOverlay->getSelectionData(cmdf, mapIndex); if (cmdf != NULL) { - const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartDataType(); + const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -310,7 +310,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() CaretAssert(numberOfOverlays > 0); const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); - CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); /* * Get extent of histogram data @@ -449,7 +449,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() CaretAssert(numberOfOverlays > 0); const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); - CaretAssert(cdt.getChartDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); + CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); if ((numberOfRows > 0) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 70c7f2e6f..f8fd27bfd 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5298,7 +5298,7 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, getTextRenderer(), translation, zooming, - chartModel->getChartOverlaySet(tabIndex), + chartModel->getChartTwoOverlaySet(tabIndex), SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, tabIndex); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 1039c8f9f..b55a4e121 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -859,11 +859,11 @@ BrowserTabContent::getOverlaySet() const * @return Overlay set for this tab. */ ChartTwoOverlaySet* -BrowserTabContent::getChartOverlaySet() +BrowserTabContent::getChartTwoOverlaySet() { Model* model = getModelForDisplay(); if (model != NULL) { - return model->getChartOverlaySet(m_tabNumber); + return model->getChartTwoOverlaySet(m_tabNumber); } return NULL; } @@ -872,11 +872,11 @@ BrowserTabContent::getChartOverlaySet() * @return Overlay set for this tab. */ const ChartTwoOverlaySet* -BrowserTabContent::getChartOverlaySet() const +BrowserTabContent::getChartTwoOverlaySet() const { const Model* model = getModelForDisplay(); if (model != NULL) { - return model->getChartOverlaySet(m_tabNumber); + return model->getChartTwoOverlaySet(m_tabNumber); } return NULL; } diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 91aabf9ce..a29912777 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -94,9 +94,9 @@ namespace caret { const OverlaySet* getOverlaySet() const; - ChartTwoOverlaySet* getChartOverlaySet(); + ChartTwoOverlaySet* getChartTwoOverlaySet(); - const ChartTwoOverlaySet* getChartOverlaySet() const; + const ChartTwoOverlaySet* getChartTwoOverlaySet() const; int32_t getTabNumber() const; diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index bf9426035..4ce9c0087 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -166,7 +166,7 @@ ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); ChartTwoCompoundDataType cdt; - chartDelegate->getChartCompoundDataTypeForChartDataType(getChartDataType(), + chartDelegate->getChartTwoCompoundDataTypeForChartTwoDataType(getChartTwoDataType(), cdt); descriptionOut.addLine(cdt.toString()); } @@ -178,7 +178,7 @@ ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) * @return The chart data type for this chart overlay. */ ChartTwoDataTypeEnum::Enum -ChartTwoOverlay::getChartDataType() const +ChartTwoOverlay::getChartTwoDataType() const { return m_chartDataType; } @@ -210,8 +210,8 @@ ChartTwoOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& cha } // do for overlay zero ?? - if (chartCompoundDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { - CaretAssert(m_chartDataType == chartCompoundDataType.getChartDataType()); + if (chartCompoundDataType.getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { + CaretAssert(m_chartDataType == chartCompoundDataType.getChartTwoDataType()); } m_chartCompoundDataType = chartCompoundDataType; } @@ -681,14 +681,14 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma for (auto mapFile : allDataFiles) { CaretAssert(mapFile); ChartableTwoFileDelegate* chartingFile = mapFile->getChartingDelegate(); - if (chartingFile->isChartingSupported()) { + if (chartingFile->isChartingTwoSupported()) { bool useIt = false; std::vector chartCompoundDataTypes; - chartingFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + chartingFile->getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& compoundType : chartCompoundDataTypes) { - if (m_chartDataType == compoundType.getChartDataType()) { + if (m_chartDataType == compoundType.getChartTwoDataType()) { if (m_overlayIndex == 0) { /* * The first overlay displays ALL files that match the @@ -897,7 +897,7 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma if (m_selectedMapFile != NULL) { const ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartFile); - chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, + chartFile->getChartTwoCompoundDataTypeForChartTwoDataType(m_chartDataType, m_chartCompoundDataType); } CaretAssert(m_parentChartTwoOverlaySet); diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index a4368eb66..36aeba37d 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -47,7 +47,7 @@ namespace caret { virtual ~ChartTwoOverlay(); - ChartTwoDataTypeEnum::Enum getChartDataType() const; + ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; ChartTwoCompoundDataType getChartTwoCompoundDataType() const; diff --git a/src/Brain/ChartTwoOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx index b24ccbe4a..1fff094b6 100644 --- a/src/Brain/ChartTwoOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -109,7 +109,7 @@ ChartTwoOverlaySetArray::getNumberOfChartOverlaySets() * Overlay set at given index. */ ChartTwoOverlaySet* -ChartTwoOverlaySetArray::getChartOverlaySet(const int32_t tabIndex) +ChartTwoOverlaySetArray::getChartTwoOverlaySet(const int32_t tabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); diff --git a/src/Brain/ChartTwoOverlaySetArray.h b/src/Brain/ChartTwoOverlaySetArray.h index 7dfa44d13..8dddcc65a 100644 --- a/src/Brain/ChartTwoOverlaySetArray.h +++ b/src/Brain/ChartTwoOverlaySetArray.h @@ -40,7 +40,7 @@ namespace caret { int32_t getNumberOfChartOverlaySets(); - ChartTwoOverlaySet* getChartOverlaySet(const int32_t indx); + ChartTwoOverlaySet* getChartTwoOverlaySet(const int32_t indx); void initializeOverlaySelections(); diff --git a/src/Brain/Model.cxx b/src/Brain/Model.cxx index 3d56b6623..e36cd9c6a 100644 --- a/src/Brain/Model.cxx +++ b/src/Brain/Model.cxx @@ -125,7 +125,7 @@ Model::initializeSelectedSurfaces() * Chart overlay set or NULL if not valid for this model. */ ChartTwoOverlaySet* -Model::getChartOverlaySet(const int /*tabIndex*/) +Model::getChartTwoOverlaySet(const int /*tabIndex*/) { return NULL; } @@ -139,7 +139,7 @@ Model::getChartOverlaySet(const int /*tabIndex*/) * Chart overlay set or NULL if not valid for this model. */ const ChartTwoOverlaySet* -Model::getChartOverlaySet(const int /*tabIndex*/) const +Model::getChartTwoOverlaySet(const int /*tabIndex*/) const { return NULL; } diff --git a/src/Brain/Model.h b/src/Brain/Model.h index 390824d7b..25ce9c572 100644 --- a/src/Brain/Model.h +++ b/src/Brain/Model.h @@ -67,9 +67,9 @@ namespace caret { virtual const OverlaySet* getOverlaySet(const int tabIndex) const = 0; - virtual ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex); + virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex); - virtual const ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex) const; + virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const; virtual void initializeSelectedSurfaces(); diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 72aae679a..9d253a4ea 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -2044,7 +2044,7 @@ ModelChart::getValidChartTwoDataTypes(std::vector& v for (auto mapFile : allDataFiles) { ChartableTwoFileDelegate* chartFile = mapFile->getChartingDelegate(); std::vector fileChartTypes; - chartFile->getSupportedChartDataTypes(fileChartTypes); + chartFile->getSupportedChartTwoDataTypes(fileChartTypes); chartTypeSet.insert(fileChartTypes.begin(), fileChartTypes.end()); @@ -2438,7 +2438,7 @@ ModelChart::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const * Chart overlay set or NULL if not valid for this model. */ ChartTwoOverlaySet* -ModelChart::getChartOverlaySet(const int tabIndex) +ModelChart::getChartTwoOverlaySet(const int tabIndex) { ChartTwoOverlaySet* chartOverlaySet = NULL; @@ -2446,13 +2446,13 @@ ModelChart::getChartOverlaySet(const int tabIndex) case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - chartOverlaySet = m_histogramChartOverlaySetArray->getChartOverlaySet(tabIndex); + chartOverlaySet = m_histogramChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartOverlaySet(tabIndex); + chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - chartOverlaySet = m_matrixChartOverlaySetArray->getChartOverlaySet(tabIndex); + chartOverlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; } @@ -2468,11 +2468,11 @@ ModelChart::getChartOverlaySet(const int tabIndex) * Chart overlay set or NULL if not valid for this model. */ const ChartTwoOverlaySet* -ModelChart::getChartOverlaySet(const int tabIndex) const +ModelChart::getChartTwoOverlaySet(const int tabIndex) const { ModelChart* nonConstModelChart = const_cast(this); CaretAssert(nonConstModelChart); - const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartOverlaySet(tabIndex); + const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartTwoOverlaySet(tabIndex); return chartOverlaySet; } diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 2e269152a..ac97bf996 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -94,9 +94,9 @@ namespace caret { const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const; - virtual ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex); + virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex); - virtual const ChartTwoOverlaySet* getChartOverlaySet(const int tabIndex) const; + virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const; virtual void receiveEvent(Event* event); diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index 2438a4fad..cde21c664 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -271,7 +271,7 @@ ChartTwoCompoundDataType::operator==(const ChartTwoCompoundDataType& obj) const * @return Type of chart data. */ ChartTwoDataTypeEnum::Enum -ChartTwoCompoundDataType::getChartDataType() const +ChartTwoCompoundDataType::getChartTwoDataType() const { return m_chartDataType; } diff --git a/src/Charting/ChartTwoCompoundDataType.h b/src/Charting/ChartTwoCompoundDataType.h index 913c6adc7..fa5586f87 100644 --- a/src/Charting/ChartTwoCompoundDataType.h +++ b/src/Charting/ChartTwoCompoundDataType.h @@ -60,7 +60,7 @@ namespace caret { bool operator==(const ChartTwoCompoundDataType& obj) const; - ChartTwoDataTypeEnum::Enum getChartDataType() const; + ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; int32_t getHistogramNumberOfBuckets() const; diff --git a/src/Charting/ChartTwoData.cxx b/src/Charting/ChartTwoData.cxx index 8a29942cc..3194b78c7 100644 --- a/src/Charting/ChartTwoData.cxx +++ b/src/Charting/ChartTwoData.cxx @@ -225,7 +225,7 @@ ChartTwoData::restoreFromScene(const SceneAttributes* sceneAttributes, * @return The chart data type. */ ChartTwoDataTypeEnum::Enum -ChartTwoData::getChartDataType() const +ChartTwoData::getChartTwoDataType() const { return m_chartDataType; } diff --git a/src/Charting/ChartTwoData.h b/src/Charting/ChartTwoData.h index 13f2a55a6..b1f6623f7 100644 --- a/src/Charting/ChartTwoData.h +++ b/src/Charting/ChartTwoData.h @@ -50,7 +50,7 @@ namespace caret { */ virtual ChartTwoData* clone() const = 0; - ChartTwoDataTypeEnum::Enum getChartDataType() const; + ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; const ChartDataSource* getChartDataSource() const; diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index e1c18b303..3b361aeed 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -156,8 +156,11 @@ ChartableTwoFileBaseChart::getCiftiMappableDataFile() const return m_parentCiftiMappableDataFile; } +/** + * @return Chart version two data type + */ ChartTwoDataTypeEnum::Enum -ChartableTwoFileBaseChart::getChartDataType() const +ChartableTwoFileBaseChart::getChartTwoDataType() const { return m_chartType; } @@ -166,9 +169,9 @@ ChartableTwoFileBaseChart::getChartDataType() const * @return Chart compound data type supported by subclass. */ ChartTwoCompoundDataType -ChartableTwoFileBaseChart::getChartCompoundDataType() const +ChartableTwoFileBaseChart::getChartTwoCompoundDataType() const { - CaretAssertMessage((m_compoundChartDataType.getChartDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID), + CaretAssertMessage((m_compoundChartDataType.getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID), "Data type is invalid, was updateChartCompoundDataTypeAfterFileChanges() called by " "implementing class."); return m_compoundChartDataType; @@ -183,9 +186,9 @@ ChartableTwoFileBaseChart::getChartCompoundDataType() const * match the data type passed to the constructor. */ void -ChartableTwoFileBaseChart::updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) +ChartableTwoFileBaseChart::updateChartTwoCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) { - CaretAssert(m_chartType == compoundChartDataType.getChartDataType()); + CaretAssert(m_chartType == compoundChartDataType.getChartTwoDataType()); m_compoundChartDataType = compoundChartDataType; } diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index 5024a2238..f4fd24ee4 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -59,9 +59,9 @@ namespace caret { const CiftiMappableDataFile* getCiftiMappableDataFile() const; - ChartTwoDataTypeEnum::Enum getChartDataType() const; + ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; - ChartTwoCompoundDataType getChartCompoundDataType() const; + ChartTwoCompoundDataType getChartTwoCompoundDataType() const; // ADD_NEW_METHODS_HERE @@ -81,7 +81,7 @@ namespace caret { protected: - void updateChartCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType); + void updateChartTwoCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index 1d2200722..c745de05b 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -260,32 +260,56 @@ ChartableTwoFileDelegate::getCaretMappableDataFile() const return m_caretMappableDataFile; } -ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() +/** + * @return Histogram charting. + */ +ChartableTwoFileHistogramChart* +ChartableTwoFileDelegate::getHistogramCharting() { return m_histogramCharting.get(); } -const ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() const +/** + * @return Histogram charting. + */ +const ChartableTwoFileHistogramChart* +ChartableTwoFileDelegate::getHistogramCharting() const { return m_histogramCharting.get(); } -ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() +/** + * @return Line series charting. + */ +ChartableTwoFileLineSeriesChart* +ChartableTwoFileDelegate::getLineSeriesCharting() { return m_lineSeriesCharting.get(); } -const ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() const +/** + * @return Line series charting. + */ +const ChartableTwoFileLineSeriesChart* +ChartableTwoFileDelegate::getLineSeriesCharting() const { return m_lineSeriesCharting.get(); } -ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() +/** + * @return Matrix charting. + */ +ChartableTwoFileMatrixChart* +ChartableTwoFileDelegate::getMatrixCharting() { return m_matrixCharting.get(); } -const ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() const +/** + * @return Matrix charting. + */ +const ChartableTwoFileMatrixChart* +ChartableTwoFileDelegate::getMatrixCharting() const { return m_matrixCharting.get(); } @@ -314,10 +338,10 @@ const ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() * Does this file support any type of charting? */ bool -ChartableTwoFileDelegate::isChartingSupported() const +ChartableTwoFileDelegate::isChartingTwoSupported() const { std::vector chartDataTypes; - getSupportedChartDataTypes(chartDataTypes); + getSupportedChartTwoDataTypes(chartDataTypes); return ( ! chartDataTypes.empty()); } @@ -331,10 +355,10 @@ ChartableTwoFileDelegate::isChartingSupported() const * True if the chart data type is supported, else false. */ bool -ChartableTwoFileDelegate::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const +ChartableTwoFileDelegate::isChartingSupportedForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const { std::vector chartDataTypes; - getSupportedChartDataTypes(chartDataTypes); + getSupportedChartTwoDataTypes(chartDataTypes); if (std::find(chartDataTypes.begin(), chartDataTypes.end(), @@ -354,10 +378,10 @@ ChartableTwoFileDelegate::isChartingSupportedForChartDataType(const ChartTwoData * True if the chart compound data type is supported, else false. */ bool -ChartableTwoFileDelegate::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const +ChartableTwoFileDelegate::isChartingSupportedForChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const { std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& ccdt : chartCompoundDataTypes) { if (ccdt == chartCompoundDataType) { @@ -375,18 +399,18 @@ ChartableTwoFileDelegate::isChartingSupportedForChartCompoundDataType(const Char * Output containing all chart data types supported by this data file. */ void -ChartableTwoFileDelegate::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const +ChartableTwoFileDelegate::getSupportedChartTwoDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); if (m_histogramCharting != NULL) { - chartDataTypesOut.push_back(m_histogramCharting->getChartDataType()); + chartDataTypesOut.push_back(m_histogramCharting->getChartTwoDataType()); } if (m_lineSeriesCharting!= NULL) { - chartDataTypesOut.push_back(m_lineSeriesCharting->getChartDataType()); + chartDataTypesOut.push_back(m_lineSeriesCharting->getChartTwoDataType()); } if (m_matrixCharting != NULL) { - chartDataTypesOut.push_back(m_matrixCharting->getChartDataType()); + chartDataTypesOut.push_back(m_matrixCharting->getChartTwoDataType()); } } @@ -397,18 +421,18 @@ ChartableTwoFileDelegate::getSupportedChartDataTypes(std::vector& chartCompoundDataTypesOut) const +ChartableTwoFileDelegate::getSupportedChartTwoCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const { chartCompoundDataTypesOut.clear(); if (m_histogramCharting->getHistogramContentType() != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED) { - chartCompoundDataTypesOut.push_back(m_histogramCharting->getChartCompoundDataType()); + chartCompoundDataTypesOut.push_back(m_histogramCharting->getChartTwoCompoundDataType()); } if (m_lineSeriesCharting->getLineSeriesContentType() != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { - chartCompoundDataTypesOut.push_back(m_lineSeriesCharting->getChartCompoundDataType()); + chartCompoundDataTypesOut.push_back(m_lineSeriesCharting->getChartTwoCompoundDataType()); } if (m_matrixCharting->getMatrixContentType() != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { - chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartCompoundDataType()); + chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartTwoCompoundDataType()); } // const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); @@ -529,13 +553,13 @@ ChartableTwoFileDelegate::getSupportedChartCompoundDataTypes(std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); + getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& cdt : chartCompoundDataTypes) { - if (cdt.getChartDataType() == chartDataType) { + if (cdt.getChartTwoDataType() == chartDataType) { chartCompoundDataTypeOut = cdt; return true; } diff --git a/src/Files/ChartableTwoFileDelegate.h b/src/Files/ChartableTwoFileDelegate.h index c98cc0511..654992d26 100644 --- a/src/Files/ChartableTwoFileDelegate.h +++ b/src/Files/ChartableTwoFileDelegate.h @@ -67,17 +67,17 @@ namespace caret { const ChartableTwoFileMatrixChart* getMatrixCharting() const; - bool isChartingSupported() const; + bool isChartingTwoSupported() const; - bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; + bool isChartingSupportedForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; - bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; + bool isChartingSupportedForChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; - void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const; + void getSupportedChartTwoDataTypes(std::vector& chartDataTypesOut) const; - void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; + void getSupportedChartTwoCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; - bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, + bool getChartTwoCompoundDataTypeForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType, ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index f242b34f3..e751862d1 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -70,7 +70,7 @@ m_histogramContentType(histogramContentType) histogramNumberOfBuckets = histogram->getNumberOfBuckets(); } } - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram(histogramNumberOfBuckets)); + updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram(histogramNumberOfBuckets)); } /** diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 85177aedd..fae04533f 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -138,7 +138,7 @@ m_lineSeriesContentType(lineSeriesContentType) m_lineSeriesContentType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; } - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, + updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, xAxisNumberOfElements)); } diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 1a0731e6a..1fd53de45 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -84,7 +84,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) } - updateChartCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, + updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, numCols)); m_rowColumnDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; diff --git a/src/Files/ChartableTwoInterface.cxx b/src/Files/ChartableTwoInterface.cxx deleted file mode 100644 index 670e49b94..000000000 --- a/src/Files/ChartableTwoInterface.cxx +++ /dev/null @@ -1,599 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHARTABLE_TWO_INTERFACE_DECLARE__ -#include "ChartableTwoInterface.h" -#undef __CHARTABLE_TWO_INTERFACE_DECLARE__ - -#include "CaretAssert.h" -#include "CaretMappableDataFile.h" -#include "CiftiConnectivityMatrixParcelFile.h" -#include "CiftiMappableDataFile.h" -#include "CiftiParcelLabelFile.h" -#include "CiftiParcelReordering.h" -#include "CiftiParcelScalarFile.h" -using namespace caret; - - - -/** - * \class caret::ChartableTwoInterface - * \brief Interface for files that are chartable. Contains functionality but no data. - * \ingroup Files - */ - -/** - * Constructor. - * - * @param type of matrix (if any) supported by implementing file. - * - * @param histogramContentType - * Type of histogram chart supported (or not supported) by implementing file. - * @param lineSeriesContentType - * Type of line series chart supported (or not supported) by implementing file. - * @param matrixContentType - * Type of matrix chart supported (or not supported) by implementing file. - */ -ChartableTwoInterface::ChartableTwoInterface() -{ - -} - -/** - * Destructor. - */ -ChartableTwoInterface::~ChartableTwoInterface() -{ -} - -///** -// * @return The CaretMappableDataFile that implements this interface. -// * NULL is returned if not a CaretMappableDataFile. -// */ -//CaretMappableDataFile* -//ChartableTwoInterface::getAsCaretMappableDataFile() -//{ -// return dynamic_cast(this); -//} -// -///** -// * @return The CaretMappableDataFile that implements this interface. -// * NULL is returned if not a CaretMappableDataFile. -// */ -//const CaretMappableDataFile* -//ChartableTwoInterface::getAsCaretMappableDataFile() const -//{ -// return dynamic_cast(this); -//} -// -///** -// * @return The CiftiMappableDataFile that implements this interface. -// * NULL is returned if not a CiftiMappableDataFile. -// */ -//CiftiMappableDataFile* -//ChartableTwoInterface::getAsCiftiMappableDataFile() -//{ -// return dynamic_cast(this); -//} -// -///** -// * @return The CiftiMappableDataFile that implements this interface. -// * NULL is returned if not a CiftiMappableDataFile. -// */ -//const CiftiMappableDataFile* -//ChartableTwoInterface::getAsCiftiMappableDataFile() const -//{ -// return dynamic_cast(this); -//} - -/** - * Does this file support any type of charting? - */ -bool -ChartableTwoInterface::isChartingSupported() const -{ - std::vector chartDataTypes; - getSupportedChartDataTypes(chartDataTypes); - - return ( ! chartDataTypes.empty()); -} - -/** - * Test for support of the given chart data type. - * - * @param chartDataType - * Type of chart data. - * @return - * True if the chart data type is supported, else false. - */ -bool -ChartableTwoInterface::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const -{ - std::vector chartDataTypes; - getSupportedChartDataTypes(chartDataTypes); - - if (std::find(chartDataTypes.begin(), - chartDataTypes.end(), - chartDataType) != chartDataTypes.end()) { - return true; - } - - return false; -} - -/** - * Test for support of the given chart compound data type. - * - * @param chartCompoundDataType - * Type of chart compound data. - * @return - * True if the chart compound data type is supported, else false. - */ -bool -ChartableTwoInterface::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const -{ - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - - for (auto& ccdt : chartCompoundDataTypes) { - if (ccdt == chartCompoundDataType) { - return true; - } - } - - return false; -} - -/** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ -void -ChartableTwoInterface::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const -{ - chartDataTypesOut.clear(); - - if (getHistogramChartDelegate() != NULL) { - chartDataTypesOut.push_back(getHistogramChartDelegate()->getChartDataType()); - } - if (getLineSeriesChartDelegate() != NULL) { - chartDataTypesOut.push_back(getLineSeriesChartDelegate()->getChartDataType()); - } - if (getMatrixChartDelegate() != NULL) { - chartDataTypesOut.push_back(getMatrixChartDelegate()->getChartDataType()); - } - - CaretAssertMessage((! chartDataTypesOut.empty()), - "Why is this interface implemented if implementing file does not support charts?"); -} - -/** - * Get chart data types supported by this file. - * - * @param chartDataTypesOut - * Output containing all chart data types supported by this data file. - */ -void -ChartableTwoInterface::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const -{ - chartCompoundDataTypesOut.clear(); - - - if (getHistogramChartDelegate() != NULL) { - chartCompoundDataTypesOut.push_back(getHistogramChartDelegate()->getChartCompoundDataType()); - } - if (getLineSeriesChartDelegate() != NULL) { - chartCompoundDataTypesOut.push_back(getLineSeriesChartDelegate()->getChartCompoundDataType()); - } - if (getMatrixChartDelegate() != NULL) { - chartCompoundDataTypesOut.push_back(getMatrixChartDelegate()->getChartCompoundDataType()); - } - - -// const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); -// if (cmdf == NULL) { -// return; -// } -// -// switch (m_histogramContentType) { -// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: -// break; -// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: -// if (cmdf->getNumberOfMaps() > 0) { -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); -// } -// break; -// } -// -// switch (m_lineSeriesContentType) { -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: -// if (cmdf->getNumberOfMaps() > 1) { -// const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// const int32_t numMaps = cmdf->getNumberOfMaps(); -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numMaps)); -// } -// break; -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: -// { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// const int32_t numRows = dims[1]; -// -// if ((numRows > 0) -// && (numCols > 1)) { -// const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numCols)); -// } -// } break; -// } -// -// switch (m_matrixContentType) { -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: -// { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// const int32_t numRows = dims[1]; -// -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, -// numCols)); -// } break; -// } -} - -/** - * Get the chart compound data type supported by this file that uses the given - * chart data type. - * - * @param chartDataType - * The chart data type. - * @param chartCompoundDataTypeOut - * Output with the chart compound data type. - * @return - * True if there is output chart compound data type is valid. - * False if output chart compound data type is invalid OR if chartDataType is invalid. - */ -bool -ChartableTwoInterface::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - ChartTwoCompoundDataType& chartCompoundDataTypeOut) const -{ - std::vector chartCompoundDataTypes; - getSupportedChartCompoundDataTypes(chartCompoundDataTypes); - for (auto& cdt : chartCompoundDataTypes) { - if (cdt.getChartDataType() == chartDataType) { - chartCompoundDataTypeOut = cdt; - return true; - } - } - - /* default constructor is invalid data type */ - chartCompoundDataTypeOut = ChartTwoCompoundDataType(); - return false; -} - - -///** -// * @return The content type for histograms. -// */ -//ChartTwoHistogramContentTypeEnum::Enum ChartableTwoInterface::getHistogramContentType() const -//{ -// return m_histogramContentType; -//} -// -///** -// * @return The content type for line series. -// */ -//ChartTwoLineSeriesContentTypeEnum::Enum ChartableTwoInterface::getLineSeriesContentType() const -//{ -// return m_lineSeriesContentType; -//} -// -///** -// * @return The content type for matrix. -// */ -//ChartTwoMatrixContentTypeEnum::Enum ChartableTwoInterface::getMatrixContentType() const -//{ -// return m_matrixContentType; -//} -// -// -///** -// * Get the matrix dimensions. -// * -// * @param numberOfRowsOut -// * Number of rows in the matrix. -// * @param numberOfColumnsOut -// * Number of rows in the matrix. -// */ -//void -//ChartableTwoInterface::getTwoMatrixDimensions(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut) const -//{ -// if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { -// numberOfRowsOut = 0; -// numberOfColumnsOut = 0; -// return; -// } -// -// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); -// CaretAssert(ciftiMapFile); -// CaretAssertToDoFatal(); -//// ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, -//// numberOfColumnsOut); -// // std::vector dims; -// // ciftiMapFile->getMapDimensions(dims); -// // CaretAssertVectorIndex(dims, 1); -// // numberOfRowsOut = dims[0]; -// // numberOfColumnsOut = dims[1]; -//} -// -///** -// * Get the matrix RGBA coloring for this matrix data creator. -// * -// * @param numberOfRowsOut -// * Number of rows in the coloring matrix. -// * @param numberOfColumnsOut -// * Number of rows in the coloring matrix. -// * @param rgbaOut -// * RGBA coloring output with number of elements -// * (numberOfRowsOut * numberOfColumnsOut * 4). -// * @return -// * True if data output data is valid, else false. -// */ -//bool -//ChartableTwoInterface::getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// std::vector& rgbaOut) const -//{ -// const CaretMappableDataFile* mapFile = getAsCaretMappableDataFile(); -// CaretAssert(mapFile); -// -// bool useMapFileHelperFlag = false; -// bool useMatrixFileHelperFlag = false; -// -// std::vector parcelReorderedRowIndices; -// -// switch (mapFile->getDataFileType()) { -// case DataFileTypeEnum::CONNECTIVITY_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL: -// { -// useMatrixFileHelperFlag = true; -// -// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(mapFile); -// CaretAssert(parcelConnFile); -// if (parcelConnFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(mapFile); -// CaretAssert(parcelLabelFile); -// if (parcelLabelFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(mapFile); -// CaretAssert(parcelScalarFile); -// if (parcelScalarFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: -// useMatrixFileHelperFlag = true; -// break; -// case DataFileTypeEnum::ANNOTATION: -// break; -// case DataFileTypeEnum::BORDER: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: -// break; -// case DataFileTypeEnum::FOCI: -// break; -// case DataFileTypeEnum::IMAGE: -// break; -// case DataFileTypeEnum::LABEL: -// break; -// case DataFileTypeEnum::METRIC: -// break; -// case DataFileTypeEnum::PALETTE: -// break; -// case DataFileTypeEnum::RGBA: -// break; -// case DataFileTypeEnum::SCENE: -// break; -// case DataFileTypeEnum::SPECIFICATION: -// break; -// case DataFileTypeEnum::SURFACE: -// break; -// case DataFileTypeEnum::UNKNOWN: -// break; -// case DataFileTypeEnum::VOLUME: -// break; -// } -// -// if (( ! useMapFileHelperFlag) -// && ( ! useMatrixFileHelperFlag)) { -// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); -// return false; -// } -// -// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); -// CaretAssert(ciftiMapFile); -// -// -// bool validDataFlag = false; -// if (useMapFileHelperFlag) { -// CaretAssertToDoFatal(); -//// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, -//// numberOfColumnsOut, -//// parcelReorderedRowIndices, -//// rgbaOut); -// } -// else if (useMatrixFileHelperFlag) { -// CaretAssertToDoFatal(); -//// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, -//// numberOfColumnsOut, -//// parcelReorderedRowIndices, -//// rgbaOut); -// } -// switch (m_matrixContentType) { -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: -// break; -// } -// -// return validDataFlag; -//} - diff --git a/src/Files/ChartableTwoInterface.h b/src/Files/ChartableTwoInterface.h deleted file mode 100644 index f54010790..000000000 --- a/src/Files/ChartableTwoInterface.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef __CHARTABLE_TWO_INTERFACE_H__ -#define __CHARTABLE_TWO_INTERFACE_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include "ChartTwoCompoundDataType.h" -#include "ChartTwoDataTypeEnum.h" -#include "ChartableTwoFileHistogramChart.h" -#include "ChartableTwoFileLineSeriesChart.h" -#include "ChartableTwoFileMatrixChart.h" -#include "ChartTwoLineSeriesContentTypeEnum.h" -#include "ChartTwoMatrixContentTypeEnum.h" - -namespace caret { - - class CaretMappableDataFile; - class ChartTwoDataCartesianHistory; - class CiftiMappableDataFile; - - class ChartableTwoInterface { - - public: - ChartableTwoInterface(); - - virtual ~ChartableTwoInterface(); - - virtual CaretMappableDataFile* getAsCaretMappableDataFile() = 0; - - virtual const CaretMappableDataFile* getAsCaretMappableDataFile() const = 0; - - virtual ChartableTwoFileHistogramChart* getHistogramChartDelegate() = 0; - - virtual const ChartableTwoFileHistogramChart* getHistogramChartDelegate() const = 0; - - virtual ChartableTwoFileLineSeriesChart* getLineSeriesChartDelegate() = 0; - - virtual const ChartableTwoFileLineSeriesChart* getLineSeriesChartDelegate() const = 0; - - virtual ChartableTwoFileMatrixChart* getMatrixChartDelegate() = 0; - - virtual const ChartableTwoFileMatrixChart* getMatrixChartDelegate() const = 0; - - bool isChartingSupported() const; - - bool isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; - - bool isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; - - void getSupportedChartDataTypes(std::vector& chartDataTypesOut) const; - - void getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; - - bool getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, - ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; - - - /* IMPLEMENT ABOVE NON-VIRTUAL METHODS USING THE VIRTUAL METHODS */ - - /* METHODS NO LONGER NEEDED ??? */ - -// CiftiMappableDataFile* getAsCiftiMappableDataFile(); -// -// const CiftiMappableDataFile* getAsCiftiMappableDataFile() const; -// -// -// ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; -// -// ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; -// -// ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; -// -// void getTwoMatrixDimensions(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut) const; -// -// bool getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// std::vector& rgbaOut) const; - -// /** -// * @return Is line series charting enabled for this file in the given tab? -// */ -// virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const = 0; -// -// /** -// * Set charting enabled for this file in the given tab -// * -// * @param enabled -// * New status for charting enabled. -// */ -// virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, -// const bool enabled) = 0; - - /** - * @return Charting history if this file charts to lines. - */ - //virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; - - // ADD_NEW_METHODS_HERE - - private: - ChartableTwoInterface(const ChartableTwoInterface&); - - ChartableTwoInterface& operator=(const ChartableTwoInterface&); - -// const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; -// -// const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; -// -// const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __CHARTABLE_TWO_INTERFACE_DECLARE__ - // -#endif // __CHARTABLE_TWO_INTERFACE_DECLARE__ - -} // namespace -#endif //__CHARTABLE_TWO_INTERFACE_H__ diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 5380b6b4d..78ec6d6f3 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -274,7 +274,7 @@ ChartTwoOverlaySetViewController::receiveEvent(Event* event) void ChartTwoOverlaySetViewController::updateViewController() { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet == NULL) { return; } @@ -300,7 +300,7 @@ ChartTwoOverlaySetViewController::updateViewController() const ChartTwoOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); if (primaryOverlay != NULL) { AString mapRowOrColumnName = "Map"; - switch (primaryOverlay->getChartDataType()) { + switch (primaryOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: @@ -325,13 +325,13 @@ ChartTwoOverlaySetViewController::updateViewController() * @return The overlay set in this view controller. */ ChartTwoOverlaySet* -ChartTwoOverlaySetViewController::getChartOverlaySet() +ChartTwoOverlaySetViewController::getChartTwoOverlaySet() { ChartTwoOverlaySet* chartOverlaySet = NULL; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent != NULL) { - chartOverlaySet = browserTabContent->getChartOverlaySet(); + chartOverlaySet = browserTabContent->getChartTwoOverlaySet(); } return chartOverlaySet; @@ -345,7 +345,7 @@ ChartTwoOverlaySetViewController::getChartOverlaySet() void ChartTwoOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayAbove(overlayIndex); this->updateColoringAndGraphics(); @@ -360,7 +360,7 @@ ChartTwoOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIn void ChartTwoOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayBelow(overlayIndex); this->updateColoringAndGraphics(); @@ -375,7 +375,7 @@ ChartTwoOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIn void ChartTwoOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->removeDisplayedOverlay(overlayIndex); this->updateColoringAndGraphics(); @@ -390,7 +390,7 @@ ChartTwoOverlaySetViewController::processRemoveOverlay(const int32_t overlayInde void ChartTwoOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayDown(overlayIndex); this->updateColoringAndGraphics(); @@ -405,7 +405,7 @@ ChartTwoOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIn void ChartTwoOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) { - ChartTwoOverlaySet* chartOverlaySet = getChartOverlaySet(); + ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayUp(overlayIndex); this->updateColoringAndGraphics(); diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.h b/src/GuiQt/ChartTwoOverlaySetViewController.h index 58dd1338f..f637eae69 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.h +++ b/src/GuiQt/ChartTwoOverlaySetViewController.h @@ -66,7 +66,7 @@ namespace caret { ChartTwoOverlaySetViewController& operator=(const ChartTwoOverlaySetViewController&); - ChartTwoOverlaySet* getChartOverlaySet(); + ChartTwoOverlaySet* getChartTwoOverlaySet(); void updateViewController(); diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h index fa704c4d1..c9fc37ccb 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h @@ -86,12 +86,12 @@ namespace caret { /** * @return The chart overlay for the editor. */ - ChartTwoOverlay* getChartOverlay() { return m_chartOverlay; } + ChartTwoOverlay* getChartTwoOverlay() { return m_chartOverlay; } /** * @return The overlay for the editor. */ - const ChartTwoOverlay* getChartOverlay() const { return m_chartOverlay; } + const ChartTwoOverlay* getChartTwoOverlay() const { return m_chartOverlay; } private: EventOverlaySettingsEditorDialogRequest(const EventOverlaySettingsEditorDialogRequest&); -- GitLab From de5c1e7865d3906e189bbc79d75d43c4e76e4b3a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 30 Jan 2017 16:03:26 -0600 Subject: [PATCH 192/755] Continuing charting development. Updated ModelChart for scene saving and restoring. --- src/Brain/ChartTwoOverlaySet.cxx | 2 +- src/Brain/ModelChart.cxx | 219 +++++----------------- src/Files/ChartableTwoFileMatrixChart.cxx | 5 - 3 files changed, 46 insertions(+), 180 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 1eea38dd9..31feeb276 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -505,7 +505,7 @@ ChartTwoOverlaySet::firstOverlaySelectionChanged() PlainTextStringBuilder description; getDescriptionOfContent(description); - std::cout << "First Overlay Changed: " << qPrintable(description.getText()) << std::endl; + //std::cout << "First Overlay Changed: " << qPrintable(description.getText()) << std::endl; m_inFirstOverlayChangedMethodFlag = false; } diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 9d253a4ea..2b58cd3b3 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -90,10 +90,20 @@ ModelChart::ModelChart(Brain* brain) m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); } - m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); - m_sceneAssistant->add("m_histogramChartOverlaySetArray", "ChartTwoOverlaySetArray", m_histogramChartOverlaySetArray.get()); initializeCharts(); + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", + m_selectedChartTwoDataType); + m_sceneAssistant->add("m_histogramChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_histogramChartOverlaySetArray.get()); + m_sceneAssistant->add("m_matrixChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_matrixChartOverlaySetArray.get()); + m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_lineSeriesChartOverlaySetArray.get()); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); @@ -831,7 +841,19 @@ void ModelChart::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { - CaretAssertToDoFatal(); + std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); + + /* + * Save matrix properties. + */ + SceneObjectMapIntegerKey* matrixPropsMap = new SceneObjectMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP", + SceneObjectDataTypeEnum::SCENE_CLASS); + + for (int32_t tabIndex : tabIndices) { + matrixPropsMap->addClass(tabIndex, m_chartTwoMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, + "m_chartTwoMatrixDisplayProperties")); + } + sceneClass->addChild(matrixPropsMap); } @@ -850,6 +872,9 @@ void ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + const ChartingVersionEnum::Enum chartingVersion = ChartingVersionEnum::CHARTING_VERSION_TWO; sceneClass->addEnumeratedType("chartingVersion", chartingVersion); @@ -883,6 +908,9 @@ ModelChart::restoreModelSpecificInformationFromScene(const SceneAttributes* scen { reset(); + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + const ChartingVersionEnum::Enum chartingVersion = sceneClass->getEnumeratedTypeValue("chartingVersion", ChartingVersionEnum::CHARTING_VERSION_ONE); @@ -970,13 +998,24 @@ ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttrib void ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) -{ +{ /* + * Restore matrix chart series models from scene. + */ + const SceneObjectMapIntegerKey* matrixPropsMap = sceneClass->getMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP"); + if (matrixPropsMap != NULL) { + const std::vector tabIndices = matrixPropsMap->getKeys(); + for (const int32_t tabIndex : tabIndices) { + const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); + m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); + } + } + /* * Restore the chart models */ restoreVersionTwoChartModelsFromScene(sceneAttributes, sceneClass); - CaretAssertToDoFatal(); } /** @@ -1289,175 +1328,7 @@ void ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { - /* - * Restore the chart models - */ - const SceneClassArray* chartModelArray = sceneClass->getClassArray("chartModelArray"); - if (chartModelArray != NULL) { - const int numElements = chartModelArray->getNumberOfArrayElements(); - for (int32_t i = 0; i < numElements; i++) { - const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); - if (chartClassContainer != NULL) { - const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); - const ChartOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", - ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); - const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); - - if ((tabIndex >= 0) - && (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) - && (chartModelClass != NULL)) { - CaretAssertArrayIndex(m_chartModelDataSeries, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - - switch (chartDataType) { - case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - CaretAssert(0); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: - m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, - chartModelClass); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: - m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, - chartModelClass); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, - chartModelClass); - break; - } - } - } - } - } - - /* - * Restore the chart data. - */ - std::vector > restoredChartData; - const SceneClassArray* chartDataArray = sceneClass->getClassArray("chartDataArray"); - if (chartDataArray != NULL) { - const int numElements = chartDataArray->getNumberOfArrayElements(); - for (int32_t i = 0; i < numElements; i++) { - const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); - if (chartDataContainer != NULL) { - const ChartOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", - ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); - const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); - if ((chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) - && (chartDataClass != NULL)) { - ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); - CaretAssert(chartData); - - /* - * The chart's points are saved in the scene and this - * function call restores the points. This is part of - * the original implementation. However, it was decided - * that the when the scene is restored, the data should - * be loaded from the file to reflect any changes made - * to the data file. But, we still load the chart points - * saved to the scene in case the file is missing. - */ - chartData->restoreFromScene(sceneAttributes, chartDataClass); - - /* - * Now load the chart data from the file using the - * information in the chart's data source. If this is - * successful, then overwrite the chart data points - * that were loaded from the scene file. - * - * Also need to copy the unique identifier so that - * the chart data goes to the correct model. - */ - ChartData* newChartData = loadCartesianChartWhenRestoringScene(chartData); - if (newChartData != NULL) { - newChartData->setUniqueIdentifier(chartData->getUniqueIdentifier()); - newChartData->copySelectionStatusForAllTabs(chartData); - delete chartData; - chartData = newChartData; - } - else { - const AString msg("FAILED to load line chart data from file for " - + chartData->getChartDataSource()->getDescription() - + " so chart points from scene will be used. If content of the file " - " has changed since the scene was created, the chart may not be accurate."); - sceneAttributes->addToErrorMessage(msg); - CaretLogWarning(msg); - } - - restoredChartData.push_back(QSharedPointer(chartData)); - } - } - } - } - - /* - * Have chart models restore pointers to chart data - * The chart models use shared pointers are used since the chart - * data may be in multiple tabs. User may remove the charts - * from some tabs but not others and shared pointers make management - * easier. - */ - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartModelDataSeries[i]->restoreChartDataFromScene(sceneAttributes, - restoredChartData); - } - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartModelFrequencySeries[i]->restoreChartDataFromScene(sceneAttributes, - restoredChartData); - } - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartModelTimeSeries[i]->restoreChartDataFromScene(sceneAttributes, - restoredChartData); - } - - /* - * The chart data are also saved here as weak pointers so - * that they can be saved to a scene only one time. If - */ - for (std::vector >::iterator rcdIter = restoredChartData.begin(); - rcdIter != restoredChartData.end(); - rcdIter++) { - QSharedPointer chartPointer = *rcdIter; - - switch (chartPointer->getChartDataType()) { - case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: - CaretAssert(0); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - CaretAssert(0); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - CaretAssert(0); - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: - { - QSharedPointer cartChartPointer = chartPointer.dynamicCast(); - CaretAssert( ! cartChartPointer.isNull()); - m_dataSeriesChartData.push_back(cartChartPointer); - } - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: - { - QSharedPointer cartChartPointer = chartPointer.dynamicCast(); - CaretAssert( ! cartChartPointer.isNull()); - m_frequencySeriesChartData.push_back(cartChartPointer); - } - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - { - QSharedPointer cartChartPointer = chartPointer.dynamicCast(); - CaretAssert( ! cartChartPointer.isNull()); - m_timeSeriesChartData.push_back(cartChartPointer); - } - break; - } - } + /* Probably nothing to do here */ } /** diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 1fd53de45..1e3d64f5e 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -547,13 +547,8 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); if (scalarDataSeriesFile != NULL) { - CaretAssertToDoWarning(); scalarDataSeriesFile->setSelectedMapIndex(tabIndex, rowColumnIndex); -// const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(tabIndex); -// if (scalarDataSeriesMapIndex >= 0) { -// rowIndicesSet.insert(scalarDataSeriesMapIndex); -// } } } -- GitLab From a8e372db60c7807b108f413896b0d741b077ae60 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 31 Jan 2017 14:48:00 -0600 Subject: [PATCH 193/755] Continuing new charting. Added identification of matrix chart cells. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 402 ++++++++---------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 15 +- src/Brain/CMakeLists.txt | 6 + src/Brain/IdentificationStringBuilder.cxx | 1 - src/Brain/IdentificationTextGenerator.cxx | 92 +++- src/Brain/IdentificationTextGenerator.h | 12 + src/Brain/SelectionItemChartTwoHistogram.cxx | 109 +++++ src/Brain/SelectionItemChartTwoHistogram.h | 61 +++ src/Brain/SelectionItemChartTwoLineSeries.cxx | 108 +++++ src/Brain/SelectionItemChartTwoLineSeries.h | 61 +++ src/Brain/SelectionItemChartTwoMatrix.cxx | 169 ++++++++ src/Brain/SelectionItemChartTwoMatrix.h | 78 ++++ src/Brain/SelectionItemDataTypeEnum.cxx | 12 + src/Brain/SelectionItemDataTypeEnum.h | 6 + src/Brain/SelectionManager.cxx | 65 ++- src/Brain/SelectionManager.h | 23 + src/GuiQt/ChartTwoOverlayViewController.cxx | 81 ++-- src/GuiQt/GuiManager.cxx | 99 ++++- 18 files changed, 1138 insertions(+), 262 deletions(-) create mode 100644 src/Brain/SelectionItemChartTwoHistogram.cxx create mode 100644 src/Brain/SelectionItemChartTwoHistogram.h create mode 100644 src/Brain/SelectionItemChartTwoLineSeries.cxx create mode 100644 src/Brain/SelectionItemChartTwoLineSeries.h create mode 100644 src/Brain/SelectionItemChartTwoMatrix.cxx create mode 100644 src/Brain/SelectionItemChartTwoMatrix.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index a2edef94b..2f37082a2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -41,6 +41,10 @@ #include "IdentificationWithColor.h" #include "ModelChart.h" #include "SessionManager.h" +#include "SelectionItemChartTwoHistogram.h" +#include "SelectionItemChartTwoLineSeries.h" +#include "SelectionItemChartTwoMatrix.h" +#include "SelectionManager.h" using namespace caret; @@ -120,6 +124,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_viewport[3] = viewport[3]; m_tabIndex = tabIndex; + m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); + m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); + m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); /* * Check for a 'selection' type mode @@ -129,17 +136,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: - CaretAssertToDoWarning(); - return; -// if (chartDataSeriesID->isEnabledForSelection() -// || chartFrequencySeriesID->isEnabledForSelection() -// || chartTimeSeriesID->isEnabledForSelection()) { -// m_identificationModeFlag = true; -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// else { -// return; -// } + if (m_selectionItemHistogram->isEnabledForSelection() + || m_selectionItemLineSeries->isEnabledForSelection() + || m_selectionItemMatrix->isEnabledForSelection()) { + m_identificationModeFlag = true; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + return; + } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; @@ -178,10 +183,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, } } - if (m_identificationModeFlag) { - processIdentification(); - } - restoreStateOfOpenGL(); } @@ -191,34 +192,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, void BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() { - /* - * Check for a 'selection' type mode - */ - m_identificationModeFlag = false; - switch (m_fixedPipelineDrawing->mode) { - case BrainOpenGLFixedPipeline::MODE_DRAWING: - break; - case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: -// if (chartDataSeriesID->isEnabledForSelection() -// || chartFrequencySeriesID->isEnabledForSelection() -// || chartTimeSeriesID->isEnabledForSelection()) { -// m_identificationModeFlag = true; -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// else { - CaretAssertToDoWarning(); - return; -// } - break; - case BrainOpenGLFixedPipeline::MODE_PROJECTION: - return; - break; - } - - saveStateOfOpenGL(); - - resetIdentification(); - const int32_t vpX = m_viewport[0]; const int32_t vpY = m_viewport[1]; const int32_t vpWidth = m_viewport[2]; @@ -390,16 +363,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() drawHistogramChartContent(histogramChart); } } - - /* - * Process selection - */ - if (m_identificationModeFlag) { - processIdentification(); - } - - restoreStateOfOpenGL(); - } /* @@ -424,8 +387,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() m_viewport[3]); bool applyTransformationsFlag = true; -// float panningXY[2] = { 0.0, 0.0 }; -// float zooming = 1.0; float cellWidth = 1.0; float cellHeight = 1.0; @@ -474,37 +435,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() cellHeight *= cellHeightZoom; } - - //ChartMatrixDisplayProperties* matrixProperties = chartMatrixInterface->getChartMatrixDisplayProperties(m_tabIndex); - //CaretAssert(matrixProperties); - const ChartMatrixScaleModeEnum::Enum scaleMode = ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO; // matrixProperties->getScaleMode(); - switch (scaleMode) { - case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: - /* - * Auto scale 'fills' the matrix region - * and updates the width and height in the - * matrix properties for use in manual mode. - * There is NO zooming or panning for Auto scale. - */ - //cellWidth = graphicsWidth / numberOfCols; - //cellHeight = graphicsHeight / numberOfRows; - - //matrixProperties->setCellWidth(cellWidth); - //matrixProperties->setCellHeight(cellHeight); - break; - case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: - /* - * Use the cell width and height for manual mode - * and allow both panning and zooming. - */ - //cellWidth = matrixProperties->getCellWidth(); - //cellHeight = matrixProperties->getCellHeight(); - - //matrixProperties->getViewPanning(panningXY); - //zooming = matrixProperties->getViewZooming(); - //applyTransformationsFlag = true; - break; - } /* * Set the coordinates for the area in which the matrix is drawn. */ @@ -569,10 +499,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() && (overlayColumns == numberOfCols)) { drawMatrixChartContent(matrixChart, chartOverlay->getMatrixTriangularViewingMode(), - //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL, - //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL, - //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL, - //ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL, cellWidth, cellHeight, m_zooming); @@ -657,6 +583,24 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float cellHeight, const float zooming) { + m_identificationModeFlag = false; + switch (m_fixedPipelineDrawing->mode) { + case BrainOpenGLFixedPipeline::MODE_DRAWING: + break; + case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: + if (m_selectionItemMatrix->isEnabledForSelection()) { + m_identificationModeFlag = true; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + return; + } + break; + case BrainOpenGLFixedPipeline::MODE_PROJECTION: + return; + break; + } + int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; @@ -697,10 +641,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); -// getMatrixHighlighting(matrixChart -// selectedRowIndices, -// selectedColumnIndices); - uint8_t highlightRGBByte[3]; m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); const float highlightRGB[3] = { @@ -1125,6 +1065,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glPolygonMode(GL_FRONT, GL_FILL); } + + if (m_identificationModeFlag) { + processMatrixIdentification(matrixChart); + } } /** @@ -1214,129 +1158,157 @@ BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() } /** - * Process identification. + * Process identification for histogram. + * + * @param histogramChart + * The histogram chart. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::processIdentification() +BrainOpenGLChartTwoDrawingFixedPipeline::processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart) { - CaretAssertToDoWarning(); -// int32_t identifiedItemIndex; -// float depth = -1.0; -// -// if (m_chartModelDataSeriesBeingDrawnForIdentification != NULL) { -// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// identifiedItemIndex, -// depth); -// if (identifiedItemIndex >= 0) { -// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; -// const int32_t chartDataIndex = m_identificationIndices[idIndex]; -// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; -// -// SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); -// if (chartDataSeriesID->isOtherScreenDepthCloserToViewer(depth)) { -// ChartDataCartesian* chartDataCartesian = -// dynamic_cast(m_chartModelDataSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); -// CaretAssert(chartDataCartesian); -// chartDataSeriesID->setChart(m_chartModelDataSeriesBeingDrawnForIdentification, -// chartDataCartesian, -// chartLineIndex); -// -// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); -// const float lineXYZ[3] = { -// chartPoint->getX(), -// chartPoint->getY(), -// 0.0 -// }; -// -// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartDataSeriesID, -// lineXYZ); -// } -// } -// } -// else if (m_chartModelFrequencySeriesBeingDrawnForIdentification != NULL) { -// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// identifiedItemIndex, -// depth); -// if (identifiedItemIndex >= 0) { -// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; -// const int32_t chartDataIndex = m_identificationIndices[idIndex]; -// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; -// -// SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); -// if (chartFrequencySeriesID->isOtherScreenDepthCloserToViewer(depth)) { -// ChartDataCartesian* chartDataCartesian = -// dynamic_cast(m_chartModelFrequencySeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); -// CaretAssert(chartDataCartesian); -// chartFrequencySeriesID->setChart(m_chartModelFrequencySeriesBeingDrawnForIdentification, -// chartDataCartesian, -// chartLineIndex); -// -// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); -// const float lineXYZ[3] = { -// chartPoint->getX(), -// chartPoint->getY(), -// 0.0 -// }; -// -// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartFrequencySeriesID, -// lineXYZ); -// } -// } -// } -// else if (m_chartModelTimeSeriesBeingDrawnForIdentification != NULL) { -// m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// identifiedItemIndex, -// depth); -// if (identifiedItemIndex >= 0) { -// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; -// const int32_t chartDataIndex = m_identificationIndices[idIndex]; -// const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; -// -// SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); -// if (chartTimeSeriesID->isOtherScreenDepthCloserToViewer(depth)) { -// ChartDataCartesian* chartDataCartesian = -// dynamic_cast(m_chartModelTimeSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); -// CaretAssert(chartDataCartesian); -// chartTimeSeriesID->setChart(m_chartModelTimeSeriesBeingDrawnForIdentification, -// chartDataCartesian, -// chartLineIndex); -// -// const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); -// const float lineXYZ[3] = { -// chartPoint->getX(), -// chartPoint->getY(), -// 0.0 -// }; -// -// m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartTimeSeriesID, -// lineXYZ); -// } -// } -// } -// else if (m_chartableMatrixInterfaceBeingDrawnForIdentification != NULL) { -// m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// identifiedItemIndex, -// depth); -// if (identifiedItemIndex >= 0) { -// const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; -// const int32_t rowIndex = m_identificationIndices[idIndex]; -// const int32_t columnIndex = m_identificationIndices[idIndex + 1]; -// -// SelectionItemChartMatrix* chartMatrixID = m_brain->getSelectionManager()->getChartMatrixIdentification(); -// if (chartMatrixID->isOtherScreenDepthCloserToViewer(depth)) { -// chartMatrixID->setChartMatrix(m_chartableMatrixInterfaceBeingDrawnForIdentification, -// rowIndex, -// columnIndex); -// } -// } -// } } + +/** + * Process identification for line-series. + * + * @param lineSeriesChart + * The line-series chart. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart) +{ + // int32_t identifiedItemIndex; + // float depth = -1.0; + // + // if (m_chartModelDataSeriesBeingDrawnForIdentification != NULL) { + // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, + // m_fixedPipelineDrawing->mouseX, + // m_fixedPipelineDrawing->mouseY, + // identifiedItemIndex, + // depth); + // if (identifiedItemIndex >= 0) { + // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; + // const int32_t chartDataIndex = m_identificationIndices[idIndex]; + // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; + // + // SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); + // if (chartDataSeriesID->isOtherScreenDepthCloserToViewer(depth)) { + // ChartDataCartesian* chartDataCartesian = + // dynamic_cast(m_chartModelDataSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); + // CaretAssert(chartDataCartesian); + // chartDataSeriesID->setChart(m_chartModelDataSeriesBeingDrawnForIdentification, + // chartDataCartesian, + // chartLineIndex); + // + // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); + // const float lineXYZ[3] = { + // chartPoint->getX(), + // chartPoint->getY(), + // 0.0 + // }; + // + // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartDataSeriesID, + // lineXYZ); + // } + // } + // } + // else if (m_chartModelFrequencySeriesBeingDrawnForIdentification != NULL) { + // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, + // m_fixedPipelineDrawing->mouseX, + // m_fixedPipelineDrawing->mouseY, + // identifiedItemIndex, + // depth); + // if (identifiedItemIndex >= 0) { + // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; + // const int32_t chartDataIndex = m_identificationIndices[idIndex]; + // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; + // + // SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); + // if (chartFrequencySeriesID->isOtherScreenDepthCloserToViewer(depth)) { + // ChartDataCartesian* chartDataCartesian = + // dynamic_cast(m_chartModelFrequencySeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); + // CaretAssert(chartDataCartesian); + // chartFrequencySeriesID->setChart(m_chartModelFrequencySeriesBeingDrawnForIdentification, + // chartDataCartesian, + // chartLineIndex); + // + // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); + // const float lineXYZ[3] = { + // chartPoint->getX(), + // chartPoint->getY(), + // 0.0 + // }; + // + // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartFrequencySeriesID, + // lineXYZ); + // } + // } + // } + // else if (m_chartModelTimeSeriesBeingDrawnForIdentification != NULL) { + // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, + // m_fixedPipelineDrawing->mouseX, + // m_fixedPipelineDrawing->mouseY, + // identifiedItemIndex, + // depth); + // if (identifiedItemIndex >= 0) { + // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; + // const int32_t chartDataIndex = m_identificationIndices[idIndex]; + // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; + // + // SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); + // if (chartTimeSeriesID->isOtherScreenDepthCloserToViewer(depth)) { + // ChartDataCartesian* chartDataCartesian = + // dynamic_cast(m_chartModelTimeSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); + // CaretAssert(chartDataCartesian); + // chartTimeSeriesID->setChart(m_chartModelTimeSeriesBeingDrawnForIdentification, + // chartDataCartesian, + // chartLineIndex); + // + // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); + // const float lineXYZ[3] = { + // chartPoint->getX(), + // chartPoint->getY(), + // 0.0 + // }; + // + // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartTimeSeriesID, + // lineXYZ); + // } + // } + // } + +} + +/** + * Process identification for matrix. + * + * @param matrixChart + * The matrix chart. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart) +{ + if (matrixChart != NULL) { + int32_t identifiedItemIndex; + float depth = -1.0; + m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + identifiedItemIndex, + depth); + if (identifiedItemIndex >= 0) { + const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; + const int32_t rowIndex = m_identificationIndices[idIndex]; + const int32_t columnIndex = m_identificationIndices[idIndex + 1]; + + if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(depth)) { + m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), + rowIndex, + columnIndex); + } + } + } + +} + diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 3437d3d5a..72ec7ead6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -32,6 +32,9 @@ namespace caret { class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class ModelChart; + class SelectionItemChartTwoHistogram; + class SelectionItemChartTwoLineSeries; + class SelectionItemChartTwoMatrix; class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { @@ -87,7 +90,11 @@ namespace caret { void resetIdentification(); - void processIdentification(); + void processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart); + + void processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart); + + void processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart); void addToChartMatrixIdentification(const int32_t matrixRowIndex, const int32_t matrixColumnIndex, @@ -132,6 +139,12 @@ namespace caret { CaretPreferences* m_preferences; + SelectionItemChartTwoHistogram* m_selectionItemHistogram; + + SelectionItemChartTwoLineSeries* m_selectionItemLineSeries; + + SelectionItemChartTwoMatrix* m_selectionItemMatrix; + bool m_identificationModeFlag; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 74b058a30..a1a540ca5 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -159,6 +159,9 @@ SelectionItemChartDataSeries.h SelectionItemChartFrequencySeries.h SelectionItemChartMatrix.h SelectionItemChartTimeSeries.h +SelectionItemChartTwoHistogram.h +SelectionItemChartTwoLineSeries.h +SelectionItemChartTwoMatrix.h SelectionItemCiftiConnectivityMatrixRowColumn.h SelectionItemFocusSurface.h SelectionItemFocusVolume.h @@ -299,6 +302,9 @@ SelectionItemChartDataSeries.cxx SelectionItemChartFrequencySeries.cxx SelectionItemChartMatrix.cxx SelectionItemChartTimeSeries.cxx +SelectionItemChartTwoHistogram.cxx +SelectionItemChartTwoLineSeries.cxx +SelectionItemChartTwoMatrix.cxx SelectionItemCiftiConnectivityMatrixRowColumn.cxx SelectionItemFocusSurface.cxx SelectionItemFocusVolume.cxx diff --git a/src/Brain/IdentificationStringBuilder.cxx b/src/Brain/IdentificationStringBuilder.cxx index 0a34799d3..fe3d0916f 100644 --- a/src/Brain/IdentificationStringBuilder.cxx +++ b/src/Brain/IdentificationStringBuilder.cxx @@ -18,7 +18,6 @@ */ /*LICENSE_END*/ - #include "IdentificationStringBuilder.h" using namespace caret; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index ccf7508e7..ba9f4f2fe 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -33,6 +33,9 @@ #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartableMatrixInterface.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartableTwoFileMatrixChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CaretVolumeExtension.h" @@ -50,6 +53,9 @@ #include "SelectionItemChartMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemChartTimeSeries.h" +#include "SelectionItemChartTwoHistogram.h" +#include "SelectionItemChartTwoLineSeries.h" +#include "SelectionItemChartTwoMatrix.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemImage.h" @@ -143,6 +149,15 @@ IdentificationTextGenerator::createIdentificationText(const SelectionManager* id this->generateCiftiConnectivityMatrixIdentificationText(idText, idManager->getCiftiConnectivityMatrixRowColumnIdentification()); + this->generateChartTwoHistogramIdentificationText(idText, + idManager->getChartTwoHistogramIdentification()); + + this->generateChartTwoLineSeriesIdentificationText(idText, + idManager->getChartTwoLineSeriesIdentification()); + + this->generateChartTwoMatrixIdentificationText(idText, + idManager->getChartTwoMatrixIdentification()); + this->generateImageIdentificationText(idText, idManager->getImageIdentification()); @@ -772,6 +787,79 @@ IdentificationTextGenerator::generateChartMatrixIdentificationText(Identificatio } } +/** + * Generate identification text for a chart two histogram. + * + * @param idText + * String builder for identification text. + * @param idChartTwoHistogram + * Information for selected chart two histogram. + */ +void +IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoHistogram* idChartTwoHistogram) const +{ + CaretAssertToDoWarning(); +} + +/** + * Generate identification text for a chart two line-series. + * + * @param idText + * String builder for identification text. + * @param idChartTwoLineSeries + * Information for selected chart two line-series. + */ +void +IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const +{ + CaretAssertToDoWarning(); +} + +/** + * Generate identification text for a chart two matrix. + * + * @param idText + * String builder for identification text. + * @param idChartTwoMatrix + * Information for selected chart two matrix. + */ +void +IdentificationTextGenerator::generateChartTwoMatrixIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoMatrix* idChartTwoMatrix) const +{ + if (idChartTwoMatrix->isValid()) { + const ChartableTwoFileMatrixChart* matrixChart = idChartTwoMatrix->getFileMatrixChart(); + CaretAssert(matrixChart); + + const int32_t rowIndex = idChartTwoMatrix->getRowIndex(); + const int32_t colIndex = idChartTwoMatrix->getColumnIndex(); + + const CaretMappableDataFile* mapFile = matrixChart->getCaretMappableDataFile(); + CaretAssert(mapFile); + + AString boldText("MATRIX ROW/COLUMN"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + + const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); + if (rowIndex >= 0) { + const AString rowName = (matrixFile != NULL) ? (" " + matrixFile->getRowName(rowIndex)) : ""; + idText.addLine(true, + "Row", + (AString::number(rowIndex) + rowName)); + } + if (colIndex >= 0) { + const AString colName = (matrixFile != NULL) ? (" " + matrixFile->getColumnName(colIndex)) : ""; + idText.addLine(true, + "Column", + (AString::number(colIndex) + colName)); + } + } +} + /** * Generate identification text for a CIFTI Connectivity Matrix Row/Column * @param idText @@ -793,8 +881,8 @@ IdentificationTextGenerator::generateCiftiConnectivityMatrixIdentificationText(I boldText, connMatrixFile->getFileNameNoPath()); - AString rowName = ""; - AString colName = ""; + AString rowName = " "; + AString colName = " "; bool validData = true; if (validData) { if (rowIndex >= 0) { diff --git a/src/Brain/IdentificationTextGenerator.h b/src/Brain/IdentificationTextGenerator.h index 14f8a79be..e38aab140 100644 --- a/src/Brain/IdentificationTextGenerator.h +++ b/src/Brain/IdentificationTextGenerator.h @@ -34,6 +34,9 @@ namespace caret { class SelectionItemChartDataSeries; class SelectionItemChartFrequencySeries; class SelectionItemChartMatrix; + class SelectionItemChartTwoHistogram; + class SelectionItemChartTwoLineSeries; + class SelectionItemChartTwoMatrix; class SelectionItemCiftiConnectivityMatrixRowColumn; class SelectionItemChartTimeSeries; class SelectionItemFocusSurface; @@ -92,6 +95,15 @@ namespace caret { void generateChartMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartMatrix* idChartMatrix) const; + void generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoHistogram* idChartTwoHistogram) const; + + void generateChartTwoLineSeriesIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const; + + void generateChartTwoMatrixIdentificationText(IdentificationStringBuilder& idText, + const SelectionItemChartTwoMatrix* idChartTwoMatrix) const; + void generateCiftiConnectivityMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemCiftiConnectivityMatrixRowColumn* idCiftiConnMatrix) const; diff --git a/src/Brain/SelectionItemChartTwoHistogram.cxx b/src/Brain/SelectionItemChartTwoHistogram.cxx new file mode 100644 index 000000000..1a26665a4 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoHistogram.cxx @@ -0,0 +1,109 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ +#include "SelectionItemChartTwoHistogram.h" +#undef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SelectionItemChartTwoHistogram + * \brief Selection of charting two histogram + * \ingroup Brain + */ + +/** + * Constructor. + */ +SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram() +: SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_HISTOGRAM) +{ + +} + +/** + * Destructor. + */ +SelectionItemChartTwoHistogram::~SelectionItemChartTwoHistogram() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) +: SelectionItem(obj) +{ + this->copyHelperSelectionItemChartTwoHistogram(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SelectionItemChartTwoHistogram& +SelectionItemChartTwoHistogram::operator=(const SelectionItemChartTwoHistogram& obj) +{ + if (this != &obj) { + SelectionItem::operator=(obj); + this->copyHelperSelectionItemChartTwoHistogram(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) +{ + +} + +/** + * @return True if the selected chart is valid, else false. + */ +bool +SelectionItemChartTwoHistogram::isValid() const +{ + return false; +} + +/** + * Reset the selections. + */ +void +SelectionItemChartTwoHistogram::reset() +{ +} + + diff --git a/src/Brain/SelectionItemChartTwoHistogram.h b/src/Brain/SelectionItemChartTwoHistogram.h new file mode 100644 index 000000000..284388e96 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoHistogram.h @@ -0,0 +1,61 @@ +#ifndef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ +#define __SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "SelectionItem.h" + + + +namespace caret { + + class SelectionItemChartTwoHistogram : public SelectionItem { + + public: + SelectionItemChartTwoHistogram(); + + virtual ~SelectionItemChartTwoHistogram(); + + SelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); + + SelectionItemChartTwoHistogram& operator=(const SelectionItemChartTwoHistogram& obj); + + virtual bool isValid() const override; + + virtual void reset() override; + + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ + // +#endif // __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ + +} // namespace +#endif //__SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ diff --git a/src/Brain/SelectionItemChartTwoLineSeries.cxx b/src/Brain/SelectionItemChartTwoLineSeries.cxx new file mode 100644 index 000000000..9c79c1a73 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoLineSeries.cxx @@ -0,0 +1,108 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ +#include "SelectionItemChartTwoLineSeries.h" +#undef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SelectionItemChartTwoLineSeries + * \brief Selection of chart version two line series + * \ingroup Brain + */ + +/** + * Constructor. + */ +SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries() +: SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LINE_SERIES) +{ + +} + +/** + * Destructor. + */ +SelectionItemChartTwoLineSeries::~SelectionItemChartTwoLineSeries() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) +: SelectionItem(obj) +{ + this->copyHelperSelectionItemChartTwoLineSeries(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SelectionItemChartTwoLineSeries& +SelectionItemChartTwoLineSeries::operator=(const SelectionItemChartTwoLineSeries& obj) +{ + if (this != &obj) { + SelectionItem::operator=(obj); + this->copyHelperSelectionItemChartTwoLineSeries(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SelectionItemChartTwoLineSeries::copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) +{ + +} + +/** + * @return True if the selected chart is valid, else false. + */ +bool +SelectionItemChartTwoLineSeries::isValid() const +{ + return false; +} + +/** + * Reset the selections. + */ +void +SelectionItemChartTwoLineSeries::reset() +{ +} + diff --git a/src/Brain/SelectionItemChartTwoLineSeries.h b/src/Brain/SelectionItemChartTwoLineSeries.h new file mode 100644 index 000000000..cf3799e8d --- /dev/null +++ b/src/Brain/SelectionItemChartTwoLineSeries.h @@ -0,0 +1,61 @@ +#ifndef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ +#define __SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "SelectionItem.h" + + + +namespace caret { + + class SelectionItemChartTwoLineSeries : public SelectionItem { + + public: + SelectionItemChartTwoLineSeries(); + + virtual ~SelectionItemChartTwoLineSeries(); + + SelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj); + + SelectionItemChartTwoLineSeries& operator=(const SelectionItemChartTwoLineSeries& obj); + + virtual bool isValid() const override; + + virtual void reset() override; + + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ + // +#endif // __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ + +} // namespace +#endif //__SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ diff --git a/src/Brain/SelectionItemChartTwoMatrix.cxx b/src/Brain/SelectionItemChartTwoMatrix.cxx new file mode 100644 index 000000000..b6c560249 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoMatrix.cxx @@ -0,0 +1,169 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ +#include "SelectionItemChartTwoMatrix.h" +#undef __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SelectionItemChartTwoMatrix + * \brief Selection of chart two matrix + * \ingroup Brain + */ + +/** + * Constructor. + */ +SelectionItemChartTwoMatrix::SelectionItemChartTwoMatrix() +: SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_MATRIX) +{ + m_fileMatrixChart = NULL; + m_rowIndex = -1; + m_columnIndex = -1; +} + +/** + * Destructor. + */ +SelectionItemChartTwoMatrix::~SelectionItemChartTwoMatrix() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SelectionItemChartTwoMatrix::SelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj) +: SelectionItem(obj) +{ + this->copyHelperSelectionItemChartTwoMatrix(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SelectionItemChartTwoMatrix& +SelectionItemChartTwoMatrix::operator=(const SelectionItemChartTwoMatrix& obj) +{ + if (this != &obj) { + SelectionItem::operator=(obj); + this->copyHelperSelectionItemChartTwoMatrix(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SelectionItemChartTwoMatrix::copyHelperSelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj) +{ + m_fileMatrixChart = obj.m_fileMatrixChart; + m_rowIndex = obj.m_rowIndex; + m_columnIndex = obj.m_columnIndex; +} + +/** + * @return True if the selected chart is valid, else false. + */ +bool +SelectionItemChartTwoMatrix::isValid() const +{ + if ((m_fileMatrixChart != NULL) + && (m_rowIndex >= 0) + && (m_columnIndex >= 0)) { + return true; + } + + return false; +} + +/** + * Reset the selections. + */ +void +SelectionItemChartTwoMatrix::reset() +{ + m_fileMatrixChart = NULL; + m_rowIndex = -1; + m_columnIndex = -1; +} + +/** + * @return Matrix chart that was selected. + */ +ChartableTwoFileMatrixChart* +SelectionItemChartTwoMatrix::getFileMatrixChart() const +{ + return m_fileMatrixChart; +} + +/** + * @return Row index selected. + */ +int32_t +SelectionItemChartTwoMatrix::getRowIndex() const +{ + return m_rowIndex; +} + +/** + * @return column index selected. + */ +int32_t +SelectionItemChartTwoMatrix::getColumnIndex() const +{ + return m_columnIndex; +} + +/** + * Set the matrix chart. + * + * @param fileMatrixChart + * Matrix chart that was selected. + * @param rowIndex + * Index of row selected. + * @param columnIndex + * Index of column selected. + */ +void +SelectionItemChartTwoMatrix::setMatrixChart(ChartableTwoFileMatrixChart* fileMatrixChart, + const int32_t rowIndex, + const int32_t columnIndex) +{ + m_fileMatrixChart = fileMatrixChart; + m_rowIndex = rowIndex; + m_columnIndex = columnIndex; +} + + diff --git a/src/Brain/SelectionItemChartTwoMatrix.h b/src/Brain/SelectionItemChartTwoMatrix.h new file mode 100644 index 000000000..98081dbb8 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoMatrix.h @@ -0,0 +1,78 @@ +#ifndef __SELECTION_ITEM_CHART_TWO_MATRIX_H__ +#define __SELECTION_ITEM_CHART_TWO_MATRIX_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "SelectionItem.h" + + + +namespace caret { + + class ChartableTwoFileMatrixChart; + + class SelectionItemChartTwoMatrix : public SelectionItem { + + public: + SelectionItemChartTwoMatrix(); + + virtual ~SelectionItemChartTwoMatrix(); + + SelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj); + + SelectionItemChartTwoMatrix& operator=(const SelectionItemChartTwoMatrix& obj); + + virtual bool isValid() const override; + + virtual void reset() override; + + ChartableTwoFileMatrixChart* getFileMatrixChart() const; + + int32_t getRowIndex() const; + + int32_t getColumnIndex() const; + + void setMatrixChart(ChartableTwoFileMatrixChart* fileMatrixChart, + const int32_t rowIndex, + const int32_t columnIndex); + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperSelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj); + + ChartableTwoFileMatrixChart* m_fileMatrixChart; + + int32_t m_rowIndex; + + int32_t m_columnIndex; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ + // +#endif // __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ + +} // namespace +#endif //__SELECTION_ITEM_CHART_TWO_MATRIX_H__ diff --git a/src/Brain/SelectionItemDataTypeEnum.cxx b/src/Brain/SelectionItemDataTypeEnum.cxx index 7e4816ff2..fc165a10e 100644 --- a/src/Brain/SelectionItemDataTypeEnum.cxx +++ b/src/Brain/SelectionItemDataTypeEnum.cxx @@ -99,6 +99,18 @@ SelectionItemDataTypeEnum::initialize() "CHART_TIME_SERIES", "Time-Series Chart")); + enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_HISTOGRAM, + "CHART_TWO_HISTOGRAM", + "Histogram Chart Two")); + + enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_LINE_SERIES, + "CHART_TWO_LINE_SERIES", + "Line-Series Chart Two")); + + enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_MATRIX, + "CHART_TWO_MATRIX", + "Matrix Chart Two")); + enumData.push_back(SelectionItemDataTypeEnum(CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN, "CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN", "CIFTI Connectivity Row or Column")); diff --git a/src/Brain/SelectionItemDataTypeEnum.h b/src/Brain/SelectionItemDataTypeEnum.h index 22f0b7276..965735320 100644 --- a/src/Brain/SelectionItemDataTypeEnum.h +++ b/src/Brain/SelectionItemDataTypeEnum.h @@ -57,6 +57,12 @@ public: CHART_MATRIX, /** Time-Series Chart */ CHART_TIME_SERIES, + /** Version Two Chart Histogram */ + CHART_TWO_HISTOGRAM, + /** Version Two Chart Line-Series */ + CHART_TWO_LINE_SERIES, + /** Version Two Chart Matrix */ + CHART_TWO_MATRIX, /** CIFTI Connectivity Matrix Row or Column */ CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN, /** Focus on Surface */ diff --git a/src/Brain/SelectionManager.cxx b/src/Brain/SelectionManager.cxx index 7946f5222..1fc97a436 100644 --- a/src/Brain/SelectionManager.cxx +++ b/src/Brain/SelectionManager.cxx @@ -37,6 +37,9 @@ #include "SelectionItemChartFrequencySeries.h" #include "SelectionItemChartMatrix.h" #include "SelectionItemChartTimeSeries.h" +#include "SelectionItemChartTwoHistogram.h" +#include "SelectionItemChartTwoLineSeries.h" +#include "SelectionItemChartTwoMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" @@ -72,6 +75,10 @@ SelectionManager::SelectionManager() m_chartDataSeriesIdentification = new SelectionItemChartDataSeries(); m_chartDataFrequencyIdentification = new SelectionItemChartFrequencySeries(); m_chartMatrixIdentification = new SelectionItemChartMatrix(); + m_chartTwoHistogramIdentification = std::unique_ptr(new SelectionItemChartTwoHistogram()); + m_chartTwoLineSeriesIdentification = std::unique_ptr(new SelectionItemChartTwoLineSeries()); + m_chartTwoMatrixIdentification = std::unique_ptr(new SelectionItemChartTwoMatrix()); + m_ciftiConnectivityMatrixRowColumnIdentfication = new SelectionItemCiftiConnectivityMatrixRowColumn(); m_chartTimeSeriesIdentification = new SelectionItemChartTimeSeries(); m_surfaceFocusIdentification = new SelectionItemFocusSurface(); @@ -91,6 +98,9 @@ SelectionManager::SelectionManager() m_allSelectionItems.push_back(m_chartDataFrequencyIdentification); m_allSelectionItems.push_back(m_chartMatrixIdentification); m_allSelectionItems.push_back(m_chartTimeSeriesIdentification); + m_allSelectionItems.push_back(m_chartTwoHistogramIdentification.get()); + m_allSelectionItems.push_back(m_chartTwoLineSeriesIdentification.get()); + m_allSelectionItems.push_back(m_chartTwoMatrixIdentification.get()); m_allSelectionItems.push_back(m_ciftiConnectivityMatrixRowColumnIdentfication); m_allSelectionItems.push_back(m_surfaceFocusIdentification); m_allSelectionItems.push_back(m_surfaceNodeIdentification); @@ -704,7 +714,6 @@ SelectionManager::getChartFrequencySeriesIdentification() const return m_chartDataFrequencyIdentification; } - /** * @return Identification for matrix chart. */ @@ -723,6 +732,60 @@ SelectionManager::getChartMatrixIdentification() const return m_chartMatrixIdentification; } +/** + * @return Identification for chart two histogram identification + */ +SelectionItemChartTwoHistogram* +SelectionManager::getChartTwoHistogramIdentification() +{ + return m_chartTwoHistogramIdentification.get(); +} + +/** + * @return Identification for chart two histogram identification + */ +const SelectionItemChartTwoHistogram* +SelectionManager::getChartTwoHistogramIdentification() const +{ + return m_chartTwoHistogramIdentification.get(); +} + +/** + * @return Identification for chart two line series identification + */ +SelectionItemChartTwoLineSeries* +SelectionManager::getChartTwoLineSeriesIdentification() +{ + return m_chartTwoLineSeriesIdentification.get(); +} + +/** + * @return Identification for chart two line series identification + */ +const SelectionItemChartTwoLineSeries* +SelectionManager::getChartTwoLineSeriesIdentification() const +{ + return m_chartTwoLineSeriesIdentification.get(); +} + +/** + * @return Identification for chart two matrix identification. + */ +SelectionItemChartTwoMatrix* +SelectionManager::getChartTwoMatrixIdentification() +{ + return m_chartTwoMatrixIdentification.get(); +} + +/** + * @return Identification for chart two matrix identification. + */ +const SelectionItemChartTwoMatrix* +SelectionManager::getChartTwoMatrixIdentification() const +{ + return m_chartTwoMatrixIdentification.get(); +} + /** * @return Identification for CIFTI Connectivity Matrix Row/Column. */ diff --git a/src/Brain/SelectionManager.h b/src/Brain/SelectionManager.h index ae33c68c9..cae784499 100644 --- a/src/Brain/SelectionManager.h +++ b/src/Brain/SelectionManager.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include "CaretObject.h" #include "EventListenerInterface.h" @@ -35,6 +37,9 @@ namespace caret { class SelectionItemChartFrequencySeries; class SelectionItemChartMatrix; class SelectionItemChartTimeSeries; + class SelectionItemChartTwoHistogram; + class SelectionItemChartTwoLineSeries; + class SelectionItemChartTwoMatrix; class SelectionItemCiftiConnectivityMatrixRowColumn; class SelectionItemFocusSurface; class SelectionItemFocusVolume; @@ -128,6 +133,18 @@ namespace caret { const SelectionItemCiftiConnectivityMatrixRowColumn* getCiftiConnectivityMatrixRowColumnIdentification() const; + SelectionItemChartTwoHistogram* getChartTwoHistogramIdentification(); + + const SelectionItemChartTwoHistogram* getChartTwoHistogramIdentification() const; + + SelectionItemChartTwoLineSeries* getChartTwoLineSeriesIdentification(); + + const SelectionItemChartTwoLineSeries* getChartTwoLineSeriesIdentification() const; + + SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification(); + + const SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification() const; + AString getIdentificationText(const Brain* brain) const; void filterSelections(const bool applySelectionBackgroundFiltering); @@ -177,6 +194,12 @@ namespace caret { SelectionItemChartTimeSeries* m_chartTimeSeriesIdentification; + std::unique_ptr m_chartTwoHistogramIdentification; + + std::unique_ptr m_chartTwoLineSeriesIdentification; + + std::unique_ptr m_chartTwoMatrixIdentification; + SelectionItemCiftiConnectivityMatrixRowColumn* m_ciftiConnectivityMatrixRowColumnIdentfication; SelectionItemFocusSurface* m_surfaceFocusIdentification; diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index c0ac5df01..365c29c4e 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -50,6 +50,7 @@ using namespace caret; #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventOverlaySettingsEditorDialogRequest.h" +#include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FilePathNamePrefixCompactor.h" @@ -309,8 +310,7 @@ ChartTwoOverlayViewController::fileComboBoxSelected(int indx) updateViewController(m_chartOverlay); m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); - updateGraphicsWindow(); - updateUserInterface(); + updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); // if (file != NULL) { @@ -325,11 +325,11 @@ ChartTwoOverlayViewController::fileComboBoxSelected(int indx) /** * Called when a selection is made from the map index spin box. - * @parm indx + * @parm indxIn * Index of selection. */ void -ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) +ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indxIn) { if (m_chartOverlay == NULL) { @@ -344,17 +344,17 @@ ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; /* - * Overlay indices range [0, N-1] but spin box shows [1, N]. + * Spin box may range [0, N-1] or [1, N] but in source code + * indices are always [0, N-1] */ - const int overlayIndex = indx - 1; - - m_chartOverlay->setSelectionData(file, overlayIndex); + const int32_t indx = indxIn - m_mapRowOrColumnIndexSpinBox->minimum(); + m_chartOverlay->setSelectionData(file, indx); const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, file, - overlayIndex, + indx, m_chartOverlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } @@ -363,14 +363,13 @@ ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indx) * Need to update map name combo box. */ m_mapRowOrColumnNameComboBox->blockSignals(true); - if ((overlayIndex >= 0) - && (overlayIndex < m_mapRowOrColumnNameComboBox->count())) { - m_mapRowOrColumnNameComboBox->setCurrentIndex(overlayIndex); + if ((indx >= 0) + && (indx < m_mapRowOrColumnNameComboBox->count())) { + m_mapRowOrColumnNameComboBox->setCurrentIndex(indx); } m_mapRowOrColumnNameComboBox->blockSignals(false); - this->updateUserInterface(); - this->updateGraphicsWindow(); + this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); } @@ -407,14 +406,15 @@ ChartTwoOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) /* * Need to update map index spin box. - * Note that the map index spin box ranges [1, N]. + * Spin box may range [0, N-1] or [1, N] but in source code + * indices are always [0, N-1] */ + const int spinBoxIndex = indx + m_mapRowOrColumnIndexSpinBox->minimum(); m_mapRowOrColumnIndexSpinBox->blockSignals(true); - m_mapRowOrColumnIndexSpinBox->setValue(indx); + m_mapRowOrColumnIndexSpinBox->setValue(spinBoxIndex); m_mapRowOrColumnIndexSpinBox->blockSignals(false); - this->updateUserInterface(); - this->updateGraphicsWindow(); + this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); } @@ -446,9 +446,7 @@ ChartTwoOverlayViewController::enabledCheckBoxClicked(bool checked) EventManager::get()->sendEvent(selectMapEvent.getPointer()); } - this->updateUserInterface(); - - this->updateGraphicsWindow(); + this->updateUserInterfaceAndGraphicsWindow(); } /** @@ -493,7 +491,7 @@ ChartTwoOverlayViewController::validateYokingSelection() { m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateViewController(m_chartOverlay); - updateGraphicsWindow(); + updateUserInterfaceAndGraphicsWindow(); //EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } @@ -664,8 +662,28 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla m_mapRowOrColumnNameComboBox->addItem(selectedFileMapNames[i]); } m_mapRowOrColumnNameComboBox->setCurrentIndex(selectedMapIndex); - m_mapRowOrColumnIndexSpinBox->setRange(0, numberOfMaps - 1); - m_mapRowOrColumnIndexSpinBox->setValue(selectedMapIndex); + + /* + * Spin box ranges [0, N-1] or [1, N] depending upon data + */ + int32_t mapIndexMinimumValue = 1; + int32_t mapIndexMaximumValue = numberOfMaps; + switch (m_chartOverlay->getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + mapIndexMinimumValue = 0; + mapIndexMaximumValue = numberOfMaps - 1; + break; + } + + m_mapRowOrColumnIndexSpinBox->setRange(mapIndexMinimumValue, mapIndexMaximumValue); + const int spinBoxIndex = selectedMapIndex + m_mapRowOrColumnIndexSpinBox->minimum(); + m_mapRowOrColumnIndexSpinBox->setValue(spinBoxIndex); } m_mapRowOrColumnNameComboBox->blockSignals(false); m_mapRowOrColumnIndexSpinBox->blockSignals(false); @@ -812,12 +830,7 @@ ChartTwoOverlayViewController::updateUserInterfaceAndGraphicsWindow() void ChartTwoOverlayViewController::updateUserInterface() { -// if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); -// } -// else { -// EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).getPointer()); -// } + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** @@ -826,12 +839,8 @@ ChartTwoOverlayViewController::updateUserInterface() void ChartTwoOverlayViewController::updateGraphicsWindow() { -// if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); -// } -// else { -// EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); -// } + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index f6f443831..877e856a8 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -43,6 +43,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" +#include "ChartableTwoFileMatrixChart.h" #include "ChartingDataManager.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" @@ -96,6 +97,7 @@ #include "SceneWindowGeometry.h" #include "SelectionManager.h" #include "SelectionItemChartMatrix.h" +#include "SelectionItemChartTwoMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemSurfaceNodeIdentificationSymbol.h" @@ -2695,15 +2697,15 @@ GuiManager::processIdentification(const int32_t tabIndex, } } - SelectionItemChartMatrix* idChartMatrix = selectionManager->getChartMatrixIdentification(); - if (idChartMatrix->isValid()) { - ChartableMatrixInterface* chartMatrixInterface = idChartMatrix->getChartableMatrixInterface(); + SelectionItemChartMatrix* idChartOneMatrix = selectionManager->getChartMatrixIdentification(); + if (idChartOneMatrix->isValid()) { + ChartableMatrixInterface* chartMatrixInterface = idChartOneMatrix->getChartableMatrixInterface(); if (chartMatrixInterface != NULL) { CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(chartMatrixInterface); if (ciftiParcelFile != NULL) { if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { - const int32_t rowIndex = idChartMatrix->getMatrixRowIndex(); - const int32_t columnIndex = idChartMatrix->getMatrixColumnIndex(); + const int32_t rowIndex = idChartOneMatrix->getMatrixRowIndex(); + const int32_t columnIndex = idChartOneMatrix->getMatrixColumnIndex(); if ((rowIndex >= 0) && (columnIndex >= 0)) { try { @@ -2726,7 +2728,7 @@ GuiManager::processIdentification(const int32_t tabIndex, CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(chartMatrixInterface); if (scalarDataSeriesFile != NULL) { - const int32_t rowIndex = idChartMatrix->getMatrixRowIndex(); + const int32_t rowIndex = idChartOneMatrix->getMatrixRowIndex(); if (rowIndex >= 0) { scalarDataSeriesFile->setSelectedMapIndex(tabIndex, rowIndex); @@ -2770,6 +2772,91 @@ GuiManager::processIdentification(const int32_t tabIndex, } } + SelectionItemChartTwoMatrix* idChartTwoMatrix = selectionManager->getChartTwoMatrixIdentification(); + if (idChartTwoMatrix != NULL) { + if (idChartTwoMatrix->isValid()) { + ChartableTwoFileMatrixChart* matrixChart = idChartTwoMatrix->getFileMatrixChart(); + const int32_t rowIndex = idChartTwoMatrix->getRowIndex(); + const int32_t colIndex = idChartTwoMatrix->getColumnIndex(); + + CaretMappableDataFile* cmdf = matrixChart->getCaretMappableDataFile(); + CaretAssert(cmdf); + + switch (matrixChart->getMatrixContentType()) { + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: + { + CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(cmdf); + if (ciftiParcelFile != NULL) { + if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { + if ((rowIndex >= 0) + && (colIndex >= 0)) { + try { + ciftiConnectivityManager->loadRowOrColumnFromParcelFile(brain, + ciftiParcelFile, + rowIndex, + colIndex, + ciftiLoadingInfo); + + } + catch (const DataFileException& e) { + cursor.restoreCursor(); + QMessageBox::critical(parentWidget, "", e.whatString()); + cursor.showWaitCursor(); + } + updateGraphicsFlag = true; + } + } + } + else { + CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(cmdf); + if (matrixFile != NULL) { + if ((rowIndex >= 0) + || (colIndex >= 0)) { + ciftiConnectivityManager->loadRowOrColumnFromConnectivityMatrixFile(brain, + matrixFile, + rowIndex, + colIndex, + ciftiLoadingInfo); + updateGraphicsFlag = true; + + } + } + } + } + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: + { + CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(cmdf); + if (scalarDataSeriesFile != NULL) { + if (rowIndex >= 0) { + scalarDataSeriesFile->setSelectedMapIndex(tabIndex, + rowIndex); + + const MapYokingGroupEnum::Enum mapYoking = scalarDataSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); + + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + scalarDataSeriesFile, + rowIndex, + true); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + else { + chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, + rowIndex); + } + + updateGraphicsFlag = true; + } + } + } + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: + break; + } + } + } + /* * Generate identification manager */ -- GitLab From 15a1bb28a780f3df39462a1244ec6b4463bfb298 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 1 Feb 2017 12:04:31 -0600 Subject: [PATCH 194/755] Continuing charting development. Created a 'ModeChartTwo' so that both old charts (ModelChart) and new Charts (ModelChartTwo) are available. The goal is to allow bot old and new chart scenes to load correctly so that conversion of charts from version for old to new is not needed. It will also allow scene with old charts to display correctly. --- src/Brain/Brain.cxx | 36 + src/Brain/Brain.h | 7 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 63 +- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 +- .../BrainOpenGLChartTwoDrawingInterface.h | 8 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 72 +- src/Brain/BrainOpenGLFixedPipeline.h | 11 +- src/Brain/BrowserTabContent.cxx | 312 ++++- src/Brain/BrowserTabContent.h | 24 +- src/Brain/CMakeLists.txt | 2 + src/Brain/ModelChart.cxx | 430 +------ src/Brain/ModelChart.h | 40 - src/Brain/ModelChartTwo.cxx | 1037 +++++++++++++++++ src/Brain/ModelChartTwo.h | 164 +++ src/Brain/ModelTypeEnum.cxx | 46 +- src/Brain/ModelTypeEnum.h | 2 + src/Brain/VolumeSliceSettings.cxx | 2 + src/Charting/ChartTwoDataCartesianHistory.cxx | 36 +- .../BrainBrowserWindowOrientedToolBox.cxx | 34 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 125 +- src/GuiQt/BrainBrowserWindowToolBar.h | 5 +- ...ainBrowserWindowToolBarChartAttributes.cxx | 4 +- .../BrainBrowserWindowToolBarChartAxes.cxx | 2 +- ...BrowserWindowToolBarChartTwoAttributes.cxx | 12 +- ...rowserWindowToolBarChartTwoOrientation.cxx | 2 +- .../BrainBrowserWindowToolBarChartTwoType.cxx | 15 +- .../BrainBrowserWindowToolBarChartType.cxx | 4 +- src/GuiQt/GuiManager.cxx | 4 + 28 files changed, 1773 insertions(+), 731 deletions(-) create mode 100644 src/Brain/ModelChartTwo.cxx create mode 100644 src/Brain/ModelChartTwo.h diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 80e888c6a..fee9cb1e5 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -87,6 +87,7 @@ #include "MathFunctions.h" #include "MetricFile.h" #include "ModelChart.h" +#include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" @@ -139,6 +140,7 @@ Brain::Brain() m_sceneAnnotationFile->clearModified(); m_modelChart = NULL; + m_modelChartTwo = NULL; m_surfaceMontageModel = NULL; m_volumeSliceModel = NULL; m_wholeBrainModel = NULL; @@ -265,6 +267,9 @@ Brain::~Brain() if (m_modelChart != NULL) { delete m_modelChart; } + if (m_modelChartTwo != NULL) { + delete m_modelChartTwo; + } if (m_surfaceMontageModel != NULL) { delete m_surfaceMontageModel; } @@ -680,6 +685,9 @@ Brain::resetBrain(const ResetBrainKeepSceneFiles keepSceneFiles, if (m_modelChart != NULL) { m_modelChart->reset(); } + if (m_modelChartTwo != NULL) { + m_modelChartTwo->reset(); + } m_gapsAndMargins->reset(); @@ -4708,6 +4716,16 @@ Brain::updateChartModel() m_modelChart = NULL; } } + + if (m_modelChartTwo == NULL) { + m_modelChartTwo = new ModelChartTwo(this); + EventModelAdd eventAddModel(m_modelChartTwo); + EventManager::get()->sendEvent(eventAddModel.getPointer()); + + if (m_isSpecFileBeingRead == false) { + m_modelChartTwo->initializeOverlays(); + } + } } /** @@ -5925,6 +5943,24 @@ Brain::getChartModel() const return m_modelChart; } +/** + * @return The chart two model (warning may be NULL!) + */ +ModelChartTwo* +Brain::getChartTwoModel() +{ + return m_modelChartTwo; +} + +/** + * @return The chart two model (warning may be NULL!) + */ +const ModelChartTwo* +Brain::getChartTwoModel() const +{ + return m_modelChartTwo; +} + /** * @return The annotation manager. */ diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index dbf781a51..8d64cb7ce 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -84,6 +84,7 @@ namespace caret { class LabelFile; class MetricFile; class ModelChart; + class ModelChartTwo; class ModelSurfaceMontage; class ModelVolume; class ModelWholeBrain; @@ -195,6 +196,10 @@ namespace caret { const ModelChart* getChartModel() const; + ModelChartTwo* getChartTwoModel(); + + const ModelChartTwo* getChartTwoModel() const; + ChartingDataManager* getChartingDataManager(); const ChartingDataManager* getChartingDataManager() const; @@ -753,6 +758,8 @@ namespace caret { ModelChart* m_modelChart; + ModelChartTwo* m_modelChartTwo; + ModelVolume* m_volumeSliceModel; ModelWholeBrain* m_wholeBrainModel; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 2f37082a2..0c0949be2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -29,7 +29,6 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" -#include "ChartMatrixScaleModeEnum.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -39,7 +38,7 @@ #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "IdentificationWithColor.h" -#include "ModelChart.h" +#include "ModelChartTwo.h" #include "SessionManager.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLineSeries.h" @@ -77,8 +76,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * * @param brain * Brain. - * @parm chartModel - * The chart model in the window. + * @parm chartTwoModel + * The chart two model in the window. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param textRenderer @@ -98,7 +97,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, - ModelChart* chartModel, + ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], @@ -109,7 +108,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, const int32_t tabIndex) { m_brain = brain; - m_chartModel = chartModel; + m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = textRenderer; m_translation[0] = translation[0]; @@ -155,31 +154,33 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, resetIdentification(); - const int32_t numberOfOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); - if (numberOfOverlays > 0) { - ChartTwoOverlay* topOverlay = chartOverlaySet->getOverlay(0); - if (topOverlay->isEnabled()) { - CaretMappableDataFile* cmdf = NULL; - int32_t mapIndex = -1; - topOverlay->getSelectionData(cmdf, mapIndex); - if (cmdf != NULL) { - const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); - switch (chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - drawHistogramChart(); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - drawMatrixChart(); - break; + if (m_chartOverlaySet != NULL) { + const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); + if (numberOfOverlays > 0) { + ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + if (topOverlay->isEnabled()) { + CaretMappableDataFile* cmdf = NULL; + int32_t mapIndex = -1; + topOverlay->getSelectionData(cmdf, mapIndex); + if (cmdf != NULL) { + const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + drawHistogramChart(); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + drawMatrixChart(); + break; + } } } - } - for (int32_t iOverlay = (numberOfOverlays -1); iOverlay >= 0; iOverlay--) { - + for (int32_t iOverlay = (numberOfOverlays -1); iOverlay >= 0; iOverlay--) { + + } } } @@ -425,7 +426,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() /* * Set the width and neight of each matrix cell. */ - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; @@ -615,7 +616,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT return; } - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 72ec7ead6..71caf1533 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -31,7 +31,6 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; - class ModelChart; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; @@ -44,7 +43,7 @@ namespace caret { virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, - ModelChart* chartModel, + ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], @@ -117,7 +116,7 @@ namespace caret { Brain* m_brain; - ModelChart* m_chartModel; + ModelChartTwo* m_chartTwoModel; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index d1e15f254..32f74cbbd 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -32,7 +32,7 @@ namespace caret { class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; class ChartTwoOverlaySet; - class ModelChart; + class ModelChartTwo; class BrainOpenGLChartTwoDrawingInterface { @@ -46,8 +46,8 @@ namespace caret { * * @param brain * Brain. - * @param chartModel - * The chart model. + * @param chartTwoModel + * The chart two model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param textRenderer @@ -66,7 +66,7 @@ namespace caret { * Index of the tab. */ virtual void drawChartOverlaySet(Brain* brain, - ModelChart* chartModel, + ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrainOpenGLTextRenderInterface* textRenderer, const float translation[3], diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index f8fd27bfd..124d1509f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -123,6 +123,7 @@ #include "SelectionManager.h" #include "MathFunctions.h" #include "ModelChart.h" +#include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" @@ -400,6 +401,10 @@ BrainOpenGLFixedPipeline::updateForegroundAndBackgroundColors(BrainOpenGLViewpor prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundChartView(m_backgroundColorByte); break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(m_foregroundColorByte); + prefs->getBackgroundAndForegroundColors()->getColorBackgroundChartView(m_backgroundColorByte); + break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: @@ -904,12 +909,16 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, CaretAssert((this->windowTabIndex >= 0) && (this->windowTabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); ModelChart* modelChart = dynamic_cast(model); + ModelChartTwo* modelTwoChart = dynamic_cast(model); ModelSurface* surfaceModel = dynamic_cast(model); ModelSurfaceMontage* surfaceMontageModel = dynamic_cast(model); ModelVolume* volumeModel = dynamic_cast(model); ModelWholeBrain* wholeBrainModel = dynamic_cast(model); if (modelChart != NULL) { - drawChartData(browserTabContent, modelChart, viewport); + drawChartOneData(browserTabContent, modelChart, viewport); + } + else if (modelTwoChart != NULL) { + drawChartTwoData(browserTabContent, modelTwoChart, viewport); } else if (surfaceModel != NULL) { m_mirroredClippingEnabled = true; @@ -5275,7 +5284,7 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte * The viewport (x, y, width, height) */ void -BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, +BrainOpenGLFixedPipeline::drawChartOneData(BrowserTabContent* browserTabContent, ModelChart* chartModel, const int32_t viewport[4]) { @@ -5285,27 +5294,6 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, const int32_t tabIndex = browserTabContent->getTabNumber(); - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { - if (m_windowIndex == 0) { - float translation[3]; - browserTabContent->getTranslation(translation); - BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; - const float zooming = browserTabContent->getScaling(); - - chartDrawing.drawChartOverlaySet(m_brain, - chartModel, - this, - getTextRenderer(), - translation, - zooming, - chartModel->getChartTwoOverlaySet(tabIndex), - SelectionItemDataTypeEnum::CHART_DATA_SERIES, - viewport, - tabIndex); - return; - } - } - ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; const ChartOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); @@ -5375,6 +5363,44 @@ BrainOpenGLFixedPipeline::drawChartData(BrowserTabContent* browserTabContent, } } +/** + * Draw a chart two model. + * + * @param browserTabContent + * Content of browser tab. + * @param chartModel + * The chart model. + * @param viewport + * The viewport (x, y, width, height) + */ +void +BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, + ModelChartTwo* chartModel, + const int32_t viewport[4]) +{ + + CaretAssert(browserTabContent); + CaretAssert(chartModel); + + const int32_t tabIndex = browserTabContent->getTabNumber(); + + float translation[3]; + browserTabContent->getTranslation(translation); + BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; + const float zooming = browserTabContent->getScaling(); + + chartDrawing.drawChartOverlaySet(m_brain, + chartModel, + this, + getTextRenderer(), + translation, + zooming, + chartModel->getChartTwoOverlaySet(tabIndex), + SelectionItemDataTypeEnum::CHART_DATA_SERIES, + viewport, + tabIndex); +} + /** * Setup the orthographic projection. * @param viewport diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 808449efc..6782c0d02 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -68,6 +68,7 @@ namespace caret { class Surface; class Model; class ModelChart; + class ModelChartTwo; class ModelSurface; class ModelSurfaceMontage; class ModelVolume; @@ -180,9 +181,13 @@ namespace caret { void initializeMembersBrainOpenGL(); - void drawChartData(BrowserTabContent* browserTabContent, - ModelChart* chartData, - const int32_t viewport[4]); + void drawChartOneData(BrowserTabContent* browserTabContent, + ModelChart* chartData, + const int32_t viewport[4]); + + void drawChartTwoData(BrowserTabContent* browserTabContent, + ModelChartTwo* chartData, + const int32_t viewport[4]); void drawSurfaceModel(ModelSurface* surfaceModel, const int32_t viewport[4]); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index b55a4e121..fb57d597c 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -40,6 +40,7 @@ #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartModelDataSeries.h" +#include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" @@ -61,6 +62,7 @@ #include "MathFunctions.h" #include "Matrix4x4.h" #include "ModelChart.h" +#include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelSurfaceSelector.h" @@ -112,6 +114,7 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_wholeBrainModel = NULL; m_surfaceMontageModel = NULL; m_chartModel = NULL; + m_chartTwoModel = NULL; m_guiName = ""; m_userName = ""; m_volumeSurfaceOutlineSetModel = new VolumeSurfaceOutlineSetModel(); @@ -125,7 +128,7 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_flatSurfaceViewingTransformation = new ViewingTransformations(); m_viewingTransformation = new ViewingTransformations(); m_volumeSliceViewingTransformation = new ViewingTransformationsVolume(); - m_chartMatrixViewingTranformation = new ViewingTransformations(); + m_chartTwoMatrixViewingTranformation = new ViewingTransformations(); m_wholeBrainSurfaceSettings = new WholeBrainSurfaceSettings(); @@ -170,9 +173,9 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) "ViewingTransformations", m_volumeSliceViewingTransformation); - m_sceneClassAssistant->add("m_chartMatrixViewingTranformation", + m_sceneClassAssistant->add("m_chartTwoMatrixViewingTranformation", "ViewingTransformations", - m_chartMatrixViewingTranformation); + m_chartTwoMatrixViewingTranformation); m_sceneClassAssistant->add("m_volumeSliceSettings", "VolumeSliceSettings", @@ -224,7 +227,7 @@ BrowserTabContent::~BrowserTabContent() delete m_cerebellumViewingTransformation; delete m_viewingTransformation; delete m_volumeSliceViewingTransformation; - delete m_chartMatrixViewingTranformation; + delete m_chartTwoMatrixViewingTranformation; delete m_obliqueVolumeRotationMatrix; delete m_surfaceModelSelector; @@ -279,7 +282,7 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) *m_flatSurfaceViewingTransformation = *tabToClone->m_flatSurfaceViewingTransformation; *m_viewingTransformation = *tabToClone->m_viewingTransformation; *m_volumeSliceViewingTransformation = *tabToClone->m_volumeSliceViewingTransformation; - *m_chartMatrixViewingTranformation = *tabToClone->m_chartMatrixViewingTranformation; + *m_chartTwoMatrixViewingTranformation = *tabToClone->m_chartTwoMatrixViewingTranformation; *m_volumeSliceSettings = *tabToClone->m_volumeSliceSettings; *m_wholeBrainSurfaceSettings = *tabToClone->m_wholeBrainSurfaceSettings; @@ -422,6 +425,7 @@ BrowserTabContent::getDescriptionOfContent(PlainTextStringBuilder& descriptionOu bool volumeFlag = false; switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: @@ -553,6 +557,9 @@ BrowserTabContent::getModelForDisplay() case ModelTypeEnum::MODEL_TYPE_CHART: mdc = m_chartModel; break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + mdc = m_chartTwoModel; + break; } return mdc; @@ -587,6 +594,9 @@ BrowserTabContent::getModelForDisplay() const case ModelTypeEnum::MODEL_TYPE_CHART: mdc = m_chartModel; break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + mdc = m_chartTwoModel; + break; } return mdc; @@ -600,7 +610,7 @@ BrowserTabContent::getModelForDisplay() const * chart. */ ModelChart* -BrowserTabContent::getDisplayedChartModel() +BrowserTabContent::getDisplayedChartOneModel() { ModelChart* mc = dynamic_cast(getModelForDisplay()); return mc; @@ -614,12 +624,40 @@ BrowserTabContent::getDisplayedChartModel() * chart. */ const ModelChart* -BrowserTabContent::getDisplayedChartModel() const +BrowserTabContent::getDisplayedChartOneModel() const { const ModelChart* mc = dynamic_cast(getModelForDisplay()); return mc; } +/** + * Get the displayed chart model two. + * + * @return Pointer to displayed chart model or + * NULL if the displayed model is NOT a + * chart. + */ +ModelChartTwo* +BrowserTabContent::getDisplayedChartTwoModel() +{ + ModelChartTwo* mc = dynamic_cast(getModelForDisplay()); + return mc; +} + +/** + * Get the displayed chart model two. + * + * @return Pointer to displayed chart model or + * NULL if the displayed model is NOT a + * chart. + */ +const ModelChartTwo* +BrowserTabContent::getDisplayedChartTwoModel() const +{ + const ModelChartTwo* mc = dynamic_cast(getModelForDisplay()); + return mc; +} + /** * Get the displayed surface model. * @@ -726,12 +764,12 @@ BrowserTabContent::isFlatSurfaceDisplayed() const } /** - * @return True if the displayed model is a chart + * @return True if the displayed model is a chart one */ bool -BrowserTabContent::isChartDisplayed() const +BrowserTabContent::isChartOneDisplayed() const { - const ModelChart* chartModel = getDisplayedChartModel(); + const ModelChart* chartModel = getDisplayedChartOneModel(); if (chartModel != NULL) { return true; } @@ -739,6 +777,21 @@ BrowserTabContent::isChartDisplayed() const return false; } +/** + * @return True if the displayed model is a chart two + */ +bool +BrowserTabContent::isChartTwoDisplayed() const +{ + const ModelChartTwo* chartModel = getDisplayedChartTwoModel(); + if (chartModel != NULL) { + return true; + } + + return false; +} + + /** * @return Is the displayed model a volume slice model? */ @@ -856,7 +909,7 @@ BrowserTabContent::getOverlaySet() const } /** - * @return Overlay set for this tab. + * @return Chart overlay set for this tab. */ ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() @@ -869,7 +922,7 @@ BrowserTabContent::getChartTwoOverlaySet() } /** - * @return Overlay set for this tab. + * @return Chart overlay set for this tab. */ const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() const @@ -910,6 +963,7 @@ BrowserTabContent::update(const std::vector models) m_wholeBrainModel = NULL; m_surfaceMontageModel = NULL; m_chartModel = NULL; + m_chartTwoModel = NULL; for (int i = 0; i < numModels; i++) { Model* mdc = models[i]; @@ -919,6 +973,7 @@ BrowserTabContent::update(const std::vector models) ModelWholeBrain* mdcwb = dynamic_cast(mdc); ModelSurfaceMontage* mdcsm = dynamic_cast(mdc); ModelChart* mdch = dynamic_cast(mdc); + ModelChartTwo* mdchTwo = dynamic_cast(mdc); if (mdcs != NULL) { /* nothing to do since the surface model selector handles surfaces */ @@ -936,9 +991,13 @@ BrowserTabContent::update(const std::vector models) m_surfaceMontageModel = mdcsm; } else if (mdch != NULL) { - CaretAssertMessage((m_chartModel == NULL), "There is more than one surface chart model."); + CaretAssertMessage((m_chartModel == NULL), "There is more than one chart model."); m_chartModel = mdch; } + else if (mdchTwo != NULL) { + CaretAssertMessage((m_chartTwoModel == NULL), "There is more than one chart two model."); + m_chartTwoModel = mdchTwo; + } else { CaretAssertMessage(0, (AString("Unknown type of brain model.") + mdc->getNameForGUI(true))); } @@ -972,6 +1031,11 @@ BrowserTabContent::update(const std::vector models) m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + if (m_chartTwoModel == NULL) { + m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; + } + break; } if (m_selectedModelType == ModelTypeEnum::MODEL_TYPE_INVALID) { @@ -990,6 +1054,9 @@ BrowserTabContent::update(const std::vector models) else if (m_chartModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_CHART; } + else if (m_chartTwoModel != NULL) { + m_selectedModelType = ModelTypeEnum::MODEL_TYPE_CHART_TWO; + } } if (m_volumeModel != NULL) { @@ -1025,17 +1092,29 @@ BrowserTabContent::update(const std::vector models) } /** - * Is the chart model selection valid? + * Is the chart one model selection valid? * * @return bool indicating validity. */ bool -BrowserTabContent::isChartModelValid() const +BrowserTabContent::isChartOneModelValid() const { bool valid = (m_chartModel != NULL); return valid; } +/** + * Is the chart two model selection valid? + * + * @return bool indicating validity. + */ +bool +BrowserTabContent::isChartTwoModelValid() const +{ + bool valid = (m_chartTwoModel != NULL); + return valid; +} + /** * Is the surface model selection valid? * @@ -1263,12 +1342,16 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo } bool useOverlayFlag = false; - bool useChartsFlag = false; + bool useChartOneFlag = false; + bool useChartTwoFlag = false; switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_CHART: - useChartsFlag = true; + useChartOneFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + useChartTwoFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE: useOverlayFlag = true; @@ -1305,8 +1388,8 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo } } - if (useChartsFlag) { - ModelChart* modelChart = getDisplayedChartModel(); + if (useChartOneFlag) { + ModelChart* modelChart = getDisplayedChartOneModel(); if (modelChart != NULL) { CaretDataFileSelectionModel* fileModel = NULL; @@ -1351,6 +1434,47 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo } } + if (useChartTwoFlag) { + ModelChartTwo* modelChartTwo = getDisplayedChartTwoModel(); + if (modelChartTwo != NULL) { + ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); + if (overlaySet != NULL) { + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); + if (chartOverlay->isEnabled()) { + switch (chartOverlay->getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + { + CaretMappableDataFile* overlayDataFile = NULL; + int32_t mapIndex; + chartOverlay->getSelectionData(overlayDataFile, + mapIndex); + + if (overlayDataFile != NULL) { + if (overlayDataFile->isMappedWithPalette()) { + AnnotationColorBar* colorBar = chartOverlay->getColorBar(); + const int32_t mapIndex = 0; + colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, + overlayDataFile, + mapIndex)); + } + } + } + break; + } + } + } + } + } + } + const int32_t numColorBarMapInfo = static_cast(colorBarMapFileInfo.size()); for (int32_t i = 0; i < numColorBarMapInfo; i++) { CaretAssertVectorIndex(colorBarMapFileInfo, i); @@ -1408,12 +1532,16 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetChartTwoOverlaySet(m_tabNumber); + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = (numOverlays - 1); i >= 0; i--) { + ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); + if (chartOverlay->isEnabled()) { + switch (chartOverlay->getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + { + CaretMappableDataFile* overlayDataFile = NULL; + int32_t mapIndex; + chartOverlay->getSelectionData(overlayDataFile, + mapIndex); + + if (overlayDataFile != NULL) { + if (overlayDataFile->isMappedWithPalette()) { + AnnotationColorBar* colorBar = chartOverlay->getColorBar(); + if (colorBar->isDisplayed()) { + mapFiles.push_back(overlayDataFile); + mapIndices.push_back(0); + } + } + } + } + break; + } + } + } + } + } + + CaretAssert(mapFiles.size() == mapIndices.size()); } /** @@ -1655,6 +1824,25 @@ BrowserTabContent::getFilesDisplayedInTab(std::vector& displayed break; case ModelTypeEnum::MODEL_TYPE_CHART: break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + { + const ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(tabIndex); + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + const ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); + if (chartOverlay->isEnabled()) { + CaretMappableDataFile* overlayDataFile = NULL; + int32_t mapIndex; + chartOverlay->getSelectionData(overlayDataFile, + mapIndex); + + if (overlayDataFile != NULL) { + displayedDataFiles.insert(overlayDataFile); + } + } + } + } + break; } /* @@ -1751,8 +1939,8 @@ BrowserTabContent::getViewingTransformation() else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } - else if (isChartDisplayed()) { - return m_chartMatrixViewingTranformation; + else if (isChartTwoDisplayed()) { + return m_chartTwoMatrixViewingTranformation; } return m_viewingTransformation; } @@ -1769,8 +1957,8 @@ BrowserTabContent::getViewingTransformation() const else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } - else if (isChartDisplayed()) { - return m_chartMatrixViewingTranformation; + else if (isChartTwoDisplayed()) { + return m_chartTwoMatrixViewingTranformation; } return m_viewingTransformation; } @@ -2210,7 +2398,8 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten break; } } - else if (isChartDisplayed()) { + else if (isChartOneDisplayed() + || isChartTwoDisplayed()) { /* no rotation for chart */ } else if (isCerebellumDisplayed()) { @@ -2398,8 +2587,8 @@ void BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, const int32_t mouseDY) { - if (isChartDisplayed()) { - ModelChart* modelChart = getDisplayedChartModel(); + if (isChartOneDisplayed()) { + ModelChart* modelChart = getDisplayedChartOneModel(); CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; @@ -2410,22 +2599,23 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } - if (matrixSelectionModel != NULL) { - ChartableMatrixInterface* chartableInterface = matrixSelectionModel->getSelectedFileOfType(); - if (chartableInterface != NULL) { - ChartMatrixDisplayProperties* matrixProperties = chartableInterface->getChartMatrixDisplayProperties(m_tabNumber); - matrixProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); - float scaling = matrixProperties->getViewZooming(); - if (mouseDY != 0.0) { - scaling *= (1.0f + (mouseDY * 0.01)); - } - if (scaling < 0.01) { - scaling = 0.01; - } - matrixProperties->setViewZooming(scaling); + if (matrixSelectionModel != NULL) { + ChartableMatrixInterface* chartableInterface = matrixSelectionModel->getSelectedFileOfType(); + if (chartableInterface != NULL) { + ChartMatrixDisplayProperties* matrixProperties = chartableInterface->getChartMatrixDisplayProperties(m_tabNumber); + matrixProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); + float scaling = matrixProperties->getViewZooming(); + if (mouseDY != 0.0) { + scaling *= (1.0f + (mouseDY * 0.01)); } + if (scaling < 0.01) { + scaling = 0.01; + } + matrixProperties->setViewZooming(scaling); } - + } + } + else if (isChartTwoDisplayed()) { float scaling = getViewingTransformation()->getScaling(); if (mouseDY != 0.0) { scaling *= (1.0f + (mouseDY * 0.01)); @@ -2523,8 +2713,8 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon translation[2] += dz; m_volumeSliceViewingTransformation->setTranslation(translation); } - else if (isChartDisplayed()) { - ModelChart* modelChart = getDisplayedChartModel(); + else if (isChartOneDisplayed()) { + ModelChart* modelChart = getDisplayedChartOneModel(); CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; @@ -2547,16 +2737,14 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon matrixProperties->setViewPanning(translation); } } - - /** Charting "two" */ - { - float translation[3]; - m_chartMatrixViewingTranformation->getTranslation(translation); - translation[0] += mouseDX; - translation[1] += mouseDY; - translation[2] = 0; // NO Z-translation - m_chartMatrixViewingTranformation->setTranslation(translation); - } + } + else if (isChartTwoDisplayed()) { + float translation[3]; + m_chartTwoMatrixViewingTranformation->getTranslation(translation); + translation[0] += mouseDX; + translation[1] += mouseDY; + translation[2] = 0; // NO Z-translation + m_chartTwoMatrixViewingTranformation->setTranslation(translation); } else if (isCerebellumDisplayed()) { const float screenDX = mouseDX; @@ -2765,12 +2953,12 @@ BrowserTabContent::getTransformationsForOpenGLDrawing(const ProjectionViewTypeEn return; } - if (isChartDisplayed()) { - m_chartMatrixViewingTranformation->getTranslation(translationOut); + if (isChartTwoDisplayed()) { + m_chartTwoMatrixViewingTranformation->getTranslation(translationOut); Matrix4x4 matrix; matrix.identity(); matrix.getMatrixForOpenGL(rotationMatrixOut); - scalingOut = m_chartMatrixViewingTranformation->getScaling(); + scalingOut = m_chartTwoMatrixViewingTranformation->getScaling(); return; } @@ -3143,6 +3331,8 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: @@ -3998,7 +4188,7 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; - *m_chartMatrixViewingTranformation = *btc->m_chartMatrixViewingTranformation; + *m_chartTwoMatrixViewingTranformation = *btc->m_chartTwoMatrixViewingTranformation; *m_volumeSliceSettings = *btc->m_volumeSliceSettings; *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; @@ -4049,7 +4239,7 @@ BrowserTabContent::updateYokedBrowserTabs() *btc->m_flatSurfaceViewingTransformation = *m_flatSurfaceViewingTransformation; *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; - *btc->m_chartMatrixViewingTranformation = *m_chartMatrixViewingTranformation; + *btc->m_chartTwoMatrixViewingTranformation = *m_chartTwoMatrixViewingTranformation; *btc->m_volumeSliceSettings = *m_volumeSliceSettings; *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index a29912777..989f90e93 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -47,6 +47,7 @@ namespace caret { class ClippingPlaneGroup; class Matrix4x4; class ModelChart; + class ModelChartTwo; class ModelSurface; class ModelSurfaceMontage; class ModelSurfaceSelector; @@ -108,9 +109,13 @@ namespace caret { Model* getModelForDisplay(); - ModelChart* getDisplayedChartModel(); + ModelChart* getDisplayedChartOneModel(); - const ModelChart* getDisplayedChartModel() const; + const ModelChart* getDisplayedChartOneModel() const; + + ModelChartTwo* getDisplayedChartTwoModel(); + + const ModelChartTwo* getDisplayedChartTwoModel() const; ModelSurface* getDisplayedSurfaceModel(); @@ -134,7 +139,9 @@ namespace caret { bool isCerebellumDisplayed() const; - bool isChartDisplayed() const; + bool isChartOneDisplayed() const; + + bool isChartTwoDisplayed() const; bool isFlatSurfaceDisplayed() const; @@ -146,7 +153,9 @@ namespace caret { void update(const std::vector models); - bool isChartModelValid() const; + bool isChartOneModelValid() const; + + bool isChartTwoModelValid() const; bool isSurfaceModelValid() const; @@ -446,6 +455,9 @@ namespace caret { /** The chart model */ ModelChart* m_chartModel; + /** The chart two model */ + ModelChartTwo* m_chartTwoModel; + /** * Name requested by user interface - reflects contents * such as Surface, Volume Slices, etc @@ -488,8 +500,8 @@ namespace caret { /** Transformation for volume slices viewing */ ViewingTransformationsVolume* m_volumeSliceViewingTransformation; - /** Transformation for matrix chart viewing */ - ViewingTransformations* m_chartMatrixViewingTranformation; + /** Transformation for matrix chart two viewing */ + ViewingTransformations* m_chartTwoMatrixViewingTranformation; /** Volume slice settings for volume slices */ VolumeSliceSettings* m_volumeSliceSettings; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index a1a540ca5..3bac9d2a1 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -141,6 +141,7 @@ IdentifiedItemVoxel.h ImageDepthPositionEnum.h Model.h ModelChart.h +ModelChartTwo.h ModelSurface.h ModelSurfaceMontage.h ModelSurfaceSelector.h @@ -284,6 +285,7 @@ IdentifiedItemVoxel.cxx ImageDepthPositionEnum.cxx Model.cxx ModelChart.cxx +ModelChartTwo.cxx ModelSurface.cxx ModelSurfaceMontage.cxx ModelSurfaceSelector.cxx diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 2b58cd3b3..0087756d7 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -33,17 +33,12 @@ #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartableLineSeriesRowColumnInterface.h" #include "ChartableMatrixInterface.h" -#include "ChartableTwoFileDelegate.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" -#include "ChartTwoMatrixDisplayProperties.h" -#include "ChartTwoOverlay.h" -#include "ChartTwoOverlaySet.h" -#include "ChartTwoOverlaySetArray.h" #include "ChartingVersionEnum.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" @@ -76,35 +71,15 @@ ModelChart::ModelChart(Brain* brain) Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); - m_histogramChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, - "Histogram Chart Overlays")); - m_matrixChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, - "Matrix Chart Overlays")); - m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, - "Line Series Chart Overlays")); - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); - m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); } initializeCharts(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); - m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", - m_selectedChartTwoDataType); - m_sceneAssistant->add("m_histogramChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_histogramChartOverlaySetArray.get()); - m_sceneAssistant->add("m_matrixChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_matrixChartOverlaySetArray.get()); - m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_lineSeriesChartOverlaySetArray.get()); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } @@ -125,9 +100,6 @@ ModelChart::~ModelChart() delete m_chartableMatrixSeriesFileSelectionModel[i]; m_chartableMatrixSeriesFileSelectionModel[i] = NULL; - - delete m_chartTwoMatrixDisplayProperties[i]; - m_chartTwoMatrixDisplayProperties[i] = NULL; } } @@ -136,7 +108,6 @@ ModelChart::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedChartOneDataType[i] = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; - m_selectedChartTwoDataType[i] = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; m_chartModelDataSeries[i] = new ChartModelDataSeries(); m_chartModelDataSeries[i]->getLeftAxis()->setText("Value"); @@ -826,37 +797,6 @@ ModelChart::saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneClass->addChild(matrixSeriesSceneMap); } -/** - * Save version two charting information specific to this type of model to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * saving the scene. - * - * @param sceneClass - * SceneClass to which model specific information is added. - */ -void -ModelChart::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) -{ - std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); - - /* - * Save matrix properties. - */ - SceneObjectMapIntegerKey* matrixPropsMap = new SceneObjectMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP", - SceneObjectDataTypeEnum::SCENE_CLASS); - - for (int32_t tabIndex : tabIndices) { - matrixPropsMap->addClass(tabIndex, m_chartTwoMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, - "m_chartTwoMatrixDisplayProperties")); - } - sceneClass->addChild(matrixPropsMap); -} - - /** * Save information specific to this type of model to the scene. * @@ -875,20 +815,8 @@ ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttr m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - const ChartingVersionEnum::Enum chartingVersion = ChartingVersionEnum::CHARTING_VERSION_TWO; - sceneClass->addEnumeratedType("chartingVersion", - chartingVersion); - - switch (chartingVersion) { - case ChartingVersionEnum::CHARTING_VERSION_ONE: - saveVersionOneModelSpecificInformationToScene(sceneAttributes, - sceneClass); - break; - case ChartingVersionEnum::CHARTING_VERSION_TWO: - saveVersionTwoModelSpecificInformationToScene(sceneAttributes, - sceneClass); - break; - } + saveVersionOneModelSpecificInformationToScene(sceneAttributes, + sceneClass); } /** @@ -911,20 +839,8 @@ ModelChart::restoreModelSpecificInformationFromScene(const SceneAttributes* scen m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); - const ChartingVersionEnum::Enum chartingVersion = - sceneClass->getEnumeratedTypeValue("chartingVersion", - ChartingVersionEnum::CHARTING_VERSION_ONE); - - switch (chartingVersion) { - case ChartingVersionEnum::CHARTING_VERSION_ONE: - restoreVersionOneModelSpecificInformationFromScene(sceneAttributes, - sceneClass); - break; - case ChartingVersionEnum::CHARTING_VERSION_TWO: - restoreVersionTwoModelSpecificInformationFromScene(sceneAttributes, - sceneClass); - break; - } + restoreVersionOneModelSpecificInformationFromScene(sceneAttributes, + sceneClass); } /** @@ -984,40 +900,6 @@ ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttrib } } -/** - * Restore information specific to the type of model from VERSION TWO scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass from which model specific information is obtained. - */ -void -ModelChart::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ /* - * Restore matrix chart series models from scene. - */ - const SceneObjectMapIntegerKey* matrixPropsMap = sceneClass->getMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP"); - if (matrixPropsMap != NULL) { - const std::vector tabIndices = matrixPropsMap->getKeys(); - for (const int32_t tabIndex : tabIndices) { - const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); - m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); - } - } - - /* - * Restore the chart models - */ - restoreVersionTwoChartModelsFromScene(sceneAttributes, - sceneClass); -} - /** * Save chart models to the scene. * @@ -1313,24 +1195,6 @@ ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAt } } -/** - * Restore the chart models from a VERSION TWO scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass from which model specific information is obtained. - */ -void -ModelChart::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - /* Probably nothing to do here */ -} - /** * Load the cartesian chart data using the given chart data source. * @@ -1872,196 +1736,6 @@ ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const } - -/** - * Set the type of chart selected in the given tab. - * - * @param tabIndex - * Index of tab. - * @param dataType - * Type of data for chart. - */ -void -ModelChart::setSelectedChartTwoDataType(const int32_t tabIndex, - const ChartTwoDataTypeEnum::Enum dataType) -{ - CaretAssertArrayIndex(m_selectedChartTwoDataType, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - m_selectedChartTwoDataType[tabIndex] = dataType; -} - -/** - * Get the valid chart data types based upon the currently loaded files. - * - * @param validChartDataTypesOut - * Output containing valid chart data types. - */ -void -ModelChart::getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const -{ - validChartDataTypesOut.clear(); - - /** - * Get the data files. - */ - std::vector allDataFiles; - EventCaretMappableDataFilesGet eventGetMapDataFiles; - EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); - eventGetMapDataFiles.getAllFiles(allDataFiles); - - std::set chartTypeSet; - - for (auto mapFile : allDataFiles) { - ChartableTwoFileDelegate* chartFile = mapFile->getChartingDelegate(); - std::vector fileChartTypes; - chartFile->getSupportedChartTwoDataTypes(fileChartTypes); - - chartTypeSet.insert(fileChartTypes.begin(), - fileChartTypes.end()); - } - - validChartDataTypesOut.insert(validChartDataTypesOut.end(), - chartTypeSet.begin(), - chartTypeSet.end()); -} - -/** - * Get the type of chart selected in the given tab. - * - * @param tabIndex - * Index of tab. - * @return - * Chart type in the given tab. - */ -ChartTwoDataTypeEnum::Enum -ModelChart::getSelectedChartTwoDataType(const int32_t tabIndex) const -{ - CaretAssertArrayIndex(m_selectedChartDataType, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - ChartTwoDataTypeEnum::Enum chartDataType = m_selectedChartTwoDataType[tabIndex]; - - std::vector validChartDataTypes; - getValidChartTwoDataTypes(validChartDataTypes); - - /* - * Test if selected chart type is still valid - */ - if (std::find(validChartDataTypes.begin(), - validChartDataTypes.end(), - chartDataType) == validChartDataTypes.end()) { - chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; - } - - /* - * Find a valid chart type? - */ - if (chartDataType == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { - if ( ! validChartDataTypes.empty()) { - CaretAssertVectorIndex(validChartDataTypes, 0); - chartDataType = validChartDataTypes[0]; - } - } - - m_selectedChartTwoDataType[tabIndex] = chartDataType; - return chartDataType; - -// /* -// * Verify that the selected chart data type is valid. -// */ -// std::vector validChartDataTypes; -// getValidChartOneDataTypes(validChartDataTypes); -// if (std::find(validChartDataTypes.begin(), -// validChartDataTypes.end(), -// chartDataType) == validChartDataTypes.end()) { -// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; -// } -// -// /* -// * If selected chart data type is invalid, find a valid chart type, -// * preferably one that contains data. -// */ -// if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// if ( ! validChartDataTypes.empty()) { -// /* -// * Will become the the first valid chart data type that contains -// * data (if there is one) -// */ -// ChartOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; -// -// /* -// * Loop through all chart types (some or all valid charts -// * types may not contain data until the user commands loading of data) -// */ -// std::vector allChartDataTypes; -// ChartOneDataTypeEnum::getAllEnums(allChartDataTypes); -// for (std::vector::iterator iter = allChartDataTypes.begin(); -// iter != allChartDataTypes.end(); -// iter++) { -// const ChartOneDataTypeEnum::Enum cdt = *iter; -// if (std::find(validChartDataTypes.begin(), -// validChartDataTypes.end(), -// cdt) != validChartDataTypes.end()) { -// if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataType = cdt; -// } -// -// switch (cdt) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { -// if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; -// } -// } -// break; -// } -// } -// } -// -// if (chartDataTypeWithValidData != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataType = chartDataTypeWithValidData; -// } -// else if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { -// chartDataType = validChartDataTypes[0]; -// } -// } -// } -// -// /* -// * Selected type may have changed due to loaded files changing -// */ -// m_selectedChartDataType[tabIndex] = chartDataType; -// -// return chartDataType; -} - /** * Update the chart overlay sets. * @@ -2071,17 +1745,6 @@ ModelChart::getSelectedChartTwoDataType(const int32_t tabIndex) const void ModelChart::updateChartOverlaySets(const int32_t tabIndex) { - CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - switch (m_selectedChartTwoDataType[tabIndex]) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - break; - } } /** @@ -2180,12 +1843,6 @@ ModelChart::getSelectedFrequencySeriesChartModelHelper(const int32_t tabIndex) c return m_chartModelFrequencySeries[tabIndex]; } - - - - - - /** * Get the time series chart model selected in the given tab. * @@ -2270,82 +1927,3 @@ ModelChart::getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex) return m_chartableMatrixSeriesFileSelectionModel[tabIndex]; } -/** - * @return The chart matrix display properties for the given tab. - * - * @param tabIndex - * The tab index. - */ -ChartTwoMatrixDisplayProperties* -ModelChart::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) -{ - CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - return m_chartTwoMatrixDisplayProperties[tabIndex]; -} - -/** - * @return The chart matrix display properties for the given tab. - * - * @param tabIndex - * The tab index. - */ -const ChartTwoMatrixDisplayProperties* -ModelChart::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const -{ - CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - return m_chartTwoMatrixDisplayProperties[tabIndex]; -} - -/** - * Get the chart overlay set for this model. - * - * @param tabIndex - * Index for the chart overlay set. - * @return - * Chart overlay set or NULL if not valid for this model. - */ -ChartTwoOverlaySet* -ModelChart::getChartTwoOverlaySet(const int tabIndex) -{ - ChartTwoOverlaySet* chartOverlaySet = NULL; - - switch (getSelectedChartTwoDataType(tabIndex)) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - chartOverlaySet = m_histogramChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - chartOverlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); - break; - } - - return chartOverlaySet; -} - -/** - * Get the chart overlay set for this model. - * - * @param tabIndex - * Index for the chart overlay set. - * @return - * Chart overlay set or NULL if not valid for this model. - */ -const ChartTwoOverlaySet* -ModelChart::getChartTwoOverlaySet(const int tabIndex) const -{ - ModelChart* nonConstModelChart = const_cast(this); - CaretAssert(nonConstModelChart); - const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartTwoOverlaySet(tabIndex); - - return chartOverlaySet; -} - - diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index ac97bf996..e388fee82 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -28,7 +28,6 @@ #include #include -#include "ChartTwoDataTypeEnum.h" #include "ChartOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" @@ -49,8 +48,6 @@ namespace caret { class ChartModelDataSeries; class ChartModelFrequencySeries; class ChartModelTimeSeries; - class ChartTwoMatrixDisplayProperties; - class ChartTwoOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; class OverlaySetArray; @@ -90,14 +87,6 @@ namespace caret { const OverlaySet* getOverlaySet(const int tabIndex) const; - ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex); - - const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const; - - virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex); - - virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const; - virtual void receiveEvent(Event* event); void getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const; @@ -107,13 +96,6 @@ namespace caret { void setSelectedChartOneDataType(const int32_t tabIndex, const ChartOneDataTypeEnum::Enum dataType); - void getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const; - - ChartTwoDataTypeEnum::Enum getSelectedChartTwoDataType(const int32_t tabIndex) const; - - void setSelectedChartTwoDataType(const int32_t tabIndex, - const ChartTwoDataTypeEnum::Enum dataType); - ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex); const ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex) const; @@ -173,9 +155,6 @@ namespace caret { void restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); - void restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; @@ -187,31 +166,12 @@ namespace caret { virtual void saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); - virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); - void restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); - void restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; - /** Chart Overlay sets for XX data type */ - std::unique_ptr m_histogramChartOverlaySetArray; - - /** Chart Overlay sets for XX data type */ - std::unique_ptr m_lineSeriesChartOverlaySetArray; - - /** Chart Overlay sets for XX data type */ - std::unique_ptr m_matrixChartOverlaySetArray; - - ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - - mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - mutable ChartOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx new file mode 100644 index 000000000..c5c5d8c1b --- /dev/null +++ b/src/Brain/ModelChartTwo.cxx @@ -0,0 +1,1037 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#include "Brain.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "CaretMappableDataFile.h" +#include "CaretDataFileSelectionModel.h" +#include "CaretLogger.h" +#include "CaretMappableDataFileAndMapSelectionModel.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartTwoMatrixDisplayProperties.h" +#include "ChartTwoOverlay.h" +#include "ChartTwoOverlaySet.h" +#include "ChartTwoOverlaySetArray.h" +#include "ChartingVersionEnum.h" +#include "CiftiMappableDataFile.h" +#include "CiftiScalarDataSeriesFile.h" +#include "EventBrowserTabGetAll.h" +#include "EventCaretMappableDataFilesGet.h" +#include "EventManager.h" +#include "EventNodeIdentificationColorsGetFromCharts.h" +#include "ModelChartTwo.h" +#include "OverlaySet.h" +#include "OverlaySetArray.h" +#include "PlainTextStringBuilder.h" +#include "SceneClass.h" +#include "SceneClassArray.h" +#include "SceneClassAssistant.h" +#include "SceneObjectMapIntegerKey.h" +#include "SurfaceFile.h" + +using namespace caret; + +/** + * Constructor. + * + */ +ModelChartTwo::ModelChartTwo(Brain* brain) +: Model(ModelTypeEnum::MODEL_TYPE_CHART_TWO, + brain) +{ + std::vector overlaySurfaceStructures; + m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, + Overlay::INCLUDE_VOLUME_FILES_YES, + "Chart View"); + + m_histogramChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, + "Histogram Chart Overlays")); + m_matrixChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, + "Matrix Chart Overlays")); + m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + "Line Series Chart Overlays")); + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); + m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, + DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); + m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); + } + + initializeCharts(); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", + m_selectedChartTwoDataType); + m_sceneAssistant->add("m_histogramChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_histogramChartOverlaySetArray.get()); + m_sceneAssistant->add("m_matrixChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_matrixChartOverlaySetArray.get()); + m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", + "ChartTwoOverlaySetArray", + m_lineSeriesChartOverlaySetArray.get()); + + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); +} + +/** + * Destructor + */ +ModelChartTwo::~ModelChartTwo() +{ + delete m_overlaySetArray; + EventManager::get()->removeAllEventsFromListener(this); + + removeAllCharts(); + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + delete m_chartableMatrixFileSelectionModel[i]; + m_chartableMatrixFileSelectionModel[i] = NULL; + + delete m_chartableMatrixSeriesFileSelectionModel[i]; + m_chartableMatrixSeriesFileSelectionModel[i] = NULL; + + delete m_chartTwoMatrixDisplayProperties[i]; + m_chartTwoMatrixDisplayProperties[i] = NULL; + } +} + +void +ModelChartTwo::initializeCharts() +{ + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_selectedChartTwoDataType[i] = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + } +} + +/** + * Reset this model. + */ +void +ModelChartTwo::reset() +{ + removeAllCharts(); + + initializeCharts(); +} + +/** + * Remove all of the charts. + */ +void +ModelChartTwo::removeAllCharts() +{ +} + +/** + * Load chart data for an average of surface nodes. + * + * @param structure + * The surface structure + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param nodeIndices + * Indices of node. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const std::vector& nodeIndices) +{ + CaretAssertToDoWarning(); +// std::map > chartFileEnabledTabs; +// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); +// fileTabIter != chartFileEnabledTabs.end(); +// fileTabIter++) { +// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; +// const std::vector tabIndices = fileTabIter->second; +// +// CaretAssert(chartFile); +// ChartData* chartData = chartFile->loadAverageLineSeriesChartDataForSurfaceNodes(structure, +// nodeIndices); +// if (chartData != NULL) { +// ChartDataSource* dataSource = chartData->getChartDataSource(); +// dataSource->setSurfaceNodeAverage(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), +// StructureEnum::toName(structure), +// surfaceNumberOfNodes, nodeIndices); +// +// addChartToChartModels(tabIndices, +// chartData); +// } +// } +} + +/** + * Load chart data for voxel at the given coordinate. + * + * @param xyz + * Coordinate of voxel. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadChartDataForVoxelAtCoordinate(const float xyz[3]) +{ + CaretAssertToDoWarning(); +// std::map > chartFileEnabledTabs; +// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); +// fileTabIter != chartFileEnabledTabs.end(); +// fileTabIter++) { +// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; +// const std::vector tabIndices = fileTabIter->second; +// +// CaretAssert(chartFile); +// ChartData* chartData = chartFile->loadLineSeriesChartDataForVoxelAtCoordinate(xyz); +// if (chartData != NULL) { +// ChartDataSource* dataSource = chartData->getChartDataSource(); +// dataSource->setVolumeVoxel(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), +// xyz); +// +// addChartToChartModels(tabIndices, +// chartData); +// } +// } +} + +/** + * Load chart data for CIFTI Map files yoked to the given yoking group. + * + * @param mapYokingGroup + * The map yoking group. + * @param mapIndex + * The map index. + */ +void +ModelChartTwo::loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex) +{ + if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + return; + } + + CaretAssertToDoWarning(); + +// std::map > chartFileEnabledTabs; +// getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); +// fileTabIter != chartFileEnabledTabs.end(); +// fileTabIter++) { +// ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; +// CaretAssert(chartFile); +// CiftiScalarDataSeriesFile* csdsf = dynamic_cast(chartFile); +// if (csdsf != NULL) { +// +// std::vector matchedTabIndices; +// const std::vector tabIndices = fileTabIter->second; +// for (std::vector::const_iterator tabIter = tabIndices.begin(); +// tabIter != tabIndices.end(); +// tabIter++) { +// const int32_t tabIndex = *tabIter; +// if (csdsf->getMatrixRowColumnMapYokingGroup(tabIndex) == mapYokingGroup) { +// matchedTabIndices.push_back(tabIndex); +// } +// } +// +// if ( ! matchedTabIndices.empty()) { +// ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(mapIndex); +// if (chartData != NULL) { +// ChartDataSource* dataSource = chartData->getChartDataSource(); +// dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), +// mapIndex); +// +// addChartToChartModels(matchedTabIndices, +// chartData); +// } +// } +// } +// } +} + + +/** + * Load chart data from given file at the given row. + * + * @param ciftiMapFile + * The CIFTI file. + * @param rowIndex + * Index of row in the file. + */ +void +ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, + const int32_t rowIndex) +{ +// CaretAssert(ciftiMapFile); +// +// std::map > chartFileEnabledTabs; +// getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); +// fileTabIter != chartFileEnabledTabs.end(); +// fileTabIter++) { +// ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; +// if (ciftiMapFile == dynamic_cast(chartFile)) { +// const std::vector tabIndices = fileTabIter->second; +// +// CaretAssert(chartFile); +// ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(rowIndex); +// if (chartData != NULL) { +// ChartDataSource* dataSource = chartData->getChartDataSource(); +// dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), +// rowIndex); +// +// addChartToChartModels(tabIndices, +// chartData); +// } +// } +// } +} + +///** +// * Get tabs and brainordinate chart files for loading chart data. +// * +// * @param chartBrainordinateFileEnabledTabsOut +// * Map with first being a chartable file and the second being +// * tabs for which that chartable file is enabled. +// */ +//void +//ModelChartTwo::getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const +//{ +// chartBrainordinateFileEnabledTabsOut.clear(); +// +// std::map > chartFileEnabledTabs; +// getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator iter = chartFileEnabledTabs.begin(); +// iter != chartFileEnabledTabs.end(); +// iter++) { +// ChartableLineSeriesBrainordinateInterface* brainChartFile = dynamic_cast(iter->first); +// if (brainChartFile != NULL) { +// chartBrainordinateFileEnabledTabsOut.insert(std::make_pair(brainChartFile, +// iter->second)); +// } +// } +//} + + +///** +// * Get tabs and row column chart files for loading chart data. +// * +// * @param chartRowColumnFilesEnabledTabsOut +// * Map with first being a chartable file and the second being +// * tabs for which that chartable file is enabled. +// */ +//void +//ModelChartTwo::getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const +//{ +// chartRowColumnFilesEnabledTabsOut.clear(); +// +// std::map > chartFileEnabledTabs; +// getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator iter = chartFileEnabledTabs.begin(); +// iter != chartFileEnabledTabs.end(); +// iter++) { +// ChartableLineSeriesRowColumnInterface* rowColChartFile = dynamic_cast(iter->first); +// if (rowColChartFile != NULL) { +// chartRowColumnFilesEnabledTabsOut.insert(std::make_pair(rowColChartFile, +// iter->second)); +// } +// } +//} + +///** +// * Get line series chart files for loading chart data. +// * +// * @param chartFileEnabledTabsOut +// * Map with first being a chartable file and the second being +// * tabs for which that chartable file is enabled. +// */ +//void +//ModelChartTwo::getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const +//{ +// chartFileEnabledTabsOut.clear(); +// +// EventBrowserTabGetAll allTabsEvent; +// EventManager::get()->sendEvent(allTabsEvent.getPointer()); +// std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); +// +// std::vector chartFiles; +// m_brain->getAllChartableLineSeriesDataFiles(chartFiles); +// +// for (std::vector::iterator iter = chartFiles.begin(); +// iter != chartFiles.end(); +// iter++) { +// ChartableLineSeriesInterface* cf = *iter; +// std::vector chartFileTabIndices; +// +// for (std::vector::iterator tabIter = validTabIndices.begin(); +// tabIter != validTabIndices.end(); +// tabIter++) { +// const int32_t tabIndex = *tabIter; +// if (cf->isLineSeriesChartingEnabled(tabIndex)) { +// chartFileTabIndices.push_back(tabIndex); +// } +// } +// +// if ( ! chartFileTabIndices.empty()) { +// chartFileEnabledTabsOut.insert(std::make_pair(cf, chartFileTabIndices)); +// } +// } +//} + +/** + * Load chart data for a surface node. + * + * @param structure + * The surface structure + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param nodeIndex + * Index of node. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const int32_t nodeIndex) +{ + CaretAssertToDoWarning(); + +// std::map > chartFileEnabledTabs; +// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); +// +// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); +// fileTabIter != chartFileEnabledTabs.end(); +// fileTabIter++) { +// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; +// const std::vector tabIndices = fileTabIter->second; +// +// CaretAssert(chartFile); +// ChartData* chartData = chartFile->loadLineSeriesChartDataForSurfaceNode(structure, +// nodeIndex); +// if (chartData != NULL) { +// ChartDataSource* dataSource = chartData->getChartDataSource(); +// dataSource->setSurfaceNode(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), +// StructureEnum::toName(structure), +// surfaceNumberOfNodes, +// nodeIndex); +// +// addChartToChartModels(tabIndices, +// chartData); +// } +// } +} + +/** + * Receive an event. + * + * @param event + * The event that the receive can respond to. + */ +void +ModelChartTwo::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS) { + EventNodeIdentificationColorsGetFromCharts* nodeChartID = + dynamic_cast(event); + CaretAssert(nodeChartID); + + EventBrowserTabGetAll allTabsEvent; + EventManager::get()->sendEvent(allTabsEvent.getPointer()); + std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); + + + const AString structureName = nodeChartID->getStructureName(); + + std::vector cartesianChartData; + +// for (std::list >::iterator dsIter = m_dataSeriesChartData.begin(); +// dsIter != m_dataSeriesChartData.end(); +// dsIter++) { +// QSharedPointer spCart = dsIter->toStrongRef(); +// if ( ! spCart.isNull()) { +// cartesianChartData.push_back(spCart.data()); +// } +// } +// for (std::list >::iterator tsIter = m_frequencySeriesChartData.begin(); +// tsIter != m_frequencySeriesChartData.end(); +// tsIter++) { +// QSharedPointer spCart = tsIter->toStrongRef(); +// if ( ! spCart.isNull()) { +// cartesianChartData.push_back(spCart.data()); +// } +// } +// for (std::list >::iterator tsIter = m_timeSeriesChartData.begin(); +// tsIter != m_timeSeriesChartData.end(); +// tsIter++) { +// QSharedPointer spCart = tsIter->toStrongRef(); +// if ( ! spCart.isNull()) { +// cartesianChartData.push_back(spCart.data()); +// } +// } +// +// +// /* +// * Iterate over node indices for which colors are desired. +// */ +// const std::vector nodeIndices = nodeChartID->getNodeIndices(); +// for (std::vector::const_iterator nodeIter = nodeIndices.begin(); +// nodeIter != nodeIndices.end(); +// nodeIter++) { +// const int32_t nodeIndex = *nodeIter; +// +// /* +// * Iterate over the data in the cartesian chart +// */ +// for (std::vector::iterator cdIter = cartesianChartData.begin(); +// cdIter != cartesianChartData.end(); +// cdIter++) { +// const ChartDataCartesian* cdc = *cdIter; +// const ChartDataSource* cds = cdc->getChartDataSource(); +// if (cds->isSurfaceNodeSourceOfData(structureName, nodeIndex)) { +// /* +// * Found node index so add its color to the event +// */ +// const CaretColorEnum::Enum color = cdc->getColor(); +// const float* rgb = CaretColorEnum::toRGB(color); +// nodeChartID->addNode(nodeIndex, +// rgb); +// break; +// } +// } +// } + + nodeChartID->setEventProcessed(); + } +} + +/** + * Get the name for use in a GUI. + * + * @param includeStructureFlag - Prefix label with structure to which + * this structure model belongs. + * @return Name for use in a GUI. + * + */ +AString +ModelChartTwo::getNameForGUI(const bool /*includeStructureFlag*/) const +{ + AString name = "Chart"; + return name; +} + +/** + * @return The name that should be displayed in the tab + * displaying this model. + */ +AString +ModelChartTwo::getNameForBrowserTab() const +{ + AString name = "Chart"; + return name; +} + +/** + * Get the overlay set for the given tab. + * @param tabIndex + * Index of tab. + * @return + * Overlay set at the given tab index. + */ +OverlaySet* +ModelChartTwo::getOverlaySet(const int tabIndex) +{ + CaretAssertArrayIndex(m_overlaySetArray, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_overlaySetArray->getOverlaySet(tabIndex); +} + +/** + * Get the overlay set for the given tab. + * @param tabIndex + * Index of tab. + * @return + * Overlay set at the given tab index. + */ +const OverlaySet* +ModelChartTwo::getOverlaySet(const int tabIndex) const +{ + CaretAssertArrayIndex(m_overlaySetArray, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_overlaySetArray->getOverlaySet(tabIndex); +} + +/** + * Initilize the overlays for this model. + */ +void +ModelChartTwo::initializeOverlays() +{ + m_overlaySetArray->initializeOverlaySelections(); +} + +/** + * Save version two charting information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param sceneClass + * SceneClass to which model specific information is added. + */ +void +ModelChartTwo::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); + + /* + * Save matrix properties. + */ + SceneObjectMapIntegerKey* matrixPropsMap = new SceneObjectMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP", + SceneObjectDataTypeEnum::SCENE_CLASS); + + for (int32_t tabIndex : tabIndices) { + matrixPropsMap->addClass(tabIndex, m_chartTwoMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, + "m_chartTwoMatrixDisplayProperties")); + } + sceneClass->addChild(matrixPropsMap); +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param sceneClass + * SceneClass to which model specific information is added. + */ +void +ModelChartTwo::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + saveVersionTwoModelSpecificInformationToScene(sceneAttributes, + sceneClass); +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChartTwo::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + reset(); + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + restoreVersionTwoModelSpecificInformationFromScene(sceneAttributes, + sceneClass); +} + +/** + * Restore information specific to the type of model from VERSION TWO scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ /* + * Restore matrix chart series models from scene. + */ + const SceneObjectMapIntegerKey* matrixPropsMap = sceneClass->getMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP"); + if (matrixPropsMap != NULL) { + const std::vector tabIndices = matrixPropsMap->getKeys(); + for (const int32_t tabIndex : tabIndices) { + const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); + m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); + } + } + + /* + * Restore the chart models + */ + restoreVersionTwoChartModelsFromScene(sceneAttributes, + sceneClass); +} + +/** + * Restore the chart models from a VERSION TWO scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ModelChartTwo::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + /* Probably nothing to do here */ +} + + +/** + * Get a text description of the window's content. + * + * @param tabIndex + * Index of the tab for content description. + * @param descriptionOut + * Description of the window's content. + */ +void +ModelChartTwo::getDescriptionOfContent(const int32_t tabIndex, + PlainTextStringBuilder& descriptionOut) const +{ +// ChartModel* chartModel = NULL; +// switch (getSelectedChartOneDataType(tabIndex)) { +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: +// { +// CaretDataFileSelectionModel* sm = m_chartableMatrixFileSelectionModel[tabIndex]; +// const CaretDataFile* caretFile = sm->getSelectedFile(); +// if (caretFile != NULL) { +// descriptionOut.addLine("Matrix (layer) chart for: " +// + caretFile->getFileNameNoPath()); +// return; +// } +// } +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: +// { +// CaretDataFileSelectionModel* sm = m_chartableMatrixSeriesFileSelectionModel[tabIndex]; +// const CaretDataFile* caretFile = sm->getSelectedFile(); +// if (caretFile != NULL) { +// descriptionOut.addLine("Matrix (series) chart for: " +// + caretFile->getFileNameNoPath()); +// return; +// } +// } +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: +// chartModel = const_cast(getSelectedDataSeriesChartModel(tabIndex)); +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: +// chartModel = const_cast(getSelectedFrequencySeriesChartModel(tabIndex)); +// break; +// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: +// chartModel = const_cast(getSelectedTimeSeriesChartModel(tabIndex)); +// break; +// } +// +// const ChartModel* chartModelConst = chartModel; +// +// if (chartModel != NULL) { +// descriptionOut.addLine("Chart Type: " +// + ChartOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); +// +// descriptionOut.pushIndentation(); +// +// const std::vector cdVec = chartModelConst->getAllChartDatas(); +// for (std::vector::const_iterator iter = cdVec.begin(); +// iter != cdVec.end(); +// iter++) { +// const ChartData* cd = *iter; +// if (cd->isSelected(tabIndex)) { +// descriptionOut.addLine(cd->getChartDataSource()->getDescription()); +// } +// } +// +// if (chartModel->isAverageChartDisplaySupported()) { +// if (chartModel->isAverageChartDisplaySelected()) { +// descriptionOut.addLine("Average Chart Displayed"); +// } +// } +// +// descriptionOut.popIndentation(); +// } +// else { +// descriptionOut.addLine("No charts to display"); +// } +} + +/** + * Copy the tab content from the source tab index to the + * destination tab index. + * + * @param sourceTabIndex + * Source from which tab content is copied. + * @param destinationTabIndex + * Destination to which tab content is copied. + */ +void +ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, + const int32_t destinationTabIndex) +{ + Model::copyTabContent(sourceTabIndex, + destinationTabIndex); + + m_overlaySetArray->copyOverlaySet(sourceTabIndex, + destinationTabIndex); + + m_selectedChartTwoDataType[destinationTabIndex] = m_selectedChartTwoDataType[sourceTabIndex]; + m_chartableMatrixFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixFileSelectionModel[sourceTabIndex]->getSelectedFile()); + m_chartableMatrixSeriesFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixSeriesFileSelectionModel[sourceTabIndex]->getSelectedFile()); +} + + +/** + * Set the type of chart selected in the given tab. + * + * @param tabIndex + * Index of tab. + * @param dataType + * Type of data for chart. + */ +void +ModelChartTwo::setSelectedChartTwoDataType(const int32_t tabIndex, + const ChartTwoDataTypeEnum::Enum dataType) +{ + CaretAssertArrayIndex(m_selectedChartTwoDataType, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + m_selectedChartTwoDataType[tabIndex] = dataType; +} + +/** + * Get the valid chart data types based upon the currently loaded files. + * + * @param validChartDataTypesOut + * Output containing valid chart data types. + */ +void +ModelChartTwo::getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const +{ + validChartDataTypesOut.clear(); + + /** + * Get the data files. + */ + std::vector allDataFiles; + EventCaretMappableDataFilesGet eventGetMapDataFiles; + EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); + eventGetMapDataFiles.getAllFiles(allDataFiles); + + std::set chartTypeSet; + + for (auto mapFile : allDataFiles) { + ChartableTwoFileDelegate* chartFile = mapFile->getChartingDelegate(); + std::vector fileChartTypes; + chartFile->getSupportedChartTwoDataTypes(fileChartTypes); + + chartTypeSet.insert(fileChartTypes.begin(), + fileChartTypes.end()); + } + + validChartDataTypesOut.insert(validChartDataTypesOut.end(), + chartTypeSet.begin(), + chartTypeSet.end()); +} + +/** + * Get the type of chart selected in the given tab. + * + * @param tabIndex + * Index of tab. + * @return + * Chart type in the given tab. + */ +ChartTwoDataTypeEnum::Enum +ModelChartTwo::getSelectedChartTwoDataType(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_selectedChartTwoDataType, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + ChartTwoDataTypeEnum::Enum chartDataType = m_selectedChartTwoDataType[tabIndex]; + + std::vector validChartDataTypes; + getValidChartTwoDataTypes(validChartDataTypes); + + /* + * Test if selected chart type is still valid + */ + if (std::find(validChartDataTypes.begin(), + validChartDataTypes.end(), + chartDataType) == validChartDataTypes.end()) { + chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + } + + /* + * Find a valid chart type? + */ + if (chartDataType == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { + if ( ! validChartDataTypes.empty()) { + CaretAssertVectorIndex(validChartDataTypes, 0); + chartDataType = validChartDataTypes[0]; + } + } + + m_selectedChartTwoDataType[tabIndex] = chartDataType; + return chartDataType; +} + +/** + * Update the chart overlay sets. + * + * @param tabIndex + * Index of the tab. + */ +void +ModelChartTwo::updateChartOverlaySets(const int32_t tabIndex) +{ + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + switch (m_selectedChartTwoDataType[tabIndex]) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } +} + +/** + * @return The chart matrix display properties for the given tab. + * + * @param tabIndex + * The tab index. + */ +ChartTwoMatrixDisplayProperties* +ModelChartTwo::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) +{ + CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_chartTwoMatrixDisplayProperties[tabIndex]; +} + +/** + * @return The chart matrix display properties for the given tab. + * + * @param tabIndex + * The tab index. + */ +const ChartTwoMatrixDisplayProperties* +ModelChartTwo::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const +{ + CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, + BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, + tabIndex); + return m_chartTwoMatrixDisplayProperties[tabIndex]; +} + +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +ChartTwoOverlaySet* +ModelChartTwo::getChartTwoOverlaySet(const int tabIndex) +{ + ChartTwoOverlaySet* chartOverlaySet = NULL; + + switch (getSelectedChartTwoDataType(tabIndex)) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + chartOverlaySet = m_histogramChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + chartOverlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); + break; + } + + return chartOverlaySet; +} + +/** + * Get the chart overlay set for this model. + * + * @param tabIndex + * Index for the chart overlay set. + * @return + * Chart overlay set or NULL if not valid for this model. + */ +const ChartTwoOverlaySet* +ModelChartTwo::getChartTwoOverlaySet(const int tabIndex) const +{ + ModelChartTwo* nonConstModelChart = const_cast(this); + CaretAssert(nonConstModelChart); + const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartTwoOverlaySet(tabIndex); + + return chartOverlaySet; +} + + diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h new file mode 100644 index 000000000..0fa7c5fb3 --- /dev/null +++ b/src/Brain/ModelChartTwo.h @@ -0,0 +1,164 @@ +#ifndef __MODEL_CHART_TWO_H__ +#define __MODEL_CHART_TWO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include + +#include +#include +#include + +#include "ChartTwoDataTypeEnum.h" +#include "EventListenerInterface.h" +#include "MapYokingGroupEnum.h" +#include "Model.h" +#include "StructureEnum.h" + +namespace caret { + + class CaretDataFileSelectionModel; + class ChartTwoMatrixDisplayProperties; + class ChartTwoOverlaySetArray; + class CiftiConnectivityMatrixParcelFile; + class CiftiMappableDataFile; + class OverlaySetArray; + class SurfaceFile; + + /// Controls the display of a chart. + class ModelChartTwo : public Model, public EventListenerInterface { + + public: + ModelChartTwo(Brain* brain); + + virtual ~ModelChartTwo(); + + virtual void initializeOverlays() override; + + virtual AString getNameForGUI(const bool includeStructureFlag) const override; + + virtual AString getNameForBrowserTab() const override; + + void loadChartDataForSurfaceNode(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const int32_t nodeIndex); + + void loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const std::vector& nodeIndices); + + void loadChartDataForVoxelAtCoordinate(const float xyz[3]); + + void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, + const int32_t rowIndex); + + void loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex); + + virtual OverlaySet* getOverlaySet(const int tabIndex) override; + + virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; + + ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex); + + const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const; + + virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) override; + + virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const override; + + virtual void receiveEvent(Event* event) override; + + void getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const; + + ChartTwoDataTypeEnum::Enum getSelectedChartTwoDataType(const int32_t tabIndex) const; + + void setSelectedChartTwoDataType(const int32_t tabIndex, + const ChartTwoDataTypeEnum::Enum dataType); + + virtual void getDescriptionOfContent(const int32_t tabIndex, + PlainTextStringBuilder& descriptionOut) const override; + + virtual void copyTabContent(const int32_t sourceTabIndex, + const int32_t destinationTabIndex) override; + + void reset(); + + protected: + virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) override; + + virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) override; + + private: + ModelChartTwo(const ModelChartTwo&); + + ModelChartTwo& operator=(const ModelChartTwo&); + + void initializeCharts(); + + void removeAllCharts(); + + void updateChartOverlaySets(const int32_t tabIndex); + + void restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + +// void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; +// +// void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; +// +// void getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const; + + virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + void restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + /** Overlays sets for this model and for each tab */ + OverlaySetArray* m_overlaySetArray; + + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_histogramChartOverlaySetArray; + + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_lineSeriesChartOverlaySetArray; + + /** Chart Overlay sets for XX data type */ + std::unique_ptr m_matrixChartOverlaySetArray; + + ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + std::unique_ptr m_sceneAssistant; + }; + +} // namespace + +#endif // __MODEL_CHART_TWO_H__ diff --git a/src/Brain/ModelTypeEnum.cxx b/src/Brain/ModelTypeEnum.cxx index b73b4b8a3..be37b3ef8 100644 --- a/src/Brain/ModelTypeEnum.cxx +++ b/src/Brain/ModelTypeEnum.cxx @@ -70,36 +70,40 @@ ModelTypeEnum::initialize() } initializedFlag = true; - enumData.push_back(ModelTypeEnum(MODEL_TYPE_INVALID, - 0, - "MODEL_TYPE_INVALID", - "Invalid")); + enumData.push_back(ModelTypeEnum(MODEL_TYPE_INVALID, + 0, + "MODEL_TYPE_INVALID", + "Invalid")); - enumData.push_back(ModelTypeEnum(MODEL_TYPE_CHART, - 1, - "MODEL_TYPE_CHART", - "Chart")); + enumData.push_back(ModelTypeEnum(MODEL_TYPE_CHART, + 1, + "MODEL_TYPE_CHART", + "Chart")); - enumData.push_back(ModelTypeEnum(MODEL_TYPE_SURFACE, + enumData.push_back(ModelTypeEnum(MODEL_TYPE_CHART_TWO, 2, + "MODEL_TYPE_CHART_TWO", + "Chart")); + + enumData.push_back(ModelTypeEnum(MODEL_TYPE_SURFACE, + 3, "MODEL_TYPE_SURFACE", "Surface")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_SURFACE_MONTAGE, - 3, - "MODEL_TYPE_SURFACE_MONTAGE", - "Surface Montage")); - - enumData.push_back(ModelTypeEnum(MODEL_TYPE_VOLUME_SLICES, - 4, - "MODEL_TYPE_VOLUME_SLICES", - "Volume")); + 4, + "MODEL_TYPE_SURFACE_MONTAGE", + "Surface Montage")); - enumData.push_back(ModelTypeEnum(MODEL_TYPE_WHOLE_BRAIN, - 5, - "MODEL_TYPE_WHOLE_BRAIN", - "Whole Brain")); + enumData.push_back(ModelTypeEnum(MODEL_TYPE_VOLUME_SLICES, + 5, + "MODEL_TYPE_VOLUME_SLICES", + "Volume")); + enumData.push_back(ModelTypeEnum(MODEL_TYPE_WHOLE_BRAIN, + 6, + "MODEL_TYPE_WHOLE_BRAIN", + "Whole Brain")); } /** diff --git a/src/Brain/ModelTypeEnum.h b/src/Brain/ModelTypeEnum.h index 287fa04c6..3d52e072c 100644 --- a/src/Brain/ModelTypeEnum.h +++ b/src/Brain/ModelTypeEnum.h @@ -40,6 +40,8 @@ public: MODEL_TYPE_INVALID, /** Chart */ MODEL_TYPE_CHART, + /** Chart Two */ + MODEL_TYPE_CHART_TWO, /** Surface */ MODEL_TYPE_SURFACE, /** Surface Montage */ diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index e7f81c580..5e3e509c9 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -177,6 +177,8 @@ VolumeSliceSettings::getDescriptionOfContent(const ModelTypeEnum::Enum modelType switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: diff --git a/src/Charting/ChartTwoDataCartesianHistory.cxx b/src/Charting/ChartTwoDataCartesianHistory.cxx index eda539cc5..106cf95c2 100644 --- a/src/Charting/ChartTwoDataCartesianHistory.cxx +++ b/src/Charting/ChartTwoDataCartesianHistory.cxx @@ -310,16 +310,18 @@ ChartTwoDataCartesianHistory::saveToScene(const SceneAttributes* sceneAttributes /* * Save chart history */ - SceneObjectMapIntegerKey* chartHistoryMap = new SceneObjectMapIntegerKey("m_chartHistoryMap", - SceneObjectDataTypeEnum::SCENE_CLASS); - const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); - for (auto tabIndex : tabIndices) { - CaretAssertVectorIndex(m_chartHistory, tabIndex); - chartHistoryMap->addClass(tabIndex, - m_chartHistory[tabIndex]->saveToScene(sceneAttributes, - "m_chartHistory")); + const int32_t numHistory = static_cast(m_chartHistory.size()); + if (numHistory > 0) { + SceneObjectMapIntegerKey* chartHistoryMap = new SceneObjectMapIntegerKey("m_chartHistoryMap", + SceneObjectDataTypeEnum::SCENE_CLASS); + for (int32_t i = 0; i < numHistory; i++) { + CaretAssertVectorIndex(m_chartHistory, i); + chartHistoryMap->addClass(i, + m_chartHistory[i]->saveToScene(sceneAttributes, + "m_chartHistory")); + } + sceneClass->addChild(chartHistoryMap); } - sceneClass->addChild(chartHistoryMap); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, @@ -357,12 +359,16 @@ ChartTwoDataCartesianHistory::restoreFromScene(const SceneAttributes* sceneAttri */ const SceneObjectMapIntegerKey* chartHistoryMap = sceneClass->getMapIntegerKey("m_chartHistoryMap"); if (chartHistoryMap != NULL) { - const std::vector tabIndices = chartHistoryMap->getKeys(); - for (auto tabIndex : tabIndices) { - const SceneClass* sceneClass = chartHistoryMap->classValue(tabIndex); - CaretAssertVectorIndex(m_chartHistory, tabIndex); - m_chartHistory[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); + const std::vector indices = chartHistoryMap->getKeys(); + const int32_t numIndices = static_cast(indices.size()); + for (int32_t i = 0; i < numIndices; i++) { + const SceneClass* historyClass = chartHistoryMap->classValue(i); + ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + historyItem->restoreFromScene(sceneAttributes, + historyClass); + addHistoryItem(historyItem); } } diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index b85ba76d7..f55290fa7 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -650,8 +650,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) int defaultTabIndex = -1; bool enableLayers = true; bool enableVolumeSurfaceOutline = false; - bool enableOldCharts = false; - bool enableNewCharts = false; + bool enableChartOne = false; + bool enableChartTwo = false; EventBrowserWindowContentGet browserContentEvent(m_browserWindowIndex); EventManager::get()->sendEvent(browserContentEvent.getPointer()); BrowserTabContent* windowContent = browserContentEvent.getSelectedBrowserTabContent(); @@ -676,20 +676,18 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) & haveVolumes); break; case ModelTypeEnum::MODEL_TYPE_CHART: - if (m_browserWindowIndex == 0) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { - defaultTabIndex = m_chartOverlayTabIndex; - enableNewCharts = true; - } - else { - defaultTabIndex = m_chartTabIndex; - enableOldCharts = true; - } - } - else { - defaultTabIndex = m_chartTabIndex; - enableOldCharts = true; - } + defaultTabIndex = m_chartTabIndex; + enableChartOne = true; + enableLayers = false; + enableVolumeSurfaceOutline = false; + haveBorders = false; + haveFibers = false; + haveFoci = false; + haveLabels = false; + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + defaultTabIndex = m_chartOverlayTabIndex; + enableChartTwo = true; enableLayers = false; enableVolumeSurfaceOutline = false; haveBorders = false; @@ -713,8 +711,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) * NOTE: Order is important so that overlay tab is * automatically selected. */ - if (m_chartTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartTabIndex, enableOldCharts); - if (m_chartOverlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartOverlayTabIndex, enableNewCharts); + if (m_chartTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartTabIndex, enableChartOne); + if (m_chartOverlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartOverlayTabIndex, enableChartTwo); if (m_connectivityTabIndex >= 0) m_tabWidget->setTabEnabled(m_connectivityTabIndex, haveConnFiles); if (m_volumeSurfaceOutlineTabIndex >= 0) m_tabWidget->setTabEnabled(m_volumeSurfaceOutlineTabIndex, enableVolumeSurfaceOutline); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 264839d7d..ba7ef6cad 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -93,6 +93,7 @@ #include "GuiManager.h" #include "Model.h" #include "ModelChart.h" +#include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelSurfaceSelector.h" @@ -156,7 +157,6 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->isContructorFinished = false; this->isDestructionInProgress = false; - m_chartingTwoFlag = false; this->viewOrientationLeftIcon = NULL; this->viewOrientationRightIcon = NULL; @@ -749,6 +749,7 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() int32_t cerebellumSurfaceTypeCode = 1000000; ModelChart* chartModel = NULL; + ModelChartTwo* chartTwoModel = NULL; ModelSurfaceMontage* surfaceMontageModel = NULL; ModelVolume* volumeModel = NULL; ModelWholeBrain* wholeBrainModel = NULL; @@ -817,6 +818,9 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() else if (dynamic_cast(*iter)) { chartModel = dynamic_cast(*iter); } + else if (dynamic_cast(*iter)) { + chartTwoModel = dynamic_cast(*iter); + } else { CaretAssertMessage(0, AString("Unknow controller type: ") + (*iter)->getNameForGUI(true)); } @@ -854,6 +858,9 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() if (chartModel != NULL) { numberOfTabsNeeded++; } + if (chartTwoModel != NULL) { + numberOfTabsNeeded++; + } if (leftSurfaceModel != NULL) { numberOfTabsNeeded++; } @@ -879,6 +886,8 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() wholeBrainModel); tabIndex = loadIntoTab(tabIndex, chartModel); + tabIndex = loadIntoTab(tabIndex, + chartTwoModel); tabIndex = loadIntoTab(tabIndex, leftSurfaceModel); tabIndex = loadIntoTab(tabIndex, @@ -934,6 +943,8 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() break; case ModelTypeEnum::MODEL_TYPE_CHART: break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; } } } @@ -1370,16 +1381,6 @@ BrainBrowserWindowToolBar::updateToolBar() this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - /* - * Use new charting in 1st window and old charting in other windows? - */ - m_chartingTwoFlag = false; - if (this->browserWindowIndex == 0) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1)) { - m_chartingTwoFlag = true; - } - } - BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); const ModelTypeEnum::Enum viewModel = this->updateViewWidget(browserTabContent); @@ -1388,7 +1389,7 @@ BrainBrowserWindowToolBar::updateToolBar() bool showWholeBrainSurfaceOptionsWidget = false; bool showSingleSurfaceOptionsWidget = false; bool showSurfaceMontageOptionsWidget = false; - bool showClippingOptionsWidget = true; + bool showClippingOptionsWidget = false; bool showVolumeIndicesWidget = false; bool showVolumePlaneWidget = false; bool showVolumeMontageWidget = false; @@ -1409,65 +1410,64 @@ BrainBrowserWindowToolBar::updateToolBar() case ModelTypeEnum::MODEL_TYPE_SURFACE: showOrientationWidget = true; showSingleSurfaceOptionsWidget = true; + showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: showOrientationWidget = true; showSurfaceMontageOptionsWidget = true; + showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: showVolumeIndicesWidget = true; showVolumePlaneWidget = true; showVolumeMontageWidget = true; + showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: showOrientationWidget = true; showWholeBrainSurfaceOptionsWidget = true; showVolumeIndicesWidget = true; + showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_CHART: { - if (m_chartingTwoFlag) { - showChartTwoTypeWidget = true; - } - else { - showChartOneTypeWidget = true; - } - - showClippingOptionsWidget = false; - - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { - if (m_chartingTwoFlag) { - showChartTwoOrientationWidget = true; - showChartTwoAttributesWidget = true; - } - else { - switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { - case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: - showChartOneAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: - showChartOneAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - showChartOneAxesWidget = true; - showChartOneAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: - showChartOneAxesWidget = true; - showChartOneAttributesWidget = true; - break; - case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: - showChartOneAxesWidget = true; - showChartOneAttributesWidget = true; - break; - } + switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + showChartOneAxesWidget = true; + showChartOneAttributesWidget = true; + break; } } } break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + { + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); + if (modelChartTwo != NULL) { + showChartTwoTypeWidget = true; + showChartTwoOrientationWidget = true; + showChartTwoAttributesWidget = true; + } + } + break; } /* @@ -1582,18 +1582,20 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab QWidget* BrainBrowserWindowToolBar::createViewWidget() { - this->viewModeChartRadioButton = new QRadioButton("Chart"); + this->viewModeChartOneRadioButton = new QRadioButton("Chart"); + this->viewModeChartTwoRadioButton = new QRadioButton("Chart Two"); this->viewModeSurfaceRadioButton = new QRadioButton("Surface"); this->viewModeSurfaceMontageRadioButton = new QRadioButton("Montage"); this->viewModeVolumeRadioButton = new QRadioButton("Volume"); this->viewModeWholeBrainRadioButton = new QRadioButton("All"); -// this->viewModeChartRadioButton->setVisible(false); +// this->viewModeChartOneRadioButton->setVisible(false); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); - layout->addWidget(this->viewModeChartRadioButton); + layout->addWidget(this->viewModeChartOneRadioButton); + layout->addWidget(this->viewModeChartTwoRadioButton); layout->addWidget(this->viewModeSurfaceMontageRadioButton); layout->addWidget(this->viewModeVolumeRadioButton); layout->addWidget(this->viewModeWholeBrainRadioButton); @@ -1601,7 +1603,8 @@ BrainBrowserWindowToolBar::createViewWidget() layout->addStretch(); QButtonGroup* viewModeRadioButtonGroup = new QButtonGroup(this); - viewModeRadioButtonGroup->addButton(this->viewModeChartRadioButton); + viewModeRadioButtonGroup->addButton(this->viewModeChartOneRadioButton); + viewModeRadioButtonGroup->addButton(this->viewModeChartTwoRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeSurfaceRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeSurfaceMontageRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeVolumeRadioButton); @@ -1610,7 +1613,8 @@ BrainBrowserWindowToolBar::createViewWidget() this, SLOT(viewModeRadioButtonClicked(QAbstractButton*))); this->viewWidgetGroup = new WuQWidgetObjectGroup(this); - this->viewWidgetGroup->add(this->viewModeChartRadioButton); + this->viewWidgetGroup->add(this->viewModeChartOneRadioButton); + this->viewWidgetGroup->add(this->viewModeChartTwoRadioButton); this->viewWidgetGroup->add(this->viewModeSurfaceRadioButton); this->viewWidgetGroup->add(this->viewModeSurfaceMontageRadioButton); this->viewWidgetGroup->add(this->viewModeVolumeRadioButton); @@ -1652,7 +1656,8 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent this->viewModeSurfaceMontageRadioButton->setEnabled(browserTabContent->isSurfaceMontageModelValid()); this->viewModeVolumeRadioButton->setEnabled(browserTabContent->isVolumeSliceModelValid()); this->viewModeWholeBrainRadioButton->setEnabled(browserTabContent->isWholeBrainModelValid()); - this->viewModeChartRadioButton->setEnabled(browserTabContent->isChartModelValid()); + this->viewModeChartOneRadioButton->setEnabled(browserTabContent->isChartOneModelValid()); + this->viewModeChartTwoRadioButton->setEnabled(browserTabContent->isChartTwoModelValid()); } switch (modelType) { @@ -1671,7 +1676,10 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent this->viewModeWholeBrainRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_CHART: - this->viewModeChartRadioButton->setChecked(true); + this->viewModeChartOneRadioButton->setChecked(true); + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + this->viewModeChartTwoRadioButton->setChecked(true); break; } @@ -3192,9 +3200,12 @@ BrainBrowserWindowToolBar::viewModeRadioButtonClicked(QAbstractButton*) return; } - if (this->viewModeChartRadioButton->isChecked()) { + if (this->viewModeChartOneRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_CHART); } + else if (this->viewModeChartTwoRadioButton->isChecked()) { + btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_CHART_TWO); + } else if (this->viewModeSurfaceRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_SURFACE); } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index b87c51e40..bee144fb5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -275,7 +275,8 @@ namespace caret { QRadioButton* viewModeSurfaceMontageRadioButton; QRadioButton* viewModeVolumeRadioButton; QRadioButton* viewModeWholeBrainRadioButton; - QRadioButton* viewModeChartRadioButton; + QRadioButton* viewModeChartOneRadioButton; + QRadioButton* viewModeChartTwoRadioButton; QAction* customViewAction; @@ -422,8 +423,6 @@ namespace caret { bool isContructorFinished; bool isDestructionInProgress; - - bool m_chartingTwoFlag; }; } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx index e157247f5..c86c6fd58 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx @@ -129,7 +129,7 @@ BrainBrowserWindowToolBarChartAttributes::getCartesianChart() BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); @@ -169,7 +169,7 @@ BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx index 9f3887261..f8ed112f2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx @@ -273,7 +273,7 @@ BrainBrowserWindowToolBarChartAxes::getCartesianChart() BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index e686f97be..3a6e69b4d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -41,7 +41,7 @@ #include "ChartTwoMatrixDisplayProperties.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" -#include "ModelChart.h" +#include "ModelChartTwo.h" #include "WuQFactory.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -96,10 +96,10 @@ void BrainBrowserWindowToolBarChartTwoAttributes::updateContent(BrowserTabContent* browserTabContent) { if (browserTabContent != NULL) { - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); const int32_t tabIndex = browserTabContent->getTabNumber(); - if (modelChart != NULL) { - switch (modelChart->getSelectedChartTwoDataType(tabIndex)) { + if (modelChartTwo != NULL) { + switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: @@ -183,8 +183,8 @@ BrainBrowserWindowToolBarChartTwoAttributes::getChartableTwoMatrixDisplayPropert BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { - ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); - matrixDisplayProperties = modelChart->getChartTwoMatrixDisplayProperties(browserTabContent->getTabNumber()); + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); + matrixDisplayProperties = modelChartTwo->getChartTwoMatrixDisplayProperties(browserTabContent->getTabNumber()); // // if (modelChart != NULL) { // const int32_t tabIndex = browserTabContent->getTabNumber(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx index 8e049c139..b829cdd0e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx @@ -31,7 +31,7 @@ #include "CaretAssert.h" #include "CaretPreferences.h" #include "EventManager.h" -#include "ModelChart.h" +#include "ModelChartTwo.h" #include "SessionManager.h" #include "WuQtUtilities.h" diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx index aaa1112a8..a1cdab23e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx @@ -30,9 +30,8 @@ #include "BrowserTabContent.h" #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" -#include "ChartModel.h" #include "EnumComboBoxTemplate.h" -#include "ModelChart.h" +#include "ModelChartTwo.h" #include "WuQtUtilities.h" using namespace caret; @@ -105,9 +104,9 @@ BrainBrowserWindowToolBarChartTwoType::chartTypeRadioButtonClicked(int buttonInd m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); - ModelChart* chartModel = btc->getDisplayedChartModel(); + ModelChartTwo* chartModelTwo = btc->getDisplayedChartTwoModel(); const int32_t tabIndex = btc->getTabNumber(); - chartModel->setSelectedChartTwoDataType(tabIndex, + chartModelTwo->setSelectedChartTwoDataType(tabIndex, chartDataType); //updateContent(btc); @@ -128,13 +127,13 @@ BrainBrowserWindowToolBarChartTwoType::updateContent(BrowserTabContent* browserT m_chartTypeButtonGroup->blockSignals(true); - const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); - if (chartModel != NULL) { + const ModelChartTwo* chartModelTwo = browserTabContent->getDisplayedChartTwoModel(); + if (chartModelTwo != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); - const ChartTwoDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartTwoDataType(tabIndex); + const ChartTwoDataTypeEnum::Enum selectedChartType = chartModelTwo->getSelectedChartTwoDataType(tabIndex); std::vector validChartDataTypes; - chartModel->getValidChartTwoDataTypes(validChartDataTypes); + chartModelTwo->getValidChartTwoDataTypes(validChartDataTypes); for (auto chartTypeButton : m_chartTypeRadioButtons) { ChartTwoDataTypeEnum::Enum chartType = chartTypeButton.first; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index 3f479cec7..2b2ae2d97 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -146,7 +146,7 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); - ModelChart* chartModel = btc->getDisplayedChartModel(); + ModelChart* chartModel = btc->getDisplayedChartOneModel(); const int32_t tabIndex = btc->getTabNumber(); chartModel->setSelectedChartOneDataType(tabIndex, chartDataType); @@ -169,7 +169,7 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC m_chartTypeButtonGroup->blockSignals(true); - const ModelChart* chartModel = browserTabContent->getDisplayedChartModel(); + const ModelChart* chartModel = browserTabContent->getDisplayedChartOneModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartOneDataType(tabIndex); diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 877e856a8..1d0c25706 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -580,6 +580,8 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, return NULL; } + EventManager::get()->blockEvent(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET, true); + int32_t windowIndex = -1; int32_t numWindows = static_cast(m_brainBrowserWindows.size()); @@ -614,6 +616,8 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, bbw->resetGraphicsWidgetMinimumSize(); + EventManager::get()->blockEvent(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET, false); + return bbw; } -- GitLab From d64e94da156eff64a0dffb0c6201daddf9148aaf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 2 Feb 2017 16:42:34 -0600 Subject: [PATCH 195/755] Continuing charting development. Starting to draw histogram charts. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 562 +++++++++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 14 +- src/Brain/IdentificationTextGenerator.cxx | 16 + src/Brain/ModelChart.cxx | 4 +- src/Brain/SelectionItemChartTwoHistogram.cxx | 33 +- src/Brain/SelectionItemChartTwoHistogram.h | 12 + src/Charting/CMakeLists.txt | 4 + src/Charting/ChartTwoDataCartesian.cxx | 13 + src/Charting/ChartTwoDataHistogram.cxx | 329 ++++++++++ src/Charting/ChartTwoDataHistogram.h | 104 ++++ .../ChartTwoHistogramViewingTypeEnum.cxx | 373 ++++++++++++ .../ChartTwoHistogramViewingTypeEnum.h | 104 ++++ src/Files/ChartableTwoFileHistogramChart.cxx | 39 ++ src/Files/ChartableTwoFileHistogramChart.h | 12 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 4 +- 15 files changed, 1540 insertions(+), 83 deletions(-) create mode 100644 src/Charting/ChartTwoDataHistogram.cxx create mode 100644 src/Charting/ChartTwoDataHistogram.h create mode 100644 src/Charting/ChartTwoHistogramViewingTypeEnum.cxx create mode 100644 src/Charting/ChartTwoHistogramViewingTypeEnum.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0c0949be2..1c305bd5d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -29,6 +29,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" +#include "ChartTwoDataHistogram.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -38,6 +39,7 @@ #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "IdentificationWithColor.h" +#include "MathFunctions.h" #include "ModelChartTwo.h" #include "SessionManager.h" #include "SelectionItemChartTwoHistogram.h" @@ -127,6 +129,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); + bool drawHistogramFlag = true; + bool drawLineSeriesFlag = true; + bool drawMatrixFlag = true; + /* * Check for a 'selection' type mode */ @@ -135,9 +141,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: - if (m_selectionItemHistogram->isEnabledForSelection() - || m_selectionItemLineSeries->isEnabledForSelection() - || m_selectionItemMatrix->isEnabledForSelection()) { + if ( ! m_selectionItemHistogram->isEnabledForSelection()) { + drawHistogramFlag = false; + } + if ( ! m_selectionItemLineSeries->isEnabledForSelection()) { + drawLineSeriesFlag = false; + } + if ( ! m_selectionItemMatrix->isEnabledForSelection()) { + drawMatrixFlag = false; + } + if (drawHistogramFlag + || drawLineSeriesFlag + || drawMatrixFlag) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @@ -168,19 +183,23 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - drawHistogramChart(); + if (drawHistogramFlag) { + drawHistogramChart(); + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + if (drawLineSeriesFlag) { + + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - drawMatrixChart(); + if (drawMatrixFlag) { + drawMatrixChart(); + } break; } } } - for (int32_t iOverlay = (numberOfOverlays -1); iOverlay >= 0; iOverlay--) { - - } } } @@ -274,11 +293,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() // chartGraphicsDrawingViewport); // } - glViewport(chartGraphicsDrawingViewport[0], - chartGraphicsDrawingViewport[1], - chartGraphicsDrawingViewport[2], - chartGraphicsDrawingViewport[3]); - const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); @@ -289,11 +303,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() /* * Get extent of histogram data */ - CaretAssertToDoWarning(); // extent of all displayed histograms float xMin = 0.0; - float xMax = 100.0; + float xMax = 0.0; float yMin = 0.0; - float yMax = 100.0; + float yMax = 0.0; for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -311,14 +324,41 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); if (histogramChart->isValid()) { + const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); + float bounds[4]; + if (histogramData->getBounds(bounds)) { + xMin = std::min(xMin, bounds[0]); + xMax = std::max(xMax, bounds[1]); + yMin = std::min(yMin, bounds[2]); + yMax = std::max(yMax, bounds[3]); + } } } + /* + * Bounds valid? + */ + if ((xMin >= xMax) + || (yMin >= yMax)) { + return; + } + +// std::cout << "All bounds: " +// << xMin << " " +// << xMax << " " +// << yMin << " " +// << yMax << " " << std::endl; + + glViewport(chartGraphicsDrawingViewport[0], + chartGraphicsDrawingViewport[1], + chartGraphicsDrawingViewport[2], + chartGraphicsDrawingViewport[3]); + glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(xMin, xMax, yMin, yMax, - -1.0, 1.0); + -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -344,6 +384,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() 0.0); } + int32_t layerIndex = 0; for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -361,7 +402,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); if (histogramChart->isValid()) { - drawHistogramChartContent(histogramChart); + drawHistogramChartContent(histogramChart, + mapIndex); + layerIndex++; } } } @@ -370,9 +413,346 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Draw the given histogram chart. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart) +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex) { - std::cout << "DRAW HISTOGRAM" << std::endl; + const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); + + if (m_identificationModeFlag) { + resetIdentification(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + +// m_identificationModeFlag = false; +// switch (m_fixedPipelineDrawing->mode) { +// case BrainOpenGLFixedPipeline::MODE_DRAWING: +// break; +// case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: +// if (m_selectionItemMatrix->isEnabledForSelection()) { +// m_identificationModeFlag = true; +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// else { +// return; +// } +// break; +// case BrainOpenGLFixedPipeline::MODE_PROJECTION: +// return; +// break; +// } + + float bounds[4]; + if ( ! histogramData->getBounds(bounds)) { + return; + } + + glColor3f(1.0, 0.0, 0.0); + glBegin(GL_LINES); + glVertex3f(bounds[0], bounds[2], 0.0); + glVertex3f(bounds[1], bounds[3], 0.0); + glEnd(); + + const std::vector heightValues = histogramData->getHistogramValues(); + const int32_t numValues = static_cast(heightValues.size()); + if (numValues > 1) { + std::vector quadVerticesXYZ; + std::vector quadVerticesFloatRGBA; + std::vector quadVerticesByteRGBA; + + switch (histogramData->getHistogramViewingType()) { + case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS: + { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 4; + const int32_t totalVertices = verticesPerBar * numValues; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.; + + for (int32_t i = 0; i < numValues; i++) { + float left = i; + float right = i + 1; + float bottom = 0; + CaretAssertVectorIndex(heightValues, i); + float top = heightValues[i]; + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + + if (m_identificationModeFlag) { + uint8_t idRGBA[4]; + addToHistogramIdentification(i, idRGBA); + + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + } + else { + float rgba[4] = { 1.0, 0.5, 0.0, 1.0 }; + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + + } + + /* + * Draw the bar elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); + glColor4ubv(&quadVerticesByteRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + else { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); + glColor4fv(&quadVerticesFloatRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + } + break; + case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE: + { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 2; + const int32_t totalVertices = verticesPerBar * numValues + 4; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.0; + + const int32_t lastValueIndex = numValues - 1; + for (int32_t i = 0; i < numValues; i++) { + float left = i; + float right = i + 1; + float bottom = 0; + CaretAssertVectorIndex(heightValues, i); + float top = heightValues[i]; + + float rgba[4] = { 1.0, 0.5, 0.0, 1.0 }; + + uint8_t idRGBA[4]; + if (m_identificationModeFlag) { + addToHistogramIdentification(i, idRGBA); + } + + if (i == 0) { + /* + * Left side of first bar + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + else { + if (top > heightValues[i - 1]) { + /* + * Line from previous bar that is lower in + * height than this bar + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(heightValues[i - 1]); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + } + + /* + * Draw line across top + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + + if (i == lastValueIndex) { + /* + * Right side of last bar + */ + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + else { + if (top > heightValues[i + 1]) { + /* + * Line from bar down to next bar + * with a lower height + */ + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(heightValues[i + 1]); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + } + } + + /* + * Draw the line elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + m_fixedPipelineDrawing->setLineWidth(5); + glBegin(GL_LINES); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); + glColor4ubv(&quadVerticesByteRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + else { + m_fixedPipelineDrawing->setLineWidth(2); + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_LINES); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); + glColor4fv(&quadVerticesFloatRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + } + break; + } + + } + + if (m_identificationModeFlag) { + processHistogramIdentification(histogramChart); + } } @@ -584,24 +964,29 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float cellHeight, const float zooming) { - m_identificationModeFlag = false; - switch (m_fixedPipelineDrawing->mode) { - case BrainOpenGLFixedPipeline::MODE_DRAWING: - break; - case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: - if (m_selectionItemMatrix->isEnabledForSelection()) { - m_identificationModeFlag = true; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else { - return; - } - break; - case BrainOpenGLFixedPipeline::MODE_PROJECTION: - return; - break; + if (m_identificationModeFlag) { + resetIdentification(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +// m_identificationModeFlag = false; +// switch (m_fixedPipelineDrawing->mode) { +// case BrainOpenGLFixedPipeline::MODE_DRAWING: +// break; +// case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: +// if (m_selectionItemMatrix->isEnabledForSelection()) { +// m_identificationModeFlag = true; +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// else { +// return; +// } +// break; +// case BrainOpenGLFixedPipeline::MODE_PROJECTION: +// return; +// break; +// } + int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; @@ -1096,36 +1481,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::saveStateOfOpenGL() glDisable(GL_BLEND); } -/** - * Add an item for matrix identification. - * - * @param matrixRowIndex - * Index of the row - * @param matrixColumnIndex - * Index of the column - * @param rgbaForColorIdentificationOut - * Encoded identification in RGBA color OUTPUT - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::addToChartMatrixIdentification(const int32_t matrixRowIndex, - const int32_t matrixColumnIndex, - uint8_t rgbaForColorIdentificationOut[4]) -{ - const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; - - m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, - m_selectionItemDataType, - idIndex); - rgbaForColorIdentificationOut[3] = 255; - - /* - * If these items change, need to update reset and - * processing of identification. - */ - m_identificationIndices.push_back(matrixRowIndex); - m_identificationIndices.push_back(matrixColumnIndex); -} - /** * Restore the state of OpenGL. * Copied from Qt's qgl.cpp, qt_restore_gl_state(). @@ -1157,6 +1512,31 @@ BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() m_identificationIndices.reserve(estimatedNumberOfItems); } } +/** + * Add an item for matrix identification. + * + * @param barIndex + * Index of the histogram bar. + * @param rgbaForColorIdentificationOut + * Encoded identification in RGBA color OUTPUT + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::addToHistogramIdentification(const int barIndex, + uint8_t rgbaForColorIdentificationOut[4]) +{ + const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_HISTOGRAM; + + m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, + m_selectionItemDataType, + idIndex); + rgbaForColorIdentificationOut[3] = 255; + + /* + * If these items change, need to update reset and + * processing of identification. + */ + m_identificationIndices.push_back(barIndex); +} /** * Process identification for histogram. @@ -1167,7 +1547,24 @@ BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() void BrainOpenGLChartTwoDrawingFixedPipeline::processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart) { - + if (histogramChart != NULL) { + int32_t identifiedItemIndex; + float depth = -1.0; + m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + identifiedItemIndex, + depth); + if (identifiedItemIndex >= 0) { + const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_HISTOGRAM; + const int32_t barIndex = m_identificationIndices[idIndex]; + + if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(depth)) { + m_selectionItemHistogram->setHistogramChart(const_cast(histogramChart), + barIndex); + } + } + } } /** @@ -1281,6 +1678,36 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const C } +/** + * Add an item for matrix identification. + * + * @param matrixRowIndex + * Index of the row + * @param matrixColumnIndex + * Index of the column + * @param rgbaForColorIdentificationOut + * Encoded identification in RGBA color OUTPUT + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::addToChartMatrixIdentification(const int32_t matrixRowIndex, + const int32_t matrixColumnIndex, + uint8_t rgbaForColorIdentificationOut[4]) +{ + const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; + + m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, + m_selectionItemDataType, + idIndex); + rgbaForColorIdentificationOut[3] = 255; + + /* + * If these items change, need to update reset and + * processing of identification. + */ + m_identificationIndices.push_back(matrixRowIndex); + m_identificationIndices.push_back(matrixColumnIndex); +} + /** * Process identification for matrix. * @@ -1310,6 +1737,5 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processMatrixIdentification(const Chart } } } - } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 71caf1533..b59d0d5f3 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -28,6 +28,7 @@ namespace caret { class CaretPreferences; + class ChartTwoDataHistogram; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; @@ -89,15 +90,18 @@ namespace caret { void resetIdentification(); + void addToHistogramIdentification(const int barIndex, + uint8_t rgbaForColorIdentificationOut[4]); + void processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart); void processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart); - void processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart); - void addToChartMatrixIdentification(const int32_t matrixRowIndex, const int32_t matrixColumnIndex, - uint8_t rgbaForColorIdentification[4]); + uint8_t rgbaForColorIdentificationOut[4]); + void processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart); + void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, @@ -108,7 +112,8 @@ namespace caret { void drawHistogramChart(); - void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart); + void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex); // void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, // std::set& rowIndicesOut, @@ -146,6 +151,7 @@ namespace caret { bool m_identificationModeFlag; + static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 1; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index ba9f4f2fe..748f9171c 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -800,6 +800,22 @@ IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(Identif const SelectionItemChartTwoHistogram* idChartTwoHistogram) const { CaretAssertToDoWarning(); + if (idChartTwoHistogram->isValid()) { + const ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); + const int32_t barIndex = idChartTwoHistogram->getBarIndex(); + + const CaretMappableDataFile* mapFile = fileHistogramChart->getCaretMappableDataFile(); + CaretAssert(mapFile); + + AString boldText("Histogram"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + + idText.addLine(true, + "Bar Index", + (AString::number(barIndex))); + } } /** diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 0087756d7..94167bd7d 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -679,7 +679,7 @@ ModelChart::receiveEvent(Event* event) AString ModelChart::getNameForGUI(const bool /*includeStructureFlag*/) const { - AString name = "Chart"; + AString name = "ChartOld"; return name; } @@ -690,7 +690,7 @@ ModelChart::getNameForGUI(const bool /*includeStructureFlag*/) const AString ModelChart::getNameForBrowserTab() const { - AString name = "Chart"; + AString name = "ChartOld"; return name; } diff --git a/src/Brain/SelectionItemChartTwoHistogram.cxx b/src/Brain/SelectionItemChartTwoHistogram.cxx index 1a26665a4..b9a44c20f 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.cxx +++ b/src/Brain/SelectionItemChartTwoHistogram.cxx @@ -40,7 +40,8 @@ using namespace caret; SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_HISTOGRAM) { - + m_fileHistogramChart = NULL; + m_barIndex = -1; } /** @@ -86,7 +87,28 @@ SelectionItemChartTwoHistogram::operator=(const SelectionItemChartTwoHistogram& void SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) { - + m_fileHistogramChart = obj.m_fileHistogramChart; + m_barIndex = obj.m_barIndex; +} + +ChartableTwoFileHistogramChart* +SelectionItemChartTwoHistogram::getFileHistogramChart() const +{ + return m_fileHistogramChart; +} + +int32_t +SelectionItemChartTwoHistogram::getBarIndex() const +{ + return m_barIndex; +} + +void +SelectionItemChartTwoHistogram::setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, + const int32_t barIndex) +{ + m_fileHistogramChart = fileHistogramChart; + m_barIndex = barIndex; } /** @@ -95,6 +117,11 @@ SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const S bool SelectionItemChartTwoHistogram::isValid() const { + if ((m_fileHistogramChart != NULL) + && (m_barIndex >= 0)) { + return true; + } + return false; } @@ -104,6 +131,8 @@ SelectionItemChartTwoHistogram::isValid() const void SelectionItemChartTwoHistogram::reset() { + m_fileHistogramChart = NULL; + m_barIndex = -1; } diff --git a/src/Brain/SelectionItemChartTwoHistogram.h b/src/Brain/SelectionItemChartTwoHistogram.h index 284388e96..da8101225 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.h +++ b/src/Brain/SelectionItemChartTwoHistogram.h @@ -28,6 +28,8 @@ namespace caret { + class ChartableTwoFileHistogramChart; + class SelectionItemChartTwoHistogram : public SelectionItem { public: @@ -43,12 +45,22 @@ namespace caret { virtual void reset() override; + ChartableTwoFileHistogramChart* getFileHistogramChart() const; + + int32_t getBarIndex() const; + + void setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, + const int32_t barIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); + ChartableTwoFileHistogramChart* m_fileHistogramChart; + + int32_t m_barIndex; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index f6978bfcd..365238003 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -42,8 +42,10 @@ ChartTwoCompoundDataType.h ChartTwoData.h ChartTwoDataCartesian.h ChartTwoDataCartesianHistory.h +ChartTwoDataHistogram.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h +ChartTwoHistogramViewingTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixDisplayProperties.h @@ -77,8 +79,10 @@ ChartTwoCompoundDataType.cxx ChartTwoData.cxx ChartTwoDataCartesian.cxx ChartTwoDataCartesianHistory.cxx +ChartTwoDataHistogram.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx +ChartTwoHistogramViewingTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixDisplayProperties.cxx diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index e84a5b2e3..3fb943631 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -60,6 +60,19 @@ m_dataAxisUnitsX(dataAxisUnitsX), m_dataAxisUnitsY(dataAxisUnitsY) { initializeMembersChartTwoDataCartesian(); + + switch (getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + CaretAssert(0); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + CaretAssert(0); + break; + } } /** diff --git a/src/Charting/ChartTwoDataHistogram.cxx b/src/Charting/ChartTwoDataHistogram.cxx new file mode 100644 index 000000000..72b1d592c --- /dev/null +++ b/src/Charting/ChartTwoDataHistogram.cxx @@ -0,0 +1,329 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_DATA_HISTOGRAM_DECLARE__ +#include "ChartTwoDataHistogram.h" +#undef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ + +#include +#include + +#include + +#include "CaretAssert.h" +#include "ChartPoint.h" +#include "Histogram.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoDataHistogram + * \brief Chart histogram chart data. + * \ingroup Charting + */ + +/** + * Constructor. + */ +ChartTwoDataHistogram::ChartTwoDataHistogram() +: ChartTwoData(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM) +{ + initializeMembersChartTwoDataHistogram(); +} + +/** + * Destructor. + */ +ChartTwoDataHistogram::~ChartTwoDataHistogram() +{ + delete m_sceneAssistant; +} + +/** + * Initialize members of a new instance. + */ +void +ChartTwoDataHistogram::initializeMembersChartTwoDataHistogram() +{ + m_boundsValid = false; + m_histogram = NULL; + + m_histogramViewingType = ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS; + //m_histogramViewingType = ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE; + m_color = CaretColorEnum::RED; + + std::vector colorEnums; + CaretColorEnum::getColorEnums(colorEnums); + const int32_t numCaretColors = static_cast(colorEnums.size()); + + bool colorFound = false; + while ( ! colorFound) { + ChartTwoDataHistogram::caretColorIndex++; + if (ChartTwoDataHistogram::caretColorIndex >= numCaretColors) { + ChartTwoDataHistogram::caretColorIndex = 0; + } + + if (colorEnums[ChartTwoDataHistogram::caretColorIndex] == CaretColorEnum::BLACK) { + /* do not use black */ + } + else if (colorEnums[ChartTwoDataHistogram::caretColorIndex] == CaretColorEnum::WHITE) { + /* do not use white */ + } + else { + m_color = colorEnums[ChartTwoDataHistogram::caretColorIndex]; + colorFound = true; + } + } + + m_sceneAssistant = new SceneClassAssistant(); + + m_sceneAssistant->add("m_color", + &m_color); +} + +/** + * At times a copy of chart data will be needed BUT it must be + * the proper subclass so copy constructor and assignment operator + * will no function when this abstract, base class is used. Each + * subclass will override this method so that the returned class + * is of the proper type. + * + * @return Copy of this instance that is the actual subclass. + */ +ChartTwoData* +ChartTwoDataHistogram::clone() const +{ + ChartTwoDataHistogram* cloneCopy = new ChartTwoDataHistogram(*this); + return cloneCopy; +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoDataHistogram::ChartTwoDataHistogram(const ChartTwoDataHistogram& obj) +: ChartTwoData(obj) +{ + initializeMembersChartTwoDataHistogram(); + this->copyHelperChartTwoDataHistogram(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoDataHistogram& +ChartTwoDataHistogram::operator=(const ChartTwoDataHistogram& obj) +{ + if (this != &obj) { + ChartTwoData::operator=(obj); + this->copyHelperChartTwoDataHistogram(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoDataHistogram::copyHelperChartTwoDataHistogram(const ChartTwoDataHistogram& obj) +{ + CaretAssert(0); + m_color = obj.m_color; + //m_histogram = obj.m_histogram; +} + +/** + * @return The actual histogram (may be NULL). + */ +const Histogram* +ChartTwoDataHistogram::getHistogram() const +{ + return m_histogram; +} + +/** + * Set the histogram for charting. + * + * @param histogram + * Updated histogram (may be NULL). + */ +void +ChartTwoDataHistogram::setHistogram(Histogram* histogram) +{ + m_histogram = histogram; +} + +/** + * @return Reference to histogram values. Vector is empty + * if histogram is invalid. + */ +const std::vector& +ChartTwoDataHistogram::getHistogramValues() const +{ + if (m_histogram != NULL) { + return m_histogram->getHistogramDisplay(); + } + + return m_emptyData; +} + + +/** + * Get the bounds of all of the points. + * + * @param boundsOut + * On exit contains bounds (xmin, xmax, ymin, ymax). + * @return + * True if bounds valid, else false. + */ +bool +ChartTwoDataHistogram::getBounds(float boundsOut[4]) const +{ + if (! m_boundsValid) { + m_bounds[0] = 0.0; + m_bounds[1] = 0.0; + m_bounds[2] = 0.0; + m_bounds[3] = 0.0; + + if (m_histogram != NULL) { + const int32_t numBuckets = m_histogram->getNumberOfBuckets(); + if (numBuckets > 0) { + m_histogram->getRange(m_bounds[0], + m_bounds[1]); + + const std::vector& values = getHistogramValues(); + m_bounds[2] = 0.0; + if (values.empty()) { + m_bounds[3] = 0.0; + } + else { + m_bounds[3] = *std::max_element(values.begin(), + values.end()); + } + m_boundsValid = true; + } + } + } + + boundsOut[0] = m_bounds[0]; + boundsOut[1] = m_bounds[1]; + boundsOut[2] = m_bounds[2]; + boundsOut[3] = m_bounds[3]; + + return m_boundsValid; +} + +/** + * @return Color for chart + */ +CaretColorEnum::Enum +ChartTwoDataHistogram::getColor() const +{ + return m_color; +} + +/** + * Set the color for the chart. + * + * @param color + * New color for chart. + */ +void +ChartTwoDataHistogram::setColor(const CaretColorEnum::Enum color) +{ + m_color = color; +} + +ChartTwoHistogramViewingTypeEnum::Enum +ChartTwoDataHistogram::getHistogramViewingType() const +{ + return m_histogramViewingType; +} + +void +ChartTwoDataHistogram::setHistogramViewingType(const ChartTwoHistogramViewingTypeEnum::Enum histogramViewingType) +{ + m_histogramViewingType = histogramViewingType; +} + + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +ChartTwoDataHistogram::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + SceneClass* chartDataHistogram = new SceneClass("chartDataHistogram", + "ChartTwoDataHistogram", + 1); + + m_sceneAssistant->saveMembers(sceneAttributes, + chartDataHistogram); + + + sceneClass->addClass(chartDataHistogram); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +ChartTwoDataHistogram::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + const SceneClass* chartDataHistogram = sceneClass->getClass("chartDataCartesian"); + if (chartDataHistogram == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, chartDataHistogram); +} + diff --git a/src/Charting/ChartTwoDataHistogram.h b/src/Charting/ChartTwoDataHistogram.h new file mode 100644 index 000000000..99f124c97 --- /dev/null +++ b/src/Charting/ChartTwoDataHistogram.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_DATA_HISTOGRAM_H__ +#define __CHART_TWO_DATA_HISTOGRAM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretColorEnum.h" +#include "ChartAxisUnitsEnum.h" +#include "ChartTwoHistogramViewingTypeEnum.h" +#include "ChartTwoData.h" + +namespace caret { + + class ChartPoint; + class Histogram; + + class ChartTwoDataHistogram : public ChartTwoData { + + public: + ChartTwoDataHistogram(); + + virtual ~ChartTwoDataHistogram(); + + virtual ChartTwoData* clone() const; + + const std::vector& getHistogramValues() const; + + const Histogram* getHistogram() const; + + void setHistogram(Histogram* histogram); + + ChartTwoHistogramViewingTypeEnum::Enum getHistogramViewingType() const; + + void setHistogramViewingType(const ChartTwoHistogramViewingTypeEnum::Enum histogramViewingType); + + bool getBounds(float boundsOut[4]) const; + + CaretColorEnum::Enum getColor() const; + + void setColor(const CaretColorEnum::Enum color); + + // ADD_NEW_METHODS_HERE + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + private: + ChartTwoDataHistogram(const ChartTwoDataHistogram& obj); + + ChartTwoDataHistogram& operator=(const ChartTwoDataHistogram& obj); + + void copyHelperChartTwoDataHistogram(const ChartTwoDataHistogram& obj); + + void initializeMembersChartTwoDataHistogram(); + + Histogram* m_histogram; + + mutable float m_bounds[4]; + + mutable bool m_boundsValid; + + CaretColorEnum::Enum m_color; + + static int32_t caretColorIndex; + + ChartTwoHistogramViewingTypeEnum::Enum m_histogramViewingType; + + std::vector m_emptyData; + + SceneClassAssistant* m_sceneAssistant; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ + int32_t ChartTwoDataHistogram::caretColorIndex = 0; +#endif // __CHART_TWO_DATA_HISTOGRAM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_DATA_HISTOGRAM_H__ diff --git a/src/Charting/ChartTwoHistogramViewingTypeEnum.cxx b/src/Charting/ChartTwoHistogramViewingTypeEnum.cxx new file mode 100644 index 000000000..856ce7205 --- /dev/null +++ b/src/Charting/ChartTwoHistogramViewingTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ +#include "ChartTwoHistogramViewingTypeEnum.h" +#undef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoHistogramViewingTypeEnum + * \brief Type of histogram viewing by user. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoHistogramViewingTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoHistogramViewingTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoHistogramViewingTypeEnum.h" + * + * Instatiate: + * m_chartTwoHistogramViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoHistogramViewingTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoHistogramViewingTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoHistogramViewingTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoHistogramViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoHistogramViewingTypeEnum::Enum VARIABLE = m_chartTwoHistogramViewingTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoHistogramViewingTypeEnum::ChartTwoHistogramViewingTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoHistogramViewingTypeEnum::~ChartTwoHistogramViewingTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoHistogramViewingTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoHistogramViewingTypeEnum(HISTOGRAM_VIEWING_BARS, + "HISTOGRAM_VIEWING_BARS", + "Bars")); + + enumData.push_back(ChartTwoHistogramViewingTypeEnum(HISTOGRAM_VIEWING_ENVELOPE, + "HISTOGRAM_VIEWING_ENVELOPE", + "Envelope")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoHistogramViewingTypeEnum* +ChartTwoHistogramViewingTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoHistogramViewingTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoHistogramViewingTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoHistogramViewingTypeEnum::Enum +ChartTwoHistogramViewingTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramViewingTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoHistogramViewingTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoHistogramViewingTypeEnum::Enum +ChartTwoHistogramViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramViewingTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoHistogramViewingTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoHistogramViewingTypeEnum::Enum +ChartTwoHistogramViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoHistogramViewingTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoHistogramViewingTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoHistogramViewingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoHistogramViewingTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoHistogramViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoHistogramViewingTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoHistogramViewingTypeEnum.h b/src/Charting/ChartTwoHistogramViewingTypeEnum.h new file mode 100644 index 000000000..744c41491 --- /dev/null +++ b/src/Charting/ChartTwoHistogramViewingTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ +#define __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoHistogramViewingTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + HISTOGRAM_VIEWING_BARS, + /** */ + HISTOGRAM_VIEWING_ENVELOPE + }; + + + ~ChartTwoHistogramViewingTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoHistogramViewingTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoHistogramViewingTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ +std::vector ChartTwoHistogramViewingTypeEnum::enumData; +bool ChartTwoHistogramViewingTypeEnum::initializedFlag = false; +int32_t ChartTwoHistogramViewingTypeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index e751862d1..ec8c5de60 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -25,6 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" +#include "ChartTwoDataHistogram.h" #include "Histogram.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -78,6 +79,11 @@ m_histogramContentType(histogramContentType) */ ChartableTwoFileHistogramChart::~ChartableTwoFileHistogramChart() { + for (auto mapHistoPair : m_indexHistogramsMap) { + delete mapHistoPair.second; + } + m_indexHistogramsMap.clear(); + delete m_sceneAssistant; } @@ -109,6 +115,39 @@ ChartableTwoFileHistogramChart::isEmpty() const return false; } +/** + * Get the histogram chart for the given map index. + * + * @param mapIndex + * Index for the map. + * @return + * Histogram for the map with the given index. NULL if the file + * does not support a histogram. + */ +const ChartTwoDataHistogram* +ChartableTwoFileHistogramChart::getMapHistogramChart(const int32_t mapIndex) const +{ + ChartTwoDataHistogram* histogramChartOut = NULL; + + std::map::iterator iter = m_indexHistogramsMap.find(mapIndex); + if (iter != m_indexHistogramsMap.end()) { + histogramChartOut = iter->second; + } + else { + histogramChartOut = new ChartTwoDataHistogram(); + m_indexHistogramsMap.insert(std::make_pair(mapIndex, + histogramChartOut)); + } + + /* + * Update with histogram from the file even if it is NULL. + */ + CaretMappableDataFile* mapFile = const_cast(getCaretMappableDataFile()); + CaretAssert(mapFile); + histogramChartOut->setHistogram(const_cast(mapFile->getMapHistogram(mapIndex))); + + return histogramChartOut; +} /** * Save subclass data to the scene. diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index 299ebf36f..a530da756 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include "ChartableTwoFileBaseChart.h" #include "ChartTwoHistogramContentTypeEnum.h" @@ -28,6 +29,8 @@ namespace caret { + class ChartTwoDataHistogram; + class ChartableTwoFileHistogramChart : public ChartableTwoFileBaseChart { public: @@ -42,12 +45,9 @@ namespace caret { virtual bool isEmpty() const override; + const ChartTwoDataHistogram* getMapHistogramChart(const int32_t mapIndex) const; + // ADD_NEW_METHODS_HERE - - - - - protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, @@ -65,6 +65,8 @@ namespace caret { const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; + mutable std::map m_indexHistogramsMap; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index ba7ef6cad..ccdf08a20 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -884,10 +884,10 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() volumeModel); tabIndex = loadIntoTab(tabIndex, wholeBrainModel); - tabIndex = loadIntoTab(tabIndex, - chartModel); tabIndex = loadIntoTab(tabIndex, chartTwoModel); + tabIndex = loadIntoTab(tabIndex, + chartModel); tabIndex = loadIntoTab(tabIndex, leftSurfaceModel); tabIndex = loadIntoTab(tabIndex, -- GitLab From 2bd78c9572af5e70861423ef4e15af078d7ad06f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 3 Feb 2017 16:42:52 -0600 Subject: [PATCH 196/755] Continuing charting development. Created 'HistogramDrawingInfo' class that is intended for use by both drawing histograms in the graphics region and on the map settings dialog so that there will be consistent drawing and eliminates duplicate functionality. An early implementation is functioning for histograms in the graphics region. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1011 ++++++++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 9 + src/Common/CMakeLists.txt | 2 + src/Common/HistogramDrawingInfo.cxx | 161 +++ src/Common/HistogramDrawingInfo.h | 84 ++ src/Files/CaretMappableDataFile.cxx | 129 +++ src/Files/CaretMappableDataFile.h | 7 + 7 files changed, 1270 insertions(+), 133 deletions(-) create mode 100644 src/Common/HistogramDrawingInfo.cxx create mode 100644 src/Common/HistogramDrawingInfo.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 1c305bd5d..a3f73374c 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -38,9 +38,14 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" +#include "FastStatistics.h" +#include "HistogramDrawingInfo.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "ModelChartTwo.h" +#include "NodeAndVoxelColoring.h" +#include "PaletteColorMapping.h" +#include "PaletteFile.h" #include "SessionManager.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLineSeries.h" @@ -206,6 +211,280 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); } +///** +// * Draw histogram charts. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() +//{ +// const int32_t vpX = m_viewport[0]; +// const int32_t vpY = m_viewport[1]; +// const int32_t vpWidth = m_viewport[2]; +// const int32_t vpHeight = m_viewport[3]; +// +// int32_t chartGraphicsDrawingViewport[4] = { +// vpX, +// vpY, +// vpWidth, +// vpHeight +// }; +// +// +//// /* +//// * Margin is region around the chart in which +//// * the axes legends, values, and ticks are drawn. +//// */ +// const double marginSize = 30; +// Margins margins(marginSize); +//// +//// double width, height; +//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); +//// margins.m_left = std::max(margins.m_left, width); +//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); +//// margins.m_right = std::max(margins.m_right, width); +//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); +//// margins.m_top = std::max(margins.m_top, height); +//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); +//// margins.m_bottom = std::max(margins.m_bottom, height); +//// +//// if (margins.m_left > marginSize) margins.m_left += 10; +//// if (margins.m_right > marginSize) margins.m_right += 10; +//// +//// /* +//// * Ensure that there is sufficient space for the axes data display. +//// */ +//// if ((vpWidth > (marginSize * 3)) +//// && (vpHeight > (marginSize * 3))) { +//// +//// /* Draw legends and grids */ +//// drawChartAxis(vpX, +//// vpY, +//// vpWidth, +//// vpHeight, +//// margins, +//// textRenderer, +//// cartesianChart->getLeftAxis()); +//// +//// drawChartAxis(vpX, +//// vpY, +//// vpWidth, +//// vpHeight, +//// margins, +//// textRenderer, +//// cartesianChart->getRightAxis()); +//// +//// drawChartAxis(vpX, +//// vpY, +//// vpWidth, +//// vpHeight, +//// margins, +//// textRenderer, +//// cartesianChart->getBottomAxis()); +//// +//// drawChartAxis(vpX, +//// vpY, +//// vpWidth, +//// vpHeight, +//// margins, +//// textRenderer, +//// cartesianChart->getTopAxis()); +//// +//// +//// drawChartGraphicsBoxAndSetViewport(vpX, +//// vpY, +//// vpWidth, +//// vpHeight, +//// margins, +//// chartGraphicsDrawingViewport); +//// } +// +// +// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); +// CaretAssert(numberOfOverlays > 0); +// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); +// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); +// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); +// +// /* +// * Get extent of histogram data +// */ +// float xMin = 0.0; +// float xMax = 0.0; +// float yMin = 0.0; +// float yMax = 0.0; +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// int32_t mapIndex = 1; +// chartOverlay->getSelectionData(mapFile, +// mapIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// if (histogramChart->isValid()) { +// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); +// float bounds[4]; +// if (histogramData->getBounds(bounds)) { +// xMin = std::min(xMin, bounds[0]); +// xMax = std::max(xMax, bounds[1]); +// yMin = std::min(yMin, bounds[2]); +// yMax = std::max(yMax, bounds[3]); +// } +// } +// } +// +// /* +// * Bounds valid? +// */ +// if ((xMin >= xMax) +// || (yMin >= yMax)) { +// return; +// } +// +//// std::cout << "All bounds: " +//// << xMin << " " +//// << xMax << " " +//// << yMin << " " +//// << yMax << " " << std::endl; +// +// glViewport(chartGraphicsDrawingViewport[0], +// chartGraphicsDrawingViewport[1], +// chartGraphicsDrawingViewport[2], +// chartGraphicsDrawingViewport[3]); +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// glOrtho(xMin, xMax, +// yMin, yMax, +// -10.0, 10.0); +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool applyTransformationsFlag = true; +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = chartGraphicsDrawingViewport[2]; +// const float chartHeight = chartGraphicsDrawingViewport[3]; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// int32_t layerIndex = 0; +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// int32_t mapIndex = 1; +// chartOverlay->getSelectionData(mapFile, +// mapIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// if (histogramChart->isValid()) { +// drawHistogramChartContent(histogramChart, +// mapIndex); +// layerIndex++; +// } +// } +//} + +/* + * REMOVE THIS + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::colorHistogramWithPalette(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex, + std::vector& rgbaOut) +{ + CaretMappableDataFile* cmdf = const_cast(histogramChart->getCaretMappableDataFile()); + + FastStatistics* statistics = NULL; + switch (cmdf->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(cmdf->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(cmdf->getMapFastStatistics(mapIndex)); + break; + } + CaretAssert(statistics); + + PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); + CaretAssert(paletteColorMapping); + PaletteFile* paletteFile = m_brain->getPaletteFile(); + CaretAssert(paletteFile); + const Palette* palette = paletteFile->getPaletteByName(paletteColorMapping->getSelectedPaletteName()); + + const Histogram* histogram = cmdf->getMapHistogram(mapIndex); + CaretAssert(histogram); + + if ((paletteColorMapping != NULL) + && (statistics != NULL) + && (palette != NULL) + && (histogram != NULL)) { + + const std::vector& buckets = histogram->getHistogramDisplay(); + if ( ! buckets.empty()) { + rgbaOut.resize(buckets.size() * 4); + + const int32_t numDataValues = static_cast(buckets.size()); + std::vector data(numDataValues); + + const float minValue = statistics->getMin(); + const float maxValue = statistics->getMax(); + float step = 1.0; + if (numDataValues > 1) { + step = ((maxValue - minValue) + / static_cast(numDataValues)); + } + for (int64_t ix = 0; ix < numDataValues; ix++) { + const float value = (minValue + + (ix * step)); + CaretAssertVectorIndex(data, ix); + data[ix] = value; + } + + const float* dataValues = &data[0]; + float* dataRGBA = &rgbaOut[0]; + + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + dataValues, + dataValues, + numDataValues, + dataRGBA, + true); // ignore thresholding + } + } +} + /** * Draw histogram charts. */ @@ -225,73 +504,73 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() }; -// /* -// * Margin is region around the chart in which -// * the axes legends, values, and ticks are drawn. -// */ + // /* + // * Margin is region around the chart in which + // * the axes legends, values, and ticks are drawn. + // */ const double marginSize = 30; Margins margins(marginSize); -// -// double width, height; -// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); -// margins.m_left = std::max(margins.m_left, width); -// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); -// margins.m_right = std::max(margins.m_right, width); -// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); -// margins.m_top = std::max(margins.m_top, height); -// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); -// margins.m_bottom = std::max(margins.m_bottom, height); -// -// if (margins.m_left > marginSize) margins.m_left += 10; -// if (margins.m_right > marginSize) margins.m_right += 10; -// -// /* -// * Ensure that there is sufficient space for the axes data display. -// */ -// if ((vpWidth > (marginSize * 3)) -// && (vpHeight > (marginSize * 3))) { -// -// /* Draw legends and grids */ -// drawChartAxis(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// textRenderer, -// cartesianChart->getLeftAxis()); -// -// drawChartAxis(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// textRenderer, -// cartesianChart->getRightAxis()); -// -// drawChartAxis(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// textRenderer, -// cartesianChart->getBottomAxis()); -// -// drawChartAxis(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// textRenderer, -// cartesianChart->getTopAxis()); -// -// -// drawChartGraphicsBoxAndSetViewport(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// chartGraphicsDrawingViewport); -// } + // + // double width, height; + // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); + // margins.m_left = std::max(margins.m_left, width); + // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); + // margins.m_right = std::max(margins.m_right, width); + // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); + // margins.m_top = std::max(margins.m_top, height); + // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); + // margins.m_bottom = std::max(margins.m_bottom, height); + // + // if (margins.m_left > marginSize) margins.m_left += 10; + // if (margins.m_right > marginSize) margins.m_right += 10; + // + // /* + // * Ensure that there is sufficient space for the axes data display. + // */ + // if ((vpWidth > (marginSize * 3)) + // && (vpHeight > (marginSize * 3))) { + // + // /* Draw legends and grids */ + // drawChartAxis(vpX, + // vpY, + // vpWidth, + // vpHeight, + // margins, + // textRenderer, + // cartesianChart->getLeftAxis()); + // + // drawChartAxis(vpX, + // vpY, + // vpWidth, + // vpHeight, + // margins, + // textRenderer, + // cartesianChart->getRightAxis()); + // + // drawChartAxis(vpX, + // vpY, + // vpWidth, + // vpHeight, + // margins, + // textRenderer, + // cartesianChart->getBottomAxis()); + // + // drawChartAxis(vpX, + // vpY, + // vpWidth, + // vpHeight, + // margins, + // textRenderer, + // cartesianChart->getTopAxis()); + // + // + // drawChartGraphicsBoxAndSetViewport(vpX, + // vpY, + // vpWidth, + // vpHeight, + // margins, + // chartGraphicsDrawingViewport); + // } const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); @@ -300,8 +579,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + std::vector histogramDrawingInfoVector; + std::vector histogramChartVector; + std::vector mapIndexVector; /* - * Get extent of histogram data + * Get the histogram drawing information and overall extent */ float xMin = 0.0; float xMax = 0.0; @@ -323,92 +605,540 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + histogramChartVector.push_back(histogramChart); + mapIndexVector.push_back(mapIndex); + histogramDrawingInfoVector.push_back(new HistogramDrawingInfo()); + const int32_t histoIndex = static_cast(histogramDrawingInfoVector.size() - 1); + if (histogramChart->isValid()) { - const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); - float bounds[4]; - if (histogramData->getBounds(bounds)) { - xMin = std::min(xMin, bounds[0]); - xMax = std::max(xMax, bounds[1]); - yMin = std::min(yMin, bounds[2]); - yMax = std::max(yMax, bounds[3]); + AString errorMessage; + CaretAssertVectorIndex(histogramDrawingInfoVector, histoIndex); + if (mapFile->getMapHistogramDrawingInfo(mapIndex, + false, + *histogramDrawingInfoVector[histoIndex], + errorMessage)) { + float bounds[4]; + if (histogramDrawingInfoVector[histoIndex]->getBounds(bounds)) { + xMin = std::min(xMin, bounds[0]); + xMax = std::max(xMax, bounds[1]); + yMin = std::min(yMin, bounds[2]); + yMax = std::max(yMax, bounds[3]); + } + } + else { + CaretLogWarning(errorMessage + mapFile->getFileName()); } } } + CaretAssert(histogramDrawingInfoVector.size() == histogramChartVector.size()); + CaretAssert(histogramDrawingInfoVector.size() == mapIndexVector.size()); + + +// /* +// * Get extent of histogram data +// */ +// float xMin = 0.0; +// float xMax = 0.0; +// float yMin = 0.0; +// float yMax = 0.0; +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// int32_t mapIndex = 1; +// chartOverlay->getSelectionData(mapFile, +// mapIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// if (histogramChart->isValid()) { +// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); +// float bounds[4]; +// if (histogramData->getBounds(bounds)) { +// xMin = std::min(xMin, bounds[0]); +// xMax = std::max(xMax, bounds[1]); +// yMin = std::min(yMin, bounds[2]); +// yMax = std::max(yMax, bounds[3]); +// } +// } +// } /* - * Bounds valid? + * Bounds invalid? */ - if ((xMin >= xMax) - || (yMin >= yMax)) { - return; + if ((xMin < xMax) + || (yMin < yMax)) { + // std::cout << "All bounds: " + // << xMin << " " + // << xMax << " " + // << yMin << " " + // << yMax << " " << std::endl; + + glViewport(chartGraphicsDrawingViewport[0], + chartGraphicsDrawingViewport[1], + chartGraphicsDrawingViewport[2], + chartGraphicsDrawingViewport[3]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(xMin, xMax, + yMin, yMax, + -10.0, 10.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = true; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + const int32_t numToDraw = static_cast(histogramChartVector.size()); + for (int32_t i = 0; i < numToDraw; i++) { + CaretAssertVectorIndex(histogramChartVector, i); + CaretAssertVectorIndex(mapIndexVector, i); + CaretAssertVectorIndex(histogramDrawingInfoVector, i); + if (histogramDrawingInfoVector[i]->isValid()) { + drawHistogramChartContent(histogramChartVector[i], + mapIndexVector[i], + *histogramDrawingInfoVector[i]); + } + } } -// std::cout << "All bounds: " -// << xMin << " " -// << xMax << " " -// << yMin << " " -// << yMax << " " << std::endl; - - glViewport(chartGraphicsDrawingViewport[0], - chartGraphicsDrawingViewport[1], - chartGraphicsDrawingViewport[2], - chartGraphicsDrawingViewport[3]); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(xMin, xMax, - yMin, yMax, - -10.0, 10.0); + for (auto histDrawPtr : histogramDrawingInfoVector) { + delete histDrawPtr; + } + histogramDrawingInfoVector.clear(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); +// int32_t layerIndex = 0; +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// int32_t mapIndex = 1; +// chartOverlay->getSelectionData(mapFile, +// mapIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// if (histogramChart->isValid()) { +// drawHistogramChartContent(histogramChart, +// mapIndex); +// layerIndex++; +// } +// } +} + +/* + * Draw the given histogram chart. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex, + const HistogramDrawingInfo& histogramDrawingInfo) +{ +// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); +// CaretMappableDataFile* mapFile = const_cast(histogramChart->getCaretMappableDataFile()); +// CaretAssert(mapFile); +// +// HistogramDrawingInfo histogramDrawingInfo; +// AString errorMessage; +// if ( ! mapFile->getMapHistogramDrawingInfo(mapIndex, +// false, +// histogramDrawingInfo, +// errorMessage)) { +// CaretLogWarning(errorMessage + mapFile->getFileName()); +// return; +// } - bool applyTransformationsFlag = true; - if (applyTransformationsFlag) { - glTranslatef(m_translation[0], - m_translation[1], - 0.0); - - const float chartWidth = chartGraphicsDrawingViewport[2]; - const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; - glTranslatef(halfWidth, - halfHeight, - 0.0); - glScalef(m_zooming, - m_zooming, - 1.0); - glTranslatef(-halfWidth, - -halfHeight, - 0.0); + const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); + + if ( ! histogramDrawingInfo.isValid()) { + return; + } + float bounds[4]; + if ( ! histogramDrawingInfo.getBounds(bounds)) { + return; + } + if (m_identificationModeFlag) { + resetIdentification(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - int32_t layerIndex = 0; - for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); - if ( ! chartOverlay->isEnabled()) { - continue; + // m_identificationModeFlag = false; + // switch (m_fixedPipelineDrawing->mode) { + // case BrainOpenGLFixedPipeline::MODE_DRAWING: + // break; + // case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: + // if (m_selectionItemMatrix->isEnabledForSelection()) { + // m_identificationModeFlag = true; + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // } + // else { + // return; + // } + // break; + // case BrainOpenGLFixedPipeline::MODE_PROJECTION: + // return; + // break; + // } + + + glColor3f(1.0, 0.0, 0.0); + glBegin(GL_LINES); + glVertex3f(bounds[0], bounds[2], 0.0); + glVertex3f(bounds[1], bounds[3], 0.0); + glEnd(); + + const std::vector& xValues = histogramDrawingInfo.getDataX(); + const std::vector& yValues = histogramDrawingInfo.getDataY(); + const std::vector& rgbaValues = histogramDrawingInfo.getDataRGBA(); + CaretAssert(xValues.size() == yValues.size()); + CaretAssert((xValues.size() * 4) == rgbaValues.size()); + + const int32_t numValues = static_cast(xValues.size() - 1); + if (numValues > 1) { + if ( ! m_identificationModeFlag) { + bool solidColorFlag = false; + if (solidColorFlag) { + + } } + std::vector quadVerticesXYZ; + std::vector quadVerticesFloatRGBA; + std::vector quadVerticesByteRGBA; - CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = 1; - chartOverlay->getSelectionData(mapFile, - mapIndex); - if (mapFile == NULL) { - continue; + switch (histogramData->getHistogramViewingType()) { + case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS: + { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 4; + const int32_t totalVertices = verticesPerBar * numValues; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.; + + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i+1]; + float bottom = 0; + CaretAssertVectorIndex(yValues, i); + float top = yValues[i]; + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + + if (m_identificationModeFlag) { + uint8_t idRGBA[4]; + addToHistogramIdentification(i, idRGBA); + + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + } + else { + CaretAssertVectorIndex(rgbaValues, i*4 + 3); + const float* rgba = &rgbaValues[i * 4]; + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + + } + + /* + * Draw the bar elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); + glColor4ubv(&quadVerticesByteRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + else { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_QUADS); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); + glColor4fv(&quadVerticesFloatRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + } + break; + case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE: + { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 2; + const int32_t totalVertices = verticesPerBar * numValues + 4; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.0; + + const int32_t lastValueIndex = numValues - 1; + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i + 1]; + float bottom = 0; + CaretAssertVectorIndex(yValues, i); + float top = yValues[i]; + + CaretAssertVectorIndex(rgbaValues, i*4 + 3); + const float* rgba = &rgbaValues[i * 4]; + + uint8_t idRGBA[4]; + if (m_identificationModeFlag) { + addToHistogramIdentification(i, idRGBA); + } + + if (i == 0) { + /* + * Left side of first bar + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + else { + if (top > yValues[i - 1]) { + /* + * Line from previous bar that is lower in + * height than this bar + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(yValues[i - 1]); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + } + + /* + * Draw line across top + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + + if (i == lastValueIndex) { + /* + * Right side of last bar + */ + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + else { + if (top > yValues[i + 1]) { + /* + * Line from bar down to next bar + * with a lower height + */ + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(yValues[i + 1]); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } + } + } + } + + /* + * Draw the line elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + m_fixedPipelineDrawing->setLineWidth(5); + glBegin(GL_LINES); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); + glColor4ubv(&quadVerticesByteRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + else { + m_fixedPipelineDrawing->setLineWidth(2); + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); + glBegin(GL_LINES); + for (int32_t i = 0; i < numberQuadVertices; i++) { + CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); + glColor4fv(&quadVerticesFloatRGBA[i*4]); + CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); + glVertex3fv(&quadVerticesXYZ[i*3]); + } + glEnd(); + } + } + break; } - const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); - const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); - if (histogramChart->isValid()) { - drawHistogramChartContent(histogramChart, - mapIndex); - layerIndex++; - } + } + + if (m_identificationModeFlag) { + processHistogramIdentification(histogramChart); } } + /* * Draw the given histogram chart. */ @@ -455,6 +1185,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const std::vector heightValues = histogramData->getHistogramValues(); const int32_t numValues = static_cast(heightValues.size()); if (numValues > 1) { + std::vector dataColoringVectorRGBA; + if ( ! m_identificationModeFlag) { + bool solidColorFlag = false; + if (solidColorFlag) { + + } + else { + colorHistogramWithPalette(histogramChart, + mapIndex, + dataColoringVectorRGBA); + const size_t rgbaSize = numValues * 4; + CaretAssert(dataColoringVectorRGBA.size() == rgbaSize); + } + } std::vector quadVerticesXYZ; std::vector quadVerticesFloatRGBA; std::vector quadVerticesByteRGBA; @@ -504,13 +1248,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } } else { - float rgba[4] = { 1.0, 0.5, 0.0, 1.0 }; + CaretAssertVectorIndex(dataColoringVectorRGBA, i*4 + 3); + const float* rgba = &dataColoringVectorRGBA[i * 4]; for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), rgba, rgba + 4); } } - + } /* diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index b59d0d5f3..f3a4d8d0d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -32,6 +32,7 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; + class HistogramDrawingInfo; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; @@ -115,6 +116,14 @@ namespace caret { void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, const int32_t mapIndex); + void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex, + const HistogramDrawingInfo& histogramDrawingInfo); + + void colorHistogramWithPalette(const ChartableTwoFileHistogramChart* histogramChart, + const int32_t mapIndex, + std::vector& rgbaOut); + // void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, // std::set& rowIndicesOut, // std::set& columnIndicesOut) const; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index e8e776642..e97045e39 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -111,6 +111,7 @@ FileAdapter.h FileInformation.h FloatMatrix.h Histogram.h +HistogramDrawingInfo.h HtmlStringBuilder.h ImageCaptureMethodEnum.h Logger.h @@ -208,6 +209,7 @@ FileAdapter.cxx FileInformation.cxx FloatMatrix.cxx Histogram.cxx +HistogramDrawingInfo.cxx HtmlStringBuilder.cxx ImageCaptureMethodEnum.cxx Logger.cxx diff --git a/src/Common/HistogramDrawingInfo.cxx b/src/Common/HistogramDrawingInfo.cxx new file mode 100644 index 000000000..3904bbcaa --- /dev/null +++ b/src/Common/HistogramDrawingInfo.cxx @@ -0,0 +1,161 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __HISTOGRAM_DRAWING_INFO_DECLARE__ +#include "HistogramDrawingInfo.h" +#undef __HISTOGRAM_DRAWING_INFO_DECLARE__ + +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::HistogramDrawingInfo + * \brief Contains data and metadata for drawing a histogram + * \ingroup Common + */ + +/** + * Constructor creates invalid instance. + */ +HistogramDrawingInfo::HistogramDrawingInfo() +: CaretObject() +{ +} + +/** + * Destructor. + */ +HistogramDrawingInfo::~HistogramDrawingInfo() +{ +} + +/** + * Initialize for the given number of data points. + * + * @param numberOfDataPoints + * Number of data points for the histogram. + */ +void +HistogramDrawingInfo::initialize(const int32_t numberOfDataPoints) +{ + CaretAssert(numberOfDataPoints > 0); + m_dataX.resize(numberOfDataPoints, 0.0); + m_dataY.resize(numberOfDataPoints, 0.0); + m_dataRGBA.resize(numberOfDataPoints * 4, 0.0); + +} + +/** + * Reset the histogram drawing information. + */ +void +HistogramDrawingInfo::reset() +{ + m_dataX.clear(); + m_dataY.clear(); + m_dataRGBA.clear(); + m_boundsValid = false; +} + + +/** + * @return Is the histogram drawing information valid? + */ +bool +HistogramDrawingInfo::isValid() const +{ + if ( ! m_dataX.empty()) { + CaretAssert(m_dataX.size() == m_dataY.size()); + CaretAssert((m_dataX.size() * 4) == m_dataRGBA.size()); + if ((m_dataX.size() == m_dataY.size()) + && (m_dataX.size() * 4) == m_dataRGBA.size()) { + return true; + } + } + + return false; +} + +/** + * Get the bounds for the data. + * + * @param boundsOut + * Output with bounds (minX, maxX, minY, maxY) + * @return + * True if bounds valid, else false. + */ +bool +HistogramDrawingInfo::getBounds(float boundsOut[4]) const +{ + + if ( ! m_boundsValid) { + if (isValid()) { + m_bounds[0] = *std::min_element(m_dataX.begin(), m_dataX.end()); + m_bounds[1] = *std::max_element(m_dataX.begin(), m_dataX.end()); + m_bounds[2] = *std::min_element(m_dataY.begin(), m_dataY.end()); + m_bounds[3] = *std::max_element(m_dataY.begin(), m_dataY.end()); + m_boundsValid = true; + } + } + + if (m_boundsValid) { + boundsOut[0] = m_bounds[0]; + boundsOut[1] = m_bounds[1]; + boundsOut[2] = m_bounds[2]; + boundsOut[3] = m_bounds[3]; + } + else { + boundsOut[0] = 0.0; + boundsOut[1] = 0.0; + boundsOut[2] = 0.0; + boundsOut[3] = 0.0; + } + + return m_boundsValid; +} + +/** + * @return Number of data points in the histogram. + */ +int32_t +HistogramDrawingInfo::getNumberOfDataPoints() const +{ + CaretAssert(m_dataX.size() == m_dataY.size()); + CaretAssert((m_dataX.size() * 4) == m_dataRGBA.size()); + + return m_dataX.size(); +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +HistogramDrawingInfo::toString() const +{ + return "HistogramDrawingInfo"; +} + diff --git a/src/Common/HistogramDrawingInfo.h b/src/Common/HistogramDrawingInfo.h new file mode 100644 index 000000000..5b139f313 --- /dev/null +++ b/src/Common/HistogramDrawingInfo.h @@ -0,0 +1,84 @@ +#ifndef __HISTOGRAM_DRAWING_INFO_H__ +#define __HISTOGRAM_DRAWING_INFO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + + + +namespace caret { + + class HistogramDrawingInfo : public CaretObject { + + public: + HistogramDrawingInfo(); + + virtual ~HistogramDrawingInfo(); + + void initialize(const int32_t numberOfDataPoints); + + void reset(); + + bool getBounds(float boundsOut[4]) const; + + int32_t getNumberOfDataPoints() const; + + bool isValid() const; + + const std::vector& getDataX() const { return m_dataX; } + + const std::vector& getDataY() const { return m_dataY; } + + const std::vector& getDataRGBA() const { return m_dataRGBA; } + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + HistogramDrawingInfo(const HistogramDrawingInfo& obj); + + HistogramDrawingInfo& operator=(const HistogramDrawingInfo&); + + + mutable float m_bounds[4]; + + mutable bool m_boundsValid = false; + + std::vector m_dataX; + + std::vector m_dataY; + + std::vector m_dataRGBA; + + // ADD_NEW_MEMBERS_HERE + + friend class CaretMappableDataFile; + }; + +#ifdef __HISTOGRAM_DRAWING_INFO_DECLARE__ + // +#endif // __HISTOGRAM_DRAWING_INFO_DECLARE__ + +} // namespace +#endif //__HISTOGRAM_DRAWING_INFO_H__ diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 0499edd43..3488ff85d 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -31,12 +31,16 @@ #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" +#include "EventManager.h" +#include "EventPaletteGetByName.h" #include "FastStatistics.h" #include "FileInformation.h" #include "GiftiLabelTable.h" #include "GiftiMetaDataXmlElements.h" #include "Histogram.h" +#include "HistogramDrawingInfo.h" #include "LabelDrawingProperties.h" +#include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassArray.h" @@ -795,6 +799,131 @@ CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformatio } } +/** + * Get the histogram bounds, heights, and RGBA coloring. + * + * @param mapIndex + * Index of map. + * @param addEndPointForQwtFlag + * If true, add point at end for drawing with Qwt. + * @param histogramDrawingInfoOut + * Output containing histogram drawing information. + * @return + * True if output data is valid, else false. + */ +bool +CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, + const bool addEndPointForQwtFlag, + HistogramDrawingInfo& histogramDrawingInfoOut, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + histogramDrawingInfoOut.reset(); + + if ( ! isMappedWithPalette()) { + errorMessageOut = "File is not mapped with palette!"; + return false; + } + if ((mapIndex < 0) + || (mapIndex >= getNumberOfMaps())) { + CaretAssertMessage(0, "Invalid map index."); + errorMessageOut = "Invalid map index."; + return false; + } + + PaletteColorMapping* paletteColorMapping = getMapPaletteColorMapping(mapIndex); + CaretAssert(paletteColorMapping); + + EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); + EventManager::get()->sendEvent(paletteEvent.getPointer()); + const Palette* palette = paletteEvent.getPalette(); + if (palette == NULL) { + errorMessageOut = ("Unable to find palette named: " + + paletteColorMapping->getSelectedPaletteName()); + return false; + } + + const Histogram* histogram = getMapHistogram(mapIndex); + CaretAssert(histogram); + + FastStatistics* statistics = NULL; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(getMapFastStatistics(mapIndex)); + break; + } + CaretAssert(statistics); + + float minValue = 0.0; + float maxValue = 0.0; + histogram->getRange(minValue, + maxValue); + const float valueRange = maxValue - minValue; + if (valueRange <= 0.0) { + errorMessageOut = "Range of histogram values is zero"; + return false; + } + + if ((paletteColorMapping != NULL) + && (statistics != NULL) + && (palette != NULL) + && (histogram != NULL)) { + std::vector histogramBuckets = histogram->getHistogramDisplay(); + const int32_t numBucketValues = static_cast(histogramBuckets.size()); + if (numBucketValues < 2) { + errorMessageOut = "Histogram must contain two or more values"; + return false; + } + + const int32_t numberOfDataPoints = (addEndPointForQwtFlag + ? (numBucketValues + 1) + : numBucketValues); + + histogramDrawingInfoOut.initialize(numberOfDataPoints); + + if (addEndPointForQwtFlag) { + /* + * Duplicate last point for Qwt or else Qwt may not draw correctly + */ + histogramBuckets.push_back(histogramBuckets[histogramBuckets.size() - 1]); + } + histogramDrawingInfoOut.m_dataY = histogramBuckets; + + const float step = ((valueRange) + / static_cast(numberOfDataPoints)); + + for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { + const float value = (minValue + + (ix * step)); + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); + histogramDrawingInfoOut.m_dataX[ix] = value; + } + histogramDrawingInfoOut.m_dataX[0] = minValue; + histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValue; + + const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; + float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; + + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + xValuesArray, + xValuesArray, + numberOfDataPoints, + dataRGBA, + true); // ignore thresholding + + CaretAssert(histogramDrawingInfoOut.isValid()); + return histogramDrawingInfoOut.isValid(); + } + + return false; +} + + /** * @return True if any of the maps in this file contain a * color mapping that possesses a modified status. diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 0671bf2b5..baa8f76ab 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -38,6 +38,7 @@ namespace caret { class GiftiMetaData; class GiftiLabelTable; class Histogram; + class HistogramDrawingInfo; class LabelDrawingProperties; class PaletteColorMapping; class PaletteFile; @@ -271,6 +272,12 @@ namespace caret { * not mapped using a palette). */ virtual const FastStatistics* getFileFastStatistics() = 0; + + bool getMapHistogramDrawingInfo(const int32_t mapIndex, + const bool addEndPointForQwtFlag, + HistogramDrawingInfo& histogramDrawingInfoOut, + AString& errorMessageOut); + /** * Get histogram describing the distribution of data * mapped with a color palette for all data within -- GitLab From 2573e83925c370a5ca74dac0edac29c7c5695aaf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Feb 2017 09:28:48 -0600 Subject: [PATCH 197/755] Continuing charting development. Histogram is drawing in graphics region and matches histogram in map settings dialog. Added 'All/Match Palette' into palette color mapping. On dialog, 'Colorize' was replaced with a combo box for choosing a standard color or to use palette coloring for drawing histogram in both dialog and graphics region. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1249 ++++------------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 11 - src/Brain/BrainOpenGLPrimitiveDrawing.cxx | 143 ++ src/Brain/BrainOpenGLPrimitiveDrawing.h | 14 +- src/Brain/IdentificationTextGenerator.cxx | 5 +- src/Files/CaretMappableDataFile.cxx | 213 ++- src/Files/ChartableTwoFileMatrixChart.cxx | 59 +- src/Files/ChartableTwoFileMatrixChart.h | 2 +- src/GuiQt/CaretColorEnumComboBox.cxx | 101 +- src/GuiQt/CaretColorEnumComboBox.h | 6 + .../MapSettingsPaletteColorMappingWidget.cxx | 140 +- .../MapSettingsPaletteColorMappingWidget.h | 6 +- src/Palette/CMakeLists.txt | 2 + src/Palette/PaletteColorMapping.cxx | 61 +- src/Palette/PaletteColorMapping.h | 14 + src/Palette/PaletteColorMappingSaxReader.cxx | 24 + src/Palette/PaletteColorMappingXmlElements.h | 2 + src/Palette/PaletteHistogramRangeModeEnum.cxx | 373 +++++ src/Palette/PaletteHistogramRangeModeEnum.h | 104 ++ 19 files changed, 1390 insertions(+), 1139 deletions(-) create mode 100644 src/Palette/PaletteHistogramRangeModeEnum.cxx create mode 100644 src/Palette/PaletteHistogramRangeModeEnum.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index a3f73374c..12469a26a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -25,6 +25,7 @@ #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" +#include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -211,280 +212,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); } -///** -// * Draw histogram charts. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() -//{ -// const int32_t vpX = m_viewport[0]; -// const int32_t vpY = m_viewport[1]; -// const int32_t vpWidth = m_viewport[2]; -// const int32_t vpHeight = m_viewport[3]; -// -// int32_t chartGraphicsDrawingViewport[4] = { -// vpX, -// vpY, -// vpWidth, -// vpHeight -// }; -// -// -//// /* -//// * Margin is region around the chart in which -//// * the axes legends, values, and ticks are drawn. -//// */ -// const double marginSize = 30; -// Margins margins(marginSize); -//// -//// double width, height; -//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); -//// margins.m_left = std::max(margins.m_left, width); -//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); -//// margins.m_right = std::max(margins.m_right, width); -//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); -//// margins.m_top = std::max(margins.m_top, height); -//// estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); -//// margins.m_bottom = std::max(margins.m_bottom, height); -//// -//// if (margins.m_left > marginSize) margins.m_left += 10; -//// if (margins.m_right > marginSize) margins.m_right += 10; -//// -//// /* -//// * Ensure that there is sufficient space for the axes data display. -//// */ -//// if ((vpWidth > (marginSize * 3)) -//// && (vpHeight > (marginSize * 3))) { -//// -//// /* Draw legends and grids */ -//// drawChartAxis(vpX, -//// vpY, -//// vpWidth, -//// vpHeight, -//// margins, -//// textRenderer, -//// cartesianChart->getLeftAxis()); -//// -//// drawChartAxis(vpX, -//// vpY, -//// vpWidth, -//// vpHeight, -//// margins, -//// textRenderer, -//// cartesianChart->getRightAxis()); -//// -//// drawChartAxis(vpX, -//// vpY, -//// vpWidth, -//// vpHeight, -//// margins, -//// textRenderer, -//// cartesianChart->getBottomAxis()); -//// -//// drawChartAxis(vpX, -//// vpY, -//// vpWidth, -//// vpHeight, -//// margins, -//// textRenderer, -//// cartesianChart->getTopAxis()); -//// -//// -//// drawChartGraphicsBoxAndSetViewport(vpX, -//// vpY, -//// vpWidth, -//// vpHeight, -//// margins, -//// chartGraphicsDrawingViewport); -//// } -// -// -// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); -// CaretAssert(numberOfOverlays > 0); -// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); -// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); -// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); -// -// /* -// * Get extent of histogram data -// */ -// float xMin = 0.0; -// float xMax = 0.0; -// float yMin = 0.0; -// float yMax = 0.0; -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// int32_t mapIndex = 1; -// chartOverlay->getSelectionData(mapFile, -// mapIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// if (histogramChart->isValid()) { -// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); -// float bounds[4]; -// if (histogramData->getBounds(bounds)) { -// xMin = std::min(xMin, bounds[0]); -// xMax = std::max(xMax, bounds[1]); -// yMin = std::min(yMin, bounds[2]); -// yMax = std::max(yMax, bounds[3]); -// } -// } -// } -// -// /* -// * Bounds valid? -// */ -// if ((xMin >= xMax) -// || (yMin >= yMax)) { -// return; -// } -// -//// std::cout << "All bounds: " -//// << xMin << " " -//// << xMax << " " -//// << yMin << " " -//// << yMax << " " << std::endl; -// -// glViewport(chartGraphicsDrawingViewport[0], -// chartGraphicsDrawingViewport[1], -// chartGraphicsDrawingViewport[2], -// chartGraphicsDrawingViewport[3]); -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// glOrtho(xMin, xMax, -// yMin, yMax, -// -10.0, 10.0); -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool applyTransformationsFlag = true; -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = chartGraphicsDrawingViewport[2]; -// const float chartHeight = chartGraphicsDrawingViewport[3]; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// int32_t layerIndex = 0; -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// int32_t mapIndex = 1; -// chartOverlay->getSelectionData(mapFile, -// mapIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// if (histogramChart->isValid()) { -// drawHistogramChartContent(histogramChart, -// mapIndex); -// layerIndex++; -// } -// } -//} - -/* - * REMOVE THIS - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::colorHistogramWithPalette(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex, - std::vector& rgbaOut) -{ - CaretMappableDataFile* cmdf = const_cast(histogramChart->getCaretMappableDataFile()); - - FastStatistics* statistics = NULL; - switch (cmdf->getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(cmdf->getFileFastStatistics()); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(cmdf->getMapFastStatistics(mapIndex)); - break; - } - CaretAssert(statistics); - - PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); - CaretAssert(paletteColorMapping); - PaletteFile* paletteFile = m_brain->getPaletteFile(); - CaretAssert(paletteFile); - const Palette* palette = paletteFile->getPaletteByName(paletteColorMapping->getSelectedPaletteName()); - - const Histogram* histogram = cmdf->getMapHistogram(mapIndex); - CaretAssert(histogram); - - if ((paletteColorMapping != NULL) - && (statistics != NULL) - && (palette != NULL) - && (histogram != NULL)) { - - const std::vector& buckets = histogram->getHistogramDisplay(); - if ( ! buckets.empty()) { - rgbaOut.resize(buckets.size() * 4); - - const int32_t numDataValues = static_cast(buckets.size()); - std::vector data(numDataValues); - - const float minValue = statistics->getMin(); - const float maxValue = statistics->getMax(); - float step = 1.0; - if (numDataValues > 1) { - step = ((maxValue - minValue) - / static_cast(numDataValues)); - } - for (int64_t ix = 0; ix < numDataValues; ix++) { - const float value = (minValue - + (ix * step)); - CaretAssertVectorIndex(data, ix); - data[ix] = value; - } - - const float* dataValues = &data[0]; - float* dataRGBA = &rgbaOut[0]; - - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - dataValues, - dataValues, - numDataValues, - dataRGBA, - true); // ignore thresholding - } - } -} - /** * Draw histogram charts. */ @@ -633,42 +360,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() CaretAssert(histogramDrawingInfoVector.size() == histogramChartVector.size()); CaretAssert(histogramDrawingInfoVector.size() == mapIndexVector.size()); - -// /* -// * Get extent of histogram data -// */ -// float xMin = 0.0; -// float xMax = 0.0; -// float yMin = 0.0; -// float yMax = 0.0; -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// int32_t mapIndex = 1; -// chartOverlay->getSelectionData(mapFile, -// mapIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// if (histogramChart->isValid()) { -// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); -// float bounds[4]; -// if (histogramData->getBounds(bounds)) { -// xMin = std::min(xMin, bounds[0]); -// xMax = std::max(xMax, bounds[1]); -// yMin = std::min(yMin, bounds[2]); -// yMax = std::max(yMax, bounds[3]); -// } -// } -// } - /* * Bounds invalid? */ @@ -733,30 +424,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() delete histDrawPtr; } histogramDrawingInfoVector.clear(); - -// int32_t layerIndex = 0; -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// int32_t mapIndex = 1; -// chartOverlay->getSelectionData(mapFile, -// mapIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// if (histogramChart->isValid()) { -// drawHistogramChartContent(histogramChart, -// mapIndex); -// layerIndex++; -// } -// } } /* @@ -767,20 +434,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const int32_t mapIndex, const HistogramDrawingInfo& histogramDrawingInfo) { -// const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); -// CaretMappableDataFile* mapFile = const_cast(histogramChart->getCaretMappableDataFile()); -// CaretAssert(mapFile); -// -// HistogramDrawingInfo histogramDrawingInfo; -// AString errorMessage; -// if ( ! mapFile->getMapHistogramDrawingInfo(mapIndex, -// false, -// histogramDrawingInfo, -// errorMessage)) { -// CaretLogWarning(errorMessage + mapFile->getFileName()); -// return; -// } - const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); if ( ! histogramDrawingInfo.isValid()) { @@ -795,31 +448,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - // m_identificationModeFlag = false; - // switch (m_fixedPipelineDrawing->mode) { - // case BrainOpenGLFixedPipeline::MODE_DRAWING: - // break; - // case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: - // if (m_selectionItemMatrix->isEnabledForSelection()) { - // m_identificationModeFlag = true; - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // } - // else { - // return; - // } - // break; - // case BrainOpenGLFixedPipeline::MODE_PROJECTION: - // return; - // break; - // } - - - glColor3f(1.0, 0.0, 0.0); - glBegin(GL_LINES); - glVertex3f(bounds[0], bounds[2], 0.0); - glVertex3f(bounds[1], bounds[3], 0.0); - glEnd(); - const std::vector& xValues = histogramDrawingInfo.getDataX(); const std::vector& yValues = histogramDrawingInfo.getDataY(); const std::vector& rgbaValues = histogramDrawingInfo.getDataRGBA(); @@ -828,12 +456,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const int32_t numValues = static_cast(xValues.size() - 1); if (numValues > 1) { - if ( ! m_identificationModeFlag) { - bool solidColorFlag = false; - if (solidColorFlag) { - - } - } std::vector quadVerticesXYZ; std::vector quadVerticesFloatRGBA; std::vector quadVerticesByteRGBA; @@ -848,78 +470,94 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const int32_t verticesPerBar = 4; const int32_t totalVertices = verticesPerBar * numValues; quadVerticesXYZ.reserve(totalVertices * 3); + std::vector quadVerticesNormals; + quadVerticesNormals.reserve(totalVertices * 3); quadVerticesFloatRGBA.reserve(totalVertices * 4); quadVerticesByteRGBA.reserve(totalVertices * 4); + const float normalVector[3] = { 0.0, 0.0, 1.0 }; const float z = 0.; for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i+1]; - float bottom = 0; - CaretAssertVectorIndex(yValues, i); - float top = yValues[i]; - - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - - if (m_identificationModeFlag) { - uint8_t idRGBA[4]; - addToHistogramIdentification(i, idRGBA); + CaretAssertVectorIndex(rgbaValues, i*4 + 3); + const float* rgba = &rgbaValues[i * 4]; + if (rgba[3] > 0.0) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i+1]; + float bottom = 0; + CaretAssertVectorIndex(yValues, i); + float top = yValues[i]; - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + + for (int32_t iNormal = 0; iNormal < verticesPerBar; iNormal++) { + quadVerticesNormals.insert(quadVerticesNormals.end(), + normalVector, normalVector + 3); } - } - else { - CaretAssertVectorIndex(rgbaValues, i*4 + 3); - const float* rgba = &rgbaValues[i * 4]; - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + + if (m_identificationModeFlag) { + uint8_t idRGBA[4]; + addToHistogramIdentification(i, idRGBA); + + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + } + else { + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); + } } } - } /* * Draw the bar elements. */ + CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); if (m_identificationModeFlag) { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); - glColor4ubv(&quadVerticesByteRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesByteRGBA); +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// glBegin(GL_QUADS); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); +// glColor4ubv(&quadVerticesByteRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } else { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); - glColor4fv(&quadVerticesFloatRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesFloatRGBA); +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// glBegin(GL_QUADS); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); +// glColor4fv(&quadVerticesFloatRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } } break; @@ -1103,391 +741,40 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab */ if (m_identificationModeFlag) { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - m_fixedPipelineDrawing->setLineWidth(5); - glBegin(GL_LINES); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); - glColor4ubv(&quadVerticesByteRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); - } - else { - m_fixedPipelineDrawing->setLineWidth(2); - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_LINES); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); - glColor4fv(&quadVerticesFloatRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); - } - } - break; - } - - } - - if (m_identificationModeFlag) { - processHistogramIdentification(histogramChart); - } -} - - -/* - * Draw the given histogram chart. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex) -{ - const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); - - if (m_identificationModeFlag) { - resetIdentification(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - -// m_identificationModeFlag = false; -// switch (m_fixedPipelineDrawing->mode) { -// case BrainOpenGLFixedPipeline::MODE_DRAWING: -// break; -// case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: -// if (m_selectionItemMatrix->isEnabledForSelection()) { -// m_identificationModeFlag = true; -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// else { -// return; -// } -// break; -// case BrainOpenGLFixedPipeline::MODE_PROJECTION: -// return; -// break; -// } - - float bounds[4]; - if ( ! histogramData->getBounds(bounds)) { - return; - } - - glColor3f(1.0, 0.0, 0.0); - glBegin(GL_LINES); - glVertex3f(bounds[0], bounds[2], 0.0); - glVertex3f(bounds[1], bounds[3], 0.0); - glEnd(); - - const std::vector heightValues = histogramData->getHistogramValues(); - const int32_t numValues = static_cast(heightValues.size()); - if (numValues > 1) { - std::vector dataColoringVectorRGBA; - if ( ! m_identificationModeFlag) { - bool solidColorFlag = false; - if (solidColorFlag) { - - } - else { - colorHistogramWithPalette(histogramChart, - mapIndex, - dataColoringVectorRGBA); - const size_t rgbaSize = numValues * 4; - CaretAssert(dataColoringVectorRGBA.size() == rgbaSize); - } - } - std::vector quadVerticesXYZ; - std::vector quadVerticesFloatRGBA; - std::vector quadVerticesByteRGBA; - - switch (histogramData->getHistogramViewingType()) { - case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS: - { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 4; - const int32_t totalVertices = verticesPerBar * numValues; - quadVerticesXYZ.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - - const float z = 0.; - - for (int32_t i = 0; i < numValues; i++) { - float left = i; - float right = i + 1; - float bottom = 0; - CaretAssertVectorIndex(heightValues, i); - float top = heightValues[i]; - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - - if (m_identificationModeFlag) { - uint8_t idRGBA[4]; - addToHistogramIdentification(i, idRGBA); - - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - } - else { - CaretAssertVectorIndex(dataColoringVectorRGBA, i*4 + 3); - const float* rgba = &dataColoringVectorRGBA[i * 4]; - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - - } - - /* - * Draw the bar elements. - */ - if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); - glColor4ubv(&quadVerticesByteRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + const float lineWidth = 5.0; + BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, + quadVerticesByteRGBA, + lineWidth); +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// m_fixedPipelineDrawing->setLineWidth(5); +// glBegin(GL_LINES); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); +// glColor4ubv(&quadVerticesByteRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } else { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); - glColor4fv(&quadVerticesFloatRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); - } - } - break; - case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE: - { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 2; - const int32_t totalVertices = verticesPerBar * numValues + 4; - quadVerticesXYZ.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - - const float z = 0.0; - - const int32_t lastValueIndex = numValues - 1; - for (int32_t i = 0; i < numValues; i++) { - float left = i; - float right = i + 1; - float bottom = 0; - CaretAssertVectorIndex(heightValues, i); - float top = heightValues[i]; - - float rgba[4] = { 1.0, 0.5, 0.0, 1.0 }; - - uint8_t idRGBA[4]; - if (m_identificationModeFlag) { - addToHistogramIdentification(i, idRGBA); - } - if (i == 0) { - /* - * Left side of first bar - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - else { - if (top > heightValues[i - 1]) { - /* - * Line from previous bar that is lower in - * height than this bar - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(heightValues[i - 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - } + const float lineWidth = 5.0; + BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, + quadVerticesFloatRGBA, + lineWidth); - /* - * Draw line across top - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - - if (i == lastValueIndex) { - /* - * Right side of last bar - */ - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - else { - if (top > heightValues[i + 1]) { - /* - * Line from bar down to next bar - * with a lower height - */ - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(heightValues[i + 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - } - } - - /* - * Draw the line elements. - */ - if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - m_fixedPipelineDrawing->setLineWidth(5); - glBegin(GL_LINES); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); - glColor4ubv(&quadVerticesByteRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); - } - else { - m_fixedPipelineDrawing->setLineWidth(2); - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_LINES); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); - glColor4fv(&quadVerticesFloatRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); +// m_fixedPipelineDrawing->setLineWidth(2); +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// glBegin(GL_LINES); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); +// glColor4fv(&quadVerticesFloatRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } } break; @@ -1500,7 +787,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } } - /** * Draw a matrix chart. */ @@ -1632,62 +918,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() } } -///** -// * Get highlighting of rows or columns for a matrix. -// * -// * @param matrixChart -// * Matrix chart that is drawn. -// * @param rowIndicesOut -// * Output with row indices for highlighting. -// * @param columnIndicesOut -// * Output with column indices for highlighting. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, -// std::set& rowIndicesOut, -// std::set& columnIndicesOut) const -//{ -// const CiftiMappableDataFile* ciftiMapFile = matrixChart->getCiftiMappableDataFile(); -// const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); -// if (connMapFile != NULL) { -// const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); -// if (connDataLoaded != NULL) { -// int64_t loadedRowIndex = -1; -// int64_t loadedColumnIndex = -1; -// connDataLoaded->getRowColumnLoading(loadedRowIndex, -// loadedColumnIndex); -// if (loadedRowIndex >= 0) { -// rowIndicesOut.insert(loadedRowIndex); -// } -// else if (loadedColumnIndex >= 0) { -// columnIndicesOut.insert(loadedColumnIndex); -// } -// } -// } -// -// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); -// if (parcelScalarFile != NULL) { -// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); -// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); -// columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); -// } -// -// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); -// if (parcelLabelFile != NULL) { -// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); -// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); -// columnIndicesOut = mapOverlayEvent.getSelectedMapIndices(); -// } -// -// const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); -// if (scalarDataSeriesFile != NULL) { -// const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(m_tabIndex); -// if (scalarDataSeriesMapIndex >= 0) { -// rowIndicesOut.insert(scalarDataSeriesMapIndex); -// } -// } -//} - /* * Draw a matrix chart. * @@ -1714,24 +944,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -// m_identificationModeFlag = false; -// switch (m_fixedPipelineDrawing->mode) { -// case BrainOpenGLFixedPipeline::MODE_DRAWING: -// break; -// case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: -// if (m_selectionItemMatrix->isEnabledForSelection()) { -// m_identificationModeFlag = true; -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// else { -// return; -// } -// break; -// case BrainOpenGLFixedPipeline::MODE_PROJECTION: -// return; -// break; -// } - int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; @@ -1951,20 +1163,34 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT cellY -= cellHeight; } + const float normalVector[3] = { 0.0, 0.0, 1.0 }; + std::vector quadVerticesNormals; + quadVerticesNormals.reserve(quadVerticesXYZ.size()); + const int32_t numberOfVertices = static_cast(quadVerticesXYZ.size() / 3); + for (int32_t iNormal = 0; iNormal < numberOfVertices; iNormal++) { + quadVerticesNormals.insert(quadVerticesNormals.end(), + normalVector, normalVector + 3); + } + CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); + /* * Draw the matrix elements. */ if (m_identificationModeFlag) { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); - glColor4ubv(&quadVerticesByteRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesByteRGBA); + +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// glBegin(GL_QUADS); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); +// glColor4ubv(&quadVerticesByteRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } else { /* @@ -1975,15 +1201,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); - glColor4fv(&quadVerticesFloatRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesFloatRGBA); +// glBegin(GL_QUADS); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); +// glColor4fv(&quadVerticesFloatRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); glDisable(GL_BLEND); @@ -1999,6 +1227,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT gridLineColorFloats); gridLineColorFloats[3] = 1.0; std::vector outlineRGBA; + const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); outlineRGBA.reserve(numberQuadVertices * 4); for (int32_t i = 0; i < numberQuadVertices; i++) { outlineRGBA.push_back(gridLineColorFloats[0]); @@ -2006,23 +1235,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT outlineRGBA.push_back(gridLineColorFloats[2]); outlineRGBA.push_back(gridLineColorFloats[3]); } + CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); glPolygonMode(GL_FRONT, GL_LINE); glLineWidth(1.0); - glBegin(GL_QUADS); - for (int32_t i = 0; i < numberQuadVertices; i++) { - CaretAssertVectorIndex(outlineRGBA, i*4 + 3); - glColor4fv(&outlineRGBA[i*4]); - CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); - glVertex3fv(&quadVerticesXYZ[i*3]); - } - glEnd(); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + outlineRGBA); +// glBegin(GL_QUADS); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// CaretAssertVectorIndex(outlineRGBA, i*4 + 3); +// glColor4fv(&outlineRGBA[i*4]); +// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); +// glVertex3fv(&quadVerticesXYZ[i*3]); +// } +// glEnd(); } if ( (! selectedRowIndices.empty()) && highlightSelectedRowColumnFlag) { - std::vector rowXYZ; - std::vector rowRGBA; +// std::vector rowXYZ; +// std::vector rowRGBA; for (auto rowIndex : selectedRowIndices) { const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; @@ -2044,72 +1277,83 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float minX = minColumn * cellWidth; const float maxX = maxColumn * cellWidth; + std::vector rowXYZ; + rowXYZ.reserve(12); rowXYZ.push_back(minX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); - rowRGBA.push_back(highlightRGB[0]); - rowRGBA.push_back(highlightRGB[1]); - rowRGBA.push_back(highlightRGB[2]); - rowRGBA.push_back(1.0); +// rowRGBA.push_back(highlightRGB[0]); +// rowRGBA.push_back(highlightRGB[1]); +// rowRGBA.push_back(highlightRGB[2]); +// rowRGBA.push_back(1.0); rowXYZ.push_back(minX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); - rowRGBA.push_back(highlightRGB[0]); - rowRGBA.push_back(highlightRGB[1]); - rowRGBA.push_back(highlightRGB[2]); - rowRGBA.push_back(1.0); +// rowRGBA.push_back(highlightRGB[0]); +// rowRGBA.push_back(highlightRGB[1]); +// rowRGBA.push_back(highlightRGB[2]); +// rowRGBA.push_back(1.0); rowXYZ.push_back(maxX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); - rowRGBA.push_back(highlightRGB[0]); - rowRGBA.push_back(highlightRGB[1]); - rowRGBA.push_back(highlightRGB[2]); - rowRGBA.push_back(1.0); +// rowRGBA.push_back(highlightRGB[0]); +// rowRGBA.push_back(highlightRGB[1]); +// rowRGBA.push_back(highlightRGB[2]); +// rowRGBA.push_back(1.0); rowXYZ.push_back(maxX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); - rowRGBA.push_back(highlightRGB[0]); - rowRGBA.push_back(highlightRGB[1]); - rowRGBA.push_back(highlightRGB[2]); - rowRGBA.push_back(1.0); +// rowRGBA.push_back(highlightRGB[0]); +// rowRGBA.push_back(highlightRGB[1]); +// rowRGBA.push_back(highlightRGB[2]); +// rowRGBA.push_back(1.0); + + /* + * As cells get larger, increase linewidth for selected row + */ + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + const float rgba[4] = { highlightRGB[0], highlightRGB[1], highlightRGB[2], 1.0f }; + BrainOpenGLPrimitiveDrawing::drawLineLoop(rowXYZ, + rgba, + highlightLineWidth); } - CaretAssert((rowXYZ.size() / 3) == (rowRGBA.size() / 4)); - - const int32_t numberOfVertices = static_cast(rowXYZ.size() / 3); - const int32_t numberOfQuads = numberOfVertices / 4; - CaretAssert((numberOfQuads * 4) == numberOfVertices); - - /* - * As cells get larger, increase linewidth for selected row - */ - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - - for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { - glBegin(GL_LINE_LOOP); - for (int32_t iVert = 0; iVert < 4; iVert++) { - const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); - CaretAssertVectorIndex(rowRGBA, rgbaOffset + 3); - glColor4fv(&rowRGBA[rgbaOffset]); - - const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); - CaretAssertVectorIndex(rowXYZ, xyzOffset + 2); - glVertex3fv(&rowXYZ[xyzOffset]); - } - glEnd(); - } +// CaretAssert((rowXYZ.size() / 3) == (rowRGBA.size() / 4)); +// +// const int32_t numberOfVertices = static_cast(rowXYZ.size() / 3); +// const int32_t numberOfQuads = numberOfVertices / 4; +// CaretAssert((numberOfQuads * 4) == numberOfVertices); +// +// /* +// * As cells get larger, increase linewidth for selected row +// */ +// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); +// glLineWidth(highlightLineWidth); +// +// for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { +// glBegin(GL_LINE_LOOP); +// for (int32_t iVert = 0; iVert < 4; iVert++) { +// const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); +// CaretAssertVectorIndex(rowRGBA, rgbaOffset + 3); +// glColor4fv(&rowRGBA[rgbaOffset]); +// +// const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); +// CaretAssertVectorIndex(rowXYZ, xyzOffset + 2); +// glVertex3fv(&rowXYZ[xyzOffset]); +// } +// glEnd(); +// } glLineWidth(1.0); } if ( (! selectedColumnIndices.empty()) && highlightSelectedRowColumnFlag) { - std::vector columnXYZ; - std::vector columnRGBA; +// std::vector columnXYZ; +// std::vector columnRGBA; for (auto columnIndex : selectedColumnIndices) { const float colX = columnIndex * cellWidth; @@ -2132,65 +1376,76 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float maxY = maxRow * cellHeight; + std::vector columnXYZ; + columnXYZ.reserve(12); columnXYZ.push_back(colX); columnXYZ.push_back(minY); columnXYZ.push_back(0.0); - columnRGBA.push_back(highlightRGB[0]); - columnRGBA.push_back(highlightRGB[1]); - columnRGBA.push_back(highlightRGB[2]); - columnRGBA.push_back(1.0); +// columnRGBA.push_back(highlightRGB[0]); +// columnRGBA.push_back(highlightRGB[1]); +// columnRGBA.push_back(highlightRGB[2]); +// columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(minY); columnXYZ.push_back(0.0); - columnRGBA.push_back(highlightRGB[0]); - columnRGBA.push_back(highlightRGB[1]); - columnRGBA.push_back(highlightRGB[2]); - columnRGBA.push_back(1.0); +// columnRGBA.push_back(highlightRGB[0]); +// columnRGBA.push_back(highlightRGB[1]); +// columnRGBA.push_back(highlightRGB[2]); +// columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); - columnRGBA.push_back(highlightRGB[0]); - columnRGBA.push_back(highlightRGB[1]); - columnRGBA.push_back(highlightRGB[2]); - columnRGBA.push_back(1.0); +// columnRGBA.push_back(highlightRGB[0]); +// columnRGBA.push_back(highlightRGB[1]); +// columnRGBA.push_back(highlightRGB[2]); +// columnRGBA.push_back(1.0); columnXYZ.push_back(colX); columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); - columnRGBA.push_back(highlightRGB[0]); - columnRGBA.push_back(highlightRGB[1]); - columnRGBA.push_back(highlightRGB[2]); - columnRGBA.push_back(1.0); +// columnRGBA.push_back(highlightRGB[0]); +// columnRGBA.push_back(highlightRGB[1]); +// columnRGBA.push_back(highlightRGB[2]); +// columnRGBA.push_back(1.0); + + /* + * As cells get larger, increase linewidth for selected row + */ + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + const float rgba[4] = { highlightRGB[0], highlightRGB[1], highlightRGB[2], 1.0f }; + BrainOpenGLPrimitiveDrawing::drawLineLoop(columnXYZ, + rgba, + highlightLineWidth); } - CaretAssert((columnXYZ.size() / 3) == (columnRGBA.size() / 4)); - - const int32_t numberOfVertices = static_cast(columnXYZ.size() / 3); - const int32_t numberOfQuads = numberOfVertices / 4; - CaretAssert((numberOfQuads * 4) == numberOfVertices); - - /* - * As cells get larger, increase linewidth for selected row - */ - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - - for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { - glBegin(GL_LINE_LOOP); - for (int32_t iVert = 0; iVert < 4; iVert++) { - const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); - CaretAssertVectorIndex(columnRGBA, rgbaOffset + 3); - glColor4fv(&columnRGBA[rgbaOffset]); - - const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); - CaretAssertVectorIndex(columnXYZ, xyzOffset + 2); - glVertex3fv(&columnXYZ[xyzOffset]); - } - glEnd(); - } +// CaretAssert((columnXYZ.size() / 3) == (columnRGBA.size() / 4)); +// +// const int32_t numberOfVertices = static_cast(columnXYZ.size() / 3); +// const int32_t numberOfQuads = numberOfVertices / 4; +// CaretAssert((numberOfQuads * 4) == numberOfVertices); +// +// /* +// * As cells get larger, increase linewidth for selected row +// */ +// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); +// glLineWidth(highlightLineWidth); +// +// for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { +// glBegin(GL_LINE_LOOP); +// for (int32_t iVert = 0; iVert < 4; iVert++) { +// const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); +// CaretAssertVectorIndex(columnRGBA, rgbaOffset + 3); +// glColor4fv(&columnRGBA[rgbaOffset]); +// +// const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); +// CaretAssertVectorIndex(columnXYZ, xyzOffset + 2); +// glVertex3fv(&columnXYZ[xyzOffset]); +// } +// glEnd(); +// } glLineWidth(1.0); } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index f3a4d8d0d..d449e0eac 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -113,21 +113,10 @@ namespace caret { void drawHistogramChart(); - void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex); - void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, const int32_t mapIndex, const HistogramDrawingInfo& histogramDrawingInfo); - void colorHistogramWithPalette(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex, - std::vector& rgbaOut); - -// void getMatrixHighlighting(const ChartableTwoFileMatrixChart* matrixChart, -// std::set& rowIndicesOut, -// std::set& columnIndicesOut) const; - Brain* m_brain; ModelChartTwo* m_chartTwoModel; diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx index 375a041b0..7961d3ccb 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx @@ -726,6 +726,61 @@ BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, lineWidth); } +/** + * Draw a line between each pair of three-dimensional coordinates in the given color + * with optional normal vectors. + * + * @param coordinates + * Three-Dimensional coordinates (XYZ). + * @param rgba + * RGBA Colors [0.0, 1.0] for each vertex. + * @param lineWidth + * Line width used by line drawing modes. + */ +void +BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth) +{ + std::vector emptyNormals; + + std::vector rgbaBytes; + rgbaBytes.reserve(rgbaColors.size()); + for (const float component : rgbaColors) { + rgbaBytes.push_back(static_cast(component * 255.0)); + } + + drawPrimitiveWithVertexArrays(GL_LINES, + coordinates, + emptyNormals, + rgbaBytes, + lineWidth); +} + +/** + * Draw a line between each pair of three-dimensional coordinates in the given color + * with optional normal vectors. + * + * @param coordinates + * Three-Dimensional coordinates (XYZ). + * @param rgba + * RGBA Colors [0, 255] for each vertex. + * @param lineWidth + * Line width used by line drawing modes. + */ +void +BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth) +{ + std::vector emptyNormals; + drawPrimitiveWithVertexArrays(GL_LINES, + coordinates, + emptyNormals, + rgbaColors, + lineWidth); +} + /** * Draw a line strip with the given coordinates in the given color * with optional normal vectors. @@ -926,6 +981,94 @@ BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, } } +/** + * Draw a line between each pair of three-dimensional coordinates in the given colors + * per vertex with optional normal vectors using the given OpenGL mode. + * + * @param mode + * The OpenGL drawing mode. + * @param coordinates + * Three-Dimensional coordinates (XYZ). + * @param normals + * Normal vectors. There number of elements must match the numer of + * coordinates (in which case normal vectors are applied) or empty + * (in which case normal vectors are not applied). + * @param rgba + * 4 components per vertex.. + * @param lineWidth + * Line width used by line drawing modes. + */ +void +BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, + const std::vector& coordinates, + const std::vector& normals, + const std::vector& rgbaColors, + const float lineWidth) +{ + const int64_t numCoords = static_cast(coordinates.size() / 3); + if (numCoords < 1) { + CaretLogWarning("Invalid number of coordinates=" + QString::number(numCoords)); + return; + } + +// std::vector rgbaVector; +// rgbaVector.reserve(numCoords * 4); +// for (int32_t i = 0; i < numCoords; i++) { +// rgbaVector.push_back(rgba[0]); +// rgbaVector.push_back(rgba[1]); +// rgbaVector.push_back(rgba[2]); +// rgbaVector.push_back(rgba[3]); +// } + + CaretAssert(numCoords == (rgbaColors.size() / 4)); + + const int64_t numNormals = static_cast(normals.size()); + if (numNormals > 0) { + if (numCoords != numNormals) { + const AString msg("Number of coordinates " + + QString::number(numCoords) + + " does not equal number of normals=" + + QString::number(numNormals)); + CaretAssertMessage(0, msg); + CaretLogWarning(msg); + return; + } + } + + + if ((mode == GL_LINES) + || (mode == GL_LINE_LOOP) + || (mode == GL_LINE_STRIP)) { + glLineWidth(lineWidth); + } + + glVertexPointer(3, + GL_FLOAT, + 0, + reinterpret_cast(&coordinates[0])); + glColorPointer(4, + GL_UNSIGNED_BYTE, + 0, + reinterpret_cast(&rgbaColors[0])); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + if (numNormals > 0) { + glNormalPointer(GL_FLOAT, + 0, + reinterpret_cast(&normals[0])); + glEnableClientState(GL_NORMAL_ARRAY); + } + + glDrawArrays(mode, 0, numCoords); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + if (numNormals > 0) { + glDisableClientState(GL_NORMAL_ARRAY); + } +} + static void createRectangle(const float center[3], const float leftToRightUnitVector[3], diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.h b/src/Brain/BrainOpenGLPrimitiveDrawing.h index fac59270c..244b5e860 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.h +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.h @@ -66,6 +66,14 @@ namespace caret { const uint8_t rgba[4], const float lineWidth); + static void drawLines(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth); + + static void drawLines(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth); + static void drawLineStrip(const std::vector& coordinates, const float rgba[4], const float lineWidth); @@ -132,7 +140,11 @@ namespace caret { const uint8_t rgba[4], const float lineWidth); - + static void drawPrimitiveWithVertexArrays(GLenum mode, + const std::vector& coordinates, + const std::vector& normals, + const std::vector& rgba, + const float lineWidth); }; #ifdef __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 748f9171c..747731b5d 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -799,7 +799,6 @@ void IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoHistogram* idChartTwoHistogram) const { - CaretAssertToDoWarning(); if (idChartTwoHistogram->isValid()) { const ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); const int32_t barIndex = idChartTwoHistogram->getBarIndex(); @@ -830,7 +829,9 @@ void IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const { - CaretAssertToDoWarning(); + if (idChartTwoLineSeries->isValid()) { + CaretAssertToDoWarning(); + } } /** diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 3488ff85d..60cc9a83d 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -843,9 +843,6 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, return false; } - const Histogram* histogram = getMapHistogram(mapIndex); - CaretAssert(histogram); - FastStatistics* statistics = NULL; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: @@ -855,15 +852,110 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, statistics = const_cast(getMapFastStatistics(mapIndex)); break; } + CaretAssert(statistics); + float mostPos = 0.0; + float leastPos = 0.0; + float leastNeg = 0.0; + float mostNeg = 0.0; + bool matchFlag = false; + + switch (paletteColorMapping->getHistogramRangeMode()) { + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: + { + float dummy; + statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); + } + break; + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: + { + matchFlag = true; + switch (paletteColorMapping->getScaleMode()) { + case PaletteScaleModeEnum::MODE_AUTO_SCALE: + mostPos = statistics->getMax(); + leastPos = 0.0; + leastNeg = 0.0; + mostNeg = statistics->getMin(); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: + mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); + leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); + leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); + mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: + mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); + leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); + leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); + mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); + break; + case PaletteScaleModeEnum::MODE_USER_SCALE: + mostPos = paletteColorMapping->getUserScalePositiveMaximum(); + leastPos = paletteColorMapping->getUserScalePositiveMinimum(); + leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); + mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); + break; + } + } + break; + } + + /* + * Remove data that is not displayed + */ + bool isZeroIncluded = true; + const Histogram* histogram = NULL; + if (matchFlag) { + isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); + + if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { + mostNeg = 0.0; + leastNeg = 0.0; + } + if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { + mostPos = 0.0; + leastPos = 0.0; + } + + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogram = getFileHistogram(mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogram = getMapHistogram(mapIndex, + mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + } + } + else { + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogram = getFileHistogram(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogram = getMapHistogram(mapIndex); + break; + } + } + + CaretAssert(histogram); - float minValue = 0.0; - float maxValue = 0.0; - histogram->getRange(minValue, - maxValue); - const float valueRange = maxValue - minValue; - if (valueRange <= 0.0) { - errorMessageOut = "Range of histogram values is zero"; + + float minValueX = 0.0; + float maxValueX = 0.0; + histogram->getRange(minValueX, + maxValueX); + const float valueRangeX = maxValueX - minValueX; + if (valueRangeX <= 0.0) { + errorMessageOut = "Range of histogram X-values is zero"; return false; } @@ -878,7 +970,7 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, return false; } - const int32_t numberOfDataPoints = (addEndPointForQwtFlag + int32_t numberOfDataPoints = (addEndPointForQwtFlag ? (numBucketValues + 1) : numBucketValues); @@ -892,29 +984,98 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, } histogramDrawingInfoOut.m_dataY = histogramBuckets; - const float step = ((valueRange) + const bool hideZerosFlag = ( ! paletteColorMapping->isDisplayZeroDataFlag()); + const float stepX = ((valueRangeX) / static_cast(numberOfDataPoints)); + /* + * Need to find zero (or near zero if there is not an exact zero value) + */ + int32_t indexZeroX = -1; + float indexZeroDistance = std::numeric_limits::max(); + for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { - const float value = (minValue - + (ix * step)); + float valueX = (minValueX + + (ix * stepX)); + + if (hideZerosFlag) { + const float zeroDistance = ((valueX >= 0) ? valueX : -valueX); + if (zeroDistance < indexZeroDistance) { + indexZeroX = ix; + indexZeroDistance = zeroDistance; + } + } + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); - histogramDrawingInfoOut.m_dataX[ix] = value; + histogramDrawingInfoOut.m_dataX[ix] = valueX; + } + + if (indexZeroX >= 0) { + const float posZero = 0.05; + const float negZero = -posZero; + int32_t negZeroIndex = -1; + + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, indexZeroX); + const float xValue = histogramDrawingInfoOut.m_dataX[indexZeroX]; + if (xValue <= 0.0) { + negZeroIndex = indexZeroX; + } + else { + negZeroIndex = indexZeroX - 1; + } + + if ((negZeroIndex >= 0) + && (negZeroIndex < (numberOfDataPoints - 1))) { + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, negZeroIndex + 1); + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, negZeroIndex + 1); + histogramDrawingInfoOut.m_dataX[negZeroIndex] = negZero; + histogramDrawingInfoOut.m_dataY[negZeroIndex] = 0.0; + + histogramDrawingInfoOut.m_dataX.insert(histogramDrawingInfoOut.m_dataX.begin() + negZeroIndex + 1, posZero); + histogramDrawingInfoOut.m_dataY.insert(histogramDrawingInfoOut.m_dataY.begin() + negZeroIndex + 1, 0.0); + } + numberOfDataPoints = static_cast(histogramDrawingInfoOut.m_dataX.size()); + CaretAssert(histogramDrawingInfoOut.m_dataX.size() == histogramDrawingInfoOut.m_dataY.size()); + histogramDrawingInfoOut.m_dataRGBA.resize(numberOfDataPoints * 4); } - histogramDrawingInfoOut.m_dataX[0] = minValue; - histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValue; + +// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); +// std::cout << "value " << ix << ": " << histogramDrawingInfoOut.m_dataX[ix] << "," << histogramDrawingInfoOut.m_dataX[ix] << std::endl; +// } + + histogramDrawingInfoOut.m_dataX[0] = minValueX; + histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValueX; const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; - float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - xValuesArray, - xValuesArray, - numberOfDataPoints, - dataRGBA, - true); // ignore thresholding + const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); + if (histogramColor != CaretColorEnum::CUSTOM) { + float rgba[4]; + CaretColorEnum::toRGBFloat(histogramColor, rgba); + rgba[3] = 1.0; + + for (int32_t i = 0; i < numberOfDataPoints; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, i4 + 3); + histogramDrawingInfoOut.m_dataRGBA[i4] = rgba[0]; + histogramDrawingInfoOut.m_dataRGBA[i4+1] = rgba[1]; + histogramDrawingInfoOut.m_dataRGBA[i4+2] = rgba[2]; + histogramDrawingInfoOut.m_dataRGBA[i4+3] = rgba[3]; + } + } + else { + float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; + + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + xValuesArray, + xValuesArray, + numberOfDataPoints, + dataRGBA, + true); // ignore thresholding + } CaretAssert(histogramDrawingInfoOut.isValid()); return histogramDrawingInfoOut.isValid(); diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 1e3d64f5e..8fce8b82f 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -87,14 +87,14 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, numCols)); - m_rowColumnDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; - if ( ! m_validRowColumnSelectionDimensions.empty()) { - CaretAssertVectorIndex(m_validRowColumnSelectionDimensions, 0); - m_rowColumnDimension = m_validRowColumnSelectionDimensions[0]; - } - - m_sceneAssistant->add("m_rowColumnDimension", - &m_rowColumnDimension); +// m_rowColumnDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; +// if ( ! m_validRowColumnSelectionDimensions.empty()) { +// CaretAssertVectorIndex(m_validRowColumnSelectionDimensions, 0); +// m_rowColumnDimension = m_validRowColumnSelectionDimensions[0]; +// } +// +// m_sceneAssistant->add("m_rowColumnDimension", +// &m_rowColumnDimension); } /** @@ -367,7 +367,22 @@ ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, ChartTwoMatrixLoadingDimensionEnum::Enum ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const { - return m_rowColumnDimension; + ChartTwoMatrixLoadingDimensionEnum::Enum loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + + const CaretMappableDataFile* cmdf = getCaretMappableDataFile(); + const CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(cmdf); + if (matrixFile != NULL) { + switch (matrixFile->getMatrixLoadingDimension()) { + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + break; + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; + } + } + + return loadDimension; } /** @@ -379,10 +394,24 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const void ChartableTwoFileMatrixChart::setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension) { - if (m_rowColumnDimension != rowColumnDimension) { - m_rowColumnDimension = rowColumnDimension; - setModified(); + CaretMappableDataFile* cmdf = getCaretMappableDataFile(); + CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(cmdf); + if (matrixFile != NULL) { + ChartMatrixLoadingDimensionEnum::Enum oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + switch (rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; + } + matrixFile->setMatrixLoadingDimension(oldLoadDim); } +// if (m_rowColumnDimension != rowColumnDimension) { +// m_rowColumnDimension = rowColumnDimension; +// setModified(); +// } } /** @@ -413,7 +442,7 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnIndices(const int32_t tabIndex, std::vector& rowIndicesOut, std::vector& columnIndicesOut) const { - rowColumnDimensionOut = m_rowColumnDimension; + rowColumnDimensionOut = getSelectedRowColumnDimension(); rowIndicesOut.clear(); columnIndicesOut.clear(); @@ -429,7 +458,7 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnIndices(const int32_t tabIndex, int64_t loadedColumnIndex = -1; connDataLoaded->getRowColumnLoading(loadedRowIndex, loadedColumnIndex); - switch (m_rowColumnDimension) { + switch (rowColumnDimensionOut) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: if (loadedColumnIndex >= 0) { columnIndicesSet.insert(loadedColumnIndex); @@ -508,7 +537,7 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, int32_t numRows = -1; int32_t numCols = -1; getMatrixDimensions(numRows, numCols); - switch (m_rowColumnDimension) { + switch (getSelectedRowColumnDimension()) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: if ((rowColumnIndex >= 0) && (rowColumnIndex < numCols)) { diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 9eae3d245..94a24c838 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -83,7 +83,7 @@ namespace caret { const std::vector m_validRowColumnSelectionDimensions; - ChartTwoMatrixLoadingDimensionEnum::Enum m_rowColumnDimension; + //ChartTwoMatrixLoadingDimensionEnum::Enum m_rowColumnDimension; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/CaretColorEnumComboBox.cxx b/src/GuiQt/CaretColorEnumComboBox.cxx index f1f31f433..a88f711ee 100644 --- a/src/GuiQt/CaretColorEnumComboBox.cxx +++ b/src/GuiQt/CaretColorEnumComboBox.cxx @@ -25,6 +25,9 @@ #include +#include "CaretAssert.h" +#include "WuQtUtilities.h" + using namespace caret; @@ -35,36 +38,102 @@ using namespace caret; * * Control for selection of Caret Color enumerated types. */ + /** * Constructor. + * * @param parent * Parent object. */ CaretColorEnumComboBox::CaretColorEnumComboBox(QObject* parent) : WuQWidget(parent) +{ + initializeCaretColorComboBox(""); +} + +/** + * Constructor. + * + * @param customColorSelectionName + * CaretColorEnum::CUSTOM is added to the combo with this name as the text. + * Text must NOT be empty. + * @param parent + * Parent object. + */ +CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, + QObject* parent) +: WuQWidget(parent) +{ + CaretAssert( ! customColorSelectionName.isEmpty()); + initializeCaretColorComboBox(customColorSelectionName); +} + +/** + * Destructor. + */ +CaretColorEnumComboBox::~CaretColorEnumComboBox() +{ + +} + +/** + * Initialize instance that may have optional caret color enums. + * + * @param customColorSelectionName + * If NOT empty, CaretColorEnum::CUSTOM is added with text from this name. + */ +void +CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorSelectionName) { this->colorComboBox = new QComboBox(); std::vector colors; - CaretColorEnum::getColorEnums(colors); + + int64_t caretColorOptions = 0; + if ( ! customColorSelectionName.isEmpty()) { + caretColorOptions |= CaretColorEnum::OPTION_INCLUDE_CUSTOM_COLOR; + } + CaretColorEnum::getColorAndOptionalEnums(colors, + caretColorOptions); const int32_t numColors = static_cast(colors.size()); for (int32_t i = 0; i < numColors; i++) { const CaretColorEnum::Enum colorEnum = colors[i]; const int32_t indx = this->colorComboBox->count(); - const AString name = CaretColorEnum::toGuiName(colorEnum); + AString name = CaretColorEnum::toGuiName(colorEnum); + if (colorEnum == CaretColorEnum::CUSTOM) { + if ( ! customColorSelectionName.isEmpty()) { + name = customColorSelectionName; + } + } this->colorComboBox->addItem(name); - this->colorComboBox->setItemData(indx, + this->colorComboBox->setItemData(indx, CaretColorEnum::toIntegerCode(colorEnum)); - - const float* rgb = CaretColorEnum::toRGB(colorEnum); - QPixmap pm(10, 10); - pm.fill(QColor::fromRgbF(rgb[0], - rgb[1], - rgb[2])); - QIcon icon(pm); - this->colorComboBox->setItemIcon(indx, - icon); + + /* + * Create an icon with the color. + */ + float rgba[4]; + CaretColorEnum::toRGBFloat(colorEnum, rgba); + if (colorEnum == CaretColorEnum::NONE) { + rgba[3] = 0.0; + } + else if (colorEnum == CaretColorEnum::CUSTOM) { + /* + * No pixmap for CUSTOM + */ + rgba[3] = 0.0; + } + else { + rgba[3] = 1.0; + } + + if (rgba[3] > 0.0) { + QPixmap pm(WuQtUtilities::createCaretColorEnumPixmap(getWidget(), 10, 10, colorEnum, rgba, false)); + QIcon icon(pm); + this->colorComboBox->setItemIcon(indx, + icon); + } } setSelectedColor(CaretColorEnum::BLACK); @@ -72,14 +141,6 @@ CaretColorEnumComboBox::CaretColorEnumComboBox(QObject* parent) this, SLOT(colorComboBoxIndexChanged(int))); } -/** - * Destructor. - */ -CaretColorEnumComboBox::~CaretColorEnumComboBox() -{ - -} - /** * @return The actual widget. */ diff --git a/src/GuiQt/CaretColorEnumComboBox.h b/src/GuiQt/CaretColorEnumComboBox.h index afb69c42b..38b4cd8a1 100644 --- a/src/GuiQt/CaretColorEnumComboBox.h +++ b/src/GuiQt/CaretColorEnumComboBox.h @@ -36,6 +36,9 @@ namespace caret { public: CaretColorEnumComboBox(QObject* parent); + CaretColorEnumComboBox(const AString& customColorSelectionName, + QObject* parent); + virtual ~CaretColorEnumComboBox(); CaretColorEnum::Enum getSelectedColor(); @@ -57,6 +60,9 @@ namespace caret { private: QComboBox* colorComboBox; + + void initializeCaretColorComboBox(const AString& customColorSelectionName); + }; #ifdef __CARET_COLOR_ENUM_COMBOBOX_DECLARE__ diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 0b24a197e..447bb72e3 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -43,6 +43,7 @@ #undef __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_DECLARE__ #include "Brain.h" +#include "CaretColorEnumComboBox.h" #include "CaretMappableDataFile.h" #include "CursorDisplayScoped.h" #include "EnumComboBoxTemplate.h" @@ -107,8 +108,6 @@ MapSettingsPaletteColorMappingWidget::MapSettingsPaletteColorMappingWidget(QWidg */ this->setContextMenuPolicy(Qt::NoContextMenu); - this->isHistogramColored = true; - this->caretMappableDataFile = NULL; this->mapFileIndex = -1; @@ -726,15 +725,6 @@ MapSettingsPaletteColorMappingWidget::thresholdRangeModeChanged() applySelections(); } -/** - * Called when a histogram control is changed. - */ -void -MapSettingsPaletteColorMappingWidget::histogramControlChanged() -{ - this->updateWidget(); -} - /** * Create the statistics section * @return the statistics section widget. @@ -745,10 +735,10 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() /* * Control section */ - this->histogramAllRadioButton = new QRadioButton("All"); - WuQtUtilities::setToolTipAndStatusTip(this->histogramAllRadioButton, + this->histogramAllRadioButton = new QRadioButton(PaletteHistogramRangeModeEnum::toGuiName(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL)); + WuQtUtilities::setToolTipAndStatusTip(this->histogramAllRadioButton, "Displays all map data in the histogram"); - this->histogramMatchPaletteRadioButton = new QRadioButton("Match\nPalette"); + this->histogramMatchPaletteRadioButton = new QRadioButton(PaletteHistogramRangeModeEnum::toGuiName(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE)); WuQtUtilities::setToolTipAndStatusTip(this->histogramMatchPaletteRadioButton, "Use the palette mapping selections"); @@ -758,14 +748,14 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() buttGroup->addButton(this->histogramAllRadioButton); buttGroup->addButton(this->histogramMatchPaletteRadioButton); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), - this, SLOT(histogramControlChanged())); + this, SLOT(applyAndUpdate())); - this->histogramUsePaletteColors = new QCheckBox("Colorize"); - WuQtUtilities::setToolTipAndStatusTip(this->histogramUsePaletteColors, - "If checked, histogram colors match colors mapped to data"); - this->histogramUsePaletteColors->setChecked(true); - QObject::connect(this->histogramUsePaletteColors, SIGNAL(toggled(bool)), - this, SLOT(histogramControlChanged())); + m_histogramColorComboBox = new CaretColorEnumComboBox("Palette Coloring", + this); + WuQtUtilities::setToolTipAndStatusTip(m_histogramColorComboBox->getWidget(), + "Set histogram coloring"); + QObject::connect(m_histogramColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), + this, SLOT(applyAndUpdate())); QWidget* controlWidget = new QWidget(); QGridLayout* controlLayout = new QGridLayout(controlWidget); @@ -773,7 +763,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() controlLayout->addWidget(this->histogramAllRadioButton); controlLayout->addWidget(this->histogramMatchPaletteRadioButton); controlLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); - controlLayout->addWidget(this->histogramUsePaletteColors); + controlLayout->addWidget(m_histogramColorComboBox->getWidget()); controlWidget->setFixedSize(controlWidget->sizeHint()); /* @@ -1621,6 +1611,17 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile this->interpolateColorsCheckBox->setChecked(this->paletteColorMapping->isInterpolatePaletteFlag()); + switch (this->paletteColorMapping->getHistogramRangeMode()) { + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: + this->histogramAllRadioButton->setChecked(true); + break; + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: + this->histogramMatchPaletteRadioButton->setChecked(true); + break; + } + + m_histogramColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramColor()); + updateThresholdSection(); float minValue = 0.0; @@ -1677,41 +1678,45 @@ MapSettingsPaletteColorMappingWidget::getHistogram(const FastStatistics* statist float leastNeg = 0.0; float mostNeg = 0.0; bool matchFlag = false; - if (this->histogramAllRadioButton->isChecked()) { - float dummy; - statisticsForAll->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); - } - else if (this->histogramMatchPaletteRadioButton->isChecked()) { - matchFlag = true; - switch (this->paletteColorMapping->getScaleMode()) { - case PaletteScaleModeEnum::MODE_AUTO_SCALE: - mostPos = statisticsForAll->getMax(); - leastPos = 0.0; - leastNeg = 0.0; - mostNeg = statisticsForAll->getMin(); - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: - mostPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); - leastPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); - leastNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); - mostNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: - mostPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMaximumSpinBox->value()); - leastPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMinimumSpinBox->value()); - leastNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMinimumSpinBox->value()); - mostNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMaximumSpinBox->value()); - break; - case PaletteScaleModeEnum::MODE_USER_SCALE: - mostPos = this->scaleFixedPositiveMaximumSpinBox->value(); - leastPos = this->scaleFixedPositiveMinimumSpinBox->value(); - leastNeg = this->scaleFixedNegativeMinimumSpinBox->value(); - mostNeg = this->scaleFixedNegativeMaximumSpinBox->value(); - break; + + switch (this->paletteColorMapping->getHistogramRangeMode()) { + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: + { + float dummy; + statisticsForAll->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); } - } - else { - CaretAssert(0); + break; + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: + { + matchFlag = true; + switch (this->paletteColorMapping->getScaleMode()) { + case PaletteScaleModeEnum::MODE_AUTO_SCALE: + mostPos = statisticsForAll->getMax(); + leastPos = 0.0; + leastNeg = 0.0; + mostNeg = statisticsForAll->getMin(); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: + mostPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); + leastPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); + leastNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); + mostNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: + mostPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMaximumSpinBox->value()); + leastPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMinimumSpinBox->value()); + leastNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMinimumSpinBox->value()); + mostNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMaximumSpinBox->value()); + break; + case PaletteScaleModeEnum::MODE_USER_SCALE: + mostPos = this->scaleFixedPositiveMaximumSpinBox->value(); + leastPos = this->scaleFixedPositiveMinimumSpinBox->value(); + leastNeg = this->scaleFixedNegativeMinimumSpinBox->value(); + mostNeg = this->scaleFixedNegativeMaximumSpinBox->value(); + break; + } + } + break; } const PaletteNormalizationModeEnum::Enum normMode = this->caretMappableDataFile->getPaletteNormalizationMode(); @@ -1848,7 +1853,8 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() dataValues[numDataValues - 1] = maxValue; const Palette* palette = paletteFile->getPaletteByName(this->paletteColorMapping->getSelectedPaletteName()); - if (this->histogramUsePaletteColors->isChecked() + const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); + if ((histogramColor == CaretColorEnum::CUSTOM) && (palette != NULL)) { NodeAndVoxelColoring::colorScalarsWithPalette(statistics, paletteColorMapping, @@ -1860,12 +1866,16 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() true); // ignore thresholding } else { + float colorRGBA[4]; + CaretColorEnum::toRGBFloat(histogramColor, + colorRGBA); + colorRGBA[3] = 1.0; for (int64_t i = 0; i < numDataValues; i++) { const int64_t i4 = i * 4; - dataRGBA[i4] = 1.0; - dataRGBA[i4+1] = 0.0; - dataRGBA[i4+2] = 0.0; - dataRGBA[i4+3] = 1.0; + dataRGBA[i4] = colorRGBA[0]; + dataRGBA[i4+1] = colorRGBA[1]; + dataRGBA[i4+2] = colorRGBA[2]; + dataRGBA[i4+3] = colorRGBA[3]; } } } @@ -2122,6 +2132,14 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setInterpolatePaletteFlag(this->interpolateColorsCheckBox->isChecked()); + if (this->histogramAllRadioButton->isChecked()) { + this->paletteColorMapping->setHistogramRangeMode(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL); + } + else if (this->histogramMatchPaletteRadioButton->isChecked()) { + this->paletteColorMapping->setHistogramRangeMode(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE); + } + this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); + float lowValue = this->thresholdLowSpinBox->value(); float highValue = this->thresholdHighSpinBox->value(); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index 37aae1308..52edb177a 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -39,6 +39,7 @@ class QwtPlot; namespace caret { + class CaretColorEnumComboBox; class CaretMappableDataFile; class EnumComboBoxTemplate; class FastStatistics; @@ -88,7 +89,6 @@ namespace caret { void scaleFixedPositiveMinimumValueChanged(double value); void scaleFixedPositiveMaximumValueChanged(double value); - void histogramControlChanged(); void histogramResetViewButtonClicked(); void applyAndUpdate(); void applySelections(); @@ -193,9 +193,7 @@ namespace caret { QRadioButton* histogramAllRadioButton; QRadioButton* histogramMatchPaletteRadioButton; - QCheckBox* histogramUsePaletteColors; - - bool isHistogramColored; + CaretColorEnumComboBox* m_histogramColorComboBox; CaretMappableDataFile* caretMappableDataFile; CaretMappableDataFile* m_previousCaretMappableDataFile; diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index 67b9cd68b..a3a6a9553 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -25,6 +25,7 @@ PaletteColorMapping.h PaletteColorMappingSaxReader.h PaletteColorMappingXmlElements.h PaletteEnums.h +PaletteHistogramRangeModeEnum.h PaletteNormalizationModeEnum.h PaletteScalarAndColor.h PaletteThresholdRangeModeEnum.h @@ -34,6 +35,7 @@ PaletteColorBarValuesModeEnum.cxx PaletteColorMapping.cxx PaletteColorMappingSaxReader.cxx PaletteEnums.cxx +PaletteHistogramRangeModeEnum.cxx PaletteNormalizationModeEnum.cxx PaletteScalarAndColor.cxx PaletteThresholdRangeModeEnum.cxx diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 4872e42b7..57b57eb3b 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -134,6 +134,8 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->thresholdShowFailureInGreen = pcm.thresholdShowFailureInGreen; this->thresholdRangeMode = pcm.thresholdRangeMode; this->thresholdNegMinPosMaxLinked = pcm.thresholdNegMinPosMaxLinked; + this->histogramRangeMode = pcm.histogramRangeMode; + this->histogramColor = pcm.histogramColor; this->numericFormatMode = pcm.numericFormatMode; this->precisionDigits = pcm.precisionDigits; this->numericSubdivisionCount = pcm.numericSubdivisionCount; @@ -181,6 +183,8 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->thresholdShowFailureInGreen == pcm.thresholdShowFailureInGreen) && (this->thresholdRangeMode == pcm.thresholdRangeMode) && (this->thresholdNegMinPosMaxLinked == pcm.thresholdNegMinPosMaxLinked) + && (this->histogramRangeMode == pcm.histogramRangeMode) + && (this->histogramColor == pcm.histogramColor) && (this->numericFormatMode == pcm.numericFormatMode) && (this->precisionDigits == pcm.precisionDigits) && (this->numericSubdivisionCount == pcm.numericSubdivisionCount) @@ -225,6 +229,8 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() //this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP; this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; + this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; + this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->numericFormatMode = NumericFormatModeEnum::AUTO; this->precisionDigits = 2; this->numericSubdivisionCount = 0; @@ -341,6 +347,10 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED, this->thresholdNegMinPosMaxLinked); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE, + PaletteHistogramRangeModeEnum::toName(this->histogramRangeMode)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, + CaretColorEnum::toName(this->histogramColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, NumericFormatModeEnum::toName(this->numericFormatMode)); @@ -2713,10 +2723,59 @@ PaletteColorMapping::setThresholdNegMinPosMaxLinked(const bool linked) } } +/** + * @return The histogram range mode. + */ +PaletteHistogramRangeModeEnum::Enum +PaletteColorMapping::getHistogramRangeMode() const +{ + return this->histogramRangeMode; +} + +/** + * Set the histogram range mode. + * + * @param histogramRangeMode + * New value for histogram range mode. + */ +void +PaletteColorMapping::setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode) +{ + if (histogramRangeMode != this->histogramRangeMode) { + this->histogramRangeMode = histogramRangeMode; + setModified(); + } +} + +/** + * @return Color for drawing histogram. + */ +CaretColorEnum::Enum +PaletteColorMapping::getHistogramColor() const +{ + return histogramColor; +} + +/** + * Set the color for drawing the histogram. + * + * @param histogramColor + * New color for the histogram. + */ +void +PaletteColorMapping::setHistogramColor(const CaretColorEnum::Enum histogramColor) +{ + if (histogramColor != this->histogramColor) { + this->histogramColor = histogramColor; + setModified(); + } +} + /** * @return The numeric format mode. */ -NumericFormatModeEnum::Enum PaletteColorMapping::getNumericFormatMode() const +NumericFormatModeEnum::Enum +PaletteColorMapping::getNumericFormatMode() const { return this->numericFormatMode; } diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index a0b57ca4e..af02cac38 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -26,9 +26,11 @@ #include "CaretObject.h" #include "AnnotationColorBarNumericText.h" +#include "CaretColorEnum.h" #include "NumericFormatModeEnum.h" #include "PaletteColorBarValuesModeEnum.h" #include "PaletteEnums.h" +#include "PaletteHistogramRangeModeEnum.h" #include "PaletteThresholdRangeModeEnum.h" #include "XmlException.h" @@ -206,6 +208,14 @@ namespace caret { void setThresholdNegMinPosMaxLinked(const bool linked); + PaletteHistogramRangeModeEnum::Enum getHistogramRangeMode() const; + + void setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode); + + CaretColorEnum::Enum getHistogramColor() const; + + void setHistogramColor(const CaretColorEnum::Enum histogramColor); + NumericFormatModeEnum::Enum getNumericFormatMode() const; int32_t getPrecisionDigits() const; @@ -306,6 +316,10 @@ namespace caret { bool thresholdNegMinPosMaxLinked; + PaletteHistogramRangeModeEnum::Enum histogramRangeMode; + + CaretColorEnum::Enum histogramColor; + NumericFormatModeEnum::Enum numericFormatMode; int32_t precisionDigits; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 92c39b340..944d5ab58 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -300,6 +300,30 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, this->paletteColorMapping->setThresholdRangeMode(PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE); } } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE) { + bool isValid = false; + PaletteHistogramRangeModeEnum::Enum histogramRangeMode = PaletteHistogramRangeModeEnum::fromName(this->elementText, + &isValid); + if (isValid) { + this->paletteColorMapping->setHistogramRangeMode(histogramRangeMode); + } + else { + throw XmlSaxParserException("Invalid PaletteHistogramRangeModeEnum::Enum: " + + this->elementText); + } + } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR) { + bool isValid = false; + CaretColorEnum::Enum histogramColor = CaretColorEnum::fromName(this->elementText, + &isValid); + if (isValid) { + this->paletteColorMapping->setHistogramColor(histogramColor); + } + else { + throw XmlSaxParserException("Invalid CaretColorEnum::Enum: " + + this->elementText); + } + } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE) { bool isValid = false; NumericFormatModeEnum::Enum numericFormatMode = NumericFormatModeEnum::fromName(this->elementText, diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index 820a8f100..72ac6b773 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -45,6 +45,8 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_THRESHOLD_FAILURE_IN_GREEN = "ThresholdFailureInGreen"; static const AString XML_TAG_THRESHOLD_RANGE_MODE = "ThresholdRangeMode"; static const AString XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED = "ThresholdLowHighLinked"; + static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; + static const AString XML_TAG_HISTOGRAM_COLOR = "HistogramColor"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; static const AString XML_TAG_NUMERIC_SUBDIVISIONS = "NumericSubivisions"; diff --git a/src/Palette/PaletteHistogramRangeModeEnum.cxx b/src/Palette/PaletteHistogramRangeModeEnum.cxx new file mode 100644 index 000000000..d20a3375d --- /dev/null +++ b/src/Palette/PaletteHistogramRangeModeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ +#include "PaletteHistogramRangeModeEnum.h" +#undef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::PaletteHistogramRangeModeEnum + * \brief Controls whether histogram shows all data or data using map statistics + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_paletteHistogramRangeModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void paletteHistogramRangeModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "PaletteHistogramRangeModeEnum.h" + * + * Instatiate: + * m_paletteHistogramRangeModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_paletteHistogramRangeModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_paletteHistogramRangeModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(paletteHistogramRangeModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_paletteHistogramRangeModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const PaletteHistogramRangeModeEnum::Enum VARIABLE = m_paletteHistogramRangeModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +PaletteHistogramRangeModeEnum::PaletteHistogramRangeModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +PaletteHistogramRangeModeEnum::~PaletteHistogramRangeModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +PaletteHistogramRangeModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(PaletteHistogramRangeModeEnum(PALETTE_HISTOGRAM_RANGE_ALL, + "PALETTE_HISTOGRAM_RANGE_ALL", + "All")); + + enumData.push_back(PaletteHistogramRangeModeEnum(PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE, + "PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE", + "Match Palette")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const PaletteHistogramRangeModeEnum* +PaletteHistogramRangeModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const PaletteHistogramRangeModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +PaletteHistogramRangeModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +PaletteHistogramRangeModeEnum::Enum +PaletteHistogramRangeModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const PaletteHistogramRangeModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +PaletteHistogramRangeModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +PaletteHistogramRangeModeEnum::Enum +PaletteHistogramRangeModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const PaletteHistogramRangeModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +PaletteHistogramRangeModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +PaletteHistogramRangeModeEnum::Enum +PaletteHistogramRangeModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const PaletteHistogramRangeModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +PaletteHistogramRangeModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +PaletteHistogramRangeModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(PaletteHistogramRangeModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +PaletteHistogramRangeModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(PaletteHistogramRangeModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Palette/PaletteHistogramRangeModeEnum.h b/src/Palette/PaletteHistogramRangeModeEnum.h new file mode 100644 index 000000000..5566dfeac --- /dev/null +++ b/src/Palette/PaletteHistogramRangeModeEnum.h @@ -0,0 +1,104 @@ +#ifndef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ +#define __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class PaletteHistogramRangeModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Use all data for histogram plot */ + PALETTE_HISTOGRAM_RANGE_ALL, + /** Use data matching palette selections */ + PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE + }; + + + ~PaletteHistogramRangeModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + PaletteHistogramRangeModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const PaletteHistogramRangeModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ +std::vector PaletteHistogramRangeModeEnum::enumData; +bool PaletteHistogramRangeModeEnum::initializedFlag = false; +int32_t PaletteHistogramRangeModeEnum::integerCodeCounter = 0; +#endif // __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ -- GitLab From d1fc06ba2a5721f8589ab02a857edd497c083945 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Feb 2017 12:12:49 -0600 Subject: [PATCH 198/755] Added chart drawing bars/envelope controls to Map Settings Dialog. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 9 +- src/Charting/CMakeLists.txt | 2 - src/Charting/ChartTwoDataHistogram.cxx | 15 --- src/Charting/ChartTwoDataHistogram.h | 7 -- .../MapSettingsPaletteColorMappingWidget.cxx | 63 +++++----- .../MapSettingsPaletteColorMappingWidget.h | 5 +- src/Palette/CMakeLists.txt | 2 + src/Palette/PaletteColorMapping.cxx | 30 ++++- src/Palette/PaletteColorMapping.h | 7 ++ src/Palette/PaletteColorMappingSaxReader.cxx | 12 ++ src/Palette/PaletteColorMappingXmlElements.h | 1 + .../PaletteHistogramChartTypeEnum.cxx} | 112 +++++++++--------- .../PaletteHistogramChartTypeEnum.h} | 30 ++--- src/Palette/PaletteHistogramRangeModeEnum.cxx | 2 +- 14 files changed, 160 insertions(+), 137 deletions(-) rename src/{Charting/ChartTwoHistogramViewingTypeEnum.cxx => Palette/PaletteHistogramChartTypeEnum.cxx} (61%) rename src/{Charting/ChartTwoHistogramViewingTypeEnum.h => Palette/PaletteHistogramChartTypeEnum.h} (74%) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 12469a26a..803711b2c 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -460,8 +460,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab std::vector quadVerticesFloatRGBA; std::vector quadVerticesByteRGBA; - switch (histogramData->getHistogramViewingType()) { - case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS: + const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); + CaretAssert(cmdf); + const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); + switch (paletteColorMapping->getHistogramChartType()) { + case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS: { /* * Reserve to prevent reszing of vectors @@ -561,7 +564,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } } break; - case ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE: + case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_ENVELOPE: { /* * Reserve to prevent reszing of vectors diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 365238003..efbc29521 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -45,7 +45,6 @@ ChartTwoDataCartesianHistory.h ChartTwoDataHistogram.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h -ChartTwoHistogramViewingTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixDisplayProperties.h @@ -82,7 +81,6 @@ ChartTwoDataCartesianHistory.cxx ChartTwoDataHistogram.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx -ChartTwoHistogramViewingTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixDisplayProperties.cxx diff --git a/src/Charting/ChartTwoDataHistogram.cxx b/src/Charting/ChartTwoDataHistogram.cxx index 72b1d592c..207b7bdd2 100644 --- a/src/Charting/ChartTwoDataHistogram.cxx +++ b/src/Charting/ChartTwoDataHistogram.cxx @@ -70,8 +70,6 @@ ChartTwoDataHistogram::initializeMembersChartTwoDataHistogram() m_boundsValid = false; m_histogram = NULL; - m_histogramViewingType = ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_BARS; - //m_histogramViewingType = ChartTwoHistogramViewingTypeEnum::HISTOGRAM_VIEWING_ENVELOPE; m_color = CaretColorEnum::RED; std::vector colorEnums; @@ -263,19 +261,6 @@ ChartTwoDataHistogram::setColor(const CaretColorEnum::Enum color) m_color = color; } -ChartTwoHistogramViewingTypeEnum::Enum -ChartTwoDataHistogram::getHistogramViewingType() const -{ - return m_histogramViewingType; -} - -void -ChartTwoDataHistogram::setHistogramViewingType(const ChartTwoHistogramViewingTypeEnum::Enum histogramViewingType) -{ - m_histogramViewingType = histogramViewingType; -} - - /** * Save subclass data to the scene. * diff --git a/src/Charting/ChartTwoDataHistogram.h b/src/Charting/ChartTwoDataHistogram.h index 99f124c97..34dc51b00 100644 --- a/src/Charting/ChartTwoDataHistogram.h +++ b/src/Charting/ChartTwoDataHistogram.h @@ -23,7 +23,6 @@ #include "CaretColorEnum.h" #include "ChartAxisUnitsEnum.h" -#include "ChartTwoHistogramViewingTypeEnum.h" #include "ChartTwoData.h" namespace caret { @@ -46,10 +45,6 @@ namespace caret { void setHistogram(Histogram* histogram); - ChartTwoHistogramViewingTypeEnum::Enum getHistogramViewingType() const; - - void setHistogramViewingType(const ChartTwoHistogramViewingTypeEnum::Enum histogramViewingType); - bool getBounds(float boundsOut[4]) const; CaretColorEnum::Enum getColor() const; @@ -85,8 +80,6 @@ namespace caret { static int32_t caretColorIndex; - ChartTwoHistogramViewingTypeEnum::Enum m_histogramViewingType; - std::vector m_emptyData; SceneClassAssistant* m_sceneAssistant; diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 447bb72e3..8b528bef8 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -735,35 +735,37 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() /* * Control section */ - this->histogramAllRadioButton = new QRadioButton(PaletteHistogramRangeModeEnum::toGuiName(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL)); - WuQtUtilities::setToolTipAndStatusTip(this->histogramAllRadioButton, - "Displays all map data in the histogram"); - this->histogramMatchPaletteRadioButton = new QRadioButton(PaletteHistogramRangeModeEnum::toGuiName(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE)); - WuQtUtilities::setToolTipAndStatusTip(this->histogramMatchPaletteRadioButton, - "Use the palette mapping selections"); - - this->histogramAllRadioButton->setChecked(true); - - QButtonGroup* buttGroup = new QButtonGroup(this); - buttGroup->addButton(this->histogramAllRadioButton); - buttGroup->addButton(this->histogramMatchPaletteRadioButton); - QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), + QLabel* horizRangeLabel = new QLabel("Range"); + m_histogramHorizontalRangeComboBox = new EnumComboBoxTemplate(this); + QObject::connect(this->m_histogramHorizontalRangeComboBox, SIGNAL(itemActivated()), this, SLOT(applyAndUpdate())); - - m_histogramColorComboBox = new CaretColorEnumComboBox("Palette Coloring", + this->m_histogramHorizontalRangeComboBox->setup(); + this->m_histogramHorizontalRangeComboBox->getWidget()->setToolTip("Horizontal range of histogram"); + + QLabel* colorLabel = new QLabel("Color"); + m_histogramColorComboBox = new CaretColorEnumComboBox("Palette", this); WuQtUtilities::setToolTipAndStatusTip(m_histogramColorComboBox->getWidget(), "Set histogram coloring"); QObject::connect(m_histogramColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); + QLabel* chartTypeLabel = new QLabel("Chart"); + m_histogramChartTypeComboBox = new EnumComboBoxTemplate(this); + QObject::connect(this->m_histogramChartTypeComboBox, SIGNAL(itemActivated()), + this, SLOT(applyAndUpdate())); + this->m_histogramChartTypeComboBox->setup(); + this->m_histogramChartTypeComboBox->getWidget()->setToolTip("Set type of chart drawn"); + QWidget* controlWidget = new QWidget(); QGridLayout* controlLayout = new QGridLayout(controlWidget); this->setLayoutSpacingAndMargins(controlLayout); - controlLayout->addWidget(this->histogramAllRadioButton); - controlLayout->addWidget(this->histogramMatchPaletteRadioButton); - controlLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); - controlLayout->addWidget(m_histogramColorComboBox->getWidget()); + controlLayout->addWidget(chartTypeLabel, 0, 0); + controlLayout->addWidget(m_histogramChartTypeComboBox->getWidget(), 0, 1); + controlLayout->addWidget(colorLabel, 1, 0); + controlLayout->addWidget(m_histogramColorComboBox->getWidget(), 1, 1); + controlLayout->addWidget(horizRangeLabel, 2, 0); + controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), 2, 1); controlWidget->setFixedSize(controlWidget->sizeHint()); /* @@ -1611,17 +1613,12 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile this->interpolateColorsCheckBox->setChecked(this->paletteColorMapping->isInterpolatePaletteFlag()); - switch (this->paletteColorMapping->getHistogramRangeMode()) { - case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: - this->histogramAllRadioButton->setChecked(true); - break; - case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: - this->histogramMatchPaletteRadioButton->setChecked(true); - break; - } - m_histogramColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramColor()); + m_histogramChartTypeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramChartType()); + + m_histogramHorizontalRangeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramRangeMode()); + updateThresholdSection(); float minValue = 0.0; @@ -2132,14 +2129,10 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setInterpolatePaletteFlag(this->interpolateColorsCheckBox->isChecked()); - if (this->histogramAllRadioButton->isChecked()) { - this->paletteColorMapping->setHistogramRangeMode(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL); - } - else if (this->histogramMatchPaletteRadioButton->isChecked()) { - this->paletteColorMapping->setHistogramRangeMode(PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE); - } this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); - + this->paletteColorMapping->setHistogramChartType(m_histogramChartTypeComboBox->getSelectedItem()); + this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); + float lowValue = this->thresholdLowSpinBox->value(); float highValue = this->thresholdHighSpinBox->value(); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index 52edb177a..1a646d1ef 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -190,11 +190,12 @@ namespace caret { QComboBox* m_normalizationModeComboBox; - QRadioButton* histogramAllRadioButton; - QRadioButton* histogramMatchPaletteRadioButton; + EnumComboBoxTemplate* m_histogramHorizontalRangeComboBox; CaretColorEnumComboBox* m_histogramColorComboBox; + EnumComboBoxTemplate* m_histogramChartTypeComboBox; + CaretMappableDataFile* caretMappableDataFile; CaretMappableDataFile* m_previousCaretMappableDataFile; diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index a3a6a9553..d64f78f19 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -25,6 +25,7 @@ PaletteColorMapping.h PaletteColorMappingSaxReader.h PaletteColorMappingXmlElements.h PaletteEnums.h +PaletteHistogramChartTypeEnum.h PaletteHistogramRangeModeEnum.h PaletteNormalizationModeEnum.h PaletteScalarAndColor.h @@ -35,6 +36,7 @@ PaletteColorBarValuesModeEnum.cxx PaletteColorMapping.cxx PaletteColorMappingSaxReader.cxx PaletteEnums.cxx +PaletteHistogramChartTypeEnum.cxx PaletteHistogramRangeModeEnum.cxx PaletteNormalizationModeEnum.cxx PaletteScalarAndColor.cxx diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 57b57eb3b..810b8faca 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -135,6 +135,7 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->thresholdRangeMode = pcm.thresholdRangeMode; this->thresholdNegMinPosMaxLinked = pcm.thresholdNegMinPosMaxLinked; this->histogramRangeMode = pcm.histogramRangeMode; + this->histogramChartType = pcm.histogramChartType; this->histogramColor = pcm.histogramColor; this->numericFormatMode = pcm.numericFormatMode; this->precisionDigits = pcm.precisionDigits; @@ -184,6 +185,7 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->thresholdRangeMode == pcm.thresholdRangeMode) && (this->thresholdNegMinPosMaxLinked == pcm.thresholdNegMinPosMaxLinked) && (this->histogramRangeMode == pcm.histogramRangeMode) + && (this->histogramChartType == pcm.histogramChartType) && (this->histogramColor == pcm.histogramColor) && (this->numericFormatMode == pcm.numericFormatMode) && (this->precisionDigits == pcm.precisionDigits) @@ -230,6 +232,7 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; + this->histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->numericFormatMode = NumericFormatModeEnum::AUTO; this->precisionDigits = 2; @@ -349,9 +352,10 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) this->thresholdNegMinPosMaxLinked); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE, PaletteHistogramRangeModeEnum::toName(this->histogramRangeMode)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_CHART_TYPE, + PaletteHistogramChartTypeEnum::toName(this->histogramChartType)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, CaretColorEnum::toName(this->histogramColor)); - xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, NumericFormatModeEnum::toName(this->numericFormatMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS, @@ -2747,6 +2751,30 @@ PaletteColorMapping::setHistogramRangeMode(const PaletteHistogramRangeModeEnum:: } } +/** + * @return The histogram chart type. + */ +PaletteHistogramChartTypeEnum::Enum PaletteColorMapping::getHistogramChartType() const +{ + return this->histogramChartType; +} + +/** + * Set the histogram chart type. + * + * @param histogramChartType + * New value for histogram chart type + */ +void +PaletteColorMapping::setHistogramChartType(const PaletteHistogramChartTypeEnum::Enum histogramChartType) +{ + if (histogramChartType != this->histogramChartType) { + this->histogramChartType = histogramChartType; + setModified(); + } +} + + /** * @return Color for drawing histogram. */ diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index af02cac38..11371f1a0 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -30,6 +30,7 @@ #include "NumericFormatModeEnum.h" #include "PaletteColorBarValuesModeEnum.h" #include "PaletteEnums.h" +#include "PaletteHistogramChartTypeEnum.h" #include "PaletteHistogramRangeModeEnum.h" #include "PaletteThresholdRangeModeEnum.h" #include "XmlException.h" @@ -212,6 +213,10 @@ namespace caret { void setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode); + PaletteHistogramChartTypeEnum::Enum getHistogramChartType() const; + + void setHistogramChartType(const PaletteHistogramChartTypeEnum::Enum histogramChartType); + CaretColorEnum::Enum getHistogramColor() const; void setHistogramColor(const CaretColorEnum::Enum histogramColor); @@ -318,6 +323,8 @@ namespace caret { PaletteHistogramRangeModeEnum::Enum histogramRangeMode; + PaletteHistogramChartTypeEnum::Enum histogramChartType; + CaretColorEnum::Enum histogramColor; NumericFormatModeEnum::Enum numericFormatMode; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 944d5ab58..908c36798 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -312,6 +312,18 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, + this->elementText); } } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_CHART_TYPE) { + bool isValid = false; + PaletteHistogramChartTypeEnum::Enum histogramChartType = PaletteHistogramChartTypeEnum::fromName(this->elementText, + &isValid); + if (isValid) { + this->paletteColorMapping->setHistogramChartType(histogramChartType); + } + else { + throw XmlSaxParserException("Invalid PaletteHistogramChartTypeEnum::Enum: " + + this->elementText); + } + } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR) { bool isValid = false; CaretColorEnum::Enum histogramColor = CaretColorEnum::fromName(this->elementText, diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index 72ac6b773..a2ba5be19 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -46,6 +46,7 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_THRESHOLD_RANGE_MODE = "ThresholdRangeMode"; static const AString XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED = "ThresholdLowHighLinked"; static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; + static const AString XML_TAG_HISTOGRAM_CHART_TYPE = "HistogramChartType"; static const AString XML_TAG_HISTOGRAM_COLOR = "HistogramColor"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; diff --git a/src/Charting/ChartTwoHistogramViewingTypeEnum.cxx b/src/Palette/PaletteHistogramChartTypeEnum.cxx similarity index 61% rename from src/Charting/ChartTwoHistogramViewingTypeEnum.cxx rename to src/Palette/PaletteHistogramChartTypeEnum.cxx index 856ce7205..6f200015b 100644 --- a/src/Charting/ChartTwoHistogramViewingTypeEnum.cxx +++ b/src/Palette/PaletteHistogramChartTypeEnum.cxx @@ -20,9 +20,9 @@ /*LICENSE_END*/ #include -#define __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ -#include "ChartTwoHistogramViewingTypeEnum.h" -#undef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ +#define __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ +#include "PaletteHistogramChartTypeEnum.h" +#undef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,8 +30,8 @@ using namespace caret; /** - * \class caret::ChartTwoHistogramViewingTypeEnum - * \brief Type of histogram viewing by user. + * \class caret::PaletteHistogramChartTypeEnum + * \brief Type of chart displayed for histogram. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -40,30 +40,30 @@ using namespace caret; * class EnumComboBoxTemplate; * * Declare the member: - * EnumComboBoxTemplate* m_chartTwoHistogramViewingTypeEnumComboBox; + * EnumComboBoxTemplate* m_paletteHistogramChartTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: - * void chartTwoHistogramViewingTypeEnumComboBoxItemActivated(); + * void paletteHistogramChartTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "ChartTwoHistogramViewingTypeEnum.h" + * #include "PaletteHistogramChartTypeEnum.h" * * Instatiate: - * m_chartTwoHistogramViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_chartTwoHistogramViewingTypeEnumComboBox->setup(); + * m_paletteHistogramChartTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_paletteHistogramChartTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: - * QObject::connect(m_chartTwoHistogramViewingTypeEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(chartTwoHistogramViewingTypeEnumComboBoxItemActivated())); + * QObject::connect(m_paletteHistogramChartTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(paletteHistogramChartTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_chartTwoHistogramViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_paletteHistogramChartTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const ChartTwoHistogramViewingTypeEnum::Enum VARIABLE = m_chartTwoHistogramViewingTypeEnumComboBox->getSelectedItem(); + * const PaletteHistogramChartTypeEnum::Enum VARIABLE = m_paletteHistogramChartTypeEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -ChartTwoHistogramViewingTypeEnum::ChartTwoHistogramViewingTypeEnum(const Enum enumValue, +PaletteHistogramChartTypeEnum::PaletteHistogramChartTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,7 +91,7 @@ ChartTwoHistogramViewingTypeEnum::ChartTwoHistogramViewingTypeEnum(const Enum en /** * Destructor. */ -ChartTwoHistogramViewingTypeEnum::~ChartTwoHistogramViewingTypeEnum() +PaletteHistogramChartTypeEnum::~PaletteHistogramChartTypeEnum() { } @@ -99,19 +99,19 @@ ChartTwoHistogramViewingTypeEnum::~ChartTwoHistogramViewingTypeEnum() * Initialize the enumerated metadata. */ void -ChartTwoHistogramViewingTypeEnum::initialize() +PaletteHistogramChartTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(ChartTwoHistogramViewingTypeEnum(HISTOGRAM_VIEWING_BARS, - "HISTOGRAM_VIEWING_BARS", + enumData.push_back(PaletteHistogramChartTypeEnum(PALETTE_HISTOGRAM_CHART_BARS, + "PALETTE_HISTOGRAM_CHART_BARS", "Bars")); - enumData.push_back(ChartTwoHistogramViewingTypeEnum(HISTOGRAM_VIEWING_ENVELOPE, - "HISTOGRAM_VIEWING_ENVELOPE", + enumData.push_back(PaletteHistogramChartTypeEnum(PALETTE_HISTOGRAM_CHART_ENVELOPE, + "PALETTE_HISTOGRAM_CHART_ENVELOPE", "Envelope")); } @@ -123,14 +123,14 @@ ChartTwoHistogramViewingTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const ChartTwoHistogramViewingTypeEnum* -ChartTwoHistogramViewingTypeEnum::findData(const Enum enumValue) +const PaletteHistogramChartTypeEnum* +PaletteHistogramChartTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const ChartTwoHistogramViewingTypeEnum* d = &enumData[i]; + const PaletteHistogramChartTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -147,10 +147,10 @@ ChartTwoHistogramViewingTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -ChartTwoHistogramViewingTypeEnum::toName(Enum enumValue) { +PaletteHistogramChartTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -164,18 +164,18 @@ ChartTwoHistogramViewingTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -ChartTwoHistogramViewingTypeEnum::Enum -ChartTwoHistogramViewingTypeEnum::fromName(const AString& name, bool* isValidOut) +PaletteHistogramChartTypeEnum::Enum +PaletteHistogramChartTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoHistogramViewingTypeEnum& d = *iter; + const PaletteHistogramChartTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -187,7 +187,7 @@ ChartTwoHistogramViewingTypeEnum::fromName(const AString& name, bool* isValidOut *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); } return enumValue; } @@ -200,10 +200,10 @@ ChartTwoHistogramViewingTypeEnum::fromName(const AString& name, bool* isValidOut * String representing enumerated value. */ AString -ChartTwoHistogramViewingTypeEnum::toGuiName(Enum enumValue) { +PaletteHistogramChartTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -217,18 +217,18 @@ ChartTwoHistogramViewingTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -ChartTwoHistogramViewingTypeEnum::Enum -ChartTwoHistogramViewingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +PaletteHistogramChartTypeEnum::Enum +PaletteHistogramChartTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoHistogramViewingTypeEnum& d = *iter; + const PaletteHistogramChartTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -240,7 +240,7 @@ ChartTwoHistogramViewingTypeEnum::fromGuiName(const AString& guiName, bool* isVa *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); } return enumValue; } @@ -252,10 +252,10 @@ ChartTwoHistogramViewingTypeEnum::fromGuiName(const AString& guiName, bool* isVa * Integer code for data type. */ int32_t -ChartTwoHistogramViewingTypeEnum::toIntegerCode(Enum enumValue) +PaletteHistogramChartTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const ChartTwoHistogramViewingTypeEnum* enumInstance = findData(enumValue); + const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -270,18 +270,18 @@ ChartTwoHistogramViewingTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -ChartTwoHistogramViewingTypeEnum::Enum -ChartTwoHistogramViewingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +PaletteHistogramChartTypeEnum::Enum +PaletteHistogramChartTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = ChartTwoHistogramViewingTypeEnum::enumData[0].enumValue; + Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const ChartTwoHistogramViewingTypeEnum& enumInstance = *iter; + const PaletteHistogramChartTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -293,7 +293,7 @@ ChartTwoHistogramViewingTypeEnum::fromIntegerCode(const int32_t integerCode, boo *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoHistogramViewingTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); } return enumValue; } @@ -306,13 +306,13 @@ ChartTwoHistogramViewingTypeEnum::fromIntegerCode(const int32_t integerCode, boo * A vector that is OUTPUT containing all of the enumerated values. */ void -ChartTwoHistogramViewingTypeEnum::getAllEnums(std::vector& allEnums) +PaletteHistogramChartTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -328,16 +328,16 @@ ChartTwoHistogramViewingTypeEnum::getAllEnums(std::vector& allNames, const bool isSorted) +PaletteHistogramChartTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(ChartTwoHistogramViewingTypeEnum::toName(iter->enumValue)); + allNames.push_back(PaletteHistogramChartTypeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -354,16 +354,16 @@ ChartTwoHistogramViewingTypeEnum::getAllNames(std::vector& allNames, co * If true, the names are sorted in alphabetical order. */ void -ChartTwoHistogramViewingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +PaletteHistogramChartTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(ChartTwoHistogramViewingTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(PaletteHistogramChartTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Charting/ChartTwoHistogramViewingTypeEnum.h b/src/Palette/PaletteHistogramChartTypeEnum.h similarity index 74% rename from src/Charting/ChartTwoHistogramViewingTypeEnum.h rename to src/Palette/PaletteHistogramChartTypeEnum.h index 744c41491..82d508e85 100644 --- a/src/Charting/ChartTwoHistogramViewingTypeEnum.h +++ b/src/Palette/PaletteHistogramChartTypeEnum.h @@ -1,5 +1,5 @@ -#ifndef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ -#define __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ +#ifndef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ +#define __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class ChartTwoHistogramViewingTypeEnum { +class PaletteHistogramChartTypeEnum { public: /** @@ -36,13 +36,13 @@ public: */ enum Enum { /** */ - HISTOGRAM_VIEWING_BARS, + PALETTE_HISTOGRAM_CHART_BARS, /** */ - HISTOGRAM_VIEWING_ENVELOPE + PALETTE_HISTOGRAM_CHART_ENVELOPE }; - ~ChartTwoHistogramViewingTypeEnum(); + ~PaletteHistogramChartTypeEnum(); static AString toName(Enum enumValue); @@ -63,14 +63,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - ChartTwoHistogramViewingTypeEnum(const Enum enumValue, + PaletteHistogramChartTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const ChartTwoHistogramViewingTypeEnum* findData(const Enum enumValue); + static const PaletteHistogramChartTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -94,11 +94,11 @@ private: AString guiName; }; -#ifdef __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ -std::vector ChartTwoHistogramViewingTypeEnum::enumData; -bool ChartTwoHistogramViewingTypeEnum::initializedFlag = false; -int32_t ChartTwoHistogramViewingTypeEnum::integerCodeCounter = 0; -#endif // __CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_DECLARE__ +#ifdef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ +std::vector PaletteHistogramChartTypeEnum::enumData; +bool PaletteHistogramChartTypeEnum::initializedFlag = false; +int32_t PaletteHistogramChartTypeEnum::integerCodeCounter = 0; +#endif // __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ } // namespace -#endif //__CHART_TWO_HISTOGRAM_VIEWING_TYPE_ENUM_H__ +#endif //__PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ diff --git a/src/Palette/PaletteHistogramRangeModeEnum.cxx b/src/Palette/PaletteHistogramRangeModeEnum.cxx index d20a3375d..1cf0d5a3e 100644 --- a/src/Palette/PaletteHistogramRangeModeEnum.cxx +++ b/src/Palette/PaletteHistogramRangeModeEnum.cxx @@ -112,7 +112,7 @@ PaletteHistogramRangeModeEnum::initialize() enumData.push_back(PaletteHistogramRangeModeEnum(PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE, "PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE", - "Match Palette")); + "Palette")); } -- GitLab From 48e644a4bd0cd1418267960e23d192821c2ff024 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Feb 2017 09:10:05 -0600 Subject: [PATCH 199/755] Continuing charting development. Now able to launch Overlay and Map Settings Dialog from Chart Overlay panel. --- src/Brain/CMakeLists.txt | 2 + src/Brain/ChartTwoOverlay.cxx | 17 ++-- src/Brain/EventChartOverlayValidate.cxx | 82 +++++++++++++++ src/Brain/EventChartOverlayValidate.h | 66 +++++++++++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/GuiQt/GuiManager.cxx | 7 +- src/GuiQt/OverlaySettingsEditorDialog.cxx | 115 +++++++++++++++++----- src/GuiQt/OverlaySettingsEditorDialog.h | 14 ++- 10 files changed, 273 insertions(+), 37 deletions(-) create mode 100644 src/Brain/EventChartOverlayValidate.cxx create mode 100644 src/Brain/EventChartOverlayValidate.h diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 3bac9d2a1..3f8cca525 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -109,6 +109,7 @@ EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h EventBrowserTabNew.h +EventChartOverlayValidate.h EventDataFileAdd.h EventDataFileDelete.h EventDataFileRead.h @@ -254,6 +255,7 @@ EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx EventBrowserTabNew.cxx +EventChartOverlayValidate.cxx EventDataFileAdd.cxx EventDataFileDelete.cxx EventDataFileRead.cxx diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 4ce9c0087..6458763b9 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -33,6 +33,7 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartTwoOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" +#include "EventChartOverlayValidate.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" @@ -92,8 +93,8 @@ m_overlayIndex(overlayIndex) m_sceneAssistant->add("m_selectedHistogramMapIndex", &m_selectedHistogramMapIndex); m_sceneAssistant->add("m_allHistogramMapsSelectedFlag", &m_allHistogramMapsSelectedFlag); -// EventManager::get()->addEventListener(this, -// EventTypeEnum::EVENT_OVERLAY_VALIDATE); + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE); } /** @@ -114,12 +115,12 @@ ChartTwoOverlay::~ChartTwoOverlay() void ChartTwoOverlay::receiveEvent(Event* event) { -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } + if (event->getEventType() == EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE) { + EventChartOverlayValidate* eov = dynamic_cast(event); + CaretAssert(eov); + eov->testValidChartOverlay(this); + eov->setEventProcessed(); + } } /** diff --git a/src/Brain/EventChartOverlayValidate.cxx b/src/Brain/EventChartOverlayValidate.cxx new file mode 100644 index 000000000..61d2b7f9f --- /dev/null +++ b/src/Brain/EventChartOverlayValidate.cxx @@ -0,0 +1,82 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ +#include "EventChartOverlayValidate.h" +#undef __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ + +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventChartOverlayValidate + * \brief Test a chart overlay for validity (it exists). + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param chartOverlay + * Chart overlay for verification. + */ +EventChartOverlayValidate::EventChartOverlayValidate(const ChartTwoOverlay* chartOverlay) +: Event(EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE), + m_chartOverlay(chartOverlay) +{ + m_valid = false; +} + +/** + * Destructor. + */ +EventChartOverlayValidate::~EventChartOverlayValidate() +{ + +} + +/** + * @return true if the chart overlay was found to be valid. + */ +bool +EventChartOverlayValidate::isValidChartOverlay() const +{ + return m_valid; +} + +/** + * Set the validity if the given overlay is the overlay + * that was passed to the constructor. + * + * @param chartOverlay + * Chart overlay tested for match. + */ +void +EventChartOverlayValidate::testValidChartOverlay(const ChartTwoOverlay* chartOverlay) +{ + if (m_chartOverlay == chartOverlay) { + m_valid = true; + } +} + diff --git a/src/Brain/EventChartOverlayValidate.h b/src/Brain/EventChartOverlayValidate.h new file mode 100644 index 000000000..7f4c8dec9 --- /dev/null +++ b/src/Brain/EventChartOverlayValidate.h @@ -0,0 +1,66 @@ +#ifndef __EVENT_CHART_OVERLAY_VALIDATE_H__ +#define __EVENT_CHART_OVERLAY_VALIDATE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "Event.h" + +namespace caret { + + class ChartTwoOverlay; + + class EventChartOverlayValidate : public Event { + + public: + EventChartOverlayValidate(const ChartTwoOverlay* chartOverlay); + + virtual ~EventChartOverlayValidate(); + + bool isValidChartOverlay() const; + + void testValidChartOverlay(const ChartTwoOverlay* chartOverlay); + + private: + EventChartOverlayValidate(const EventChartOverlayValidate&); + + EventChartOverlayValidate& operator=(const EventChartOverlayValidate&); + + public: + + // ADD_NEW_METHODS_HERE + + private: + + // ADD_NEW_MEMBERS_HERE + + const ChartTwoOverlay* m_chartOverlay; + + bool m_valid; + + }; + +#ifdef __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ + // +#endif // __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ + +} // namespace +#endif //__EVENT_CHART_OVERLAY_VALIDATE_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index d803f50b7..8b9bef85a 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -489,6 +489,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: + case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_DATA_FILE_ADD: case EventTypeEnum::EVENT_DATA_FILE_DELETE: case EventTypeEnum::EVENT_DATA_FILE_READ: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 1bf2d1bc3..2dbecd050 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -161,6 +161,10 @@ EventTypeEnum::initialize() "EVENT_CHART_MATRIX_YOKING_VALIDATION", "Validate Yoking of matrix chart's rows/columns")); + enumData.push_back(EventTypeEnum(EVENT_CHART_OVERLAY_VALIDATE, + "EVENT_CHART_OVERLAY_VALIDATE", + "Validate a chart overlay for validity (it exists)")); + enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_ADD, "EVENT_DATA_FILE_ADD", "Add a data file to the Brain")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index a27272f3d..ecf392c93 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -86,6 +86,8 @@ public: EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, /** Event for yoking the loading of matrix chart rows/columns */ EVENT_CHART_MATRIX_YOKING_VALIDATION, + /** Validate that chart overlay is valid (it exists). */ + EVENT_CHART_OVERLAY_VALIDATE, /** Add a data file into the Brain*/ EVENT_DATA_FILE_ADD, /** Delete a data file from the brain */ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 1d0c25706..c99630871 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -1259,6 +1259,7 @@ GuiManager::receiveEvent(Event* event) BrainBrowserWindow* browserWindow = m_brainBrowserWindows[browserWindowIndex]; CaretAssert(browserWindow); Overlay* overlay = mapEditEvent->getOverlay(); + ChartTwoOverlay* chartOverlay = mapEditEvent->getChartTwoOverlay(); switch (mode) { case EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED: @@ -1267,7 +1268,8 @@ GuiManager::receiveEvent(Event* event) overlayEditorIter != m_overlaySettingsEditors.end(); overlayEditorIter++) { OverlaySettingsEditorDialog* med = *overlayEditorIter; - med->updateIfThisOverlayIsInDialog(overlay); + med->updateIfThisOverlayIsInDialog(overlay, + chartOverlay); } } break; @@ -1316,7 +1318,8 @@ GuiManager::receiveEvent(Event* event) } } - overlayEditor->updateDialogContent(overlay); + overlayEditor->updateDialogContent(overlay, + chartOverlay); overlayEditor->show(); overlayEditor->raise(); overlayEditor->activateWindow(); diff --git a/src/GuiQt/OverlaySettingsEditorDialog.cxx b/src/GuiQt/OverlaySettingsEditorDialog.cxx index 95a3fbcf0..d45f29bc2 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.cxx +++ b/src/GuiQt/OverlaySettingsEditorDialog.cxx @@ -32,8 +32,10 @@ #undef __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ #include "CaretMappableDataFile.h" +#include "ChartTwoOverlay.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiConnectivityMatrixParcelFile.h" +#include "EventChartOverlayValidate.h" #include "EventDataFileDelete.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" @@ -78,6 +80,8 @@ OverlaySettingsEditorDialog::OverlaySettingsEditorDialog(QWidget* parent) m_caretMappableDataFile = NULL; m_mapIndex = -1; + m_brainordinateOverlay = NULL; + m_chartOverlay = NULL; /* * No apply button @@ -217,36 +221,79 @@ OverlaySettingsEditorDialog::focusInEvent(QFocusEvent* event) /** * Update if the given overlay is displayed in the dialog. * - * @param overlay - * The overlay. + * @param brainordinateOverlay + * Brainordinate overlay for the dialog. + * @param chartOverlay + * Chart overlay for the dialog. */ void -OverlaySettingsEditorDialog::updateIfThisOverlayIsInDialog(Overlay* overlay) +OverlaySettingsEditorDialog::updateIfThisOverlayIsInDialog(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay) { - if (m_overlay == overlay) { - updateDialogContent(m_overlay); + if (m_brainordinateOverlay != NULL) { + if (m_brainordinateOverlay == brainordinateOverlay) { + updateDialogContent(m_brainordinateOverlay, + NULL); + } + } + else if (m_chartOverlay != NULL) { + if (m_chartOverlay == chartOverlay) { + updateDialogContent(NULL, + m_chartOverlay); + } } } /** * May be called to update the dialog's content. * - * @param overlay - * Overlay for the dialog. + * @param brainordinateOverlay + * Brainordinate overlay for the dialog. + * @param chartOverlay + * Chart overlay for the dialog. */ void -OverlaySettingsEditorDialog::updateDialogContent(Overlay* overlay) +OverlaySettingsEditorDialog::updateDialogContent(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay) { + updateDialogContentPrivate(brainordinateOverlay, + chartOverlay); +} + +/** + * Update the dialog's content. Only one of the parameters + * should be non-NULL. + * + * @param brainordinateOverlay + * Brainordinate overlay for the dialog. + * @param chartOverlay + * Chart overlay for the dialog. + */ +void +OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay) +{ + if ((brainordinateOverlay != NULL) + && (chartOverlay != NULL)) { + CaretAssert(0); // only one should be non-NULL + } + const int32_t selectedTabIndex = m_tabWidget->currentIndex(); - m_overlay = overlay; + m_brainordinateOverlay = brainordinateOverlay; + m_chartOverlay = chartOverlay; + // m_caretMappableDataFile = caretMappableDataFile; // m_mapFileIndex = mapFileIndex; m_caretMappableDataFile = NULL; m_mapIndex = -1; - if (m_overlay != NULL) { - overlay->getSelectionData(m_caretMappableDataFile, - m_mapIndex); + if (m_brainordinateOverlay != NULL) { + m_brainordinateOverlay->getSelectionData(m_caretMappableDataFile, + m_mapIndex); + } + if (m_chartOverlay != NULL) { + m_chartOverlay->getSelectionData(m_caretMappableDataFile, + m_mapIndex); } bool isLabelsValid = false; @@ -274,7 +321,7 @@ OverlaySettingsEditorDialog::updateDialogContent(Overlay* overlay) /* * Update layer widget */ - m_layerWidget->updateContent(m_overlay); + m_layerWidget->updateContent(m_brainordinateOverlay); if (m_caretMappableDataFile->isMappedWithLabelTable()) { if (m_caretMappableDataFile->getMapLabelTable(m_mapIndex) != NULL) { @@ -282,7 +329,7 @@ OverlaySettingsEditorDialog::updateDialogContent(Overlay* overlay) * Update label editor */ isLabelsValid = true; - m_labelsWidget->updateContent(overlay); + m_labelsWidget->updateContent(m_brainordinateOverlay); } } @@ -303,8 +350,14 @@ OverlaySettingsEditorDialog::updateDialogContent(Overlay* overlay) isPaletteValid = true; m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, m_mapIndex); - - m_colorBarWidget->updateContent(m_overlay->getColorBar(), + AnnotationColorBar* colorBar = NULL; + if (m_brainordinateOverlay != NULL) { + colorBar = m_brainordinateOverlay->getColorBar(); + } + else if (m_chartOverlay != NULL) { + colorBar = m_chartOverlay->getColorBar(); + } + m_colorBarWidget->updateContent(colorBar, paletteColorMapping); } } @@ -341,7 +394,7 @@ OverlaySettingsEditorDialog::updateDialogContent(Overlay* overlay) } } - + /* * Set enabled status of tabs @@ -408,15 +461,28 @@ OverlaySettingsEditorDialog::updateDialog() /* * Validate overlay to prevent crash */ - EventOverlayValidate validateOverlayEvent(m_overlay); - EventManager::get()->sendEvent(validateOverlayEvent.getPointer()); - if (validateOverlayEvent.isValidOverlay() == false) { - m_overlay = NULL; + + if (m_brainordinateOverlay != NULL) { + EventOverlayValidate validateOverlayEvent(m_brainordinateOverlay); + EventManager::get()->sendEvent(validateOverlayEvent.getPointer()); + if ( ! validateOverlayEvent.isValidOverlay()) { + m_brainordinateOverlay = NULL; + } } - updateDialogContent(m_overlay); + if (m_chartOverlay != NULL) { + EventChartOverlayValidate validateChartOverlayEvent(m_chartOverlay); + EventManager::get()->sendEvent(validateChartOverlayEvent.getPointer()); + if ( ! validateChartOverlayEvent.isValidChartOverlay()) { + m_chartOverlay = NULL; + } + } + + updateDialogContentPrivate(m_brainordinateOverlay, + m_chartOverlay); - if (m_overlay == NULL) { + if ((m_brainordinateOverlay == NULL) + && (m_chartOverlay == NULL)) { close(); } } @@ -433,7 +499,8 @@ OverlaySettingsEditorDialog::closeButtonPressed() * and we don't want the dialog updating if it is not * visible. */ - updateDialogContent(NULL); + updateDialogContent(NULL, + NULL); /* * Allow this dialog to be reused (checked means DO NOT reuse) diff --git a/src/GuiQt/OverlaySettingsEditorDialog.h b/src/GuiQt/OverlaySettingsEditorDialog.h index d81e275c1..e57b215da 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.h +++ b/src/GuiQt/OverlaySettingsEditorDialog.h @@ -33,6 +33,7 @@ class QTabWidget; namespace caret { class CaretMappableDataFile; + class ChartTwoOverlay; class LabelTableEditorWidget; class MapSettingsColorBarWidget; class MapSettingsFiberTrajectoryWidget; @@ -48,9 +49,11 @@ namespace caret { public: OverlaySettingsEditorDialog(QWidget* parent); - void updateDialogContent(Overlay* overlay); + void updateDialogContent(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay); - void updateIfThisOverlayIsInDialog(Overlay* overlay); + void updateIfThisOverlayIsInDialog(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay); void updateDialog(); @@ -76,6 +79,9 @@ namespace caret { void editLabelTablePushButtonClicked(); private: + void updateDialogContentPrivate(Overlay* brainordinateOverlay, + ChartTwoOverlay* chartOverlay); + QWidget* createWindowOptionsSection(); QWidget* createMapFileAndNameSection(); @@ -90,7 +96,9 @@ namespace caret { CaretMappableDataFile* m_caretMappableDataFile; - Overlay* m_overlay; + Overlay* m_brainordinateOverlay; + + ChartTwoOverlay* m_chartOverlay; int32_t m_mapIndex; -- GitLab From fb8240bb6aa0358170f970e59f8d946b4d6b69ad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Feb 2017 10:54:45 -0600 Subject: [PATCH 200/755] Continuing chart development. Cleanup of ChartTwoDataHistogram class. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 3 - .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 1 - src/Charting/ChartTwoDataHistogram.cxx | 117 ------------------ src/Charting/ChartTwoDataHistogram.h | 20 --- src/Files/ChartableTwoFileHistogramChart.cxx | 2 + 5 files changed, 2 insertions(+), 141 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 803711b2c..96cb92719 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -30,7 +30,6 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" -#include "ChartTwoDataHistogram.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -434,8 +433,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const int32_t mapIndex, const HistogramDrawingInfo& histogramDrawingInfo) { - const ChartTwoDataHistogram* histogramData = histogramChart->getMapHistogramChart(mapIndex); - if ( ! histogramDrawingInfo.isValid()) { return; } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index d449e0eac..2d9125e54 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -28,7 +28,6 @@ namespace caret { class CaretPreferences; - class ChartTwoDataHistogram; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; diff --git a/src/Charting/ChartTwoDataHistogram.cxx b/src/Charting/ChartTwoDataHistogram.cxx index 207b7bdd2..c2c3a87bd 100644 --- a/src/Charting/ChartTwoDataHistogram.cxx +++ b/src/Charting/ChartTwoDataHistogram.cxx @@ -23,13 +23,7 @@ #include "ChartTwoDataHistogram.h" #undef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ -#include -#include - -#include - #include "CaretAssert.h" -#include "ChartPoint.h" #include "Histogram.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -67,38 +61,9 @@ ChartTwoDataHistogram::~ChartTwoDataHistogram() void ChartTwoDataHistogram::initializeMembersChartTwoDataHistogram() { - m_boundsValid = false; m_histogram = NULL; - m_color = CaretColorEnum::RED; - - std::vector colorEnums; - CaretColorEnum::getColorEnums(colorEnums); - const int32_t numCaretColors = static_cast(colorEnums.size()); - - bool colorFound = false; - while ( ! colorFound) { - ChartTwoDataHistogram::caretColorIndex++; - if (ChartTwoDataHistogram::caretColorIndex >= numCaretColors) { - ChartTwoDataHistogram::caretColorIndex = 0; - } - - if (colorEnums[ChartTwoDataHistogram::caretColorIndex] == CaretColorEnum::BLACK) { - /* do not use black */ - } - else if (colorEnums[ChartTwoDataHistogram::caretColorIndex] == CaretColorEnum::WHITE) { - /* do not use white */ - } - else { - m_color = colorEnums[ChartTwoDataHistogram::caretColorIndex]; - colorFound = true; - } - } - m_sceneAssistant = new SceneClassAssistant(); - - m_sceneAssistant->add("m_color", - &m_color); } /** @@ -155,7 +120,6 @@ void ChartTwoDataHistogram::copyHelperChartTwoDataHistogram(const ChartTwoDataHistogram& obj) { CaretAssert(0); - m_color = obj.m_color; //m_histogram = obj.m_histogram; } @@ -180,87 +144,6 @@ ChartTwoDataHistogram::setHistogram(Histogram* histogram) m_histogram = histogram; } -/** - * @return Reference to histogram values. Vector is empty - * if histogram is invalid. - */ -const std::vector& -ChartTwoDataHistogram::getHistogramValues() const -{ - if (m_histogram != NULL) { - return m_histogram->getHistogramDisplay(); - } - - return m_emptyData; -} - - -/** - * Get the bounds of all of the points. - * - * @param boundsOut - * On exit contains bounds (xmin, xmax, ymin, ymax). - * @return - * True if bounds valid, else false. - */ -bool -ChartTwoDataHistogram::getBounds(float boundsOut[4]) const -{ - if (! m_boundsValid) { - m_bounds[0] = 0.0; - m_bounds[1] = 0.0; - m_bounds[2] = 0.0; - m_bounds[3] = 0.0; - - if (m_histogram != NULL) { - const int32_t numBuckets = m_histogram->getNumberOfBuckets(); - if (numBuckets > 0) { - m_histogram->getRange(m_bounds[0], - m_bounds[1]); - - const std::vector& values = getHistogramValues(); - m_bounds[2] = 0.0; - if (values.empty()) { - m_bounds[3] = 0.0; - } - else { - m_bounds[3] = *std::max_element(values.begin(), - values.end()); - } - m_boundsValid = true; - } - } - } - - boundsOut[0] = m_bounds[0]; - boundsOut[1] = m_bounds[1]; - boundsOut[2] = m_bounds[2]; - boundsOut[3] = m_bounds[3]; - - return m_boundsValid; -} - -/** - * @return Color for chart - */ -CaretColorEnum::Enum -ChartTwoDataHistogram::getColor() const -{ - return m_color; -} - -/** - * Set the color for the chart. - * - * @param color - * New color for chart. - */ -void -ChartTwoDataHistogram::setColor(const CaretColorEnum::Enum color) -{ - m_color = color; -} - /** * Save subclass data to the scene. * diff --git a/src/Charting/ChartTwoDataHistogram.h b/src/Charting/ChartTwoDataHistogram.h index 34dc51b00..d63433251 100644 --- a/src/Charting/ChartTwoDataHistogram.h +++ b/src/Charting/ChartTwoDataHistogram.h @@ -21,7 +21,6 @@ */ /*LICENSE_END*/ -#include "CaretColorEnum.h" #include "ChartAxisUnitsEnum.h" #include "ChartTwoData.h" @@ -39,18 +38,10 @@ namespace caret { virtual ChartTwoData* clone() const; - const std::vector& getHistogramValues() const; - const Histogram* getHistogram() const; void setHistogram(Histogram* histogram); - bool getBounds(float boundsOut[4]) const; - - CaretColorEnum::Enum getColor() const; - - void setColor(const CaretColorEnum::Enum color); - // ADD_NEW_METHODS_HERE protected: @@ -72,16 +63,6 @@ namespace caret { Histogram* m_histogram; - mutable float m_bounds[4]; - - mutable bool m_boundsValid; - - CaretColorEnum::Enum m_color; - - static int32_t caretColorIndex; - - std::vector m_emptyData; - SceneClassAssistant* m_sceneAssistant; @@ -90,7 +71,6 @@ namespace caret { }; #ifdef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ - int32_t ChartTwoDataHistogram::caretColorIndex = 0; #endif // __CHART_TWO_DATA_HISTOGRAM_DECLARE__ } // namespace diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index ec8c5de60..aeda9b5bd 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -127,6 +127,8 @@ ChartableTwoFileHistogramChart::isEmpty() const const ChartTwoDataHistogram* ChartableTwoFileHistogramChart::getMapHistogramChart(const int32_t mapIndex) const { + CaretAssertToDoFatal(); // This class may not be needed + ChartTwoDataHistogram* histogramChartOut = NULL; std::map::iterator iter = m_indexHistogramsMap.find(mapIndex); -- GitLab From 124cbb1b81dcad537a0e69e12d5061b9fa15bb6a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Feb 2017 15:29:20 -0600 Subject: [PATCH 201/755] Continuing charting development. Implemented 'All Maps' option. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 7 +- src/Files/CaretMappableDataFile.cxx | 82 ++++++++++++------- src/Files/CaretMappableDataFile.h | 1 + .../MapSettingsPaletteColorMappingWidget.cxx | 63 +++++++++++++- 4 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 96cb92719..2a386d679 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -340,9 +340,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() AString errorMessage; CaretAssertVectorIndex(histogramDrawingInfoVector, histoIndex); if (mapFile->getMapHistogramDrawingInfo(mapIndex, - false, - *histogramDrawingInfoVector[histoIndex], - errorMessage)) { + chartOverlay->isAllMapsSelected(), + false, + *histogramDrawingInfoVector[histoIndex], + errorMessage)) { float bounds[4]; if (histogramDrawingInfoVector[histoIndex]->getBounds(bounds)) { xMin = std::min(xMin, bounds[0]); diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 60cc9a83d..5bb7ecf6a 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -804,6 +804,8 @@ CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformatio * * @param mapIndex * Index of map. + * @param useDataFromAllMapsFlag + * If true, data from ALL maps is used not just the map specified by map index. * @param addEndPointForQwtFlag * If true, add point at end for drawing with Qwt. * @param histogramDrawingInfoOut @@ -813,6 +815,7 @@ CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformatio */ bool CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, + const bool useDataFromAllMapsFlag, const bool addEndPointForQwtFlag, HistogramDrawingInfo& histogramDrawingInfoOut, AString& errorMessageOut) @@ -844,13 +847,18 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, } FastStatistics* statistics = NULL; - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(getFileFastStatistics()); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(getMapFastStatistics(mapIndex)); - break; + if (useDataFromAllMapsFlag) { + statistics = const_cast(getFileFastStatistics()); + } + else { + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(getMapFastStatistics(mapIndex)); + break; + } } CaretAssert(statistics); @@ -917,32 +925,46 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, leastPos = 0.0; } - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - histogram = getFileHistogram(mostPos, - leastPos, - leastNeg, - mostNeg, - isZeroIncluded); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - histogram = getMapHistogram(mapIndex, - mostPos, - leastPos, - leastNeg, - mostNeg, - isZeroIncluded); - break; + if (useDataFromAllMapsFlag) { + histogram = getFileHistogram(mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + } + else { + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogram = getFileHistogram(mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogram = getMapHistogram(mapIndex, + mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + } } } else { - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - histogram = getFileHistogram(); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - histogram = getMapHistogram(mapIndex); - break; + if (useDataFromAllMapsFlag) { + histogram = getFileHistogram(); + } + else { + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogram = getFileHistogram(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogram = getMapHistogram(mapIndex); + break; + } } } diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index baa8f76ab..329fb822b 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -274,6 +274,7 @@ namespace caret { virtual const FastStatistics* getFileFastStatistics() = 0; bool getMapHistogramDrawingInfo(const int32_t mapIndex, + const bool useDataFromAllMapsFlag, const bool addEndPointForQwtFlag, HistogramDrawingInfo& histogramDrawingInfoOut, AString& errorMessageOut); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 8b528bef8..0041a393d 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -1877,10 +1877,17 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } } + PaletteHistogramChartTypeEnum::Enum histogramChartType = this->paletteColorMapping->getHistogramChartType(); + const bool allowEnvelopeChartTypeFlag = false; + if ( ! allowEnvelopeChartTypeFlag) { + histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; + } + const bool displayZeros = paletteColorMapping->isDisplayZeroDataFlag(); float z = 0.0; float maxDataFrequency = 0.0; + const int32_t lastIndex = numHistogramValues - 1; for (int64_t ix = 0; ix < numHistogramValues; ix++) { QColor color; const int64_t ix4 = ix * 4; @@ -1921,16 +1928,64 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } QVector samples; - samples.push_back(QPointF(startValue, dataFrequency)); - samples.push_back(QPointF(stopValue, dataFrequency)); QwtPlotCurve* curve = new QwtPlotCurve(); curve->setRenderHint(QwtPlotItem::RenderAntialiased); curve->setVisible(true); - curve->setStyle(QwtPlotCurve::Steps); - curve->setBrush(QBrush(color)); //, brushStyle)); curve->setPen(QPen(color)); + switch (histogramChartType) { + case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS: + curve->setStyle(QwtPlotCurve::Steps); + curve->setBrush(QBrush(color)); + samples.push_back(QPointF(startValue, dataFrequency)); + samples.push_back(QPointF(stopValue, dataFrequency)); + break; + case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_ENVELOPE: + curve->setStyle(QwtPlotCurve::Lines); + //curve->setBrush(QBrush(color)); + + /* + * Left side + */ + if (ix == 0) { + samples.push_back(QPointF(startValue, 0.0)); + samples.push_back(QPointF(startValue, dataFrequency)); + } + else { + CaretAssertVectorIndex(displayData, ix - 1); + const float lastFrequency = displayData[ix - 1]; + if (dataFrequency > lastFrequency) { + samples.push_back(QPointF(startValue, lastFrequency)); + samples.push_back(QPointF(startValue, dataFrequency)); + } + } + + /* + * Horizontal Bar + */ + samples.push_back(QPointF(startValue, dataFrequency)); + samples.push_back(QPointF(stopValue, dataFrequency)); + + /* + * Right side + */ + if (ix == lastIndex) { + samples.push_back(QPointF(stopValue, dataFrequency)); + samples.push_back(QPointF(stopValue, 0.0)); + } + else { + CaretAssertVectorIndex(displayData, ix + 1); + const float nextFrequency = displayData[ix + 1]; + if (dataFrequency > nextFrequency) { + samples.push_back(QPointF(stopValue, dataFrequency)); + samples.push_back(QPointF(stopValue, nextFrequency)); + } + } + + break; + } + curve->setSamples(samples); curve->attach(this->thresholdPlot); -- GitLab From eafeee6db5d86f21c9d47ba1ec3eedd557196674 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 10 Feb 2017 10:36:06 -0600 Subject: [PATCH 202/755] Continuing charting development. Added drawing of thresholds to histograms in graphics region. Added a preference for the histogram threshold color. Fixed initialization of color on QColorDialog. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 28 ++++++ src/Brain/BrainOpenGLPrimitiveDrawing.cxx | 4 +- src/Brain/BrainOpenGLPrimitiveDrawing.h | 6 ++ src/Common/BackgroundAndForegroundColors.cxx | 53 ++++++++++-- src/Common/BackgroundAndForegroundColors.h | 6 ++ src/Common/CaretPreferences.cxx | 10 +++ src/Common/CaretPreferences.h | 2 + src/Common/HistogramDrawingInfo.cxx | 60 ++++++++++--- src/Common/HistogramDrawingInfo.h | 18 ++++ src/Files/CaretMappableDataFile.cxx | 85 +++++++++++++++++++ src/GuiQt/PreferencesDialog.cxx | 21 ++++- src/GuiQt/PreferencesDialog.h | 4 +- 12 files changed, 270 insertions(+), 27 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 2a386d679..948ba3a0c 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -454,10 +454,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const int32_t numValues = static_cast(xValues.size() - 1); if (numValues > 1) { + { + uint8_t thresholdRGBByte[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(thresholdRGBByte); + const float histogramRGBA[4] = { + thresholdRGBByte[0] / 255.0, + thresholdRGBByte[1] / 255.0, + thresholdRGBByte[2] / 255.0, + 1.0 + }; + std::vector histogramNormals = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 }; + CaretAssert(histogramNormals.size() == 12); + + const std::vector& histogramOneXYZ = histogramDrawingInfo.getThresholdOneBounds(); + if (histogramOneXYZ.size() == 12) { + BrainOpenGLPrimitiveDrawing::drawPolygon(histogramOneXYZ, + histogramNormals, + histogramRGBA); + } + + const std::vector& histogramTwoXYZ = histogramDrawingInfo.getThresholdTwoBounds(); + if (histogramTwoXYZ.size() == 12) { + BrainOpenGLPrimitiveDrawing::drawPolygon(histogramTwoXYZ, + histogramNormals, + histogramRGBA); + } + } + std::vector quadVerticesXYZ; std::vector quadVerticesFloatRGBA; std::vector quadVerticesByteRGBA; + const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); CaretAssert(cmdf); const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx index 7961d3ccb..2049f2616 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx @@ -934,7 +934,7 @@ BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, CaretAssert(numCoords == (rgbaVector.size() / 4)); - const int64_t numNormals = static_cast(normals.size()); + const int64_t numNormals = static_cast(normals.size() / 3); if (numNormals > 0) { if (numCoords != numNormals) { const AString msg("Number of coordinates " @@ -1022,7 +1022,7 @@ BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, CaretAssert(numCoords == (rgbaColors.size() / 4)); - const int64_t numNormals = static_cast(normals.size()); + const int64_t numNormals = static_cast(normals.size() / 3); if (numNormals > 0) { if (numCoords != numNormals) { const AString msg("Number of coordinates " diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.h b/src/Brain/BrainOpenGLPrimitiveDrawing.h index 244b5e860..bc9a94000 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.h +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.h @@ -97,6 +97,12 @@ namespace caret { const float lineThickness, const float rgba[4]); +// static void drawRectangle(const float bottomLeft[3], +// const float bottomRight[3], +// const float topRight[3], +// const float topLeft[3], +// const float rgba[4]); + private: BrainOpenGLPrimitiveDrawing(); diff --git a/src/Common/BackgroundAndForegroundColors.cxx b/src/Common/BackgroundAndForegroundColors.cxx index bc01cda5d..062196b00 100644 --- a/src/Common/BackgroundAndForegroundColors.cxx +++ b/src/Common/BackgroundAndForegroundColors.cxx @@ -87,15 +87,16 @@ void BackgroundAndForegroundColors::copyHelperBackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj) { for (int32_t i = 0; i < 3; i++) { - m_colorForegroundAll[i] = obj.m_colorForegroundAll[i]; - m_colorBackgroundAll[i] = obj.m_colorBackgroundAll[i]; - m_colorForegroundChart[i] = obj.m_colorForegroundChart[i]; - m_colorBackgroundChart[i] = obj.m_colorBackgroundChart[i]; - m_colorForegroundSurface[i] = obj.m_colorForegroundSurface[i]; - m_colorBackgroundSurface[i] = obj.m_colorBackgroundSurface[i]; - m_colorForegroundVolume[i] = obj.m_colorForegroundVolume[i]; - m_colorBackgroundVolume[i] = obj.m_colorBackgroundVolume[i]; - m_colorChartMatrixGridLines[i] = obj.m_colorChartMatrixGridLines[i]; + m_colorForegroundAll[i] = obj.m_colorForegroundAll[i]; + m_colorBackgroundAll[i] = obj.m_colorBackgroundAll[i]; + m_colorForegroundChart[i] = obj.m_colorForegroundChart[i]; + m_colorBackgroundChart[i] = obj.m_colorBackgroundChart[i]; + m_colorForegroundSurface[i] = obj.m_colorForegroundSurface[i]; + m_colorBackgroundSurface[i] = obj.m_colorBackgroundSurface[i]; + m_colorForegroundVolume[i] = obj.m_colorForegroundVolume[i]; + m_colorBackgroundVolume[i] = obj.m_colorBackgroundVolume[i]; + m_colorChartMatrixGridLines[i] = obj.m_colorChartMatrixGridLines[i]; + m_colorChartHistogramThreshold[i] = obj.m_colorChartHistogramThreshold[i]; } } @@ -133,6 +134,11 @@ BackgroundAndForegroundColors::reset() const uint8_t chartGreen = 255; const uint8_t chartBlue = 255; setColor(m_colorChartMatrixGridLines, chartRed, chartGreen, chartBlue); + + const uint8_t threshRed = 100; + const uint8_t threshGreen = 100; + const uint8_t threshBlue = 255; + setColor(m_colorChartHistogramThreshold, threshRed, threshGreen, threshBlue); } /** @@ -389,6 +395,35 @@ BackgroundAndForegroundColors::setColorChartMatrixGridLines(const uint8_t colorC } } +/** + * Get the color for chart histogram threshold + * + * @param colorChartHistogramThreshold + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::getColorChartHistogramThreshold(uint8_t colorChartHistogramThreshold[3]) const +{ + for (int32_t i = 0; i < 3; i++) { + colorChartHistogramThreshold[i] = m_colorChartHistogramThreshold[i]; + } +} + +/** + * Set the color for chart histogram threshold + * + * @param colorChartHistogramThreshold + * RGB color components ranging [0, 255]. + */ +void +BackgroundAndForegroundColors::setColorChartHistogramThreshold(const uint8_t colorChartHistogramThreshold[3]) +{ + for (int32_t i = 0; i < 3; i++) { + m_colorChartHistogramThreshold[i] = colorChartHistogramThreshold[i]; + } +} + + /** * Set a color with the given color components that range 0 to 255. * diff --git a/src/Common/BackgroundAndForegroundColors.h b/src/Common/BackgroundAndForegroundColors.h index 35b00acf9..a772d6ad2 100644 --- a/src/Common/BackgroundAndForegroundColors.h +++ b/src/Common/BackgroundAndForegroundColors.h @@ -81,6 +81,10 @@ namespace caret { void setColorChartMatrixGridLines(const uint8_t colorChartMatrixGridLines[3]); + void getColorChartHistogramThreshold(uint8_t colorChartMatrixGridLines[3]) const; + + void setColorChartHistogramThreshold(const uint8_t colorChartMatrixGridLines[3]); + private: void copyHelperBackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj); @@ -107,6 +111,8 @@ namespace caret { uint8_t m_colorChartMatrixGridLines[3]; + uint8_t m_colorChartHistogramThreshold[3]; + // ADD_NEW_MEMBERS_HERE friend class BackgroundAndForegroundColorsSceneHelper; diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index bcbd0581c..48534171e 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -614,6 +614,10 @@ CaretPreferences::setUserBackgroundAndForegroundColors(const BackgroundAndForegr writeUnsignedByteArray(NAME_COLOR_CHART_MATRIX_GRID_LINES, this->userColors.m_colorChartMatrixGridLines, 3); + + writeUnsignedByteArray(NAME_COLOR_CHART_HISTOGRAM_THRESHOLD, + this->userColors.m_colorChartHistogramThreshold, + 3); } /** @@ -1386,6 +1390,12 @@ CaretPreferences::readPreferences() 3); userColors.setColorChartMatrixGridLines(colorRGB); + userColors.getColorChartHistogramThreshold(colorRGB); + readUnsignedByteArray(NAME_COLOR_CHART_HISTOGRAM_THRESHOLD, + colorRGB, + 3); + userColors.setColorChartHistogramThreshold(colorRGB); + this->previousSpecFiles.clear(); const int numPrevSpec = this->qSettings->beginReadArray(NAME_PREVIOUS_SPEC_FILES); for (int i = 0; i < numPrevSpec; i++) { diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index 249ebf2b9..916e58594 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -306,6 +306,7 @@ namespace caret { static const AString NAME_COLOR_BACKGROUND_VOLUME; static const AString NAME_COLOR_FOREGROUND_VOLUME; static const AString NAME_COLOR_CHART_MATRIX_GRID_LINES; + static const AString NAME_COLOR_CHART_HISTOGRAM_THRESHOLD; static const AString NAME_DEVELOP_MENU; static const AString NAME_DYNAMIC_CONNECTIVITY_ON; static const AString NAME_IMAGE_CAPTURE_METHOD; @@ -346,6 +347,7 @@ namespace caret { const AString CaretPreferences::NAME_COLOR_BACKGROUND_VOLUME = "colorBackgroundVolume"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_VOLUME = "colorForegroundVolume"; const AString CaretPreferences::NAME_COLOR_CHART_MATRIX_GRID_LINES = "colorChartMatrixGridLines"; + const AString CaretPreferences::NAME_COLOR_CHART_HISTOGRAM_THRESHOLD = "colorChartHistogramThreshold"; const AString CaretPreferences::NAME_DEVELOP_MENU = "developMenu"; const AString CaretPreferences::NAME_DYNAMIC_CONNECTIVITY_ON = "dynamicConnectivityDefaultedOn"; const AString CaretPreferences::NAME_IMAGE_CAPTURE_METHOD = "imageCaptureMethod"; diff --git a/src/Common/HistogramDrawingInfo.cxx b/src/Common/HistogramDrawingInfo.cxx index 3904bbcaa..9cfb0bad0 100644 --- a/src/Common/HistogramDrawingInfo.cxx +++ b/src/Common/HistogramDrawingInfo.cxx @@ -42,6 +42,7 @@ using namespace caret; HistogramDrawingInfo::HistogramDrawingInfo() : CaretObject() { + reset(); } /** @@ -64,7 +65,6 @@ HistogramDrawingInfo::initialize(const int32_t numberOfDataPoints) m_dataX.resize(numberOfDataPoints, 0.0); m_dataY.resize(numberOfDataPoints, 0.0); m_dataRGBA.resize(numberOfDataPoints * 4, 0.0); - } /** @@ -77,6 +77,10 @@ HistogramDrawingInfo::reset() m_dataY.clear(); m_dataRGBA.clear(); m_boundsValid = false; + m_thresholdOneBoundsXYZ.clear(); + m_thresholdTwoBoundsXYZ.clear(); + m_thresholdOneBoundsValid = false; + m_thresholdOneBoundsValid = false; } @@ -120,22 +124,52 @@ HistogramDrawingInfo::getBounds(float boundsOut[4]) const } } - if (m_boundsValid) { - boundsOut[0] = m_bounds[0]; - boundsOut[1] = m_bounds[1]; - boundsOut[2] = m_bounds[2]; - boundsOut[3] = m_bounds[3]; - } - else { - boundsOut[0] = 0.0; - boundsOut[1] = 0.0; - boundsOut[2] = 0.0; - boundsOut[3] = 0.0; - } + boundsOut[0] = m_bounds[0]; + boundsOut[1] = m_bounds[1]; + boundsOut[2] = m_bounds[2]; + boundsOut[3] = m_bounds[3]; return m_boundsValid; } +///** +// * Get the bounds for the threshold one. +// * +// * @param boundsOut +// * Output with bounds (minX, maxX, minY, maxY) +// * @return +// * True if bounds valid, else false. +// */ +//const +//HistogramDrawingInfo::getThresholdOneBounds(float boundsOut[4]) const +//{ +// boundsOut[0] = m_thresholdOneBounds[0]; +// boundsOut[1] = m_thresholdOneBounds[1]; +// boundsOut[2] = m_thresholdOneBounds[2]; +// boundsOut[3] = m_thresholdOneBounds[3]; +// +// return m_thresholdOneBoundsValid; +//} + +///** +// * Get the bounds for threshold two. +// * +// * @param boundsOut +// * Output with bounds (minX, maxX, minY, maxY) +// * @return +// * True if bounds valid, else false. +// */ +//bool +//HistogramDrawingInfo::getThresholdTwoBounds(float boundsOut[4]) const +//{ +// boundsOut[0] = m_thresholdTwoBounds[0]; +// boundsOut[1] = m_thresholdTwoBounds[1]; +// boundsOut[2] = m_thresholdTwoBounds[2]; +// boundsOut[3] = m_thresholdTwoBounds[3]; +// +// return m_thresholdTwoBoundsValid; +//} + /** * @return Number of data points in the histogram. */ diff --git a/src/Common/HistogramDrawingInfo.h b/src/Common/HistogramDrawingInfo.h index 5b139f313..20d8791c2 100644 --- a/src/Common/HistogramDrawingInfo.h +++ b/src/Common/HistogramDrawingInfo.h @@ -45,12 +45,22 @@ namespace caret { bool isValid() const; + /** @return X-coordinates of histogram bars */ const std::vector& getDataX() const { return m_dataX; } + /** @return Y-coordinates of histogram bars */ const std::vector& getDataY() const { return m_dataY; } + /** @return RGBA data for histogram bars */ const std::vector& getDataRGBA() const { return m_dataRGBA; } + /** @return XYZ coordinates for threshold one bounds, may be empty ! */ + const std::vector& getThresholdOneBounds() const { return m_thresholdOneBoundsXYZ; } + + /** @return XYZ coordinates for threshold two bounds, may be empty ! */ + const std::vector& getThresholdTwoBounds() const { return m_thresholdTwoBoundsXYZ; } + + // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -71,6 +81,14 @@ namespace caret { std::vector m_dataRGBA; + std::vector m_thresholdOneBoundsXYZ; + + bool m_thresholdOneBoundsValid = false; + + std::vector m_thresholdTwoBoundsXYZ; + + bool m_thresholdTwoBoundsValid = false; + // ADD_NEW_MEMBERS_HERE friend class CaretMappableDataFile; diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 5bb7ecf6a..9722bef78 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1099,6 +1099,91 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, true); // ignore thresholding } + bool setThresholdingFlag = false; + switch (paletteColorMapping->getThresholdType()) { + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: + setThresholdingFlag = true; + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: + break; + } + + if (setThresholdingFlag) { + float bounds[4]; + if (histogramDrawingInfoOut.getBounds(bounds)) { + const float minX = bounds[0]; + const float maxX = bounds[1]; + const float minY = bounds[2]; + const float maxY = bounds[3]; + + float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); + float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); + switch (paletteColorMapping->getThresholdTest()) { + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: + { + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = minX; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMinValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMinValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = minX; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; + + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ.resize(12); + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[0] = threshMaxValue; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[1] = minY; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[2] = 0.0; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[3] = maxX; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[4] = minY; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[5] = 0.0; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[6] = maxX; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[7] = maxY; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[8] = 0.0; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[9] = threshMaxValue; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[10] = maxY; + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[11] = 0.0; + } + break; + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: + { + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = threshMinValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMaxValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMaxValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = threshMinValue; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; + histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; + } + break; + } + + switch (paletteColorMapping->getThresholdRangeMode()) { + case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE: + break; + case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP: + break; + case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED: + break; + } + } + } + CaretAssert(histogramDrawingInfoOut.isValid()); return histogramDrawingInfoOut.isValid(); } diff --git a/src/GuiQt/PreferencesDialog.cxx b/src/GuiQt/PreferencesDialog.cxx index 8ccff5d7d..7ec3766ff 100644 --- a/src/GuiQt/PreferencesDialog.cxx +++ b/src/GuiQt/PreferencesDialog.cxx @@ -171,6 +171,10 @@ PreferencesDialog::addColorButtonAndSwatch(QGridLayout* gridLayout, buttonText = "Chart Grid Lines"; m_chartMatrixGridLinesColorWidget = colorSwatchWidget; break; + case PREF_COLOR_CHART_THRESHOLD: + buttonText = "Chart Threshold"; + m_chartHistogramThresholdColorWidget = colorSwatchWidget; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -218,7 +222,9 @@ PreferencesDialog::createColorsWidget() addColorButtonAndSwatch(gridLayout, PREF_COLOR_CHART_MATRIX_GRID_LINES, colorSignalMapper); - + addColorButtonAndSwatch(gridLayout, + PREF_COLOR_CHART_THRESHOLD, + colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_SURFACE, colorSignalMapper); @@ -300,6 +306,10 @@ PreferencesDialog::updateColorWidget(CaretPreferences* prefs) colors.getColorChartMatrixGridLines(rgb); colorSwatchWidget = m_chartMatrixGridLinesColorWidget; break; + case PREF_COLOR_CHART_THRESHOLD: + colors.getColorChartHistogramThreshold(rgb); + colorSwatchWidget = m_chartHistogramThresholdColorWidget; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -791,6 +801,10 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) colors.getColorChartMatrixGridLines(rgb); prefColorName = "Chart Matrix Grid Lines"; break; + case PREF_COLOR_CHART_THRESHOLD: + colors.getColorChartHistogramThreshold(rgb); + prefColorName = "Chart Histohram Threshold"; + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; @@ -801,9 +815,9 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) rgb[2]); QColorDialog colorDialog(this); - colorDialog.setCurrentColor(initialColor); colorDialog.setOption(QColorDialog::DontUseNativeDialog); colorDialog.setWindowTitle(prefColorName); + colorDialog.setCurrentColor(initialColor); if (colorDialog.exec() == QColorDialog::Accepted) { const QColor newColor = colorDialog.currentColor(); @@ -841,6 +855,9 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) case PREF_COLOR_CHART_MATRIX_GRID_LINES: colors.setColorChartMatrixGridLines(rgb); break; + case PREF_COLOR_CHART_THRESHOLD: + colors.setColorChartHistogramThreshold(rgb); + break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; diff --git a/src/GuiQt/PreferencesDialog.h b/src/GuiQt/PreferencesDialog.h index 0ccd515e5..9aeab8785 100644 --- a/src/GuiQt/PreferencesDialog.h +++ b/src/GuiQt/PreferencesDialog.h @@ -87,7 +87,8 @@ namespace caret { PREF_COLOR_FOREGROUND_SURFACE = 6, PREF_COLOR_FOREGROUND_VOLUME = 7, PREF_COLOR_CHART_MATRIX_GRID_LINES = 8, - NUMBER_OF_PREF_COLORS = 9 + PREF_COLOR_CHART_THRESHOLD = 9, + NUMBER_OF_PREF_COLORS = 10 }; QWidget* createColorsWidget(); @@ -129,6 +130,7 @@ namespace caret { QWidget* m_backgroundColorSurfaceWidget; QWidget* m_backgroundColorVolumeWidget; QWidget* m_chartMatrixGridLinesColorWidget; + QWidget* m_chartHistogramThresholdColorWidget; WuQTrueFalseComboBox* m_miscDevelopMenuEnabledComboBox; QComboBox* m_miscLoggingLevelComboBox; -- GitLab From 4f6053d908802260aa1141bcfae8b369633e3e9e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Feb 2017 12:18:47 -0600 Subject: [PATCH 203/755] Improved commands for development code generation --- src/Commands/CommandClassAddMember.cxx | 34 ++++++++++++++++++++++---- src/Commands/CommandClassCreate.cxx | 23 ++++++++++++++--- src/Commands/CommandClassCreate.h | 2 ++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/Commands/CommandClassAddMember.cxx b/src/Commands/CommandClassAddMember.cxx index 02be06a9a..f2773bc0b 100644 --- a/src/Commands/CommandClassAddMember.cxx +++ b/src/Commands/CommandClassAddMember.cxx @@ -110,7 +110,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) AString headerMethodCode = ""; AString implementationCode = ""; - const AString indentText = " "; + const AString indentText = " "; /* * Process parameters @@ -162,6 +162,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) * is a class and use a pointer for the class. However, * treat AString and QString as primitive types. */ + bool isEnum = false; bool isString = false; bool isClass = false; const QChar firstDataTypeChar = dataType[0]; @@ -170,6 +171,9 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) || (dataType == "QString")) { isString = true; } + else if (dataType.endsWith("Enum")) { + isEnum = true; + } else { isClass = true; } @@ -199,17 +203,25 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) firstGetSetNameChar = firstGetSetNameChar.toUpper(); getSetName[0] = firstGetSetNameChar; } - const AString getterName = ("get" + getSetName); + const AString getterName = (((dataType == "bool") + ? "is" + : "get") + getSetName); const AString setterName = ("set" + getSetName); /* * Declare the member for the header file */ + if (isClass) { + headerMemberCode += ("#include \n" + "\n"); + } if (description.isEmpty() == false) { headerMemberCode += (indentText + "/** " + description + "*/\n"); } - headerMemberCode += (indentText - + returnType + headerMemberCode += (indentText + + (isClass ? "std::unique_ptr<" : "") + + dataType //returnType + + (isClass ? ">" : "") + " " + name + ";" @@ -220,6 +232,17 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) const AString classColonName = (className + "::"); if (isClass) { + implementationCode += ("\n" + + indentText + + name + + " = std::unique_ptr<" + + dataType + + ">(new" + + dataType + + "());" + + "\n" + + "\n"); + /* * For class members, create only getter methods * that are both const and non-const @@ -248,7 +271,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) + (isConstMethod ? " const" : "") + "\n" + "{\n" - + " return " + name + ";\n" + + " return " + name + ".get();\n" + "}\n" + "\n"); } @@ -291,6 +314,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) implementationCode += ("/**\n" " * Set " + description + "\n" + " *\n" " * @param " + parameterName + "\n" " * New value for " + description + "\n" " */\n" diff --git a/src/Commands/CommandClassCreate.cxx b/src/Commands/CommandClassCreate.cxx index 00139c4eb..854b84e3f 100644 --- a/src/Commands/CommandClassCreate.cxx +++ b/src/Commands/CommandClassCreate.cxx @@ -293,6 +293,11 @@ CommandClassCreate::createHeaderFile(const AString& outputFileName, t += ("#define " + ifndefName + "\n"); t += this->getCopyright(); t += ("\n"); + if (m_useUniquePtrFlag) { + t += ("\n"); + t += ("#include \n"); + t += ("\n"); + } t += (this->getIncludeDeclaration(derivedFromClassName) + "\n"); t += ("\n"); @@ -419,7 +424,12 @@ CommandClassCreate::createHeaderFile(const AString& outputFileName, } if (hasSceneInterface || hasSubClassSceneSaving) { - t += (" SceneClassAssistant* m_sceneAssistant;\n"); + if (m_useUniquePtrFlag) { + t += (" std::unique_ptr m_sceneAssistant;\n"); + } + else { + t += (" SceneClassAssistant* m_sceneAssistant;\n"); + } t += ("\n"); } t += (" " + getNewMembersString() + "\n"); @@ -536,7 +546,12 @@ CommandClassCreate::createImplementationFile(const AString& outputFileName, t += (" \n"); if (hasSceneInterface || hasSubClassSceneSaving) { - t += (" m_sceneAssistant = new SceneClassAssistant();\n"); + if (m_useUniquePtrFlag) { + t += (" m_sceneAssistant = std::unique_ptr(new SceneClassAssistant());\n"); + } + else { + t += (" m_sceneAssistant = new SceneClassAssistant();\n"); + } t += (" \n"); } if (hasEventListener) { @@ -554,7 +569,9 @@ CommandClassCreate::createImplementationFile(const AString& outputFileName, } if (hasSceneInterface || hasSubClassSceneSaving) { - t += (" delete m_sceneAssistant;\n"); + if ( ! m_useUniquePtrFlag) { + t += (" delete m_sceneAssistant;\n"); + } } t += ("}\n"); t += ("\n"); diff --git a/src/Commands/CommandClassCreate.h b/src/Commands/CommandClassCreate.h index 17c6086a7..ec04160df 100644 --- a/src/Commands/CommandClassCreate.h +++ b/src/Commands/CommandClassCreate.h @@ -72,6 +72,8 @@ namespace caret { const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving); + + const bool m_useUniquePtrFlag = true; }; } // namespace -- GitLab From a90c5ff45085689a0f9cb04bca8da50efb8e3fa7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Feb 2017 12:36:45 -0600 Subject: [PATCH 204/755] Continuing charting development. Add axis to histogram charts with auto scaling; add identification of histogram bars, add preferences color for histogram chart thresholding. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 504 +++++++++++++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 27 +- src/Brain/ChartTwoOverlaySet.cxx | 92 ++- src/Brain/ChartTwoOverlaySet.h | 20 + src/Brain/IdentificationTextGenerator.cxx | 81 ++- src/Brain/ModelChartTwo.cxx | 22 +- src/Brain/ModelChartTwo.h | 4 +- src/Brain/SelectionItemChartTwoHistogram.cxx | 47 +- src/Brain/SelectionItemChartTwoHistogram.h | 10 +- src/Charting/CMakeLists.txt | 4 + .../ChartTwoAxisScaleRangeModeEnum.cxx | 373 ++++++++++ src/Charting/ChartTwoAxisScaleRangeModeEnum.h | 104 +++ src/Charting/ChartTwoCartesianAxis.cxx | 653 ++++++++++++++++++ src/Charting/ChartTwoCartesianAxis.h | 169 +++++ src/Common/HistogramDrawingInfo.cxx | 28 + src/Common/HistogramDrawingInfo.h | 3 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 1 + src/GuiQt/PreferencesDialog.cxx | 2 +- 18 files changed, 2091 insertions(+), 53 deletions(-) create mode 100644 src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx create mode 100644 src/Charting/ChartTwoAxisScaleRangeModeEnum.h create mode 100644 src/Charting/ChartTwoCartesianAxis.cxx create mode 100644 src/Charting/ChartTwoCartesianAxis.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 948ba3a0c..bf2e29779 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -23,6 +23,7 @@ #include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #undef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ +#include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" @@ -30,6 +31,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" +#include "ChartTwoCartesianAxis.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -54,8 +56,9 @@ using namespace caret; +static const float fontSizeInPixels = 14; + - /** * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline * \brief Drawing of version two charts. @@ -234,8 +237,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() // * Margin is region around the chart in which // * the axes legends, values, and ticks are drawn. // */ - const double marginSize = 30; - Margins margins(marginSize); + // const double marginSize = 30; + // Margins margins(marginSize); // // double width, height; // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); @@ -361,7 +364,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() CaretAssert(histogramDrawingInfoVector.size() == mapIndexVector.size()); /* - * Bounds invalid? + * Bounds valid? */ if ((xMin < xMax) || (yMin < yMax)) { @@ -371,6 +374,85 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() // << yMin << " " // << yMax << " " << std::endl; + /* + * Margin is region around the chart in which + * the axes legends, values, and ticks are drawn. + */ + const double marginSize = 30; + Margins margins(marginSize); + + ChartTwoCartesianAxis* leftAxis = m_chartOverlaySet->getChartAxisLeft(); + ChartTwoCartesianAxis* rightAxis = m_chartOverlaySet->getChartAxisRight(); + ChartTwoCartesianAxis* bottomAxis = m_chartOverlaySet->getChartAxisBottom(); + ChartTwoCartesianAxis* topAxis = NULL; + + const float bounds[4] = { xMin, xMax, yMin, yMax }; + double width = 0.0, height = 0.0; + estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, leftAxis, width, height); + margins.m_left = std::max(margins.m_left, width); + estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, rightAxis, width, height); + margins.m_right = std::max(margins.m_right, width); + estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, topAxis, width, height); + margins.m_top = std::max(margins.m_top, height); + estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, bottomAxis, width, height); + margins.m_bottom = std::max(margins.m_bottom, height); + + if (margins.m_left > marginSize) margins.m_left += 10; + if (margins.m_right > marginSize) margins.m_right += 10; + + /* + * Ensure that there is sufficient space for the axes data display. + */ + if ((vpWidth > (marginSize * 3)) + && (vpHeight > (marginSize * 3))) { + + /* Draw legends and grids */ + drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + leftAxis); + drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + rightAxis); + drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + bottomAxis); + drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + topAxis); + + drawChartGraphicsBoxAndSetViewport(vpX, + vpY, + vpWidth, + vpHeight, + margins, + chartGraphicsDrawingViewport); + + if (leftAxis->isVisible()) { + yMin = leftAxis->getMinimumValue(); + yMax = leftAxis->getMaximumValue(); + } + if (bottomAxis->isVisible()) { + xMin = bottomAxis->getMinimumValue(); + xMax = bottomAxis->getMaximumValue(); + } + } + glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], @@ -538,7 +620,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab if (m_identificationModeFlag) { uint8_t idRGBA[4]; - addToHistogramIdentification(i, idRGBA); + addToHistogramIdentification(mapIndex, i, idRGBA); for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), @@ -618,7 +700,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab uint8_t idRGBA[4]; if (m_identificationModeFlag) { - addToHistogramIdentification(i, idRGBA); + addToHistogramIdentification(mapIndex, i, idRGBA); } if (i == 0) { @@ -1544,13 +1626,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() /** * Add an item for matrix identification. * - * @param barIndex + * @param mapIndex + * Index of the map whose histogram is displayed (negative indicates all maps). + * @param bucketIndex * Index of the histogram bar. * @param rgbaForColorIdentificationOut - * Encoded identification in RGBA color OUTPUT + * Encoded identification in RGBA color OUTPUT */ void -BrainOpenGLChartTwoDrawingFixedPipeline::addToHistogramIdentification(const int barIndex, +BrainOpenGLChartTwoDrawingFixedPipeline::addToHistogramIdentification(const int32_t mapIndex, + const int32_t bucketIndex, uint8_t rgbaForColorIdentificationOut[4]) { const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_HISTOGRAM; @@ -1564,7 +1649,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::addToHistogramIdentification(const int * If these items change, need to update reset and * processing of identification. */ - m_identificationIndices.push_back(barIndex); + m_identificationIndices.push_back(mapIndex); + m_identificationIndices.push_back(bucketIndex); } /** @@ -1586,11 +1672,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processHistogramIdentification(const Ch depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_HISTOGRAM; - const int32_t barIndex = m_identificationIndices[idIndex]; + const int32_t mapIndex = m_identificationIndices[idIndex]; + const int32_t bucketIndex = m_identificationIndices[idIndex+1]; if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(depth)) { m_selectionItemHistogram->setHistogramChart(const_cast(histogramChart), - barIndex); + mapIndex, + bucketIndex); } } } @@ -1768,3 +1856,395 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processMatrixIdentification(const Chart } } +/** + * Estimate the size of the axis' text. + * + * @param dataBounds + * Bounds of data [minX, maxX, minY, maxY]. + * @param viewportHeight + * Height of viewport. + * @param cartesianAxis + * The axis. + * @param widthOut + * Width of text out. + * @param heightOut + * Heigh of text out. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], + const float viewportHeight, + ChartTwoCartesianAxis* cartesianAxis, + double& widthOut, + double& heightOut) +{ + widthOut = 0; + heightOut = 0; + + if (cartesianAxis == NULL) { + return; + } + if ( ! cartesianAxis->isVisible()) { + return; + } + + /* + * The length of the axis does not matter here. + * We are just estimating the width and height of the axes text labels. + */ + const float axisLength = 1000.0; + std::vector labelOffsetInPixels; + std::vector labelTexts; + cartesianAxis->getLabelsAndPositions(dataBounds, + axisLength, + fontSizeInPixels, + labelOffsetInPixels, + labelTexts); + for (std::vector::iterator iter = labelTexts.begin(); + iter != labelTexts.end(); + iter++) { + const AString text = *iter; + if ( ! text.isEmpty()) { + AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setText(text); + double textWidth = 0.0; + double textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); + + widthOut = std::max(widthOut, textWidth); + heightOut = std::max(heightOut, textHeight); + } + } +} + +/** + * Draw the chart graphics surrounding box and set the graphics viewport. + * drawChartGraphicsBoxAndSetViewport + * @param vpX + * Viewport X + * @param vpY + * Viewport Y + * @param vpWidth + * Viewport width + * @param vpHeight + * Viewport height + * @param marginSize + * Margin around grid/box + * @param chartGraphicsDrawingViewportOut + * Output containing viewport for drawing chart graphics within + * the box/grid that is adjusted for the box's line thickness. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const Margins& margins, + int32_t chartGraphicsDrawingViewportOut[4]) +{ + + const float gridLineWidth = 2; + const float halfGridLineWidth = gridLineWidth / 2.0; + + const float gridLeft = vpX + margins.m_left; + const float gridRight = vpX + vpWidth - margins.m_right; + const float gridBottom = vpY + margins.m_bottom; + const float gridTop = vpY + vpHeight - margins.m_top; + + glViewport(vpX, + vpY, + vpWidth, + vpHeight); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(vpX, (vpX + vpWidth), + vpY, (vpY + vpHeight), + -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glLineWidth(gridLineWidth); + + glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); + + glBegin(GL_LINES); + + /* bottom line */ + glVertex3f(gridLeft, gridBottom + halfGridLineWidth, 0.0); + glVertex3f(gridRight, gridBottom + halfGridLineWidth, 0.0); + + /* right line */ + glVertex3f(gridRight - halfGridLineWidth, gridBottom, 0.0); + glVertex3f(gridRight - halfGridLineWidth, gridTop, 0.0); + + /* top line */ + glVertex3f(gridRight, gridTop - halfGridLineWidth, 0.0); + glVertex3f(gridLeft, gridTop - halfGridLineWidth, 0.0); + + /* left line */ + glVertex3f(gridLeft + halfGridLineWidth, gridTop, 0.0); + glVertex3f(gridLeft + halfGridLineWidth, gridBottom, 0.0); + + glEnd(); + + /* + * Region inside the grid's box + */ + const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(gridLineWidth + 1.0)); + const int32_t graphicsRight = static_cast(gridRight - std::floor(gridLineWidth + 1.0)); + const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(gridLineWidth + 1.0)); + const int32_t graphicsTop = static_cast(gridTop - std::floor(gridLineWidth + 1.0)); + + const int32_t graphicsWidth = graphicsRight - graphicsLeft; + const int32_t graphicsHeight = graphicsTop - graphicsBottom; + chartGraphicsDrawingViewportOut[0] = graphicsLeft; + chartGraphicsDrawingViewportOut[1] = graphicsBottom; + chartGraphicsDrawingViewportOut[2] = graphicsWidth; + chartGraphicsDrawingViewportOut[3] = graphicsHeight; +} + +/** + * Draw the chart axes grid/box + * + * @param vpX + * Viewport X for all chart content + * @param vpY + * Viewport Y for all chart content + * @param vpWidth + * Viewport width for all chart content + * @param vpHeight + * Viewport height for all chart content + * @param margins + * Margin around graphics region. The margin corresponding to the + * axis may be changed so that all text in the axis is visible + * (and not cut off). + * @param axis + * Axis that is drawn. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], + const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + Margins& margins, + ChartTwoCartesianAxis* axis) +{ + if (axis == NULL) { + return; + } + if ( ! axis->isVisible()) { + return; + } + + float axisLength = 0.0; + + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + axisLength = vpWidth - (margins.m_left + margins.m_right); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + axisLength = vpHeight - (margins.m_top + margins.m_bottom); + break; + } + + std::vector labelOffsetInPixels; + std::vector labelTexts; + axis->getLabelsAndPositions(dataBounds, + axisLength, + fontSizeInPixels, + labelOffsetInPixels, + labelTexts); + + const float rgba[4] = { + m_fixedPipelineDrawing->m_foregroundColorFloat[0], + m_fixedPipelineDrawing->m_foregroundColorFloat[1], + m_fixedPipelineDrawing->m_foregroundColorFloat[2], + 1.0 + }; + + const int32_t numLabelsToDraw = static_cast(labelTexts.size()); + AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setCustomTextColor(rgba); + annotationText.setTextColor(CaretColorEnum::CUSTOM); + + if (numLabelsToDraw > 0) { + float labelX = 0.0; + float labelY = 0.0; + float labelOffsetMultiplierX = 0.0; + float labelOffsetMultiplierY = 0.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + + /* + * Viewport for axis name and numeric values + */ + int32_t axisVpX = vpX; + int32_t axisVpY = vpY; + int32_t axisVpWidth = vpWidth; + int32_t axisVpHeight = vpHeight; + + float tickDeltaXY[2] = { 0.0, 0.0 }; + const float tickLength = 5.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + axisVpX = vpX; + axisVpY = vpY; + axisVpWidth = vpWidth; + axisVpHeight = margins.m_bottom; + labelX = margins.m_left; + labelY = margins.m_bottom; + labelOffsetMultiplierX = 1.0; + labelOffsetMultiplierY = 0.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + tickDeltaXY[0] = 0.0; + tickDeltaXY[1] = -tickLength; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + axisVpX = vpX; + axisVpY = vpY + vpHeight - margins.m_top; + axisVpWidth = vpWidth; + axisVpHeight = margins.m_top; + labelX = margins.m_left; + labelY = 0.0; + labelOffsetMultiplierX = 1.0; + labelOffsetMultiplierY = 0.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + tickDeltaXY[0] = 0.0; + tickDeltaXY[1] = tickLength; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + axisVpX = vpX; + axisVpY = vpY; + axisVpWidth = margins.m_left; + axisVpHeight = vpHeight; + labelX = margins.m_left; + labelY = margins.m_bottom; + labelOffsetMultiplierX = 0.0; + labelOffsetMultiplierY = 1.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + tickDeltaXY[0] = -tickLength; + tickDeltaXY[1] = 0.0; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + axisVpX = vpX + vpWidth - margins.m_right; + axisVpY = vpY; + axisVpWidth = margins.m_right; + axisVpHeight = vpHeight; + labelX = 0.0; + labelY = margins.m_bottom; + labelOffsetMultiplierX = 0.0; + labelOffsetMultiplierY = 1.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + tickDeltaXY[0] = tickLength; + tickDeltaXY[1] = 0.0; + break; + } + + /* + * Viewport for axis text and numeric values + */ + const int viewport[4] = { + axisVpX, + axisVpY, + axisVpWidth, + axisVpHeight + }; + glViewport(viewport[0], + viewport[1], + viewport[2], + viewport[3]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, axisVpWidth, 0, axisVpHeight, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); + + for (int32_t i = 0; i < numLabelsToDraw; i++) { + const float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; + const float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; + + const float tickEndX = tickStartX + tickDeltaXY[0]; + const float tickEndY = tickStartY + tickDeltaXY[1]; + + glBegin(GL_LINES); + glVertex2f(tickStartX, + tickStartY); + glVertex2f(tickEndX, + tickEndY); + glEnd(); + + const float textX = tickEndX; + const float textY = tickEndY; + annotationText.setText(labelTexts[i]); + m_textRenderer->drawTextAtViewportCoords(textX, + textY, + 0.0, + annotationText); + } + + const AString axisText = axis->getLabelText(); + if ( ! axisText.isEmpty()) { + //AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + + bool drawAxisTextVerticalFlag = false; + float axisTextCenterX = axisVpWidth / 2.0; + float axisTextCenterY = axisVpHeight / 2.0; + const float textMarginOffset = 5.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + axisTextCenterX = (vpWidth / 2.0); + axisTextCenterY = textMarginOffset; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + axisTextCenterX = (vpWidth / 2.0); + axisTextCenterY = margins.m_top - textMarginOffset; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + axisTextCenterX = textMarginOffset; + axisTextCenterY = (vpHeight / 2.0); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + drawAxisTextVerticalFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + axisTextCenterX = margins.m_right - textMarginOffset; + axisTextCenterY = (vpHeight / 2.0); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + drawAxisTextVerticalFlag = true; + break; + } + if (drawAxisTextVerticalFlag) { + annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); + annotationText.setText(axisText); + m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, + axisTextCenterY, + 0.0, + annotationText); + } + else { + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + annotationText.setText(axisText); + m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, + axisTextCenterY, + 0.0, + annotationText); + } + } + } +} + diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 2d9125e54..6540389fd 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -28,6 +28,7 @@ namespace caret { class CaretPreferences; + class ChartTwoCartesianAxis; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; @@ -90,7 +91,8 @@ namespace caret { void resetIdentification(); - void addToHistogramIdentification(const int barIndex, + void addToHistogramIdentification(const int32_t mapIndex, + const int32_t bucketIndex, uint8_t rgbaForColorIdentificationOut[4]); void processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart); @@ -116,6 +118,27 @@ namespace caret { const int32_t mapIndex, const HistogramDrawingInfo& histogramDrawingInfo); + void drawChartGraphicsBoxAndSetViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const Margins& margins, + int32_t chartGraphicsDrawingViewportOut[4]); + + void drawChartAxisCartesian(const float dataBounds[4], + const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + Margins& margins, + ChartTwoCartesianAxis* axis); + + void estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], + const float viewportHeight, + ChartTwoCartesianAxis* cartesianAxis, + double& widthOut, + double& heightOut); + Brain* m_brain; ModelChartTwo* m_chartTwoModel; @@ -148,7 +171,7 @@ namespace caret { bool m_identificationModeFlag; - static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 1; + static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 31feeb276..aa505f43a 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -24,6 +24,7 @@ #undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "CaretAssert.h" +#include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" @@ -61,7 +62,42 @@ m_tabIndex(tabIndex) { m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; - m_sceneAssistant = new SceneClassAssistant(); + m_chartAxisLeft = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT)); + m_chartAxisRight = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT)); + m_chartAxisBottom = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); + + m_chartAxisLeft->setVisible(false); + m_chartAxisRight->setVisible(false); + m_chartAxisBottom->setVisible(false); + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + m_chartAxisLeft->setVisible(true); + m_chartAxisLeft->setLabelText("Counts"); + m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisBottom->setVisible(true); + m_chartAxisBottom->setLabelText("Data"); + m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + m_chartAxisLeft->setVisible(true); + m_chartAxisBottom->setVisible(true); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_chartAxisLeft", + "ChartTwoCartesianAxis", + m_chartAxisLeft.get()); + m_sceneAssistant->add("m_chartAxisRight", + "ChartTwoCartesianAxis", + m_chartAxisRight.get()); + m_sceneAssistant->add("m_chartAxisBottom", + "ChartTwoCartesianAxis", + m_chartAxisBottom.get()); m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); @@ -550,6 +586,60 @@ ChartTwoOverlaySet::receiveEvent(Event* event) // } } +/** + * @return The chart left-axis. + */ +ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisLeft() +{ + return m_chartAxisLeft.get(); +} + +/** + * @return The chart left-axis (const method) + */ +const ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisLeft() const +{ + return m_chartAxisLeft.get(); +} + +/** + * @return The chart right-axis. + */ +ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisRight() +{ + return m_chartAxisRight.get(); +} + +/** + * @return The chart right-axis (const method) + */ +const ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisRight() const +{ + return m_chartAxisRight.get(); +} + +/** + * @return The chart bottom-axis. + */ +ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisBottom() +{ + return m_chartAxisBottom.get(); +} + +/** + * @return The chart bottom-axis (const method) + */ +const ChartTwoCartesianAxis* +ChartTwoOverlaySet::getChartAxisBottom() const +{ + return m_chartAxisBottom.get(); +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 5922f0a00..15eb3baca 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -20,6 +20,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ +#include #include "BrainConstants.h" #include "CaretObject.h" @@ -29,6 +30,7 @@ namespace caret { + class ChartTwoCartesianAxis; class ChartTwoOverlay; class PlainTextStringBuilder; class SceneClassAssistant; @@ -58,6 +60,18 @@ namespace caret { int32_t getNumberOfDisplayedOverlays() const; + ChartTwoCartesianAxis* getChartAxisLeft(); + + const ChartTwoCartesianAxis* getChartAxisLeft() const; + + ChartTwoCartesianAxis* getChartAxisRight(); + + const ChartTwoCartesianAxis* getChartAxisRight() const; + + ChartTwoCartesianAxis* getChartAxisBottom(); + + const ChartTwoCartesianAxis* getChartAxisBottom() const; + void insertOverlayAbove(const int32_t overlayIndex); void insertOverlayBelow(const int32_t overlayIndex); @@ -114,6 +128,12 @@ namespace caret { const ChartTwoDataTypeEnum::Enum m_chartDataType; + std::unique_ptr m_chartAxisLeft; + + std::unique_ptr m_chartAxisRight; + + std::unique_ptr m_chartAxisBottom; + const AString m_name; const int32_t m_tabIndex; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 747731b5d..9acb4e536 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -45,6 +45,8 @@ #include "FociFile.h" #include "Focus.h" #include "GiftiLabel.h" +#include "Histogram.h" +#include "HistogramDrawingInfo.h" #include "ImageFile.h" #include "OverlaySet.h" #include "SelectionItemBorderSurface.h" @@ -800,20 +802,73 @@ IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(Identif const SelectionItemChartTwoHistogram* idChartTwoHistogram) const { if (idChartTwoHistogram->isValid()) { - const ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); - const int32_t barIndex = idChartTwoHistogram->getBarIndex(); - - const CaretMappableDataFile* mapFile = fileHistogramChart->getCaretMappableDataFile(); + ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); + const int32_t mapIndex = idChartTwoHistogram->getMapIndex(); + const int32_t bucketIndex = idChartTwoHistogram->getBucketIndex(); + CaretMappableDataFile* mapFile = fileHistogramChart->getCaretMappableDataFile(); CaretAssert(mapFile); - - AString boldText("Histogram"); - idText.addLine(false, - boldText, - mapFile->getFileNameNoPath()); - - idText.addLine(true, - "Bar Index", - (AString::number(barIndex))); + + const bool allMapsFlag = (mapIndex < 0); + HistogramDrawingInfo histogramDrawingInfo; + AString errorMessage; + if (mapFile->getMapHistogramDrawingInfo(mapIndex, + allMapsFlag, + false, + histogramDrawingInfo, + errorMessage)) { + if (histogramDrawingInfo.isValid()) { + + float bucketValue = 0.0; + float bucketHeight = 0.0; + if (histogramDrawingInfo.getBucketDataValueAndCount(bucketIndex, + bucketValue, + bucketHeight)) { + + AString boldText("Histogram"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + idText.addLine(true, + "Bucket Index", + (AString::number(bucketIndex))); + idText.addLine(true, + "Data Value at Bucket", + (AString::number(bucketValue))); + + idText.addLine(true, + "Bucket Count", + (AString::number(bucketHeight))); + } + } + } +// if (mapFile->getNumberOfMaps() > 0) { +// const Histogram* histogram = ((mapIndex >= 0) +// ? mapFile->getMapHistogram(mapIndex) +// : mapFile->getFileHistogram()); +// +// float bucketValue = 0.0; +// float bucketHeight = 0.0; +// if (histogram->getBucketDataValueAndCount(bucketIndex, +// bucketValue, +// bucketHeight)) { +// AString boldText("Histogram"); +// idText.addLine(false, +// boldText, +// mapFile->getFileNameNoPath()); +// +// idText.addLine(true, +// "Bucket Index", +// (AString::number(bucketIndex))); +// +// idText.addLine(true, +// "Data Value at Bucket", +// (AString::number(bucketValue))); +// +// idText.addLine(true, +// "Bucket Count", +// (AString::number(bucketHeight))); +// } +// } } } diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index c5c5d8c1b..32600eec0 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -74,9 +74,9 @@ ModelChartTwo::ModelChartTwo(Brain* brain) "Line Series Chart Overlays")); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); - m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, - DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); + //m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); + //m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, + // DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); } @@ -110,11 +110,11 @@ ModelChartTwo::~ModelChartTwo() removeAllCharts(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - delete m_chartableMatrixFileSelectionModel[i]; - m_chartableMatrixFileSelectionModel[i] = NULL; + //delete m_chartableMatrixFileSelectionModel[i]; + //m_chartableMatrixFileSelectionModel[i] = NULL; - delete m_chartableMatrixSeriesFileSelectionModel[i]; - m_chartableMatrixSeriesFileSelectionModel[i] = NULL; + //delete m_chartableMatrixSeriesFileSelectionModel[i]; + //m_chartableMatrixSeriesFileSelectionModel[i] = NULL; delete m_chartTwoMatrixDisplayProperties[i]; m_chartTwoMatrixDisplayProperties[i] = NULL; @@ -703,8 +703,8 @@ ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAtt const std::vector tabIndices = matrixPropsMap->getKeys(); for (const int32_t tabIndex : tabIndices) { const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); - m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); + //m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, + // sceneClass); } } @@ -834,8 +834,8 @@ ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, destinationTabIndex); m_selectedChartTwoDataType[destinationTabIndex] = m_selectedChartTwoDataType[sourceTabIndex]; - m_chartableMatrixFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixFileSelectionModel[sourceTabIndex]->getSelectedFile()); - m_chartableMatrixSeriesFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixSeriesFileSelectionModel[sourceTabIndex]->getSelectedFile()); + //m_chartableMatrixFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixFileSelectionModel[sourceTabIndex]->getSelectedFile()); + //m_chartableMatrixSeriesFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixSeriesFileSelectionModel[sourceTabIndex]->getSelectedFile()); } diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index 0fa7c5fb3..6661ec9bc 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -152,9 +152,9 @@ namespace caret { mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + //CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + //CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; std::unique_ptr m_sceneAssistant; }; diff --git a/src/Brain/SelectionItemChartTwoHistogram.cxx b/src/Brain/SelectionItemChartTwoHistogram.cxx index b9a44c20f..396918730 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.cxx +++ b/src/Brain/SelectionItemChartTwoHistogram.cxx @@ -41,7 +41,8 @@ SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_HISTOGRAM) { m_fileHistogramChart = NULL; - m_barIndex = -1; + m_mapIndex = -1; + m_bucketIndex = -1; } /** @@ -88,27 +89,53 @@ void SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) { m_fileHistogramChart = obj.m_fileHistogramChart; - m_barIndex = obj.m_barIndex; + m_mapIndex = obj.m_mapIndex; + m_bucketIndex = obj.m_bucketIndex; } + ChartableTwoFileHistogramChart* SelectionItemChartTwoHistogram::getFileHistogramChart() const { return m_fileHistogramChart; } +/** + * @return Index of map index selected. + */ +int32_t +SelectionItemChartTwoHistogram::getMapIndex() const +{ + return m_mapIndex; +} + +/** + * @return Index of histogram bucket selected. + */ int32_t -SelectionItemChartTwoHistogram::getBarIndex() const +SelectionItemChartTwoHistogram::getBucketIndex() const { - return m_barIndex; + return m_bucketIndex; } +/* + * Set histogram identification. + * + * @param fileHistogramChart + * The histogram chart. + * @param mapIndex + * Index of the map whose histogram is displayed (negative indicates all maps). + * @param bucketIndex + * Index of the histogram bucket. + */ void SelectionItemChartTwoHistogram::setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, - const int32_t barIndex) + const int32_t mapIndex, + const int32_t bucketIndex) { m_fileHistogramChart = fileHistogramChart; - m_barIndex = barIndex; + m_mapIndex = mapIndex; + m_bucketIndex = bucketIndex; } /** @@ -117,8 +144,11 @@ SelectionItemChartTwoHistogram::setHistogramChart(ChartableTwoFileHistogramChart bool SelectionItemChartTwoHistogram::isValid() const { + /* + * Map index is negative if all maps selected. + */ if ((m_fileHistogramChart != NULL) - && (m_barIndex >= 0)) { + && (m_bucketIndex >= 0)) { return true; } @@ -132,7 +162,8 @@ void SelectionItemChartTwoHistogram::reset() { m_fileHistogramChart = NULL; - m_barIndex = -1; + m_mapIndex = -1; + m_bucketIndex = -1; } diff --git a/src/Brain/SelectionItemChartTwoHistogram.h b/src/Brain/SelectionItemChartTwoHistogram.h index da8101225..dcde564b8 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.h +++ b/src/Brain/SelectionItemChartTwoHistogram.h @@ -47,10 +47,13 @@ namespace caret { ChartableTwoFileHistogramChart* getFileHistogramChart() const; - int32_t getBarIndex() const; + int32_t getBucketIndex() const; + + int32_t getMapIndex() const; void setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, - const int32_t barIndex); + const int32_t mapIndex, + const int32_t bucketIndex); // ADD_NEW_METHODS_HERE @@ -59,7 +62,8 @@ namespace caret { ChartableTwoFileHistogramChart* m_fileHistogramChart; - int32_t m_barIndex; + int32_t m_mapIndex; + int32_t m_bucketIndex; // ADD_NEW_MEMBERS_HERE diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index efbc29521..3989fa70a 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -38,6 +38,8 @@ ChartSelectionModeEnum.h ChartOneDataTypeEnum.h ChartingVersionEnum.h +ChartTwoAxisScaleRangeModeEnum.h +ChartTwoCartesianAxis.h ChartTwoCompoundDataType.h ChartTwoData.h ChartTwoDataCartesian.h @@ -51,6 +53,7 @@ ChartTwoMatrixDisplayProperties.h ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h +ChartTwoAxisScaleRangeModeEnum.cxx ChartAxis.cxx ChartAxisCartesian.cxx ChartAxisLocationEnum.cxx @@ -74,6 +77,7 @@ ChartSelectionModeEnum.cxx ChartOneDataTypeEnum.cxx ChartingVersionEnum.cxx +ChartTwoCartesianAxis.cxx ChartTwoCompoundDataType.cxx ChartTwoData.cxx ChartTwoDataCartesian.cxx diff --git a/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx new file mode 100644 index 000000000..c5353a7e4 --- /dev/null +++ b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ +#include "ChartTwoAxisScaleRangeModeEnum.h" +#undef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoAxisScaleRangeModeEnum + * \brief Chart Two Axis Scale Range Mode. + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoAxisScaleRangeModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoAxisScaleRangeModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoAxisScaleRangeModeEnum.h" + * + * Instatiate: + * m_chartTwoAxisScaleRangeModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoAxisScaleRangeModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoAxisScaleRangeModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoAxisScaleRangeModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoAxisScaleRangeModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoAxisScaleRangeModeEnum::Enum VARIABLE = m_chartTwoAxisScaleRangeModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoAxisScaleRangeModeEnum::ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoAxisScaleRangeModeEnum::~ChartTwoAxisScaleRangeModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoAxisScaleRangeModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_AUTO, + "AXIS_DATA_RANGE_AUTO", + "Axis Data Range Auto")); + + enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_USER, + "AXIS_DATA_RANGE_USER", + "Axis Data Range User")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoAxisScaleRangeModeEnum* +ChartTwoAxisScaleRangeModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoAxisScaleRangeModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoAxisScaleRangeModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoAxisScaleRangeModeEnum::Enum +ChartTwoAxisScaleRangeModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoAxisScaleRangeModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoAxisScaleRangeModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoAxisScaleRangeModeEnum::Enum +ChartTwoAxisScaleRangeModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoAxisScaleRangeModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoAxisScaleRangeModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoAxisScaleRangeModeEnum::Enum +ChartTwoAxisScaleRangeModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoAxisScaleRangeModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoAxisScaleRangeModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoAxisScaleRangeModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoAxisScaleRangeModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoAxisScaleRangeModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoAxisScaleRangeModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoAxisScaleRangeModeEnum.h b/src/Charting/ChartTwoAxisScaleRangeModeEnum.h new file mode 100644 index 000000000..0317d5344 --- /dev/null +++ b/src/Charting/ChartTwoAxisScaleRangeModeEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ +#define __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoAxisScaleRangeModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** */ + AXIS_DATA_RANGE_AUTO, + /** */ + AXIS_DATA_RANGE_USER + }; + + + ~ChartTwoAxisScaleRangeModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoAxisScaleRangeModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ +std::vector ChartTwoAxisScaleRangeModeEnum::enumData; +bool ChartTwoAxisScaleRangeModeEnum::initializedFlag = false; +int32_t ChartTwoAxisScaleRangeModeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx new file mode 100644 index 000000000..6f2e840b9 --- /dev/null +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -0,0 +1,653 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_CARTESIAN_AXIS_DECLARE__ +#include "ChartTwoCartesianAxis.h" +#undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "ChartScaleAutoRanging.h" +#include "MathFunctions.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoCartesianAxis + * \brief Chart Two Cartesian Axis Attributes. + * \ingroup Charting + */ + +/** + * Constructor. + * + * @param axisLocation + * Location of the axis (left, right, bottom, top) + */ +ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum axisLocation) +: CaretObject(), +m_axisLocation(axisLocation) +{ + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_userScaleMinimumValue", + &m_userScaleMinimumValue); + m_sceneAssistant->add("m_userScaleMaximumValue", + &m_userScaleMaximumValue); + m_sceneAssistant->add("m_minimumValue", + &m_minimumValue); + m_sceneAssistant->add("m_maximumValue", + &m_maximumValue); + m_sceneAssistant->add("m_axisLabelsMinimumValue", + &m_axisLabelsMinimumValue); + m_sceneAssistant->add("m_axisLabelsMaximumValue", + &m_axisLabelsMaximumValue); + m_sceneAssistant->add("m_axisLabelsStepValue", + &m_axisLabelsStepValue); + m_sceneAssistant->add("m_axisDigitsRightOfDecimal", + &m_axisDigitsRightOfDecimal); + + m_sceneAssistant->add("m_scaleRangeMode", + &m_scaleRangeMode); + m_sceneAssistant->add("m_units", + &m_units); + m_sceneAssistant->add("m_numericFormat", + &m_numericFormat); + m_sceneAssistant->add("m_numberOfSubdivisions", + &m_numberOfSubdivisions); + m_sceneAssistant->add("m_labelText", + &m_labelText); + m_sceneAssistant->add("m_visible", + &m_visible); + m_sceneAssistant->add("m_showTickmarks", + &m_showTickmarks); +} + +/** + * Destructor. + */ +ChartTwoCartesianAxis::~ChartTwoCartesianAxis() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj) +: CaretObject(obj), +m_axisLocation(obj.m_axisLocation) +{ + this->copyHelperChartTwoCartesianAxis(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoCartesianAxis& +ChartTwoCartesianAxis::operator=(const ChartTwoCartesianAxis& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperChartTwoCartesianAxis(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj) +{ + CaretAssert(m_axisLocation == obj.m_axisLocation); + + m_userScaleMinimumValue = obj.m_userScaleMinimumValue; + m_userScaleMaximumValue = obj.m_userScaleMaximumValue; + m_minimumValue = obj.m_minimumValue; + m_maximumValue = obj.m_maximumValue; + m_axisLabelsMinimumValue = obj.m_axisLabelsMinimumValue; + m_axisLabelsMaximumValue = obj.m_axisLabelsMaximumValue; + m_axisLabelsStepValue = obj.m_axisLabelsStepValue; + m_axisDigitsRightOfDecimal = obj.m_axisDigitsRightOfDecimal; + m_scaleRangeMode = obj.m_scaleRangeMode; + m_units = obj.m_units; + m_numericFormat = obj.m_numericFormat; + m_numberOfSubdivisions = obj.m_numberOfSubdivisions; + m_labelText = obj.m_labelText; + m_visible = obj.m_visible; + m_showTickmarks = obj.m_showTickmarks; +} + +/** + * @return The axis location (left, right, bottom, top) + */ +ChartAxisLocationEnum::Enum +ChartTwoCartesianAxis::getAxisLocation() const +{ + return m_axisLocation; +} + +/** + * @return Number of subdivisions + */ +int32_t +ChartTwoCartesianAxis::getNumberOfSubdivisions() const +{ + return m_numberOfSubdivisions; +} + +/** + * Set Number of subdivisions + * @param numberOfSubdivisions + * New value for Number of subdivisions + */ +void +ChartTwoCartesianAxis::setNumberOfSubdivisions(const int32_t numberOfSubdivisions) +{ + m_numberOfSubdivisions = numberOfSubdivisions; +} + +/** + * @return User scale's minimum value + */ +float +ChartTwoCartesianAxis::getUserScaleMinimumValue() const +{ + return m_userScaleMinimumValue; +} + +/** + * @return User scale's maximum value + */ +float +ChartTwoCartesianAxis::getUserScaleMaximumValue() const +{ + return m_userScaleMaximumValue; +} + +/** + * Set User scale's maximum value + * @param userScaleMaximumValue + * New value for User scale's maximum value + */ +void +ChartTwoCartesianAxis::setUserScaleMaximumValue(const float userScaleMaximumValue) +{ + m_userScaleMaximumValue = userScaleMaximumValue; +} + +/** + * Set User scale's minimum value + * @param userScaleMinimumValue + * New value for User scale's minimum value + */ +void +ChartTwoCartesianAxis::setUserScaleMinimumValue(const float userScaleMinimumValue) +{ + m_userScaleMinimumValue = userScaleMinimumValue; +} + +/** + * @return The minimum value for the axis. + */ +float +ChartTwoCartesianAxis::getMinimumValue() const +{ + return m_minimumValue; +} + +/** + * @return The maximum value for the axis. + */ +float +ChartTwoCartesianAxis::getMaximumValue() const +{ + return m_maximumValue; +} + +/** + * @return Is the axis visible + */ +bool +ChartTwoCartesianAxis::isVisible() const +{ + return m_visible; +} + +/** + * Set visibility for the axis + * + * @param visible + * New value for axis visibility + */ +void +ChartTwoCartesianAxis::setVisible(const bool visible) +{ + m_visible = visible; +} + +/** + * @return Show axis tickmarks + */ +bool +ChartTwoCartesianAxis::isShowTickmarks() const +{ + return m_showTickmarks; +} + +/** + * Set Show axis tickmarks + * @param showTickmarks + * New value for Show axis tickmarks + */ +void +ChartTwoCartesianAxis::setShowTickmarks(const bool showTickmarks) +{ + m_showTickmarks = showTickmarks; +} + +/** + * @return Scale Range Mode + */ +ChartTwoAxisScaleRangeModeEnum::Enum +ChartTwoCartesianAxis::getScaleRangeMode() const +{ + return m_scaleRangeMode; +} + +/** + * Set Scale Range Mode + * + * @param scaleRangeMode + * New value for Scale Range Mode + */ +void +ChartTwoCartesianAxis::setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode) +{ + m_scaleRangeMode = scaleRangeMode; +} + +/** + * @return Axis units + */ +ChartAxisUnitsEnum::Enum +ChartTwoCartesianAxis::getUnits() const +{ + return m_units; +} + +/** + * Set Axis units + * + * @param units + * New value for Axis units + */ +void +ChartTwoCartesianAxis::setUnits(const ChartAxisUnitsEnum::Enum units) +{ + m_units = units; +} + +/** + * @return Numeric format mode + */ +NumericFormatModeEnum::Enum +ChartTwoCartesianAxis::getNumericFormat() const +{ + return m_numericFormat; +} + +/** + * Set Numeric format mode + * + * @param numericFormat + * New value for Numeric format mode + */ +void +ChartTwoCartesianAxis::setNumericFormat(const NumericFormatModeEnum::Enum numericFormat) +{ + m_numericFormat = numericFormat; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +ChartTwoCartesianAxis::toString() const +{ + return "ChartTwoCartesianAxis"; +} + +/** + * @return Text for axis label + */ +AString +ChartTwoCartesianAxis::getLabelText() const +{ + return m_labelText; +} + +/** + * Set Text for axis label + * + * @param labelText + * New value for Text for axis label + */ +void +ChartTwoCartesianAxis::setLabelText(const AString& labelText) +{ + m_labelText = labelText; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoCartesianAxis::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoCartesianAxis", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + +/** + * Update for auto range scale. + * + * @param dataBounds + * Bounds of data [minX, maxX, minY, maxY]. + */ +void +ChartTwoCartesianAxis::updateForAutoRangeScale(const float dataBounds[4]) +{ + float minValue = m_minimumValue; + float maxValue = m_maximumValue; + + switch (m_scaleRangeMode) { + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + { + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + minValue = dataBounds[0]; + maxValue = dataBounds[1]; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + minValue = dataBounds[2]; + maxValue = dataBounds[3]; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + minValue = dataBounds[2]; + maxValue = dataBounds[3]; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + minValue = dataBounds[0]; + maxValue = dataBounds[1]; + break; + } + + m_minimumValue = minValue; + m_maximumValue = maxValue; + } + break; + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + break; + } + + double scaleStep = 0.0; + double scaleMin = 0.0; + double scaleMax = 0.0; + int32_t digitsRightOfDecimal = 0; + + ChartScaleAutoRanging::createAutoScale(m_minimumValue, + m_maximumValue, + scaleMin, + scaleMax, + scaleStep, + digitsRightOfDecimal); + m_axisLabelsMinimumValue = scaleMin; + m_axisLabelsMaximumValue = scaleMax; + m_axisLabelsStepValue = scaleStep; + m_axisDigitsRightOfDecimal = digitsRightOfDecimal; + + /** + * Use auto-scaled range for left and right axis + */ + switch (m_scaleRangeMode) { + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + m_minimumValue = m_axisLabelsMinimumValue; + m_maximumValue = m_axisLabelsMaximumValue; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_minimumValue = m_axisLabelsMinimumValue; + m_maximumValue = m_axisLabelsMaximumValue; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + break; + } + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + break; + } +} + +/** + * Get the axis labels and their positions for drawing the scale. + * + * @param dataBounds + * Bounds of data [minX, maxX, minY, maxY]. + * @param axisLengthInPixels + * Length of axis in pixels. + * @param fontSizeInPixels + * Size of the font in pixels. + * @param labelOffsetInPixelsOut + * Output containing offset in pixels for the scale labels. + * @param labelTextOut + * Output containing text for scale labels. + */ +void +ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], + const float axisLengthInPixels, + const float /*fontSizeInPixels*/, + std::vector& labelOffsetInPixelsOut, + std::vector& labelTextOut) +{ + labelOffsetInPixelsOut.clear(); + labelTextOut.clear(); + + if (axisLengthInPixels < 25.0) { + return; + } + + updateForAutoRangeScale(dataBounds); + + float dataStart = m_minimumValue; + float dataEnd = m_maximumValue; + float dataRange = (m_maximumValue - m_minimumValue); + if (dataRange <= 0.0) { + return; + } + + float labelsStart = m_axisLabelsMinimumValue; + float labelsEnd = m_axisLabelsMaximumValue; + /* + * If the "labels end" or "labels start" value is not valid (infinity or not-a-number) there + * are invalid values in the data and will cause the labels processing later + * in this method to fail. So, alert the user that there is a problem in + * the data. + * + * A set is used to track those models for which the user has + * already been alerted. Otherwise, the alert message will be + * displayed every time this method is called (which is many) and + * the user will receive endless pop-ups. + */ + if ( (! MathFunctions::isNumeric(labelsStart)) + || (! MathFunctions::isNumeric(labelsEnd))) { + const AString msg("Invalid numbers (infinity or not-a-number) found when trying to create chart. " + "Run \"wb_command -file-information\" on files being charted to find the file " + "that contains invalid data so that the file can be fixed."); + CaretLogWarning(msg); + return; + } + + float labelsRange = (m_axisLabelsMaximumValue - m_axisLabelsMinimumValue); + if (labelsRange <= 0.0) { + return; + } + + const float tickLabelsStep = m_axisLabelsStepValue; + if (tickLabelsStep <= 0.0) { + return; + } + + + float labelValue = labelsStart; + while (labelValue <= labelsEnd) { + float labelParametricValue = (labelValue - dataStart) / dataRange; + + float labelValueForText = labelValue; + + if (dataRange >= 10.0) { + /* + * Is this the first label? + */ + if (labelValue <= labelsStart) { + /* + * Handles case when the minimum DATA value is just a little + * bit greater than the minimum value for axis labels such + * as in Data-Series data when the minimum data value is "1" + * and the minimum axis label value is "0". Without this + * code no value is displayed at the left edge of the axis. + */ + if (labelParametricValue < 0.0) { + const float nextParametricValue = ((labelValue + tickLabelsStep) - dataStart) / dataRange; + if (nextParametricValue > 0.05) { + labelParametricValue = 0.0; + labelValueForText = dataStart; + } + } + } + + if (labelParametricValue < 0.0) { + if (labelParametricValue >= -0.01) { + labelParametricValue = 0.0; + } + } + + /* + * Is this the last label? + */ + if (labelValue >= labelsEnd) { + /* + * Like above, ensures a value is displayed at the right + * edge of the axis. + */ + if (labelParametricValue > 1.0) { + const float prevParametricValue = ((labelValue - tickLabelsStep) - dataStart) / dataRange; + if (prevParametricValue < 0.95) { + labelParametricValue = 1.0; + labelValueForText = dataEnd; + } + } + } + + if (labelParametricValue > 1.0) { + if (labelParametricValue < 1.01) { + labelParametricValue = 1.0; + } + } + } + + if ((labelParametricValue >= 0.0) + && (labelParametricValue <= 1.0)) { + const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; + const AString labelText = AString::number(labelValueForText, 'f', m_axisDigitsRightOfDecimal); + + labelOffsetInPixelsOut.push_back(labelPixelsPosition); + labelTextOut.push_back(labelText); + } + else { + // std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; + } + + labelValue += tickLabelsStep; + } +} diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h new file mode 100644 index 000000000..7fa5f38cb --- /dev/null +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -0,0 +1,169 @@ +#ifndef __CHART_TWO_CARTESIAN_AXIS_H__ +#define __CHART_TWO_CARTESIAN_AXIS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" +#include "ChartAxisLocationEnum.h" +#include "ChartAxisUnitsEnum.h" +#include "ChartTwoAxisScaleRangeModeEnum.h" +#include "HistogramDrawingInfo.h" +#include "NumericFormatModeEnum.h" +#include "SceneableInterface.h" + + +namespace caret { + class SceneClassAssistant; + + class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { + + public: + ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum axisLocation); + + virtual ~ChartTwoCartesianAxis(); + + ChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); + + ChartTwoCartesianAxis& operator=(const ChartTwoCartesianAxis& obj); + + ChartAxisLocationEnum::Enum getAxisLocation() const; + + float getUserScaleMinimumValue() const; + + void setUserScaleMinimumValue(const float value); + + float getUserScaleMaximumValue() const; + + void setUserScaleMaximumValue(const float value); + + float getMinimumValue() const; + + float getMaximumValue() const; + + ChartTwoAxisScaleRangeModeEnum::Enum getScaleRangeMode() const; + + void setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode); + + ChartAxisUnitsEnum::Enum getUnits() const; + + void setUnits(ChartAxisUnitsEnum::Enum units); + + NumericFormatModeEnum::Enum getNumericFormat() const; + + void setNumericFormat(const NumericFormatModeEnum::Enum numericFormat); + + int32_t getNumberOfSubdivisions() const; + + void setNumberOfSubdivisions(const int32_t numberOfSubdivisions); + + bool isVisible() const; + + void setVisible(const bool visible); + + bool isShowTickmarks() const; + + void setShowTickmarks(const bool showTickmarks); + + void getLabelsAndPositions(const float dataBounds[4], + const float axisLengthInPixels, + const float fontSizeInPixels, + std::vector& labelOffsetInPixelsOut, + std::vector& labelTextOut); + + AString getLabelText() const; + + void setLabelText(const AString& labelText); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); + + virtual void updateForAutoRangeScale(const float dataBounds[4]); + + std::unique_ptr m_sceneAssistant; + + const ChartAxisLocationEnum::Enum m_axisLocation; + + float m_userScaleMinimumValue = -1.0; + + float m_userScaleMaximumValue = 1.0; + + float m_minimumValue = 0.0; + + float m_maximumValue = 100.0; + + float m_axisLabelsMinimumValue = 0.0; + + float m_axisLabelsMaximumValue = 100.0; + + float m_axisLabelsStepValue = 1.0; + + int32_t m_axisDigitsRightOfDecimal = 1; + + ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; + + ChartAxisUnitsEnum::Enum m_units = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + + NumericFormatModeEnum::Enum m_numericFormat = NumericFormatModeEnum::AUTO; + + int32_t m_numberOfSubdivisions = 2; + + AString m_labelText; + + bool m_visible = false; + + bool m_showTickmarks = true; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ + // +#endif // __CHART_TWO_CARTESIAN_AXIS_DECLARE__ + +} // namespace +#endif //__CHART_TWO_CARTESIAN_AXIS_H__ diff --git a/src/Common/HistogramDrawingInfo.cxx b/src/Common/HistogramDrawingInfo.cxx index 9cfb0bad0..7f09dd24a 100644 --- a/src/Common/HistogramDrawingInfo.cxx +++ b/src/Common/HistogramDrawingInfo.cxx @@ -182,6 +182,34 @@ HistogramDrawingInfo::getNumberOfDataPoints() const return m_dataX.size(); } +/** + * Get the bucket value (x-axis) and bucket display value (y-axis) + * for the given bucket index. + * + * @param bucketIndex + * Index of the bucket. + * @param bucketValueOut + * Output with bucket value (x-axis) + * @param bucketHeightOut + * Output with bucket height (y-axis) + * @return + * True if output values are valid, else false. + */ +bool +HistogramDrawingInfo::getBucketDataValueAndCount(const int32_t bucketIndex, + float& bucketValueOut, + float& bucketDisplayValueOut) const +{ + if ((bucketIndex >= 0) + && (bucketIndex < static_cast(m_dataX.size()))) { + bucketValueOut = m_dataX[bucketIndex]; + CaretAssert(m_dataX.size() == m_dataY.size()); + bucketDisplayValueOut = m_dataY[bucketIndex]; + return true; + } + + return false; +} /** * Get a description of this object's content. diff --git a/src/Common/HistogramDrawingInfo.h b/src/Common/HistogramDrawingInfo.h index 20d8791c2..accbe5bca 100644 --- a/src/Common/HistogramDrawingInfo.h +++ b/src/Common/HistogramDrawingInfo.h @@ -60,6 +60,9 @@ namespace caret { /** @return XYZ coordinates for threshold two bounds, may be empty ! */ const std::vector& getThresholdTwoBounds() const { return m_thresholdTwoBoundsXYZ; } + bool getBucketDataValueAndCount(const int32_t bucketIndex, + float& bucketValueOut, + float& bucketDisplayValueOut) const; // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index ccdf08a20..f27b8d02b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1433,6 +1433,7 @@ BrainBrowserWindowToolBar::updateToolBar() { ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { + showChartOneTypeWidget = true; switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; diff --git a/src/GuiQt/PreferencesDialog.cxx b/src/GuiQt/PreferencesDialog.cxx index 7ec3766ff..73adaf469 100644 --- a/src/GuiQt/PreferencesDialog.cxx +++ b/src/GuiQt/PreferencesDialog.cxx @@ -803,7 +803,7 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) break; case PREF_COLOR_CHART_THRESHOLD: colors.getColorChartHistogramThreshold(rgb); - prefColorName = "Chart Histohram Threshold"; + prefColorName = "Chart Histogram Threshold"; break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); -- GitLab From 142f894a4bf86488febec375f6a593623a560040 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 15 Feb 2017 09:02:34 -0600 Subject: [PATCH 205/755] Continuing charting development. Cleaned up chart two axes. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 107 ++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 8 +- src/Charting/ChartTwoCartesianAxis.cxx | 303 +++++++++--------- src/Charting/ChartTwoCartesianAxis.h | 43 ++- 4 files changed, 245 insertions(+), 216 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index bf2e29779..71bfd7a79 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -406,35 +406,54 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() if ((vpWidth > (marginSize * 3)) && (vpHeight > (marginSize * 3))) { + float axisMinimumValue = 0.0; + float axisMaximumValue = 0.0; + /* Draw legends and grids */ + if (drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + leftAxis, + axisMinimumValue, + axisMaximumValue)) { + yMin = axisMinimumValue; + yMax = axisMaximumValue; + } + drawChartAxisCartesian(bounds, vpX, vpY, vpWidth, vpHeight, margins, - leftAxis); - drawChartAxisCartesian(bounds, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - rightAxis); - drawChartAxisCartesian(bounds, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - bottomAxis); + rightAxis, + axisMinimumValue, + axisMaximumValue); + if (drawChartAxisCartesian(bounds, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + bottomAxis, + axisMinimumValue, + axisMaximumValue)) { + xMin = axisMinimumValue; + xMax = axisMaximumValue; + } + drawChartAxisCartesian(bounds, vpX, vpY, vpWidth, vpHeight, margins, - topAxis); + topAxis, + axisMinimumValue, + axisMaximumValue); drawChartGraphicsBoxAndSetViewport(vpX, vpY, @@ -442,15 +461,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() vpHeight, margins, chartGraphicsDrawingViewport); - - if (leftAxis->isVisible()) { - yMin = leftAxis->getMinimumValue(); - yMax = leftAxis->getMaximumValue(); - } - if (bottomAxis->isVisible()) { - xMin = bottomAxis->getMinimumValue(); - xMax = bottomAxis->getMaximumValue(); - } } glViewport(chartGraphicsDrawingViewport[0], @@ -1892,11 +1902,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH * We are just estimating the width and height of the axes text labels. */ const float axisLength = 1000.0; + float minimumValue = 0.0; + float maximumValue = 0.0; std::vector labelOffsetInPixels; std::vector labelTexts; cartesianAxis->getLabelsAndPositions(dataBounds, axisLength, - fontSizeInPixels, + minimumValue, + maximumValue, labelOffsetInPixels, labelTexts); for (std::vector::iterator iter = labelTexts.begin(); @@ -2021,21 +2034,29 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons * (and not cut off). * @param axis * Axis that is drawn. + * @param axisMinimumOut + * Minimum value along the axis. + * @param axisMaximumOut + * Maximum value along the axis. + * @return + * True if the axis is valid and was drawn, else false. */ -void +bool BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], - const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, - Margins& margins, - ChartTwoCartesianAxis* axis) + const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const Margins& margins, + ChartTwoCartesianAxis* axis, + float& axisMinimumOut, + float& axisMaximumOut) { if (axis == NULL) { - return; + return false; } if ( ! axis->isVisible()) { - return; + return false; } float axisLength = 0.0; @@ -2053,11 +2074,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data std::vector labelOffsetInPixels; std::vector labelTexts; - axis->getLabelsAndPositions(dataBounds, - axisLength, - fontSizeInPixels, - labelOffsetInPixels, - labelTexts); + const bool validAxisFlag = axis->getLabelsAndPositions(dataBounds, + axisLength, + axisMinimumOut, + axisMaximumOut, + labelOffsetInPixels, + labelTexts); + if ( ! validAxisFlag) { + return false; + } const float rgba[4] = { m_fixedPipelineDrawing->m_foregroundColorFloat[0], @@ -2246,5 +2271,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data } } } + + return true; } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 6540389fd..5995987b7 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -125,13 +125,15 @@ namespace caret { const Margins& margins, int32_t chartGraphicsDrawingViewportOut[4]); - void drawChartAxisCartesian(const float dataBounds[4], + bool drawChartAxisCartesian(const float dataBounds[4], const float vpX, const float vpY, const float vpWidth, const float vpHeight, - Margins& margins, - ChartTwoCartesianAxis* axis); + const Margins& margins, + ChartTwoCartesianAxis* axis, + float& axisMinimumOut, + float& axisMaximumOut); void estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], const float viewportHeight, diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 6f2e840b9..6138bf057 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -56,27 +56,19 @@ m_axisLocation(axisLocation) &m_userScaleMinimumValue); m_sceneAssistant->add("m_userScaleMaximumValue", &m_userScaleMaximumValue); - m_sceneAssistant->add("m_minimumValue", - &m_minimumValue); - m_sceneAssistant->add("m_maximumValue", - &m_maximumValue); - m_sceneAssistant->add("m_axisLabelsMinimumValue", - &m_axisLabelsMinimumValue); - m_sceneAssistant->add("m_axisLabelsMaximumValue", - &m_axisLabelsMaximumValue); m_sceneAssistant->add("m_axisLabelsStepValue", &m_axisLabelsStepValue); - m_sceneAssistant->add("m_axisDigitsRightOfDecimal", - &m_axisDigitsRightOfDecimal); + m_sceneAssistant->add("m_userDigitsRightOfDecimal", + &m_userDigitsRightOfDecimal); m_sceneAssistant->add("m_scaleRangeMode", &m_scaleRangeMode); m_sceneAssistant->add("m_units", &m_units); - m_sceneAssistant->add("m_numericFormat", - &m_numericFormat); - m_sceneAssistant->add("m_numberOfSubdivisions", - &m_numberOfSubdivisions); + m_sceneAssistant->add("m_userNumericFormat", + &m_userNumericFormat); + m_sceneAssistant->add("m_userNumberOfSubdivisions", + &m_userNumberOfSubdivisions); m_sceneAssistant->add("m_labelText", &m_labelText); m_sceneAssistant->add("m_visible", @@ -133,16 +125,12 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_userScaleMinimumValue = obj.m_userScaleMinimumValue; m_userScaleMaximumValue = obj.m_userScaleMaximumValue; - m_minimumValue = obj.m_minimumValue; - m_maximumValue = obj.m_maximumValue; - m_axisLabelsMinimumValue = obj.m_axisLabelsMinimumValue; - m_axisLabelsMaximumValue = obj.m_axisLabelsMaximumValue; m_axisLabelsStepValue = obj.m_axisLabelsStepValue; - m_axisDigitsRightOfDecimal = obj.m_axisDigitsRightOfDecimal; + m_userDigitsRightOfDecimal = obj.m_userDigitsRightOfDecimal; m_scaleRangeMode = obj.m_scaleRangeMode; m_units = obj.m_units; - m_numericFormat = obj.m_numericFormat; - m_numberOfSubdivisions = obj.m_numberOfSubdivisions; + m_userNumericFormat = obj.m_userNumericFormat; + m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_labelText = obj.m_labelText; m_visible = obj.m_visible; m_showTickmarks = obj.m_showTickmarks; @@ -158,23 +146,45 @@ ChartTwoCartesianAxis::getAxisLocation() const } /** - * @return Number of subdivisions + * @return User's digits right of decimal point. */ int32_t -ChartTwoCartesianAxis::getNumberOfSubdivisions() const +ChartTwoCartesianAxis::getUserDigitsRightOfDecimal() const { - return m_numberOfSubdivisions; + return m_userDigitsRightOfDecimal; } /** - * Set Number of subdivisions + * Set user's digits right of decimal point. + * + * @param digitsRightOfDecimal + * Numer of digits right of decimal point. + */ +void +ChartTwoCartesianAxis::setUserDigitsRightOfDecimal(const int32_t digitsRightOfDecimal) +{ + m_userDigitsRightOfDecimal = digitsRightOfDecimal; +} + + +/** + * @return User's number of subdivisions + */ +int32_t +ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const +{ + return m_userNumberOfSubdivisions; +} + +/** + * Set User's number of subdivisions * @param numberOfSubdivisions * New value for Number of subdivisions */ void -ChartTwoCartesianAxis::setNumberOfSubdivisions(const int32_t numberOfSubdivisions) +ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions) { - m_numberOfSubdivisions = numberOfSubdivisions; + m_userNumberOfSubdivisions = numberOfSubdivisions; } /** @@ -217,24 +227,6 @@ ChartTwoCartesianAxis::setUserScaleMinimumValue(const float userScaleMinimumValu m_userScaleMinimumValue = userScaleMinimumValue; } -/** - * @return The minimum value for the axis. - */ -float -ChartTwoCartesianAxis::getMinimumValue() const -{ - return m_minimumValue; -} - -/** - * @return The maximum value for the axis. - */ -float -ChartTwoCartesianAxis::getMaximumValue() const -{ - return m_maximumValue; -} - /** * @return Is the axis visible */ @@ -319,24 +311,24 @@ ChartTwoCartesianAxis::setUnits(const ChartAxisUnitsEnum::Enum units) } /** - * @return Numeric format mode + * @return User's umeric format mode */ NumericFormatModeEnum::Enum -ChartTwoCartesianAxis::getNumericFormat() const +ChartTwoCartesianAxis::getUserNumericFormat() const { - return m_numericFormat; + return m_userNumericFormat; } /** - * Set Numeric format mode + * Set User's Numeric format mode * * @param numericFormat * New value for Numeric format mode */ void -ChartTwoCartesianAxis::setNumericFormat(const NumericFormatModeEnum::Enum numericFormat) +ChartTwoCartesianAxis::setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat) { - m_numericFormat = numericFormat; + m_userNumericFormat = numericFormat; } /** @@ -427,86 +419,71 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, } /** - * Update for auto range scale. + * Given the bounds of the data, determine the auto range minimum and maximum values. * * @param dataBounds - * Bounds of data [minX, maxX, minY, maxY]. + * Bounds of the data. + * @param minimumOut + * Output minimum value for autoranging. + * @param maximumOut + * Output maximum value for autoranging. + * @param stepValueOut + * Output step value for scale. + * @param digitsRightOfDecimalOut + * Output with digits right of decimal. + * @return + * True if output values are valid, else false. */ -void -ChartTwoCartesianAxis::updateForAutoRangeScale(const float dataBounds[4]) +bool +ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], + float& minimumOut, + float& maximumOut, + float& stepValueOut, + int32_t& digitsRightOfDecimalOut) const { - float minValue = m_minimumValue; - float maxValue = m_maximumValue; + float minValue = 1.0; + float maxValue = -1.0; - switch (m_scaleRangeMode) { - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: - { - switch (m_axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - minValue = dataBounds[0]; - maxValue = dataBounds[1]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - minValue = dataBounds[2]; - maxValue = dataBounds[3]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - minValue = dataBounds[2]; - maxValue = dataBounds[3]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - minValue = dataBounds[0]; - maxValue = dataBounds[1]; - break; - } - - m_minimumValue = minValue; - m_maximumValue = maxValue; - } + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + minValue = dataBounds[0]; + maxValue = dataBounds[1]; break; - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + minValue = dataBounds[2]; + maxValue = dataBounds[3]; break; - } - - double scaleStep = 0.0; - double scaleMin = 0.0; - double scaleMax = 0.0; - int32_t digitsRightOfDecimal = 0; - - ChartScaleAutoRanging::createAutoScale(m_minimumValue, - m_maximumValue, - scaleMin, - scaleMax, - scaleStep, - digitsRightOfDecimal); - m_axisLabelsMinimumValue = scaleMin; - m_axisLabelsMaximumValue = scaleMax; - m_axisLabelsStepValue = scaleStep; - m_axisDigitsRightOfDecimal = digitsRightOfDecimal; - - /** - * Use auto-scaled range for left and right axis - */ - switch (m_scaleRangeMode) { - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: - switch (m_axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - m_minimumValue = m_axisLabelsMinimumValue; - m_maximumValue = m_axisLabelsMaximumValue; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - m_minimumValue = m_axisLabelsMinimumValue; - m_maximumValue = m_axisLabelsMaximumValue; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + minValue = dataBounds[2]; + maxValue = dataBounds[3]; break; - } - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + minValue = dataBounds[0]; + maxValue = dataBounds[1]; break; } + + if (maxValue > minValue) { + double scaleStep = 0.0; + double scaleMin = 0.0; + double scaleMax = 0.0; + int32_t digitsRightOfDecimal = 0; + + ChartScaleAutoRanging::createAutoScale(minValue, + maxValue, + scaleMin, + scaleMax, + scaleStep, + digitsRightOfDecimal); + minimumOut = scaleMin; + maximumOut = scaleMax; + stepValueOut = scaleStep; + digitsRightOfDecimalOut = digitsRightOfDecimal; + + return true; + } + + return false; } /** @@ -515,39 +492,61 @@ ChartTwoCartesianAxis::updateForAutoRangeScale(const float dataBounds[4]) * @param dataBounds * Bounds of data [minX, maxX, minY, maxY]. * @param axisLengthInPixels - * Length of axis in pixels. - * @param fontSizeInPixels - * Size of the font in pixels. + * Length of axis in pixels. + * @param minimumOut + * Output minimum value for autoranging. + * @param maximumOut + * Output maximum value for autoranging. * @param labelOffsetInPixelsOut - * Output containing offset in pixels for the scale labels. + * Output containing offset in pixels for the scale labels. * @param labelTextOut - * Output containing text for scale labels. + * Output containing text for scale labels. + * @return + * True if output data is valid, else false. */ -void +bool ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], const float axisLengthInPixels, - const float /*fontSizeInPixels*/, + float& minimumOut, + float& maximumOut, std::vector& labelOffsetInPixelsOut, - std::vector& labelTextOut) + std::vector& labelTextOut) const { + minimumOut = 0.0; + maximumOut = 0.0; labelOffsetInPixelsOut.clear(); labelTextOut.clear(); if (axisLengthInPixels < 25.0) { - return; + return false; } - updateForAutoRangeScale(dataBounds); + float labelsStart = 0.0; + float labelsEnd = 0.0; + float labelsStep = 1.0; + int32_t labelsDigitsRightOfDecimal = 0; - float dataStart = m_minimumValue; - float dataEnd = m_maximumValue; - float dataRange = (m_maximumValue - m_minimumValue); - if (dataRange <= 0.0) { - return; + switch (m_scaleRangeMode) { + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + if ( ! getAutoRangeMinimumAndMaximum(dataBounds, + labelsStart, + labelsEnd, + labelsStep, + labelsDigitsRightOfDecimal)) { + return false; + } + break; + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + if (m_userScaleMinimumValue < m_userScaleMaximumValue) { + labelsStart = m_userScaleMinimumValue; + labelsEnd = m_userScaleMaximumValue; + } + break; } + + minimumOut = labelsStart; + maximumOut = labelsEnd; - float labelsStart = m_axisLabelsMinimumValue; - float labelsEnd = m_axisLabelsMaximumValue; /* * If the "labels end" or "labels start" value is not valid (infinity or not-a-number) there * are invalid values in the data and will cause the labels processing later @@ -565,27 +564,27 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], "Run \"wb_command -file-information\" on files being charted to find the file " "that contains invalid data so that the file can be fixed."); CaretLogWarning(msg); - return; + return false; } - float labelsRange = (m_axisLabelsMaximumValue - m_axisLabelsMinimumValue); + float labelsRange = (labelsEnd - labelsStart); if (labelsRange <= 0.0) { - return; + return false; } - const float tickLabelsStep = m_axisLabelsStepValue; + const float tickLabelsStep = labelsStep; if (tickLabelsStep <= 0.0) { - return; + return false; } float labelValue = labelsStart; while (labelValue <= labelsEnd) { - float labelParametricValue = (labelValue - dataStart) / dataRange; + float labelParametricValue = (labelValue - labelsStart) / labelsRange; float labelValueForText = labelValue; - if (dataRange >= 10.0) { + if (labelsRange >= 10.0) { /* * Is this the first label? */ @@ -598,10 +597,10 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], * code no value is displayed at the left edge of the axis. */ if (labelParametricValue < 0.0) { - const float nextParametricValue = ((labelValue + tickLabelsStep) - dataStart) / dataRange; + const float nextParametricValue = ((labelValue + tickLabelsStep) - labelsStart) / labelsRange; if (nextParametricValue > 0.05) { labelParametricValue = 0.0; - labelValueForText = dataStart; + labelValueForText = labelsStart; } } } @@ -621,10 +620,10 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], * edge of the axis. */ if (labelParametricValue > 1.0) { - const float prevParametricValue = ((labelValue - tickLabelsStep) - dataStart) / dataRange; + const float prevParametricValue = ((labelValue - tickLabelsStep) - labelsStart) / labelsRange; if (prevParametricValue < 0.95) { labelParametricValue = 1.0; - labelValueForText = dataEnd; + labelValueForText = labelsEnd; } } } @@ -639,7 +638,7 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], if ((labelParametricValue >= 0.0) && (labelParametricValue <= 1.0)) { const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; - const AString labelText = AString::number(labelValueForText, 'f', m_axisDigitsRightOfDecimal); + const AString labelText = AString::number(labelValueForText, 'f', labelsDigitsRightOfDecimal); labelOffsetInPixelsOut.push_back(labelPixelsPosition); labelTextOut.push_back(labelText); @@ -650,4 +649,8 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], labelValue += tickLabelsStep; } + + CaretAssert(labelOffsetInPixelsOut.size() == labelTextOut.size()); + return ( ! labelTextOut.empty()); } + diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 7fa5f38cb..31f5aa175 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -54,11 +54,11 @@ namespace caret { float getUserScaleMaximumValue() const; void setUserScaleMaximumValue(const float value); + + int32_t getUserDigitsRightOfDecimal() const; - float getMinimumValue() const; + void setUserDigitsRightOfDecimal(const int32_t digitsRightOfDecimal); - float getMaximumValue() const; - ChartTwoAxisScaleRangeModeEnum::Enum getScaleRangeMode() const; void setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode); @@ -67,13 +67,13 @@ namespace caret { void setUnits(ChartAxisUnitsEnum::Enum units); - NumericFormatModeEnum::Enum getNumericFormat() const; + NumericFormatModeEnum::Enum getUserNumericFormat() const; - void setNumericFormat(const NumericFormatModeEnum::Enum numericFormat); + void setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat); - int32_t getNumberOfSubdivisions() const; + int32_t getUserNumberOfSubdivisions() const; - void setNumberOfSubdivisions(const int32_t numberOfSubdivisions); + void setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions); bool isVisible() const; @@ -83,12 +83,13 @@ namespace caret { void setShowTickmarks(const bool showTickmarks); - void getLabelsAndPositions(const float dataBounds[4], + bool getLabelsAndPositions(const float dataBounds[4], const float axisLengthInPixels, - const float fontSizeInPixels, + float& minimumOut, + float& maximumOut, std::vector& labelOffsetInPixelsOut, - std::vector& labelTextOut); - + std::vector& labelTextOut) const; + AString getLabelText() const; void setLabelText(const AString& labelText); @@ -121,7 +122,11 @@ namespace caret { private: void copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); - virtual void updateForAutoRangeScale(const float dataBounds[4]); + bool getAutoRangeMinimumAndMaximum(const float dataBounds[4], + float& minimumOut, + float& maximumOut, + float& stepValueOut, + int32_t& digitsRightOfDecimalOut) const; std::unique_ptr m_sceneAssistant; @@ -131,25 +136,17 @@ namespace caret { float m_userScaleMaximumValue = 1.0; - float m_minimumValue = 0.0; - - float m_maximumValue = 100.0; - - float m_axisLabelsMinimumValue = 0.0; - - float m_axisLabelsMaximumValue = 100.0; - float m_axisLabelsStepValue = 1.0; - int32_t m_axisDigitsRightOfDecimal = 1; + int32_t m_userDigitsRightOfDecimal = 1; ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; ChartAxisUnitsEnum::Enum m_units = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; - NumericFormatModeEnum::Enum m_numericFormat = NumericFormatModeEnum::AUTO; + NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; - int32_t m_numberOfSubdivisions = 2; + int32_t m_userNumberOfSubdivisions = 2; AString m_labelText; -- GitLab From dee85bbf9860c21c9ee88f7391d502a5656a5132 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 16 Feb 2017 16:17:32 -0600 Subject: [PATCH 206/755] Continuing charting development. Added control of chart axies (auto/user range, user range values, ticks, axis name, numeric format, decimals, and subdivisions. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 16 +- src/Brain/ChartTwoOverlaySet.cxx | 19 + src/Brain/ChartTwoOverlaySet.h | 2 + .../ChartTwoAxisScaleRangeModeEnum.cxx | 4 +- src/Charting/ChartTwoCartesianAxis.cxx | 87 +++- src/Charting/ChartTwoCartesianAxis.h | 12 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 63 ++- src/GuiQt/BrainBrowserWindowToolBar.h | 6 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 405 ++++++++++++++++++ .../BrainBrowserWindowToolBarChartTwoAxes.h | 108 +++++ src/GuiQt/CMakeLists.txt | 9 +- 11 files changed, 697 insertions(+), 34 deletions(-) create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 71bfd7a79..b3193bac8 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -2196,6 +2196,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); + const bool showTicksFlag = axis->isShowTickmarks(); + for (int32_t i = 0; i < numLabelsToDraw; i++) { const float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; const float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; @@ -2203,12 +2205,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const float tickEndX = tickStartX + tickDeltaXY[0]; const float tickEndY = tickStartY + tickDeltaXY[1]; - glBegin(GL_LINES); - glVertex2f(tickStartX, - tickStartY); - glVertex2f(tickEndX, - tickEndY); - glEnd(); + if (showTicksFlag) { + glBegin(GL_LINES); + glVertex2f(tickStartX, + tickStartY); + glVertex2f(tickEndX, + tickEndY); + glEnd(); + } const float textX = tickEndX; const float textY = tickEndY; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index aa505f43a..3e5411a8f 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -631,6 +631,25 @@ ChartTwoOverlaySet::getChartAxisBottom() return m_chartAxisBottom.get(); } +std::vector +ChartTwoOverlaySet::getDisplayedChartAxes() const +{ + std::vector axes; + + if (m_chartAxisBottom->isVisible()) { + axes.push_back(m_chartAxisBottom.get()); + } + if (m_chartAxisLeft->isVisible()) { + axes.push_back(m_chartAxisLeft.get()); + } + if (m_chartAxisRight->isVisible()) { + axes.push_back(m_chartAxisRight.get()); + } + + return axes; +} + + /** * @return The chart bottom-axis (const method) */ diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 15eb3baca..4a3a0bd63 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -72,6 +72,8 @@ namespace caret { const ChartTwoCartesianAxis* getChartAxisBottom() const; + std::vector getDisplayedChartAxes() const; + void insertOverlayAbove(const int32_t overlayIndex); void insertOverlayBelow(const int32_t overlayIndex); diff --git a/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx index c5353a7e4..cb6d2a8aa 100644 --- a/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx +++ b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx @@ -108,11 +108,11 @@ ChartTwoAxisScaleRangeModeEnum::initialize() enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_AUTO, "AXIS_DATA_RANGE_AUTO", - "Axis Data Range Auto")); + "Auto")); enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_USER, "AXIS_DATA_RANGE_USER", - "Axis Data Range User")); + "User")); } diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 6138bf057..bbb7383b5 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -27,6 +27,7 @@ #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" #include "MathFunctions.h" +#include "NumericTextFormatting.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -169,6 +170,7 @@ ChartTwoCartesianAxis::setUserDigitsRightOfDecimal(const int32_t digitsRightOfDe /** * @return User's number of subdivisions + * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) */ int32_t ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const @@ -179,7 +181,8 @@ ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const /** * Set User's number of subdivisions * @param numberOfSubdivisions - * New value for Number of subdivisions + * New value for Number of subdivisions. + * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) */ void ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions) @@ -489,7 +492,7 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], /** * Get the axis labels and their positions for drawing the scale. * - * @param dataBounds + * @param dataBoundsIn * Bounds of data [minX, maxX, minY, maxY]. * @param axisLengthInPixels * Length of axis in pixels. @@ -505,13 +508,20 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], * True if output data is valid, else false. */ bool -ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], +ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBoundsIn[4], const float axisLengthInPixels, float& minimumOut, float& maximumOut, std::vector& labelOffsetInPixelsOut, std::vector& labelTextOut) const { + float dataBounds[4] = { + dataBoundsIn[0], + dataBoundsIn[1], + dataBoundsIn[2], + dataBoundsIn[3], + }; + minimumOut = 0.0; maximumOut = 0.0; labelOffsetInPixelsOut.clear(); @@ -528,22 +538,55 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], switch (m_scaleRangeMode) { case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: - if ( ! getAutoRangeMinimumAndMaximum(dataBounds, - labelsStart, - labelsEnd, - labelsStep, - labelsDigitsRightOfDecimal)) { - return false; - } break; case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: - if (m_userScaleMinimumValue < m_userScaleMaximumValue) { - labelsStart = m_userScaleMinimumValue; - labelsEnd = m_userScaleMaximumValue; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + dataBounds[0] = m_userScaleMinimumValue; + dataBounds[1] = m_userScaleMaximumValue; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + dataBounds[2] = m_userScaleMinimumValue; + dataBounds[3] = m_userScaleMaximumValue; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + dataBounds[2] = m_userScaleMinimumValue; + dataBounds[3] = m_userScaleMaximumValue; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + dataBounds[0] = m_userScaleMinimumValue; + dataBounds[1] = m_userScaleMaximumValue; + break; } break; } + if ( ! getAutoRangeMinimumAndMaximum(dataBounds, + labelsStart, + labelsEnd, + labelsStep, + labelsDigitsRightOfDecimal)) { + return false; + } + + switch (m_scaleRangeMode) { + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + break; + case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + labelsStart = m_userScaleMinimumValue; + labelsEnd = m_userScaleMaximumValue; + break; + } + + if (m_userNumberOfSubdivisions >= 0) { + const float labelsRange = labelsEnd - labelsStart; + if (labelsRange <= 0.0) { + return false; + } + const float dividend = (1.0 + m_userNumberOfSubdivisions); + labelsStep = labelsRange / dividend; + } + minimumOut = labelsStart; maximumOut = labelsEnd; @@ -577,6 +620,7 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], return false; } + std::vector labelNumericValues; float labelValue = labelsStart; while (labelValue <= labelsEnd) { @@ -638,10 +682,11 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], if ((labelParametricValue >= 0.0) && (labelParametricValue <= 1.0)) { const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; - const AString labelText = AString::number(labelValueForText, 'f', labelsDigitsRightOfDecimal); - + labelNumericValues.push_back(labelValueForText); labelOffsetInPixelsOut.push_back(labelPixelsPosition); - labelTextOut.push_back(labelText); + +// const AString labelText = AString::number(labelValueForText, 'f', labelsDigitsRightOfDecimal); +// labelTextOut.push_back(labelText); } else { // std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; @@ -650,6 +695,16 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBounds[4], labelValue += tickLabelsStep; } + const int32_t numValues = static_cast(labelNumericValues.size()); + if (numValues > 0) { + labelTextOut.resize(numValues); + NumericTextFormatting::formatValueRange(m_userNumericFormat, + m_userDigitsRightOfDecimal, + &labelNumericValues[0], + &labelTextOut[0], + labelNumericValues.size()); + } + CaretAssert(labelOffsetInPixelsOut.size() == labelTextOut.size()); return ( ! labelTextOut.empty()); } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 31f5aa175..7538ada10 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -83,7 +83,7 @@ namespace caret { void setShowTickmarks(const bool showTickmarks); - bool getLabelsAndPositions(const float dataBounds[4], + bool getLabelsAndPositions(const float dataBoundsIn[4], const float axisLengthInPixels, float& minimumOut, float& maximumOut, @@ -132,9 +132,9 @@ namespace caret { const ChartAxisLocationEnum::Enum m_axisLocation; - float m_userScaleMinimumValue = -1.0; + float m_userScaleMinimumValue = -100.0; - float m_userScaleMaximumValue = 1.0; + float m_userScaleMaximumValue = 100.0; float m_axisLabelsStepValue = 1.0; @@ -146,7 +146,11 @@ namespace caret { NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; - int32_t m_userNumberOfSubdivisions = 2; + /** + * Number of subdivisions. + * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) + */ + int32_t m_userNumberOfSubdivisions = -1; AString m_labelText; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f27b8d02b..146e7ece0 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -56,6 +56,7 @@ #include "BrainBrowserWindowToolBarChartAttributes.h" #include "BrainBrowserWindowToolBarChartAxes.h" #include "BrainBrowserWindowToolBarChartTwoAttributes.h" +#include "BrainBrowserWindowToolBarChartTwoAxes.h" #include "BrainBrowserWindowToolBarChartTwoOrientation.h" #include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" @@ -336,6 +337,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->chartAttributesWidget = createChartAttributesWidget(); this->chartTwoOrientationWidget = createChartTwoOrientationWidget(); this->chartTwoAttributesWidget = createChartTwoAttributesWidget(); + this->chartTwoAxesWidget = createChartTwoAxesWidget(); this->chartTypeWidget = createChartTypeWidget(); this->chartTypeTwoWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); @@ -382,6 +384,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolbarWidgetLayout->addWidget(this->chartTwoAttributesWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartTwoAxesWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->modeWidget, 0, Qt::AlignLeft); @@ -1400,6 +1404,7 @@ BrainBrowserWindowToolBar::updateToolBar() bool showChartOneAttributesWidget = false; bool showChartTwoOrientationWidget = false; bool showChartTwoAttributesWidget = false; + bool showChartTwoAxesWidget = false; bool showModeWidget = true; bool showWindowWidget = true; @@ -1463,9 +1468,25 @@ BrainBrowserWindowToolBar::updateToolBar() { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); if (modelChartTwo != NULL) { - showChartTwoTypeWidget = true; - showChartTwoOrientationWidget = true; - showChartTwoAttributesWidget = true; + switch (modelChartTwo->getSelectedChartTwoDataType(browserTabContent->getTabNumber())) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + showChartTwoAxesWidget = true; + showChartTwoOrientationWidget = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + showChartTwoAxesWidget = true; + showChartTwoOrientationWidget = true; + showChartTwoAttributesWidget = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + showChartTwoOrientationWidget = true; + showChartTwoAttributesWidget = true; + break; + } + + showChartTwoTypeWidget = true; } } break; @@ -1487,6 +1508,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartAttributesWidget->setVisible(false); this->chartTwoOrientationWidget->setVisible(false); this->chartTwoAttributesWidget->setVisible(false); + this->chartTwoAxesWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); this->volumePlaneWidget->setVisible(false); this->volumeMontageWidget->setVisible(false); @@ -1504,6 +1526,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartAttributesWidget->setVisible(showChartOneAttributesWidget); this->chartTwoOrientationWidget->setVisible(showChartTwoOrientationWidget); this->chartTwoAttributesWidget->setVisible(showChartTwoAttributesWidget); + this->chartTwoAxesWidget->setVisible(showChartTwoAxesWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); @@ -1567,6 +1590,7 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab this->updateChartAttributesWidget(browserTabContent); this->updateChartTwoOrientationWidget(browserTabContent); this->updateChartTwoAttributesWidget(browserTabContent); + this->updateChartTwoAxesWidget(browserTabContent); this->updateVolumeMontageWidget(browserTabContent); this->updateVolumePlaneWidget(browserTabContent); this->updateModeWidget(browserTabContent); @@ -2883,6 +2907,39 @@ BrainBrowserWindowToolBar::updateChartTwoAttributesWidget(BrowserTabContent* bro m_chartTwoAttributesToolBarComponent->updateContent(browserTabContent); } +/** + * Create the chart two axes widget. + * + * @return + * Widget containing the chart two axes. + */ +QWidget* +BrainBrowserWindowToolBar::createChartTwoAxesWidget() +{ + this->m_chartTwoAxesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAxes(this); + QWidget* w = this->createToolWidget("Chart Axes", + this->m_chartTwoAxesToolBarComponent, + WIDGET_PLACEMENT_LEFT, + WIDGET_PLACEMENT_TOP, + 100); + w->setVisible(false); + return w; +} + +/** + * Update the chart axes widget. + * + * @param browserTabContent + * The active model display (may be NULL). + */ +void +BrainBrowserWindowToolBar::updateChartTwoAxesWidget(BrowserTabContent* browserTabContent) +{ + if (this->chartTwoAxesWidget->isHidden()) { + return; + } + m_chartTwoAxesToolBarComponent->updateContent(browserTabContent); +} /** * Create the single surface options widget. diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index bee144fb5..9eb79f650 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -52,6 +52,7 @@ namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; + class BrainBrowserWindowToolBarChartTwoAxes; class BrainBrowserWindowToolBarChartTwoOrientation; class BrainBrowserWindowToolBarChartTwoType; class BrainBrowserWindowToolBarChartTwoAttributes; @@ -146,6 +147,7 @@ namespace caret { QWidget* createChartAttributesWidget(); QWidget* createChartTwoOrientationWidget(); QWidget* createChartTwoAttributesWidget(); + QWidget* createChartTwoAxesWidget(); QWidget* createChartTypeWidget(); QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); @@ -165,6 +167,7 @@ namespace caret { void updateChartAxesWidget(BrowserTabContent* browserTabContent); void updateChartAttributesWidget(BrowserTabContent* browserTabContent); void updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent); + void updateChartTwoAxesWidget(BrowserTabContent* browserTabContent); void updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent); void updateChartTypeWidget(BrowserTabContent* browserTabContent); void updateChartTypeTwoWidget(BrowserTabContent* browserTabContent); @@ -195,6 +198,7 @@ namespace caret { QWidget* chartAttributesWidget; QWidget* chartTwoOrientationWidget; QWidget* chartTwoAttributesWidget; + QWidget* chartTwoAxesWidget; WuQWidgetObjectGroup* viewWidgetGroup; WuQWidgetObjectGroup* orientationWidgetGroup; @@ -366,6 +370,7 @@ namespace caret { BrainBrowserWindowToolBarChartTwoType* m_chartTwoTypeToolBarComponent; BrainBrowserWindowToolBarChartType* m_chartTypeToolBarComponent; BrainBrowserWindowToolBarChartAttributes* m_chartAttributesToolBarComponent; + BrainBrowserWindowToolBarChartTwoAxes* m_chartTwoAxesToolBarComponent; BrainBrowserWindowToolBarChartTwoOrientation* m_chartTwoOrientationToolBarComponent; BrainBrowserWindowToolBarChartTwoAttributes* m_chartTwoAttributesToolBarComponent; BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; @@ -401,6 +406,7 @@ namespace caret { private: friend class BrainBrowserWindow; friend class BrainBrowserWindowToolBarChartAxes; + friend class BrainBrowserWindowToolBarChartTwoAxes; friend class BrainBrowserWindowToolBarChartTwoOrientation; friend class BrainBrowserWindowToolBarChartTwoAttributes; friend class BrainBrowserWindowToolBarChartTwoType; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx new file mode 100644 index 000000000..864e52a9d --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -0,0 +1,405 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include +#include +#include +#include +#include + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ +#include "BrainBrowserWindowToolBarChartTwoAxes.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ + +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "CaretDataFile.h" +#include "CaretDataFileSelectionModel.h" +#include "ChartTwoCartesianAxis.h" +#include "ChartTwoOverlaySet.h" +#include "EnumComboBoxTemplate.h" +#include "CaretMappableDataFile.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "ModelChartTwo.h" +#include "WuQDataEntryDialog.h" +#include "WuQFactory.h" +#include "WuQWidgetObjectGroup.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarChartTwoAxes + * \brief Controls for chart attributes. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parentToolBar + * The parent toolbar. + */ +BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar) +: BrainBrowserWindowToolBarComponent(parentToolBar) +{ + /* + * Axes selection + */ + m_axisComboBox = new EnumComboBoxTemplate(this); + m_axisComboBox->setup(); + QObject::connect(m_axisComboBox, &EnumComboBoxTemplate::itemActivated, + this, &BrainBrowserWindowToolBarChartTwoAxes::axisChanged); + m_axisComboBox->getWidget()->setToolTip("Choose axis for editing"); + + /* + * Controls for axis parameters + */ + m_axisNameToolButton = new QToolButton(); + m_axisNameToolButton->setText("Edit Axis Label"); + QObject::connect(m_axisNameToolButton, &QToolButton::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); + m_axisNameToolButton->setToolTip("Edit name lable displayed in axis"); + + m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); + m_autoUserRangeComboBox->setup(); + QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + m_autoUserRangeComboBox->getWidget()->setToolTip("Choose auto or user axis scaling"); + + const double bigValue = 999999.0; + m_userMinimumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); + QObject::connect(m_userMinimumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); + + m_userMaximumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); + QObject::connect(m_userMaximumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); + + m_showTickMarksCheckBox = new QCheckBox("Show Ticks"); + QObject::connect(m_showTickMarksCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); + + m_userNumericFormatComboBox = new EnumComboBoxTemplate(this); + m_userNumericFormatComboBox->setup(); + QObject::connect(m_userNumericFormatComboBox, &EnumComboBoxTemplate::itemActivated, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + m_userNumericFormatComboBox->getWidget()->setToolTip("Choose format of axis scale numeric values"); + + m_userDigitsRightOfDecimalSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 10, 1); + QObject::connect(m_userDigitsRightOfDecimalSpinBox, static_cast(&QSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); // ok int converts to double + m_userDigitsRightOfDecimalSpinBox->setToolTip("Set digits right of decimal for\ndecimal or scientific format"); + + m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(-1, 10, 1); + m_userSubdivisionsSpinBox->setSpecialValueText("Auto"); + QObject::connect(m_userSubdivisionsSpinBox, static_cast(&QSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); // ok int converts to double + m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis"); + + /* + * Group widgets for blocking signals + */ + m_widgetGroup = new WuQWidgetObjectGroup(this); + m_widgetGroup->add(m_axisNameToolButton); + m_widgetGroup->add(m_autoUserRangeComboBox->getWidget()); + m_widgetGroup->add(m_userMinimumValueSpinBox); + m_widgetGroup->add(m_userMaximumValueSpinBox); + m_widgetGroup->add(m_showTickMarksCheckBox); + m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); + m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); + m_widgetGroup->add(m_userSubdivisionsSpinBox); + + const int COLUMN_ONE = 0; + const int COLUMN_TWO = 1; + const int COLUMN_THREE = 2; + const int COLUMN_FOUR = 3; + const int COLUMN_FIVE = 4; + /* + * Layouts + */ + QGridLayout* layout = new QGridLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); + int leftRow = 0; + layout->addWidget(new QLabel("Axis"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_axisComboBox->getWidget(), leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Range"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_autoUserRangeComboBox->getWidget(), leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Maximum"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_userMaximumValueSpinBox, leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Minimum"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_userMinimumValueSpinBox, leftRow, COLUMN_TWO); + leftRow++; + + layout->setColumnMinimumWidth(COLUMN_THREE, 7); + + int rightRow = 0; + layout->addWidget(m_axisNameToolButton, rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE); + rightRow++; + layout->addWidget(new QLabel("Format"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE); + rightRow++; + layout->addWidget(new QLabel("Decimals"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE); + rightRow++; + layout->addWidget(new QLabel("Subdivisions"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_FIVE); + rightRow++; + + QVBoxLayout* dialogLayout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); + dialogLayout->addLayout(layout); + dialogLayout->addStretch(); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarChartTwoAxes::~BrainBrowserWindowToolBarChartTwoAxes() +{ +} + +/** + * Update content of this tool bar component. + * + * @param browserTabContent + * Content of the browser tab. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserTabContent) +{ + if (browserTabContent == NULL) { + setEnabled(false); + return; + } + + ChartTwoCartesianAxis* selectedAxis = NULL; + + const ChartAxisLocationEnum::Enum defaultAxis = getSelectedAxisLocation(); + + m_axisComboBox->blockSignals(true); + m_axisComboBox->getComboBox()->clear(); + + ChartTwoOverlaySet* chartOverlaySet = NULL; + if (browserTabContent != NULL) { + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); + const int32_t tabIndex = browserTabContent->getTabNumber(); + if (modelChartTwo != NULL) { + switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + if (chartOverlaySet != NULL) { + int32_t defaultAxisIndex = 0; + + std::vector validAxesLocations; + std::vector axes = chartOverlaySet->getDisplayedChartAxes(); + const int32_t numAxes = static_cast(axes.size()); + for (int32_t i = 0; i < numAxes; i++) { + const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); + if (defaultAxis == axisLocation) { + defaultAxisIndex = i; + } + validAxesLocations.push_back(axisLocation); + } + CaretAssert(validAxesLocations.size() == axes.size()); + + if ( ! axes.empty()) { + CaretAssertVectorIndex(validAxesLocations, defaultAxisIndex); + const ChartAxisLocationEnum::Enum axisLocation = validAxesLocations[defaultAxisIndex]; + m_axisComboBox->setupWithItems(validAxesLocations); + m_axisComboBox->setSelectedItem(axisLocation); + + CaretAssertVectorIndex(axes, defaultAxisIndex); + selectedAxis = axes[defaultAxisIndex]; + } + } + } + } + m_axisComboBox->blockSignals(false); + + updateControls(selectedAxis); + + setEnabled(selectedAxis != NULL); +} + +/** + * Called when axis is changed. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::axisChanged() +{ + updateContent(getTabContentFromSelectedTab()); +} + +/** + * @return The selected axes location (will return left even if no valid selection). + */ +ChartAxisLocationEnum::Enum +BrainBrowserWindowToolBarChartTwoAxes::getSelectedAxisLocation() const +{ + ChartAxisLocationEnum::Enum axis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; + + if (m_axisComboBox->getComboBox()->count() > 0) { + axis = m_axisComboBox->getSelectedItem(); + } + + return axis; +} + + + +/** + * Update the content with the given axis. + * + * @param chartAxis + * New chart axis content. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* chartAxis) +{ + m_chartAxis = chartAxis; + + if (m_chartAxis != NULL) { + m_widgetGroup->blockAllSignals(true); + //m_axisNameToolButton->setText(m_chartAxis->getLabelText()); + m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); + m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); + m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); + m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); + const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); + m_userNumericFormatComboBox->setSelectedItem(numericFormat); + m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); + m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); + m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); + + m_widgetGroup->blockAllSignals(false); + } +} + +/** + * Called when a widget is changed by the user. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::valueChanged() +{ + CaretAssert(m_chartAxis); + if (m_chartAxis != NULL) { + m_chartAxis->setScaleRangeMode(m_autoUserRangeComboBox->getSelectedItem()); + m_chartAxis->setUserScaleMinimumValue(m_userMinimumValueSpinBox->value()); + m_chartAxis->setUserScaleMaximumValue(m_userMaximumValueSpinBox->value()); + m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); + m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); + m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); + m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); + } + + updateContent(getTabContentFromSelectedTab()); + + updateGraphics(); +} + +/** + * Update the graphics. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::updateGraphics() +{ + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + + +/** + * Called when a widget is changed by a slot using a bool parameter. + * Parameters must match when using function pointers. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool(bool) +{ + valueChanged(); +} + +/** + * Called when a widget is changed by a slot using a double parameter. + * Parameters must match when using function pointers. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble(double) +{ + valueChanged(); +} + +/** + * Called when a widget is changed by a slot using a int parameter. + * Parameters must match when using function pointers. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt(int) +{ + valueChanged(); +} + +/** + * Called when name toolbutton is clicked to change axis name. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) +{ + CaretAssert(m_chartAxis); + if (m_chartAxis != NULL) { + WuQDataEntryDialog newNameDialog("Axis Name", + m_axisNameToolButton); + QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Axis Name"); + lineEdit->setText(m_chartAxis->getLabelText()); + if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { + const AString name = lineEdit->text().trimmed(); + if ( ! name.isEmpty()) { + m_chartAxis->setLabelText(name); + valueChanged(); + } + } + } +} + + + + diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h new file mode 100644 index 000000000..e98525fba --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -0,0 +1,108 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "BrainBrowserWindowToolBarComponent.h" +#include "ChartAxisLocationEnum.h" + +class QCheckBox; +class QDoubleSpinBox; +class QLabel; +class QSpinBox; +class QToolButton; + +namespace caret { + + class ChartTwoCartesianAxis; + class ChartTwoCartesianAxisWidget; + class EnumComboBoxTemplate; + class WuQWidgetObjectGroup; + + class BrainBrowserWindowToolBarChartTwoAxes : public BrainBrowserWindowToolBarComponent { + Q_OBJECT + + public: + BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar); + + virtual ~BrainBrowserWindowToolBarChartTwoAxes(); + + virtual void updateContent(BrowserTabContent* browserTabContent); + + // ADD_NEW_METHODS_HERE + + private slots: + void axisChanged(); + + void valueChanged(); + + void valueChangedBool(bool); + + void valueChangedDouble(double); + + void valueChangedInt(int); + + void axisNameToolButtonClicked(bool); + + private: + BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); + + BrainBrowserWindowToolBarChartTwoAxes& operator=(const BrainBrowserWindowToolBarChartTwoAxes&); + + ChartAxisLocationEnum::Enum getSelectedAxisLocation() const; + + void updateControls(ChartTwoCartesianAxis* chartAxis); + + void updateGraphics(); + + // ADD_NEW_MEMBERS_HERE + + EnumComboBoxTemplate* m_axisComboBox; + + QToolButton* m_axisNameToolButton; + + EnumComboBoxTemplate* m_autoUserRangeComboBox; + + QDoubleSpinBox* m_userMinimumValueSpinBox; + + QDoubleSpinBox* m_userMaximumValueSpinBox; + + QCheckBox* m_showTickMarksCheckBox; + + EnumComboBoxTemplate* m_userNumericFormatComboBox; + + QSpinBox* m_userDigitsRightOfDecimalSpinBox; + + QSpinBox* m_userSubdivisionsSpinBox; + + ChartTwoCartesianAxis* m_chartAxis; + + WuQWidgetObjectGroup* m_widgetGroup; + + }; + +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 4f7a592ad..88d791566 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -73,8 +73,9 @@ ELSE() BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h - BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoAttributes.h + BrainBrowserWindowToolBarChartTwoAxes.h + BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -259,8 +260,9 @@ BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h -BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoAttributes.h +BrainBrowserWindowToolBarChartTwoAxes.h +BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -469,8 +471,9 @@ BrainBrowserWindowOrientedToolBox.cxx BrainBrowserWindowToolBar.cxx BrainBrowserWindowToolBarChartAttributes.cxx BrainBrowserWindowToolBarChartAxes.cxx -BrainBrowserWindowToolBarChartTwoOrientation.cxx BrainBrowserWindowToolBarChartTwoAttributes.cxx +BrainBrowserWindowToolBarChartTwoAxes.cxx +BrainBrowserWindowToolBarChartTwoOrientation.cxx BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx -- GitLab From c478bd1771eb70757c89e1ca5b2f5414f94cde95 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Feb 2017 15:09:40 -0600 Subject: [PATCH 207/755] Continuing charting development. Added ability for displaying axes on the left and/or right for histograms. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 453 ++++++------------ src/Brain/ChartTwoOverlay.cxx | 71 +++ src/Brain/ChartTwoOverlay.h | 13 + src/Brain/ChartTwoOverlaySet.cxx | 3 + .../ChartTwoOverlaySetViewController.cxx | 30 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 168 ++++++- src/GuiQt/ChartTwoOverlayViewController.h | 18 +- 7 files changed, 432 insertions(+), 324 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index b3193bac8..20ff3d3f2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -214,6 +214,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); } +class HistogramChartDrawingInfo { +public: + HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, + const ChartableTwoFileHistogramChart* histogramChart, + int32_t mapIndex, + ChartAxisLocationEnum::Enum verticalAxisLocation) + : m_histogramDrawingInfo(histogramDrawingInfo), + m_histogramChart(histogramChart), + m_mapIndex(mapIndex), + m_verticalAxisLocation(verticalAxisLocation) { } + + HistogramDrawingInfo* m_histogramDrawingInfo; + const ChartableTwoFileHistogramChart* m_histogramChart; + int32_t m_mapIndex; + ChartAxisLocationEnum::Enum m_verticalAxisLocation; + + ~HistogramChartDrawingInfo() { + delete m_histogramDrawingInfo; + } +}; + /** * Draw histogram charts. */ @@ -232,92 +253,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() vpHeight }; - - // /* - // * Margin is region around the chart in which - // * the axes legends, values, and ticks are drawn. - // */ - // const double marginSize = 30; - // Margins margins(marginSize); - // - // double width, height; - // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); - // margins.m_left = std::max(margins.m_left, width); - // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); - // margins.m_right = std::max(margins.m_right, width); - // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); - // margins.m_top = std::max(margins.m_top, height); - // estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); - // margins.m_bottom = std::max(margins.m_bottom, height); - // - // if (margins.m_left > marginSize) margins.m_left += 10; - // if (margins.m_right > marginSize) margins.m_right += 10; - // - // /* - // * Ensure that there is sufficient space for the axes data display. - // */ - // if ((vpWidth > (marginSize * 3)) - // && (vpHeight > (marginSize * 3))) { - // - // /* Draw legends and grids */ - // drawChartAxis(vpX, - // vpY, - // vpWidth, - // vpHeight, - // margins, - // textRenderer, - // cartesianChart->getLeftAxis()); - // - // drawChartAxis(vpX, - // vpY, - // vpWidth, - // vpHeight, - // margins, - // textRenderer, - // cartesianChart->getRightAxis()); - // - // drawChartAxis(vpX, - // vpY, - // vpWidth, - // vpHeight, - // margins, - // textRenderer, - // cartesianChart->getBottomAxis()); - // - // drawChartAxis(vpX, - // vpY, - // vpWidth, - // vpHeight, - // margins, - // textRenderer, - // cartesianChart->getTopAxis()); - // - // - // drawChartGraphicsBoxAndSetViewport(vpX, - // vpY, - // vpWidth, - // vpHeight, - // margins, - // chartGraphicsDrawingViewport); - // } - - const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); - std::vector histogramDrawingInfoVector; - std::vector histogramChartVector; - std::vector mapIndexVector; + std::vector drawingInfo; + + bool haveBottomAxisFlag = false; + bool haveLeftAxisFlag = false; + bool haveRightAxisFlag = false; + /* * Get the histogram drawing information and overall extent */ - float xMin = 0.0; - float xMax = 0.0; - float yMin = 0.0; - float yMax = 0.0; + float xMin = std::numeric_limits::max();; + float xMax = -std::numeric_limits::max();; + float yMinLeft = std::numeric_limits::max(); + float yMaxLeft = -std::numeric_limits::max();; + float yMinRight = std::numeric_limits::max();; + float yMaxRight = -std::numeric_limits::max();; for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -334,46 +290,59 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); - histogramChartVector.push_back(histogramChart); - mapIndexVector.push_back(mapIndex); - histogramDrawingInfoVector.push_back(new HistogramDrawingInfo()); - const int32_t histoIndex = static_cast(histogramDrawingInfoVector.size() - 1); if (histogramChart->isValid()) { AString errorMessage; - CaretAssertVectorIndex(histogramDrawingInfoVector, histoIndex); + HistogramDrawingInfo* histogramDrawingInfo = new HistogramDrawingInfo(); if (mapFile->getMapHistogramDrawingInfo(mapIndex, chartOverlay->isAllMapsSelected(), false, - *histogramDrawingInfoVector[histoIndex], + *histogramDrawingInfo, errorMessage)) { + drawingInfo.push_back(new HistogramChartDrawingInfo(histogramDrawingInfo, + histogramChart, + mapIndex, + chartOverlay->getCartesianVerticalAxisLocation())); + float bounds[4]; - if (histogramDrawingInfoVector[histoIndex]->getBounds(bounds)) { + if (histogramDrawingInfo->getBounds(bounds)) { xMin = std::min(xMin, bounds[0]); xMax = std::max(xMax, bounds[1]); - yMin = std::min(yMin, bounds[2]); - yMax = std::max(yMax, bounds[3]); + + haveBottomAxisFlag = true; + switch (chartOverlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yMinRight = std::min(yMinRight, bounds[2]); + yMaxRight = std::max(yMaxRight, bounds[3]); + haveRightAxisFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + yMinLeft = std::min(yMinLeft, bounds[2]); + yMaxLeft = std::max(yMaxLeft, bounds[3]); + haveLeftAxisFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); + break; + } } } else { + delete histogramDrawingInfo; CaretLogWarning(errorMessage + mapFile->getFileName()); } } } - CaretAssert(histogramDrawingInfoVector.size() == histogramChartVector.size()); - CaretAssert(histogramDrawingInfoVector.size() == mapIndexVector.size()); /* * Bounds valid? */ if ((xMin < xMax) - || (yMin < yMax)) { - // std::cout << "All bounds: " - // << xMin << " " - // << xMax << " " - // << yMin << " " - // << yMax << " " << std::endl; - + && ((yMinLeft < yMaxLeft) + || (yMinRight < yMaxRight))) { /* * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. @@ -386,15 +355,21 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() ChartTwoCartesianAxis* bottomAxis = m_chartOverlaySet->getChartAxisBottom(); ChartTwoCartesianAxis* topAxis = NULL; - const float bounds[4] = { xMin, xMax, yMin, yMax }; + leftAxis->setVisible(haveLeftAxisFlag); + rightAxis->setVisible(haveRightAxisFlag); + bottomAxis->setVisible(haveBottomAxisFlag); + + const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; + const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; - estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, leftAxis, width, height); + + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, leftAxis, width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, rightAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpHeight, rightAxis, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, topAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, topAxis, width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(bounds, vpHeight, bottomAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, bottomAxis, width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; @@ -410,7 +385,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() float axisMaximumValue = 0.0; /* Draw legends and grids */ - if (drawChartAxisCartesian(bounds, + if (drawChartAxisCartesian(boundsLeftBottomTop, vpX, vpY, vpWidth, @@ -419,11 +394,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() leftAxis, axisMinimumValue, axisMaximumValue)) { - yMin = axisMinimumValue; - yMax = axisMaximumValue; + yMinLeft = axisMinimumValue; + yMaxLeft = axisMaximumValue; } - drawChartAxisCartesian(bounds, + if (drawChartAxisCartesian(boundsRight, vpX, vpY, vpWidth, @@ -431,8 +406,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() margins, rightAxis, axisMinimumValue, - axisMaximumValue); - if (drawChartAxisCartesian(bounds, + axisMaximumValue)) { + yMinRight = axisMinimumValue; + yMaxRight = axisMaximumValue; + } + if (drawChartAxisCartesian(boundsLeftBottomTop, vpX, vpY, vpWidth, @@ -445,7 +423,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() xMax = axisMaximumValue; } - drawChartAxisCartesian(bounds, + drawChartAxisCartesian(boundsLeftBottomTop, vpX, vpY, vpWidth, @@ -468,54 +446,70 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() chartGraphicsDrawingViewport[2], chartGraphicsDrawingViewport[3]); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(xMin, xMax, - yMin, yMax, - -10.0, 10.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - bool applyTransformationsFlag = true; - if (applyTransformationsFlag) { - glTranslatef(m_translation[0], - m_translation[1], - 0.0); - - const float chartWidth = chartGraphicsDrawingViewport[2]; - const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; - glTranslatef(halfWidth, - halfHeight, - 0.0); - glScalef(m_zooming, - m_zooming, - 1.0); - glTranslatef(-halfWidth, - -halfHeight, - 0.0); - } - - const int32_t numToDraw = static_cast(histogramChartVector.size()); - for (int32_t i = 0; i < numToDraw; i++) { - CaretAssertVectorIndex(histogramChartVector, i); - CaretAssertVectorIndex(mapIndexVector, i); - CaretAssertVectorIndex(histogramDrawingInfoVector, i); - if (histogramDrawingInfoVector[i]->isValid()) { - drawHistogramChartContent(histogramChartVector[i], - mapIndexVector[i], - *histogramDrawingInfoVector[i]); + for (auto& drawInfo : drawingInfo) { + if (drawInfo->m_histogramDrawingInfo->isValid()) { + + bool leftVerticalAxisFlag = true; + switch (drawInfo->m_verticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + leftVerticalAxisFlag = false; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (leftVerticalAxisFlag) { + glOrtho(xMin, xMax, + yMinLeft, yMaxLeft, + -10.0, 10.0); + } + else { + glOrtho(xMin, xMax, + yMinRight, yMaxRight, + -10.0, 10.0); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = false; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + drawHistogramChartContent(drawInfo->m_histogramChart, + drawInfo->m_mapIndex, + *drawInfo->m_histogramDrawingInfo); + } } - } } - - for (auto histDrawPtr : histogramDrawingInfoVector) { - delete histDrawPtr; + for (auto& histDrawInfo : drawingInfo) { + delete histDrawInfo; } - histogramDrawingInfoVector.clear(); } /* @@ -655,30 +649,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, quadVerticesNormals, quadVerticesByteRGBA); -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// glBegin(GL_QUADS); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); -// glColor4ubv(&quadVerticesByteRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } else { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, quadVerticesNormals, quadVerticesFloatRGBA); -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// glBegin(GL_QUADS); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); -// glColor4fv(&quadVerticesFloatRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } } break; @@ -867,35 +843,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, quadVerticesByteRGBA, lineWidth); -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// m_fixedPipelineDrawing->setLineWidth(5); -// glBegin(GL_LINES); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); -// glColor4ubv(&quadVerticesByteRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } else { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - const float lineWidth = 5.0; + const float lineWidth = 1.0; BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, quadVerticesFloatRGBA, lineWidth); - -// m_fixedPipelineDrawing->setLineWidth(2); -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// glBegin(GL_LINES); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); -// glColor4fv(&quadVerticesFloatRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } } break; @@ -1302,16 +1257,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, quadVerticesNormals, quadVerticesByteRGBA); - -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// glBegin(GL_QUADS); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); -// glColor4ubv(&quadVerticesByteRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } else { /* @@ -1325,15 +1270,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, quadVerticesNormals, quadVerticesFloatRGBA); -// glBegin(GL_QUADS); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); -// glColor4fv(&quadVerticesFloatRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); - glDisable(GL_BLEND); @@ -1363,21 +1299,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, quadVerticesNormals, outlineRGBA); -// glBegin(GL_QUADS); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// CaretAssertVectorIndex(outlineRGBA, i*4 + 3); -// glColor4fv(&outlineRGBA[i*4]); -// CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); -// glVertex3fv(&quadVerticesXYZ[i*3]); -// } -// glEnd(); } if ( (! selectedRowIndices.empty()) && highlightSelectedRowColumnFlag) { -// std::vector rowXYZ; -// std::vector rowRGBA; - for (auto rowIndex : selectedRowIndices) { const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; @@ -1403,35 +1328,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowXYZ.push_back(minX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); -// rowRGBA.push_back(highlightRGB[0]); -// rowRGBA.push_back(highlightRGB[1]); -// rowRGBA.push_back(highlightRGB[2]); -// rowRGBA.push_back(1.0); rowXYZ.push_back(minX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); -// rowRGBA.push_back(highlightRGB[0]); -// rowRGBA.push_back(highlightRGB[1]); -// rowRGBA.push_back(highlightRGB[2]); -// rowRGBA.push_back(1.0); rowXYZ.push_back(maxX); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); -// rowRGBA.push_back(highlightRGB[0]); -// rowRGBA.push_back(highlightRGB[1]); -// rowRGBA.push_back(highlightRGB[2]); -// rowRGBA.push_back(1.0); - rowXYZ.push_back(maxX); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); -// rowRGBA.push_back(highlightRGB[0]); -// rowRGBA.push_back(highlightRGB[1]); -// rowRGBA.push_back(highlightRGB[2]); -// rowRGBA.push_back(1.0); /* * As cells get larger, increase linewidth for selected row @@ -1443,39 +1351,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT highlightLineWidth); } -// CaretAssert((rowXYZ.size() / 3) == (rowRGBA.size() / 4)); -// -// const int32_t numberOfVertices = static_cast(rowXYZ.size() / 3); -// const int32_t numberOfQuads = numberOfVertices / 4; -// CaretAssert((numberOfQuads * 4) == numberOfVertices); -// -// /* -// * As cells get larger, increase linewidth for selected row -// */ -// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); -// glLineWidth(highlightLineWidth); -// -// for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { -// glBegin(GL_LINE_LOOP); -// for (int32_t iVert = 0; iVert < 4; iVert++) { -// const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); -// CaretAssertVectorIndex(rowRGBA, rgbaOffset + 3); -// glColor4fv(&rowRGBA[rgbaOffset]); -// -// const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); -// CaretAssertVectorIndex(rowXYZ, xyzOffset + 2); -// glVertex3fv(&rowXYZ[xyzOffset]); -// } -// glEnd(); -// } glLineWidth(1.0); } if ( (! selectedColumnIndices.empty()) && highlightSelectedRowColumnFlag) { -// std::vector columnXYZ; -// std::vector columnRGBA; - for (auto columnIndex : selectedColumnIndices) { const float colX = columnIndex * cellWidth; @@ -1502,35 +1382,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnXYZ.push_back(colX); columnXYZ.push_back(minY); columnXYZ.push_back(0.0); -// columnRGBA.push_back(highlightRGB[0]); -// columnRGBA.push_back(highlightRGB[1]); -// columnRGBA.push_back(highlightRGB[2]); -// columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(minY); columnXYZ.push_back(0.0); -// columnRGBA.push_back(highlightRGB[0]); -// columnRGBA.push_back(highlightRGB[1]); -// columnRGBA.push_back(highlightRGB[2]); -// columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); -// columnRGBA.push_back(highlightRGB[0]); -// columnRGBA.push_back(highlightRGB[1]); -// columnRGBA.push_back(highlightRGB[2]); -// columnRGBA.push_back(1.0); - columnXYZ.push_back(colX); columnXYZ.push_back(maxY); columnXYZ.push_back(0.0); -// columnRGBA.push_back(highlightRGB[0]); -// columnRGBA.push_back(highlightRGB[1]); -// columnRGBA.push_back(highlightRGB[2]); -// columnRGBA.push_back(1.0); /* * As cells get larger, increase linewidth for selected row @@ -1541,32 +1404,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rgba, highlightLineWidth); } - -// CaretAssert((columnXYZ.size() / 3) == (columnRGBA.size() / 4)); -// -// const int32_t numberOfVertices = static_cast(columnXYZ.size() / 3); -// const int32_t numberOfQuads = numberOfVertices / 4; -// CaretAssert((numberOfQuads * 4) == numberOfVertices); -// -// /* -// * As cells get larger, increase linewidth for selected row -// */ -// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); -// glLineWidth(highlightLineWidth); -// -// for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { -// glBegin(GL_LINE_LOOP); -// for (int32_t iVert = 0; iVert < 4; iVert++) { -// const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); -// CaretAssertVectorIndex(columnRGBA, rgbaOffset + 3); -// glColor4fv(&columnRGBA[rgbaOffset]); -// -// const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); -// CaretAssertVectorIndex(columnXYZ, xyzOffset + 2); -// glVertex3fv(&columnXYZ[xyzOffset]); -// } -// glEnd(); -// } glLineWidth(1.0); } diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 6458763b9..b5292c701 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -78,6 +78,7 @@ m_overlayIndex(overlayIndex) m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; + m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; m_selectedMapFile = NULL; m_selectedHistogramMapIndex = -1; @@ -90,6 +91,8 @@ m_overlayIndex(overlayIndex) m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar.get()); m_sceneAssistant->add("m_matrixTriangularViewingMode", &m_matrixTriangularViewingMode); + m_sceneAssistant->add("m_cartesianVerticalAxisLocation", + &m_cartesianVerticalAxisLocation); m_sceneAssistant->add("m_selectedHistogramMapIndex", &m_selectedHistogramMapIndex); m_sceneAssistant->add("m_allHistogramMapsSelectedFlag", &m_allHistogramMapsSelectedFlag); @@ -281,6 +284,7 @@ ChartTwoOverlay::copyData(const ChartTwoOverlay* overlay) *m_colorBar = *overlay->m_colorBar; m_matrixTriangularViewingMode = overlay->m_matrixTriangularViewingMode; + m_cartesianVerticalAxisLocation = overlay->m_cartesianVerticalAxisLocation; m_selectedMapFile = overlay->m_selectedMapFile; m_selectedHistogramMapIndex = overlay->m_selectedHistogramMapIndex; @@ -1079,6 +1083,73 @@ ChartTwoOverlay::isMatrixTriangularViewingModeSupported() const return false; } +/** + * @return Location of vertical cartesian axis + */ +ChartAxisLocationEnum::Enum +ChartTwoOverlay::getCartesianVerticalAxisLocation() const +{ + validateCartesianVerticalAxisLocation(); + return m_cartesianVerticalAxisLocation; +} + +/** + * Set Location of vertical cartesian axis + * + * @param cartesianVerticalAxisLocation + * New value for Location of vertical cartesian axis + */ +void +ChartTwoOverlay::setCartesianVerticalAxisLocation(const ChartAxisLocationEnum::Enum cartesianVerticalAxisLocation) +{ + m_cartesianVerticalAxisLocation = cartesianVerticalAxisLocation; + validateCartesianVerticalAxisLocation(); +} + +/** + * Validate cartesian vertical axis to valid locations (left and right) + */ +void +ChartTwoOverlay::validateCartesianVerticalAxisLocation() const +{ + + switch (m_cartesianVerticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; + break; + } +} + + +/** + * @return Is the cartesian vertical axis location supported? + */ +bool +ChartTwoOverlay::isCartesianVerticalAxisLocationSupported() const +{ + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + return true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + return false; +} + + /** * Save information specific to this type of model to the scene. * diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 36aeba37d..8c28ed591 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -24,6 +24,7 @@ #include "CaretObject.h" +#include "ChartAxisLocationEnum.h" #include "ChartTwoCompoundDataType.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "EventListenerInterface.h" @@ -85,6 +86,12 @@ namespace caret { bool isMatrixTriangularViewingModeSupported() const; + ChartAxisLocationEnum::Enum getCartesianVerticalAxisLocation() const; + + void setCartesianVerticalAxisLocation(const ChartAxisLocationEnum::Enum cartesianVerticalAxisLocation); + + bool isCartesianVerticalAxisLocationSupported() const; + void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, @@ -136,6 +143,8 @@ namespace caret { std::vector* selectedFileMapNamesOut, int32_t& selectedMapIndexOut) const; + void validateCartesianVerticalAxisLocation() const; + /** Parent chart overlay set (only used by first overlay in the set */ ChartTwoOverlaySet* m_parentChartTwoOverlaySet; @@ -171,6 +180,10 @@ namespace caret { bool m_allHistogramMapsSelectedFlag = false; ChartTwoMatrixTriangularViewingModeEnum::Enum m_matrixTriangularViewingMode; + + /** Location of vertical cartesian axis*/ + mutable ChartAxisLocationEnum::Enum m_cartesianVerticalAxisLocation; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 3e5411a8f..e5b068d1f 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -76,6 +76,9 @@ m_tabIndex(tabIndex) m_chartAxisLeft->setVisible(true); m_chartAxisLeft->setLabelText("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisRight->setVisible(false); + m_chartAxisRight->setLabelText("Counts"); + m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisBottom->setVisible(true); m_chartAxisBottom->setLabelText("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 78ec6d6f3..048a67e22 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -104,11 +104,12 @@ m_browserWindowIndex(browserWindowIndex) static const int COLUMN_SETTINGS_CONSTRUCTION = 3; static const int COLUMN_HISTORY = 4; static const int COLUMN_MATRIX_VIEW = 5; - static const int COLUMN_FILE = 6; - static const int COLUMN_YOKE = 7; - static const int COLUMN_MAP_INDEX = 8; - static const int COLUMN_ALL_MAPS = 9; - static const int COLUMN_MAP_NAME = 10; + static const int COLUMN_AXIS = 6; + static const int COLUMN_FILE = 7; + static const int COLUMN_YOKE = 8; + static const int COLUMN_MAP_INDEX = 9; + static const int COLUMN_ALL_MAPS = 10; + static const int COLUMN_MAP_NAME = 11; gridLayout->setColumnStretch(COLUMN_ON, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); @@ -116,6 +117,7 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); gridLayout->setColumnStretch(COLUMN_HISTORY, 0); gridLayout->setColumnStretch(COLUMN_MATRIX_VIEW, 0); + gridLayout->setColumnStretch(COLUMN_AXIS, 0); gridLayout->setColumnStretch(COLUMN_FILE, 100); gridLayout->setColumnStretch(COLUMN_YOKE, 0); gridLayout->setColumnStretch(COLUMN_ALL_MAPS, 0); @@ -133,7 +135,7 @@ m_browserWindowIndex(browserWindowIndex) int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); - gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 4, Qt::AlignHCenter); + gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 5, Qt::AlignHCenter); //gridLayout->addWidget(historyLabel, row, COLUMN_HISTORY, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, row, COLUMN_YOKE, Qt::AlignHCenter); @@ -152,6 +154,7 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_historyToolButton, row, COLUMN_HISTORY, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, COLUMN_MATRIX_VIEW, Qt::AlignHCenter); + glg->addWidget(covc->m_axisLocationToolButton, row, COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); @@ -166,13 +169,14 @@ m_browserWindowIndex(browserWindowIndex) static const int ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION = 3; static const int ROW_ONE_COLUMN_HISTORY = 4; static const int ROW_ONE_COLUMN_MATRIX_VIEW = 5; - static const int ROW_ONE_COLUMN_FILE_LABEL = 6; - static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 7; + static const int ROW_ONE_COLUMN_AXIS = 6; + static const int ROW_ONE_COLUMN_FILE_LABEL = 7; + static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 8; static const int ROW_TWO_COLUMN_YOKE = 0; static const int ROW_TWO_COLUMN_ALL_MAPS = 3; - static const int ROW_TWO_COLUMN_MAP_INDEX = 6; - static const int ROW_TWO_COLUMN_MAP_NAME = 7; + static const int ROW_TWO_COLUMN_MAP_INDEX = 7; + static const int ROW_TWO_COLUMN_MAP_NAME = 8; gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); @@ -181,7 +185,8 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); gridLayout->setColumnStretch(6, 0); - gridLayout->setColumnStretch(7, 100); + gridLayout->setColumnStretch(7, 0); + gridLayout->setColumnStretch(8, 100); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; @@ -206,13 +211,14 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_historyToolButton, row, ROW_ONE_COLUMN_HISTORY, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, ROW_ONE_COLUMN_MATRIX_VIEW, Qt::AlignHCenter); + glg->addWidget(covc->m_axisLocationToolButton, row, ROW_ONE_COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 2); row++; glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); // glg->addWidget(covc->m_historyToolButton, row, ROW_TWO_COLUMN_HISTORY, 1, 2, Qt::AlignHCenter); - glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 3, Qt::AlignRight); + glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 4, Qt::AlignRight); glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 365c29c4e..f07e99dc1 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -186,6 +186,18 @@ m_chartOverlay(NULL) m_matrixTriangularViewModeToolButton->setPopupMode(QToolButton::InstantPopup); + /* + * Axis location button + */ + m_axisLocationAction = WuQtUtilities::createAction("A", + "Vertical Axis Location", + this); + m_axisLocationToolButton = new QToolButton(); + QMenu* axisLocationMenu = createAxisLocationMenu(m_axisLocationToolButton); + m_axisLocationAction->setMenu(axisLocationMenu); + m_axisLocationToolButton->setDefaultAction(m_axisLocationAction); + m_axisLocationToolButton->setPopupMode(QToolButton::InstantPopup); + /* * Map file Selection Check Box */ @@ -784,6 +796,23 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla } } } + + /* + * Update vertical axis location + */ + m_axisLocationAction->setEnabled(false); + if (validOverlayAndFileFlag) { + if (m_chartOverlay->isCartesianVerticalAxisLocationSupported()) { + m_axisLocationAction->setEnabled(true); + const ChartAxisLocationEnum::Enum axisLocation = m_chartOverlay->getCartesianVerticalAxisLocation(); + for (auto& almd : m_axisLocationMenuData) { + if (std::get<0>(almd) == axisLocation) { + updateAxisLocationAction(axisLocation); + break; + } + } + } + } } /** @@ -813,6 +842,33 @@ ChartTwoOverlayViewController::updateMatrixTriangularViewModeAction(const ChartT m_matrixTriangularViewModeAction->blockSignals(false); } +/** + * Update the axis location button. + * + * @param axisLocation + * Axis location. + */ +void +ChartTwoOverlayViewController::updateAxisLocationAction(const ChartAxisLocationEnum::Enum axisLocation) +{ + CaretAssert(m_axisLocationAction); + m_axisLocationAction->blockSignals(true); + for (auto& almd : m_axisLocationMenuData) { + if (std::get<0>(almd) == axisLocation) { + QPixmap pixmap = std::get<2>(almd); + if ( ! pixmap.isNull()) { + m_axisLocationAction->setIcon(pixmap); + m_axisLocationAction->setText(""); + } + else { + m_axisLocationAction->setText("A"); + } + break; + } + } + m_axisLocationAction->blockSignals(false); +} + /** * Update graphics and GUI after selections made @@ -857,8 +913,6 @@ ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* paren QMenu* menu = new QMenu(parent); QObject::connect(menu, &QMenu::triggered, this, &ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered); -// QObject::connect(menu, SIGNAL(triggered(QAction*)), -// this, SLOT(menuMatrixTriangularViewModeTriggered(QAction* action))); QActionGroup* actionGroup = new QActionGroup(this); actionGroup->setExclusive(true); @@ -898,6 +952,59 @@ ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* ac } } +/** + * Create the axis location menu. + * @param parent + * Parent widget. + */ +QMenu* +ChartTwoOverlayViewController::createAxisLocationMenu(QWidget* widget) +{ + std::vector axisLocations; + axisLocations.push_back(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + axisLocations.push_back(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT); + + QMenu* menu = new QMenu(widget); + QObject::connect(menu, &QMenu::triggered, + this, &ChartTwoOverlayViewController::menuAxisLocationTriggered); + + QActionGroup* actionGroup = new QActionGroup(this); + actionGroup->setExclusive(true); + + for (auto axis: axisLocations) { + QAction* action = menu->addAction(ChartAxisLocationEnum::toGuiName(axis)); + action->setCheckable(true); + action->setData((int)ChartAxisLocationEnum::toIntegerCode(axis)); + QPixmap pixmap = createAxisLocationPixmap(menu, axis); + action->setIcon(pixmap); + actionGroup->addAction(action); + + m_axisLocationMenuData.push_back(std::make_tuple(axis, action, pixmap)); + } + + return menu; +} + +/** + * Called when an item is selected on axis location menu. + * + * @action + * Action of menu item selected. + */ +void +ChartTwoOverlayViewController::menuAxisLocationTriggered(QAction* action) +{ + const QVariant itemData = action->data(); + CaretAssert(itemData.isValid()); + bool valid = false; + ChartAxisLocationEnum::Enum axisLocation = ChartAxisLocationEnum::fromIntegerCode(itemData.toInt(), &valid); + + if (valid) { + m_chartOverlay->setCartesianVerticalAxisLocation(axisLocation); + updateAxisLocationAction(axisLocation); + this->updateGraphicsWindow(); + } +} /** * Create the construction menu. @@ -1122,6 +1229,63 @@ ChartTwoOverlayViewController::menuReloadFileTriggered() } } +/** + * Create a axis location mode pixmap. + * + * @param widget + * To color the pixmap with backround and foreground, + * the palette from the given widget is used. + * @param axisLocation + * Axis location represented by the icon. + * @return + * Pixmap for matrix view mode. + */ +QPixmap +ChartTwoOverlayViewController::createAxisLocationPixmap(QWidget* widget, + const ChartAxisLocationEnum::Enum axisLocation) +{ + CaretAssert(widget); + + /* + * Create a small, square pixmap that will contain + * the foreground color around the pixmap's perimeter. + */ + const qreal iconSize = 24.0; + const qreal minValue = 2.0; + const qreal maxValue = iconSize - minValue; + + QPixmap pixmap(static_cast(iconSize), + static_cast(iconSize)); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, + pixmap); + + QPen pen = painter->pen(); + pen.setWidthF(2.0); + painter->setPen(pen); + + const int offsetFromEdge = 3; + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + painter->drawLine(QPointF(minValue, minValue + offsetFromEdge), + QPointF(maxValue, minValue + offsetFromEdge)); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + painter->drawLine(QPointF(minValue + offsetFromEdge, minValue), + QPointF(minValue + offsetFromEdge, maxValue)); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + painter->drawLine(QPointF(maxValue - offsetFromEdge, minValue), + QPointF(maxValue - offsetFromEdge, maxValue)); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + painter->drawLine(QPointF(minValue, maxValue - offsetFromEdge), + QPointF(maxValue, maxValue - offsetFromEdge)); + break; + } + + return pixmap; +} + /** * Create a matrix view mode pixmap. * diff --git a/src/GuiQt/ChartTwoOverlayViewController.h b/src/GuiQt/ChartTwoOverlayViewController.h index 518dff29d..f3c2fddab 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.h +++ b/src/GuiQt/ChartTwoOverlayViewController.h @@ -25,6 +25,7 @@ #include #include +#include "ChartAxisLocationEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" class QAction; @@ -105,6 +106,8 @@ namespace caret { void menuMatrixTriangularViewModeTriggered(QAction* action); + void menuAxisLocationTriggered(QAction* action); + private: ChartTwoOverlayViewController(const ChartTwoOverlayViewController&); @@ -120,6 +123,8 @@ namespace caret { QMenu* createMatrixTriangularViewModeMenu(QWidget* widget); + QMenu* createAxisLocationMenu(QWidget* widget); + void validateYokingSelection(); void updateOverlaySettingsEditor(); @@ -129,8 +134,13 @@ namespace caret { QPixmap createMatrixTriangularViewModePixmap(QWidget* widget, const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); + QPixmap createAxisLocationPixmap(QWidget* widget, + const ChartAxisLocationEnum::Enum axisLocation); + void updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); + void updateAxisLocationAction(const ChartAxisLocationEnum::Enum axisLocation); + const int32_t m_browserWindowIndex; const int32_t m_chartOverlayIndex; @@ -157,8 +167,14 @@ namespace caret { QAction* m_matrixTriangularViewModeAction; + QAction* m_axisLocationAction; + + QToolButton* m_axisLocationToolButton; + std::vector> m_matrixViewMenuData; + std::vector> m_axisLocationMenuData; + QComboBox* m_mapFileComboBox; MapYokingGroupComboBox* m_mapRowOrColumnYokingGroupComboBox; @@ -173,8 +189,6 @@ namespace caret { QAction* m_constructionReloadFileAction; - WuQGridLayoutGroup* m_gridLayoutGroup; - // ADD_NEW_MEMBERS_HERE friend class ChartTwoOverlaySetViewController; -- GitLab From 6ce7cf35d50b64bbe40877df0f864991aff158e6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Feb 2017 14:54:16 -0600 Subject: [PATCH 208/755] In chart overlay, enable matrix triangular view button only when the displayed matrix contains number of rows equal to number of columns and the corresponding row and column names are identical. --- src/Brain/ChartTwoOverlay.cxx | 13 ++++++-- src/Brain/ChartTwoOverlay.h | 2 +- src/Files/ChartableTwoFileMatrixChart.cxx | 16 +++++++++- src/Files/ChartableTwoFileMatrixChart.h | 6 +++- ...iftiMappableConnectivityMatrixDataFile.cxx | 31 +++++++++++++++++++ .../CiftiMappableConnectivityMatrixDataFile.h | 2 ++ src/GuiQt/ChartTwoOverlayViewController.cxx | 19 ++++++------ 7 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index b5292c701..cde7117a7 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -1047,6 +1047,12 @@ ChartTwoOverlay::setAllMapsSelected(const bool status) ChartTwoMatrixTriangularViewingModeEnum::Enum ChartTwoOverlay::getMatrixTriangularViewingMode() const { + if ( ! isMatrixTriangularViewingModeSupported()) { + if (m_matrixTriangularViewingMode != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { + m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; + } + } + return m_matrixTriangularViewingMode; } @@ -1076,8 +1082,11 @@ ChartTwoOverlay::isMatrixTriangularViewingModeSupported() const case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - return true; - break; + { + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); + return matrixChart->isMatrixTriangularViewingModeSupported(); + } } return false; diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 8c28ed591..bc239c9d4 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -179,7 +179,7 @@ namespace caret { bool m_allHistogramMapsSelectedFlag = false; - ChartTwoMatrixTriangularViewingModeEnum::Enum m_matrixTriangularViewingMode; + mutable ChartTwoMatrixTriangularViewingModeEnum::Enum m_matrixTriangularViewingMode; /** Location of vertical cartesian axis*/ mutable ChartAxisLocationEnum::Enum m_cartesianVerticalAxisLocation; diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 8fce8b82f..e0484bc22 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -75,9 +75,13 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) numCols); } + m_matrixTriangularViewingModeSupportedFlag = false; if ((numRows > 0) && (numCols > 0)) { - /* OK */ + const CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(parentCaretMappableDataFile); + if (matrixFile != NULL) { + m_matrixTriangularViewingModeSupportedFlag = matrixFile->hasSymetricRowColumnNames(); + } } else { m_matrixContentType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; @@ -141,6 +145,16 @@ ChartableTwoFileMatrixChart::isEmpty() const return true; } +/** + * @return Is matrix triangular viewing modes supported? + */ +bool +ChartableTwoFileMatrixChart::isMatrixTriangularViewingModeSupported() const +{ + return m_matrixTriangularViewingModeSupportedFlag; +} + + /** * Get the matrix dimensions. * diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 94a24c838..098ce8f59 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -49,8 +49,10 @@ namespace caret { int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; - // ADD_NEW_METHODS_HERE + bool isMatrixTriangularViewingModeSupported() const; + // ADD_NEW_METHODS_HERE + ChartTwoMatrixLoadingDimensionEnum::Enum getSelectedRowColumnDimension() const; void setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension); @@ -83,6 +85,8 @@ namespace caret { const std::vector m_validRowColumnSelectionDimensions; + bool m_matrixTriangularViewingModeSupportedFlag = false; + //ChartTwoMatrixLoadingDimensionEnum::Enum m_rowColumnDimension; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx index 589db8589..739acee73 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx @@ -1291,6 +1291,37 @@ CiftiMappableConnectivityMatrixDataFile::getMapName(const int32_t /*mapIndex*/) return m_rowLoadedTextForMapName; } +/** + * @return True if the number of rows and columns is identical + * and the row and column names are identical for the same index + * (row "i" name is same as column "i" name for all rows/columns). + */ +bool +CiftiMappableConnectivityMatrixDataFile::hasSymetricRowColumnNames() const +{ + const CiftiXML& xml = m_ciftiFile->getCiftiXML(); + if ((xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) + && (xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS)) { + const std::vector& rowParcels = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); + const std::vector& columnParcels = xml.getParcelsMap(CiftiXML::ALONG_ROW).getParcels(); + if (rowParcels.size() == columnParcels.size()) { + const int numRowsColumns = static_cast(rowParcels.size()); + if (numRowsColumns > 0) { + for (int32_t i = 0; i < numRowsColumns; i++) { + CaretAssertVectorIndex(rowParcels, i); + CaretAssertVectorIndex(columnParcels, i); + if (rowParcels[i].m_name != columnParcels[i].m_name) { + return false; + } + } + return true; + } + } + } + + return false; +} + AString CiftiMappableConnectivityMatrixDataFile::getRowName(const int32_t rowIndex) const { diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.h b/src/Files/CiftiMappableConnectivityMatrixDataFile.h index 3bfd2db3b..a14e5fb88 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.h +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.h @@ -78,6 +78,8 @@ namespace caret { virtual AString getMapName(const int32_t mapIndex) const; + bool hasSymetricRowColumnNames() const; + AString getRowName(const int32_t rowIndex) const; AString getColumnName(const int32_t rowIndex) const; diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index f07e99dc1..0f3a820d0 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -783,17 +783,18 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla */ m_matrixTriangularViewModeAction->setEnabled(false); if (validOverlayAndFileFlag) { + const ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = m_chartOverlay->getMatrixTriangularViewingMode(); + + for (auto& mvmd : m_matrixViewMenuData) { + if (std::get<0>(mvmd) == viewMode) { + std::get<1>(mvmd)->setChecked(true); + updateMatrixTriangularViewModeAction(viewMode); + break; + } + } + if (m_chartOverlay->isMatrixTriangularViewingModeSupported()) { m_matrixTriangularViewModeAction->setEnabled(true); - const ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = m_chartOverlay->getMatrixTriangularViewingMode(); - - for (auto& mvmd : m_matrixViewMenuData) { - if (std::get<0>(mvmd) == viewMode) { - std::get<1>(mvmd)->setChecked(true); - updateMatrixTriangularViewModeAction(viewMode); - break; - } - } } } -- GitLab From b37506eea41aaf9d834a724068feaf5c5410d20f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 23 Feb 2017 16:42:05 -0600 Subject: [PATCH 209/755] Fixed crash of histogram display when a dynamic connectivity type file does not yet have data loaded (user has not clicked a brainordinate). --- src/Files/CaretMappableDataFile.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 9722bef78..915e32244 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -861,6 +861,15 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, } } + /* + * Statistics may be NULL for connectivity files (dense, dense dynamic) + * that have not yet loaded any data caused by the user clicking + * brainordinates. + */ + if (statistics == NULL) { + return false; + } + CaretAssert(statistics); float mostPos = 0.0; float leastPos = 0.0; -- GitLab From 99c93094b158d5582a0d57cd4da9a9580ebca6b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Feb 2017 11:25:48 -0600 Subject: [PATCH 210/755] Continuing charting development. Starting on histogram number of bins. --- src/Files/ChartableTwoFileHistogramChart.cxx | 80 +++++++++---------- src/Files/ChartableTwoFileHistogramChart.h | 6 +- .../MapSettingsPaletteColorMappingWidget.cxx | 16 +++- .../MapSettingsPaletteColorMappingWidget.h | 2 + 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index aeda9b5bd..1ecc05769 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -25,7 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" -#include "ChartTwoDataHistogram.h" +//#include "ChartTwoDataHistogram.h" #include "Histogram.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -79,10 +79,10 @@ m_histogramContentType(histogramContentType) */ ChartableTwoFileHistogramChart::~ChartableTwoFileHistogramChart() { - for (auto mapHistoPair : m_indexHistogramsMap) { - delete mapHistoPair.second; - } - m_indexHistogramsMap.clear(); +// for (auto mapHistoPair : m_indexHistogramsMap) { +// delete mapHistoPair.second; +// } +// m_indexHistogramsMap.clear(); delete m_sceneAssistant; } @@ -115,41 +115,41 @@ ChartableTwoFileHistogramChart::isEmpty() const return false; } -/** - * Get the histogram chart for the given map index. - * - * @param mapIndex - * Index for the map. - * @return - * Histogram for the map with the given index. NULL if the file - * does not support a histogram. - */ -const ChartTwoDataHistogram* -ChartableTwoFileHistogramChart::getMapHistogramChart(const int32_t mapIndex) const -{ - CaretAssertToDoFatal(); // This class may not be needed - - ChartTwoDataHistogram* histogramChartOut = NULL; - - std::map::iterator iter = m_indexHistogramsMap.find(mapIndex); - if (iter != m_indexHistogramsMap.end()) { - histogramChartOut = iter->second; - } - else { - histogramChartOut = new ChartTwoDataHistogram(); - m_indexHistogramsMap.insert(std::make_pair(mapIndex, - histogramChartOut)); - } - - /* - * Update with histogram from the file even if it is NULL. - */ - CaretMappableDataFile* mapFile = const_cast(getCaretMappableDataFile()); - CaretAssert(mapFile); - histogramChartOut->setHistogram(const_cast(mapFile->getMapHistogram(mapIndex))); - - return histogramChartOut; -} +///** +// * Get the histogram chart for the given map index. +// * +// * @param mapIndex +// * Index for the map. +// * @return +// * Histogram for the map with the given index. NULL if the file +// * does not support a histogram. +// */ +//const ChartTwoDataHistogram* +//ChartableTwoFileHistogramChart::getMapHistogramChart(const int32_t mapIndex) const +//{ +// CaretAssertToDoFatal(); // This class may not be needed +// +// ChartTwoDataHistogram* histogramChartOut = NULL; +// +// std::map::iterator iter = m_indexHistogramsMap.find(mapIndex); +// if (iter != m_indexHistogramsMap.end()) { +// histogramChartOut = iter->second; +// } +// else { +// histogramChartOut = new ChartTwoDataHistogram(); +// m_indexHistogramsMap.insert(std::make_pair(mapIndex, +// histogramChartOut)); +// } +// +// /* +// * Update with histogram from the file even if it is NULL. +// */ +// CaretMappableDataFile* mapFile = const_cast(getCaretMappableDataFile()); +// CaretAssert(mapFile); +// histogramChartOut->setHistogram(const_cast(mapFile->getMapHistogram(mapIndex))); +// +// return histogramChartOut; +//} /** * Save subclass data to the scene. diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index a530da756..bbfa8228d 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -29,7 +29,7 @@ namespace caret { - class ChartTwoDataHistogram; + //class ChartTwoDataHistogram; class ChartableTwoFileHistogramChart : public ChartableTwoFileBaseChart { @@ -45,7 +45,7 @@ namespace caret { virtual bool isEmpty() const override; - const ChartTwoDataHistogram* getMapHistogramChart(const int32_t mapIndex) const; + //const ChartTwoDataHistogram* getMapHistogramChart(const int32_t mapIndex) const; // ADD_NEW_METHODS_HERE @@ -65,7 +65,7 @@ namespace caret { const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; - mutable std::map m_indexHistogramsMap; + // mutable std::map m_indexHistogramsMap; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 0041a393d..00373ac1d 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -757,6 +757,12 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() this->m_histogramChartTypeComboBox->setup(); this->m_histogramChartTypeComboBox->getWidget()->setToolTip("Set type of chart drawn"); + const int32_t maxBuckets = 100000; + QLabel* bucketsLabel = new QLabel("Buckets"); + m_histogramBucketsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, maxBuckets, 1); + QObject::connect(m_histogramBucketsSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(applyAndUpdate())); + QWidget* controlWidget = new QWidget(); QGridLayout* controlLayout = new QGridLayout(controlWidget); this->setLayoutSpacingAndMargins(controlLayout); @@ -766,6 +772,8 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() controlLayout->addWidget(m_histogramColorComboBox->getWidget(), 1, 1); controlLayout->addWidget(horizRangeLabel, 2, 0); controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), 2, 1); + controlLayout->addWidget(bucketsLabel, 3, 0); + controlLayout->addWidget(m_histogramBucketsSpinBox, 3, 1); controlWidget->setFixedSize(controlWidget->sizeHint()); /* @@ -1619,20 +1627,25 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile m_histogramHorizontalRangeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramRangeMode()); + updateThresholdSection(); float minValue = 0.0; float maxValue = 0.0; + m_histogramBucketsSpinBox->blockSignals(true); FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); + //m_histogramBucketsSpinBox->setValue(this->caretMappableDataFile->getFile); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); + //m_histogramBucketsSpinBox->setValue(this->paletteColorMapping->getHistogramNumberOfBuckets()); break; } + m_histogramBucketsSpinBox->blockSignals(false); if (statistics != NULL) { minValue = statistics->getMin(); @@ -2187,7 +2200,8 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramChartType(m_histogramChartTypeComboBox->getSelectedItem()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); - +// this->paletteColorMapping->setHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); + float lowValue = this->thresholdLowSpinBox->value(); float highValue = this->thresholdHighSpinBox->value(); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index 1a646d1ef..f4e43ac5a 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -196,6 +196,8 @@ namespace caret { EnumComboBoxTemplate* m_histogramChartTypeComboBox; + QSpinBox* m_histogramBucketsSpinBox; + CaretMappableDataFile* caretMappableDataFile; CaretMappableDataFile* m_previousCaretMappableDataFile; -- GitLab From 013a2a48a22bb5a1b70682cc191b5e067f369d01 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Mar 2017 09:51:22 -0600 Subject: [PATCH 211/755] Added include for 'memory' to needed to compile on linux. --- src/Brain/ChartTwoOverlay.h | 2 +- src/Brain/ModelChart.h | 2 ++ src/Brain/ModelChartTwo.h | 2 ++ src/Charting/ChartTwoCartesianAxis.h | 1 + src/Files/ChartableTwoFileDelegate.h | 2 ++ src/Files/ChartableTwoFileLineSeriesChart.h | 2 ++ 6 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index bc239c9d4..157cdb8be 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -21,9 +21,9 @@ */ /*LICENSE_END*/ +#include #include "CaretObject.h" - #include "ChartAxisLocationEnum.h" #include "ChartTwoCompoundDataType.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index e388fee82..9cc8a6914 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include #include diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index 6661ec9bc..c51bf8001 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include #include diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 7538ada10..7db0bd326 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include "CaretObject.h" #include "ChartAxisLocationEnum.h" diff --git a/src/Files/ChartableTwoFileDelegate.h b/src/Files/ChartableTwoFileDelegate.h index 654992d26..428338afa 100644 --- a/src/Files/ChartableTwoFileDelegate.h +++ b/src/Files/ChartableTwoFileDelegate.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" #include "ChartTwoDataTypeEnum.h" diff --git a/src/Files/ChartableTwoFileLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h index d210729b8..7666d2530 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include "ChartableTwoFileBaseChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" -- GitLab From 4f0ec7046ac2d292136e943b11da010e98cf10e3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 08:29:46 -0600 Subject: [PATCH 212/755] Default new charting grid lines off. --- src/Charting/ChartTwoMatrixDisplayProperties.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Charting/ChartTwoMatrixDisplayProperties.cxx b/src/Charting/ChartTwoMatrixDisplayProperties.cxx index 62c4e6539..5f3417a81 100644 --- a/src/Charting/ChartTwoMatrixDisplayProperties.cxx +++ b/src/Charting/ChartTwoMatrixDisplayProperties.cxx @@ -151,7 +151,7 @@ ChartTwoMatrixDisplayProperties::resetPropertiesToDefault() m_cellPercentageZoomWidth = 100.0; m_cellPercentageZoomHeight = 100.0; m_highlightSelectedRowColumnFlag = true; - m_displayGridLinesFlag = true; + m_displayGridLinesFlag = false; } /** -- GitLab From a1a208ccf238fd4751254fae10aecb3bdd858cbc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 12:42:25 -0600 Subject: [PATCH 213/755] Display checkbox of top chart overlay so that user can toggle display of multiple charts --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 7 ++----- src/Brain/ChartTwoOverlay.cxx | 21 +------------------ src/Brain/ChartTwoOverlaySet.cxx | 10 --------- src/Brain/ChartTwoOverlaySet.h | 2 -- src/GuiQt/ChartTwoOverlayViewController.cxx | 12 ++--------- 5 files changed, 5 insertions(+), 47 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 20ff3d3f2..e533bf979 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -56,9 +56,6 @@ using namespace caret; -static const float fontSizeInPixels = 14; - - /** * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline * \brief Drawing of version two charts. @@ -181,7 +178,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); if (numberOfOverlays > 0) { ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); - if (topOverlay->isEnabled()) { + //if (topOverlay->isEnabled()) { CaretMappableDataFile* cmdf = NULL; int32_t mapIndex = -1; topOverlay->getSelectionData(cmdf, mapIndex); @@ -207,7 +204,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, break; } } - } + //} } } diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index cde7117a7..4105e133d 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -226,13 +226,6 @@ ChartTwoOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& cha bool ChartTwoOverlay::isEnabled() const { - /* - * First overlay is ALWAYS enabled - */ - if (m_overlayIndex == 0) { - return true; - } - return m_enabled; } @@ -244,13 +237,6 @@ ChartTwoOverlay::isEnabled() const void ChartTwoOverlay::setEnabled(const bool enabled) { - if (m_overlayIndex == 0) { - if ( ! enabled) { - CaretAssertMessage(0, "Request to disable first overlay should NEVER happen"); - CaretLogSevere("Request to disable first overlay should NEVER happen"); - return; - } - } m_enabled = enabled; } @@ -273,12 +259,7 @@ ChartTwoOverlay::copyData(const ChartTwoOverlay* overlay) * */ - /* - * NEVER disable the first overlay - */ - if (m_overlayIndex > 0) { - m_enabled = overlay->m_enabled; - } + m_enabled = overlay->m_enabled; m_mapYokingGroup = overlay->m_mapYokingGroup; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index e5b068d1f..312999c40 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -149,16 +149,6 @@ ChartTwoOverlaySet::getPrimaryOverlay() return m_overlays[0]; } -/** - * @return Returns the underlay which is the lowest - * displayed overlay. - */ -ChartTwoOverlay* -ChartTwoOverlaySet::getUnderlay() -{ - return m_overlays[getNumberOfDisplayedOverlays() - 1]; -} - /** * Get the overlay at the specified index. * @param overlayNumber diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 4a3a0bd63..887dd0928 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -48,8 +48,6 @@ namespace caret { ChartTwoOverlay* getPrimaryOverlay(); - ChartTwoOverlay* getUnderlay(); - ChartTwoOverlay* getOverlay(const int32_t overlayNumber); const ChartTwoOverlay* getOverlay(const int32_t overlayNumber) const; diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 0f3a820d0..41f5d03ac 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -709,16 +709,8 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla m_enabledCheckBox->setEnabled(false); m_enabledCheckBox->setChecked(false); if (validOverlayAndFileFlag) { - /* - * First overlay is ALWAYS ENABLED and HIDDEN - */ - if (m_chartOverlayIndex == 0) { - m_enabledCheckBox->setVisible(false); - } - else { - m_enabledCheckBox->setEnabled(true); - m_enabledCheckBox->setChecked(m_chartOverlay->isEnabled()); - } + m_enabledCheckBox->setEnabled(true); + m_enabledCheckBox->setChecked(m_chartOverlay->isEnabled()); } -- GitLab From dad0989fc0510c68994c9a080cd1be63dc0d841c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Mar 2017 15:33:56 -0600 Subject: [PATCH 214/755] Finished merging with latest 'master'. For some reason, a couple of conversions from CaretColorEnum::toRGBFloat() to CaretColorEnum::toRGBAFloat() got lost during the merge. --- src/Files/CaretMappableDataFile.cxx | 2 +- src/GuiQt/CaretColorEnumComboBox.cxx | 2 +- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 915e32244..05947d075 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1083,7 +1083,7 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); if (histogramColor != CaretColorEnum::CUSTOM) { float rgba[4]; - CaretColorEnum::toRGBFloat(histogramColor, rgba); + CaretColorEnum::toRGBAFloat(histogramColor, rgba); rgba[3] = 1.0; for (int32_t i = 0; i < numberOfDataPoints; i++) { diff --git a/src/GuiQt/CaretColorEnumComboBox.cxx b/src/GuiQt/CaretColorEnumComboBox.cxx index a88f711ee..0450c023a 100644 --- a/src/GuiQt/CaretColorEnumComboBox.cxx +++ b/src/GuiQt/CaretColorEnumComboBox.cxx @@ -114,7 +114,7 @@ CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorS * Create an icon with the color. */ float rgba[4]; - CaretColorEnum::toRGBFloat(colorEnum, rgba); + CaretColorEnum::toRGBAFloat(colorEnum, rgba); if (colorEnum == CaretColorEnum::NONE) { rgba[3] = 0.0; } diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 00373ac1d..02beea99f 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -1877,7 +1877,7 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } else { float colorRGBA[4]; - CaretColorEnum::toRGBFloat(histogramColor, + CaretColorEnum::toRGBAFloat(histogramColor, colorRGBA); colorRGBA[3] = 1.0; for (int64_t i = 0; i < numDataValues; i++) { -- GitLab From 87f996bb7c65a3d7730dc6cfeb2bebb1352a0a98 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Mar 2017 14:23:16 -0600 Subject: [PATCH 215/755] When PaletteColorMappingSaxReader encounters an unexpected element, include the content in the message. --- src/Palette/PaletteColorMappingSaxReader.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 908c36798..503226486 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -372,9 +372,10 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, else { std::ostringstream str; str - << "Unrecognized (perhaps new) palette color mapping element \"" + << "Unrecognized (perhaps new) palette color mapping element ignored \"" << qName.toStdString() - << "\"."; + << "\" with content: " + << this->elementText.toStdString(); warning(XmlSaxParserException(AString::fromStdString(str.str()))); } break; -- GitLab From 3646acda9d63f88fd4501dd17b159fb354e56d5a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 9 Mar 2017 15:33:29 -0600 Subject: [PATCH 216/755] Changed the name of some members and methods in PaletteColorMapping to clearly indicate they are attributes of the colorbar. --- src/GuiQt/MapSettingsColorBarWidget.cxx | 16 +-- src/Palette/PaletteColorMapping.cxx | 126 +++++++++---------- src/Palette/PaletteColorMapping.h | 24 ++-- src/Palette/PaletteColorMappingSaxReader.cxx | 10 +- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/GuiQt/MapSettingsColorBarWidget.cxx b/src/GuiQt/MapSettingsColorBarWidget.cxx index 14da03ba2..0d07b13e2 100644 --- a/src/GuiQt/MapSettingsColorBarWidget.cxx +++ b/src/GuiQt/MapSettingsColorBarWidget.cxx @@ -162,10 +162,10 @@ MapSettingsColorBarWidget::applySelections() { if (m_paletteColorMapping != NULL) { m_paletteColorMapping->setColorBarValuesMode(m_colorBarDataModeComboBox->getSelectedItem()); - m_paletteColorMapping->setNumericFormatMode(m_colorBarNumericFormatModeComboBox->getSelectedItem()); - m_paletteColorMapping->setPrecisionDigits(m_colorBarDecimalsSpinBox->value()); - m_paletteColorMapping->setNumericSubdivisionCount(m_colorBarNumericSubdivisionsSpinBox->value()); - m_paletteColorMapping->setShowTickMarksSelected(m_showTickMarksCheckBox->isChecked()); + m_paletteColorMapping->setColorBarNumericFormatMode(m_colorBarNumericFormatModeComboBox->getSelectedItem()); + m_paletteColorMapping->setColorBarPrecisionDigits(m_colorBarDecimalsSpinBox->value()); + m_paletteColorMapping->setColorBarNumericSubdivisionCount(m_colorBarNumericSubdivisionsSpinBox->value()); + m_paletteColorMapping->setColorBarShowTickMarksSelected(m_showTickMarksCheckBox->isChecked()); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); @@ -369,7 +369,7 @@ MapSettingsColorBarWidget::updateColorBarAttributes() break; } - const NumericFormatModeEnum::Enum numericFormat = m_paletteColorMapping->getNumericFormatMode(); + const NumericFormatModeEnum::Enum numericFormat = m_paletteColorMapping->getColorBarNumericFormatMode(); switch (numericFormat) { case NumericFormatModeEnum::AUTO: precisionDigitsSpinBoxEnabled = false; @@ -388,17 +388,17 @@ MapSettingsColorBarWidget::updateColorBarAttributes() m_colorBarDecimalsLabel->setEnabled(precisionDigitsSpinBoxEnabled); m_colorBarDecimalsSpinBox->blockSignals(true); - m_colorBarDecimalsSpinBox->setValue(m_paletteColorMapping->getPrecisionDigits()); + m_colorBarDecimalsSpinBox->setValue(m_paletteColorMapping->getColorBarPrecisionDigits()); m_colorBarDecimalsSpinBox->blockSignals(false); m_colorBarDecimalsSpinBox->setEnabled(precisionDigitsSpinBoxEnabled); m_colorBarNumericSubdivisionsLabel->setEnabled(subdivisionsSpinBoxEnabled); m_colorBarNumericSubdivisionsSpinBox->blockSignals(true); - m_colorBarNumericSubdivisionsSpinBox->setValue(m_paletteColorMapping->getNumericSubdivisionCount()); + m_colorBarNumericSubdivisionsSpinBox->setValue(m_paletteColorMapping->getColorBarNumericSubdivisionCount()); m_colorBarNumericSubdivisionsSpinBox->blockSignals(false); m_colorBarNumericSubdivisionsSpinBox->setEnabled(subdivisionsSpinBoxEnabled); - m_showTickMarksCheckBox->setChecked(m_paletteColorMapping->isShowTickMarksSelected()); + m_showTickMarksCheckBox->setChecked(m_paletteColorMapping->isColorBarShowTickMarksSelected()); } } diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 810b8faca..b9980e24e 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -137,11 +137,11 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->histogramRangeMode = pcm.histogramRangeMode; this->histogramChartType = pcm.histogramChartType; this->histogramColor = pcm.histogramColor; - this->numericFormatMode = pcm.numericFormatMode; - this->precisionDigits = pcm.precisionDigits; - this->numericSubdivisionCount = pcm.numericSubdivisionCount; + this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; + this->colorBarPrecisionDigits = pcm.colorBarPrecisionDigits; + this->colorBarNumericSubdivisionCount = pcm.colorBarNumericSubdivisionCount; this->colorBarValuesMode = pcm.colorBarValuesMode; - this->showTickMarksSelected = pcm.showTickMarksSelected; + this->colorBarShowTickMarksSelected = pcm.colorBarShowTickMarksSelected; this->clearModified(); } @@ -187,11 +187,11 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->histogramRangeMode == pcm.histogramRangeMode) && (this->histogramChartType == pcm.histogramChartType) && (this->histogramColor == pcm.histogramColor) - && (this->numericFormatMode == pcm.numericFormatMode) - && (this->precisionDigits == pcm.precisionDigits) - && (this->numericSubdivisionCount == pcm.numericSubdivisionCount) + && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) + && (this->colorBarPrecisionDigits == pcm.colorBarPrecisionDigits) + && (this->colorBarNumericSubdivisionCount == pcm.colorBarNumericSubdivisionCount) && (this->colorBarValuesMode == pcm.colorBarValuesMode) - && (this->showTickMarksSelected == pcm.showTickMarksSelected)) { + && (this->colorBarShowTickMarksSelected == pcm.colorBarShowTickMarksSelected)) { return true; } @@ -234,12 +234,12 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; this->histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette - this->numericFormatMode = NumericFormatModeEnum::AUTO; - this->precisionDigits = 2; - this->numericSubdivisionCount = 0; + this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; + this->colorBarPrecisionDigits = 2; + this->colorBarNumericSubdivisionCount = 0; this->modifiedFlag = false; this->colorBarValuesMode = PaletteColorBarValuesModeEnum::DATA; - this->showTickMarksSelected = false; + this->colorBarShowTickMarksSelected = false; } /** @@ -357,17 +357,17 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, CaretColorEnum::toName(this->histogramColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, - NumericFormatModeEnum::toName(this->numericFormatMode)); + NumericFormatModeEnum::toName(this->colorBarNumericFormatMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS, - this->precisionDigits); + this->colorBarPrecisionDigits); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_SUBDIVISIONS, - this->numericSubdivisionCount); + this->colorBarNumericSubdivisionCount); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_COLOR_BAR_VALUES_MODE, PaletteColorBarValuesModeEnum::toName(this->colorBarValuesMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_SHOW_TICK_MARKS, - this->showTickMarksSelected); + this->colorBarShowTickMarksSelected); xmlWriter.writeEndElement(); } @@ -1911,7 +1911,7 @@ PaletteColorMapping::setupAnnotationColorBarNumericText(const FastStatistics* st delete nt; } - colorBar->setShowTickMarksSelected(this->showTickMarksSelected); + colorBar->setShowTickMarksSelected(this->colorBarShowTickMarksSelected); } /** @@ -2049,10 +2049,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ std::vector negativeValues; negativeValues.push_back(negMax); - if (this->numericSubdivisionCount > 0) { + if (this->colorBarNumericSubdivisionCount > 0) { const float range = negMin - negMax; - const float interval = range / (this->numericSubdivisionCount + 1); - for (int32_t i = 0; i < this->numericSubdivisionCount; i++) { + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { negativeValues.push_back(negMax + (interval * (i + 1))); } @@ -2064,10 +2064,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ std::vector positiveValues; positiveValues.push_back(posMin); - if (this->numericSubdivisionCount > 0) { + if (this->colorBarNumericSubdivisionCount > 0) { const float range = posMax - posMin; - const float interval = range / (this->numericSubdivisionCount + 1); - for (int32_t i = 0; i < this->numericSubdivisionCount; i++) { + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { positiveValues.push_back(posMin + (interval * (i + 1))); } @@ -2077,8 +2077,8 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic /* * Will need to override these values when percentile */ - NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->numericFormatMode; - int32_t precisionDigitsForTextFormatting = this->precisionDigits; + NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->colorBarNumericFormatMode; + int32_t precisionDigitsForTextFormatting = this->colorBarPrecisionDigits; /* * Processing for percentile mode @@ -2457,10 +2457,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ std::vector negativeValues; negativeValues.push_back(negMax); - if (this->numericSubdivisionCount > 0) { + if (this->colorBarNumericSubdivisionCount > 0) { const float range = negMin - negMax; - const float interval = range / (this->numericSubdivisionCount + 1); - for (int32_t i = 0; i < this->numericSubdivisionCount; i++) { + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { negativeValues.push_back(negMax + (interval * (i + 1))); } @@ -2472,10 +2472,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ std::vector positiveValues; positiveValues.push_back(posMin); - if (this->numericSubdivisionCount > 0) { + if (this->colorBarNumericSubdivisionCount > 0) { const float range = posMax - posMin; - const float interval = range / (this->numericSubdivisionCount + 1); - for (int32_t i = 0; i < this->numericSubdivisionCount; i++) { + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { positiveValues.push_back(posMin + (interval * (i + 1))); } @@ -2485,8 +2485,8 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic /* * Wil need to override these values when percentile */ - NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->numericFormatMode; - int32_t precisionDigitsForTextFormatting = this->precisionDigits; + NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->colorBarNumericFormatMode; + int32_t precisionDigitsForTextFormatting = this->colorBarPrecisionDigits; /* * Processing for percentile mode @@ -2800,77 +2800,77 @@ PaletteColorMapping::setHistogramColor(const CaretColorEnum::Enum histogramColor } /** - * @return The numeric format mode. + * @return The color bar numeric format mode. */ NumericFormatModeEnum::Enum -PaletteColorMapping::getNumericFormatMode() const +PaletteColorMapping::getColorBarNumericFormatMode() const { - return this->numericFormatMode; + return this->colorBarNumericFormatMode; } /** - * Set the numeric format mode. + * Set the color bar numeric format mode. * - * @param numericFormatMode - * New value for precision mode. + * @param colorBarNumericFormatMode + * New value for color bar numberic format mode */ void -PaletteColorMapping::setNumericFormatMode(const NumericFormatModeEnum::Enum numericFormatMode) +PaletteColorMapping::setColorBarNumericFormatMode(const NumericFormatModeEnum::Enum colorBarNumericFormatMode) { - if (numericFormatMode != this->numericFormatMode) { - this->numericFormatMode = numericFormatMode; + if (colorBarNumericFormatMode != this->colorBarNumericFormatMode) { + this->colorBarNumericFormatMode = colorBarNumericFormatMode; setModified(); } } /** - * @return The precision digits (right of decimal). + * @return The color bar precision digits (right of decimal). */ int32_t -PaletteColorMapping::getPrecisionDigits() const +PaletteColorMapping::getColorBarPrecisionDigits() const { - return this->precisionDigits; + return this->colorBarPrecisionDigits; } /** - * Set the precision digits (right of decimal) + * Set the color bar precision digits (right of decimal) * - * @param precisionDigits + * @param colorBarPrecisionDigits * New value for number of digits right of decimal. */ void -PaletteColorMapping::setPrecisionDigits(const int32_t precisionDigits) +PaletteColorMapping::setColorBarPrecisionDigits(const int32_t colorBarPrecisionDigits) { - if (precisionDigits != this->precisionDigits) { - this->precisionDigits = precisionDigits; + if (colorBarPrecisionDigits != this->colorBarPrecisionDigits) { + this->colorBarPrecisionDigits = colorBarPrecisionDigits; setModified(); } } /** - * @return The numeric subdivision count which is the number of + * @return The color bar numeric subdivision count which is the number of * numeric values uniformly spaced between zero and the maximum * value. */ int32_t -PaletteColorMapping::getNumericSubdivisionCount() const +PaletteColorMapping::getColorBarNumericSubdivisionCount() const { - return this->numericSubdivisionCount; + return this->colorBarNumericSubdivisionCount; } /** - * Set the numeric subdivision count which is the number of + * Set the color bar numeric subdivision count which is the number of * numeric values uniformly spaced between zero and the maximum * value. * - * @param numericSubvisionCount + * @param colorBarNumericSubdivisionCount * New value for subdivision count. */ void -PaletteColorMapping::setNumericSubdivisionCount(const int32_t numericSubdivisionCount) +PaletteColorMapping::setColorBarNumericSubdivisionCount(const int32_t colorBarNumericSubdivisionCount) { - if (numericSubdivisionCount != this->numericSubdivisionCount) { - this->numericSubdivisionCount = numericSubdivisionCount; + if (colorBarNumericSubdivisionCount != this->colorBarNumericSubdivisionCount) { + this->colorBarNumericSubdivisionCount = colorBarNumericSubdivisionCount; setModified(); } } @@ -2901,9 +2901,9 @@ void PaletteColorMapping::setColorBarValuesMode(const PaletteColorBarValuesModeE * @param Is show tick marks selected? */ bool -PaletteColorMapping::isShowTickMarksSelected() const +PaletteColorMapping::isColorBarShowTickMarksSelected() const { - return this->showTickMarksSelected; + return this->colorBarShowTickMarksSelected; } /** @@ -2913,10 +2913,10 @@ PaletteColorMapping::isShowTickMarksSelected() const * New selection status. */ void -PaletteColorMapping::setShowTickMarksSelected(const bool selected) +PaletteColorMapping::setColorBarShowTickMarksSelected(const bool selected) { - if (selected != this->showTickMarksSelected) { - this->showTickMarksSelected = selected; + if (selected != this->colorBarShowTickMarksSelected) { + this->colorBarShowTickMarksSelected = selected; setModified(); } } diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 11371f1a0..174a0ae96 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -221,25 +221,25 @@ namespace caret { void setHistogramColor(const CaretColorEnum::Enum histogramColor); - NumericFormatModeEnum::Enum getNumericFormatMode() const; + NumericFormatModeEnum::Enum getColorBarNumericFormatMode() const; - int32_t getPrecisionDigits() const; + int32_t getColorBarPrecisionDigits() const; - int32_t getNumericSubdivisionCount() const; + int32_t getColorBarNumericSubdivisionCount() const; - void setNumericFormatMode(const NumericFormatModeEnum::Enum numericFormatMode); + void setColorBarNumericFormatMode(const NumericFormatModeEnum::Enum colorBarNumericFormatMode); - void setPrecisionDigits(const int32_t precisionDigits); + void setColorBarPrecisionDigits(const int32_t colorBarPrecisionDigits); - void setNumericSubdivisionCount(const int32_t numericSubdivisionCount); + void setColorBarNumericSubdivisionCount(const int32_t colroBarNumericSubdivisionCount); PaletteColorBarValuesModeEnum::Enum getColorBarValuesMode() const; void setColorBarValuesMode(const PaletteColorBarValuesModeEnum::Enum colorBarValuesMode); - bool isShowTickMarksSelected() const; + bool isColorBarShowTickMarksSelected() const; - void setShowTickMarksSelected(const bool selected); + void setColorBarShowTickMarksSelected(const bool selected); void setModified(); @@ -327,15 +327,15 @@ namespace caret { CaretColorEnum::Enum histogramColor; - NumericFormatModeEnum::Enum numericFormatMode; + NumericFormatModeEnum::Enum colorBarNumericFormatMode; - int32_t precisionDigits; + int32_t colorBarPrecisionDigits; - int32_t numericSubdivisionCount; + int32_t colorBarNumericSubdivisionCount; PaletteColorBarValuesModeEnum::Enum colorBarValuesMode; - bool showTickMarksSelected; + bool colorBarShowTickMarksSelected; /**Tracks modification, DO NOT copy */ bool modifiedFlag; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 503226486..1e9df5387 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -341,18 +341,18 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, NumericFormatModeEnum::Enum numericFormatMode = NumericFormatModeEnum::fromName(this->elementText, &isValid); if (isValid) { - this->paletteColorMapping->setNumericFormatMode(numericFormatMode); + this->paletteColorMapping->setColorBarNumericFormatMode(numericFormatMode); } else { - throw XmlSaxParserException("Invalid PalettePrecisionModeEnum::Enum: " + throw XmlSaxParserException("Invalid NumericFormatModeEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS) { - this->paletteColorMapping->setPrecisionDigits(this->elementText.toInt()); + this->paletteColorMapping->setColorBarPrecisionDigits(this->elementText.toInt()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_SUBDIVISIONS) { - this->paletteColorMapping->setNumericSubdivisionCount(this->elementText.toInt()); + this->paletteColorMapping->setColorBarNumericSubdivisionCount(this->elementText.toInt()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_COLOR_BAR_VALUES_MODE) { bool isValid = false; @@ -367,7 +367,7 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_SHOW_TICK_MARKS) { - this->paletteColorMapping->setShowTickMarksSelected(toBool(this->elementText)); + this->paletteColorMapping->setColorBarShowTickMarksSelected(toBool(this->elementText)); } else { std::ostringstream str; -- GitLab From b89d985879dbc0efd6846178351c41a1b0c67181 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 13 Mar 2017 15:18:13 -0500 Subject: [PATCH 217/755] Implemented histogram number of buckets on the Overlay and Map Setting's Dialog's Palette tab. The number of histogram buckets is a property of the file and also of each map. When the Palette Normalization is 'Selected Map', the number of buckets is the number of buckets associated with the map. When the Palette Normalization mode is 'All Maps', the number of buckets property is that associated with the file. --- src/Common/Histogram.cxx | 11 +++ src/Common/Histogram.h | 15 ++- src/Files/CaretMappableDataFile.cxx | 33 +++++++ src/Files/CaretMappableDataFile.h | 4 + src/Files/ChartableTwoFileHistogramChart.cxx | 18 ++-- src/Files/CiftiMappableDataFile.cxx | 95 ++++++++++++++---- src/Files/CiftiMappableDataFile.h | 17 +++- src/Files/GiftiTypeFile.cxx | 96 +++++++++++++++++-- src/Files/GiftiTypeFile.h | 3 + src/Files/VolumeFile.cxx | 71 ++++++++++++-- src/Files/VolumeFile.h | 5 + src/FilesBase/GiftiMetaDataXmlElements.h | 3 + src/Gifti/GiftiDataArray.cxx | 50 +++++++--- src/Gifti/GiftiDataArray.h | 15 ++- .../MapSettingsPaletteColorMappingWidget.cxx | 13 ++- src/Palette/PaletteColorMapping.cxx | 29 ++++++ src/Palette/PaletteColorMapping.h | 6 ++ src/Palette/PaletteColorMappingSaxReader.cxx | 3 + src/Palette/PaletteColorMappingXmlElements.h | 1 + 19 files changed, 420 insertions(+), 68 deletions(-) diff --git a/src/Common/Histogram.cxx b/src/Common/Histogram.cxx index 3f08b7529..db8ecb1cf 100644 --- a/src/Common/Histogram.cxx +++ b/src/Common/Histogram.cxx @@ -176,6 +176,17 @@ void Histogram::update(const float* data, const int64_t& dataCount) } } +void Histogram::update(const int32_t& numBuckets, + const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, + float leastPositiveValueInclusive, float leastNegativeValueInclusive, + float mostNegativeValueInclusive, const bool& includeZeroValues) +{ + resize(numBuckets); + update(data, dataCount, mostPositiveValueInclusive, + leastPositiveValueInclusive, leastNegativeValueInclusive, + mostNegativeValueInclusive, includeZeroValues); +} + void Histogram::update(const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, float leastNegativeValueInclusive, float mostNegativeValueInclusive, const bool& includeZeroValues) diff --git a/src/Common/Histogram.h b/src/Common/Histogram.h index d7570ff97..be1f59b48 100644 --- a/src/Common/Histogram.h +++ b/src/Common/Histogram.h @@ -41,6 +41,16 @@ namespace caret void computeCumulative(); + void update(const float* data, + const int64_t& dataCount, + float mostPositiveValueInclusive, + float leastPositiveValueInclusive, + float leastNegativeValueInclusive, + float mostNegativeValueInclusive, + const bool& includeZeroValues); + + void update(const float* data, const int64_t& dataCount); + public: Histogram(const int& numBuckets = 100); @@ -48,11 +58,10 @@ namespace caret Histogram(const int& numBuckets, const float* data, const int64_t& dataCount); - void update(const float* data, const int64_t& dataCount); - void update(const int& numBuckets, const float* data, const int64_t& dataCount); - void update(const float* data, + void update(const int32_t& numBuckets, + const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 05947d075..886054da5 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1200,6 +1200,39 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, return false; } +/** + * @return File histogram number of buckets. + */ +int32_t +CaretMappableDataFile::getFileHistogramNumberOfBuckets() const +{ + /* + * Metadata returns zero if integer value not found + */ + const GiftiMetaData* metadata = getFileMetaData(); + CaretAssert(metadata); + int32_t numBuckets = metadata->getInt(GiftiMetaDataXmlElements::HISTOGRAM_NUMBER_OF_BUCKETS); + if (numBuckets <= 0) { + numBuckets = 100; + } + return numBuckets; +} + +/** + * Set the file histogram number of buckets. + * + * @param numberOfBuckets + * Number of buckets. + */ +void +CaretMappableDataFile::setFileHistogramNumberOfBuckets(const int32_t numberOfBuckets) +{ + GiftiMetaData* metadata = getFileMetaData(); + CaretAssert(metadata); + metadata->setInt(GiftiMetaDataXmlElements::HISTOGRAM_NUMBER_OF_BUCKETS, + numberOfBuckets); +} + /** * @return True if any of the maps in this file contain a diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 329fb822b..60ef3da8d 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -315,6 +315,10 @@ namespace caret { const float mostNegativeValueInclusive, const bool includeZeroValues) = 0; + int32_t getFileHistogramNumberOfBuckets() const; + + void setFileHistogramNumberOfBuckets(const int32_t numberOfBuckets); + /** * Get the palette color mapping for the map at the given index. * diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 1ecc05769..1ee4da5ea 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -56,21 +56,23 @@ m_histogramContentType(histogramContentType) { m_sceneAssistant = new SceneClassAssistant(); + int32_t histogramNumberOfBuckets = 0; switch (m_histogramContentType) { case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: break; case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: + { + CaretMappableDataFile* cmdf = getCaretMappableDataFile(); + if (cmdf->getNumberOfMaps() > 0) { + const Histogram* histogram = cmdf->getMapHistogram(0); + if (histogram != NULL) { + histogramNumberOfBuckets = histogram->getNumberOfBuckets(); + } + } + } break; } - int32_t histogramNumberOfBuckets = 0; - CaretMappableDataFile* cmdf = getCaretMappableDataFile(); - if (cmdf->getNumberOfMaps() > 0) { - const Histogram* histogram = cmdf->getMapHistogram(0); - if (histogram != NULL) { - histogramNumberOfBuckets = histogram->getNumberOfBuckets(); - } - } updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram(histogramNumberOfBuckets)); } diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 479943859..8e8128b22 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1718,12 +1718,22 @@ CiftiMappableDataFile::getMapHistogram(const int32_t mapIndex) if (isMappedWithPalette()) { CaretAssertVectorIndex(m_mapContent, mapIndex); + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } - if ( ! m_mapContent[mapIndex]->isHistogramValid()) { + if ( ! m_mapContent[mapIndex]->isHistogramValid(numberOfBuckets)) { std::vector data; getMapData(mapIndex, data); - m_mapContent[mapIndex]->updateHistogram(data); + m_mapContent[mapIndex]->updateHistogram(numberOfBuckets, + data); } histogramOut = m_mapContent[mapIndex]->m_histogram; @@ -1766,7 +1776,17 @@ CiftiMappableDataFile::getMapHistogram(const int32_t mapIndex, if (isMappedWithPalette()) { CaretAssertVectorIndex(m_mapContent, mapIndex); - if ( ! m_mapContent[mapIndex]->isHistogramLimitedValuesValid(mostPositiveValueInclusive, + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } + if ( ! m_mapContent[mapIndex]->isHistogramLimitedValuesValid(numberOfBuckets, + mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, @@ -1774,7 +1794,8 @@ CiftiMappableDataFile::getMapHistogram(const int32_t mapIndex, std::vector data; getMapData(mapIndex, data); - m_mapContent[mapIndex]->updateHistogramLimitedValues(data, + m_mapContent[mapIndex]->updateHistogramLimitedValues(numberOfBuckets, + data, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, @@ -1843,13 +1864,28 @@ CiftiMappableDataFile::getFileFastStatistics() const Histogram* CiftiMappableDataFile::getFileHistogram() { - if (m_fileHistogram == NULL) { + bool updateHistogramFlag = false; + const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); + if (m_fileHistogram != NULL) { + if (numberOfBuckets != m_fileHistogramNumberOfBuckets) { + updateHistogramFlag = true; + } + } + else { + updateHistogramFlag = true; + } + if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); + if ( ! fileData.empty()) { - m_fileHistogram.grabNew(new Histogram()); - m_fileHistogram->update(&fileData[0], + if (m_fileHistogram == NULL) { + m_fileHistogram.grabNew(new Histogram(numberOfBuckets)); + } + m_fileHistogram->update(numberOfBuckets, + &fileData[0], fileData.size()); + m_fileHistogramNumberOfBuckets = numberOfBuckets; } } return m_fileHistogram; @@ -1882,8 +1918,10 @@ CiftiMappableDataFile::getFileHistogram(const float mostPositiveValueInclusive, const bool includeZeroValues) { bool updateHistogramFlag = false; + const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); if (m_fileHistorgramLimitedValues != NULL) { - if ((mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) + if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) + ||(mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) @@ -1902,7 +1940,8 @@ CiftiMappableDataFile::getFileHistogram(const float mostPositiveValueInclusive, if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } - m_fileHistorgramLimitedValues->update(&fileData[0], + m_fileHistorgramLimitedValues->update(numberOfBuckets, + &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, @@ -1910,6 +1949,7 @@ CiftiMappableDataFile::getFileHistogram(const float mostPositiveValueInclusive, mostNegativeValueInclusive, includeZeroValues); + m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; @@ -6889,32 +6929,41 @@ CiftiMappableDataFile::MapContent::updateFastStatistics(const std::vector } /** + * @param numberOfBuckets, + * Number of buckets in the histogram. * @return True if histogram is valid, else false. */ bool -CiftiMappableDataFile::MapContent::isHistogramValid() const +CiftiMappableDataFile::MapContent::isHistogramValid(const int32_t numberOfBuckets) const { - return (m_histogram != NULL); + return ((m_histogram != NULL) + && (m_histogramNumberOfBuckets == numberOfBuckets)); } /** * Update the Histogram but only when needed. * + * @param numberOfBuckets, + * Number of buckets in the histogram. * @param data * Data for histogram. */ void -CiftiMappableDataFile::MapContent::updateHistogram(const std::vector& data) +CiftiMappableDataFile::MapContent::updateHistogram(const int32_t numberOfBuckets, + const std::vector& data) { if (data.empty()) { m_histogram.grabNew(NULL); } else { + CaretAssert(m_paletteColorMapping); if (m_histogram == NULL) { - m_histogram.grabNew(new Histogram()); - m_histogram->update(&data[0], - data.size()); + m_histogram.grabNew(new Histogram(numberOfBuckets)); } + m_histogram->update(numberOfBuckets, + &data[0], + data.size()); + m_histogramNumberOfBuckets = numberOfBuckets; } } @@ -6922,6 +6971,8 @@ CiftiMappableDataFile::MapContent::updateHistogram(const std::vector& dat * Is limited values histogram valid? Is is valid when it exists and * the limited value parameters have not changed. * + * @param numberOfBuckets, + * Number of buckets in the histogram. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive @@ -6936,7 +6987,8 @@ CiftiMappableDataFile::MapContent::updateHistogram(const std::vector& dat * @return true if valid, else false. */ bool -CiftiMappableDataFile::MapContent::isHistogramLimitedValuesValid(const float mostPositiveValueInclusive, +CiftiMappableDataFile::MapContent::isHistogramLimitedValuesValid(const int32_t numberOfBuckets, + const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, @@ -6945,7 +6997,8 @@ CiftiMappableDataFile::MapContent::isHistogramLimitedValuesValid(const float mos if (m_histogramLimitedValues == NULL) { return false; } - else if ((mostPositiveValueInclusive != m_histogramLimitedValuesMostPositiveValueInclusive) + else if ((numberOfBuckets != m_histogramLimitedValuesNumberOfBuckets) + || (mostPositiveValueInclusive != m_histogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_histogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_histogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_histogramLimitedValuesMostNegativeValueInclusive) @@ -6973,7 +7026,8 @@ CiftiMappableDataFile::MapContent::isHistogramLimitedValuesValid(const float mos * If true zero values (very near zero) are included. */ void -CiftiMappableDataFile::MapContent::updateHistogramLimitedValues(const std::vector& data, +CiftiMappableDataFile::MapContent::updateHistogramLimitedValues(const int32_t numberOfBuckets, + const std::vector& data, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, @@ -6987,14 +7041,15 @@ CiftiMappableDataFile::MapContent::updateHistogramLimitedValues(const std::vecto if (m_histogramLimitedValues == NULL) { m_histogramLimitedValues.grabNew(new Histogram()); } - m_histogramLimitedValues->update(&data[0], + m_histogramLimitedValues->update(numberOfBuckets, + &data[0], data.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); - + m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index dcb2ac462..4150c08d6 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -552,17 +552,20 @@ namespace caret { void updateFastStatistics(const std::vector& data); - bool isHistogramValid() const; + bool isHistogramValid(const int32_t numberOfBuckets) const; - void updateHistogram(const std::vector& data); + void updateHistogram(const int32_t numberOfBuckets, + const std::vector& data); - bool isHistogramLimitedValuesValid(const float mostPositiveValueInclusive, + bool isHistogramLimitedValuesValid(const int32_t numberOfBuckets, + const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const; - void updateHistogramLimitedValues(const std::vector& data, + void updateHistogramLimitedValues(const int32_t numberOfBuckets, + const std::vector& data, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, @@ -618,9 +621,12 @@ namespace caret { /** histogram for all of map map */ CaretPointer m_histogram; + int32_t m_histogramNumberOfBuckets = 100; + /** histogram for limited values from map */ CaretPointer m_histogramLimitedValues; + int32_t m_histogramLimitedValuesNumberOfBuckets; float m_histogramLimitedValuesMostPositiveValueInclusive; float m_histogramLimitedValuesLeastPositiveValueInclusive; float m_histogramLimitedValuesLeastNegativeValueInclusive; @@ -732,9 +738,12 @@ namespace caret { /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; + int32_t m_fileHistogramNumberOfBuckets = 100; + /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; + int32_t m_fileHistogramLimitedValuesNumberOfBuckets = 100; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 73355552e..75ad31ac1 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -515,8 +515,18 @@ const FastStatistics* GiftiTypeFile::getMapFastStatistics(const int32_t mapIndex const Histogram* GiftiTypeFile::getMapHistogram(const int32_t mapIndex) { + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } + const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); - return gda->getHistogram(); + return gda->getHistogram(numberOfBuckets); } const Histogram* GiftiTypeFile::getMapHistogram(const int32_t mapIndex, @@ -526,9 +536,19 @@ const Histogram* GiftiTypeFile::getMapHistogram(const int32_t mapIndex, const float mostNegativeValueInclusive, const bool includeZeroValues) { + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); - return gda->getHistogram(mostPositiveValueInclusive, - leastPositiveValueInclusive, + return gda->getHistogram(numberOfBuckets, + mostPositiveValueInclusive, + leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); @@ -644,15 +664,32 @@ GiftiTypeFile::getFileFastStatistics() const Histogram* GiftiTypeFile::getFileHistogram() { - if (m_fileHistogram == NULL) { + const int32_t numBuckets = getFileHistogramNumberOfBuckets(); + bool updateHistogramFlag = false; + if (m_fileHistogram != NULL) { + if (numBuckets != m_histogramNumberOfBuckets) { + updateHistogramFlag = true; + } + } + else { + updateHistogramFlag = true; + + } + + if (updateHistogramFlag) { std::vector fileData; getFileDataFloat(fileData); if ( ! fileData.empty()) { - m_fileHistogram.grabNew(new Histogram()); - m_fileHistogram->update(&fileData[0], + if (m_fileHistogram == NULL) { + m_fileHistogram.grabNew(new Histogram(numBuckets)); + } + m_fileHistogram->update(numBuckets, + &fileData[0], fileData.size()); + m_histogramNumberOfBuckets = numBuckets; } } + return m_fileHistogram; } @@ -682,9 +719,11 @@ GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { + const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistorgramLimitedValues != NULL) { - if ((mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) + if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) + || (mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) @@ -703,7 +742,8 @@ GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } - m_fileHistorgramLimitedValues->update(&fileData[0], + m_fileHistorgramLimitedValues->update(numberOfBuckets, + &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, @@ -711,6 +751,7 @@ GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, mostNegativeValueInclusive, includeZeroValues); + m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; @@ -720,6 +761,45 @@ GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, } return m_fileHistorgramLimitedValues; +// bool updateHistogramFlag = false; +// if (m_fileHistorgramLimitedValues != NULL) { +// if ((mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) +// || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) +// || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) +// || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) +// || (includeZeroValues != m_fileHistogramLimitedValuesIncludeZeroValues)) { +// updateHistogramFlag = true; +// } +// } +// else { +// updateHistogramFlag = true; +// } +// +// if (updateHistogramFlag) { +// std::vector fileData; +// getFileDataFloat(fileData); +// if ( ! fileData.empty()) { +// if (m_fileHistorgramLimitedValues == NULL) { +// m_fileHistorgramLimitedValues.grabNew(new Histogram()); +// } +// m_fileHistorgramLimitedValues->update(getFileHistogramNumberOfBuckets(), +// &fileData[0], +// fileData.size(), +// mostPositiveValueInclusive, +// leastPositiveValueInclusive, +// leastNegativeValueInclusive, +// mostNegativeValueInclusive, +// includeZeroValues); +// +// m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; +// m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; +// m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; +// m_fileHistogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; +// m_fileHistogramLimitedValuesIncludeZeroValues = includeZeroValues; +// } +// } +// +// return m_fileHistorgramLimitedValues; } /** diff --git a/src/Files/GiftiTypeFile.h b/src/Files/GiftiTypeFile.h index 52e3b652f..574563428 100644 --- a/src/Files/GiftiTypeFile.h +++ b/src/Files/GiftiTypeFile.h @@ -176,9 +176,12 @@ namespace caret { /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; + int32_t m_histogramNumberOfBuckets = 100; + /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; + int32_t m_fileHistogramLimitedValuesNumberOfBuckets = 100; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 7d512e0c3..263d71a83 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -884,9 +884,31 @@ const Histogram* VolumeFile::getMapHistogram(const int32_t mapIndex) CaretAssertVectorIndex(m_brickAttributes, mapIndex); checkStatisticsValid(); const int64_t* dimensions = getDimensionsPtr(); + + bool updateHistogramFlag = false; + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } if (m_brickAttributes[mapIndex].m_histogram == NULL) { - m_brickAttributes[mapIndex].m_histogram.grabNew(new Histogram(100, getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2])); + m_brickAttributes[mapIndex].m_histogram.grabNew(new Histogram(numberOfBuckets)); + updateHistogramFlag = true; + } + else if (numberOfBuckets != m_brickAttributes[mapIndex].m_histogramNumberOfBuckets) + { + updateHistogramFlag = true; + } + + if (updateHistogramFlag) + { + m_brickAttributes[mapIndex].m_histogram->update(numberOfBuckets, getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2]); + m_brickAttributes[mapIndex].m_histogramNumberOfBuckets = numberOfBuckets; } return m_brickAttributes[mapIndex].m_histogram; } @@ -921,12 +943,22 @@ VolumeFile::getMapHistogram(const int32_t mapIndex, bool updateHistogramFlag = false; + int32_t numberOfBuckets = 0; + switch (getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + numberOfBuckets = getFileHistogramNumberOfBuckets(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); + break; + } if (m_brickAttributes[mapIndex].m_histogramLimitedValues == NULL) { m_brickAttributes[mapIndex].m_histogramLimitedValues.grabNew(new Histogram(100)); updateHistogramFlag = true; } - else if ((mostPositiveValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesMostPositiveValueInclusive) + else if ((numberOfBuckets != m_brickAttributes[mapIndex].m_histogramLimitedValuesNumberOfBuckets) + || (mostPositiveValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesMostNegativeValueInclusive) @@ -935,13 +967,15 @@ VolumeFile::getMapHistogram(const int32_t mapIndex, } if (updateHistogramFlag) { - m_brickAttributes[mapIndex].m_histogramLimitedValues->update(getFrame(mapIndex), + m_brickAttributes[mapIndex].m_histogramLimitedValues->update(numberOfBuckets, + getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2], mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); + m_brickAttributes[mapIndex].m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_brickAttributes[mapIndex].m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; @@ -1009,15 +1043,32 @@ VolumeFile::getFileFastStatistics() const Histogram* VolumeFile::getFileHistogram() { - if (m_fileHistogram == NULL) { + const int32_t numBuckets = getFileHistogramNumberOfBuckets(); + bool updateHistogramFlag = false; + if (m_fileHistogram != NULL) { + if (numBuckets != m_fileHistogramNumberOfBuckets) { + updateHistogramFlag = true; + } + } + else { + updateHistogramFlag = true; + + } + + if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { - m_fileHistogram.grabNew(new Histogram()); - m_fileHistogram->update(&fileData[0], + if (m_fileHistogram == NULL) { + m_fileHistogram.grabNew(new Histogram(numBuckets)); + } + m_fileHistogram->update(numBuckets, + &fileData[0], fileData.size()); + m_fileHistogramNumberOfBuckets = numBuckets; } } + return m_fileHistogram; } @@ -1047,9 +1098,11 @@ VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { + const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistorgramLimitedValues != NULL) { - if ((mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) + if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) + || (mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) @@ -1068,7 +1121,8 @@ VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } - m_fileHistorgramLimitedValues->update(&fileData[0], + m_fileHistorgramLimitedValues->update(numberOfBuckets, + &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, @@ -1076,6 +1130,7 @@ VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, mostNegativeValueInclusive, includeZeroValues); + m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index 5a745baa4..80ead28f9 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -62,7 +62,9 @@ namespace caret { {//TODO: prune this once statistics gets straightened out CaretPointer m_fastStatistics; CaretPointer m_histogram; + int32_t m_histogramNumberOfBuckets = 100; CaretPointer m_histogramLimitedValues; + int32_t m_histogramLimitedValuesNumberOfBuckets = 100; float m_histogramLimitedValuesMostPositiveValueInclusive; float m_histogramLimitedValuesLeastPositiveValueInclusive; float m_histogramLimitedValuesLeastNegativeValueInclusive; @@ -80,9 +82,12 @@ namespace caret { /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; + int32_t m_fileHistogramNumberOfBuckets = 100; + /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; + int32_t m_fileHistogramLimitedValuesNumberOfBuckets; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; diff --git a/src/FilesBase/GiftiMetaDataXmlElements.h b/src/FilesBase/GiftiMetaDataXmlElements.h index cbe4d01b6..b468aa7f0 100644 --- a/src/FilesBase/GiftiMetaDataXmlElements.h +++ b/src/FilesBase/GiftiMetaDataXmlElements.h @@ -208,6 +208,9 @@ namespace GiftiMetaDataXmlElements { /** name of palette normalization mode */ static const AString METADATA_PALETTE_NORMALIZATION_MODE = "PaletteNormalizationMode"; + + /** name of histogram number of buckets */ + static const AString HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; } // namespace diff --git a/src/Gifti/GiftiDataArray.cxx b/src/Gifti/GiftiDataArray.cxx index d5fb7b1b9..f38635da0 100644 --- a/src/Gifti/GiftiDataArray.cxx +++ b/src/Gifti/GiftiDataArray.cxx @@ -1723,13 +1723,21 @@ const FastStatistics* GiftiDataArray::getFastStatistics() const return m_fastStatistics; } -const Histogram* GiftiDataArray::getHistogram() const +const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { + bool updateHistogramFlag = false; if (m_histogram == NULL) { - m_histogram.grabNew(new Histogram(100)); + m_histogram.grabNew(new Histogram(numberOfBuckets)); + updateHistogramFlag = true; + } + else if (numberOfBuckets != m_histogramNumberOfBuckets) { + updateHistogramFlag = true; + } + if (updateHistogramFlag) { + m_histogram->update(numberOfBuckets, dataPointerFloat, getTotalNumberOfElements()); + m_histogramNumberOfBuckets = numberOfBuckets; } - m_histogram->update(dataPointerFloat, getTotalNumberOfElements()); } return m_histogram; } @@ -1772,23 +1780,43 @@ GiftiDataArray::getDescriptiveStatistics(const float mostPositiveValueInclusive, return this->descriptiveStatisticsLimitedValues; } -const Histogram* GiftiDataArray::getHistogram(const float mostPositiveValueInclusive, +const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets, + const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { + bool updateHistogramFlag = false; if (m_histogramLimitedValues == NULL) { - m_histogramLimitedValues.grabNew(new Histogram(100)); + m_histogramLimitedValues.grabNew(new Histogram(numberOfBuckets)); + updateHistogramFlag = true; + } + else if ((numberOfBuckets != m_histogramLimitedValuesNumberOfBuckets) + || (mostPositiveValueInclusive != m_histogramLimitedValuesMostPositiveValueInclusive) + || (leastPositiveValueInclusive != m_histogramLimitedValuesLeastPositiveValueInclusive) + || (leastNegativeValueInclusive != m_histogramLimitedValuesLeastNegativeValueInclusive) + || (mostNegativeValueInclusive != m_histogramLimitedValuesMostNegativeValueInclusive) + || (includeZeroValues != m_histogramLimitedValuesIncludeZeroValues)) { + updateHistogramFlag = true; + } + if (updateHistogramFlag) { + m_histogramLimitedValues->update(numberOfBuckets, + dataPointerFloat, getTotalNumberOfElements(), + mostPositiveValueInclusive, + leastPositiveValueInclusive, + leastNegativeValueInclusive, + mostNegativeValueInclusive, + includeZeroValues); + m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; + m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; + m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; + m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; + m_histogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; + m_histogramLimitedValuesIncludeZeroValues = includeZeroValues; } - m_histogramLimitedValues->update(dataPointerFloat, getTotalNumberOfElements(), - mostPositiveValueInclusive, - leastPositiveValueInclusive, - leastNegativeValueInclusive, - mostNegativeValueInclusive, - includeZeroValues); } return m_histogramLimitedValues; } diff --git a/src/Gifti/GiftiDataArray.h b/src/Gifti/GiftiDataArray.h index 8666c01a2..e6898e4d3 100644 --- a/src/Gifti/GiftiDataArray.h +++ b/src/Gifti/GiftiDataArray.h @@ -289,7 +289,7 @@ namespace caret { const FastStatistics* getFastStatistics() const; - const Histogram* getHistogram() const; + const Histogram* getHistogram(const int32_t numberOfBuckets) const; const DescriptiveStatistics* getDescriptiveStatistics(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, @@ -297,7 +297,8 @@ namespace caret { const float mostNegativeValueInclusive, const bool includeZeroValues) const; - const Histogram* getHistogram(const float mostPositiveValueInclusive, + const Histogram* getHistogram(const int32_t numberOfBuckets, + const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, @@ -410,11 +411,19 @@ namespace caret { mutable CaretPointer m_fastStatistics; mutable CaretPointer m_histogram; + mutable int32_t m_histogramNumberOfBuckets = 100; + + mutable CaretPointer m_histogramLimitedValues; + mutable int32_t m_histogramLimitedValuesNumberOfBuckets = 100; + mutable float m_histogramLimitedValuesMostPositiveValueInclusive; + mutable float m_histogramLimitedValuesLeastPositiveValueInclusive; + mutable float m_histogramLimitedValuesLeastNegativeValueInclusive; + mutable float m_histogramLimitedValuesMostNegativeValueInclusive; + mutable bool m_histogramLimitedValuesIncludeZeroValues; /// statistics about data (DO NOT COPY) mutable DescriptiveStatistics* descriptiveStatisticsLimitedValues; - mutable CaretPointer m_histogramLimitedValues; bool modifiedFlag; // DO NOT COPY // ***** BE SURE TO UPDATE copyHelper() if elements are added ****** diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 02beea99f..3cf427919 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -1638,11 +1638,11 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); - //m_histogramBucketsSpinBox->setValue(this->caretMappableDataFile->getFile); + m_histogramBucketsSpinBox->setValue(this->caretMappableDataFile->getFileHistogramNumberOfBuckets()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); - //m_histogramBucketsSpinBox->setValue(this->paletteColorMapping->getHistogramNumberOfBuckets()); + m_histogramBucketsSpinBox->setValue(this->paletteColorMapping->getHistogramNumberOfBuckets()); break; } m_histogramBucketsSpinBox->blockSignals(false); @@ -2200,7 +2200,14 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramChartType(m_histogramChartTypeComboBox->getSelectedItem()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); -// this->paletteColorMapping->setHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); + switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + this->caretMappableDataFile->setFileHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + this->paletteColorMapping->setHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); + break; + } float lowValue = this->thresholdLowSpinBox->value(); float highValue = this->thresholdHighSpinBox->value(); diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index b9980e24e..cf4d1175f 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -137,6 +137,7 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->histogramRangeMode = pcm.histogramRangeMode; this->histogramChartType = pcm.histogramChartType; this->histogramColor = pcm.histogramColor; + this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; this->colorBarPrecisionDigits = pcm.colorBarPrecisionDigits; this->colorBarNumericSubdivisionCount = pcm.colorBarNumericSubdivisionCount; @@ -187,6 +188,7 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->histogramRangeMode == pcm.histogramRangeMode) && (this->histogramChartType == pcm.histogramChartType) && (this->histogramColor == pcm.histogramColor) + && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets) && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) && (this->colorBarPrecisionDigits == pcm.colorBarPrecisionDigits) && (this->colorBarNumericSubdivisionCount == pcm.colorBarNumericSubdivisionCount) @@ -234,6 +236,7 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; this->histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette + this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; this->colorBarPrecisionDigits = 2; this->colorBarNumericSubdivisionCount = 0; @@ -356,6 +359,8 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) PaletteHistogramChartTypeEnum::toName(this->histogramChartType)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, CaretColorEnum::toName(this->histogramColor)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS, + this->histogramNumberOfBuckets); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, NumericFormatModeEnum::toName(this->colorBarNumericFormatMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS, @@ -2799,6 +2804,30 @@ PaletteColorMapping::setHistogramColor(const CaretColorEnum::Enum histogramColor } } +/** + * @return Histogram number of buckets. + */ +int32_t +PaletteColorMapping::getHistogramNumberOfBuckets() const +{ + return this->histogramNumberOfBuckets; +} + +/** + * Set the histogram number of buckets. + * + * @param histogramNumberOfBuckets + * Number of buckets for the histogram. + */ +void +PaletteColorMapping::setHistogramNumberOfBuckets(const int32_t histogramNumberOfBuckets) +{ + if (histogramNumberOfBuckets != this->histogramNumberOfBuckets) { + this->histogramNumberOfBuckets = histogramNumberOfBuckets; + setModified(); + } +} + /** * @return The color bar numeric format mode. */ diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 174a0ae96..7048e6729 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -221,6 +221,10 @@ namespace caret { void setHistogramColor(const CaretColorEnum::Enum histogramColor); + int32_t getHistogramNumberOfBuckets() const; + + void setHistogramNumberOfBuckets(const int32_t histogramNumberOfBuckets); + NumericFormatModeEnum::Enum getColorBarNumericFormatMode() const; int32_t getColorBarPrecisionDigits() const; @@ -327,6 +331,8 @@ namespace caret { CaretColorEnum::Enum histogramColor; + int32_t histogramNumberOfBuckets; + NumericFormatModeEnum::Enum colorBarNumericFormatMode; int32_t colorBarPrecisionDigits; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 1e9df5387..12604cbc9 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -336,6 +336,9 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, + this->elementText); } } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS) { + this->paletteColorMapping->setHistogramNumberOfBuckets(this->elementText.toInt()); + } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE) { bool isValid = false; NumericFormatModeEnum::Enum numericFormatMode = NumericFormatModeEnum::fromName(this->elementText, diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index a2ba5be19..ea64bec6f 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -48,6 +48,7 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; static const AString XML_TAG_HISTOGRAM_CHART_TYPE = "HistogramChartType"; static const AString XML_TAG_HISTOGRAM_COLOR = "HistogramColor"; + static const AString XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; static const AString XML_TAG_NUMERIC_SUBDIVISIONS = "NumericSubivisions"; -- GitLab From 7183c080bc13cc2cce87a508d07fa9b162023112 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 13 Mar 2017 15:19:01 -0500 Subject: [PATCH 218/755] Correct spelling of "Verify" in Scene Options on the Scene Dialog. --- src/GuiQt/SceneDialog.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index f1aeb6ee2..d72824c8d 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -347,6 +347,7 @@ SceneDialog::updateSceneFileComboBoxModifiedIcons() } m_sceneFileSelectionComboBox->blockSignals(false); + /* comment */ } /** -- GitLab From fb7cbd20f519e40266b916508d62d2964798efa8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Mar 2017 12:14:44 -0500 Subject: [PATCH 219/755] Changed text for coloring histogram with palette --- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 3cf427919..3450858b0 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -743,7 +743,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() this->m_histogramHorizontalRangeComboBox->getWidget()->setToolTip("Horizontal range of histogram"); QLabel* colorLabel = new QLabel("Color"); - m_histogramColorComboBox = new CaretColorEnumComboBox("Palette", + m_histogramColorComboBox = new CaretColorEnumComboBox("With Palette", this); WuQtUtilities::setToolTipAndStatusTip(m_histogramColorComboBox->getWidget(), "Set histogram coloring"); -- GitLab From 877551b9c9dc0da3afd0429a66b66d34ffc21634 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Mar 2017 12:16:17 -0500 Subject: [PATCH 220/755] Fixed restoration of a scene containing a histogram. The charts were only created when a file was loaded and since scenes try to avoid reloading files, the charts need to be recreated when restoring scene to the data file. --- src/Files/CaretMappableDataFile.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 886054da5..9f5668c21 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -403,6 +403,14 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr m_labelDrawingProperties->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelDrawingProperties")); + const SceneClass* chartingDelegateClass = sceneClass->getClass("m_chartingDelegate"); + m_chartingDelegate.reset(); + if (chartingDelegateClass != NULL) { + ChartableTwoFileDelegate* chartingDelegate = getChartingDelegate(); // creates charting delegate if not valid + chartingDelegate->updateAfterFileChanged(); + chartingDelegate->restoreFromScene(sceneAttributes, + chartingDelegateClass); + } if (isMappedWithPalette()) { /* -- GitLab From 04757e9f1c9815276b018a98b2b5b586dd4a112a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Mar 2017 15:54:07 -0500 Subject: [PATCH 221/755] Improvement of histogram chart drawing including: Tick position improved so no gaps at histogram region box and axis name no longer overlaps axis numerical values. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 135 +++++++++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 2 + 2 files changed, 118 insertions(+), 19 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index e533bf979..bc48d58fa 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -265,12 +265,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() /* * Get the histogram drawing information and overall extent */ - float xMin = std::numeric_limits::max();; - float xMax = -std::numeric_limits::max();; + float xMin = std::numeric_limits::max(); + float xMax = -std::numeric_limits::max(); float yMinLeft = std::numeric_limits::max(); - float yMaxLeft = -std::numeric_limits::max();; - float yMinRight = std::numeric_limits::max();; - float yMaxRight = -std::numeric_limits::max();; + float yMaxLeft = -std::numeric_limits::max(); + float yMinRight = std::numeric_limits::max(); + float yMaxRight = -std::numeric_limits::max(); for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -344,7 +344,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. */ - const double marginSize = 30; + const double marginSize = 10; Margins margins(marginSize); ChartTwoCartesianAxis* leftAxis = m_chartOverlaySet->getChartAxisLeft(); @@ -1761,6 +1761,46 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH heightOut = std::max(heightOut, textHeight); } } + + const AString labelText = cartesianAxis->getLabelText(); + if ( ! labelText.isEmpty()) { + AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setText(labelText); + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + break; + } + + double textWidth = 0.0; + double textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); + + const float verticalOffset = 4; // adds space between scale values and label + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + heightOut += (textHeight + verticalOffset); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + widthOut += textWidth; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + widthOut += textWidth; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + heightOut += (textHeight + verticalOffset); + break; + } + } } /** @@ -1788,9 +1828,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const Margins& margins, int32_t chartGraphicsDrawingViewportOut[4]) { - - const float gridLineWidth = 2; - const float halfGridLineWidth = gridLineWidth / 2.0; + const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; const float gridLeft = vpX + margins.m_left; const float gridRight = vpX + vpWidth - margins.m_right; @@ -1811,7 +1849,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glLineWidth(gridLineWidth); + glLineWidth(GRID_LINE_WIDTH); glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); @@ -1838,10 +1876,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons /* * Region inside the grid's box */ - const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(gridLineWidth + 1.0)); - const int32_t graphicsRight = static_cast(gridRight - std::floor(gridLineWidth + 1.0)); - const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(gridLineWidth + 1.0)); - const int32_t graphicsTop = static_cast(gridTop - std::floor(gridLineWidth + 1.0)); + const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(GRID_LINE_WIDTH + 1.0)); + const int32_t graphicsRight = static_cast(gridRight - std::floor(GRID_LINE_WIDTH + 1.0)); + const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(GRID_LINE_WIDTH + 1.0)); + const int32_t graphicsTop = static_cast(gridTop - std::floor(GRID_LINE_WIDTH + 1.0)); const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; @@ -2032,14 +2070,73 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const bool showTicksFlag = axis->isShowTickmarks(); + const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; + const int32_t firstIndex = 0; + const int32_t lastIndex = numLabelsToDraw - 1; for (int32_t i = 0; i < numLabelsToDraw; i++) { - const float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; - const float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; - + float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; + float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; + float textOffsetX = 0.0; + float textOffsetY = 0.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + if (i == firstIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + tickStartX += halfGridLineWidth; + } + else if (i == lastIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + tickStartX -= halfGridLineWidth; + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + tickStartX -= halfGridLineWidth; + if (i == firstIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + tickStartY += halfGridLineWidth; + } + else if (i == lastIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + tickStartY -= halfGridLineWidth; + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + tickStartX += halfGridLineWidth; + if (i == firstIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + tickStartY += halfGridLineWidth; + } + else if (i == lastIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + tickStartY -= halfGridLineWidth; + } + textOffsetX = -2.0; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + if (i == firstIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + tickStartX += halfGridLineWidth; + } + else if (i == lastIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + tickStartX -= halfGridLineWidth; + } + textOffsetY = -2.0; + break; + } const float tickEndX = tickStartX + tickDeltaXY[0]; const float tickEndY = tickStartY + tickDeltaXY[1]; if (showTicksFlag) { + glLineWidth(GRID_LINE_WIDTH); glBegin(GL_LINES); glVertex2f(tickStartX, tickStartY); @@ -2048,8 +2145,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data glEnd(); } - const float textX = tickEndX; - const float textY = tickEndY; + const float textX = tickEndX + textOffsetX; + const float textY = tickEndY + textOffsetY; annotationText.setText(labelTexts[i]); m_textRenderer->drawTextAtViewportCoords(textX, textY, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 5995987b7..457aa1a8d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -171,6 +171,8 @@ namespace caret { SelectionItemChartTwoMatrix* m_selectionItemMatrix; + const float GRID_LINE_WIDTH = 2.0; + bool m_identificationModeFlag; static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; -- GitLab From 1fb747b6b89027e9a9e48406f7e54bacd6f5e6f0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Mar 2017 16:07:18 -0500 Subject: [PATCH 222/755] Fix missing description for charting content in auto-generated scene description. --- src/Brain/BrowserTabContent.cxx | 18 +++++++++++++----- src/Charting/ChartTwoCompoundDataType.cxx | 8 ++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index fb57d597c..dbb3a42e5 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -418,15 +418,17 @@ BrowserTabContent::getDescriptionOfContent(PlainTextStringBuilder& descriptionOu const Model* model = getModelForDisplay(); if (model != NULL) { - bool chartFlag = false; - bool surfaceFlag = false; + bool chartOneFlag = false; + bool chartTwoFlag = false; + bool surfaceFlag = false; bool surfaceMontageFlag = false; bool wholeBrainFlag = false; bool volumeFlag = false; switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: + chartOneFlag = true; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: - chartFlag = true; + chartTwoFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; @@ -444,7 +446,7 @@ BrowserTabContent::getDescriptionOfContent(PlainTextStringBuilder& descriptionOu break; } - if (chartFlag) { + if (chartOneFlag) { model->getDescriptionOfContent(tabIndex, descriptionOut); } @@ -496,7 +498,13 @@ BrowserTabContent::getDescriptionOfContent(PlainTextStringBuilder& descriptionOu descriptionOut.popIndentation(); } - if ( ! chartFlag) { + if (chartOneFlag) { + /* nothing */ + } + else if (chartTwoFlag) { + getChartTwoOverlaySet()->getDescriptionOfContent(descriptionOut); + } + else { getOverlaySet()->getDescriptionOfContent(descriptionOut); } } diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index cde21c664..a29935384 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -330,15 +330,15 @@ ChartTwoCompoundDataType::toString() const { const AString indent = " "; AString text = ("type=" - + ChartTwoDataTypeEnum::toName(m_chartDataType)); + + ChartTwoDataTypeEnum::toGuiName(m_chartDataType)); switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - text.appendWithNewLine(indent - + "buckets=" - + QString::number(m_histogramNumberOfBuckets)); + //text.appendWithNewLine(indent + // + "buckets=" + // + QString::number(m_histogramNumberOfBuckets)); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: text.appendWithNewLine(indent -- GitLab From 20e36525da718324ea33daf736816cca83db7be8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 15 Mar 2017 16:04:58 -0500 Subject: [PATCH 223/755] Continuing charting development. Updates and fixes for saving and restoring scenes for both new histogram and matrix charts. --- src/Brain/ChartTwoOverlay.cxx | 208 +++++++++++++++++++++++++ src/Brain/ChartTwoOverlaySet.cxx | 2 + src/Brain/ChartTwoOverlaySetArray.cxx | 61 ++++++-- src/Brain/ModelChartTwo.cxx | 4 +- src/Files/ChartableTwoFileDelegate.cxx | 7 +- src/Scenes/SceneClassAssistant.h | 3 + 6 files changed, 266 insertions(+), 19 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 4105e133d..1e0d538f3 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -1161,6 +1161,41 @@ ChartTwoOverlay::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); + std::vector mapFiles; + CaretMappableDataFile* selectedMapFile = NULL; + //AString selectedMapUniqueID; + int32_t selectedMapIndex; + getSelectionData(mapFiles, + selectedMapFile, + selectedMapIndex); + + AString sceneSelectedMapFileNameWithPath; + AString sceneSelectedMapFileNameNoPath; + AString sceneSelectedMapName; + int32_t sceneSelectedMapIndex = selectedMapIndex; + + /* + * NOTE:Some of the connectivity matrix files may not have a valid + * selection index (-1) until the user identifies a brainordinate + */ + if (selectedMapFile != NULL) { + sceneSelectedMapFileNameWithPath = selectedMapFile->getFileName(); + sceneSelectedMapFileNameNoPath = selectedMapFile->getFileNameNoPath(); + if ((selectedMapIndex >= 0) + && (selectedMapIndex < selectedMapFile->getNumberOfMaps())) { + sceneSelectedMapName = selectedMapFile->getMapName(selectedMapIndex); + } + } + + sceneClass->addPathName("sceneSelectedMapFileNameWithPath", + sceneSelectedMapFileNameWithPath); + sceneClass->addString("sceneSelectedMapFileNameNoPath", + sceneSelectedMapFileNameNoPath); + sceneClass->addString("sceneSelectedMapName", + sceneSelectedMapName); + sceneClass->addInteger("sceneSelectedMapIndex", + sceneSelectedMapIndex); + // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); @@ -1190,6 +1225,179 @@ ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + /* + * Making a call to getSelectionData() to get the availble + * map files + */ + std::vector mapFiles; + CaretMappableDataFile* unusedSelectedMapFile = NULL; + int32_t unusedSelectedMapIndex; + getSelectionData(mapFiles, + unusedSelectedMapFile, + unusedSelectedMapIndex); + + const AString selectedMapFileNameWithPath = sceneClass->getPathNameValue("sceneSelectedMapFileNameWithPath"); + + const AString selectedMapFileName = sceneClass->getStringValue("sceneSelectedMapFileNameNoPath", + ""); + const AString selectedMapName = sceneClass->getStringValue("sceneSelectedMapName", + ""); + const int32_t selectedMapIndex = sceneClass->getIntegerValue("sceneSelectedMapIndex", + -1); + + bool found = false; + + /* + * Is used when the file is found but a map is not matched + */ + CaretMappableDataFile* matchedMapFile = NULL; + + /* + * First try to find file by filename INCLUDING path and map by unique ID + */ + + /* + * Find map by unique ID, map index, and map file + */ + CaretMappableDataFile* foundMapNameFile = NULL; + int32_t foundMapNameIndex = -1; + CaretMappableDataFile* foundMapIndexFile = NULL; + int32_t foundMapIndex = -1; + + /* + * Try to match files twice. First time by name with path, then + * by name without path. + */ + for (int iTries = 0; iTries < 2; iTries++) { + for (std::vector::iterator iter = mapFiles.begin(); + iter != mapFiles.end(); + iter++) { + CaretMappableDataFile* mapFile = *iter; + + bool testIt = false; + switch (iTries) { + case 0: { + const AString fileName = mapFile->getFileName(); + if (fileName == selectedMapFileNameWithPath) { + testIt = true; + } + } + break; + + case 1: { + const AString fileName = mapFile->getFileNameNoPath(); + if (fileName == selectedMapFileName) { + testIt = true; + } + } + break; + } + + + if (testIt) { + CaretMappableDataFile* mapFile = *iter; + matchedMapFile = mapFile; + + if (foundMapNameIndex < 0) { + if ( ! selectedMapName.isEmpty()) { + const int mapNameIndex = mapFile->getMapIndexFromName(selectedMapName); + if (mapNameIndex >= 0) { + foundMapNameFile = mapFile; + foundMapNameIndex = mapNameIndex; + } + } + + } + + if (foundMapIndex < 0) { + if (selectedMapIndex >= 0) { + if (selectedMapIndex < mapFile->getNumberOfMaps()) { + foundMapIndexFile = mapFile; + foundMapIndex = selectedMapIndex; + } + } + } + } + } + } + + if (! found) { + if (foundMapIndex >= 0) { + if (foundMapIndexFile != NULL) { + setSelectionData(foundMapIndexFile, + foundMapIndex); + found = true; + } + } + } + + if (! found) { + if (foundMapNameIndex >= 0) { + if (foundMapNameFile != NULL) { + setSelectionData(foundMapNameFile, + foundMapNameIndex); + found = true; + } + } + } + + if ( ! found) { + /* + * If not found by unique ID, try to find map by name + */ + if ( ! selectedMapName.isEmpty()) { + for (std::vector::iterator iter = mapFiles.begin(); + iter != mapFiles.end(); + iter++) { + CaretMappableDataFile* mapFile = *iter; + const AString fileName = mapFile->getFileNameNoPath(); + if (fileName == selectedMapFileName) { + CaretMappableDataFile* mapFile = *iter; + matchedMapFile = mapFile; + + const int32_t mapIndex = mapFile->getMapIndexFromName(selectedMapName); + if (mapIndex >= 0) { + setSelectionData(mapFile, + mapIndex); + found = true; + break; + } + } + } + } + } + + /* + * NOTE:Some of the connectivity matrix files may not have a valid + * selection index (-1) until the user identifies a brainordinate + */ + if ( ! found) { + if (matchedMapFile != NULL) { + if (matchedMapFile->getNumberOfMaps() > 0) { + int32_t defaultMapIndex = -1; + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + defaultMapIndex = 0; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + defaultMapIndex = 0; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + setSelectionData(matchedMapFile, + defaultMapIndex); + } + } + } + + + + + + //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 312999c40..99a7a5535 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -31,6 +31,8 @@ #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" +#include "SceneObjectMapIntegerKey.h" + using namespace caret; diff --git a/src/Brain/ChartTwoOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx index 1fff094b6..7fbe0a804 100644 --- a/src/Brain/ChartTwoOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -28,6 +28,7 @@ #include "ChartTwoOverlaySet.h" #include "EventBrowserTabDelete.h" #include "EventManager.h" +#include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" using namespace caret; @@ -195,17 +196,34 @@ ChartTwoOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, "ChartTwoOverlaySetArray", 1); - const int32_t numOverlaySetsToSave = getNumberOfChartOverlaySets(); + std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); - std::vector overlaySetVector; - for (int i = 0; i < numOverlaySetsToSave; i++) { - overlaySetVector.push_back(m_chartOverlaySets[i]->saveToScene(sceneAttributes, - "m_chartOverlaySet")); + /* + * Save overlay sets for tabs + */ + SceneObjectMapIntegerKey* overlaySetMap = new SceneObjectMapIntegerKey("m_chartOverlaySetMAP", + SceneObjectDataTypeEnum::SCENE_CLASS); + + for (const auto tabIndex : tabIndices) { + overlaySetMap->addClass(tabIndex, m_chartOverlaySets[tabIndex]->saveToScene(sceneAttributes, + "m_chartOverlaySet")); } + sceneClass->addChild(overlaySetMap); + + + - SceneClassArray* overlaySetArray = new SceneClassArray("m_chartOverlaySets", - overlaySetVector); - sceneClass->addChild(overlaySetArray); +// const int32_t numOverlaySetsToSave = getNumberOfChartOverlaySets(); +// +// std::vector overlaySetVector; +// for (int i = 0; i < numOverlaySetsToSave; i++) { +// overlaySetVector.push_back(m_chartOverlaySets[i]->saveToScene(sceneAttributes, +// "m_chartOverlaySet")); +// } +// +// SceneClassArray* overlaySetArray = new SceneClassArray("m_chartOverlaySets", +// overlaySetVector); +// sceneClass->addChild(overlaySetArray); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, @@ -233,16 +251,27 @@ ChartTwoOverlaySetArray::restoreFromScene(const SceneAttributes* sceneAttributes return; } - - const SceneClassArray* overlaySetArray = sceneClass->getClassArray("m_chartOverlaySets"); - if (overlaySetArray != NULL) { - const int32_t numOverlaySets = std::min(overlaySetArray->getNumberOfArrayElements(), - (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); - for (int32_t i = 0; i < numOverlaySets; i++) { - m_chartOverlaySets[i]->restoreFromScene(sceneAttributes, - overlaySetArray->getClassAtIndex(i)); + const SceneObjectMapIntegerKey* overlaySetMap = sceneClass->getMapIntegerKey("m_chartOverlaySetMAP"); + if (overlaySetMap != NULL) { + const std::vector tabIndices = overlaySetMap->getKeys(); + for (const auto tabIndex : tabIndices) { + const SceneClass* sceneClass = overlaySetMap->classValue(tabIndex); + CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); + m_chartOverlaySets[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); } } + + +// const SceneClassArray* overlaySetArray = sceneClass->getClassArray("m_chartOverlaySets"); +// if (overlaySetArray != NULL) { +// const int32_t numOverlaySets = std::min(overlaySetArray->getNumberOfArrayElements(), +// (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); +// for (int32_t i = 0; i < numOverlaySets; i++) { +// m_chartOverlaySets[i]->restoreFromScene(sceneAttributes, +// overlaySetArray->getClassAtIndex(i)); +// } +// } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 32600eec0..6f5bbe4a0 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -703,8 +703,8 @@ ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAtt const std::vector tabIndices = matrixPropsMap->getKeys(); for (const int32_t tabIndex : tabIndices) { const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); - //m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, - // sceneClass); + m_chartTwoMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, + sceneClass); } } diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index c745de05b..1c38ad760 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -594,11 +594,16 @@ ChartableTwoFileDelegate::saveToScene(const SceneAttributes* sceneAttributes, if (m_histogramCharting != NULL) { sceneClass->addClass(m_histogramCharting->saveToScene(sceneAttributes, "m_histogramCharting")); + } + if (m_lineSeriesCharting != NULL) { sceneClass->addClass(m_lineSeriesCharting->saveToScene(sceneAttributes, "m_lineSeriesCharting")); + } + if (m_matrixCharting != NULL) { sceneClass->addClass(m_matrixCharting->saveToScene(sceneAttributes, - "m_matrixCharting")); + "m_matrixCharting")); } + return sceneClass; } diff --git a/src/Scenes/SceneClassAssistant.h b/src/Scenes/SceneClassAssistant.h index 70f15c82b..35c835cf3 100644 --- a/src/Scenes/SceneClassAssistant.h +++ b/src/Scenes/SceneClassAssistant.h @@ -185,6 +185,9 @@ namespace caret { const SceneClass& sceneClass) = 0; virtual void save(const SceneAttributes& sceneAttributes, SceneClass& sceneClass) = 0; + + AString getName() const { return m_name; } + protected: const AString m_name; -- GitLab From 90ccec74abf3299c44f462e8adc65c386d64eb5c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Mar 2017 10:07:01 -0500 Subject: [PATCH 224/755] Continuing charting development. When a scene is restored that contains "version one charts" but no "version two charts", load the "version one chart" data into the "version two chart" data (as much as possible). This has been added for matrix charts. --- src/Brain/Brain.cxx | 26 ++++- src/Brain/Brain.h | 2 + src/Brain/BrowserTabContent.cxx | 26 +++-- src/Brain/Model.cxx | 23 ++++ src/Brain/Model.h | 6 ++ src/Brain/ModelChart.h | 2 + src/Brain/ModelChartTwo.cxx | 183 ++++++++++++++++++++++++++++++++ src/Brain/ModelChartTwo.h | 7 ++ src/Brain/SessionManager.cxx | 4 + 9 files changed, 268 insertions(+), 11 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index fee9cb1e5..f605b1bf7 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -7200,6 +7200,9 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, EventModelGetAll getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); std::vector allModels = getAllModels.getModels(); + for (auto model : allModels) { + model->setRestoredFromScene(false); + } const SceneClassArray* modelsClassArray = sceneClass->getClassArray("models"); const int32_t numModelClasses = modelsClassArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numModelClasses; i++) { @@ -7211,7 +7214,7 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, iter != allModels.end(); iter++) { Model* mdc = *iter; - mdc->restoreFromScene(sceneAttributes, + mdc->restoreFromScene(sceneAttributes, modelsClassArray->getClassAtIndex(i)); } } @@ -7279,6 +7282,27 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAnnotationFile->clearModified(); } +/** + * If model one charts are in scene but not + * model two charts, attempt to restore model + * one charts to model two charts. + * + * This must be performed AFTER browser tabs + * have been restored by the SessionManager. + */ +void +Brain::restoreModelChartOneToModelChartTwo() +{ + CaretAssert(m_modelChartTwo); + if ( ! m_modelChartTwo->isRestoredFromScene()) { + CaretAssert(m_modelChart); + if (m_modelChart->isRestoredFromScene()) { + m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); + } + } + +} + /** * @return The gaps and margins. */ diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index 8d64cb7ce..adb191341 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -407,6 +407,8 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); + void restoreModelChartOneToModelChartTwo(); + IdentificationManager* getIdentificationManager(); SelectionManager* getSelectionManager(); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index dbb3a42e5..f28cf5439 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -922,11 +922,14 @@ BrowserTabContent::getOverlaySet() const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() { - Model* model = getModelForDisplay(); - if (model != NULL) { - return model->getChartTwoOverlaySet(m_tabNumber); - } - return NULL; + CaretAssert(m_chartTwoModel); + return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); + +// Model* model = getModelForDisplay(); +// if (model != NULL) { +// return model->getChartTwoOverlaySet(m_tabNumber); +// } +// return NULL; } /** @@ -935,11 +938,14 @@ BrowserTabContent::getChartTwoOverlaySet() const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() const { - const Model* model = getModelForDisplay(); - if (model != NULL) { - return model->getChartTwoOverlaySet(m_tabNumber); - } - return NULL; + CaretAssert(m_chartTwoModel); + return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); + +// const Model* model = getModelForDisplay(); +// if (model != NULL) { +// return model->getChartTwoOverlaySet(m_tabNumber); +// } +// return NULL; } /** diff --git a/src/Brain/Model.cxx b/src/Brain/Model.cxx index e36cd9c6a..6ec95a26a 100644 --- a/src/Brain/Model.cxx +++ b/src/Brain/Model.cxx @@ -254,6 +254,8 @@ Model::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + setRestoredFromScene(true); + if (m_modelType == ModelTypeEnum::MODEL_TYPE_SURFACE) { const AString surfaceName = sceneClass->getStringValue("surfaceName", "NOT-FOUND"); @@ -434,4 +436,25 @@ Model::copyTabContent(const int32_t /*sourceTabIndex*/, } +/** + * @return True if model was restored from scene + */ +bool Model::isRestoredFromScene() const +{ + return m_restoredFromSceneFlag; +} + +/** + * Set model was restored from scene. + * + * @param restoredStatus + * New value for restored status. + */ +void +Model::setRestoredFromScene(const bool restoredStatus) +{ + m_restoredFromSceneFlag = restoredStatus; +} + + diff --git a/src/Brain/Model.h b/src/Brain/Model.h index 25ce9c572..f17458bda 100644 --- a/src/Brain/Model.h +++ b/src/Brain/Model.h @@ -87,6 +87,10 @@ namespace caret { virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); + bool isRestoredFromScene() const; + + void setRestoredFromScene(const bool restoredStatus); + protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; @@ -115,6 +119,8 @@ namespace caret { ModelTypeEnum::Enum m_modelType; std::vector m_oldSceneTransformations; + + bool m_restoredFromSceneFlag = false; }; } // namespace diff --git a/src/Brain/ModelChart.h b/src/Brain/ModelChart.h index 9cc8a6914..b654dd7a7 100644 --- a/src/Brain/ModelChart.h +++ b/src/Brain/ModelChart.h @@ -201,6 +201,8 @@ namespace caret { CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; std::unique_ptr m_sceneAssistant; + + friend class ModelChartTwo; }; } // namespace diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 6f5bbe4a0..67341480b 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -21,6 +21,7 @@ #include #include +#include "AnnotationColorBar.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" @@ -30,17 +31,25 @@ #include "CaretLogger.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartableTwoFileDelegate.h" +#include "ChartableMatrixParcelInterface.h" +#include "ChartableMatrixSeriesInterface.h" +#include "ChartMatrixDisplayProperties.h" +#include "ChartableTwoFileMatrixChart.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoOverlaySetArray.h" #include "ChartingVersionEnum.h" +#include "ConnectivityDataLoaded.h" +#include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" +#include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" +#include "ModelChart.h" #include "ModelChartTwo.h" #include "OverlaySet.h" #include "OverlaySetArray.h" @@ -715,6 +724,180 @@ ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAtt sceneClass); } +/** + * Try to restore a scene from a version one chart model + * by copying data from the chart one model. + * + * @param modelChartOne + * The charting version one model. + */ +void +ModelChartTwo::restoreSceneFromChartOneModel(ModelChart* modelChartOne) +{ + if (isRestoredFromScene()) { + CaretAssert(0); + } + setRestoredFromScene(true); + + EventBrowserTabGetAll allTabsEvent; + EventManager::get()->sendEvent(allTabsEvent.getPointer()); + std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); + + for (auto tabIndex : validTabIndices) { + switch (modelChartOne->getSelectedChartOneDataType(tabIndex)) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + setSelectedChartTwoDataType(tabIndex, ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + setSelectedChartTwoDataType(tabIndex, + ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); + restoreMatrixChartFromChartOneModel(modelChartOne, + tabIndex); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + setSelectedChartTwoDataType(tabIndex, + ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); + restoreMatrixChartFromChartOneModel(modelChartOne, + tabIndex); + break; + } + } +} + +/** + * Restore matrix from model one chart by copying from the model. + * + * @param modelChartOne + * The charting version one model. + * @param tabIndex + * Index of tab being restored + */ +void +ModelChartTwo::restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, + const int32_t tabIndex) +{ + CaretAssert(modelChartOne); + + CaretDataFileSelectionModel* fileSelectionModel = NULL; + switch (modelChartOne->getSelectedChartOneDataType(tabIndex)) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + CaretAssert(0); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + fileSelectionModel = modelChartOne->getChartableMatrixParcelFileSelectionModel(tabIndex); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + fileSelectionModel = modelChartOne->getChartableMatrixSeriesFileSelectionModel(tabIndex); + break; + } + + CaretDataFile* caretDataFile = fileSelectionModel->getSelectedFile(); + if (caretDataFile == NULL) { + return; + } + CaretMappableDataFile* mapFile = dynamic_cast(caretDataFile); + if (mapFile == NULL) { + return; + } + + ChartableTwoFileMatrixChart* fileMatrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); + if (fileMatrixChart == NULL) { + return; + } + + ChartableMatrixParcelInterface* chartOneMatrixParcelFile = dynamic_cast(mapFile); + ChartableMatrixSeriesInterface* chartOneMatrixSeriesFile = dynamic_cast(mapFile); + + int32_t selectedRowColumnIndex = -1; + MapYokingGroupEnum::Enum chartOneYoking = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + ChartMatrixDisplayProperties* chartOneMatrixDisplayProperties = NULL; + if (chartOneMatrixParcelFile != NULL) { + chartOneMatrixDisplayProperties = chartOneMatrixParcelFile->getChartMatrixDisplayProperties(tabIndex); + + switch (chartOneMatrixParcelFile->getMatrixLoadingDimension()) { + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); + break; + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); + break; + } + + CiftiMappableConnectivityMatrixDataFile* connMatrixFile = dynamic_cast(mapFile); + if (connMatrixFile != NULL) { + const ConnectivityDataLoaded* connDataLoaded = connMatrixFile->getConnectivityDataLoaded(); + if (connDataLoaded != NULL) { + int64_t loadedRowIndex = -1; + int64_t loadedColumnIndex = -1; + connDataLoaded->getRowColumnLoading(loadedRowIndex, + loadedColumnIndex); + if (loadedRowIndex >= 0) { + selectedRowColumnIndex = loadedRowIndex; + } + else if (loadedColumnIndex >= 0) { + selectedRowColumnIndex = loadedColumnIndex; + } + } + } + } + else if (chartOneMatrixSeriesFile != NULL) { + chartOneMatrixDisplayProperties = chartOneMatrixSeriesFile->getChartMatrixDisplayProperties(tabIndex); + + chartOneYoking = chartOneMatrixSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); + fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); + selectedRowColumnIndex = chartOneMatrixSeriesFile->getSelectedMapIndex(tabIndex); + } + else { + CaretAssertMessage(0, "Has new matrix chart type been added?"); + return; + } + + + CaretAssert(chartOneMatrixDisplayProperties); + ChartTwoMatrixDisplayProperties* chartTwoMatrixDisplayProperties = getChartTwoMatrixDisplayProperties(tabIndex); + CaretAssert(chartTwoMatrixDisplayProperties); + chartTwoMatrixDisplayProperties->resetPropertiesToDefault(); + chartTwoMatrixDisplayProperties->setGridLinesDisplayed(chartOneMatrixDisplayProperties->isGridLinesDisplayed()); + chartTwoMatrixDisplayProperties->setSelectedRowColumnHighlighted(chartOneMatrixDisplayProperties->isSelectedRowColumnHighlighted()); + AnnotationColorBar* chartOneColorBar = chartOneMatrixDisplayProperties->getColorBar(); + + EventBrowserTabGet getTabEvent(tabIndex); + EventManager::get()->sendEvent(getTabEvent.getPointer()); + BrowserTabContent* browserTabContent = getTabEvent.getBrowserTab(); + if (browserTabContent != NULL) { + ChartTwoOverlaySet* chartTwoOverlaySet = browserTabContent->getChartTwoOverlaySet(); + CaretAssert(chartTwoOverlaySet); + for (int32_t iOverlay = 0; iOverlay < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; iOverlay++) { + ChartTwoOverlay* chartTwoOverlay = chartTwoOverlaySet->getOverlay(iOverlay); + CaretAssert(chartTwoOverlay); + if (iOverlay == 0) { + chartTwoOverlay->setEnabled(true); + chartTwoOverlay->setSelectionData(mapFile, + selectedRowColumnIndex); + chartTwoOverlay->setMatrixTriangularViewingMode(ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL); + chartTwoOverlay->setAllMapsSelected(false); + chartTwoOverlay->setCartesianVerticalAxisLocation(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + chartTwoOverlay->setMapYokingGroup(chartOneYoking); + AnnotationColorBar* chartTwoColorBar = chartTwoOverlay->getColorBar(); + if ((chartOneColorBar != NULL) + && (chartTwoColorBar != NULL)) { + *chartTwoColorBar = *chartOneColorBar; + } + } + else { + chartTwoOverlay->setEnabled(false); + } + } + } +} + /** * Restore the chart models from a VERSION TWO scene. * diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index c51bf8001..2d8e213d1 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -30,6 +30,7 @@ #include #include +#include "CaretDataFileSelectionModel.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" @@ -43,6 +44,7 @@ namespace caret { class ChartTwoOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; + class ModelChart; class OverlaySetArray; class SurfaceFile; @@ -105,6 +107,8 @@ namespace caret { void reset(); + void restoreSceneFromChartOneModel(ModelChart* modelChartOne); + protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; @@ -126,6 +130,9 @@ namespace caret { void restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); + void restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, + const int32_t tabIndex); + // void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; // // void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 5a466d276..1cd719d43 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -744,6 +744,10 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, m_browserTabs[tabIndex] = tab; } + for (auto brainPtr : m_brains) { + brainPtr->restoreModelChartOneToModelChartTwo(); + } + /* * Restore foreground and background colors to scene foreground and background colors */ -- GitLab From d3d112085ab9015f1916034d098b5ff41ead7030 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Mar 2017 09:33:37 -0500 Subject: [PATCH 225/755] Histogram charting updates: Axis title on left and right is now rotated -90 degrees. Fixed spacing and layout issues in axes when title is not displayed. Removed ticks from first and last scale values. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 593 ++++++++++++++---- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 3 + src/Brain/ChartTwoOverlaySet.cxx | 6 +- src/Brain/FtglFontTextRenderer.cxx | 19 +- src/Charting/ChartTwoCartesianAxis.cxx | 58 +- src/Charting/ChartTwoCartesianAxis.h | 12 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 12 +- 7 files changed, 536 insertions(+), 167 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index bc48d58fa..89b9db281 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -23,6 +23,8 @@ #include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #undef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ +#include + #include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" @@ -1738,16 +1740,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH const float axisLength = 1000.0; float minimumValue = 0.0; float maximumValue = 0.0; - std::vector labelOffsetInPixels; - std::vector labelTexts; - cartesianAxis->getLabelsAndPositions(dataBounds, - axisLength, - minimumValue, - maximumValue, - labelOffsetInPixels, - labelTexts); - for (std::vector::iterator iter = labelTexts.begin(); - iter != labelTexts.end(); + std::vector scaleValueOffsetInPixels; + std::vector scaleValuesText; + cartesianAxis->getScaleValuesAndOffsets(dataBounds, + axisLength, + minimumValue, + maximumValue, + scaleValueOffsetInPixels, + scaleValuesText); + for (std::vector::iterator iter = scaleValuesText.begin(); + iter != scaleValuesText.end(); iter++) { const AString text = *iter; if ( ! text.isEmpty()) { @@ -1762,19 +1764,36 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH } } - const AString labelText = cartesianAxis->getLabelText(); - if ( ! labelText.isEmpty()) { + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + if (heightOut > 0) { + heightOut += s_tickLength; + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + if (widthOut > 0) { + widthOut += s_tickLength; + } + break; + } + + const AString axisTitle = cartesianAxis->getAxisTitle(); + if ( ! axisTitle.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setText(labelText); + annotationText.setText(axisTitle); switch (cartesianAxis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + annotationText.setRotationAngle(-90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + annotationText.setRotationAngle(-90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); @@ -1785,19 +1804,24 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH double textHeight = 0.0; m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); - const float verticalOffset = 4; // adds space between scale values and label + /* + * Note: Text on left and right is rotated but we need the width + * and height after rotation so swap the width and height of the text + */ switch (cartesianAxis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += (textHeight + verticalOffset); + heightOut += textHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + std::swap(textWidth, textHeight); widthOut += textWidth; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + std::swap(textWidth, textHeight); widthOut += textWidth; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += (textHeight + verticalOffset); + heightOut += textHeight; break; } } @@ -1889,6 +1913,330 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons chartGraphicsDrawingViewportOut[3] = graphicsHeight; } +///** +// * Draw the chart axes grid/box +// * +// * @param vpX +// * Viewport X for all chart content +// * @param vpY +// * Viewport Y for all chart content +// * @param vpWidth +// * Viewport width for all chart content +// * @param vpHeight +// * Viewport height for all chart content +// * @param margins +// * Margin around graphics region. The margin corresponding to the +// * axis may be changed so that all text in the axis is visible +// * (and not cut off). +// * @param axis +// * Axis that is drawn. +// * @param axisMinimumOut +// * Minimum value along the axis. +// * @param axisMaximumOut +// * Maximum value along the axis. +// * @return +// * True if the axis is valid and was drawn, else false. +// */ +//bool +//BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], +// const float vpX, +// const float vpY, +// const float vpWidth, +// const float vpHeight, +// const Margins& margins, +// ChartTwoCartesianAxis* axis, +// float& axisMinimumOut, +// float& axisMaximumOut) +//{ +// if (axis == NULL) { +// return false; +// } +// if ( ! axis->isVisible()) { +// return false; +// } +// +// float axisLength = 0.0; +// +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// axisLength = vpWidth - (margins.m_left + margins.m_right); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// axisLength = vpHeight - (margins.m_top + margins.m_bottom); +// break; +// } +// +// std::vector labelOffsetInPixels; +// std::vector labelTexts; +// const bool validAxisFlag = axis->getLabelsAndPositions(dataBounds, +// axisLength, +// axisMinimumOut, +// axisMaximumOut, +// labelOffsetInPixels, +// labelTexts); +// if ( ! validAxisFlag) { +// return false; +// } +// +// const float rgba[4] = { +// m_fixedPipelineDrawing->m_foregroundColorFloat[0], +// m_fixedPipelineDrawing->m_foregroundColorFloat[1], +// m_fixedPipelineDrawing->m_foregroundColorFloat[2], +// 1.0 +// }; +// +// const int32_t numLabelsToDraw = static_cast(labelTexts.size()); +// AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); +// annotationText.setCustomTextColor(rgba); +// annotationText.setTextColor(CaretColorEnum::CUSTOM); +// +// if (numLabelsToDraw > 0) { +// float labelX = 0.0; +// float labelY = 0.0; +// float labelOffsetMultiplierX = 0.0; +// float labelOffsetMultiplierY = 0.0; +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// +// /* +// * Viewport for axis name and numeric values +// */ +// int32_t axisVpX = vpX; +// int32_t axisVpY = vpY; +// int32_t axisVpWidth = vpWidth; +// int32_t axisVpHeight = vpHeight; +// +// float tickDeltaXY[2] = { 0.0, 0.0 }; +// const float tickLength = 5.0; +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// axisVpX = vpX; +// axisVpY = vpY; +// axisVpWidth = vpWidth; +// axisVpHeight = margins.m_bottom; +// labelX = margins.m_left; +// labelY = margins.m_bottom; +// labelOffsetMultiplierX = 1.0; +// labelOffsetMultiplierY = 0.0; +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// tickDeltaXY[0] = 0.0; +// tickDeltaXY[1] = -tickLength; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// axisVpX = vpX; +// axisVpY = vpY + vpHeight - margins.m_top; +// axisVpWidth = vpWidth; +// axisVpHeight = margins.m_top; +// labelX = margins.m_left; +// labelY = 0.0; +// labelOffsetMultiplierX = 1.0; +// labelOffsetMultiplierY = 0.0; +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); +// tickDeltaXY[0] = 0.0; +// tickDeltaXY[1] = tickLength; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// axisVpX = vpX; +// axisVpY = vpY; +// axisVpWidth = margins.m_left; +// axisVpHeight = vpHeight; +// labelX = margins.m_left; +// labelY = margins.m_bottom; +// labelOffsetMultiplierX = 0.0; +// labelOffsetMultiplierY = 1.0; +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// tickDeltaXY[0] = -tickLength; +// tickDeltaXY[1] = 0.0; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// axisVpX = vpX + vpWidth - margins.m_right; +// axisVpY = vpY; +// axisVpWidth = margins.m_right; +// axisVpHeight = vpHeight; +// labelX = 0.0; +// labelY = margins.m_bottom; +// labelOffsetMultiplierX = 0.0; +// labelOffsetMultiplierY = 1.0; +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// tickDeltaXY[0] = tickLength; +// tickDeltaXY[1] = 0.0; +// break; +// } +// +// /* +// * Viewport for axis text and numeric values +// */ +// const int viewport[4] = { +// axisVpX, +// axisVpY, +// axisVpWidth, +// axisVpHeight +// }; +// glViewport(viewport[0], +// viewport[1], +// viewport[2], +// viewport[3]); +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// glOrtho(0, axisVpWidth, 0, axisVpHeight, -1.0, 1.0); +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); +// +// const bool showTicksFlag = axis->isShowTickmarks(); +// +// const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; +// const int32_t firstIndex = 0; +// const int32_t lastIndex = numLabelsToDraw - 1; +// for (int32_t i = 0; i < numLabelsToDraw; i++) { +// float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; +// float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; +// float textOffsetX = 0.0; +// float textOffsetY = 0.0; +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); +// if (i == firstIndex) { +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); +// tickStartX += halfGridLineWidth; +// } +// else if (i == lastIndex) { +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); +// tickStartX -= halfGridLineWidth; +// } +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// tickStartX -= halfGridLineWidth; +// if (i == firstIndex) { +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); +// tickStartY += halfGridLineWidth; +// } +// else if (i == lastIndex) { +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// tickStartY -= halfGridLineWidth; +// } +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// tickStartX += halfGridLineWidth; +// if (i == firstIndex) { +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); +// tickStartY += halfGridLineWidth; +// } +// else if (i == lastIndex) { +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// tickStartY -= halfGridLineWidth; +// } +// textOffsetX = -2.0; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// if (i == firstIndex) { +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); +// tickStartX += halfGridLineWidth; +// } +// else if (i == lastIndex) { +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); +// tickStartX -= halfGridLineWidth; +// } +// textOffsetY = -2.0; +// break; +// } +// const float tickEndX = tickStartX + tickDeltaXY[0]; +// const float tickEndY = tickStartY + tickDeltaXY[1]; +// +// if (showTicksFlag) { +// glLineWidth(GRID_LINE_WIDTH); +// glBegin(GL_LINES); +// glVertex2f(tickStartX, +// tickStartY); +// glVertex2f(tickEndX, +// tickEndY); +// glEnd(); +// } +// +// const float textX = tickEndX + textOffsetX; +// const float textY = tickEndY + textOffsetY; +// annotationText.setText(labelTexts[i]); +// m_textRenderer->drawTextAtViewportCoords(textX, +// textY, +// 0.0, +// annotationText); +// } +// +// const AString axisText = axis->getLabelText(); +// if ( ! axisText.isEmpty()) { +// //AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); +// +// bool drawAxisTextVerticalFlag = false; +// float axisTextCenterX = axisVpWidth / 2.0; +// float axisTextCenterY = axisVpHeight / 2.0; +// const float textMarginOffset = 5.0; +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// axisTextCenterX = margins.m_left + axisTextCenterX; +// axisTextCenterY = textMarginOffset; +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// axisTextCenterX = vpX + (vpWidth / 2.0); +// axisTextCenterY = margins.m_top - textMarginOffset; +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// axisTextCenterX = textMarginOffset; +// axisTextCenterY = margins.m_bottom + axisTextCenterY; +// //annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); +// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); +// drawAxisTextVerticalFlag = true; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// axisTextCenterX = margins.m_right - textMarginOffset; +// axisTextCenterY = vpY + (vpHeight / 2.0); +// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); +// drawAxisTextVerticalFlag = true; +// break; +// } +// if (drawAxisTextVerticalFlag) { +// //annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); +// annotationText.setRotationAngle(-90.0); +// annotationText.setText(axisText); +// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, +// axisTextCenterY, +// 0.0, +// annotationText); +// annotationText.setRotationAngle(0.0); +// } +// else { +// annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); +// annotationText.setText(axisText); +// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, +// axisTextCenterY, +// 0.0, +// annotationText); +// } +// } +// } +// +// return true; +//} + /** * Draw the chart axes grid/box * @@ -1931,27 +2279,57 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data return false; } - float axisLength = 0.0; + int32_t axisVpX = 0; + int32_t axisVpY = 0; + int32_t axisVpWidth = 0; + int32_t axisVpHeight = 0; + float axisLength = 0.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + axisVpX = vpX + margins.m_left; + axisVpY = vpY; + axisVpWidth = vpWidth - (margins.m_left + margins.m_right); + axisVpHeight = margins.m_bottom; + axisLength = axisVpWidth; + break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisLength = vpWidth - (margins.m_left + margins.m_right); + axisVpX = vpX + margins.m_left; + axisVpY = vpY + vpHeight - margins.m_top; + axisVpWidth = vpWidth - (margins.m_left + margins.m_right); + axisVpHeight = margins.m_top; + axisLength = axisVpWidth; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + axisVpX = vpX; + axisVpY = vpY + margins.m_bottom; + axisVpWidth = margins.m_left + 1; // so ticks go to box + axisVpHeight = vpHeight - (margins.m_bottom + margins.m_top); + axisLength = axisVpHeight; + break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisLength = vpHeight - (margins.m_top + margins.m_bottom); + axisVpX = vpX + vpWidth - margins.m_right; + axisVpY = vpY + margins.m_bottom; + axisVpWidth = margins.m_right; + axisVpHeight = vpHeight - (margins.m_bottom + margins.m_top); + axisLength = axisVpHeight; break; } + const int32_t axisViewport[4] { + axisVpX, + axisVpY, + axisVpWidth, + axisVpHeight + }; - std::vector labelOffsetInPixels; - std::vector labelTexts; - const bool validAxisFlag = axis->getLabelsAndPositions(dataBounds, + std::vector scaleValueOffsetInPixels; + std::vector scaleValuesText; + const bool validAxisFlag = axis->getScaleValuesAndOffsets(dataBounds, axisLength, axisMinimumOut, axisMaximumOut, - labelOffsetInPixels, - labelTexts); + scaleValueOffsetInPixels, + scaleValuesText); if ( ! validAxisFlag) { return false; } @@ -1963,101 +2341,67 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data 1.0 }; - const int32_t numLabelsToDraw = static_cast(labelTexts.size()); + const int32_t numScaleValuesToDraw = static_cast(scaleValuesText.size()); AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setCustomTextColor(rgba); annotationText.setTextColor(CaretColorEnum::CUSTOM); - if (numLabelsToDraw > 0) { - float labelX = 0.0; - float labelY = 0.0; - float labelOffsetMultiplierX = 0.0; - float labelOffsetMultiplierY = 0.0; + if (numScaleValuesToDraw > 0) { + float startX = 0.0; + float startY = 0.0; + float offsetMultiplierX = 0.0; + float offsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - /* - * Viewport for axis name and numeric values - */ - int32_t axisVpX = vpX; - int32_t axisVpY = vpY; - int32_t axisVpWidth = vpWidth; - int32_t axisVpHeight = vpHeight; - float tickDeltaXY[2] = { 0.0, 0.0 }; - const float tickLength = 5.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisVpX = vpX; - axisVpY = vpY; - axisVpWidth = vpWidth; - axisVpHeight = margins.m_bottom; - labelX = margins.m_left; - labelY = margins.m_bottom; - labelOffsetMultiplierX = 1.0; - labelOffsetMultiplierY = 0.0; + startX = 0; + startY = axisVpHeight; + offsetMultiplierX = 1.0; + offsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); tickDeltaXY[0] = 0.0; - tickDeltaXY[1] = -tickLength; + tickDeltaXY[1] = -s_tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisVpX = vpX; - axisVpY = vpY + vpHeight - margins.m_top; - axisVpWidth = vpWidth; - axisVpHeight = margins.m_top; - labelX = margins.m_left; - labelY = 0.0; - labelOffsetMultiplierX = 1.0; - labelOffsetMultiplierY = 0.0; + startX = 0.0; + startY = 0.0; + offsetMultiplierX = 1.0; + offsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); tickDeltaXY[0] = 0.0; - tickDeltaXY[1] = tickLength; + tickDeltaXY[1] = s_tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisVpX = vpX; - axisVpY = vpY; - axisVpWidth = margins.m_left; - axisVpHeight = vpHeight; - labelX = margins.m_left; - labelY = margins.m_bottom; - labelOffsetMultiplierX = 0.0; - labelOffsetMultiplierY = 1.0; + startX = axisVpWidth; + startY = 0.0; + offsetMultiplierX = 0.0; + offsetMultiplierY = 1.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickDeltaXY[0] = -tickLength; + tickDeltaXY[0] = -s_tickLength; tickDeltaXY[1] = 0.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisVpX = vpX + vpWidth - margins.m_right; - axisVpY = vpY; - axisVpWidth = margins.m_right; - axisVpHeight = vpHeight; - labelX = 0.0; - labelY = margins.m_bottom; - labelOffsetMultiplierX = 0.0; - labelOffsetMultiplierY = 1.0; + startX = 0.0; + startY = 0.0; + offsetMultiplierX = 0.0; + offsetMultiplierY = 1.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickDeltaXY[0] = tickLength; + tickDeltaXY[0] = s_tickLength; tickDeltaXY[1] = 0.0; break; } - /* - * Viewport for axis text and numeric values - */ - const int viewport[4] = { - axisVpX, - axisVpY, - axisVpWidth, - axisVpHeight - }; - glViewport(viewport[0], - viewport[1], - viewport[2], - viewport[3]); + glViewport(axisViewport[0], + axisViewport[1], + axisViewport[2], + axisViewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -2068,16 +2412,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); - const bool showTicksFlag = axis->isShowTickmarks(); + const bool showTicksEnabledFlag = axis->isShowTickmarks(); const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; const int32_t firstIndex = 0; - const int32_t lastIndex = numLabelsToDraw - 1; - for (int32_t i = 0; i < numLabelsToDraw; i++) { - float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; - float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; + const int32_t lastIndex = numScaleValuesToDraw - 1; + for (int32_t i = 0; i < numScaleValuesToDraw; i++) { + float tickStartX = startX + scaleValueOffsetInPixels[i] * offsetMultiplierX; + float tickStartY = startY + scaleValueOffsetInPixels[i] * offsetMultiplierY; float textOffsetX = 0.0; float textOffsetY = 0.0; + bool showTickAtScaleValueFlag = showTicksEnabledFlag; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); @@ -2090,6 +2435,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); tickStartX -= halfGridLineWidth; } + textOffsetY = 2.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); @@ -2103,6 +2449,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); tickStartY -= halfGridLineWidth; } + textOffsetX = 2.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); @@ -2135,7 +2482,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const float tickEndX = tickStartX + tickDeltaXY[0]; const float tickEndY = tickStartY + tickDeltaXY[1]; - if (showTicksFlag) { + if ((i == firstIndex) + || (i == lastIndex)) { + showTickAtScaleValueFlag = false; + } + + if (showTickAtScaleValueFlag) { glLineWidth(GRID_LINE_WIDTH); glBegin(GL_LINES); glVertex2f(tickStartX, @@ -2147,16 +2499,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const float textX = tickEndX + textOffsetX; const float textY = tickEndY + textOffsetY; - annotationText.setText(labelTexts[i]); + annotationText.setText(scaleValuesText[i]); m_textRenderer->drawTextAtViewportCoords(textX, - textY, - 0.0, - annotationText); + textY, + 0.0, + annotationText); } - const AString axisText = axis->getLabelText(); - if ( ! axisText.isEmpty()) { - //AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + const AString axisTitle = axis->getAxisTitle(); + if ( ! axisTitle.isEmpty()) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); @@ -2166,47 +2517,47 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const float textMarginOffset = 5.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisTextCenterX = (vpWidth / 2.0); + axisTextCenterX = (axisVpWidth / 2.0); axisTextCenterY = textMarginOffset; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisTextCenterX = (vpWidth / 2.0); - axisTextCenterY = margins.m_top - textMarginOffset; + axisTextCenterX = (axisVpWidth / 2.0); + axisTextCenterY = axisVpHeight - textMarginOffset; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: axisTextCenterX = textMarginOffset; - axisTextCenterY = (vpHeight / 2.0); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + axisTextCenterY = (axisVpHeight / 2.0); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); drawAxisTextVerticalFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisTextCenterX = margins.m_right - textMarginOffset; - axisTextCenterY = (vpHeight / 2.0); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + axisTextCenterX = axisVpWidth - textMarginOffset; + axisTextCenterY = (axisVpHeight / 2.0); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); drawAxisTextVerticalFlag = true; break; } if (drawAxisTextVerticalFlag) { - annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); - annotationText.setText(axisText); + annotationText.setRotationAngle(-90.0); + annotationText.setText(axisTitle); m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, - axisTextCenterY, - 0.0, - annotationText); + axisTextCenterY, + 0.0, + annotationText); + annotationText.setRotationAngle(0.0); } else { annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setText(axisText); + annotationText.setText(axisTitle); m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, - axisTextCenterY, - 0.0, - annotationText); + axisTextCenterY, + 0.0, + annotationText); } } } return true; } - diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 457aa1a8d..89ebf5877 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -179,6 +179,9 @@ namespace caret { static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; + static constexpr float s_tickLength = 5.0; + + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 99a7a5535..0a62d6026 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -76,13 +76,13 @@ m_tabIndex(tabIndex) break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: m_chartAxisLeft->setVisible(true); - m_chartAxisLeft->setLabelText("Counts"); + m_chartAxisLeft->setAxisTitle("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisRight->setVisible(false); - m_chartAxisRight->setLabelText("Counts"); + m_chartAxisRight->setAxisTitle("Counts"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisBottom->setVisible(true); - m_chartAxisBottom->setLabelText("Data"); + m_chartAxisBottom->setAxisTitle("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 13f34b376..24f80a1c8 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -877,7 +878,23 @@ FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotatio m_viewportHeight = viewportHeight; double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; - getBoundsForTextAtViewportCoords(annotationText, 0.0, 0.0, 0.0, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); + if (annotationText.getRotationAngle() != 0.0) { + /* + * Any rotation must be removed as the rotation is applied to the viewport postions. + * For example, if the text is rotated -90 degrees, the top-right and top-left will + * be on the left and bottom-right and bottom-left will be on the right + */ + std::unique_ptr annotation = std::unique_ptr(annotationText.clone()); + AnnotationText* textCopy = dynamic_cast(annotation.get()); + CaretAssert(textCopy); + textCopy->setRotationAngle(0.0); + getBoundsForTextAtViewportCoords(*textCopy, 0.0, 0.0, 0.0, + viewportHeight, bottomLeft, bottomRight, topRight, topLeft); + } + else { + getBoundsForTextAtViewportCoords(annotationText, 0.0, 0.0, 0.0, + viewportHeight, bottomLeft, bottomRight, topRight, topLeft); + } widthOut = MathFunctions::distance3D(bottomLeft, bottomRight); heightOut = MathFunctions::distance3D(topLeft, bottomLeft); diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index bbb7383b5..522a9dc87 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -70,8 +70,8 @@ m_axisLocation(axisLocation) &m_userNumericFormat); m_sceneAssistant->add("m_userNumberOfSubdivisions", &m_userNumberOfSubdivisions); - m_sceneAssistant->add("m_labelText", - &m_labelText); + m_sceneAssistant->add("m_axisTitle", + &m_axisTitle); m_sceneAssistant->add("m_visible", &m_visible); m_sceneAssistant->add("m_showTickmarks", @@ -132,7 +132,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_units = obj.m_units; m_userNumericFormat = obj.m_userNumericFormat; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; - m_labelText = obj.m_labelText; + m_axisTitle = obj.m_axisTitle; m_visible = obj.m_visible; m_showTickmarks = obj.m_showTickmarks; } @@ -345,24 +345,24 @@ ChartTwoCartesianAxis::toString() const } /** - * @return Text for axis label + * @return Title for axis */ AString -ChartTwoCartesianAxis::getLabelText() const +ChartTwoCartesianAxis::getAxisTitle() const { - return m_labelText; + return m_axisTitle; } /** - * Set Text for axis label + * Set title for axis * - * @param labelText - * New value for Text for axis label + * @param axisTitle + * New value for axis title */ void -ChartTwoCartesianAxis::setLabelText(const AString& labelText) +ChartTwoCartesianAxis::setAxisTitle(const AString& axisTitle) { - m_labelText = labelText; + m_axisTitle = axisTitle; } /** @@ -490,7 +490,7 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], } /** - * Get the axis labels and their positions for drawing the scale. + * Get the axis scale text values and their positions for drawing the scale. * * @param dataBoundsIn * Bounds of data [minX, maxX, minY, maxY]. @@ -500,20 +500,20 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], * Output minimum value for autoranging. * @param maximumOut * Output maximum value for autoranging. - * @param labelOffsetInPixelsOut - * Output containing offset in pixels for the scale labels. - * @param labelTextOut - * Output containing text for scale labels. + * @param scaleValuesOffsetInPixelsOut + * Output containing offset in pixels for the scale values. + * @param scaleValuesOut + * Output containing text for scale values. * @return * True if output data is valid, else false. */ bool -ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBoundsIn[4], - const float axisLengthInPixels, - float& minimumOut, - float& maximumOut, - std::vector& labelOffsetInPixelsOut, - std::vector& labelTextOut) const +ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], + const float axisLengthInPixels, + float& minimumOut, + float& maximumOut, + std::vector& scaleValuesOffsetInPixelsOut, + std::vector& scaleValuesOut) const { float dataBounds[4] = { dataBoundsIn[0], @@ -524,8 +524,8 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBoundsIn[4], minimumOut = 0.0; maximumOut = 0.0; - labelOffsetInPixelsOut.clear(); - labelTextOut.clear(); + scaleValuesOffsetInPixelsOut.clear(); + scaleValuesOut.clear(); if (axisLengthInPixels < 25.0) { return false; @@ -683,7 +683,7 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBoundsIn[4], && (labelParametricValue <= 1.0)) { const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; labelNumericValues.push_back(labelValueForText); - labelOffsetInPixelsOut.push_back(labelPixelsPosition); + scaleValuesOffsetInPixelsOut.push_back(labelPixelsPosition); // const AString labelText = AString::number(labelValueForText, 'f', labelsDigitsRightOfDecimal); // labelTextOut.push_back(labelText); @@ -697,15 +697,15 @@ ChartTwoCartesianAxis::getLabelsAndPositions(const float dataBoundsIn[4], const int32_t numValues = static_cast(labelNumericValues.size()); if (numValues > 0) { - labelTextOut.resize(numValues); + scaleValuesOut.resize(numValues); NumericTextFormatting::formatValueRange(m_userNumericFormat, m_userDigitsRightOfDecimal, &labelNumericValues[0], - &labelTextOut[0], + &scaleValuesOut[0], labelNumericValues.size()); } - CaretAssert(labelOffsetInPixelsOut.size() == labelTextOut.size()); - return ( ! labelTextOut.empty()); + CaretAssert(scaleValuesOffsetInPixelsOut.size() == scaleValuesOut.size()); + return ( ! scaleValuesOut.empty()); } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 7db0bd326..c72e93c9c 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -84,16 +84,16 @@ namespace caret { void setShowTickmarks(const bool showTickmarks); - bool getLabelsAndPositions(const float dataBoundsIn[4], + bool getScaleValuesAndOffsets(const float dataBoundsIn[4], const float axisLengthInPixels, float& minimumOut, float& maximumOut, - std::vector& labelOffsetInPixelsOut, - std::vector& labelTextOut) const; + std::vector& scaleValuesOffsetInPixelsOut, + std::vector& scaleValuesOut) const; - AString getLabelText() const; + AString getAxisTitle() const; - void setLabelText(const AString& labelText); + void setAxisTitle(const AString& axisTitle); // ADD_NEW_METHODS_HERE @@ -153,7 +153,7 @@ namespace caret { */ int32_t m_userNumberOfSubdivisions = -1; - AString m_labelText; + AString m_axisTitle; bool m_visible = false; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 864e52a9d..ce44a770f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -79,7 +79,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Controls for axis parameters */ m_axisNameToolButton = new QToolButton(); - m_axisNameToolButton->setText("Edit Axis Label"); + m_axisNameToolButton->setText("Edit Axis Title"); QObject::connect(m_axisNameToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); @@ -386,16 +386,14 @@ BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) { CaretAssert(m_chartAxis); if (m_chartAxis != NULL) { - WuQDataEntryDialog newNameDialog("Axis Name", + WuQDataEntryDialog newNameDialog("Axis Title", m_axisNameToolButton); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Axis Name"); - lineEdit->setText(m_chartAxis->getLabelText()); + lineEdit->setText(m_chartAxis->getAxisTitle()); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); - if ( ! name.isEmpty()) { - m_chartAxis->setLabelText(name); - valueChanged(); - } + m_chartAxis->setAxisTitle(name); + valueChanged(); } } } -- GitLab From 19a0325bf51b434b15643c3ed02346ab36fe60dd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Mar 2017 10:02:52 -0500 Subject: [PATCH 226/755] Histogram chart update: Fixed problem with axis selection combo box in Toolbar->Char Axes. It was not updated when chart overlays were changed or a vertical axis location in an overlay was changed. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 18 +++---- src/Brain/ChartTwoOverlaySet.cxx | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 89b9db281..6a228ea5a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -260,9 +260,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() std::vector drawingInfo; - bool haveBottomAxisFlag = false; - bool haveLeftAxisFlag = false; - bool haveRightAxisFlag = false; +// bool haveBottomAxisFlag = false; +// bool haveLeftAxisFlag = false; +// bool haveRightAxisFlag = false; /* * Get the histogram drawing information and overall extent @@ -308,7 +308,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() xMin = std::min(xMin, bounds[0]); xMax = std::max(xMax, bounds[1]); - haveBottomAxisFlag = true; +// haveBottomAxisFlag = true; switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); @@ -316,12 +316,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: yMinRight = std::min(yMinRight, bounds[2]); yMaxRight = std::max(yMaxRight, bounds[3]); - haveRightAxisFlag = true; +// haveRightAxisFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: yMinLeft = std::min(yMinLeft, bounds[2]); yMaxLeft = std::max(yMaxLeft, bounds[3]); - haveLeftAxisFlag = true; +// haveLeftAxisFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); @@ -354,9 +354,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() ChartTwoCartesianAxis* bottomAxis = m_chartOverlaySet->getChartAxisBottom(); ChartTwoCartesianAxis* topAxis = NULL; - leftAxis->setVisible(haveLeftAxisFlag); - rightAxis->setVisible(haveRightAxisFlag); - bottomAxis->setVisible(haveBottomAxisFlag); +// leftAxis->setVisible(haveLeftAxisFlag); +// rightAxis->setVisible(haveRightAxisFlag); +// bottomAxis->setVisible(haveBottomAxisFlag); const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 0a62d6026..ce67363de 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -631,6 +631,55 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const { std::vector axes; + bool showAxesFlag = false; + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + showAxesFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + showAxesFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + bool showBottomFlag = false; + bool showLeftFlag = false; + bool showRightFlag = false; + + if (showAxesFlag) { + for (auto overlay : m_overlays) { + if (overlay->isEnabled()) { + CaretMappableDataFile* mapFile = NULL; + int32_t mapIndex = -1; + overlay->getSelectionData(mapFile, mapIndex); + if (mapFile != NULL) { + showBottomFlag = true; + switch (overlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssert(0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + showLeftFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + showRightFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + } + } + } + } + + m_chartAxisBottom->setVisible(showBottomFlag); + m_chartAxisLeft->setVisible(showLeftFlag); + m_chartAxisRight->setVisible(showRightFlag); + if (m_chartAxisBottom->isVisible()) { axes.push_back(m_chartAxisBottom.get()); } -- GitLab From e66184c3bba0985412eb3903a73523fde74cecb8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Mar 2017 10:27:42 -0500 Subject: [PATCH 227/755] For histogram chart, do not display "Chart Orientation" in the toolbar. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 146e7ece0..09cbbe401 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1473,11 +1473,9 @@ BrainBrowserWindowToolBar::updateToolBar() break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: showChartTwoAxesWidget = true; - showChartTwoOrientationWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: showChartTwoAxesWidget = true; - showChartTwoOrientationWidget = true; showChartTwoAttributesWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: -- GitLab From bb9198a73b5c90ad722712fcc1ca57ee99cd86e3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Mar 2017 15:22:22 -0500 Subject: [PATCH 228/755] For Histogram, changed implementation of subdivision. Auto subdivisions is now selected using a checkbox and the spin box for subdivisions is applied when "auto" is unchecked. --- src/Charting/ChartTwoCartesianAxis.cxx | 30 ++++++++++++++++--- src/Charting/ChartTwoCartesianAxis.h | 12 ++++---- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 28 +++++++++++------ .../BrainBrowserWindowToolBarChartTwoAxes.h | 2 ++ 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 522a9dc87..41129625a 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -68,6 +68,8 @@ m_axisLocation(axisLocation) &m_units); m_sceneAssistant->add("m_userNumericFormat", &m_userNumericFormat); + m_sceneAssistant->add("m_autoSubdivisionsEnabled", + &m_autoSubdivisionsEnabled); m_sceneAssistant->add("m_userNumberOfSubdivisions", &m_userNumberOfSubdivisions); m_sceneAssistant->add("m_axisTitle", @@ -131,6 +133,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_scaleRangeMode = obj.m_scaleRangeMode; m_units = obj.m_units; m_userNumericFormat = obj.m_userNumericFormat; + m_autoSubdivisionsEnabled = obj.m_autoSubdivisionsEnabled; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_axisTitle = obj.m_axisTitle; m_visible = obj.m_visible; @@ -169,8 +172,7 @@ ChartTwoCartesianAxis::setUserDigitsRightOfDecimal(const int32_t digitsRightOfDe /** - * @return User's number of subdivisions - * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) + * @return User's number of subdivisions. */ int32_t ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const @@ -182,7 +184,6 @@ ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const * Set User's number of subdivisions * @param numberOfSubdivisions * New value for Number of subdivisions. - * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) */ void ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions) @@ -190,6 +191,27 @@ ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivi m_userNumberOfSubdivisions = numberOfSubdivisions; } +/** + * @return auto subdivisions enabled + */ +bool +ChartTwoCartesianAxis::isAutoSubdivisionsEnabled() const +{ + return m_autoSubdivisionsEnabled; +} + +/** + * Set auto subdivisions enabled + * + * @param autoSubdivisionsEnabled + * New value for auto subdivisions enabled + */ +void +ChartTwoCartesianAxis::setAutoSubdivisionsEnabled(const bool autoSubdivisionsEnabled) +{ + m_autoSubdivisionsEnabled = autoSubdivisionsEnabled; +} + /** * @return User scale's minimum value */ @@ -578,7 +600,7 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], break; } - if (m_userNumberOfSubdivisions >= 0) { + if ( ! m_autoSubdivisionsEnabled) { const float labelsRange = labelsEnd - labelsStart; if (labelsRange <= 0.0) { return false; diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index c72e93c9c..b42e782ac 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -72,6 +72,10 @@ namespace caret { void setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat); + bool isAutoSubdivisionsEnabled() const; + + void setAutoSubdivisionsEnabled(const bool autoSubdivisionsEnabled); + int32_t getUserNumberOfSubdivisions() const; void setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions); @@ -147,11 +151,9 @@ namespace caret { NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; - /** - * Number of subdivisions. - * Note that value "-1" is AUTO (see QSpinBox::setSpecialValueText()) - */ - int32_t m_userNumberOfSubdivisions = -1; + bool m_autoSubdivisionsEnabled = true; + + int32_t m_userNumberOfSubdivisions = 2; AString m_axisTitle; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index ce44a770f..11e37cbad 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -115,14 +115,18 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_userDigitsRightOfDecimalSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 10, 1); QObject::connect(m_userDigitsRightOfDecimalSpinBox, static_cast(&QSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); // ok int converts to double + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userDigitsRightOfDecimalSpinBox->setToolTip("Set digits right of decimal for\ndecimal or scientific format"); - m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(-1, 10, 1); - m_userSubdivisionsSpinBox->setSpecialValueText("Auto"); + m_autoSubdivisionsCheckBox = new QCheckBox("Auto"); + QObject::connect(m_autoSubdivisionsCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_autoSubdivisionsCheckBox->setToolTip("Enable auto subdivisions"); + + m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 100, 1); QObject::connect(m_userSubdivisionsSpinBox, static_cast(&QSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); // ok int converts to double - m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis"); + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); + m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis when Auto is not checked"); /* * Group widgets for blocking signals @@ -135,6 +139,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_widgetGroup->add(m_showTickMarksCheckBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); + m_widgetGroup->add(m_autoSubdivisionsCheckBox); m_widgetGroup->add(m_userSubdivisionsSpinBox); const int COLUMN_ONE = 0; @@ -142,6 +147,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra const int COLUMN_THREE = 2; const int COLUMN_FOUR = 3; const int COLUMN_FIVE = 4; + const int COLUMN_SIX = 5; /* * Layouts */ @@ -165,16 +171,17 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra int rightRow = 0; layout->addWidget(m_axisNameToolButton, rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE); + layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE, 1, 2); rightRow++; layout->addWidget(new QLabel("Format"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE); + layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE, 1, 2); rightRow++; layout->addWidget(new QLabel("Decimals"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE); + layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE, 1, 2); rightRow++; layout->addWidget(new QLabel("Subdivisions"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_FIVE); + layout->addWidget(m_autoSubdivisionsCheckBox, rightRow, COLUMN_FIVE, Qt::AlignHCenter); + layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_SIX, Qt::AlignRight); rightRow++; QVBoxLayout* dialogLayout = new QVBoxLayout(this); @@ -310,7 +317,9 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* cha m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); + m_autoSubdivisionsCheckBox->setChecked(m_chartAxis->isAutoSubdivisionsEnabled()); m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); + m_userSubdivisionsSpinBox->setEnabled( ! m_chartAxis->isAutoSubdivisionsEnabled()); m_widgetGroup->blockAllSignals(false); } @@ -330,6 +339,7 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); + m_chartAxis->setAutoSubdivisionsEnabled(m_autoSubdivisionsCheckBox->isChecked()); m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index e98525fba..d7c850ac5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -92,6 +92,8 @@ namespace caret { QSpinBox* m_userDigitsRightOfDecimalSpinBox; + QCheckBox* m_autoSubdivisionsCheckBox; + QSpinBox* m_userSubdivisionsSpinBox; ChartTwoCartesianAxis* m_chartAxis; -- GitLab From 71736890fecef6e3730d6e64c979b2222e01fa97 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Mar 2017 16:26:52 -0500 Subject: [PATCH 229/755] For histogram chart range scale, if AUTO ranging selected for an axis, updated the Minimum and Maximum Axis values in the toolbar so that they match the ranges in the graphics region. If the user changes a minimum or maximum value with AUTO ranging, change the ranging to USER. --- src/Charting/ChartTwoCartesianAxis.cxx | 2 + src/Charting/ChartTwoCartesianAxis.h | 4 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 51 +++++++++++++++++-- .../BrainBrowserWindowToolBarChartTwoAxes.h | 4 ++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 41129625a..63401a959 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -593,6 +593,8 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], switch (m_scaleRangeMode) { case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + m_userScaleMinimumValue = labelsStart; + m_userScaleMaximumValue = labelsEnd; break; case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: labelsStart = m_userScaleMinimumValue; diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index b42e782ac..841dba9d6 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -137,9 +137,9 @@ namespace caret { const ChartAxisLocationEnum::Enum m_axisLocation; - float m_userScaleMinimumValue = -100.0; + mutable float m_userScaleMinimumValue = -100.0; - float m_userScaleMaximumValue = 100.0; + mutable float m_userScaleMaximumValue = 100.0; float m_axisLabelsStepValue = 1.0; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 11e37cbad..2d0afff90 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -35,10 +35,11 @@ #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" +#include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" -#include "CaretMappableDataFile.h" +#include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "ModelChartTwo.h" @@ -94,12 +95,12 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra const double bigValue = 999999.0; m_userMinimumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); QObject::connect(m_userMinimumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged); m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); m_userMaximumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); QObject::connect(m_userMaximumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); m_showTickMarksCheckBox = new QCheckBox("Show Ticks"); @@ -188,6 +189,9 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); dialogLayout->addLayout(layout); dialogLayout->addStretch(); + + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** @@ -197,6 +201,25 @@ BrainBrowserWindowToolBarChartTwoAxes::~BrainBrowserWindowToolBarChartTwoAxes() { } +/** + * Receive an event. + * + * @param event + * The event. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { + EventBrowserWindowGraphicsRedrawn* redrawEvent = dynamic_cast(event); + CaretAssert(redrawEvent); + updateContent(getTabContentFromSelectedTab()); + } + else { + BrainBrowserWindowToolBarComponent::receiveEvent(event); + } +} + /** * Update content of this tool bar component. * @@ -343,9 +366,9 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); } - updateContent(getTabContentFromSelectedTab()); - updateGraphics(); + + updateContent(getTabContentFromSelectedTab()); } /** @@ -358,6 +381,24 @@ BrainBrowserWindowToolBarChartTwoAxes::updateGraphics() } +/** + * Called when the minimum or maximum value is changed. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged(double) +{ + if (m_chartAxis != NULL) { + /* + * If the minimum or maximum value is modified by user, + * ensure Auto/User Range selection is USER + */ + m_autoUserRangeComboBox->getWidget()->blockSignals(true); + m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER); + m_autoUserRangeComboBox->getWidget()->blockSignals(false); + valueChanged(); + } +} + /** * Called when a widget is changed by a slot using a bool parameter. * Parameters must match when using function pointers. diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index d7c850ac5..8f330687c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -48,6 +48,8 @@ namespace caret { virtual void updateContent(BrowserTabContent* browserTabContent); + virtual void receiveEvent(Event* event); + // ADD_NEW_METHODS_HERE private slots: @@ -61,6 +63,8 @@ namespace caret { void valueChangedInt(int); + void axisMinimumMaximumValueChanged(double); + void axisNameToolButtonClicked(bool); private: -- GitLab From 7816527b71de8c406edf5c73bdc1ed1f3ce0f60b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Mar 2017 09:23:54 -0500 Subject: [PATCH 230/755] Continuing charting development. Fixed File Menu-->Duplicate Tab for when the selected tab is a Charting Two tab. --- src/Brain/ChartTwoOverlaySet.cxx | 4 ++++ src/Brain/ModelChartTwo.cxx | 13 ++++++++++--- src/Brain/ModelChartTwo.h | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index ce67363de..dd03a4d1d 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -139,6 +139,10 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->copyData(overlaySet->getOverlay(i)); } + *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; + *m_chartAxisRight = *overlaySet->m_chartAxisRight; + *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; + m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 67341480b..d6a4a3bf9 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -1015,10 +1015,17 @@ ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); - + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); m_selectedChartTwoDataType[destinationTabIndex] = m_selectedChartTwoDataType[sourceTabIndex]; - //m_chartableMatrixFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixFileSelectionModel[sourceTabIndex]->getSelectedFile()); - //m_chartableMatrixSeriesFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixSeriesFileSelectionModel[sourceTabIndex]->getSelectedFile()); + + m_histogramChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, + destinationTabIndex); + m_lineSeriesChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, + destinationTabIndex); + m_matrixChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, + destinationTabIndex); + *m_chartTwoMatrixDisplayProperties[destinationTabIndex] = *m_chartTwoMatrixDisplayProperties[sourceTabIndex]; } diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index 2d8e213d1..e5df77055 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -148,6 +148,8 @@ namespace caret { /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; + mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + /** Chart Overlay sets for XX data type */ std::unique_ptr m_histogramChartOverlaySetArray; @@ -159,8 +161,6 @@ namespace caret { ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - //CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; //CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; -- GitLab From 38349a787c29f1193f724e878665b3d16a995a01 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Mar 2017 14:36:13 -0500 Subject: [PATCH 231/755] Continuing charting development. Fixed Overlay/Map Settings Editor so it is enabled when a matrix or histogram chart is displayed for editing of palette. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 31 +- src/Brain/BrowserTabContent.cxx | 66 +++- src/Brain/ChartTwoOverlay.cxx | 360 ++++-------------- src/Brain/ChartTwoOverlay.h | 19 +- src/Brain/ChartTwoOverlaySet.cxx | 7 +- src/GuiQt/AnnotationCoordinateWidget.cxx | 2 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 132 ++++--- ...ventOverlaySettingsEditorDialogRequest.cxx | 21 +- .../EventOverlaySettingsEditorDialogRequest.h | 27 +- src/GuiQt/MapYokingGroupComboBox.cxx | 14 +- src/GuiQt/OverlaySettingsEditorDialog.cxx | 235 ++++++++---- src/GuiQt/OverlaySettingsEditorDialog.h | 5 +- 12 files changed, 440 insertions(+), 479 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 6a228ea5a..24d787059 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -180,11 +180,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); if (numberOfOverlays > 0) { ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); - //if (topOverlay->isEnabled()) { - CaretMappableDataFile* cmdf = NULL; - int32_t mapIndex = -1; - topOverlay->getSelectionData(cmdf, mapIndex); - if (cmdf != NULL) { + CaretAssert(topOverlay); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + topOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + if (mapFile != NULL) { const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: @@ -206,7 +209,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, break; } } - //} } } @@ -280,9 +282,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() } CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = 1; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, - mapIndex); + selectedIndexType, + selectedIndex); if (mapFile == NULL) { continue; } @@ -291,16 +295,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); if (histogramChart->isValid()) { + CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); AString errorMessage; HistogramDrawingInfo* histogramDrawingInfo = new HistogramDrawingInfo(); - if (mapFile->getMapHistogramDrawingInfo(mapIndex, + if (mapFile->getMapHistogramDrawingInfo(selectedIndex, chartOverlay->isAllMapsSelected(), false, *histogramDrawingInfo, errorMessage)) { drawingInfo.push_back(new HistogramChartDrawingInfo(histogramDrawingInfo, histogramChart, - mapIndex, + selectedIndex, chartOverlay->getCartesianVerticalAxisLocation())); float bounds[4]; @@ -966,9 +971,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() } CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = 1; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, - mapIndex); + selectedIndexType, + selectedIndex); if (mapFile == NULL) { continue; } diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index f28cf5439..8ca72739e 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1466,18 +1466,20 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { - CaretMappableDataFile* overlayDataFile = NULL; - int32_t mapIndex; - chartOverlay->getSelectionData(overlayDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - if (overlayDataFile != NULL) { - if (overlayDataFile->isMappedWithPalette()) { + if (mapFile != NULL) { + if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); const int32_t mapIndex = 0; colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, - overlayDataFile, - mapIndex)); + mapFile, + selectedIndex)); } } } @@ -1654,6 +1656,24 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorisEnabled()) { switch (chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + + if (mapFile != NULL) { + if (mapFile->isMappedWithPalette()) { + AnnotationColorBar* colorBar = chartOverlay->getColorBar(); + if (colorBar->isDisplayed()) { + mapFiles.push_back(mapFile); + mapIndices.push_back(selectedIndex); + } + } + } + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -1661,16 +1681,18 @@ BrowserTabContent::getDisplayedPaletteMapFiles(std::vectorgetSelectionData(overlayDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - if (overlayDataFile != NULL) { - if (overlayDataFile->isMappedWithPalette()) { + if (mapFile != NULL) { + if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); if (colorBar->isDisplayed()) { - mapFiles.push_back(overlayDataFile); + mapFiles.push_back(mapFile); mapIndices.push_back(0); } } @@ -1845,13 +1867,15 @@ BrowserTabContent::getFilesDisplayedInTab(std::vector& displayed for (int32_t i = 0; i < numOverlays; i++) { const ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); if (chartOverlay->isEnabled()) { - CaretMappableDataFile* overlayDataFile = NULL; - int32_t mapIndex; - chartOverlay->getSelectionData(overlayDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - if (overlayDataFile != NULL) { - displayedDataFiles.insert(overlayDataFile); + if (mapFile != NULL) { + displayedDataFiles.insert(mapFile); } } } diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 1e0d538f3..78cb7e83b 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -151,20 +151,37 @@ ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) if (me != NULL) { if (me->isEnabled()) { CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = 0; + SelectedIndexType indexType = SelectedIndexType::INVALID; + int32_t index = 0; me->getSelectionData(mapFile, - mapIndex); + indexType, + index); if (mapFile != NULL) { descriptionOut.addLine("Overlay Index: " + AString::number(m_overlayIndex)); descriptionOut.addLine("File: "+ mapFile->getFileNameNoPath()); if (mapFile->hasMapAttributes()) { - if ((mapIndex >= 0) - && (mapIndex < mapFile->getNumberOfMaps())) { - descriptionOut.addLine("Map Index: " - + AString::number(mapIndex + 1)); - descriptionOut.addLine("Map Name: " - + mapFile->getMapName(mapIndex)); + switch (indexType) { + case SelectedIndexType::INVALID: + descriptionOut.addLine("Invalid selection type (none of map, row, column)"); + break; + case SelectedIndexType::COLUMN: + descriptionOut.addLine("Column " + + AString::number(index)); + break; + case SelectedIndexType::MAP: + if ((index >= 0) + && (index < mapFile->getNumberOfMaps())) { + descriptionOut.addLine("Map Index: " + + AString::number(index + 1)); + descriptionOut.addLine("Map Name: " + + mapFile->getMapName(index)); + } + break; + case SelectedIndexType::ROW: + descriptionOut.addLine("Row " + + AString::number(index)); + break; } } @@ -379,17 +396,21 @@ ChartTwoOverlay::getColorBar() const * * @param selectedMapFileOut * The selected map file. May be NULL. - * @param selectedMapIndexOut - * Index of selected map in the selected file. + * @param selectedIndexTypeOut + * Type of index selection + * @param selectedIndexOut + * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) const + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const { std::vector mapFiles; getSelectionData(mapFiles, selectedMapFileOut, - selectedMapIndexOut); + selectedIndexTypeOut, + selectedIndexOut); } /** @@ -402,58 +423,23 @@ ChartTwoOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, * The selected map file. May be NULL. * @param selectedFileMapNamesOut * Map names from selected file. - * @param selectedMapIndexOut - * Index of selected map in the selected file. + * @param selectedIndexTypeOut + * Type of index selection + * @param selectedIndexOut + * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, - CaretMappableDataFile* &selectedMapFileOut, - std::vector& selectedFileMapNamesOut, - int32_t& selectedMapIndexOut) const + CaretMappableDataFile* &selectedMapFileOut, + std::vector& selectedFileMapNamesOut, + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const { getSelectionDataPrivate(mapFilesOut, selectedMapFileOut, &selectedFileMapNamesOut, - selectedMapIndexOut); - -// CaretAssertToDoFatal(); -// selectedFileMapNamesOut.clear(); -// -// getSelectionData(mapFilesOut, -// selectedMapFileOut, -// selectedMapIndexOut); -// -// if (selectedMapFileOut == NULL) { -// return; -// } -// -// switch (m_chartDataType) { -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: -// { -// const int32_t numMaps = selectedMapFileOut->getNumberOfMaps(); -// for (int32_t i = 0; i < numMaps; i++) { -// selectedFileMapNamesOut.push_back(selectedMapFileOut->getMapName(i)); -// } -// } -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: -// { -// ChartableTwoFileDelegate* chartDelegate = selectedMapFileOut->getChartingDelegate(); -// const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); -// CaretAssert(matrixChart); -// int32_t numRows = 0; -// int32_t numCols = 0; -// matrixChart->getMatrixDimensions(numRows, numCols); -// for (int32_t i = 0; i < numRows; i++) { -// selectedFileMapNamesOut.push_back("Row " + QString::number(i + 1)); -// } -// } -// break; -// } + selectedIndexTypeOut, + selectedIndexOut); } /** @@ -464,169 +450,24 @@ ChartTwoOverlay::getSelectionData(std::vector& mapFilesO * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. - * @param selectedMapIndexOut - * Index of selected map in the selected file. + * @param selectedIndexTypeOut + * Type of index selection + * @param selectedIndexOut + * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) const + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const { getSelectionDataPrivate(mapFilesOut, selectedMapFileOut, NULL, - selectedMapIndexOut); + selectedIndexTypeOut, + selectedIndexOut); } -///** -// * Return the selection information. This method is typically -// * called to update the user-interface. -// * -// * @param mapFilesOut -// * Contains all map files that can be selected. -// * @param selectedMapFileOut -// * The selected map file. May be NULL. -// * @param selectedMapIndexOut -// * Index of selected map in the selected file. -// */ -//void -//ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, -// CaretMappableDataFile* &selectedMapFileOut, -// int32_t& selectedMapIndexOut) -//{ -// mapFilesOut.clear(); -// selectedMapFileOut = NULL; -// selectedMapIndexOut = -1; -// -// /** -// * Get the data files. -// */ -// std::vector allDataFiles; -// EventCaretMappableDataFilesGet eventGetMapDataFiles; -// EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); -// eventGetMapDataFiles.getAllFiles(allDataFiles); -// -// /* -// * Use only those data files that meet criteria. -// */ -// for (auto mapFile : allDataFiles) { -// CaretAssert(mapFile); -// ChartableTwoFileDelegate* chartingFile = mapFile->getChartingDelegate(); -// if (chartingFile->isChartingSupported()) { -// bool useIt = false; -// -// std::vector chartCompoundDataTypes; -// chartingFile->getSupportedChartCompoundDataTypes(chartCompoundDataTypes); -// -// for (auto& compoundType : chartCompoundDataTypes) { -// if (m_chartDataType == compoundType.getChartDataType()) { -// if (m_overlayIndex == 0) { -// /* -// * The first overlay displays ALL files that match the -// * enumerated chart type -// */ -// useIt = true; -// } -// else { -// if (m_chartCompoundDataType == compoundType) { -// /* -// * If not the first overlay, the enumerated type -// * and dimensions must also match -// */ -// useIt = true; -// } -// } -// } -// } -// -// if (useIt) { -// mapFilesOut.push_back(mapFile); -// } -// } -// } -// -// /* -// * Does selected data file still no longer exist? -// */ -// if (std::find(mapFilesOut.begin(), -// mapFilesOut.end(), -// m_selectedMapFile) == mapFilesOut.end()) { -// /* -// * Invalidate seleted file and disable yoking since -// * the selected file will change. -// */ -// m_selectedMapFile = NULL; -// m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; -// } -// -// /* -// * If selected data file is valid, see if selected -// * map is still valid. If not, use first map. -// */ -// if (m_selectedMapFile != NULL) { -// if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { -// m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; -// } -// if (m_selectedMapIndex < 0) { -// m_selectedMapIndex = 0; -// } -// } -// else { -// /* -// * Use first map in first file that has one or more maps. -// */ -// if (m_selectedMapFile == NULL) { -// if (mapFilesOut.empty() == false) { -// for (std::vector::iterator iter = mapFilesOut.begin(); -// iter != mapFilesOut.end(); -// iter++) { -// CaretMappableDataFile* mapTypeFile = *iter; -// if (mapTypeFile->getNumberOfMaps() > 0) { -// m_selectedMapFile = mapTypeFile; -// m_selectedMapIndex = 0; -// break; -// } -// } -// } -// } -// } -// -// selectedMapFileOut = m_selectedMapFile; -// if (selectedMapFileOut != NULL) { -// // /* -// // * Update for overlay yoking -// // */ -// // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { -// // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); -// // if ((yokeMapIndex >= 0) -// // && (yokeMapIndex < selectedMapFileOut->getNumberOfMaps())) { -// // m_selectedMapIndex = yokeMapIndex; -// // } -// // else if (yokeMapIndex >= selectedMapFileOut->getNumberOfMaps()) { -// // m_selectedMapIndex = selectedMapFileOut->getNumberOfMaps() - 1; -// // } -// // } -// // -// selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); -// } -// -// /* -// * Update the compound data type if this is the FIRST OVERLAY -// */ -// if (m_overlayIndex == 0) { -// if (m_selectedMapFile != NULL) { -// ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); -// CaretAssert(chartFile); -// chartFile->getChartCompoundDataTypeForChartDataType(m_chartDataType, -// m_chartCompoundDataType); -// } -// CaretAssert(m_parentChartTwoOverlaySet); -// m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); -// } -// //If selected type changes, need to update other overlays in the overlay set with -// //the selected data type} -//} - /** * Return the selection information. This method is typically * called to update the user-interface. @@ -642,13 +483,15 @@ ChartTwoOverlay::getSelectionData(std::vector& mapFilesO */ void ChartTwoOverlay::getSelectionDataPrivate(std::vector& mapFilesOut, - CaretMappableDataFile* &selectedMapFileOut, - std::vector* selectedFileMapNamesOut, - int32_t& selectedMapIndexOut) const + CaretMappableDataFile* &selectedMapFileOut, + std::vector* selectedFileMapNamesOut, + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const { mapFilesOut.clear(); selectedMapFileOut = NULL; - selectedMapIndexOut = -1; + selectedIndexTypeOut = SelectedIndexType::INVALID; + selectedIndexOut = -1; if (selectedFileMapNamesOut != NULL) { selectedFileMapNamesOut->clear(); } @@ -714,38 +557,6 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } -// /* -// * If selected data file is valid, see if selected -// * map is still valid. If not, use first map. -// */ -// if (m_selectedMapFile != NULL) { -// if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { -// m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; -// } -// if (m_selectedMapIndex < 0) { -// m_selectedMapIndex = 0; -// } -// } -// else { -// /* -// * Use first map in first file that has one or more maps. -// */ -// if (m_selectedMapFile == NULL) { -// if (mapFilesOut.empty() == false) { -// for (std::vector::iterator iter = mapFilesOut.begin(); -// iter != mapFilesOut.end(); -// iter++) { -// CaretMappableDataFile* mapTypeFile = *iter; -// if (mapTypeFile->getNumberOfMaps() > 0) { -// m_selectedMapFile = mapTypeFile; -// m_selectedMapIndex = 0; -// break; -// } -// } -// } -// } -// } - /* * If no file selected, select the first valid file */ @@ -792,7 +603,8 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma if (m_selectedHistogramMapIndex < 0) { m_selectedHistogramMapIndex = 0; } - selectedMapIndexOut = m_selectedHistogramMapIndex; + selectedIndexTypeOut = SelectedIndexType::MAP; + selectedIndexOut = m_selectedHistogramMapIndex; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: @@ -820,14 +632,16 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma numMaps = numCols; namePrefix = "Column "; if ( ! columnIndices.empty()) { - selectedMapIndexOut = columnIndices[0]; + selectedIndexTypeOut = SelectedIndexType::COLUMN; + selectedIndexOut = columnIndices[0]; } break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: numMaps = numRows; namePrefix = "Row "; if ( ! rowIndices.empty()) { - selectedMapIndexOut = rowIndices[0]; + selectedIndexTypeOut = SelectedIndexType::ROW; + selectedIndexOut = rowIndices[0]; } break; } @@ -842,39 +656,9 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma } break; } - -// /* -// * If selected data file is valid, see if selected -// * map is still valid. If not, use first map. -// */ -// if (m_selectedMapFile != NULL) { -// if (m_selectedHistogramMapIndex >= numMaps) { -// m_selectedHistogramMapIndex = numMaps - 1; -// } -// if (m_selectedHistogramMapIndex < 0) { -// m_selectedHistogramMapIndex = 0; -// } -// } } selectedMapFileOut = m_selectedMapFile; -// if (selectedMapFileOut != NULL) { -// // /* -// // * Update for overlay yoking -// // */ -// // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { -// // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); -// // if ((yokeMapIndex >= 0) -// // && (yokeMapIndex < numMaps)) { -// // m_selectedMapIndex = yokeMapIndex; -// // } -// // else if (yokeMapIndex >= numMaps) { -// // m_selectedMapIndex = numMaps - 1; -// // } -// // } -// // -// selectedMapIndexOut = m_selectedHistogramMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); -// } /* * Update the compound data type if this is the FIRST OVERLAY @@ -889,8 +673,6 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma CaretAssert(m_parentChartTwoOverlaySet); m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); } - //If selected type changes, need to update other overlays in the overlay set with - //the selected data type} } /** @@ -949,9 +731,12 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, * selected file and map index and update if needed * (such as a valid map index). */ - CaretMappableDataFile* filePointer = NULL; - int32_t mapIndex = -1; - getSelectionData(filePointer, mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + getSelectionData(mapFile, + selectedIndexType, + selectedIndex); } /* @@ -980,9 +765,10 @@ ChartTwoOverlay::isAllMapsSupported() const case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { CaretMappableDataFile* cmdf = NULL; + SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = 0; - getSelectionData(cmdf, + indexType, mapIndex); if (cmdf != NULL) { @@ -1164,9 +950,11 @@ ChartTwoOverlay::saveToScene(const SceneAttributes* sceneAttributes, std::vector mapFiles; CaretMappableDataFile* selectedMapFile = NULL; //AString selectedMapUniqueID; + SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; int32_t selectedMapIndex; getSelectionData(mapFiles, selectedMapFile, + selectedIndexType, selectedMapIndex); AString sceneSelectedMapFileNameWithPath; @@ -1231,9 +1019,11 @@ ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, */ std::vector mapFiles; CaretMappableDataFile* unusedSelectedMapFile = NULL; + SelectedIndexType unusedSelectedIndexType = SelectedIndexType::INVALID; int32_t unusedSelectedMapIndex; getSelectionData(mapFiles, unusedSelectedMapFile, + unusedSelectedIndexType, unusedSelectedMapIndex); const AString selectedMapFileNameWithPath = sceneClass->getPathNameValue("sceneSelectedMapFileNameWithPath"); diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 157cdb8be..079c8a17e 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -42,6 +42,13 @@ namespace caret { class ChartTwoOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: + enum class SelectedIndexType { + INVALID, + MAP, + ROW, + COLUMN + }; + ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t overlayIndex); @@ -95,14 +102,17 @@ namespace caret { void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, - int32_t& selectedMapIndexOut) const; + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const; void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) const; + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const; void getSelectionData(CaretMappableDataFile* &selectedMapFileOut, - int32_t& selectedMapIndexOut) const; + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const; void setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex); @@ -141,7 +151,8 @@ namespace caret { void getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector* selectedFileMapNamesOut, - int32_t& selectedMapIndexOut) const; + SelectedIndexType& selectedIndexTypeOut, + int32_t& selectedIndexOut) const; void validateCartesianVerticalAxisLocation() const; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index dd03a4d1d..00c106eb2 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -657,8 +657,11 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const for (auto overlay : m_overlays) { if (overlay->isEnabled()) { CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = -1; - overlay->getSelectionData(mapFile, mapIndex); + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + overlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); if (mapFile != NULL) { showBottomFlag = true; switch (overlay->getCartesianVerticalAxisLocation()) { diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index b5027158a..905b7c8b1 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -454,8 +454,8 @@ AnnotationCoordinateWidget::valueChanged() if (updateUserInterfaceFlag) { EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, m_browserWindowIndex, - (ChartTwoOverlay*)NULL, NULL, + (CaretMappableDataFile*)NULL, -1).getPointer()); } } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 41f5d03ac..c3328f196 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -282,17 +282,20 @@ ChartTwoOverlayViewController::updateOverlaySettingsEditor() } CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = -1; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, - mapIndex); + selectedIndexType, + selectedIndex); if ((mapFile != NULL) - && (mapIndex >= 0)) { + && (selectedIndex >= 0)) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED, m_browserWindowIndex, m_chartOverlay, mapFile, - mapIndex); + selectedIndexType, + selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } @@ -446,16 +449,20 @@ ChartTwoOverlayViewController::enabledCheckBoxClicked(bool checked) const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - CaretMappableDataFile* myFile = NULL; - int32_t myIndex = -1; - m_chartOverlay->getSelectionData(myFile, - myIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - EventMapYokingSelectMap selectMapEvent(mapYoking, - myFile, - myIndex, - m_chartOverlay->isEnabled()); - EventManager::get()->sendEvent(selectMapEvent.getPointer()); + if (selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + mapFile, + selectedIndex, + m_chartOverlay->isEnabled()); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } } this->updateUserInterfaceAndGraphicsWindow(); @@ -535,16 +542,19 @@ ChartTwoOverlayViewController::settingsActionTriggered() return; } - CaretMappableDataFile* mapFile; - int32_t mapIndex = -1; + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, - mapIndex); + selectedIndexType, + selectedIndex); if (mapFile != NULL) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, m_browserWindowIndex, m_chartOverlay, mapFile, - mapIndex); + selectedIndexType, + selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } @@ -559,10 +569,12 @@ ChartTwoOverlayViewController::historyActionTriggered(bool) return; } - CaretMappableDataFile* mapFile; - int32_t mapIndex = -1; + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, - mapIndex); + selectedIndexType, + selectedIndex); std::cout << "History button clicked. Enabled=" << qPrintable(AString::fromBool(m_chartOverlay->isHistorySupported())) << std::endl; @@ -596,12 +608,14 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla std::vector dataFiles; CaretMappableDataFile* selectedFile = NULL; std::vector selectedFileMapNames; - int32_t selectedMapIndex = -1; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(dataFiles, selectedFile, selectedFileMapNames, - selectedMapIndex); + selectedIndexType, + selectedIndex); } /* @@ -673,7 +687,7 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla CaretAssertVectorIndex(selectedFileMapNames, i); m_mapRowOrColumnNameComboBox->addItem(selectedFileMapNames[i]); } - m_mapRowOrColumnNameComboBox->setCurrentIndex(selectedMapIndex); + m_mapRowOrColumnNameComboBox->setCurrentIndex(selectedIndex); /* * Spin box ranges [0, N-1] or [1, N] depending upon data @@ -694,7 +708,7 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla } m_mapRowOrColumnIndexSpinBox->setRange(mapIndexMinimumValue, mapIndexMaximumValue); - const int spinBoxIndex = selectedMapIndex + m_mapRowOrColumnIndexSpinBox->minimum(); + const int spinBoxIndex = selectedIndex + m_mapRowOrColumnIndexSpinBox->minimum(); m_mapRowOrColumnIndexSpinBox->setValue(spinBoxIndex); } m_mapRowOrColumnNameComboBox->blockSignals(false); @@ -1062,17 +1076,19 @@ void ChartTwoOverlayViewController::menuConstructionAboutToShow() { if (m_chartOverlay != NULL) { - CaretMappableDataFile* caretDataFile = NULL; - int32_t mapIndex = -1; - m_chartOverlay->getSelectionData(caretDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); QString menuText = "Reload Selected File"; - if (caretDataFile != NULL) { - if (caretDataFile->isModified()) { + if (mapFile != NULL) { + if (mapFile->isModified()) { QString suffix = " (MODIFIED)"; - if (caretDataFile->isModifiedPaletteColorMapping()) { - if ( ! caretDataFile->isModifiedExcludingPaletteColorMapping()) { + if (mapFile->isModifiedPaletteColorMapping()) { + if ( ! mapFile->isModifiedExcludingPaletteColorMapping()) { suffix = " (MODIFIED PALETTE)"; } } @@ -1135,13 +1151,15 @@ void ChartTwoOverlayViewController::menuCopyFileNameToClipBoard() { if (m_chartOverlay != NULL) { - CaretMappableDataFile* caretDataFile = NULL; - int32_t mapIndex = -1; - m_chartOverlay->getSelectionData(caretDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - if (caretDataFile != NULL) { - QApplication::clipboard()->setText(caretDataFile->getFileName().trimmed(), + if (mapFile != NULL) { + QApplication::clipboard()->setText(mapFile->getFileName().trimmed(), QClipboard::Clipboard); } } @@ -1154,15 +1172,21 @@ void ChartTwoOverlayViewController::menuCopyMapNameToClipBoard() { if (m_chartOverlay != NULL) { - CaretMappableDataFile* caretDataFile = NULL; - int32_t mapIndex = -1; - m_chartOverlay->getSelectionData(caretDataFile, - mapIndex); + std::vector allMapFiles; + std::vector indexNames; + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(allMapFiles, + mapFile, + indexNames, + selectedIndexType, + selectedIndex); - if (caretDataFile != NULL) { - if ((mapIndex >= 0) - && (mapIndex < caretDataFile->getNumberOfMaps())) { - QApplication::clipboard()->setText(caretDataFile->getMapName(mapIndex).trimmed(), + if (mapFile != NULL) { + if ((selectedIndex >= 0) + && (selectedIndex < static_cast(indexNames.size()))) { + QApplication::clipboard()->setText(indexNames[selectedIndex], QClipboard::Clipboard); } } @@ -1176,16 +1200,18 @@ void ChartTwoOverlayViewController::menuReloadFileTriggered() { if (m_chartOverlay != NULL) { - CaretMappableDataFile* caretDataFile = NULL; - int32_t mapIndex = -1; - m_chartOverlay->getSelectionData(caretDataFile, - mapIndex); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); - if (caretDataFile != NULL) { + if (mapFile != NULL) { AString username; AString password; - if (DataFile::isFileOnNetwork(caretDataFile->getFileName())) { + if (DataFile::isFileOnNetwork(mapFile->getFileName())) { const QString msg("This file is on the network. " "If accessing the file requires a username and " "password, enter it here. Otherwise, remove any " @@ -1205,7 +1231,7 @@ ChartTwoOverlayViewController::menuReloadFileTriggered() } EventDataFileReload reloadEvent(GuiManager::get()->getBrain(), - caretDataFile); + mapFile); reloadEvent.setUsernameAndPassword(username, password); EventManager::get()->sendEvent(reloadEvent.getPointer()); diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx index 3104f4570..c5252c6aa 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx @@ -39,14 +39,14 @@ using namespace caret; * Overlay for map editor. * @param mapFile * Caret Mappable Data File. - * @param mapIndex - * Map index in mapFile. + * @param selectedIndex + * Selected index in mapFile. */ EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, Overlay* overlay, CaretMappableDataFile* mapFile, - const int32_t mapIndex) + const int32_t selectedIndex) : Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), m_mode(mode) { @@ -54,7 +54,8 @@ m_mode(mode) m_overlay = overlay; m_chartOverlay = NULL; m_mapFile = mapFile; - m_mapIndex = mapIndex; + m_chartSelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + m_selectedIndex = selectedIndex; } /** @@ -68,14 +69,17 @@ m_mode(mode) * Overlay for map editor. * @param mapFile * Caret Mappable Data File. - * @param mapIndex - * Map index in mapFile. + * @param selectedIndexType + * Type of index selected in chart. + * @param selectedIndex + * Selected index in mapFile. */ EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, - const int32_t mapIndex) + ChartTwoOverlay::SelectedIndexType selectedIndexType, + const int32_t selectedIndex) : Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), m_mode(mode) { @@ -83,7 +87,8 @@ m_mode(mode) m_overlay = NULL; m_chartOverlay = chartOverlay; m_mapFile = mapFile; - m_mapIndex = mapIndex; + m_chartSelectedIndexType = selectedIndexType; + m_selectedIndex = selectedIndex; } /* diff --git a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h index c9fc37ccb..06689b115 100644 --- a/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h +++ b/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h @@ -21,7 +21,7 @@ */ /*LICENSE_END*/ - +#include "ChartTwoOverlay.h" #include "Event.h" namespace caret { @@ -43,13 +43,14 @@ namespace caret { const int32_t browserWindowIndex, Overlay* overlay, CaretMappableDataFile* mapFile, - const int32_t mapIndex); + const int32_t selectedIndex); EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, - const int32_t mapIndex); + ChartTwoOverlay::SelectedIndexType selectedIndexType, + const int32_t selectedIndex); virtual ~EventOverlaySettingsEditorDialogRequest(); @@ -68,10 +69,10 @@ namespace caret { */ CaretMappableDataFile* getCaretMappableDataFile() const { return m_mapFile; } - /** - * @return Index of map in the map file - */ - int32_t getMapIndex() const { return m_mapIndex; } +// /** +// * @return Index of selection in the map file +// */ +// int32_t getSelectedIndex() const { return m_selectedIndex; } /** * @return The overlay for the editor. @@ -93,6 +94,11 @@ namespace caret { */ const ChartTwoOverlay* getChartTwoOverlay() const { return m_chartOverlay; } +// /** +// * @return The type of index for chart file +// */ +// ChartTwoOverlay::SelectedIndexType getChartSelectedIndexType() const { return m_chartSelectedIndexType; } + private: EventOverlaySettingsEditorDialogRequest(const EventOverlaySettingsEditorDialogRequest&); @@ -113,8 +119,11 @@ namespace caret { /** Map file containing map whose color palette is edited */ CaretMappableDataFile* m_mapFile; - /** Index of map in the map file */ - int32_t m_mapIndex; + /** Selected index type for charts */ + ChartTwoOverlay::SelectedIndexType m_chartSelectedIndexType; + + /** Selected index in the map file */ + int32_t m_selectedIndex; }; } // namespace diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index 9b161f58b..55f263686 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -208,21 +208,25 @@ MapYokingGroupComboBox::validateYokingChange(ChartTwoOverlay* chartOverlay) const MapYokingGroupEnum::Enum previousMapYokingGroup = chartOverlay->getMapYokingGroup(); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); CaretMappableDataFile* mapFile = NULL; - int32_t mapIndex = -1; - chartOverlay->getSelectionData(mapFile, mapIndex); + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); bool selectionStatus = chartOverlay->isEnabled(); if ((mapFile != NULL) - && (mapIndex >= 0)) { + && (selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP) + && (selectedIndex >= 0)) { const YokeValidationResult result = validateYoking(mapFile, - mapIndex, + selectedIndex, selectionStatus); switch (result) { case YOKE_VALIDATE_RESULT_ACCEPT: chartOverlay->setEnabled(selectionStatus); chartOverlay->setSelectionData(mapFile, - mapIndex); + selectedIndex); chartOverlay->setMapYokingGroup(newYokingGroup); break; case YOKE_VALIDATE_RESULT_OFF: diff --git a/src/GuiQt/OverlaySettingsEditorDialog.cxx b/src/GuiQt/OverlaySettingsEditorDialog.cxx index d45f29bc2..757b74a9e 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.cxx +++ b/src/GuiQt/OverlaySettingsEditorDialog.cxx @@ -79,9 +79,10 @@ OverlaySettingsEditorDialog::OverlaySettingsEditorDialog(QWidget* parent) this->setDeleteWhenClosed(false); m_caretMappableDataFile = NULL; - m_mapIndex = -1; + m_selectedMapFileIndex = -1; m_brainordinateOverlay = NULL; m_chartOverlay = NULL; + m_chartOverlaySelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; /* * No apply button @@ -282,18 +283,17 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv m_brainordinateOverlay = brainordinateOverlay; m_chartOverlay = chartOverlay; -// m_caretMappableDataFile = caretMappableDataFile; -// m_mapFileIndex = mapFileIndex; - m_caretMappableDataFile = NULL; - m_mapIndex = -1; + m_chartOverlaySelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + m_selectedMapFileIndex = -1; if (m_brainordinateOverlay != NULL) { m_brainordinateOverlay->getSelectionData(m_caretMappableDataFile, - m_mapIndex); + m_selectedMapFileIndex); } if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(m_caretMappableDataFile, - m_mapIndex); + m_chartOverlaySelectedIndexType, + m_selectedMapFileIndex); } bool isLabelsValid = false; @@ -308,90 +308,169 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv QString mapName = ""; if (m_caretMappableDataFile != NULL) { - if ((m_mapIndex >= 0) - && (m_mapIndex < m_caretMappableDataFile->getNumberOfMaps())) { - /* - * Get name of file and map - */ - mapFileName = m_caretMappableDataFile->getFileNameNoPath(); - if (m_mapIndex >= 0) { - mapName = m_caretMappableDataFile->getMapName(m_mapIndex); - } - - /* - * Update layer widget - */ - m_layerWidget->updateContent(m_brainordinateOverlay); - - if (m_caretMappableDataFile->isMappedWithLabelTable()) { - if (m_caretMappableDataFile->getMapLabelTable(m_mapIndex) != NULL) { - /* - * Update label editor - */ - isLabelsValid = true; - m_labelsWidget->updateContent(m_brainordinateOverlay); + if (m_brainordinateOverlay != NULL) { + if ((m_selectedMapFileIndex >= 0) + && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { + /* + * Get name of file and map + */ + mapFileName = m_caretMappableDataFile->getFileNameNoPath(); + if (m_selectedMapFileIndex >= 0) { + mapName = m_caretMappableDataFile->getMapName(m_selectedMapFileIndex); } - } - - metadata = m_caretMappableDataFile->getMapMetaData(m_mapIndex); - if (metadata != NULL) { + /* - * TODO: Update metadata widget + * Update layer widget */ - //isMetadataValid = true; - } - - if (m_caretMappableDataFile->isMappedWithPalette()) { - PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(m_mapIndex); - if (paletteColorMapping != NULL) { + m_layerWidget->updateContent(m_brainordinateOverlay); + + if (m_caretMappableDataFile->isMappedWithLabelTable()) { + if (m_caretMappableDataFile->getMapLabelTable(m_selectedMapFileIndex) != NULL) { + /* + * Update label editor + */ + isLabelsValid = true; + m_labelsWidget->updateContent(m_brainordinateOverlay); + } + } + + metadata = m_caretMappableDataFile->getMapMetaData(m_selectedMapFileIndex); + if (metadata != NULL) { /* - * Update palette settings + * TODO: Update metadata widget */ - isPaletteValid = true; - m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, - m_mapIndex); - AnnotationColorBar* colorBar = NULL; - if (m_brainordinateOverlay != NULL) { - colorBar = m_brainordinateOverlay->getColorBar(); - } - else if (m_chartOverlay != NULL) { - colorBar = m_chartOverlay->getColorBar(); + //isMetadataValid = true; + } + + if (m_caretMappableDataFile->isMappedWithPalette()) { + PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(m_selectedMapFileIndex); + if (paletteColorMapping != NULL) { + /* + * Update palette settings + */ + isPaletteValid = true; + m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, + m_selectedMapFileIndex); + AnnotationColorBar* colorBar = NULL; + if (m_brainordinateOverlay != NULL) { + colorBar = m_brainordinateOverlay->getColorBar(); + } + else if (m_chartOverlay != NULL) { + colorBar = m_chartOverlay->getColorBar(); + } + m_colorBarWidget->updateContent(colorBar, + paletteColorMapping); } - m_colorBarWidget->updateContent(colorBar, - paletteColorMapping); } - } - - CiftiFiberTrajectoryFile* trajFile = dynamic_cast(m_caretMappableDataFile); - if (trajFile != NULL) { + + CiftiFiberTrajectoryFile* trajFile = dynamic_cast(m_caretMappableDataFile); + if (trajFile != NULL) { + /* + * Update trajectory + */ + isFiberTrajectoryValid = true; + m_fiberTrajectoryWidget->updateEditor(trajFile); + } + + CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); + if (parcelsFile != NULL) { + /* + * Update parcels + */ + isParcelsValid = true; + m_parcelsWidget->updateEditor(parcelsFile); + } + /* - * Update trajectory + * Is volume mappable */ - isFiberTrajectoryValid = true; - m_fiberTrajectoryWidget->updateEditor(trajFile); + if (m_caretMappableDataFile->isVolumeMappable()) { + if (isFiberTrajectoryValid) { + /* nothing */ + } + else { + isVolumeLayer = true; + } + } } - - CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); - if (parcelsFile != NULL) { + } + else if (m_chartOverlay != NULL) { + int32_t selectedMapIndex = -1; + bool mapTypeFlag = false; + switch (m_chartOverlaySelectedIndexType) { + case ChartTwoOverlay::SelectedIndexType::INVALID: + CaretAssert(0); + break; + case ChartTwoOverlay::SelectedIndexType::MAP: + if ((m_selectedMapFileIndex >= 0) + && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { + selectedMapIndex = m_selectedMapFileIndex; + mapTypeFlag = true; + } + break; + case ChartTwoOverlay::SelectedIndexType::COLUMN: + case ChartTwoOverlay::SelectedIndexType::ROW: + if (m_selectedMapFileIndex >= 0) { + if (m_caretMappableDataFile->getNumberOfMaps() == 1) { + m_selectedMapFileIndex = 0; + } + selectedMapIndex = m_selectedMapFileIndex; + } + break; + } + if ((selectedMapIndex >= 0) + && (selectedMapIndex < m_caretMappableDataFile->getNumberOfMaps())) { /* - * Update parcels + * Get name of file and map */ - isParcelsValid = true; - m_parcelsWidget->updateEditor(parcelsFile); - } - - /* - * Is volume mappable - */ - if (m_caretMappableDataFile->isVolumeMappable()) { - if (isFiberTrajectoryValid) { - /* nothing */ + mapFileName = m_caretMappableDataFile->getFileNameNoPath(); + if (m_selectedMapFileIndex >= 0) { + mapName = m_caretMappableDataFile->getMapName(selectedMapIndex); } - else { - isVolumeLayer = true; + + if (mapTypeFlag) { + metadata = m_caretMappableDataFile->getMapMetaData(selectedMapIndex); + if (metadata != NULL) { + /* + * TODO: Update metadata widget + */ + //isMetadataValid = true; + } + } + + if (m_caretMappableDataFile->isMappedWithPalette()) { + PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(selectedMapIndex); + if (paletteColorMapping != NULL) { + /* + * Update palette settings + */ + isPaletteValid = true; + m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, + selectedMapIndex); + AnnotationColorBar* colorBar = NULL; + if (m_brainordinateOverlay != NULL) { + colorBar = m_brainordinateOverlay->getColorBar(); + } + else if (m_chartOverlay != NULL) { + colorBar = m_chartOverlay->getColorBar(); + } + m_colorBarWidget->updateContent(colorBar, + paletteColorMapping); + } + } + + CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); + if (parcelsFile != NULL) { + /* + * Update parcels + */ + isParcelsValid = true; + m_parcelsWidget->updateEditor(parcelsFile); } } - + } + else { + CaretAssert(0); } } @@ -578,9 +657,9 @@ OverlaySettingsEditorDialog::editLabelTablePushButtonClicked() { if (m_caretMappableDataFile != NULL) { if (m_caretMappableDataFile->isMappedWithLabelTable()) { - if (m_mapIndex >= 0) { + if (m_selectedMapFileIndex >= 0) { GiftiLabelTableEditor labelTableEditor(m_caretMappableDataFile, - m_mapIndex, + m_selectedMapFileIndex, "Edit Labels", GiftiLabelTableEditor::OPTION_ADD_APPLY_BUTTON, m_editLabelTablePushButton); diff --git a/src/GuiQt/OverlaySettingsEditorDialog.h b/src/GuiQt/OverlaySettingsEditorDialog.h index e57b215da..7d60ab254 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.h +++ b/src/GuiQt/OverlaySettingsEditorDialog.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include "ChartTwoOverlay.h" #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" @@ -100,7 +101,9 @@ namespace caret { ChartTwoOverlay* m_chartOverlay; - int32_t m_mapIndex; + ChartTwoOverlay::SelectedIndexType m_chartOverlaySelectedIndexType; + + int32_t m_selectedMapFileIndex; MapSettingsPaletteColorMappingWidget* m_paletteColorMappingWidget; -- GitLab From 68d67a1181adffc71035b07a114d2882bc7864de Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Mar 2017 16:01:14 -0500 Subject: [PATCH 232/755] Continuing charting development. Fix color bar display when viewing charts. Adjust heigh of chart viewport so that the color bar does not overlap the chart. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 92 ++++++++++++++----- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 9 +- .../BrainOpenGLChartTwoDrawingInterface.h | 22 +---- src/Brain/BrainOpenGLFixedPipeline.cxx | 14 +-- src/Brain/BrowserTabContent.cxx | 25 ++++- 5 files changed, 101 insertions(+), 61 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 24d787059..0a53f2375 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -25,11 +25,13 @@ #include +#include "AnnotationColorBar.h" #include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLTextRenderInterface.h" +#include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" @@ -85,57 +87,97 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * * @param brain * Brain. - * @parm chartTwoModel - * The chart two model in the window. + * @param browserTabContent + * Content of the browser tab. + * @param chartTwoModel + * The chart two model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. - * @param textRenderer - * Text rendering. - * @param translation - * The chart's translation. - * @param zooming - * The chart's zooming. - * @param chartOverlaySet - * Chart overlay set that is drawn. * @param selectionItemDataType * Selected data type. * @param viewport * Viewport for the chart. - * @param tabIndex - * Index of the tab. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, + BrowserTabContent* browserTabContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, - BrainOpenGLTextRenderInterface* textRenderer, - const float translation[3], - const float zooming, - ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4], - const int32_t tabIndex) + const int32_t viewport[4]) { + CaretAssert(brain); + CaretAssert(browserTabContent); + CaretAssert(chartTwoModel); + CaretAssert(fixedPipelineDrawing); m_brain = brain; m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; - m_textRenderer = textRenderer; - m_translation[0] = translation[0]; - m_translation[1] = translation[1]; - m_translation[2] = translation[2]; - m_zooming = zooming; - m_chartOverlaySet = chartOverlaySet; + m_textRenderer = fixedPipelineDrawing->getTextRenderer(); + m_translation[0] = 0.0; + m_translation[1] = 0.0; + m_translation[2] = 0.0; + browserTabContent->getTranslation(m_translation); + m_tabIndex = browserTabContent->getTabNumber(); + m_zooming = browserTabContent->getScaling(); + m_chartOverlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabIndex); m_selectionItemDataType = selectionItemDataType; m_viewport[0] = viewport[0]; m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; - m_tabIndex = tabIndex; m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); + /* + * Find color bars for this tab and decrease height of + * viewport so chart is above color bars. + */ + std::vector colorBars; + browserTabContent->getAnnotationColorBars(colorBars); + if ( ! colorBars.empty()) { + int heightOfAllColorBars = 0; + + for (auto cb : colorBars) { + bool useItFlag = false; + switch (cb->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::PIXELS: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + useItFlag = true; + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + + if (useItFlag) { + float bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; + float viewportXYZ[3] = { 5.0, 5.0, 0.0 }; + const bool boundsValid = cb->getShapeBounds(m_viewport[2], m_viewport[3], + viewportXYZ, + bottomLeft, bottomRight, topRight, topLeft); + if (boundsValid) { + heightOfAllColorBars += (topRight[1] - bottomRight[1]); + } + } + } + + if (heightOfAllColorBars > 0) { + const int32_t extraSpace = 5; + heightOfAllColorBars += extraSpace; + if (heightOfAllColorBars < viewport[3]) { + m_viewport[1] += heightOfAllColorBars; + m_viewport[3] -= heightOfAllColorBars; + } + } + } + bool drawHistogramFlag = true; bool drawLineSeriesFlag = true; bool drawMatrixFlag = true; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 89ebf5877..26197e959 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -29,6 +29,7 @@ namespace caret { class CaretPreferences; class ChartTwoCartesianAxis; + class ChartTwoOverlaySet; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; @@ -45,15 +46,11 @@ namespace caret { virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, + BrowserTabContent* browserTabContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, - BrainOpenGLTextRenderInterface* textRenderer, - const float translation[3], - const float zooming, - ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4], - const int32_t tabIndex) override; + const int32_t viewport[4]) override; // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 32f74cbbd..076a04bbf 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -31,7 +31,7 @@ namespace caret { class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; - class ChartTwoOverlaySet; + class BrowserTabContent; class ModelChartTwo; class BrainOpenGLChartTwoDrawingInterface { @@ -46,35 +46,23 @@ namespace caret { * * @param brain * Brain. + * @param browserTabContent + * Content of the browser tab. * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. - * @param textRenderer - * Text rendering. - * @param translation - * The chart's translation. - * @param zooming - * The chart's zooming. - * @param chartOverlaySet - * Chart overlay set that is drawn. * @param selectionItemDataType * Selected data type. * @param viewport * Viewport for the chart. - * @param tabIndex - * Index of the tab. */ virtual void drawChartOverlaySet(Brain* brain, + BrowserTabContent* browserTabContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, - BrainOpenGLTextRenderInterface* textRenderer, - const float translation[3], - const float zooming, - ChartTwoOverlaySet* chartOverlaySet, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4], - const int32_t tabIndex) = 0; + const int32_t viewport[4]) = 0; // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 124d1509f..e68a3d0e8 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5382,23 +5382,13 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, CaretAssert(browserTabContent); CaretAssert(chartModel); - const int32_t tabIndex = browserTabContent->getTabNumber(); - - float translation[3]; - browserTabContent->getTranslation(translation); BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; - const float zooming = browserTabContent->getScaling(); - chartDrawing.drawChartOverlaySet(m_brain, + browserTabContent, chartModel, this, - getTextRenderer(), - translation, - zooming, - chartModel->getChartTwoOverlaySet(tabIndex), SelectionItemDataTypeEnum::CHART_DATA_SERIES, - viewport, - tabIndex); + viewport); } /** diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 8ca72739e..9dee387dd 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1459,6 +1459,24 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo if (chartOverlay->isEnabled()) { switch (chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + + + if (mapFile != NULL) { + if (mapFile->isMappedWithPalette()) { + AnnotationColorBar* colorBar = chartOverlay->getColorBar(); + colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, + mapFile, + selectedIndex)); + } + } + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -1473,10 +1491,15 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo selectedIndexType, selectedIndex); + if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); - const int32_t mapIndex = 0; + /* + * Matrix is all maps and uses map index 0 + */ + selectedIndex = 0; + colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, mapFile, selectedIndex)); -- GitLab From a2b6854f676bc58d17e6bc18c3972e75fb129ba0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 23 Mar 2017 12:14:03 -0500 Subject: [PATCH 233/755] Fixed for histogram chart. No longer inserts a 'zero' bucket into the histogram when zeros are not displayed. Instead, Palette coloring is ALWAYS applied to the histogram since the palette coloring will use an alpha value of zero for data not colored. If the user is using a solid color, it will be later applied and it will not modify the alpha values so that non-displayed histogram bars remain hidden. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1 + src/Files/CaretMappableDataFile.cxx | 542 +++++++++++++++--- .../MapSettingsPaletteColorMappingWidget.cxx | 54 +- 3 files changed, 498 insertions(+), 99 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0a53f2375..229223a95 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -723,6 +723,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab CaretAssertVectorIndex(xValues, i + 1); float left = xValues[i]; float right = xValues[i + 1]; + CaretAssert(right >= left); float bottom = 0; CaretAssertVectorIndex(yValues, i); float top = yValues[i]; diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 9f5668c21..abcfb6ba3 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -824,9 +824,9 @@ CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformatio bool CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, const bool useDataFromAllMapsFlag, - const bool addEndPointForQwtFlag, - HistogramDrawingInfo& histogramDrawingInfoOut, - AString& errorMessageOut) + const bool addEndPointForQwtFlag, + HistogramDrawingInfo& histogramDrawingInfoOut, + AString& errorMessageOut) { errorMessageOut.clear(); histogramDrawingInfoOut.reset(); @@ -924,7 +924,7 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, } break; } - + /* * Remove data that is not displayed */ @@ -1010,111 +1010,90 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, } int32_t numberOfDataPoints = (addEndPointForQwtFlag - ? (numBucketValues + 1) - : numBucketValues); + ? (numBucketValues + 1) + : numBucketValues); + /* + * Set up vectors for X/Y values and coloring + */ histogramDrawingInfoOut.initialize(numberOfDataPoints); + const float stepX = (valueRangeX + / static_cast(numBucketValues)); + for (int64_t ix = 0; ix < numBucketValues; ix++) { + float valueX = (minValueX + + (ix * stepX)); + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); + histogramDrawingInfoOut.m_dataX[ix] = valueX; + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, ix); + CaretAssertVectorIndex(histogramBuckets, ix); + histogramDrawingInfoOut.m_dataY[ix] = histogramBuckets[ix]; + } if (addEndPointForQwtFlag) { /* * Duplicate last point for Qwt or else Qwt may not draw correctly */ - histogramBuckets.push_back(histogramBuckets[histogramBuckets.size() - 1]); + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, numBucketValues); + histogramDrawingInfoOut.m_dataX[numBucketValues] = histogramDrawingInfoOut.m_dataX[numBucketValues - 1]; + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, numBucketValues); + histogramDrawingInfoOut.m_dataY[numBucketValues] = histogramDrawingInfoOut.m_dataY[numBucketValues - 1]; } - histogramDrawingInfoOut.m_dataY = histogramBuckets; - const bool hideZerosFlag = ( ! paletteColorMapping->isDisplayZeroDataFlag()); - const float stepX = ((valueRangeX) - / static_cast(numberOfDataPoints)); - /* - * Need to find zero (or near zero if there is not an exact zero value) + * Adjust X-value of first and last points */ - int32_t indexZeroX = -1; - float indexZeroDistance = std::numeric_limits::max(); - - for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { - float valueX = (minValueX - + (ix * stepX)); - - if (hideZerosFlag) { - const float zeroDistance = ((valueX >= 0) ? valueX : -valueX); - if (zeroDistance < indexZeroDistance) { - indexZeroX = ix; - indexZeroDistance = zeroDistance; - } - } - - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); - histogramDrawingInfoOut.m_dataX[ix] = valueX; - } - - if (indexZeroX >= 0) { - const float posZero = 0.05; - const float negZero = -posZero; - int32_t negZeroIndex = -1; - - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, indexZeroX); - const float xValue = histogramDrawingInfoOut.m_dataX[indexZeroX]; - if (xValue <= 0.0) { - negZeroIndex = indexZeroX; - } - else { - negZeroIndex = indexZeroX - 1; - } - - if ((negZeroIndex >= 0) - && (negZeroIndex < (numberOfDataPoints - 1))) { - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, negZeroIndex + 1); - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, negZeroIndex + 1); - histogramDrawingInfoOut.m_dataX[negZeroIndex] = negZero; - histogramDrawingInfoOut.m_dataY[negZeroIndex] = 0.0; - - histogramDrawingInfoOut.m_dataX.insert(histogramDrawingInfoOut.m_dataX.begin() + negZeroIndex + 1, posZero); - histogramDrawingInfoOut.m_dataY.insert(histogramDrawingInfoOut.m_dataY.begin() + negZeroIndex + 1, 0.0); - } - numberOfDataPoints = static_cast(histogramDrawingInfoOut.m_dataX.size()); - CaretAssert(histogramDrawingInfoOut.m_dataX.size() == histogramDrawingInfoOut.m_dataY.size()); - histogramDrawingInfoOut.m_dataRGBA.resize(numberOfDataPoints * 4); - } - -// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); -// std::cout << "value " << ix << ": " << histogramDrawingInfoOut.m_dataX[ix] << "," << histogramDrawingInfoOut.m_dataX[ix] << std::endl; -// } - histogramDrawingInfoOut.m_dataX[0] = minValueX; histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValueX; + + /* + * Always color using palette and it will assign a zero alpha + * value to buckets that do not fall in the palette negative + * postive min/max ranges. + */ const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; + float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + xValuesArray, + xValuesArray, + numberOfDataPoints, + dataRGBA, + true); // ignore thresholding + /* + * If bucket is not colored (zero alpha) set bucket height to zero + */ + for (int32_t i = 0; i < numberOfDataPoints; i++) { + const int32_t alphaIndex = i * 4 + 3; + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, alphaIndex); + if (histogramDrawingInfoOut.m_dataRGBA[alphaIndex] <= 0.0) { + CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, i); + histogramDrawingInfoOut.m_dataY[i] = 0.0; + } + } + + /* + * If selected, apply solid color to histogram + */ const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); if (histogramColor != CaretColorEnum::CUSTOM) { float rgba[4]; CaretColorEnum::toRGBAFloat(histogramColor, rgba); - rgba[3] = 1.0; + /* + * Note: DO NOT override alpha value that was set + * using palette coloring + */ for (int32_t i = 0; i < numberOfDataPoints; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, i4 + 3); histogramDrawingInfoOut.m_dataRGBA[i4] = rgba[0]; histogramDrawingInfoOut.m_dataRGBA[i4+1] = rgba[1]; histogramDrawingInfoOut.m_dataRGBA[i4+2] = rgba[2]; - histogramDrawingInfoOut.m_dataRGBA[i4+3] = rgba[3]; } } - else { - float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; - - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - xValuesArray, - xValuesArray, - numberOfDataPoints, - dataRGBA, - true); // ignore thresholding - } bool setThresholdingFlag = false; switch (paletteColorMapping->getThresholdType()) { @@ -1155,7 +1134,7 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = minX; histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; - + histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ.resize(12); histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[0] = threshMaxValue; histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[1] = minY; @@ -1208,6 +1187,407 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, return false; } +///** +// * Get the histogram bounds, heights, and RGBA coloring. +// * +// * @param mapIndex +// * Index of map. +// * @param useDataFromAllMapsFlag +// * If true, data from ALL maps is used not just the map specified by map index. +// * @param addEndPointForQwtFlag +// * If true, add point at end for drawing with Qwt. +// * @param histogramDrawingInfoOut +// * Output containing histogram drawing information. +// * @return +// * True if output data is valid, else false. +// */ +//bool +//CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, +// const bool useDataFromAllMapsFlag, +// const bool addEndPointForQwtFlag, +// HistogramDrawingInfo& histogramDrawingInfoOut, +// AString& errorMessageOut) +//{ +// errorMessageOut.clear(); +// histogramDrawingInfoOut.reset(); +// +// if ( ! isMappedWithPalette()) { +// errorMessageOut = "File is not mapped with palette!"; +// return false; +// } +// if ((mapIndex < 0) +// || (mapIndex >= getNumberOfMaps())) { +// CaretAssertMessage(0, "Invalid map index."); +// errorMessageOut = "Invalid map index."; +// return false; +// } +// +// PaletteColorMapping* paletteColorMapping = getMapPaletteColorMapping(mapIndex); +// CaretAssert(paletteColorMapping); +// +// EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); +// EventManager::get()->sendEvent(paletteEvent.getPointer()); +// const Palette* palette = paletteEvent.getPalette(); +// if (palette == NULL) { +// errorMessageOut = ("Unable to find palette named: " +// + paletteColorMapping->getSelectedPaletteName()); +// return false; +// } +// +// FastStatistics* statistics = NULL; +// if (useDataFromAllMapsFlag) { +// statistics = const_cast(getFileFastStatistics()); +// } +// else { +// switch (getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// statistics = const_cast(getFileFastStatistics()); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// statistics = const_cast(getMapFastStatistics(mapIndex)); +// break; +// } +// } +// +// /* +// * Statistics may be NULL for connectivity files (dense, dense dynamic) +// * that have not yet loaded any data caused by the user clicking +// * brainordinates. +// */ +// if (statistics == NULL) { +// return false; +// } +// +// CaretAssert(statistics); +// float mostPos = 0.0; +// float leastPos = 0.0; +// float leastNeg = 0.0; +// float mostNeg = 0.0; +// bool matchFlag = false; +// +// switch (paletteColorMapping->getHistogramRangeMode()) { +// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: +// { +// float dummy; +// statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); +// } +// break; +// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: +// { +// matchFlag = true; +// switch (paletteColorMapping->getScaleMode()) { +// case PaletteScaleModeEnum::MODE_AUTO_SCALE: +// mostPos = statistics->getMax(); +// leastPos = 0.0; +// leastNeg = 0.0; +// mostNeg = statistics->getMin(); +// break; +// case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: +// mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); +// leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); +// leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); +// mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); +// break; +// case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: +// mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); +// leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); +// leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); +// mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); +// break; +// case PaletteScaleModeEnum::MODE_USER_SCALE: +// mostPos = paletteColorMapping->getUserScalePositiveMaximum(); +// leastPos = paletteColorMapping->getUserScalePositiveMinimum(); +// leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); +// mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); +// break; +// } +// } +// break; +// } +// +// /* +// * Remove data that is not displayed +// */ +// bool isZeroIncluded = true; +// const Histogram* histogram = NULL; +// if (matchFlag) { +// isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); +// +// if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { +// mostNeg = 0.0; +// leastNeg = 0.0; +// } +// if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { +// mostPos = 0.0; +// leastPos = 0.0; +// } +// +// if (useDataFromAllMapsFlag) { +// histogram = getFileHistogram(mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// } +// else { +// switch (getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// histogram = getFileHistogram(mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// histogram = getMapHistogram(mapIndex, +// mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// break; +// } +// } +// } +// else { +// if (useDataFromAllMapsFlag) { +// histogram = getFileHistogram(); +// } +// else { +// switch (getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// histogram = getFileHistogram(); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// histogram = getMapHistogram(mapIndex); +// break; +// } +// } +// } +// +// CaretAssert(histogram); +// +// +// float minValueX = 0.0; +// float maxValueX = 0.0; +// histogram->getRange(minValueX, +// maxValueX); +// const float valueRangeX = maxValueX - minValueX; +// if (valueRangeX <= 0.0) { +// errorMessageOut = "Range of histogram X-values is zero"; +// return false; +// } +// +// if ((paletteColorMapping != NULL) +// && (statistics != NULL) +// && (palette != NULL) +// && (histogram != NULL)) { +// std::vector histogramBuckets = histogram->getHistogramDisplay(); +// const int32_t numBucketValues = static_cast(histogramBuckets.size()); +// if (numBucketValues < 2) { +// errorMessageOut = "Histogram must contain two or more values"; +// return false; +// } +// +// int32_t numberOfDataPoints = (addEndPointForQwtFlag +// ? (numBucketValues + 1) +// : numBucketValues); +// +// histogramDrawingInfoOut.initialize(numberOfDataPoints); +// +// if (addEndPointForQwtFlag) { +// /* +// * Duplicate last point for Qwt or else Qwt may not draw correctly +// */ +// histogramBuckets.push_back(histogramBuckets[histogramBuckets.size() - 1]); +// } +// histogramDrawingInfoOut.m_dataY = histogramBuckets; +// +// const bool hideZerosFlag = ( ! paletteColorMapping->isDisplayZeroDataFlag()); +// const float stepX = ((valueRangeX) +// / static_cast(numberOfDataPoints)); +// +// /* +// * Need to find zero (or near zero if there is not an exact zero value) +// */ +// int32_t indexZeroX = -1; +// float indexZeroDistance = std::numeric_limits::max(); +// +// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { +// float valueX = (minValueX +// + (ix * stepX)); +// +// if (hideZerosFlag) { +// const float zeroDistance = ((valueX >= 0) ? valueX : -valueX); +// if (zeroDistance < indexZeroDistance) { +// indexZeroX = ix; +// indexZeroDistance = zeroDistance; +// } +// } +// +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); +// histogramDrawingInfoOut.m_dataX[ix] = valueX; +// } +// +// if (indexZeroX >= 0) { +// const float posZero = 0.05; +// const float negZero = -posZero; +// int32_t negZeroIndex = -1; +// +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, indexZeroX); +// const float xValue = histogramDrawingInfoOut.m_dataX[indexZeroX]; +// if (xValue <= 0.0) { +// negZeroIndex = indexZeroX; +// } +// else { +// negZeroIndex = indexZeroX - 1; +// } +// +// if ((negZeroIndex >= 0) +// && (negZeroIndex < (numberOfDataPoints - 1))) { +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, negZeroIndex + 1); +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, negZeroIndex + 1); +// histogramDrawingInfoOut.m_dataX[negZeroIndex] = negZero; +// histogramDrawingInfoOut.m_dataY[negZeroIndex] = 0.0; +// +// histogramDrawingInfoOut.m_dataX.insert(histogramDrawingInfoOut.m_dataX.begin() + negZeroIndex + 1, posZero); +// histogramDrawingInfoOut.m_dataY.insert(histogramDrawingInfoOut.m_dataY.begin() + negZeroIndex + 1, 0.0); +// } +// numberOfDataPoints = static_cast(histogramDrawingInfoOut.m_dataX.size()); +// CaretAssert(histogramDrawingInfoOut.m_dataX.size() == histogramDrawingInfoOut.m_dataY.size()); +// histogramDrawingInfoOut.m_dataRGBA.resize(numberOfDataPoints * 4); +// } +// +//// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { +//// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); +//// std::cout << "value " << ix << ": " << histogramDrawingInfoOut.m_dataX[ix] << "," << histogramDrawingInfoOut.m_dataX[ix] << std::endl; +//// } +// +// histogramDrawingInfoOut.m_dataX[0] = minValueX; +// histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValueX; +// +// const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; +// +// const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); +// if (histogramColor != CaretColorEnum::CUSTOM) { +// float rgba[4]; +// CaretColorEnum::toRGBAFloat(histogramColor, rgba); +// rgba[3] = 1.0; +// +// for (int32_t i = 0; i < numberOfDataPoints; i++) { +// const int32_t i4 = i * 4; +// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, i4 + 3); +// histogramDrawingInfoOut.m_dataRGBA[i4] = rgba[0]; +// histogramDrawingInfoOut.m_dataRGBA[i4+1] = rgba[1]; +// histogramDrawingInfoOut.m_dataRGBA[i4+2] = rgba[2]; +// histogramDrawingInfoOut.m_dataRGBA[i4+3] = rgba[3]; +// } +// } +// else { +// float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; +// +// NodeAndVoxelColoring::colorScalarsWithPalette(statistics, +// paletteColorMapping, +// palette, +// xValuesArray, +// xValuesArray, +// numberOfDataPoints, +// dataRGBA, +// true); // ignore thresholding +// } +// +// bool setThresholdingFlag = false; +// switch (paletteColorMapping->getThresholdType()) { +// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: +// break; +// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: +// break; +// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: +// setThresholdingFlag = true; +// break; +// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: +// break; +// } +// +// if (setThresholdingFlag) { +// float bounds[4]; +// if (histogramDrawingInfoOut.getBounds(bounds)) { +// const float minX = bounds[0]; +// const float maxX = bounds[1]; +// const float minY = bounds[2]; +// const float maxY = bounds[3]; +// +// float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); +// float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); +// switch (paletteColorMapping->getThresholdTest()) { +// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: +// { +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = minX; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMinValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMinValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = minX; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; +// +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ.resize(12); +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[0] = threshMaxValue; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[1] = minY; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[2] = 0.0; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[3] = maxX; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[4] = minY; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[5] = 0.0; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[6] = maxX; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[7] = maxY; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[8] = 0.0; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[9] = threshMaxValue; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[10] = maxY; +// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[11] = 0.0; +// } +// break; +// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: +// { +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = threshMinValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMaxValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMaxValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = threshMinValue; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; +// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; +// } +// break; +// } +// +// switch (paletteColorMapping->getThresholdRangeMode()) { +// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE: +// break; +// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP: +// break; +// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED: +// break; +// } +// } +// } +// +// CaretAssert(histogramDrawingInfoOut.isValid()); +// return histogramDrawingInfoOut.isValid(); +// } +// +// return false; +//} + /** * @return File histogram number of buckets. */ diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 3450858b0..e5c51c15d 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -1827,7 +1827,8 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() //const int64_t* histogram = const_cast(statistics->getHistogram()); float minValue, maxValue; myHist->getRange(minValue, maxValue); - const std::vector& displayData = myHist->getHistogramDisplay(); + const std::vector& displayDataReference = myHist->getHistogramDisplay(); + std::vector displayData = displayDataReference; // may modify it const int64_t numHistogramValues = (int64_t)(displayData.size()); /* @@ -1863,29 +1864,46 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() dataValues[numDataValues - 1] = maxValue; const Palette* palette = paletteFile->getPaletteByName(this->paletteColorMapping->getSelectedPaletteName()); - const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); - if ((histogramColor == CaretColorEnum::CUSTOM) - && (palette != NULL)) { + + /* + * Color with palette so that alpha values are zero for regions not displayed + */ + if (palette != NULL) { NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - dataValues, - dataValues, - numDataValues, + paletteColorMapping, + palette, + dataValues, + dataValues, + numDataValues, dataRGBA, true); // ignore thresholding + + /* + * If bucket is not colored (zero alpha) set bucket height to zero + */ + for (int32_t i = 0; i < numHistogramValues; i++) { + const int32_t alphaIndex = i * 4 + 3; + CaretAssertArrayIndex(dataRGBA, (numDataValues * 4), alphaIndex); + if (dataRGBA[alphaIndex] <= 0.0) { + CaretAssertVectorIndex(displayData, i); + displayData[i] = 0.0; + } + } } - else { + + const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); + if (histogramColor != CaretColorEnum::CUSTOM) { + /* + * DO NOT override RGBA + */ float colorRGBA[4]; CaretColorEnum::toRGBAFloat(histogramColor, colorRGBA); - colorRGBA[3] = 1.0; for (int64_t i = 0; i < numDataValues; i++) { const int64_t i4 = i * 4; dataRGBA[i4] = colorRGBA[0]; dataRGBA[i4+1] = colorRGBA[1]; dataRGBA[i4+2] = colorRGBA[2]; - dataRGBA[i4+3] = colorRGBA[3]; } } } @@ -1915,12 +1933,12 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() bool displayIt = true; - if (displayZeros == false) { - if ((startValue <= 0.0) && (stopValue >= 0.0)) { - dataFrequency = 0.0; - displayIt = false; - } - } +// if (displayZeros == false) { +// if ((startValue <= 0.0) && (stopValue >= 0.0)) { +// dataFrequency = 0.0; +// displayIt = false; +// } +// } if (dataFrequency > maxDataFrequency) { maxDataFrequency = dataFrequency; -- GitLab From a7cac2c210ae2b05c14995407d84ca0c92d30a6d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 23 Mar 2017 15:41:40 -0500 Subject: [PATCH 234/755] Palette Color Mapping Dialog --> Palette Section: Added an additional column on the right titled "Data" that lists the data values that correspond to the Full, Abs Pct, Percent, and Fixed percentages/values. Thus, if the user has "Percent" selected, the user can view the data values that correspond to the Pos Max %, Pos Min %, Neg Min %, and Neg Max %. --- .../MapSettingsPaletteColorMappingWidget.cxx | 107 +++++++++++++++++- .../MapSettingsPaletteColorMappingWidget.h | 7 ++ 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index e5c51c15d..9f634d084 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -965,6 +965,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoPercentageNegativeMaximumValueCha this->scaleAutoPercentageNegativeMinimumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -985,6 +986,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoPercentageNegativeMinimumValueCha this->scaleAutoPercentageNegativeMaximumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } @@ -1006,6 +1008,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoPercentagePositiveMinimumValueCha this->scaleAutoPercentagePositiveMaximumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } @@ -1027,6 +1030,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoPercentagePositiveMaximumValueCha this->scaleAutoPercentagePositiveMinimumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1047,6 +1051,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoAbsolutePercentageMinimumValueCha this->scaleAutoAbsolutePercentageMaximumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1067,6 +1072,7 @@ MapSettingsPaletteColorMappingWidget::scaleAutoAbsolutePercentageMaximumValueCha this->scaleAutoAbsolutePercentageMinimumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1087,6 +1093,7 @@ MapSettingsPaletteColorMappingWidget::scaleFixedNegativeMaximumValueChanged(doub this->scaleFixedNegativeMinimumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1107,6 +1114,7 @@ MapSettingsPaletteColorMappingWidget::scaleFixedNegativeMinimumValueChanged(doub this->scaleFixedNegativeMaximumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1127,6 +1135,7 @@ MapSettingsPaletteColorMappingWidget::scaleFixedPositiveMinimumValueChanged(doub this->scaleFixedPositiveMaximumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1147,6 +1156,7 @@ MapSettingsPaletteColorMappingWidget::scaleFixedPositiveMaximumValueChanged(doub this->scaleFixedPositiveMinimumSpinBox->blockSignals(false); } applySelections(); + updatePaletteMappedToDataValueLabels(); } /** @@ -1353,16 +1363,30 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() this->paletteWidgetGroup->add(this->scaleFixedPositiveMaximumSpinBox); this->scaleFixedPositiveMaximumSpinBox->setFixedWidth(fixedSpinBoxWidth); + /* + * Labels for values at palette percentages + */ + this->scaleNegativeMaximumValueLabel = new QLabel(""); + this->scaleNegativeMinimumValueLabel = new QLabel(""); + this->scalePositiveMinimumValueLabel = new QLabel(""); + this->scalePositiveMaximumValueLabel = new QLabel(""); + + /* + * Layout widgets + */ QWidget* colorMappingWidget = new QWidget(); QGridLayout* colorMappingLayout = new QGridLayout(colorMappingWidget); colorMappingLayout->setColumnStretch(0, 0); colorMappingLayout->setColumnStretch(1, 100); colorMappingLayout->setColumnStretch(2, 100); + colorMappingLayout->setColumnStretch(3, 100); + colorMappingLayout->setColumnStretch(4, 100); this->setLayoutSpacingAndMargins(colorMappingLayout); colorMappingLayout->addWidget(this->scaleAutoRadioButton, 0, 0, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleAutoAbsolutePercentageRadioButton, 0, 1, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleAutoPercentageRadioButton, 0, 2, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleFixedRadioButton, 0, 3, Qt::AlignHCenter); + colorMappingLayout->addWidget(new QLabel("Data"), 0, 4, Qt::AlignHCenter); colorMappingLayout->addWidget(new QLabel("Pos Max"), 1, 0, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Pos Min"), 2, 0, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Neg Min"), 3, 0, Qt::AlignRight); @@ -1377,6 +1401,10 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() colorMappingLayout->addWidget(this->scaleFixedPositiveMinimumSpinBox, 2, 3); colorMappingLayout->addWidget(this->scaleFixedNegativeMinimumSpinBox, 3, 3); colorMappingLayout->addWidget(this->scaleFixedNegativeMaximumSpinBox, 4, 3); + colorMappingLayout->addWidget(this->scalePositiveMaximumValueLabel, 1, 4, Qt::AlignRight); + colorMappingLayout->addWidget(this->scalePositiveMinimumValueLabel, 2, 4, Qt::AlignRight); + colorMappingLayout->addWidget(this->scaleNegativeMinimumValueLabel, 3, 4, Qt::AlignRight); + colorMappingLayout->addWidget(this->scaleNegativeMaximumValueLabel, 4, 4, Qt::AlignRight); /* * Display Mode @@ -1513,6 +1541,70 @@ MapSettingsPaletteColorMappingWidget::updateThresholdSection() this->thresholdWidgetGroup->blockAllSignals(false); } +/** + * Update the labels that list values that correspond to the palette + * mapping values (percent neg/pos min/max, full, etc). + */ +void +MapSettingsPaletteColorMappingWidget::updatePaletteMappedToDataValueLabels() +{ + if (this->caretMappableDataFile == NULL) { + return; + } + else if (this->mapFileIndex < 0) { + return; + } + + FastStatistics* statistics = NULL; + switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); + break; + } + + double posMaxLabelValue = 0.0; + double posMinLabelValue = 0.0; + double negMinLabelValue = 0.0; + double negMaxLabelValue = 0.0; + + if (statistics != NULL) { + switch (this->paletteColorMapping->getScaleMode()) { + case PaletteScaleModeEnum::MODE_AUTO_SCALE: + posMaxLabelValue = statistics->getMostPositiveValue(); + posMinLabelValue = 0.0; + negMinLabelValue = 0.0; + negMaxLabelValue = statistics->getMostNegativeValue(); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: + posMaxLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); + posMinLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); + negMinLabelValue = -posMinLabelValue; + negMaxLabelValue = -posMaxLabelValue; + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: + posMaxLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScalePercentagePositiveMaximum()); + posMinLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScalePercentagePositiveMinimum()); + negMinLabelValue = statistics->getApproxNegativePercentile(this->paletteColorMapping->getAutoScalePercentageNegativeMinimum()); + negMaxLabelValue = statistics->getApproxNegativePercentile(this->paletteColorMapping->getAutoScalePercentageNegativeMaximum()); + break; + case PaletteScaleModeEnum::MODE_USER_SCALE: + posMaxLabelValue = this->paletteColorMapping->getUserScalePositiveMaximum(); + posMinLabelValue = this->paletteColorMapping->getUserScalePositiveMinimum(); + negMinLabelValue = this->paletteColorMapping->getUserScaleNegativeMinimum(); + negMaxLabelValue = this->paletteColorMapping->getUserScaleNegativeMaximum(); + break; + } + } + + this->scalePositiveMaximumValueLabel->setText(QString::number(posMaxLabelValue, 'f', 2)); + this->scalePositiveMinimumValueLabel->setText(QString::number(posMinLabelValue, 'f', 2)); + this->scaleNegativeMinimumValueLabel->setText(QString::number(negMinLabelValue, 'f', 2)); + this->scaleNegativeMaximumValueLabel->setText(QString::number(negMaxLabelValue, 'f', 2)); +} + /** * This PRIVATE method updates the editor content and MUST always be used * when something within this class requires updating the displayed data. @@ -1627,26 +1719,33 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile m_histogramHorizontalRangeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramRangeMode()); - + updatePaletteMappedToDataValueLabels(); updateThresholdSection(); float minValue = 0.0; float maxValue = 0.0; m_histogramBucketsSpinBox->blockSignals(true); - FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); m_histogramBucketsSpinBox->setValue(this->caretMappableDataFile->getFileHistogramNumberOfBuckets()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); m_histogramBucketsSpinBox->setValue(this->paletteColorMapping->getHistogramNumberOfBuckets()); break; } m_histogramBucketsSpinBox->blockSignals(false); + FastStatistics* statistics = NULL; + switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); + break; + } + if (statistics != NULL) { minValue = statistics->getMin(); maxValue = statistics->getMax(); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index f4e43ac5a..aca77653c 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -127,6 +127,8 @@ namespace caret { void updateThresholdControlsMinimumMaximumRangeValues(); + void updatePaletteMappedToDataValueLabels(); + void setLayoutSpacingAndMargins(QLayout* layout); const Histogram* getHistogram(const FastStatistics* statisticsForAll) const; @@ -156,6 +158,11 @@ namespace caret { QDoubleSpinBox* scaleFixedPositiveMinimumSpinBox; QDoubleSpinBox* scaleFixedPositiveMaximumSpinBox; + QLabel* scaleNegativeMaximumValueLabel; + QLabel* scaleNegativeMinimumValueLabel; + QLabel* scalePositiveMinimumValueLabel; + QLabel* scalePositiveMaximumValueLabel; + QCheckBox* displayModePositiveCheckBox; QCheckBox* displayModeZeroCheckBox; QCheckBox* displayModeNegativeCheckBox; -- GitLab From 6f636ffd53b25675b37ad6e249de8236e5c79a7e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 24 Mar 2017 16:06:30 -0500 Subject: [PATCH 235/755] Corrections for selection of rows and/or columns in for pconn and pscalar matrix charts. --- src/Brain/ChartTwoOverlay.cxx | 26 +- src/Files/ChartableTwoFileMatrixChart.cxx | 676 ++++++++++-------- src/Files/ChartableTwoFileMatrixChart.h | 47 +- .../ChartTwoOverlaySetViewController.cxx | 48 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 11 +- 5 files changed, 453 insertions(+), 355 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 78cb7e83b..5b3faa4d5 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -626,31 +626,41 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma rowIndices, columnIndices); - AString namePrefix; switch (rowColumnDimension) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: numMaps = numCols; - namePrefix = "Column "; if ( ! columnIndices.empty()) { selectedIndexTypeOut = SelectedIndexType::COLUMN; selectedIndexOut = columnIndices[0]; } + if (matrixChart->hasColumnSelection()) { + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); + // const AString namePrefix = "Column "; + // selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); + } + } + } break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: numMaps = numRows; - namePrefix = "Row "; if ( ! rowIndices.empty()) { selectedIndexTypeOut = SelectedIndexType::ROW; selectedIndexOut = rowIndices[0]; } + if (matrixChart->hasRowSelection()) { + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); + // const AString namePrefix = "Row "; + // selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); + } + } + } break; } - if (selectedFileMapNamesOut != NULL) { - for (int32_t i = 0; i < numMaps; i++) { - selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); - } - } } diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index e0484bc22..d38be6a39 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -28,6 +28,7 @@ #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" +#include "CiftiXML.h" #include "CiftiScalarDataSeriesFile.h" #include "ConnectivityDataLoaded.h" #include "EventCaretMappableDataFileMapsViewedInOverlays.h" @@ -37,10 +38,8 @@ using namespace caret; - - /** - * \class caret::ChartableTwoFileMatrixChart + * \class caret::ChartableTwoFileMatrixChart * \brief Implementation of base chart delegate for matrix charts. * \ingroup Files */ @@ -65,19 +64,143 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) { m_sceneAssistant = new SceneClassAssistant(); - int32_t numRows = 0; - int32_t numCols = 0; + m_numberOfRows = 0; + m_numberOfColumns = 0; + + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_parcelScalarFileSelectedColumn[i] = 0; + } + m_sceneAssistant->addTabIndexedIntegerArray("m_parcelScalarFileSelectedColumn", + m_parcelScalarFileSelectedColumn); if (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); - ciftiMapFile->helpMapFileGetMatrixDimensions(numRows, - numCols); + ciftiMapFile->helpMapFileGetMatrixDimensions(m_numberOfRows, + m_numberOfColumns); + + switch (ciftiMapFile->getDataFileType()) { + case DataFileTypeEnum::ANNOTATION: + break; + case DataFileTypeEnum::BORDER: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: + break; + case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL: + m_matrixDataFileType = MatrixDataFileType::PARCEL; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + m_matrixDataFileType = MatrixDataFileType::PARCEL_LABEL; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + m_matrixDataFileType = MatrixDataFileType::PARCEL_SCALAR; + break; + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + break; + case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: + m_matrixDataFileType = MatrixDataFileType::SCALAR_DATA_SERIES; + break; + case DataFileTypeEnum::FOCI: + break; + case DataFileTypeEnum::IMAGE: + break; + case DataFileTypeEnum::LABEL: + break; + case DataFileTypeEnum::METRIC: + break; + case DataFileTypeEnum::PALETTE: + break; + case DataFileTypeEnum::RGBA: + break; + case DataFileTypeEnum::SCENE: + break; + case DataFileTypeEnum::SPECIFICATION: + break; + case DataFileTypeEnum::SURFACE: + break; + case DataFileTypeEnum::UNKNOWN: + break; + case DataFileTypeEnum::VOLUME: + break; + } + + bool hasColumnMapSelectionFlag = false; + switch (m_matrixDataFileType) { + case MatrixDataFileType::INVALID: + CaretAssert(0); + return; + break; + case MatrixDataFileType::PARCEL: + m_parcelFile = dynamic_cast(ciftiMapFile); + CaretAssert(m_parcelFile); + m_hasRowSelectionFlag = true; + m_hasColumnSelectionFlag = true; + break; + case MatrixDataFileType::PARCEL_LABEL: + m_parcelLabelFile = dynamic_cast(ciftiMapFile); + CaretAssert(m_parcelLabelFile); + break; + case MatrixDataFileType::PARCEL_SCALAR: + m_parcelScalarFile = dynamic_cast(ciftiMapFile); + m_hasColumnSelectionFlag = true; + hasColumnMapSelectionFlag = true; + CaretAssert(m_parcelScalarFile); + break; + case MatrixDataFileType::SCALAR_DATA_SERIES: + m_scalarDataSeriesFile = dynamic_cast(ciftiMapFile); + CaretAssert(m_scalarDataSeriesFile); + break; + } + + if (m_hasRowSelectionFlag) { + const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); + if (rowParcelsMap != NULL) { + const int32_t numRowParcels = rowParcelsMap->getLength(); + CaretAssert(numRowParcels == m_numberOfRows); + for (int32_t i = 0; i < numRowParcels; i++) { + m_rowNames.push_back("Row " + AString::number(i + 1) + ": " + rowParcelsMap->getIndexName(i)); + } + } + } + + if (m_hasColumnSelectionFlag) { + const CiftiParcelsMap* colParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); + if (colParcelsMap != NULL) { + const int32_t numColParcels = colParcelsMap->getLength(); + CaretAssert(numColParcels == m_numberOfColumns); + for (int32_t i = 0; i < numColParcels; i++) { + m_columnNames.push_back("Column " + AString::number(i + 1) + ": " + colParcelsMap->getIndexName(i)); + } + } + + if (hasColumnMapSelectionFlag) { + m_columnNames.clear(); + for (int32_t i = 0; i < m_numberOfColumns; i++) { + m_columnNames.push_back(m_parcelScalarFile->getMapName(i)); + } + } + } } m_matrixTriangularViewingModeSupportedFlag = false; - if ((numRows > 0) - && (numCols > 0)) { + if ((m_numberOfRows > 0) + && (m_numberOfColumns > 0)) { const CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(parentCaretMappableDataFile); if (matrixFile != NULL) { m_matrixTriangularViewingModeSupportedFlag = matrixFile->hasSymetricRowColumnNames(); @@ -88,17 +211,8 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) } - updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, - numCols)); - -// m_rowColumnDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; -// if ( ! m_validRowColumnSelectionDimensions.empty()) { -// CaretAssertVectorIndex(m_validRowColumnSelectionDimensions, 0); -// m_rowColumnDimension = m_validRowColumnSelectionDimensions[0]; -// } -// -// m_sceneAssistant->add("m_rowColumnDimension", -// &m_rowColumnDimension); + updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(m_numberOfRows, + m_numberOfColumns)); } /** @@ -205,174 +319,6 @@ ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, return ciftiMapFile->getMatrixForChartingRGBA(numberOfRowsOut, numberOfColumnsOut, rgbaOut); - -// bool useMapFileHelperFlag = false; -// bool useMatrixFileHelperFlag = false; -// -// std::vector parcelReorderedRowIndices; -// -// switch (ciftiMapFile->getDataFileType()) { -// case DataFileTypeEnum::CONNECTIVITY_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL: -// { -// useMatrixFileHelperFlag = true; -// -// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(ciftiMapFile); -// CaretAssert(parcelConnFile); -// if (parcelConnFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); -// CaretAssert(parcelLabelFile); -// if (parcelLabelFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); -// CaretAssert(parcelScalarFile); -// if (parcelScalarFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: -// useMatrixFileHelperFlag = true; -// break; -// case DataFileTypeEnum::ANNOTATION: -// break; -// case DataFileTypeEnum::BORDER: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: -// break; -// case DataFileTypeEnum::FOCI: -// break; -// case DataFileTypeEnum::IMAGE: -// break; -// case DataFileTypeEnum::LABEL: -// break; -// case DataFileTypeEnum::METRIC: -// break; -// case DataFileTypeEnum::PALETTE: -// break; -// case DataFileTypeEnum::RGBA: -// break; -// case DataFileTypeEnum::SCENE: -// break; -// case DataFileTypeEnum::SPECIFICATION: -// break; -// case DataFileTypeEnum::SURFACE: -// break; -// case DataFileTypeEnum::UNKNOWN: -// break; -// case DataFileTypeEnum::VOLUME: -// break; -// } -// -// if (( ! useMapFileHelperFlag) -// && ( ! useMatrixFileHelperFlag)) { -// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); -// return false; -// } -// -// bool validDataFlag = false; -// if (useMapFileHelperFlag) { -// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, -// numberOfColumnsOut, -// parcelReorderedRowIndices, -// rgbaOut); -// } -// else if (useMatrixFileHelperFlag) { -// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, -// numberOfColumnsOut, -// parcelReorderedRowIndices, -// rgbaOut); -// } -// switch (m_matrixContentType) { -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SERIES: -// break; -// } -// -// return validDataFlag; } /** @@ -383,17 +329,31 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const { ChartTwoMatrixLoadingDimensionEnum::Enum loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; - const CaretMappableDataFile* cmdf = getCaretMappableDataFile(); - const CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(cmdf); - if (matrixFile != NULL) { - switch (matrixFile->getMatrixLoadingDimension()) { - case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: - loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; - break; - case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: - loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; - break; - } + switch (m_matrixDataFileType) { + case MatrixDataFileType::INVALID: + CaretAssert(0); + break; + case MatrixDataFileType::PARCEL: + CaretAssert(m_parcelFile); + switch (m_parcelFile->getMatrixLoadingDimension()) { + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + break; + case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; + } + break; + case MatrixDataFileType::PARCEL_LABEL: + CaretAssert(m_parcelLabelFile); + break; + case MatrixDataFileType::PARCEL_SCALAR: + CaretAssert(m_parcelScalarFile); + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; + case MatrixDataFileType::SCALAR_DATA_SERIES: + CaretAssert(m_scalarDataSeriesFile); + break; } return loadDimension; @@ -408,24 +368,35 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const void ChartableTwoFileMatrixChart::setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension) { - CaretMappableDataFile* cmdf = getCaretMappableDataFile(); - CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(cmdf); - if (matrixFile != NULL) { - ChartMatrixLoadingDimensionEnum::Enum oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; - switch (rowColumnDimension) { - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: - oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; - break; - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: - oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; - break; + switch (m_matrixDataFileType) { + case MatrixDataFileType::INVALID: + CaretAssert(0); + break; + case MatrixDataFileType::PARCEL: + { + CaretAssert(m_parcelFile); + ChartMatrixLoadingDimensionEnum::Enum oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + switch (rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; + } + m_parcelFile->setMatrixLoadingDimension(oldLoadDim); } - matrixFile->setMatrixLoadingDimension(oldLoadDim); + break; + case MatrixDataFileType::PARCEL_LABEL: + CaretAssert(m_parcelLabelFile); + break; + case MatrixDataFileType::PARCEL_SCALAR: + CaretAssert(m_parcelScalarFile); + break; + case MatrixDataFileType::SCALAR_DATA_SERIES: + CaretAssert(m_scalarDataSeriesFile); + break; } -// if (m_rowColumnDimension != rowColumnDimension) { -// m_rowColumnDimension = rowColumnDimension; -// setModified(); -// } } /** @@ -443,80 +414,91 @@ ChartableTwoFileMatrixChart::getValidRowColumnSelectionDimensions(std::vector& rowIndicesOut, - std::vector& columnIndicesOut) const + std::vector& selectedRowIndicesOut, + std::vector& selectedColumnIndicesOut) const { rowColumnDimensionOut = getSelectedRowColumnDimension(); - rowIndicesOut.clear(); - columnIndicesOut.clear(); + selectedRowIndicesOut.clear(); + selectedColumnIndicesOut.clear(); std::set rowIndicesSet; std::set columnIndicesSet; - const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); - const CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); - if (connMapFile != NULL) { - const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); - if (connDataLoaded != NULL) { - int64_t loadedRowIndex = -1; - int64_t loadedColumnIndex = -1; - connDataLoaded->getRowColumnLoading(loadedRowIndex, - loadedColumnIndex); - switch (rowColumnDimensionOut) { - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: - if (loadedColumnIndex >= 0) { - columnIndicesSet.insert(loadedColumnIndex); - } - break; - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: - if (loadedRowIndex >= 0) { - rowIndicesSet.insert(loadedRowIndex); - } - break; + switch (m_matrixDataFileType) { + case MatrixDataFileType::INVALID: + CaretAssert(0); + break; + case MatrixDataFileType::PARCEL: + { + CaretAssert(m_parcelFile); + const ConnectivityDataLoaded* connDataLoaded = m_parcelFile->getConnectivityDataLoaded(); + if (connDataLoaded != NULL) { + int64_t loadedRowIndex = -1; + int64_t loadedColumnIndex = -1; + connDataLoaded->getRowColumnLoading(loadedRowIndex, + loadedColumnIndex); + switch (rowColumnDimensionOut) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + if (loadedColumnIndex >= 0) { + columnIndicesSet.insert(loadedColumnIndex); + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + if (loadedRowIndex >= 0) { + rowIndicesSet.insert(loadedRowIndex); + } + break; + } } } - } - - const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); - if (parcelScalarFile != NULL) { - EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); - EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { - columnIndicesSet.insert(indx); - } - } - - const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); - if (parcelLabelFile != NULL) { - EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); - EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { - columnIndicesSet.insert(indx); + break; + case MatrixDataFileType::PARCEL_LABEL: + { + CaretAssert(m_parcelLabelFile); + EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); + EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { + columnIndicesSet.insert(indx); + } } - } - - const CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); - if (scalarDataSeriesFile != NULL) { - const int32_t scalarDataSeriesMapIndex = scalarDataSeriesFile->getSelectedMapIndex(tabIndex); - if (scalarDataSeriesMapIndex >= 0) { - rowIndicesSet.insert(scalarDataSeriesMapIndex); + break; + case MatrixDataFileType::PARCEL_SCALAR: + CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + columnIndicesSet.insert(m_parcelScalarFileSelectedColumn[tabIndex]); +// { +// CaretAssert(m_parcelScalarFile); +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelScalarFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { +// columnIndicesSet.insert(indx); +// } +// } + break; + case MatrixDataFileType::SCALAR_DATA_SERIES: + { + CaretAssert(m_scalarDataSeriesFile); + const int32_t scalarDataSeriesMapIndex = m_scalarDataSeriesFile->getSelectedMapIndex(tabIndex); + if (scalarDataSeriesMapIndex >= 0) { + rowIndicesSet.insert(scalarDataSeriesMapIndex); + } } + break; } - rowIndicesOut.insert(rowIndicesOut.end(), + selectedRowIndicesOut.insert(selectedRowIndicesOut.end(), rowIndicesSet.begin(), rowIndicesSet.end()); - columnIndicesOut.insert(columnIndicesOut.end(), + selectedColumnIndicesOut.insert(selectedColumnIndicesOut.end(), columnIndicesSet.begin(), columnIndicesSet.end()); } @@ -541,60 +523,126 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, return; } - CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); - CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(ciftiMapFile); - if (connMapFile != NULL) { - /* - * Load data for the row/column. - * Invalidating coloring results in the necessary update of brainordinate coloring. - */ - int32_t numRows = -1; - int32_t numCols = -1; - getMatrixDimensions(numRows, numCols); - switch (getSelectedRowColumnDimension()) { - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: - if ((rowColumnIndex >= 0) - && (rowColumnIndex < numCols)) { - connMapFile->loadDataForColumnIndex(rowColumnIndex); - connMapFile->invalidateColoringInAllMaps(); - } - break; - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: - if ((rowColumnIndex >= 0) - && (rowColumnIndex < numRows)) { - connMapFile->loadDataForRowIndex(rowColumnIndex); - connMapFile->invalidateColoringInAllMaps(); - } - break; + switch (m_matrixDataFileType) { + case MatrixDataFileType::INVALID: + CaretAssert(0); + break; + case MatrixDataFileType::PARCEL: + { + CaretAssert(m_parcelFile); + int32_t numRows = -1; + int32_t numCols = -1; + getMatrixDimensions(numRows, numCols); + switch (getSelectedRowColumnDimension()) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numCols)) { + m_parcelFile->loadDataForColumnIndex(rowColumnIndex); + m_parcelFile->invalidateColoringInAllMaps(); + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + if ((rowColumnIndex >= 0) + && (rowColumnIndex < numRows)) { + m_parcelFile->loadDataForRowIndex(rowColumnIndex); + m_parcelFile->invalidateColoringInAllMaps(); + } + break; + } + } + break; + case MatrixDataFileType::PARCEL_LABEL: + { + CaretAssert(m_parcelLabelFile); + CaretAssertToDoWarning(); + // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); + // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { + // columnIndicesSet.insert(indx); + // } + } + break; + case MatrixDataFileType::PARCEL_SCALAR: + { + CaretAssert(m_parcelScalarFile); + CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + m_parcelScalarFileSelectedColumn[tabIndex] = rowColumnIndex; + // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelScalarFile); + // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); + // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { + // columnIndicesSet.insert(indx); + // } } + break; + case MatrixDataFileType::SCALAR_DATA_SERIES: + CaretAssert(m_scalarDataSeriesFile); + m_scalarDataSeriesFile->setSelectedMapIndex(tabIndex, + rowColumnIndex); + break; } - - CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(ciftiMapFile); - if (parcelScalarFile != NULL) { - CaretAssertToDoWarning(); -// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); -// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); -// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { -// columnIndicesSet.insert(indx); -// } +} + +/** + * @return True if the file supports row selection. + */ +bool +ChartableTwoFileMatrixChart::hasRowSelection() const +{ + return m_hasRowSelectionFlag; +} + +/** + * @return True if the file supports column selection. + */ +bool +ChartableTwoFileMatrixChart::hasColumnSelection() const +{ + return m_hasColumnSelectionFlag; +} + +/** + * @return Name of row at the given index. + * + * @param rowIndex + * Index of the row. + */ +AString +ChartableTwoFileMatrixChart::getRowName(const int32_t rowIndex) const +{ + if ((rowIndex >= 0) + && (rowIndex < m_numberOfRows)) { + if (rowIndex < static_cast(m_rowNames.size())) { + CaretAssertVectorIndex(m_rowNames, rowIndex); + return m_rowNames[rowIndex]; + } + return ("Row: " + AString::number(rowIndex)); } - const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(ciftiMapFile); - if (parcelLabelFile != NULL) { -// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); -// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); -// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { -// columnIndicesSet.insert(indx); -// } + return ""; +} + +/** + * @return Name of column at the given index. + * + * @param columnIndex + * Index of the row. + */ +AString +ChartableTwoFileMatrixChart::getColumnName(const int32_t columnIndex) const +{ + if ((columnIndex >= 0) + && (columnIndex < m_numberOfColumns)) { + if (columnIndex < static_cast(m_columnNames.size())) { + CaretAssertVectorIndex(m_columnNames, columnIndex); + return m_columnNames[columnIndex]; + } + return ("Column: " + AString::number(columnIndex)); } - CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(ciftiMapFile); - if (scalarDataSeriesFile != NULL) { - scalarDataSeriesFile->setSelectedMapIndex(tabIndex, - rowColumnIndex); - } + return ""; } + /** * Save subclass data to the scene. * diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 098ce8f59..cc75668e3 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -21,12 +21,18 @@ */ /*LICENSE_END*/ +#include "BrainConstants.h" #include "ChartTwoMatrixContentTypeEnum.h" #include "ChartTwoMatrixLoadingDimensionEnum.h" #include "ChartableTwoFileBaseChart.h" namespace caret { + class CiftiConnectivityMatrixParcelFile; + class CiftiParcelLabelFile; + class CiftiParcelScalarFile; + class CiftiScalarDataSeriesFile; + class ChartableTwoFileMatrixChart : public ChartableTwoFileBaseChart { public: @@ -61,13 +67,29 @@ namespace caret { void getSelectedRowColumnIndices(const int32_t tabIndex, ChartTwoMatrixLoadingDimensionEnum::Enum& rowColumnDimensionOut, - std::vector& rowIndicesOut, - std::vector& columnIndicesOut) const; + std::vector& selectedRowIndicesOut, + std::vector& selectedColumnIndicesOut) const; void setSelectedRowColumnIndex(const int32_t tabIndex, const int32_t rowColumnIndex); + bool hasRowSelection() const; + + bool hasColumnSelection() const; + + AString getRowName(const int32_t rowIndex) const; + + AString getColumnName(const int32_t columnIndex) const; + protected: + enum class MatrixDataFileType { + INVALID, + PARCEL, + PARCEL_LABEL, + PARCEL_SCALAR, + SCALAR_DATA_SERIES + }; + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; @@ -87,8 +109,27 @@ namespace caret { bool m_matrixTriangularViewingModeSupportedFlag = false; - //ChartTwoMatrixLoadingDimensionEnum::Enum m_rowColumnDimension; + int32_t m_numberOfRows = 0; + + int32_t m_numberOfColumns = 0; + + std::vector m_rowNames; + + std::vector m_columnNames; + + bool m_hasRowSelectionFlag = false; + + bool m_hasColumnSelectionFlag = false; + + MatrixDataFileType m_matrixDataFileType = MatrixDataFileType::INVALID; + + CiftiConnectivityMatrixParcelFile *m_parcelFile = NULL; + CiftiParcelLabelFile* m_parcelLabelFile = NULL; + CiftiParcelScalarFile* m_parcelScalarFile = NULL; + CiftiScalarDataSeriesFile* m_scalarDataSeriesFile = NULL; + int32_t m_parcelScalarFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 048a67e22..35b45757a 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -130,8 +130,8 @@ m_browserWindowIndex(browserWindowIndex) QLabel* fileLabel = new QLabel("File"); QLabel* yokeLabel = new QLabel("Yoke"); QLabel* allMapsLabel = new QLabel("All"); - m_mapRowOrColumnIndexLabel = new QLabel("Map Index"); - m_mapRowOrColumnNameLabel = new QLabel("Map Name"); + m_mapRowOrColumnIndexLabel = new QLabel("Index"); + m_mapRowOrColumnNameLabel = new QLabel("Name"); int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); @@ -303,28 +303,28 @@ ChartTwoOverlaySetViewController::updateViewController() m_chartOverlayGridLayoutGroups[i]->setVisible(displayOverlay); } - const ChartTwoOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); - if (primaryOverlay != NULL) { - AString mapRowOrColumnName = "Map"; - switch (primaryOverlay->getChartTwoDataType()) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - mapRowOrColumnName = "Row"; - break; - } - - if (m_mapRowOrColumnIndexLabel != NULL) { - m_mapRowOrColumnIndexLabel->setText(mapRowOrColumnName+ " Index"); - } - if (m_mapRowOrColumnNameLabel != NULL) { - m_mapRowOrColumnNameLabel->setText(mapRowOrColumnName + " Name"); - } - } +// const ChartTwoOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); +// if (primaryOverlay != NULL) { +// AString mapRowOrColumnName = "Map"; +// switch (primaryOverlay->getChartTwoDataType()) { +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: +// mapRowOrColumnName = "Row"; +// break; +// } +// +// if (m_mapRowOrColumnIndexLabel != NULL) { +// m_mapRowOrColumnIndexLabel->setText(mapRowOrColumnName+ " Index"); +// } +// if (m_mapRowOrColumnNameLabel != NULL) { +// m_mapRowOrColumnNameLabel->setText(mapRowOrColumnName + " Name"); +// } +// } } /** diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index c3328f196..99c50bf91 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -246,11 +246,12 @@ m_chartOverlay(NULL) QObject::connect(m_mapRowOrColumnIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(mapRowOrColumnIndexSpinBoxValueChanged(int))); m_mapRowOrColumnIndexSpinBox->setToolTip("Select map/row/column by its index"); - m_mapRowOrColumnIndexSpinBox->setRange(0, 9999); // fix size for 4 digits + m_mapRowOrColumnIndexSpinBox->setRange(1, 9999); // fix size for 4 digits m_mapRowOrColumnIndexSpinBox->setFixedSize(m_mapRowOrColumnIndexSpinBox->sizeHint()); // m_mapRowOrColumnIndexSpinBox->setSizePolicy(QSizePolicy::Fixed, // QSizePolicy::Fixed); - m_mapRowOrColumnIndexSpinBox->setRange(0, 0); + m_mapRowOrColumnIndexSpinBox->setRange(1, 1); + m_mapRowOrColumnIndexSpinBox->setValue(1); /* * Map/Row/Column Name Combo Box @@ -676,8 +677,8 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla m_mapRowOrColumnNameComboBox->clear(); m_mapRowOrColumnIndexSpinBox->setEnabled(false); m_mapRowOrColumnIndexSpinBox->blockSignals(true); - m_mapRowOrColumnIndexSpinBox->setRange(0, 0); - m_mapRowOrColumnIndexSpinBox->setValue(0); + m_mapRowOrColumnIndexSpinBox->setRange(1, 1); + m_mapRowOrColumnIndexSpinBox->setValue(1); const int32_t numberOfMaps = static_cast(selectedFileMapNames.size()); if (numberOfMaps > 0) { m_mapRowOrColumnNameComboBox->setEnabled(true); @@ -702,8 +703,6 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - mapIndexMinimumValue = 0; - mapIndexMaximumValue = numberOfMaps - 1; break; } -- GitLab From 8f03e3f5b4b19f575e57f773ef71157644c07325 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 28 Mar 2017 13:05:38 -0500 Subject: [PATCH 236/755] Fixed crash in scene restoration of model one matrix charts to model two charts when loading an old (mid 2016) scene. --- src/Files/CaretMappableDataFile.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index abcfb6ba3..c66da330e 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -404,11 +404,9 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr m_labelDrawingProperties->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelDrawingProperties")); const SceneClass* chartingDelegateClass = sceneClass->getClass("m_chartingDelegate"); - m_chartingDelegate.reset(); + m_chartingDelegate->updateAfterFileChanged(); if (chartingDelegateClass != NULL) { - ChartableTwoFileDelegate* chartingDelegate = getChartingDelegate(); // creates charting delegate if not valid - chartingDelegate->updateAfterFileChanged(); - chartingDelegate->restoreFromScene(sceneAttributes, + m_chartingDelegate->restoreFromScene(sceneAttributes, chartingDelegateClass); } -- GitLab From 844d7fc17c0e041a001555e48ef1e1f5cdc7bd23 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Mar 2017 09:19:31 -0500 Subject: [PATCH 237/755] When the user switched the vertical axis from left to right (or right to left) the vertical axis was missing briefly and has been fixed. In Toolbar -> Chart Axis, when updating and the selected axis is not valid, set the axis to the opposite of the last valid index (i.e.: If the last selection was Left and Left is no longer valid, default to the Right axis). --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 36 +++++++++++-------- src/Charting/ChartAxisLocationEnum.cxx | 30 ++++++++++++++++ src/Charting/ChartAxisLocationEnum.h | 2 ++ .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 23 ++++++++++-- src/GuiQt/ChartTwoOverlayViewController.cxx | 2 +- 5 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 229223a95..53d58ac8b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -304,10 +304,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() std::vector drawingInfo; -// bool haveBottomAxisFlag = false; -// bool haveLeftAxisFlag = false; -// bool haveRightAxisFlag = false; - /* * Get the histogram drawing information and overall extent */ @@ -355,7 +351,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() xMin = std::min(xMin, bounds[0]); xMax = std::max(xMax, bounds[1]); -// haveBottomAxisFlag = true; switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); @@ -363,12 +358,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: yMinRight = std::min(yMinRight, bounds[2]); yMaxRight = std::max(yMaxRight, bounds[3]); -// haveRightAxisFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: yMinLeft = std::min(yMinLeft, bounds[2]); yMaxLeft = std::max(yMaxLeft, bounds[3]); -// haveLeftAxisFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); @@ -396,14 +389,29 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const double marginSize = 10; Margins margins(marginSize); - ChartTwoCartesianAxis* leftAxis = m_chartOverlaySet->getChartAxisLeft(); - ChartTwoCartesianAxis* rightAxis = m_chartOverlaySet->getChartAxisRight(); - ChartTwoCartesianAxis* bottomAxis = m_chartOverlaySet->getChartAxisBottom(); + ChartTwoCartesianAxis* leftAxis = NULL; + ChartTwoCartesianAxis* rightAxis = NULL; + ChartTwoCartesianAxis* bottomAxis = NULL; ChartTwoCartesianAxis* topAxis = NULL; - -// leftAxis->setVisible(haveLeftAxisFlag); -// rightAxis->setVisible(haveRightAxisFlag); -// bottomAxis->setVisible(haveBottomAxisFlag); + + std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); + for (auto axis : displayedAxes) { + CaretAssert(axis); + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + bottomAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + leftAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + rightAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + topAxis = axis; + break; + } + } const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; diff --git a/src/Charting/ChartAxisLocationEnum.cxx b/src/Charting/ChartAxisLocationEnum.cxx index 0de4a227e..abd51637a 100644 --- a/src/Charting/ChartAxisLocationEnum.cxx +++ b/src/Charting/ChartAxisLocationEnum.cxx @@ -379,3 +379,33 @@ ChartAxisLocationEnum::getAllGuiNames(std::vector& allGuiNames, const b } } +/** + * Get the opposite axis for the given axis (left <--> right; top <--> bottom). + * + * @param axis + * The axis. + * @return + * Opposite axis. + */ +ChartAxisLocationEnum::Enum +ChartAxisLocationEnum::getOppositeAxis(const ChartAxisLocationEnum::Enum axis) +{ + ChartAxisLocationEnum::Enum oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM; + switch (axis) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM; + break; + } + return oppositeAxis; +} + + diff --git a/src/Charting/ChartAxisLocationEnum.h b/src/Charting/ChartAxisLocationEnum.h index f6c1b0673..f565c1737 100644 --- a/src/Charting/ChartAxisLocationEnum.h +++ b/src/Charting/ChartAxisLocationEnum.h @@ -66,6 +66,8 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + static ChartAxisLocationEnum::Enum getOppositeAxis(const ChartAxisLocationEnum::Enum axis); + private: ChartAxisLocationEnum(const Enum enumValue, const AString& name, diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 2d0afff90..f484da380 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -236,7 +236,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT ChartTwoCartesianAxis* selectedAxis = NULL; - const ChartAxisLocationEnum::Enum defaultAxis = getSelectedAxisLocation(); + const ChartAxisLocationEnum::Enum lastSelectedAxis = getSelectedAxisLocation(); m_axisComboBox->blockSignals(true); m_axisComboBox->getComboBox()->clear(); @@ -259,21 +259,38 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT } if (chartOverlaySet != NULL) { - int32_t defaultAxisIndex = 0; + int32_t defaultAxisIndex = -1; std::vector validAxesLocations; std::vector axes = chartOverlaySet->getDisplayedChartAxes(); const int32_t numAxes = static_cast(axes.size()); for (int32_t i = 0; i < numAxes; i++) { const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); - if (defaultAxis == axisLocation) { + if (lastSelectedAxis == axisLocation) { defaultAxisIndex = i; } validAxesLocations.push_back(axisLocation); } CaretAssert(validAxesLocations.size() == axes.size()); + if (defaultAxisIndex < 0) { + /* + * If selected axis not found, switch to opposite axis + * User may have switched vertical axis from left to right + */ + ChartAxisLocationEnum::Enum oppositeAxis = ChartAxisLocationEnum::getOppositeAxis(lastSelectedAxis); + for (int32_t i = 0; i < numAxes; i++) { + if (oppositeAxis == axes[i]->getAxisLocation()) { + defaultAxisIndex = i; + break; + } + } + } + if ( ! axes.empty()) { + if (defaultAxisIndex < 0) { + defaultAxisIndex = 0; + } CaretAssertVectorIndex(validAxesLocations, defaultAxisIndex); const ChartAxisLocationEnum::Enum axisLocation = validAxesLocations[defaultAxisIndex]; m_axisComboBox->setupWithItems(validAxesLocations); diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 99c50bf91..1dcfb8a65 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -901,7 +901,7 @@ ChartTwoOverlayViewController::updateUserInterface() void ChartTwoOverlayViewController::updateGraphicsWindow() { - EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); + //EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } -- GitLab From 93f7027ff705a5113e73e83ea9125b019b193786 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Mar 2017 10:03:07 -0500 Subject: [PATCH 238/755] Reduce with of 'Fixed' section in Palette settings of Overlay and Map Settings dialog. --- .../MapSettingsPaletteColorMappingWidget.cxx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 9f634d084..f8071ecac 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -1223,7 +1223,7 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() * Spin box width */ const int percentSpinBoxWidth = 75; - const int fixedSpinBoxWidth = 100; // fixed may have much larger data values + const int fixedSpinBoxWidth = 82; // fixed may have much larger data values /* * Percentage mapping */ @@ -1315,7 +1315,7 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-BIG_NUMBER, 0.0, 1.0, - 3, + 2, this, SLOT(scaleFixedNegativeMaximumValueChanged(double))); @@ -1328,7 +1328,7 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-BIG_NUMBER, 0.0, 1.0, - 3, + 2, this, SLOT(scaleFixedNegativeMinimumValueChanged(double))); @@ -1341,7 +1341,7 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, BIG_NUMBER, 1.0, - 3, + 2, this, SLOT(scaleFixedPositiveMinimumValueChanged(double))); @@ -1354,7 +1354,7 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, BIG_NUMBER, 1.0, - 3, + 2, this, SLOT(scaleFixedPositiveMaximumValueChanged(double))); @@ -1366,10 +1366,15 @@ MapSettingsPaletteColorMappingWidget::createPaletteSection() /* * Labels for values at palette percentages */ - this->scaleNegativeMaximumValueLabel = new QLabel(""); - this->scaleNegativeMinimumValueLabel = new QLabel(""); - this->scalePositiveMinimumValueLabel = new QLabel(""); - this->scalePositiveMaximumValueLabel = new QLabel(""); + const AString bigText(7, QChar(' ')); + this->scaleNegativeMaximumValueLabel = new QLabel(bigText); + this->scaleNegativeMinimumValueLabel = new QLabel(bigText); + this->scalePositiveMinimumValueLabel = new QLabel(bigText); + this->scalePositiveMaximumValueLabel = new QLabel(bigText); +// this->scaleNegativeMaximumValueLabel->setSizePolicy(QSizePolicy::Fixed, this->scaleNegativeMaximumValueLabel->sizePolicy().verticalPolicy()); +// this->scaleNegativeMinimumValueLabel->setSizePolicy(QSizePolicy::Fixed, this->scaleNegativeMinimumValueLabel->sizePolicy().verticalPolicy()); +// this->scalePositiveMinimumValueLabel->setSizePolicy(QSizePolicy::Fixed, this->scalePositiveMinimumValueLabel->sizePolicy().verticalPolicy()); +// this->scalePositiveMaximumValueLabel->setSizePolicy(QSizePolicy::Fixed, this->scalePositiveMaximumValueLabel->sizePolicy().verticalPolicy()); /* * Layout widgets -- GitLab From fdf0ebe72bd1d4cbfdae111a0c1fb4e63fd0ebb2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Mar 2017 10:16:44 -0500 Subject: [PATCH 239/755] Prevent excessive expansion in height of palette settings widget. Histogram was sometimes very tall making the dialog very tall. --- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index f8071ecac..37d0bf1a2 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -132,33 +132,27 @@ MapSettingsPaletteColorMappingWidget::MapSettingsPaletteColorMappingWidget(QWidg this->setLayoutSpacingAndMargins(leftLayout); leftLayout->addWidget(thresholdWidget); leftLayout->addWidget(paletteWidget); - leftLayout->addStretch(); +// leftLayout->addStretch(); QVBoxLayout* dataLayout = new QVBoxLayout(); dataLayout->addWidget(normalizationWidget); dataLayout->addWidget(dataOptionsWidget); - //dataLayout->addStretch(); - -// QHBoxLayout* histoColorBarLayout = new QHBoxLayout(); -// histoColorBarLayout->addWidget(histogramControlWidget); -// histoColorBarLayout->addStretch(); QWidget* bottomRightWidget = new QWidget(); QHBoxLayout* bottomRightLayout = new QHBoxLayout(bottomRightWidget); this->setLayoutSpacingAndMargins(bottomRightLayout); -// bottomRightLayout->addLayout(histoColorBarLayout); bottomRightLayout->addWidget(histogramControlWidget); bottomRightLayout->addLayout(dataLayout); bottomRightLayout->addStretch(); bottomRightWidget->setFixedHeight(bottomRightWidget->sizeHint().height()); -// bottomRightWidget->setFixedSize(bottomRightWidget->sizeHint()); QWidget* rightWidget = new QWidget(); QVBoxLayout* rightLayout = new QVBoxLayout(rightWidget); this->setLayoutSpacingAndMargins(rightLayout); rightLayout->addWidget(histogramWidget, 100); rightLayout->addWidget(bottomRightWidget, 0); - rightLayout->addStretch(); + rightWidget->setFixedHeight(leftWidget->sizeHint().height()); +// rightLayout->addStretch(); QHBoxLayout* layout = new QHBoxLayout(this); this->setLayoutSpacingAndMargins(layout); -- GitLab From 6c44e9f5e4efcb37fde3223c1f8403298d5961d1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Mar 2017 09:58:34 -0500 Subject: [PATCH 240/755] Histogram's display mode had mutually exclusive modes of bars or envelope and now the user may use either or both of bars and envelope. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 407 +++++++++--------- .../MapSettingsPaletteColorMappingWidget.cxx | 264 +++++++----- .../MapSettingsPaletteColorMappingWidget.h | 4 +- src/Palette/CMakeLists.txt | 2 - src/Palette/PaletteColorMapping.cxx | 57 ++- src/Palette/PaletteColorMapping.h | 13 +- src/Palette/PaletteColorMappingSaxReader.cxx | 16 +- src/Palette/PaletteColorMappingXmlElements.h | 3 +- src/Palette/PaletteHistogramChartTypeEnum.cxx | 373 ---------------- src/Palette/PaletteHistogramChartTypeEnum.h | 104 ----- 10 files changed, 412 insertions(+), 831 deletions(-) delete mode 100644 src/Palette/PaletteHistogramChartTypeEnum.cxx delete mode 100644 src/Palette/PaletteHistogramChartTypeEnum.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 53d58ac8b..82beae307 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -629,127 +629,152 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); CaretAssert(cmdf); const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); - switch (paletteColorMapping->getHistogramChartType()) { - case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS: - { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 4; - const int32_t totalVertices = verticesPerBar * numValues; - quadVerticesXYZ.reserve(totalVertices * 3); - std::vector quadVerticesNormals; - quadVerticesNormals.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - const float normalVector[3] = { 0.0, 0.0, 1.0 }; - - const float z = 0.; - - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(rgbaValues, i*4 + 3); - const float* rgba = &rgbaValues[i * 4]; - if (rgba[3] > 0.0) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i+1]; - float bottom = 0; - CaretAssertVectorIndex(yValues, i); - float top = yValues[i]; - - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - - for (int32_t iNormal = 0; iNormal < verticesPerBar; iNormal++) { - quadVerticesNormals.insert(quadVerticesNormals.end(), - normalVector, normalVector + 3); - } + if (paletteColorMapping->isHistogramBarsVisible()) { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 4; + const int32_t totalVertices = verticesPerBar * numValues; + quadVerticesXYZ.reserve(totalVertices * 3); + std::vector quadVerticesNormals; + quadVerticesNormals.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + const float normalVector[3] = { 0.0, 0.0, 1.0 }; + + const float z = 0.; + + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(rgbaValues, i*4 + 3); + const float* rgba = &rgbaValues[i * 4]; + if (rgba[3] > 0.0) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i+1]; + float bottom = 0; + CaretAssertVectorIndex(yValues, i); + float top = yValues[i]; + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + + for (int32_t iNormal = 0; iNormal < verticesPerBar; iNormal++) { + quadVerticesNormals.insert(quadVerticesNormals.end(), + normalVector, normalVector + 3); + } + + if (m_identificationModeFlag) { + uint8_t idRGBA[4]; + addToHistogramIdentification(mapIndex, i, idRGBA); - if (m_identificationModeFlag) { - uint8_t idRGBA[4]; - addToHistogramIdentification(mapIndex, i, idRGBA); - - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); } - else { - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } + } + else { + for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + rgba, rgba + 4); } } } + } + + /* + * Draw the bar elements. + */ + CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesByteRGBA); + } + else { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, + quadVerticesNormals, + quadVerticesFloatRGBA); + } + } + + if (paletteColorMapping->isHistogramEnvelopeVisible()) { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 2; + const int32_t totalVertices = verticesPerBar * numValues + 4; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.0; + + const int32_t lastValueIndex = numValues - 1; + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i + 1]; + CaretAssert(right >= left); + float bottom = 0; + CaretAssertVectorIndex(yValues, i); + float top = yValues[i]; - /* - * Draw the bar elements. - */ - CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); + uint8_t idRGBA[4]; if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesByteRGBA); + addToHistogramIdentification(mapIndex, i, idRGBA); } - else { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesFloatRGBA); - } - } - break; - case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_ENVELOPE: - { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 2; - const int32_t totalVertices = verticesPerBar * numValues + 4; - quadVerticesXYZ.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - - const float z = 0.0; - const int32_t lastValueIndex = numValues - 1; - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i + 1]; - CaretAssert(right >= left); - float bottom = 0; - CaretAssertVectorIndex(yValues, i); - float top = yValues[i]; - - CaretAssertVectorIndex(rgbaValues, i*4 + 3); - const float* rgba = &rgbaValues[i * 4]; - - uint8_t idRGBA[4]; + if (i == 0) { + /* + * Left side of first bar + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - addToHistogramIdentification(mapIndex, i, idRGBA); + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); } - - if (i == 0) { + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + } + else { + if (top > yValues[i - 1]) { /* - * Left side of first bar + * Line from previous bar that is lower in + * height than this bar */ quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(yValues[i - 1]); quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), @@ -757,8 +782,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } + quadVerticesXYZ.push_back(left); quadVerticesXYZ.push_back(top); quadVerticesXYZ.push_back(z); @@ -768,45 +795,45 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } } - else { - if (top > yValues[i - 1]) { - /* - * Line from previous bar that is lower in - * height than this bar - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(yValues[i - 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - } - + } + + /* + * Draw line across top + */ + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + + if (i == lastValueIndex) { /* - * Draw line across top + * Right side of last bar */ - quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(right); quadVerticesXYZ.push_back(top); quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { @@ -815,10 +842,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); + quadVerticesXYZ.push_back(bottom); quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), @@ -826,12 +854,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } - - if (i == lastValueIndex) { + } + else { + if (top > yValues[i + 1]) { /* - * Right side of last bar + * Line from bar down to next bar + * with a lower height */ quadVerticesXYZ.push_back(right); quadVerticesXYZ.push_back(top); @@ -842,10 +873,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(yValues[i + 1]); quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), @@ -853,64 +885,33 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - } - else { - if (top > yValues[i + 1]) { - /* - * Line from bar down to next bar - * with a lower height - */ - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(yValues[i + 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); } } } + } + + /* + * Draw the elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - /* - * Draw the line elements. - */ - if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - - const float lineWidth = 5.0; - BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, - quadVerticesByteRGBA, - lineWidth); - } - else { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - - const float lineWidth = 1.0; - BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, - quadVerticesFloatRGBA, - lineWidth); - } + const float lineWidth = 5.0; + BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, + quadVerticesByteRGBA, + lineWidth); + } + else { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + + const float lineWidth = 1.0; + BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, + quadVerticesFloatRGBA, + lineWidth); } - break; } - } if (m_identificationModeFlag) { diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 37d0bf1a2..2d6ccdad8 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -726,9 +726,20 @@ MapSettingsPaletteColorMappingWidget::thresholdRangeModeChanged() QWidget* MapSettingsPaletteColorMappingWidget::createHistogramControlSection() { - /* - * Control section - */ + QLabel* showLabel = new QLabel("Show "); + m_histogramBarsVisibleCheckBox = new QCheckBox("Bars"); + QObject::connect(m_histogramBarsVisibleCheckBox, &QCheckBox::clicked, + [=] { this->applyAndUpdate(); } ); + + m_histogramEnvelopeVisibleCheckBox = new QCheckBox("Envelope"); + QObject::connect(m_histogramEnvelopeVisibleCheckBox, &QCheckBox::clicked, + [=] { this->applyAndUpdate(); }); + + QHBoxLayout* showLayout = new QHBoxLayout(); + showLayout->addWidget(m_histogramBarsVisibleCheckBox); + showLayout->addStretch(); + showLayout->addWidget(m_histogramEnvelopeVisibleCheckBox); + QLabel* horizRangeLabel = new QLabel("Range"); m_histogramHorizontalRangeComboBox = new EnumComboBoxTemplate(this); QObject::connect(this->m_histogramHorizontalRangeComboBox, SIGNAL(itemActivated()), @@ -736,7 +747,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() this->m_histogramHorizontalRangeComboBox->setup(); this->m_histogramHorizontalRangeComboBox->getWidget()->setToolTip("Horizontal range of histogram"); - QLabel* colorLabel = new QLabel("Color"); + QLabel* colorLabel = new QLabel("Bars Color"); m_histogramColorComboBox = new CaretColorEnumComboBox("With Palette", this); WuQtUtilities::setToolTipAndStatusTip(m_histogramColorComboBox->getWidget(), @@ -744,13 +755,6 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() QObject::connect(m_histogramColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); - QLabel* chartTypeLabel = new QLabel("Chart"); - m_histogramChartTypeComboBox = new EnumComboBoxTemplate(this); - QObject::connect(this->m_histogramChartTypeComboBox, SIGNAL(itemActivated()), - this, SLOT(applyAndUpdate())); - this->m_histogramChartTypeComboBox->setup(); - this->m_histogramChartTypeComboBox->getWidget()->setToolTip("Set type of chart drawn"); - const int32_t maxBuckets = 100000; QLabel* bucketsLabel = new QLabel("Buckets"); m_histogramBucketsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, maxBuckets, 1); @@ -760,14 +764,19 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() QWidget* controlWidget = new QWidget(); QGridLayout* controlLayout = new QGridLayout(controlWidget); this->setLayoutSpacingAndMargins(controlLayout); - controlLayout->addWidget(chartTypeLabel, 0, 0); - controlLayout->addWidget(m_histogramChartTypeComboBox->getWidget(), 0, 1); - controlLayout->addWidget(colorLabel, 1, 0); - controlLayout->addWidget(m_histogramColorComboBox->getWidget(), 1, 1); - controlLayout->addWidget(horizRangeLabel, 2, 0); - controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), 2, 1); - controlLayout->addWidget(bucketsLabel, 3, 0); - controlLayout->addWidget(m_histogramBucketsSpinBox, 3, 1); + int rowIndex = 0; + controlLayout->addWidget(showLabel, rowIndex, 0); + controlLayout->addLayout(showLayout, rowIndex, 1); + rowIndex++; + controlLayout->addWidget(colorLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramColorComboBox->getWidget(), rowIndex, 1); + rowIndex++; + controlLayout->addWidget(horizRangeLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), rowIndex, 1); + rowIndex++; + controlLayout->addWidget(bucketsLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramBucketsSpinBox, rowIndex, 1); + rowIndex++; controlWidget->setFixedSize(controlWidget->sizeHint()); /* @@ -1714,7 +1723,8 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile m_histogramColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramColor()); - m_histogramChartTypeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramChartType()); + m_histogramBarsVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramBarsVisible()); + m_histogramEnvelopeVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramEnvelopeVisible()); m_histogramHorizontalRangeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramRangeMode()); @@ -2006,125 +2016,142 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } } - PaletteHistogramChartTypeEnum::Enum histogramChartType = this->paletteColorMapping->getHistogramChartType(); - const bool allowEnvelopeChartTypeFlag = false; - if ( ! allowEnvelopeChartTypeFlag) { - histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; - } +// const bool drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); +// bool drawEnvelopeFlag = false; +// const bool allowEnvelopeChartTypeFlag = true; +// if (allowEnvelopeChartTypeFlag) { +// drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); +// } - const bool displayZeros = paletteColorMapping->isDisplayZeroDataFlag(); + const QPalette palette = this->thresholdPlot->palette(); + const QPalette::ColorRole foregroundRole = this->thresholdPlot->foregroundRole(); + const QBrush foregroundBrush = palette.brush(foregroundRole); + const QColor foregroundColor = foregroundBrush.color(); float z = 0.0; float maxDataFrequency = 0.0; - const int32_t lastIndex = numHistogramValues - 1; - for (int64_t ix = 0; ix < numHistogramValues; ix++) { - QColor color; - const int64_t ix4 = ix * 4; - color.setRedF(dataRGBA[ix4]); - color.setGreenF(dataRGBA[ix4+1]); - color.setBlueF(dataRGBA[ix4+2]); - color.setAlphaF(1.0); - - const float startValue = dataValues[ix]; - const float stopValue = dataValues[ix + 1]; - float dataFrequency = displayData[ix]; - - bool displayIt = true; - -// if (displayZeros == false) { -// if ((startValue <= 0.0) && (stopValue >= 0.0)) { -// dataFrequency = 0.0; -// displayIt = false; -// } -// } - - if (dataFrequency > maxDataFrequency) { - maxDataFrequency = dataFrequency; + for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { + bool drawBarsFlag = false; + bool drawEnvelopeFlag = false; + if (drawModeInt == 0) { + drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); } - - /* - * If color is not displayed ('none' or thresholded), - * set its frequncey value to a small value so that the plot - * retains its shape and color is still slightly visible - */ - //Qt::BrushStyle brushStyle = Qt::SolidPattern; - if (dataRGBA[ix4+3] <= 0.0) { - displayIt = false; + else if (drawModeInt == 1) { + drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); } - if (displayIt == false) { - color.setAlpha(0); - } - - QVector samples; - - QwtPlotCurve* curve = new QwtPlotCurve(); - curve->setRenderHint(QwtPlotItem::RenderAntialiased); - curve->setVisible(true); - - curve->setPen(QPen(color)); - switch (histogramChartType) { - case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS: - curve->setStyle(QwtPlotCurve::Steps); - curve->setBrush(QBrush(color)); - samples.push_back(QPointF(startValue, dataFrequency)); - samples.push_back(QPointF(stopValue, dataFrequency)); - break; - case PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_ENVELOPE: - curve->setStyle(QwtPlotCurve::Lines); - //curve->setBrush(QBrush(color)); + if (drawBarsFlag + || drawEnvelopeFlag) { + const int32_t lastIndex = numHistogramValues - 1; + for (int64_t ix = 0; ix < numHistogramValues; ix++) { + QColor color; + const int64_t ix4 = ix * 4; + if (drawBarsFlag) { + color.setRedF(dataRGBA[ix4]); + color.setGreenF(dataRGBA[ix4+1]); + color.setBlueF(dataRGBA[ix4+2]); + color.setAlphaF(1.0); + } + else if (drawEnvelopeFlag) { + color = foregroundColor; + } + + const float startValue = dataValues[ix]; + const float stopValue = dataValues[ix + 1]; + float dataFrequency = displayData[ix]; + + bool displayIt = true; + + if (dataFrequency > maxDataFrequency) { + maxDataFrequency = dataFrequency; + } /* - * Left side + * If color is not displayed ('none' or thresholded), + * set its frequncey value to a small value so that the plot + * retains its shape and color is still slightly visible */ - if (ix == 0) { - samples.push_back(QPointF(startValue, 0.0)); - samples.push_back(QPointF(startValue, dataFrequency)); + //Qt::BrushStyle brushStyle = Qt::SolidPattern; + if (dataRGBA[ix4+3] <= 0.0) { + displayIt = false; } - else { - CaretAssertVectorIndex(displayData, ix - 1); - const float lastFrequency = displayData[ix - 1]; - if (dataFrequency > lastFrequency) { - samples.push_back(QPointF(startValue, lastFrequency)); - samples.push_back(QPointF(startValue, dataFrequency)); - } + + if (displayIt == false) { + color.setAlpha(0); } - /* - * Horizontal Bar - */ - samples.push_back(QPointF(startValue, dataFrequency)); - samples.push_back(QPointF(stopValue, dataFrequency)); - - /* - * Right side - */ - if (ix == lastIndex) { + QVector samples; + + QwtPlotCurve* curve = new QwtPlotCurve(); + curve->setRenderHint(QwtPlotItem::RenderAntialiased); + curve->setVisible(true); + + curve->setPen(QPen(color)); + + if (drawBarsFlag) { + curve->setStyle(QwtPlotCurve::Steps); + curve->setBrush(QBrush(color)); + samples.push_back(QPointF(startValue, dataFrequency)); samples.push_back(QPointF(stopValue, dataFrequency)); - samples.push_back(QPointF(stopValue, 0.0)); } - else { - CaretAssertVectorIndex(displayData, ix + 1); - const float nextFrequency = displayData[ix + 1]; - if (dataFrequency > nextFrequency) { + if (drawEnvelopeFlag) { + curve->setStyle(QwtPlotCurve::Lines); + //curve->setBrush(QBrush(color)); + + /* + * Left side + */ + if (ix == 0) { + samples.push_back(QPointF(startValue, 0.0)); + samples.push_back(QPointF(startValue, dataFrequency)); + } + else { + CaretAssertVectorIndex(displayData, ix - 1); + const float lastFrequency = displayData[ix - 1]; + if (dataFrequency > lastFrequency) { + samples.push_back(QPointF(startValue, lastFrequency)); + samples.push_back(QPointF(startValue, dataFrequency)); + } + } + + /* + * Horizontal Bar + */ + samples.push_back(QPointF(startValue, dataFrequency)); + samples.push_back(QPointF(stopValue, dataFrequency)); + + /* + * Right side + */ + if (ix == lastIndex) { samples.push_back(QPointF(stopValue, dataFrequency)); - samples.push_back(QPointF(stopValue, nextFrequency)); + samples.push_back(QPointF(stopValue, 0.0)); + } + else { + CaretAssertVectorIndex(displayData, ix + 1); + const float nextFrequency = displayData[ix + 1]; + if (dataFrequency > nextFrequency) { + samples.push_back(QPointF(stopValue, dataFrequency)); + samples.push_back(QPointF(stopValue, nextFrequency)); + } } } - break; + curve->setSamples(samples); + + curve->attach(this->thresholdPlot); + + if (ix == 0) { + z = curve->z(); + } + } + } - - curve->setSamples(samples); - curve->attach(this->thresholdPlot); - - if (ix == 0) { - z = curve->z(); - } + z--; } - - z = z - 1; + + z--; if ((numHistogramValues > 2) && (this->paletteColorMapping->getThresholdType() != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF)) { @@ -2314,7 +2341,8 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setInterpolatePaletteFlag(this->interpolateColorsCheckBox->isChecked()); this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); - this->paletteColorMapping->setHistogramChartType(m_histogramChartTypeComboBox->getSelectedItem()); + this->paletteColorMapping->setHistogramBarsVisible(m_histogramBarsVisibleCheckBox->isChecked()); + this->paletteColorMapping->setHistogramEnvelopeVisible(m_histogramEnvelopeVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index aca77653c..486343b71 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -201,8 +201,10 @@ namespace caret { CaretColorEnumComboBox* m_histogramColorComboBox; - EnumComboBoxTemplate* m_histogramChartTypeComboBox; + QCheckBox* m_histogramBarsVisibleCheckBox; + QCheckBox* m_histogramEnvelopeVisibleCheckBox; + QSpinBox* m_histogramBucketsSpinBox; CaretMappableDataFile* caretMappableDataFile; diff --git a/src/Palette/CMakeLists.txt b/src/Palette/CMakeLists.txt index d64f78f19..a3a6a9553 100644 --- a/src/Palette/CMakeLists.txt +++ b/src/Palette/CMakeLists.txt @@ -25,7 +25,6 @@ PaletteColorMapping.h PaletteColorMappingSaxReader.h PaletteColorMappingXmlElements.h PaletteEnums.h -PaletteHistogramChartTypeEnum.h PaletteHistogramRangeModeEnum.h PaletteNormalizationModeEnum.h PaletteScalarAndColor.h @@ -36,7 +35,6 @@ PaletteColorBarValuesModeEnum.cxx PaletteColorMapping.cxx PaletteColorMappingSaxReader.cxx PaletteEnums.cxx -PaletteHistogramChartTypeEnum.cxx PaletteHistogramRangeModeEnum.cxx PaletteNormalizationModeEnum.cxx PaletteScalarAndColor.cxx diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index cf4d1175f..3e9df7396 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -135,7 +135,8 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->thresholdRangeMode = pcm.thresholdRangeMode; this->thresholdNegMinPosMaxLinked = pcm.thresholdNegMinPosMaxLinked; this->histogramRangeMode = pcm.histogramRangeMode; - this->histogramChartType = pcm.histogramChartType; + this->histogramBarsVisible = pcm.histogramBarsVisible; + this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; this->histogramColor = pcm.histogramColor; this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; @@ -186,7 +187,8 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->thresholdRangeMode == pcm.thresholdRangeMode) && (this->thresholdNegMinPosMaxLinked == pcm.thresholdNegMinPosMaxLinked) && (this->histogramRangeMode == pcm.histogramRangeMode) - && (this->histogramChartType == pcm.histogramChartType) + && (this->histogramBarsVisible == pcm.histogramBarsVisible) + && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) && (this->histogramColor == pcm.histogramColor) && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets) && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) @@ -234,7 +236,8 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; - this->histogramChartType = PaletteHistogramChartTypeEnum::PALETTE_HISTOGRAM_CHART_BARS; + this->histogramBarsVisible = true; + this->histogramEnvelopeVisible = false; this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; @@ -355,8 +358,10 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) this->thresholdNegMinPosMaxLinked); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE, PaletteHistogramRangeModeEnum::toName(this->histogramRangeMode)); - xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_CHART_TYPE, - PaletteHistogramChartTypeEnum::toName(this->histogramChartType)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_VISIBLE, + this->histogramBarsVisible); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE, + this->histogramEnvelopeVisible); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, CaretColorEnum::toName(this->histogramColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS, @@ -2757,28 +2762,52 @@ PaletteColorMapping::setHistogramRangeMode(const PaletteHistogramRangeModeEnum:: } /** - * @return The histogram chart type. + * @return show histogram bars */ -PaletteHistogramChartTypeEnum::Enum PaletteColorMapping::getHistogramChartType() const +bool +PaletteColorMapping::isHistogramBarsVisible() const { - return this->histogramChartType; + return this->histogramBarsVisible; } /** - * Set the histogram chart type. + * Set show histogram bars * - * @param histogramChartType - * New value for histogram chart type + * @param histogramBarsVisible + * New value for show histogram bars */ void -PaletteColorMapping::setHistogramChartType(const PaletteHistogramChartTypeEnum::Enum histogramChartType) +PaletteColorMapping::setHistogramBarsVisible(const bool histogramBarsVisible) { - if (histogramChartType != this->histogramChartType) { - this->histogramChartType = histogramChartType; + if (histogramBarsVisible != this->histogramBarsVisible) { + this->histogramBarsVisible = histogramBarsVisible; setModified(); } } +/** + * @return show histogram envelope + */ +bool +PaletteColorMapping::isHistogramEnvelopeVisible() const +{ + return this->histogramEnvelopeVisible; +} + +/** + * Set show histogram envelope + * + * @param histogramEnvelopeVisible + * New value for show histogram envelope + */ +void +PaletteColorMapping::setHistogramEnvelopeVisible(const bool histogramEnvelopeVisible) +{ + if (histogramEnvelopeVisible != this->histogramEnvelopeVisible) { + this->histogramEnvelopeVisible = histogramEnvelopeVisible; + setModified(); + } +} /** * @return Color for drawing histogram. diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 7048e6729..d281a6ba8 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -30,7 +30,6 @@ #include "NumericFormatModeEnum.h" #include "PaletteColorBarValuesModeEnum.h" #include "PaletteEnums.h" -#include "PaletteHistogramChartTypeEnum.h" #include "PaletteHistogramRangeModeEnum.h" #include "PaletteThresholdRangeModeEnum.h" #include "XmlException.h" @@ -213,9 +212,13 @@ namespace caret { void setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode); - PaletteHistogramChartTypeEnum::Enum getHistogramChartType() const; + bool isHistogramBarsVisible() const; - void setHistogramChartType(const PaletteHistogramChartTypeEnum::Enum histogramChartType); + void setHistogramBarsVisible(const bool histogramBarsVisible); + + bool isHistogramEnvelopeVisible() const; + + void setHistogramEnvelopeVisible(const bool histogramEnvelopeVisible); CaretColorEnum::Enum getHistogramColor() const; @@ -327,7 +330,9 @@ namespace caret { PaletteHistogramRangeModeEnum::Enum histogramRangeMode; - PaletteHistogramChartTypeEnum::Enum histogramChartType; + bool histogramBarsVisible; + + bool histogramEnvelopeVisible; CaretColorEnum::Enum histogramColor; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 12604cbc9..a18a9376a 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -312,17 +312,11 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, + this->elementText); } } - else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_CHART_TYPE) { - bool isValid = false; - PaletteHistogramChartTypeEnum::Enum histogramChartType = PaletteHistogramChartTypeEnum::fromName(this->elementText, - &isValid); - if (isValid) { - this->paletteColorMapping->setHistogramChartType(histogramChartType); - } - else { - throw XmlSaxParserException("Invalid PaletteHistogramChartTypeEnum::Enum: " - + this->elementText); - } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_VISIBLE) { + this->paletteColorMapping->setHistogramBarsVisible(toBool(this->elementText)); + } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE) { + this->paletteColorMapping->setHistogramEnvelopeVisible(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR) { bool isValid = false; diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index ea64bec6f..babc6609f 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -46,7 +46,8 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_THRESHOLD_RANGE_MODE = "ThresholdRangeMode"; static const AString XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED = "ThresholdLowHighLinked"; static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; - static const AString XML_TAG_HISTOGRAM_CHART_TYPE = "HistogramChartType"; + static const AString XML_TAG_HISTOGRAM_BARS_VISIBLE = "HistogramBarsVisible"; + static const AString XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE = "HistogramEnvelopeVisible"; static const AString XML_TAG_HISTOGRAM_COLOR = "HistogramColor"; static const AString XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; diff --git a/src/Palette/PaletteHistogramChartTypeEnum.cxx b/src/Palette/PaletteHistogramChartTypeEnum.cxx deleted file mode 100644 index 6f200015b..000000000 --- a/src/Palette/PaletteHistogramChartTypeEnum.cxx +++ /dev/null @@ -1,373 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include -#define __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ -#include "PaletteHistogramChartTypeEnum.h" -#undef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ - -#include "CaretAssert.h" - -using namespace caret; - - -/** - * \class caret::PaletteHistogramChartTypeEnum - * \brief Type of chart displayed for histogram. - * - * Using this enumerated type in the GUI with an EnumComboBoxTemplate - * - * Header File (.h) - * Forward declare the data type: - * class EnumComboBoxTemplate; - * - * Declare the member: - * EnumComboBoxTemplate* m_paletteHistogramChartTypeEnumComboBox; - * - * Declare a slot that is called when user changes selection - * private slots: - * void paletteHistogramChartTypeEnumComboBoxItemActivated(); - * - * Implementation File (.cxx) - * Include the header files - * #include "EnumComboBoxTemplate.h" - * #include "PaletteHistogramChartTypeEnum.h" - * - * Instatiate: - * m_paletteHistogramChartTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_paletteHistogramChartTypeEnumComboBox->setup(); - * - * Get notified when the user changes the selection: - * QObject::connect(m_paletteHistogramChartTypeEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(paletteHistogramChartTypeEnumComboBoxItemActivated())); - * - * Update the selection: - * m_paletteHistogramChartTypeEnumComboBox->setSelectedItem(NEW_VALUE); - * - * Read the selection: - * const PaletteHistogramChartTypeEnum::Enum VARIABLE = m_paletteHistogramChartTypeEnumComboBox->getSelectedItem(); - * - */ - -/** - * Constructor. - * - * @param enumValue - * An enumerated value. - * @param name - * Name of enumerated value. - * - * @param guiName - * User-friendly name for use in user-interface. - */ -PaletteHistogramChartTypeEnum::PaletteHistogramChartTypeEnum(const Enum enumValue, - const AString& name, - const AString& guiName) -{ - this->enumValue = enumValue; - this->integerCode = integerCodeCounter++; - this->name = name; - this->guiName = guiName; -} - -/** - * Destructor. - */ -PaletteHistogramChartTypeEnum::~PaletteHistogramChartTypeEnum() -{ -} - -/** - * Initialize the enumerated metadata. - */ -void -PaletteHistogramChartTypeEnum::initialize() -{ - if (initializedFlag) { - return; - } - initializedFlag = true; - - enumData.push_back(PaletteHistogramChartTypeEnum(PALETTE_HISTOGRAM_CHART_BARS, - "PALETTE_HISTOGRAM_CHART_BARS", - "Bars")); - - enumData.push_back(PaletteHistogramChartTypeEnum(PALETTE_HISTOGRAM_CHART_ENVELOPE, - "PALETTE_HISTOGRAM_CHART_ENVELOPE", - "Envelope")); - -} - -/** - * Find the data for and enumerated value. - * @param enumValue - * The enumerated value. - * @return Pointer to data for this enumerated type - * or NULL if no data for type or if type is invalid. - */ -const PaletteHistogramChartTypeEnum* -PaletteHistogramChartTypeEnum::findData(const Enum enumValue) -{ - if (initializedFlag == false) initialize(); - - size_t num = enumData.size(); - for (size_t i = 0; i < num; i++) { - const PaletteHistogramChartTypeEnum* d = &enumData[i]; - if (d->enumValue == enumValue) { - return d; - } - } - - return NULL; -} - -/** - * Get a string representation of the enumerated type. - * @param enumValue - * Enumerated value. - * @return - * String representing enumerated value. - */ -AString -PaletteHistogramChartTypeEnum::toName(Enum enumValue) { - if (initializedFlag == false) initialize(); - - const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); - return enumInstance->name; -} - -/** - * Get an enumerated value corresponding to its name. - * @param name - * Name of enumerated value. - * @param isValidOut - * If not NULL, it is set indicating that a - * enum value exists for the input name. - * @return - * Enumerated value. - */ -PaletteHistogramChartTypeEnum::Enum -PaletteHistogramChartTypeEnum::fromName(const AString& name, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const PaletteHistogramChartTypeEnum& d = *iter; - if (d.name == name) { - enumValue = d.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); - } - return enumValue; -} - -/** - * Get a GUI string representation of the enumerated type. - * @param enumValue - * Enumerated value. - * @return - * String representing enumerated value. - */ -AString -PaletteHistogramChartTypeEnum::toGuiName(Enum enumValue) { - if (initializedFlag == false) initialize(); - - const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); - return enumInstance->guiName; -} - -/** - * Get an enumerated value corresponding to its GUI name. - * @param s - * Name of enumerated value. - * @param isValidOut - * If not NULL, it is set indicating that a - * enum value exists for the input name. - * @return - * Enumerated value. - */ -PaletteHistogramChartTypeEnum::Enum -PaletteHistogramChartTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const PaletteHistogramChartTypeEnum& d = *iter; - if (d.guiName == guiName) { - enumValue = d.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); - } - return enumValue; -} - -/** - * Get the integer code for a data type. - * - * @return - * Integer code for data type. - */ -int32_t -PaletteHistogramChartTypeEnum::toIntegerCode(Enum enumValue) -{ - if (initializedFlag == false) initialize(); - const PaletteHistogramChartTypeEnum* enumInstance = findData(enumValue); - return enumInstance->integerCode; -} - -/** - * Find the data type corresponding to an integer code. - * - * @param integerCode - * Integer code for enum. - * @param isValidOut - * If not NULL, on exit isValidOut will indicate if - * integer code is valid. - * @return - * Enum for integer code. - */ -PaletteHistogramChartTypeEnum::Enum -PaletteHistogramChartTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = PaletteHistogramChartTypeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const PaletteHistogramChartTypeEnum& enumInstance = *iter; - if (enumInstance.integerCode == integerCode) { - enumValue = enumInstance.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteHistogramChartTypeEnum")); - } - return enumValue; -} - -/** - * Get all of the enumerated type values. The values can be used - * as parameters to toXXX() methods to get associated metadata. - * - * @param allEnums - * A vector that is OUTPUT containing all of the enumerated values. - */ -void -PaletteHistogramChartTypeEnum::getAllEnums(std::vector& allEnums) -{ - if (initializedFlag == false) initialize(); - - allEnums.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allEnums.push_back(iter->enumValue); - } -} - -/** - * Get all of the names of the enumerated type values. - * - * @param allNames - * A vector that is OUTPUT containing all of the names of the enumerated values. - * @param isSorted - * If true, the names are sorted in alphabetical order. - */ -void -PaletteHistogramChartTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) -{ - if (initializedFlag == false) initialize(); - - allNames.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allNames.push_back(PaletteHistogramChartTypeEnum::toName(iter->enumValue)); - } - - if (isSorted) { - std::sort(allNames.begin(), allNames.end()); - } -} - -/** - * Get all of the GUI names of the enumerated type values. - * - * @param allNames - * A vector that is OUTPUT containing all of the GUI names of the enumerated values. - * @param isSorted - * If true, the names are sorted in alphabetical order. - */ -void -PaletteHistogramChartTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) -{ - if (initializedFlag == false) initialize(); - - allGuiNames.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allGuiNames.push_back(PaletteHistogramChartTypeEnum::toGuiName(iter->enumValue)); - } - - if (isSorted) { - std::sort(allGuiNames.begin(), allGuiNames.end()); - } -} - diff --git a/src/Palette/PaletteHistogramChartTypeEnum.h b/src/Palette/PaletteHistogramChartTypeEnum.h deleted file mode 100644 index 82d508e85..000000000 --- a/src/Palette/PaletteHistogramChartTypeEnum.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ -#define __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include -#include -#include "AString.h" - -namespace caret { - -class PaletteHistogramChartTypeEnum { - -public: - /** - * Enumerated values. - */ - enum Enum { - /** */ - PALETTE_HISTOGRAM_CHART_BARS, - /** */ - PALETTE_HISTOGRAM_CHART_ENVELOPE - }; - - - ~PaletteHistogramChartTypeEnum(); - - static AString toName(Enum enumValue); - - static Enum fromName(const AString& name, bool* isValidOut); - - static AString toGuiName(Enum enumValue); - - static Enum fromGuiName(const AString& guiName, bool* isValidOut); - - static int32_t toIntegerCode(Enum enumValue); - - static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); - - static void getAllEnums(std::vector& allEnums); - - static void getAllNames(std::vector& allNames, const bool isSorted); - - static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); - -private: - PaletteHistogramChartTypeEnum(const Enum enumValue, - const AString& name, - const AString& guiName); - - static const PaletteHistogramChartTypeEnum* findData(const Enum enumValue); - - /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; - - /** Initialize instances that contain the enum values and metadata */ - static void initialize(); - - /** Indicates instance of enum values and metadata have been initialized */ - static bool initializedFlag; - - /** Auto generated integer codes */ - static int32_t integerCodeCounter; - - /** The enumerated type value for an instance */ - Enum enumValue; - - /** The integer code associated with an enumerated value */ - int32_t integerCode; - - /** The name, a text string that is identical to the enumerated value */ - AString name; - - /** A user-friendly name that is displayed in the GUI */ - AString guiName; -}; - -#ifdef __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ -std::vector PaletteHistogramChartTypeEnum::enumData; -bool PaletteHistogramChartTypeEnum::initializedFlag = false; -int32_t PaletteHistogramChartTypeEnum::integerCodeCounter = 0; -#endif // __PALETTE_HISTOGRAM_CHART_TYPE_ENUM_DECLARE__ - -} // namespace -#endif //__PALETTE_HISTOGRAM_CHART_TYPE_ENUM_H__ -- GitLab From 5e485cf34f2ac37fb8b62ffb096114125d1cd7ce Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Mar 2017 11:07:25 -0500 Subject: [PATCH 241/755] When drawing histograms draw all histogram bars first followed by all histogram envelopes so that the bars do not hide envelopes in lower layers. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 268 ++++++++++++------ .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 22 +- 2 files changed, 194 insertions(+), 96 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 82beae307..175634c71 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -257,27 +257,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); } -class HistogramChartDrawingInfo { -public: - HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - const ChartableTwoFileHistogramChart* histogramChart, - int32_t mapIndex, - ChartAxisLocationEnum::Enum verticalAxisLocation) - : m_histogramDrawingInfo(histogramDrawingInfo), - m_histogramChart(histogramChart), - m_mapIndex(mapIndex), - m_verticalAxisLocation(verticalAxisLocation) { } - - HistogramDrawingInfo* m_histogramDrawingInfo; - const ChartableTwoFileHistogramChart* m_histogramChart; - int32_t m_mapIndex; - ChartAxisLocationEnum::Enum m_verticalAxisLocation; - - ~HistogramChartDrawingInfo() { - delete m_histogramDrawingInfo; - } -}; - /** * Draw histogram charts. */ @@ -380,8 +359,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Bounds valid? */ if ((xMin < xMax) - && ((yMinLeft < yMaxLeft) - || (yMinRight < yMaxRight))) { + && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { /* * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. @@ -393,7 +371,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() ChartTwoCartesianAxis* rightAxis = NULL; ChartTwoCartesianAxis* bottomAxis = NULL; ChartTwoCartesianAxis* topAxis = NULL; - + std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); for (auto axis : displayedAxes) { CaretAssert(axis); @@ -416,7 +394,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; - + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, leftAxis, width, height); margins.m_left = std::max(margins.m_left, width); estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpHeight, rightAxis, width, height); @@ -453,13 +431,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() } if (drawChartAxisCartesian(boundsRight, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - rightAxis, - axisMinimumValue, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + rightAxis, + axisMinimumValue, axisMaximumValue)) { yMinRight = axisMinimumValue; yMaxRight = axisMaximumValue; @@ -501,79 +479,168 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() chartGraphicsDrawingViewport[3]); + /* + * Draw the bars for all histogram and then draw the envelopes + * so the envelopes are not obscured by the bars + */ + for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { for (auto& drawInfo : drawingInfo) { if (drawInfo->m_histogramDrawingInfo->isValid()) { - - bool leftVerticalAxisFlag = true; - switch (drawInfo->m_verticalAxisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - leftVerticalAxisFlag = false; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - break; + const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); + CaretAssert(cmdf); + const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); + bool drawBarsFlag = false; + bool drawEnvelopeFlag = false; + if (drawModeInt == 0) { + drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (leftVerticalAxisFlag) { - glOrtho(xMin, xMax, - yMinLeft, yMaxLeft, - -10.0, 10.0); - } - else { - glOrtho(xMin, xMax, - yMinRight, yMaxRight, - -10.0, 10.0); + else if (drawModeInt == 1) { + drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - bool applyTransformationsFlag = false; - if (applyTransformationsFlag) { - glTranslatef(m_translation[0], - m_translation[1], - 0.0); + if (drawBarsFlag + || drawEnvelopeFlag) { + bool leftVerticalAxisFlag = true; + switch (drawInfo->m_verticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + leftVerticalAxisFlag = false; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (leftVerticalAxisFlag) { + glOrtho(xMin, xMax, + yMinLeft, yMaxLeft, + -10.0, 10.0); + } + else { + glOrtho(xMin, xMax, + yMinRight, yMaxRight, + -10.0, 10.0); + } - const float chartWidth = chartGraphicsDrawingViewport[2]; - const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; - glTranslatef(halfWidth, - halfHeight, - 0.0); - glScalef(m_zooming, - m_zooming, - 1.0); - glTranslatef(-halfWidth, - -halfHeight, - 0.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = false; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + drawHistogramChartContent(drawInfo, + drawBarsFlag, + drawEnvelopeFlag); } - - drawHistogramChartContent(drawInfo->m_histogramChart, - drawInfo->m_mapIndex, - *drawInfo->m_histogramDrawingInfo); } } - } - - for (auto& histDrawInfo : drawingInfo) { - delete histDrawInfo; + } + +// for (auto& drawInfo : drawingInfo) { +// if (drawInfo->m_histogramDrawingInfo->isValid()) { +// +// bool leftVerticalAxisFlag = true; +// switch (drawInfo->m_verticalAxisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// leftVerticalAxisFlag = false; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// break; +// } +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// if (leftVerticalAxisFlag) { +// glOrtho(xMin, xMax, +// yMinLeft, yMaxLeft, +// -10.0, 10.0); +// } +// else { +// glOrtho(xMin, xMax, +// yMinRight, yMaxRight, +// -10.0, 10.0); +// } +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool applyTransformationsFlag = false; +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = chartGraphicsDrawingViewport[2]; +// const float chartHeight = chartGraphicsDrawingViewport[3]; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// drawHistogramChartContent(drawInfo->m_histogramChart, +// drawInfo->m_mapIndex, +// *drawInfo->m_histogramDrawingInfo, +// true, +// true); +// } +// } } } /* * Draw the given histogram chart. + * + * @param drawingInfo + * Histogram drawing information.. + * @param drawHistogramBarsFlag + * Draw the histogram as bars. + * @param drawHistogramEnvelopeFlag + * Draw the histogram as an envelope. + * */ void -BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex, - const HistogramDrawingInfo& histogramDrawingInfo) +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, + const bool drawHistogramBarsFlag, + const bool drawHistogramEnvelopeFlag) { + const ChartableTwoFileHistogramChart* histogramChart = drawingInfo->m_histogramChart; + const int32_t mapIndex = drawingInfo->m_mapIndex; + const HistogramDrawingInfo& histogramDrawingInfo = *drawingInfo->m_histogramDrawingInfo; + if ( ! histogramDrawingInfo.isValid()) { return; } @@ -626,10 +693,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab std::vector quadVerticesByteRGBA; - const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); - CaretAssert(cmdf); - const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(mapIndex); - if (paletteColorMapping->isHistogramBarsVisible()) { +// const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); +// CaretAssert(cmdf); + if (drawHistogramBarsFlag) { /* * Reserve to prevent reszing of vectors * as elements are added. @@ -710,7 +776,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Chartab } } - if (paletteColorMapping->isHistogramEnvelopeVisible()) { + if (drawHistogramEnvelopeFlag) { /* * Reserve to prevent reszing of vectors * as elements are added. @@ -2620,3 +2686,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data return true; } + +BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, + const ChartableTwoFileHistogramChart* histogramChart, + int32_t mapIndex, + ChartAxisLocationEnum::Enum verticalAxisLocation) +: m_histogramDrawingInfo(histogramDrawingInfo), +m_histogramChart(histogramChart), +m_mapIndex(mapIndex), +m_verticalAxisLocation(verticalAxisLocation) +{ +} + + +BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() { + delete m_histogramDrawingInfo; +} diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 26197e959..a4eeeeaf7 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -23,6 +23,7 @@ #include #include "BrainOpenGLChartTwoDrawingInterface.h" +#include "ChartAxisLocationEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" namespace caret { @@ -55,6 +56,21 @@ namespace caret { // ADD_NEW_METHODS_HERE private: + class HistogramChartDrawingInfo { + public: + HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, + const ChartableTwoFileHistogramChart* histogramChart, + int32_t mapIndex, + ChartAxisLocationEnum::Enum verticalAxisLocation); + + HistogramDrawingInfo* m_histogramDrawingInfo; + const ChartableTwoFileHistogramChart* m_histogramChart; + int32_t m_mapIndex; + ChartAxisLocationEnum::Enum m_verticalAxisLocation; + + ~HistogramChartDrawingInfo(); + }; + class Margins { public: Margins(const double defaultSize) { @@ -111,9 +127,9 @@ namespace caret { void drawHistogramChart(); - void drawHistogramChartContent(const ChartableTwoFileHistogramChart* histogramChart, - const int32_t mapIndex, - const HistogramDrawingInfo& histogramDrawingInfo); + void drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, + const bool drawHistogramBarsFlag, + const bool drawHistogramEnvelopeFlag); void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, -- GitLab From 91dfa9dff06bdd2f222387fa5c4fde6eb870e635 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 31 Mar 2017 12:57:02 -0500 Subject: [PATCH 242/755] Fixed problem with yoking for Chart Overlays including allowing yoking of a chart overlay to a map overlay. --- src/Brain/ChartTwoOverlay.cxx | 88 +++++-- src/Brain/ChartTwoOverlay.h | 2 + src/Brain/ChartTwoOverlaySet.cxx | 250 +++++++------------ src/Files/ChartableTwoFileHistogramChart.cxx | 1 - src/Files/EventMapYokingValidation.cxx | 2 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 31 +-- src/GuiQt/MapYokingGroupComboBox.cxx | 80 +----- 7 files changed, 165 insertions(+), 289 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 5b3faa4d5..95ea31950 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -69,7 +69,6 @@ m_overlayIndex(overlayIndex) { CaretAssert(m_parentChartTwoOverlaySet); - // m_chartCompoundDataType m_name = "Overlay " + AString::number(overlayIndex + 1); m_enabled = (m_overlayIndex == 0); m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; @@ -329,10 +328,36 @@ ChartTwoOverlay::isHistorySupported() const } /** - * Is map yoking supported ? + * @return Is map yoking supported ? + * + * NOTE: Within this class, do not use this method. + * Instead, use isMapYokingSupportedPrivate(). */ bool ChartTwoOverlay::isMapYokingSupported() const +{ + CaretMappableDataFile* mapFile = NULL; + SelectedIndexType indexType = SelectedIndexType::INVALID; + int32_t mapIndex = -1; + getSelectionData(mapFile, indexType, mapIndex); + + return isMapYokingSupportedPrivate(mapFile); +} + +/** + * Is map yoking supported for the given map file? + * This is a private method and used within this class. + * as use of the public method could cause stack + * overlow by use of isMapYokingSupported() and + * getSelectionData(). + * + * @param mapFile + * The map file. A NULL value is allowed. + * @return + * True if map yoking is supported, else false. + */ +bool +ChartTwoOverlay::isMapYokingSupportedPrivate(const CaretMappableDataFile* mapFile) const { bool supportedFlag = false; @@ -348,7 +373,21 @@ ChartTwoOverlay::isMapYokingSupported() const supportedFlag = true; break; } - return true; + + if (supportedFlag) { + supportedFlag = false; + + if (mapFile != NULL) { + if (mapFile->getNumberOfMaps() > 1) { + if (mapFile->isSurfaceMappable() + || mapFile->isVolumeMappable()) { + supportedFlag = true; + } + } + } + } + + return supportedFlag; } /** @@ -660,9 +699,6 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma } break; } - - - } break; } @@ -683,6 +719,12 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma CaretAssert(m_parentChartTwoOverlaySet); m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); } + + if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + if ( ! isMapYokingSupportedPrivate(m_selectedMapFile)) { + m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; + } + } } /** @@ -725,13 +767,6 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, if (m_selectedMapFile == NULL) { m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } - // if (selectedMapFile != NULL) { - // MapYokingGroupEnum::setSelectedMapIndex(m_mapYokingGroup, - // selectedMapIndex); - // } - // else { - // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; - // } } } @@ -749,18 +784,6 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, selectedIndex); } -/* - switch (m_chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - break; - } - */ /** * @return Is the all maps supported? */ @@ -1021,7 +1044,8 @@ ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, } m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); + sceneClass); + const MapYokingGroupEnum::Enum mapYokingGroupFromScene = m_mapYokingGroup; /* * Making a call to getSelectionData() to get the availble @@ -1193,6 +1217,18 @@ ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, } } + if (mapYokingGroupFromScene != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + /* + * Need to update selections and then apply yoking as + * yoking is cleared when the the previous file + * was not found. + */ + CaretMappableDataFile* mapFile = NULL; + SelectedIndexType indexType = SelectedIndexType::INVALID; + int32_t mapIndex = -1; + getSelectionData(mapFile, indexType, mapIndex); + setMapYokingGroup(mapYokingGroupFromScene); + } diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 079c8a17e..f90eefb2f 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -154,6 +154,8 @@ namespace caret { SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const; + bool isMapYokingSupportedPrivate(const CaretMappableDataFile* mapFile) const; + void validateCartesianVerticalAxisLocation() const; /** Parent chart overlay set (only used by first overlay in the set */ diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 00c106eb2..f5553314a 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -24,9 +24,12 @@ #undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "CaretAssert.h" +#include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventManager.h" +#include "EventMapYokingSelectMap.h" +#include "EventMapYokingValidation.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassArray.h" @@ -111,8 +114,8 @@ m_tabIndex(tabIndex) m_chartDataType, i); } -// EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); -// EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } /** @@ -201,10 +204,6 @@ ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionO if (getOverlay(i)->isEnabled()) { descriptionOut.pushIndentation(); -// descriptionOut.addLine("Overlay " -// + AString::number(i + 1) -// + ": "); - descriptionOut.pushIndentation(); getOverlay(i)->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); @@ -369,141 +368,10 @@ ChartTwoOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) void ChartTwoOverlaySet::initializeOverlays() { -// bool isMatchToVolumeUnderlay = false; -// bool isMatchToVolumeOverlays = false; -// -// switch (m_includeVolumeFiles) { -// case Overlay::INCLUDE_VOLUME_FILES_NO: -// break; -// case Overlay::INCLUDE_VOLUME_FILES_YES: -// /* -// * If no surface structures, then it must be volume slice view -// * so allow volumes to be in the overlays. -// */ -// if (m_includeSurfaceStructures.empty()) { -// isMatchToVolumeOverlays = true; -// } -// isMatchToVolumeUnderlay = true; -// break; -// } -// -// /* -// * Underlays consist of anatomical type data -// */ -// std::vector underlayMapFiles; -// std::vector underlayMapIndices; -// findUnderlayFiles(m_includeSurfaceStructures, -// isMatchToVolumeUnderlay, -// underlayMapFiles, -// underlayMapIndices); -// -// /* -// * Middle layers are Cifti labels or Gifti Labels -// * that do not contain shape data -// */ -// std::vector middleLayerMapFiles; -// std::vector middleLayerMapIndices; -// findMiddleLayerFiles(m_includeSurfaceStructures, -// isMatchToVolumeOverlays, -// middleLayerMapFiles, -// middleLayerMapIndices); -// -// /* -// * Overlays consist of Cifti scalars or Gifti Metric -// */ -// std::vector overlayMapFiles; -// std::vector overlayMapIndices; -// findOverlayFiles(m_includeSurfaceStructures, -// isMatchToVolumeOverlays, -// overlayMapFiles, -// overlayMapIndices); -// -// const int32_t numberOfUnderlayFiles = static_cast(underlayMapFiles.size()); -// -// /* -// * Number of overlay that are displayed. -// */ -// const int32_t numberOfDisplayedOverlays = getNumberOfDisplayedOverlays(); -// -// -// /* -// * Track overlay that were initialized -// */ -// std::vector overlayInitializedFlag(numberOfDisplayedOverlays, -// false); -// -// /* -// * Put in the shape files at the bottom -// * Note that highest overlay index is bottom -// */ -// int32_t overlayIndexForUnderlay = (numberOfDisplayedOverlays - 1); -// for (int32_t underlayFileIndex = 0; underlayFileIndex < numberOfUnderlayFiles; underlayFileIndex++) { -// if (overlayIndexForUnderlay >= 0) { -// Overlay* overlay = getOverlay(overlayIndexForUnderlay); -// overlay->setSelectionData(underlayMapFiles[underlayFileIndex], -// underlayMapIndices[underlayFileIndex]); -// overlayInitializedFlag[overlayIndexForUnderlay] = true; -// overlayIndexForUnderlay--; -// } -// else { -// break; -// } -// } -// -// /* -// * Combine overlay and middle layer files -// */ -// std::vector upperLayerFiles; -// std::vector upperLayerIndices; -// upperLayerFiles.insert(upperLayerFiles.end(), -// overlayMapFiles.begin(), -// overlayMapFiles.end()); -// upperLayerIndices.insert(upperLayerIndices.end(), -// overlayMapIndices.begin(), -// overlayMapIndices.end()); -// upperLayerFiles.insert(upperLayerFiles.end(), -// middleLayerMapFiles.begin(), -// middleLayerMapFiles.end()); -// upperLayerIndices.insert(upperLayerIndices.end(), -// middleLayerMapIndices.begin(), -// middleLayerMapIndices.end()); -// CaretAssert(upperLayerFiles.size() == upperLayerIndices.size()); -// -// const int32_t numberOfUpperFiles = static_cast(upperLayerFiles.size()); -// -// /* -// * Put in overlay and middle layer files -// */ -// for (int32_t upperFileIndex = 0; upperFileIndex < numberOfUpperFiles; upperFileIndex++) { -// /* -// * Find available overlay -// */ -// int32_t upperLayerOverlayIndex = -1; -// for (int32_t overlayIndex = 0; overlayIndex < numberOfDisplayedOverlays; overlayIndex++) { -// if (overlayInitializedFlag[overlayIndex] == false) { -// upperLayerOverlayIndex = overlayIndex; -// break; -// } -// } -// -// if (upperLayerOverlayIndex >= 0) { -// Overlay* upperLayerOverlay = getOverlay(upperLayerOverlayIndex); -// upperLayerOverlay->setSelectionData(upperLayerFiles[upperFileIndex], -// upperLayerIndices[upperFileIndex]); -// overlayInitializedFlag[upperLayerOverlayIndex] = true; -// } -// else { -// break; -// } -// } -// -// /* -// * Disable overlays that were not initialized -// */ -// for (int32_t i = 0; i < numberOfDisplayedOverlays; i++) { -// CaretAssertVectorIndex(overlayInitializedFlag, i); -// getOverlay(i)->setEnabled(overlayInitializedFlag[i]); -// } + /* + * This method could be used to choose specific file types + * for the default overlays similar to that in OverlaySet.cxx. + */ } /** @@ -521,26 +389,14 @@ ChartTwoOverlaySet::firstOverlaySelectionChanged() m_inFirstOverlayChangedMethodFlag = true; ChartTwoCompoundDataType cdt = m_overlays[0]->getChartTwoCompoundDataType(); - - - - -// std::cout << qPrintable("First Chart Overlay in tab " -// + AString::number(m_tabIndex + 1) -// + ":\n" -// + cdt.toString()) << std::endl; for (int32_t i = 1; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->setChartTwoCompoundDataType(cdt); -// if (m_overlays[i]->isEnabled()) { -// std::cout << " Overlay " << i << qPrintable(m_overlays[i]->toString()) << std::endl; -// } } PlainTextStringBuilder description; getDescriptionOfContent(description); - //std::cout << "First Overlay Changed: " << qPrintable(description.getText()) << std::endl; m_inFirstOverlayChangedMethodFlag = false; } @@ -577,12 +433,88 @@ ChartTwoOverlaySet::toString() const void ChartTwoOverlaySet::receiveEvent(Event* event) { -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } + if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { + /* + * The events intended for overlays are received here so that + * only DISPLAYED overlays are updated. + */ + EventMapYokingValidation* mapYokeEvent = dynamic_cast(event); + CaretAssert(mapYokeEvent); + + const MapYokingGroupEnum::Enum requestedYokingGroup = mapYokeEvent->getMapYokingGroup(); + if (requestedYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + + /* + * Find all overlays with the requested yoking + */ + const int32_t overlayCount = getNumberOfDisplayedOverlays(); + for (int32_t j = 0; j < overlayCount; j++) { + ChartTwoOverlay* overlay = getOverlay(j); + if (overlay->isMapYokingSupported()) { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t mapIndex = -1; + overlay->getSelectionData(mapFile, + indexType, + mapIndex); + if (mapFile != NULL) { + if (overlay->isMapYokingSupported()) { + mapYokeEvent->addMapYokedFile(mapFile, overlay->getMapYokingGroup(), m_tabIndex); + } + } + } + } + } + + mapYokeEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { + /* + * The events intended for overlays are received here so that + * only DISPLAYED overlays are updated. + */ + EventMapYokingSelectMap* selectMapEvent = dynamic_cast(event); + CaretAssert(selectMapEvent); + const MapYokingGroupEnum::Enum eventYokingGroup = selectMapEvent->getMapYokingGroup(); + if (eventYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + const int32_t yokingGroupMapIndex = MapYokingGroupEnum::getSelectedMapIndex(eventYokingGroup); + const bool yokingGroupSelectedStatus = MapYokingGroupEnum::isEnabled(eventYokingGroup); + const CaretMappableDataFile* eventMapFile = selectMapEvent->getCaretMappableDataFile(); + + /* + * Find all overlays with the requested yoking + */ + const int32_t overlayCount = getNumberOfDisplayedOverlays(); + for (int32_t j = 0; j < overlayCount; j++) { + ChartTwoOverlay* overlay = getOverlay(j); + if (overlay->isMapYokingSupported()) { + if (overlay->getMapYokingGroup() == selectMapEvent->getMapYokingGroup()) { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t mapIndex = -1; + overlay->getSelectionData(mapFile, + indexType, + mapIndex); + + if (mapFile != NULL) { + if (overlay->isMapYokingSupported()) { + if (yokingGroupMapIndex < mapFile->getNumberOfMaps()) { + overlay->setSelectionData(mapFile, + yokingGroupMapIndex); + } + + if (mapFile == eventMapFile) { + overlay->setEnabled(yokingGroupSelectedStatus); + } + } + } + } + } + } + + selectMapEvent->setEventProcessed(); + } + } } /** diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 1ee4da5ea..0e9dfbcdc 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -113,7 +113,6 @@ ChartableTwoFileHistogramChart::isValid() const bool ChartableTwoFileHistogramChart::isEmpty() const { - CaretAssertToDoWarning(); return false; } diff --git a/src/Files/EventMapYokingValidation.cxx b/src/Files/EventMapYokingValidation.cxx index eb3d66f38..8fa393892 100644 --- a/src/Files/EventMapYokingValidation.cxx +++ b/src/Files/EventMapYokingValidation.cxx @@ -220,7 +220,7 @@ m_tabIndex(tabIndex) m_infoText = (AString::number(m_numberOfMaps) + " maps in tab " - + AString::number(tabIndex) + + AString::number(tabIndex + 1) + " file: " + caretMapFile->getFileNameNoPath()); } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 1dcfb8a65..315e9e426 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -171,7 +171,6 @@ m_chartOverlay(NULL) QPixmap historyPixmap = createHistoryPixmap(m_historyToolButton); m_historyAction->setIcon(historyPixmap); m_historyToolButton->setDefaultAction(m_historyAction); - //m_historyToolButton->setIconSize(historyPixmap.size()); /* * Matrix triangular view mode button @@ -248,8 +247,6 @@ m_chartOverlay(NULL) m_mapRowOrColumnIndexSpinBox->setToolTip("Select map/row/column by its index"); m_mapRowOrColumnIndexSpinBox->setRange(1, 9999); // fix size for 4 digits m_mapRowOrColumnIndexSpinBox->setFixedSize(m_mapRowOrColumnIndexSpinBox->sizeHint()); -// m_mapRowOrColumnIndexSpinBox->setSizePolicy(QSizePolicy::Fixed, -// QSizePolicy::Fixed); m_mapRowOrColumnIndexSpinBox->setRange(1, 1); m_mapRowOrColumnIndexSpinBox->setValue(1); @@ -317,26 +314,10 @@ ChartTwoOverlayViewController::fileComboBoxSelected(int indx) CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; m_chartOverlay->setSelectionData(file, -1); - // DO NOT DO HERE validateYokingSelection(); - - //validateYokingSelection(overlay->getYokingGroup()); - // not needed with call to validateYokingSelection: this->updateViewController(this->overlay); - - // called inside validateYokingSelection(); this->updateUserInterfaceAndGraphicsWindow(); - updateViewController(m_chartOverlay); m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); - -// if (file != NULL) { -// if (file->isVolumeMappable()) { -// /* -// * Need to update slice indices/coords in toolbar. -// */ -// EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); -// } -// } } /** @@ -512,7 +493,6 @@ ChartTwoOverlayViewController::validateYokingSelection() m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateViewController(m_chartOverlay); updateUserInterfaceAndGraphicsWindow(); - //EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** @@ -733,8 +713,8 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(false); m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); if (validOverlayAndFileFlag) { - m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(true); if (m_chartOverlay->isMapYokingSupported()) { + m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(true); m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(m_chartOverlay->getMapYokingGroup()); } } @@ -901,8 +881,13 @@ ChartTwoOverlayViewController::updateUserInterface() void ChartTwoOverlayViewController::updateGraphicsWindow() { - //EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + else { + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + } } /** diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index 55f263686..a51bf45e0 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -216,7 +216,7 @@ MapYokingGroupComboBox::validateYokingChange(ChartTwoOverlay* chartOverlay) bool selectionStatus = chartOverlay->isEnabled(); if ((mapFile != NULL) - && (selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP) + && (chartOverlay->isMapYokingSupported()) && (selectedIndex >= 0)) { const YokeValidationResult result = validateYoking(mapFile, selectedIndex, @@ -313,7 +313,6 @@ MapYokingGroupComboBox::validateYoking(CaretMappableDataFile* selectedFile, * the map index and status from the yoking group. */ selectedMapIndexInOut = MapYokingGroupEnum::getSelectedMapIndex(newYokingGroup); - //selectionStatusInOut = MapYokingGroupEnum::isEnabled(newYokingGroup); } else { /* @@ -323,8 +322,6 @@ MapYokingGroupComboBox::validateYoking(CaretMappableDataFile* selectedFile, */ MapYokingGroupEnum::setSelectedMapIndex(newYokingGroup, selectedMapIndexInOut); - //MapYokingGroupEnum::setEnabled(newYokingGroup, - // selectionStatusInOut); } } } @@ -333,78 +330,3 @@ MapYokingGroupComboBox::validateYoking(CaretMappableDataFile* selectedFile, return yokeResult; } - -//void -//MapYokingGroupComboBox::validateYokingChange(const MapYokingGroupEnum::Enum previousMapYokingGroup, -// CaretMappableDataFile* selectedFile, -// const int32_t selectedMapIndex, -// ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface, -// Overlay* overlay) -//{ -// MapYokingGroupEnum::Enum yokingGroup = getMapYokingGroup(); -// if (yokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { -// CaretMappableDataFile* selectedFile = NULL; -// if ((selectedFile != NULL) -// && (selectedMapIndex >= 0)) { -// /* -// * Get info on yoking selections -// */ -// EventMapYokingValidation validateEvent(yokingGroup); -// EventManager::get()->sendEvent(validateEvent.getPointer()); -// -// const int32_t numOverlaysYoked = yokedOverlaysEvent.getNumberOfYokedOverlays(); -// -// /* -// * Check compatibility based (number of maps in yoked files) -// * and warn use if there is an incompatibility. -// */ -// AString message; -// if ( ! validateEvent.validateCompatibility(selectedFile, -// message)) { -// message.appendWithNewLine(""); -// message.appendWithNewLine("Allow yoking?"); -// -// message = WuQtUtilities::createWordWrappedToolTipText(message); -// -// WuQMessageBox::YesNoCancelResult result = -// WuQMessageBox::warningYesNoCancel(m_comboBox->getWidget(), -// message, -// ""); -// switch (result) { -// case WuQMessageBox::RESULT_YES: -// break; -// case WuQMessageBox::RESULT_NO: -// yokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; -// break; -// case WuQMessageBox::RESULT_CANCEL: -// yokingGroup = previousMapYokingGroup; -// break; -// } -// } -// -// if (overlay != NULL) { -// -// } -// overlay->setYokingGroup(yokingGroup); -// if (yokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { -// if (numOverlaysYoked <= 0) { -// OverlayYokingGroupEnum::setSelectedMapIndex(yokingGroup, -// selectedMapIndex); -// const bool enabledStatus = overlay->isEnabled(); -// OverlayYokingGroupEnum::setEnabled(yokingGroup, -// enabledStatus); -// } -// } -// } -// } -// else { -// overlay->setYokingGroup(yokingGroup); -// } -// -// updateViewController(overlay); -// -// this->updateUserInterfaceAndGraphicsWindow(); -// -//} -// - -- GitLab From b78d98ad63fda529b4f4c542ba031879419be996 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 31 Mar 2017 15:48:04 -0500 Subject: [PATCH 243/755] Smoothed drawing of histogram Envelope and made the envelope line two pixels in width. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 148 +++++++++++++++++- src/Brain/BrainOpenGLPrimitiveDrawing.cxx | 55 +++++++ src/Brain/BrainOpenGLPrimitiveDrawing.h | 8 + 3 files changed, 210 insertions(+), 1 deletion(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 175634c71..3615c81a0 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -776,7 +776,153 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } } - if (drawHistogramEnvelopeFlag) { + const bool smoothFlag = true; + + if (drawHistogramEnvelopeFlag + && smoothFlag) { + /* + * Reserve to prevent reszing of vectors + * as elements are added. + */ + const int32_t verticesPerBar = 2; + const int32_t totalVertices = verticesPerBar * numValues + 4; + quadVerticesXYZ.reserve(totalVertices * 3); + quadVerticesFloatRGBA.reserve(totalVertices * 4); + quadVerticesByteRGBA.reserve(totalVertices * 4); + + const float z = 0.0; + + const int32_t lastValueIndex = numValues - 1; + for (int32_t i = 0; i < numValues; i++) { + CaretAssertVectorIndex(xValues, i + 1); + float left = xValues[i]; + float right = xValues[i + 1]; + CaretAssert(right >= left); + float bottom = 0; + CaretAssertVectorIndex(yValues, i + 1); + float topLeft = yValues[i]; + float topRight = yValues[i+1]; + + uint8_t idRGBA[4]; + if (m_identificationModeFlag) { + addToHistogramIdentification(mapIndex, i, idRGBA); + } + if (i == 0) { + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + + quadVerticesXYZ.push_back(left); + quadVerticesXYZ.push_back(topLeft); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + } + + quadVerticesXYZ.push_back((left + right) / 2.0); + quadVerticesXYZ.push_back(topLeft); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } +// quadVerticesXYZ.push_back(left); +// quadVerticesXYZ.push_back(topLeft); +// quadVerticesXYZ.push_back(z); +// if (m_identificationModeFlag) { +// quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), +// idRGBA, idRGBA + 4); +// } +// else { +// quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), +// m_fixedPipelineDrawing->m_foregroundColorFloat, +// m_fixedPipelineDrawing->m_foregroundColorFloat + 4); +// } +// +// quadVerticesXYZ.push_back(right); +// quadVerticesXYZ.push_back(topRight); +// quadVerticesXYZ.push_back(z); +// if (m_identificationModeFlag) { +// quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), +// idRGBA, idRGBA + 4); +// } +// else { +// quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), +// m_fixedPipelineDrawing->m_foregroundColorFloat, +// m_fixedPipelineDrawing->m_foregroundColorFloat + 4); +// } + + if (i == lastValueIndex) { + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(topRight); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + + quadVerticesXYZ.push_back(right); + quadVerticesXYZ.push_back(bottom); + quadVerticesXYZ.push_back(z); + if (m_identificationModeFlag) { + quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), + idRGBA, idRGBA + 4); + } + else { + quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), + m_fixedPipelineDrawing->m_foregroundColorFloat, + m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + } + } + } + + /* + * Draw the elements. + */ + if (m_identificationModeFlag) { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); + + const float lineWidth = 5.0; + BrainOpenGLPrimitiveDrawing::drawLineStrip(quadVerticesXYZ, + quadVerticesByteRGBA, + lineWidth); + } + else { + CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); + + const float lineWidth = 2.0; + BrainOpenGLPrimitiveDrawing::drawLineStrip(quadVerticesXYZ, + quadVerticesFloatRGBA, + lineWidth); + } + } + else if (drawHistogramEnvelopeFlag) { /* * Reserve to prevent reszing of vectors * as elements are added. diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx index 2049f2616..195225de4 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx @@ -781,6 +781,61 @@ BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, lineWidth); } +/** + * Draw a line between each pair of three-dimensional coordinates in the given color + * with optional normal vectors. + * + * @param coordinates + * Three-Dimensional coordinates (XYZ). + * @param rgba + * RGBA Colors [0.0, 1.0] for each vertex. + * @param lineWidth + * Line width used by line drawing modes. + */ +void +BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth) +{ + std::vector emptyNormals; + + std::vector rgbaBytes; + rgbaBytes.reserve(rgbaColors.size()); + for (const float component : rgbaColors) { + rgbaBytes.push_back(static_cast(component * 255.0)); + } + + drawPrimitiveWithVertexArrays(GL_LINE_STRIP, + coordinates, + emptyNormals, + rgbaBytes, + lineWidth); +} + +/** + * Draw a line between each pair of three-dimensional coordinates in the given color + * with optional normal vectors. + * + * @param coordinates + * Three-Dimensional coordinates (XYZ). + * @param rgba + * RGBA Colors [0, 255] for each vertex. + * @param lineWidth + * Line width used by line drawing modes. + */ +void +BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth) +{ + std::vector emptyNormals; + drawPrimitiveWithVertexArrays(GL_LINE_STRIP, + coordinates, + emptyNormals, + rgbaColors, + lineWidth); +} + /** * Draw a line strip with the given coordinates in the given color * with optional normal vectors. diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.h b/src/Brain/BrainOpenGLPrimitiveDrawing.h index bc9a94000..a75a7c1cf 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.h +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.h @@ -82,6 +82,14 @@ namespace caret { const uint8_t rgba[4], const float lineWidth); + static void drawLineStrip(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth); + + static void drawLineStrip(const std::vector& coordinates, + const std::vector& rgbaColors, + const float lineWidth); + static void drawPolygon(const std::vector& coordinates, const std::vector& normals, const float rgba[4]); -- GitLab From 3f03accf4763f9dbda4d257661f75763af59e16d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 3 Apr 2017 09:40:54 -0500 Subject: [PATCH 244/755] Fixed a memory leak in histogram drawing. --- .../BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 3615c81a0..04b9c12d1 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -281,7 +281,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); - std::vector drawingInfo; + std::vector> drawingInfo; /* * Get the histogram drawing information and overall extent @@ -320,10 +320,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() false, *histogramDrawingInfo, errorMessage)) { - drawingInfo.push_back(new HistogramChartDrawingInfo(histogramDrawingInfo, - histogramChart, - selectedIndex, - chartOverlay->getCartesianVerticalAxisLocation())); + drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramDrawingInfo, + histogramChart, + selectedIndex, + chartOverlay->getCartesianVerticalAxisLocation()))); float bounds[4]; if (histogramDrawingInfo->getBounds(bounds)) { @@ -550,7 +550,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() 0.0); } - drawHistogramChartContent(drawInfo, + drawHistogramChartContent(drawInfo.get(), drawBarsFlag, drawEnvelopeFlag); } -- GitLab From 6099b725e04ef8130cb7522c9feb00e14dc4d35b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 4 Apr 2017 12:36:44 -0500 Subject: [PATCH 245/755] Added parcel series file to new matrix charting. Fixed map yoking for chart matrix selection when user clicks in matrix to change selected row/column. --- src/Brain/ChartTwoOverlaySet.cxx | 33 ++++ src/Brain/ChartTwoOverlaySet.h | 3 + src/Brain/IdentificationTextGenerator.cxx | 61 +++++-- src/Files/ChartableTwoFileDelegate.cxx | 2 + src/Files/ChartableTwoFileMatrixChart.cxx | 205 +++++++++++++++++----- src/Files/ChartableTwoFileMatrixChart.h | 13 ++ src/Files/CiftiMappableDataFile.cxx | 36 +++- src/Files/CiftiParcelReorderingModel.cxx | 4 +- src/Files/CiftiParcelSeriesFile.cxx | 106 +++++++++++ src/Files/CiftiParcelSeriesFile.h | 29 +++ src/GuiQt/GuiManager.cxx | 202 +++++++++++++++------ 11 files changed, 579 insertions(+), 115 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index f5553314a..b33dc5998 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -213,6 +213,39 @@ ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionO } } +/** + * Find the top-most displayed and enabled overlay containing the given data file. + * + * @param mapFile + * File for which overlay is requested. + */ +ChartTwoOverlay* +ChartTwoOverlaySet::getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile) +{ + if (mapFile == NULL) { + return NULL; + } + + ChartTwoOverlay* overlayOut = NULL; + + const int numOverlays = getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + ChartTwoOverlay* overlay = getOverlay(i); + if (overlay->isEnabled()) { + CaretMappableDataFile* overlayMapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectionType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t dataFileIndex = -1; + overlay->getSelectionData(overlayMapFile, + selectionType, + dataFileIndex); + if (mapFile == overlayMapFile) { + overlayOut = overlay; + } + } + } + + return overlayOut; +} /** * Add a displayed overlay. If the maximum diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 887dd0928..dfb5ffcdc 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -30,6 +30,7 @@ namespace caret { + class CaretMappableDataFile; class ChartTwoCartesianAxis; class ChartTwoOverlay; class PlainTextStringBuilder; @@ -58,6 +59,8 @@ namespace caret { int32_t getNumberOfDisplayedOverlays() const; + ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); + ChartTwoCartesianAxis* getChartAxisLeft(); const ChartTwoCartesianAxis* getChartAxisLeft() const; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 9acb4e536..cb4dc4246 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -910,24 +910,51 @@ IdentificationTextGenerator::generateChartTwoMatrixIdentificationText(Identifica const CaretMappableDataFile* mapFile = matrixChart->getCaretMappableDataFile(); CaretAssert(mapFile); - - AString boldText("MATRIX ROW/COLUMN"); - idText.addLine(false, - boldText, - mapFile->getFileNameNoPath()); - - const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); - if (rowIndex >= 0) { - const AString rowName = (matrixFile != NULL) ? (" " + matrixFile->getRowName(rowIndex)) : ""; - idText.addLine(true, - "Row", - (AString::number(rowIndex) + rowName)); + + const bool newIdFlag = true; + if (newIdFlag) { + AString boldText("MATRIX "); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + if ((rowIndex >= 0) + && (matrixChart->hasRowSelection())) { + const AString rowName = matrixChart->getRowName(rowIndex); + if ( ! rowName.isEmpty()) { + idText.addLine(true, + ("Row " + AString::number(rowIndex + 1)), + rowName); + } + } + if ((colIndex >= 0) + && (matrixChart->hasColumnSelection())) { + const AString colName = matrixChart->getColumnName(colIndex); + if ( ! colName.isEmpty()) { + idText.addLine(true, + ("Column " + AString::number(colIndex + 1)), + colName); + } + } } - if (colIndex >= 0) { - const AString colName = (matrixFile != NULL) ? (" " + matrixFile->getColumnName(colIndex)) : ""; - idText.addLine(true, - "Column", - (AString::number(colIndex) + colName)); + else { + AString boldText("MATRIX ROW/COLUMN"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + + const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); + if (rowIndex >= 0) { + const AString rowName = (matrixFile != NULL) ? (" " + matrixFile->getRowName(rowIndex + 1)) : ""; + idText.addLine(true, + "Row", + (AString::number(rowIndex + 1) + rowName)); + } + if (colIndex >= 0) { + const AString colName = (matrixFile != NULL) ? (" " + matrixFile->getColumnName(colIndex + 1)) : ""; + idText.addLine(true, + "Column", + (AString::number(colIndex + 1) + colName)); + } } } } diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index 1c38ad760..1085429a9 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -134,6 +134,8 @@ ChartableTwoFileDelegate::updateAfterFileChanged() case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; + matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; + validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA; diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index d38be6a39..314498dab 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -28,6 +28,7 @@ #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" +#include "CiftiParcelSeriesFile.h" #include "CiftiXML.h" #include "CiftiScalarDataSeriesFile.h" #include "ConnectivityDataLoaded.h" @@ -68,10 +69,16 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) m_numberOfColumns = 0; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + m_parcelLabelFileSelectedColumn[i] = 0; m_parcelScalarFileSelectedColumn[i] = 0; + m_parcelSeriesFileSelectedColumn[i] = 0; } + m_sceneAssistant->addTabIndexedIntegerArray("m_parcelLabelFileSelectedColumn", + m_parcelLabelFileSelectedColumn); m_sceneAssistant->addTabIndexedIntegerArray("m_parcelScalarFileSelectedColumn", m_parcelScalarFileSelectedColumn); + m_sceneAssistant->addTabIndexedIntegerArray("m_parcelSeriesFileSelectedColumn", + m_parcelSeriesFileSelectedColumn); if (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); @@ -112,6 +119,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) m_matrixDataFileType = MatrixDataFileType::PARCEL_SCALAR; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + m_matrixDataFileType = MatrixDataFileType::PARCEL_SERIES; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: m_matrixDataFileType = MatrixDataFileType::SCALAR_DATA_SERIES; @@ -140,7 +148,10 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) break; } - bool hasColumnMapSelectionFlag = false; + bool hasColumnParcelsFlag = false; + bool hasColumnMapNamesFlag = false; + bool hasRowParcelsFlag = false; + bool hasRowNumbersFlag = false; switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); @@ -150,17 +161,27 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) m_parcelFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelFile); m_hasRowSelectionFlag = true; + hasRowParcelsFlag = true; m_hasColumnSelectionFlag = true; + hasColumnParcelsFlag = true; break; case MatrixDataFileType::PARCEL_LABEL: m_parcelLabelFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelLabelFile); + m_hasColumnSelectionFlag = true; + hasColumnMapNamesFlag = true; break; case MatrixDataFileType::PARCEL_SCALAR: m_parcelScalarFile = dynamic_cast(ciftiMapFile); - m_hasColumnSelectionFlag = true; - hasColumnMapSelectionFlag = true; CaretAssert(m_parcelScalarFile); + m_hasColumnSelectionFlag = true; + hasColumnMapNamesFlag = true; + break; + case MatrixDataFileType::PARCEL_SERIES: + m_parcelSeriesFile = dynamic_cast(ciftiMapFile); + CaretAssert(m_parcelSeriesFile); + m_hasColumnSelectionFlag = true; + hasColumnMapNamesFlag = true; break; case MatrixDataFileType::SCALAR_DATA_SERIES: m_scalarDataSeriesFile = dynamic_cast(ciftiMapFile); @@ -169,32 +190,88 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) } if (m_hasRowSelectionFlag) { - const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); - if (rowParcelsMap != NULL) { - const int32_t numRowParcels = rowParcelsMap->getLength(); - CaretAssert(numRowParcels == m_numberOfRows); - for (int32_t i = 0; i < numRowParcels; i++) { - m_rowNames.push_back("Row " + AString::number(i + 1) + ": " + rowParcelsMap->getIndexName(i)); + if (hasRowParcelsFlag) { + const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); + if (rowParcelsMap != NULL) { + const int32_t numRowParcels = rowParcelsMap->getLength(); + CaretAssert(numRowParcels == m_numberOfRows); + for (int32_t i = 0; i < numRowParcels; i++) { + m_rowNames.push_back(rowParcelsMap->getIndexName(i)); + m_rowNumberAndNames.push_back("Row " + AString::number(i + 1) + ": " + rowParcelsMap->getIndexName(i)); + } + } + else { + const CiftiParcelsMap* columnParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); + if (columnParcelsMap != NULL) { + CaretAssertMessage(0, ("Trying to use row parcels but parcels are in columns. There are " + + AString::number(columnParcelsMap->getLength()) + + " parcels in the column for the file " + + getCaretMappableDataFile()->getFileNameNoPath())); + } + else { + CaretAssertMessage(0, "Trying to use row parcels but there are none for the file " + + getCaretMappableDataFile()->getFileNameNoPath()); + } + } + } + else if (hasRowNumbersFlag) { + for (int32_t i = 0; i < m_numberOfRows; i++) { + m_rowNames.push_back(AString::number(i)); + m_rowNumberAndNames.push_back("Row " + AString::number(i + 1) + ": " + AString::number(i + 1)); } } } if (m_hasColumnSelectionFlag) { - const CiftiParcelsMap* colParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); - if (colParcelsMap != NULL) { - const int32_t numColParcels = colParcelsMap->getLength(); - CaretAssert(numColParcels == m_numberOfColumns); - for (int32_t i = 0; i < numColParcels; i++) { - m_columnNames.push_back("Column " + AString::number(i + 1) + ": " + colParcelsMap->getIndexName(i)); + if (hasColumnParcelsFlag) { + const CiftiParcelsMap* colParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); + if (colParcelsMap != NULL) { + const int32_t numColParcels = colParcelsMap->getLength(); + CaretAssert(numColParcels == m_numberOfColumns); + for (int32_t i = 0; i < numColParcels; i++) { + m_columnNames.push_back(colParcelsMap->getIndexName(i)); + m_columnNumberAndNames.push_back("Column " + AString::number(i + 1) + ": " + colParcelsMap->getIndexName(i)); + } + } + else { + const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); + if (rowParcelsMap != NULL) { + CaretAssertMessage(0, ("Trying to use column parcels but parcels are in rows. There are " + + AString::number(rowParcelsMap->getLength()) + + " parcels in the row for the file " + + getCaretMappableDataFile()->getFileNameNoPath())); + } + else { + CaretAssertMessage(0, "Trying to use column parcels but there are none for the file " + + getCaretMappableDataFile()->getFileNameNoPath()); + } } } - - if (hasColumnMapSelectionFlag) { - m_columnNames.clear(); - for (int32_t i = 0; i < m_numberOfColumns; i++) { - m_columnNames.push_back(m_parcelScalarFile->getMapName(i)); + else if (hasColumnMapNamesFlag) { + const int32_t numMaps = ciftiMapFile->getNumberOfMaps(); + CaretAssert(m_numberOfColumns == numMaps); + for (int32_t i = 0; i < numMaps; i++) { + m_columnNames.push_back(ciftiMapFile->getMapName(i)); + m_columnNumberAndNames.push_back("Column " + AString::number(i + 1) + ": " + ciftiMapFile->getMapName(i)); } } + +// if (hasColumnMapSelectionFlag) { +// m_columnNames.clear(); +// for (int32_t i = 0; i < m_numberOfColumns; i++) { +// m_columnNames.push_back(ciftiMapFile->getMapName(i)); +// } +// if (m_parcelScalarFile != NULL) { +// for (int32_t i = 0; i < m_numberOfColumns; i++) { +// m_columnNames.push_back(m_parcelScalarFile->getMapName(i)); +// } +// } +// if (m_parcelSeriesFile != NULL) { +// for (int32_t i = 0; i < m_numberOfColumns; i++) { +// m_columnNames.push_back(m_parcelSeriesFile->getMapName(i)); +// } +// } +// } } } @@ -346,11 +423,16 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const break; case MatrixDataFileType::PARCEL_LABEL: CaretAssert(m_parcelLabelFile); + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; case MatrixDataFileType::PARCEL_SCALAR: CaretAssert(m_parcelScalarFile); loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; + case MatrixDataFileType::PARCEL_SERIES: + CaretAssert(m_parcelSeriesFile); + loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; + break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); break; @@ -393,6 +475,9 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnDimension(const ChartTwoMatrixL case MatrixDataFileType::PARCEL_SCALAR: CaretAssert(m_parcelScalarFile); break; + case MatrixDataFileType::PARCEL_SERIES: + CaretAssert(m_parcelSeriesFile); + break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); break; @@ -464,25 +549,23 @@ ChartableTwoFileMatrixChart::getSelectedRowColumnIndices(const int32_t tabIndex, break; case MatrixDataFileType::PARCEL_LABEL: { - CaretAssert(m_parcelLabelFile); - EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); - EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { - columnIndicesSet.insert(indx); - } + CaretAssertArrayIndex(m_parcelLabelFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + columnIndicesSet.insert(m_parcelLabelFileSelectedColumn[tabIndex]); +// CaretAssert(m_parcelLabelFile); +// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); +// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); +// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { +// columnIndicesSet.insert(indx); +// } } break; case MatrixDataFileType::PARCEL_SCALAR: CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); columnIndicesSet.insert(m_parcelScalarFileSelectedColumn[tabIndex]); -// { -// CaretAssert(m_parcelScalarFile); -// EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelScalarFile); -// EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); -// for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { -// columnIndicesSet.insert(indx); -// } -// } + break; + case MatrixDataFileType::PARCEL_SERIES: + CaretAssertArrayIndex(m_parcelSeriesFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + columnIndicesSet.insert(m_parcelSeriesFileSelectedColumn[tabIndex]); break; case MatrixDataFileType::SCALAR_DATA_SERIES: { @@ -554,7 +637,8 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, case MatrixDataFileType::PARCEL_LABEL: { CaretAssert(m_parcelLabelFile); - CaretAssertToDoWarning(); + CaretAssertArrayIndex(m_parcelLabelFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + m_parcelLabelFileSelectedColumn[tabIndex] = rowColumnIndex; // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { @@ -567,13 +651,13 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, CaretAssert(m_parcelScalarFile); CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_parcelScalarFileSelectedColumn[tabIndex] = rowColumnIndex; - // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelScalarFile); - // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); - // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { - // columnIndicesSet.insert(indx); - // } } break; + case MatrixDataFileType::PARCEL_SERIES: + CaretAssert(m_parcelSeriesFile); + CaretAssertArrayIndex(m_parcelSeriesFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + m_parcelSeriesFileSelectedColumn[tabIndex] = rowColumnIndex; + break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); m_scalarDataSeriesFile->setSelectedMapIndex(tabIndex, @@ -642,6 +726,47 @@ ChartableTwoFileMatrixChart::getColumnName(const int32_t columnIndex) const return ""; } +/** + * @return Name of row at the given index. + * + * @param rowIndex + * Index of the row. + */ +AString +ChartableTwoFileMatrixChart::getRowNumberAndName(const int32_t rowIndex) const +{ + if ((rowIndex >= 0) + && (rowIndex < m_numberOfRows)) { + if (rowIndex < static_cast(m_rowNumberAndNames.size())) { + CaretAssertVectorIndex(m_rowNumberAndNames, rowIndex); + return m_rowNumberAndNames[rowIndex]; + } + return ("Row: " + AString::number(rowIndex)); + } + + return ""; +} + +/** + * @return Name of column at the given index. + * + * @param columnIndex + * Index of the row. + */ +AString +ChartableTwoFileMatrixChart::getColumnNumberAndName(const int32_t columnIndex) const +{ + if ((columnIndex >= 0) + && (columnIndex < m_numberOfColumns)) { + if (columnIndex < static_cast(m_columnNumberAndNames.size())) { + CaretAssertVectorIndex(m_columnNumberAndNames, columnIndex); + return m_columnNumberAndNames[columnIndex]; + } + return ("Column: " + AString::number(columnIndex)); + } + + return ""; +} /** * Save subclass data to the scene. diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index cc75668e3..11e984bcc 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -31,6 +31,7 @@ namespace caret { class CiftiConnectivityMatrixParcelFile; class CiftiParcelLabelFile; class CiftiParcelScalarFile; + class CiftiParcelSeriesFile; class CiftiScalarDataSeriesFile; class ChartableTwoFileMatrixChart : public ChartableTwoFileBaseChart { @@ -77,6 +78,10 @@ namespace caret { bool hasColumnSelection() const; + AString getRowNumberAndName(const int32_t rowIndex) const; + + AString getColumnNumberAndName(const int32_t columnIndex) const; + AString getRowName(const int32_t rowIndex) const; AString getColumnName(const int32_t columnIndex) const; @@ -87,6 +92,7 @@ namespace caret { PARCEL, PARCEL_LABEL, PARCEL_SCALAR, + PARCEL_SERIES, SCALAR_DATA_SERIES }; @@ -117,6 +123,10 @@ namespace caret { std::vector m_columnNames; + std::vector m_rowNumberAndNames; + + std::vector m_columnNumberAndNames; + bool m_hasRowSelectionFlag = false; bool m_hasColumnSelectionFlag = false; @@ -126,9 +136,12 @@ namespace caret { CiftiConnectivityMatrixParcelFile *m_parcelFile = NULL; CiftiParcelLabelFile* m_parcelLabelFile = NULL; CiftiParcelScalarFile* m_parcelScalarFile = NULL; + CiftiParcelSeriesFile* m_parcelSeriesFile = NULL; CiftiScalarDataSeriesFile* m_scalarDataSeriesFile = NULL; + int32_t m_parcelLabelFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; int32_t m_parcelScalarFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + int32_t m_parcelSeriesFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 8e8128b22..927acaa6f 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -37,6 +37,7 @@ #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" +#include "CiftiParcelSeriesFile.h" #include "CaretTemporaryFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" @@ -667,6 +668,7 @@ CiftiMappableDataFile::readFile(const AString& ciftiMapFileName) } if (m_ciftiFile != NULL) { + setFileName(ciftiMapFileName); // need by charting delegate initializeAfterReading(ciftiMapFileName); } } @@ -1593,6 +1595,30 @@ CiftiMappableDataFile::getMatrixForChartingRGBA(int32_t& numberOfRowsOut, } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: + { + useMapFileHelperFlag = true; + + const CiftiParcelSeriesFile* parcelSeriesFile = dynamic_cast(this); + CaretAssert(parcelSeriesFile); + if (parcelSeriesFile != NULL) { + CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; + int32_t parcelLabelFileMapIndex = -1; + bool reorderingEnabledFlag = false; + std::vector parcelLabelFiles; + parcelSeriesFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, + parcelLabelReorderingFile, + parcelLabelFileMapIndex, + reorderingEnabledFlag); + + if (reorderingEnabledFlag) { + const CiftiParcelReordering* parcelReordering = parcelSeriesFile->getParcelReordering(parcelLabelReorderingFile, + parcelLabelFileMapIndex); + if (parcelReordering != NULL) { + parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); + } + } + } + } break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: useMatrixFileHelperFlag = true; @@ -6382,7 +6408,7 @@ CiftiMappableDataFile::helpMapFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsO const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); - const AString badMapTypeMessage("Matrix charts supports only maps in columns at this time for LABEL and SCALAR data"); + const AString badMapTypeMessage("Matrix charts supports only maps in columns at this time for LABEL, SCALAR, and SERIES data"); if (useLabelTableFlag) { if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) { CaretAssertMessage(0, badMapTypeMessage); @@ -6392,7 +6418,13 @@ CiftiMappableDataFile::helpMapFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsO } if (usePaletteFlag) { - if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::SCALARS) { + if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS) { + /* ok */ + } + else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SERIES) { + /* ok */ + } + else { CaretAssertMessage(0, badMapTypeMessage); CaretLogSevere(badMapTypeMessage); return false; diff --git a/src/Files/CiftiParcelReorderingModel.cxx b/src/Files/CiftiParcelReorderingModel.cxx index ebbe5349b..15023347a 100644 --- a/src/Files/CiftiParcelReorderingModel.cxx +++ b/src/Files/CiftiParcelReorderingModel.cxx @@ -56,8 +56,9 @@ m_parentCiftiMappableDataFile(parentCiftiMappableDataFile) switch (parentCiftiMappableDataFile->getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_PARCEL: - case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; default: CaretAssert(0); @@ -191,6 +192,7 @@ CiftiParcelReorderingModel::getParcelLabelFiles() const testAlongRow = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: + case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: testAlongColumn = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: diff --git a/src/Files/CiftiParcelSeriesFile.cxx b/src/Files/CiftiParcelSeriesFile.cxx index 9c4fd8a3c..f8a09ae08 100644 --- a/src/Files/CiftiParcelSeriesFile.cxx +++ b/src/Files/CiftiParcelSeriesFile.cxx @@ -25,8 +25,10 @@ #include "CaretLogger.h" #include "ChartDataCartesian.h" +#include "CiftiParcelReorderingModel.h" #include "SceneClass.h" #include "SceneClassArray.h" +#include "SceneClassAssistant.h" using namespace caret; @@ -47,6 +49,13 @@ CiftiParcelSeriesFile::CiftiParcelSeriesFile() for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } + + m_parcelReorderingModel = std::unique_ptr(new CiftiParcelReorderingModel(this)); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_parcelReorderingModel", + "CiftiParcelReorderingModel", + m_parcelReorderingModel.get()); } /** @@ -282,6 +291,9 @@ CiftiParcelSeriesFile::saveFileDataToScene(const SceneAttributes* sceneAttribute CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); @@ -308,6 +320,9 @@ CiftiParcelSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", @@ -326,4 +341,95 @@ CiftiParcelSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr } } +/** + * Get the selected parcel label file used for reordering of parcels. + * + * @param compatibleParcelLabelFilesOut + * All Parcel Label files that are compatible with file implementing + * this interface. + * @param selectedParcelLabelFileOut + * The selected parcel label file used for reordering the parcels. + * May be NULL! + * @param selectedParcelLabelFileMapIndexOut + * Map index in the selected parcel label file. + * @param enabledStatusOut + * Enabled status of reordering. + */ +void +CiftiParcelSeriesFile::getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, + CiftiParcelLabelFile* &selectedParcelLabelFileOut, + int32_t& selectedParcelLabelFileMapIndexOut, + bool& enabledStatusOut) const +{ + m_parcelReorderingModel->getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFilesOut, + selectedParcelLabelFileOut, + selectedParcelLabelFileMapIndexOut, + enabledStatusOut); +} + +/** + * Set the selected parcel label file used for reordering of parcels. + * + * @param selectedParcelLabelFile + * The selected parcel label file used for reordering the parcels. + * May be NULL! + * @param selectedParcelLabelFileMapIndex + * Map index in the selected parcel label file. + * @param enabledStatus + * Enabled status of reordering. + */ +void +CiftiParcelSeriesFile::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, + const int32_t selectedParcelLabelFileMapIndex, + const bool enabledStatus) +{ + m_parcelReorderingModel->setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, + selectedParcelLabelFileMapIndex, + enabledStatus); +} + +/** + * Get the parcel reordering for the given map index that was created using + * the given parcel label file and its map index. + * + * @param parcelLabelFile + * The selected parcel label file used for reordering the parcels. + * @param parcelLabelFileMapIndex + * Map index in the selected parcel label file. + * @return + * Pointer to parcel reordering or NULL if not found. + */ +const CiftiParcelReordering* +CiftiParcelSeriesFile::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, + const int32_t parcelLabelFileMapIndex) const +{ + return m_parcelReorderingModel->getParcelReordering(parcelLabelFile, + parcelLabelFileMapIndex); +} + +/** + * Create the parcel reordering for the given map index using + * the given parcel label file and its map index. + * + * @param parcelLabelFile + * The selected parcel label file used for reordering the parcels. + * @param parcelLabelFileMapIndex + * Map index in the selected parcel label file. + * @param ciftiParcelsMap + * The CIFTI parcels map that will or has been reordered. + * @param errorMessageOut + * Error message output. Will only be non-empty if NULL is returned. + * @return + * Pointer to parcel reordering or NULL if not found. + */ +bool +CiftiParcelSeriesFile::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, + const int32_t parcelLabelFileMapIndex, + AString& errorMessageOut) +{ + return m_parcelReorderingModel->createParcelReordering(parcelLabelFile, + parcelLabelFileMapIndex, + errorMessageOut); +} + diff --git a/src/Files/CiftiParcelSeriesFile.h b/src/Files/CiftiParcelSeriesFile.h index a2677b504..44c29479f 100644 --- a/src/Files/CiftiParcelSeriesFile.h +++ b/src/Files/CiftiParcelSeriesFile.h @@ -21,12 +21,19 @@ */ /*LICENSE_END*/ +#include + #include "BrainConstants.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiMappableDataFile.h" namespace caret { + class CiftiParcelLabelFile; + class CiftiParcelReordering; + class CiftiParcelReorderingModel; + class SceneClassAssistant; + class CiftiParcelSeriesFile : public CiftiMappableDataFile, public ChartableLineSeriesBrainordinateInterface { @@ -53,6 +60,23 @@ namespace caret { virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, + CiftiParcelLabelFile* &selectedParcelLabelFileOut, + int32_t& selectedParcelLabelFileMapIndexOut, + bool& enabledStatusOut) const; + + virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, + const int32_t selectedParcelLabelFileMapIndex, + const bool enabledStatus); + + virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, + const int32_t parcelLabelFileMapIndex, + AString& errorMessageOut); + + virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, + const int32_t parcelLabelFileMapIndex) const; + + private: CiftiParcelSeriesFile(const CiftiParcelSeriesFile&); @@ -71,7 +95,12 @@ namespace caret { private: // ADD_NEW_MEMBERS_HERE + std::unique_ptr m_sceneAssistant; + bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + + std::unique_ptr m_parcelReorderingModel; + }; #ifdef __CIFTI_PARCEL_SERIES_FILE_DECLARE__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index c99630871..1ac0322e9 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -43,8 +43,11 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" +#include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartingDataManager.h" +#include "ChartTwoOverlay.h" +#include "ChartTwoOverlaySet.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" #include "CiftiConnectivityMatrixParcelFile.h" @@ -57,6 +60,7 @@ #include "ElapsedTimer.h" #include "EventAlertUser.h" #include "EventAnnotationGetDrawnInWindow.h" +#include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserWindowNew.h" #include "EventGraphicsUpdateAllWindows.h" @@ -85,6 +89,7 @@ #include "ImageFile.h" #include "ImageCaptureDialog.h" #include "InformationDisplayDialog.h" +#include "ModelChartTwo.h" #include "OverlaySettingsEditorDialog.h" #include "MacDockMenu.h" #include "MovieDialog.h" @@ -2789,77 +2794,164 @@ GuiManager::processIdentification(const int32_t tabIndex, CaretMappableDataFile* cmdf = matrixChart->getCaretMappableDataFile(); CaretAssert(cmdf); - switch (matrixChart->getMatrixContentType()) { - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: - { - CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(cmdf); - if (ciftiParcelFile != NULL) { - if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { - if ((rowIndex >= 0) - && (colIndex >= 0)) { - try { - ciftiConnectivityManager->loadRowOrColumnFromParcelFile(brain, - ciftiParcelFile, - rowIndex, - colIndex, - ciftiLoadingInfo); - + bool loadMapFlag = false; + + ChartTwoOverlay* chartOverlayContainingDataFile = NULL; + + EventBrowserTabGet eventBrowserTab(tabIndex); + EventManager::get()->sendEvent(eventBrowserTab.getPointer()); + BrowserTabContent* tabContent = eventBrowserTab.getBrowserTab(); + if (tabContent != NULL) { + ModelChartTwo* chartTwoModel = tabContent->getDisplayedChartTwoModel(); + if (chartTwoModel->getSelectedChartTwoDataType(tabIndex) == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { + ChartTwoOverlaySet* chartOverlaySet = tabContent->getChartTwoOverlaySet(); + chartOverlayContainingDataFile = chartOverlaySet->getDisplayedOverlayContainingDataFile(cmdf); + } + } + + bool foundChartOverlayFlag = false; + + if (chartOverlayContainingDataFile != NULL) { + ChartableTwoFileMatrixChart* matrixChart = cmdf->getChartingDelegate()->getMatrixCharting(); + if (matrixChart != NULL) { + if (matrixChart->isValid()) { + int32_t rowColumnIndex = -1; + switch (matrixChart->getSelectedRowColumnDimension()) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + rowColumnIndex = colIndex; + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + rowColumnIndex = rowIndex; + break; + } + chartOverlayContainingDataFile->setSelectionData(cmdf, + rowColumnIndex); + const MapYokingGroupEnum::Enum mapYoking = chartOverlayContainingDataFile->getMapYokingGroup(); + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + cmdf, + rowColumnIndex, + true); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + updateGraphicsFlag = true; + foundChartOverlayFlag = true; + } + } + } + + if ( ! foundChartOverlayFlag) { + CaretLogWarning("PROGRAMMER NOTE: Failed to find chart overlay containing identified matrix row/column"); + + switch (matrixChart->getMatrixContentType()) { + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: + { + CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(cmdf); + if (ciftiParcelFile != NULL) { + if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { + if ((rowIndex >= 0) + && (colIndex >= 0)) { + try { + ciftiConnectivityManager->loadRowOrColumnFromParcelFile(brain, + ciftiParcelFile, + rowIndex, + colIndex, + ciftiLoadingInfo); + + } + catch (const DataFileException& e) { + cursor.restoreCursor(); + QMessageBox::critical(parentWidget, "", e.whatString()); + cursor.showWaitCursor(); + } + updateGraphicsFlag = true; } - catch (const DataFileException& e) { - cursor.restoreCursor(); - QMessageBox::critical(parentWidget, "", e.whatString()); - cursor.showWaitCursor(); + } + } + else { + CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(cmdf); + if (matrixFile != NULL) { + if ((rowIndex >= 0) + || (colIndex >= 0)) { + ciftiConnectivityManager->loadRowOrColumnFromConnectivityMatrixFile(brain, + matrixFile, + rowIndex, + colIndex, + ciftiLoadingInfo); + updateGraphicsFlag = true; + } - updateGraphicsFlag = true; + } + else { + loadMapFlag = true; } } } - else { - CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(cmdf); - if (matrixFile != NULL) { - if ((rowIndex >= 0) - || (colIndex >= 0)) { - ciftiConnectivityManager->loadRowOrColumnFromConnectivityMatrixFile(brain, - matrixFile, - rowIndex, - colIndex, - ciftiLoadingInfo); - updateGraphicsFlag = true; + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: + { + CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(cmdf); + if (scalarDataSeriesFile != NULL) { + if (rowIndex >= 0) { + scalarDataSeriesFile->setSelectedMapIndex(tabIndex, + rowIndex); + + const MapYokingGroupEnum::Enum mapYoking = scalarDataSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); + if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + EventMapYokingSelectMap selectMapEvent(mapYoking, + scalarDataSeriesFile, + rowIndex, + true); + EventManager::get()->sendEvent(selectMapEvent.getPointer()); + } + else { + chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, + rowIndex); + } + + updateGraphicsFlag = true; } } } + break; + case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: + break; } - break; - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: - { - CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(cmdf); - if (scalarDataSeriesFile != NULL) { - if (rowIndex >= 0) { - scalarDataSeriesFile->setSelectedMapIndex(tabIndex, - rowIndex); - - const MapYokingGroupEnum::Enum mapYoking = scalarDataSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); - - if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - EventMapYokingSelectMap selectMapEvent(mapYoking, - scalarDataSeriesFile, - rowIndex, - true); - EventManager::get()->sendEvent(selectMapEvent.getPointer()); - } - else { - chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, - rowIndex); + + if (loadMapFlag) { + ChartableTwoFileMatrixChart* matrixChart = cmdf->getChartingDelegate()->getMatrixCharting(); + if (matrixChart != NULL) { + if (matrixChart->isValid()) { + int32_t rowColumnIndex = -1; + switch (matrixChart->getSelectedRowColumnDimension()) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + rowColumnIndex = colIndex; + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + rowColumnIndex = rowIndex; + break; } + matrixChart->setSelectedRowColumnIndex(tabIndex, + rowColumnIndex); + // const MapYokingGroupEnum::Enum mapYoking = matrixChart->getMatrixRowColumnMapYokingGroup(tabIndex); + // + // if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + // EventMapYokingSelectMap selectMapEvent(mapYoking, + // scalarDataSeriesFile, + // rowIndex, + // true); + // EventManager::get()->sendEvent(selectMapEvent.getPointer()); + // } + // else { + // chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, + // rowIndex); + // } updateGraphicsFlag = true; } } } - break; - case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: - break; } } } -- GitLab From 631963dd9c7922ac53be7f1ab3de412bf64a8a10 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Apr 2017 15:16:38 -0500 Subject: [PATCH 246/755] When wb_view is run within Apple's XCode debugger, the parameter '-NSDocumentRevisionsDebugMode YES' is passed to main() and since it was not a recognized parameter, wb_view exited. wb_view now ignores this parameter. --- src/Desktop/desktop.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 244dfa35d..4d7ff5c8b 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -852,6 +852,15 @@ void parseCommandLine(const AString& progName, ProgramParameters* myParams, Prog * http://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder * http://trac.wxwidgets.org/ticket/15432 */ + } else if (thisParam == "-NSDocumentRevisionsDebugMode") { + /* + * When wb_view is started within Apple's XCode, these parameters are added + * so ignore them: + * -NSDocumentRevisionsDebugMode YES + */ + if (myParams->hasNext()) { + myParams->nextString("Argument to -NSDocumentRevisionsDebugMode"); + } } else { cerr << "unrecognized option \"" << thisParam << "\"" << endl; printHelp(progName); -- GitLab From c4b9c671f5204c522de6cefcb39173401ee8b1af Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Apr 2017 16:23:20 -0500 Subject: [PATCH 247/755] For histograms, do not let the user set vertical axis range (counts) to a value less than zero. Also, ensure that the maximum axis value is always greater than or equal to the minimum axis value. --- src/Brain/ChartTwoOverlaySet.cxx | 11 ++++ src/Charting/ChartTwoCartesianAxis.cxx | 58 +++++++++++++++++++ src/Charting/ChartTwoCartesianAxis.h | 14 +++++ .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 55 ++++++++++++++++-- .../BrainBrowserWindowToolBarChartTwoAxes.h | 4 +- 5 files changed, 137 insertions(+), 5 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index b33dc5998..304d04ffd 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -78,15 +78,26 @@ m_tabIndex(tabIndex) case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { m_chartAxisLeft->setVisible(true); m_chartAxisLeft->setAxisTitle("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + float rangeMin = 0.0, rangeMax = 0.0; + m_chartAxisLeft->getRange(rangeMin, rangeMax); + rangeMin = 0.0; + m_chartAxisLeft->setRange(rangeMin, rangeMax); + m_chartAxisRight->setVisible(false); m_chartAxisRight->setAxisTitle("Counts"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisRight->getRange(rangeMin, rangeMax); + rangeMin = 0.0; + m_chartAxisRight->setRange(rangeMin, rangeMax); + m_chartAxisBottom->setVisible(true); m_chartAxisBottom->setAxisTitle("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: m_chartAxisLeft->setVisible(true); diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 63401a959..49d6ee984 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -51,6 +51,12 @@ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum a : CaretObject(), m_axisLocation(axisLocation) { + /* + * Allowable range minimum and maximum + * NOT SAVED TO SCENE + */ + m_rangeMinimumValue = -std::numeric_limits::max(); + m_rangeMaximumValue = std::numeric_limits::max(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_userScaleMinimumValue", @@ -126,6 +132,8 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx { CaretAssert(m_axisLocation == obj.m_axisLocation); + m_rangeMinimumValue = obj.m_rangeMinimumValue; + m_rangeMaximumValue = obj.m_rangeMaximumValue; m_userScaleMinimumValue = obj.m_userScaleMinimumValue; m_userScaleMaximumValue = obj.m_userScaleMaximumValue; m_axisLabelsStepValue = obj.m_axisLabelsStepValue; @@ -138,6 +146,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_axisTitle = obj.m_axisTitle; m_visible = obj.m_visible; m_showTickmarks = obj.m_showTickmarks; + limitUserScaleMinMaxToValidRange(); } /** @@ -149,6 +158,53 @@ ChartTwoCartesianAxis::getAxisLocation() const return m_axisLocation; } +/** + * Get the range of values allowed. + * + * @param rangeMinimumOut + * Minimum value allowed. + * @param rangeMaximumOut + * Maximum value allowed. + */ +void +ChartTwoCartesianAxis::getRange(float& rangeMinimumOut, + float& rangeMaximumOut) const +{ + rangeMinimumOut = m_rangeMinimumValue; + rangeMaximumOut = m_rangeMaximumValue; +} + +/** + * Set the range of values allowed. + * + * @param rangeMinimum + * Minimum value allowed. + * @param rangeMaximum + * Maximum value allowed. + */ +void +ChartTwoCartesianAxis::setRange(const float rangeMinimum, + const float rangeMaximum) +{ + m_rangeMinimumValue = rangeMinimum; + m_rangeMaximumValue = rangeMaximum; + limitUserScaleMinMaxToValidRange(); +} + +/** + * Limit the user scale min/max values to be within the valid range. + */ +void +ChartTwoCartesianAxis::limitUserScaleMinMaxToValidRange() +{ + m_userScaleMinimumValue = MathFunctions::limitRange(m_userScaleMinimumValue, + m_rangeMinimumValue, + m_rangeMaximumValue); + m_userScaleMaximumValue = MathFunctions::limitRange(m_userScaleMaximumValue, + m_rangeMinimumValue, + m_rangeMaximumValue); +} + /** * @return User's digits right of decimal point. */ @@ -239,6 +295,7 @@ void ChartTwoCartesianAxis::setUserScaleMaximumValue(const float userScaleMaximumValue) { m_userScaleMaximumValue = userScaleMaximumValue; + limitUserScaleMinMaxToValidRange(); } /** @@ -250,6 +307,7 @@ void ChartTwoCartesianAxis::setUserScaleMinimumValue(const float userScaleMinimumValue) { m_userScaleMinimumValue = userScaleMinimumValue; + limitUserScaleMinMaxToValidRange(); } /** diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 841dba9d6..eef502e9d 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -48,6 +48,12 @@ namespace caret { ChartAxisLocationEnum::Enum getAxisLocation() const; + void getRange(float& rangeMinimumOut, + float& rangeMaximumOut) const; + + void setRange(const float rangeMinimum, + const float rangeMaximum); + float getUserScaleMinimumValue() const; void setUserScaleMinimumValue(const float value); @@ -132,11 +138,19 @@ namespace caret { float& maximumOut, float& stepValueOut, int32_t& digitsRightOfDecimalOut) const; + + void limitUserScaleMinMaxToValidRange(); std::unique_ptr m_sceneAssistant; const ChartAxisLocationEnum::Enum m_axisLocation; + /** Allowable range minimum NOT SAVED TO SCENE */ + float m_rangeMinimumValue = 0.0; + + /** Allowable range maximum NOT SAVED TO SCENE */ + float m_rangeMaximumValue = 1.0; + mutable float m_userScaleMinimumValue = -100.0; mutable float m_userScaleMaximumValue = 100.0; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index f484da380..81c01add5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -95,12 +95,12 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra const double bigValue = 999999.0; m_userMinimumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); QObject::connect(m_userMinimumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged); + this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged); m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); m_userMaximumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); QObject::connect(m_userMaximumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged); + this, &BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); m_showTickMarksCheckBox = new QCheckBox("Show Ticks"); @@ -350,7 +350,11 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* cha m_widgetGroup->blockAllSignals(true); //m_axisNameToolButton->setText(m_chartAxis->getLabelText()); m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); + float rangeMin(0.0), rangeMax(0.0); + m_chartAxis->getRange(rangeMin, rangeMax); + m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); + m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); @@ -397,12 +401,45 @@ BrainBrowserWindowToolBarChartTwoAxes::updateGraphics() EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } +/** + * Called when the minimum value is changed. + * + * @param minimumValue + * New minimum value. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged(double minimumValue) +{ + if (m_chartAxis != NULL) { + /* + * If the minimum or maximum value is modified by user, + * ensure Auto/User Range selection is USER + */ + m_autoUserRangeComboBox->getWidget()->blockSignals(true); + m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER); + m_autoUserRangeComboBox->getWidget()->blockSignals(false); + + /* + * Ensure maximum value is always greater than or equal to minimum + */ + if (minimumValue > m_userMaximumValueSpinBox->value()) { + m_userMaximumValueSpinBox->blockSignals(true); + m_userMaximumValueSpinBox->setValue(minimumValue); + m_userMaximumValueSpinBox->blockSignals(false); + } + + valueChanged(); + } +} /** - * Called when the minimum or maximum value is changed. + * Called when the maximum value is changed. + * + * @param maximumValue + * New maximum value. */ void -BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged(double) +BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumValue) { if (m_chartAxis != NULL) { /* @@ -412,6 +449,16 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMinimumMaximumValueChanged(double) m_autoUserRangeComboBox->getWidget()->blockSignals(true); m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER); m_autoUserRangeComboBox->getWidget()->blockSignals(false); + + /* + * Ensure minimum value is always less than or equal to maximum + */ + if (maximumValue < m_userMinimumValueSpinBox->value()) { + m_userMinimumValueSpinBox->blockSignals(true); + m_userMinimumValueSpinBox->setValue(maximumValue); + m_userMinimumValueSpinBox->blockSignals(false); + } + valueChanged(); } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 8f330687c..bc99de50c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -63,7 +63,9 @@ namespace caret { void valueChangedInt(int); - void axisMinimumMaximumValueChanged(double); + void axisMinimumValueChanged(double); + + void axisMaximumValueChanged(double); void axisNameToolButtonClicked(bool); -- GitLab From 2331e59bb08106493285f8632523bc760ee690a3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 6 Apr 2017 12:00:29 -0500 Subject: [PATCH 248/755] On Overlay and Map Settings Dialog's palette page, added a color selection for histogram envelope color. Also added a rainbow icon for the "Palette Color" selection for both bars and envelope. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 118 +-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 2 + src/Files/CaretMappableDataFile.cxx | 2 +- src/GuiQt/CaretColorEnumComboBox.cxx | 43 +- src/GuiQt/CaretColorEnumComboBox.h | 7 +- .../MapSettingsPaletteColorMappingWidget.cxx | 713 ++++++++++-------- .../MapSettingsPaletteColorMappingWidget.h | 4 +- src/GuiQt/WuQtUtilities.h | 4 +- src/Palette/PaletteColorMapping.cxx | 57 +- src/Palette/PaletteColorMapping.h | 12 +- src/Palette/PaletteColorMappingSaxReader.cxx | 19 +- src/Palette/PaletteColorMappingXmlElements.h | 3 +- 12 files changed, 574 insertions(+), 410 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 04b9c12d1..3f2ed0ecf 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -550,7 +550,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() 0.0); } + const CaretColorEnum::Enum envelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); drawHistogramChartContent(drawInfo.get(), + envelopeColor, drawBarsFlag, drawEnvelopeFlag); } @@ -625,7 +627,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Draw the given histogram chart. * * @param drawingInfo - * Histogram drawing information.. + * Histogram drawing information. + * @param envelopeColor + * Color for drawing envelope. * @param drawHistogramBarsFlag * Draw the histogram as bars. * @param drawHistogramEnvelopeFlag @@ -634,9 +638,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, + const CaretColorEnum::Enum envelopeColor, const bool drawHistogramBarsFlag, const bool drawHistogramEnvelopeFlag) { + float envelopeSolidColorRGBA[4]; + CaretColorEnum::toRGBAFloat(envelopeColor, + envelopeSolidColorRGBA); + const ChartableTwoFileHistogramChart* histogramChart = drawingInfo->m_histogramChart; const int32_t mapIndex = drawingInfo->m_mapIndex; const HistogramDrawingInfo& histogramDrawingInfo = *drawingInfo->m_histogramDrawingInfo; @@ -797,12 +806,34 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr CaretAssertVectorIndex(xValues, i + 1); float left = xValues[i]; float right = xValues[i + 1]; + CaretAssert(right >= left); float bottom = 0; + CaretAssertVectorIndex(yValues, i + 1); float topLeft = yValues[i]; float topRight = yValues[i+1]; + float leftRGBA[4]; + float rightRGBA[4]; + float middleRGBA[4]; + if (envelopeColor == CaretColorEnum::CUSTOM) { + CaretAssertVectorIndex(rgbaValues, (i + 1) * 4 + 3); + const float* leftColorPtr = &rgbaValues[i * 4]; + const float* rightColorPtr = &rgbaValues[i * 4]; + for (int32_t m = 0; m < 4; m++) { + leftRGBA[m] = leftColorPtr[m]; + rightRGBA[m] = rightColorPtr[m]; + middleRGBA[m] = (leftColorPtr[m] + rightColorPtr[m]) / 2.0; + }; + } + else { + for (int32_t m = 0; m < 4; m++) { + leftRGBA[m] = envelopeSolidColorRGBA[m]; + rightRGBA[m] = envelopeSolidColorRGBA[m]; + middleRGBA[m] = envelopeSolidColorRGBA[m]; + }; + } uint8_t idRGBA[4]; if (m_identificationModeFlag) { addToHistogramIdentification(mapIndex, i, idRGBA); @@ -817,8 +848,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + leftRGBA, + leftRGBA + 4); } quadVerticesXYZ.push_back(left); @@ -830,8 +861,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + leftRGBA, + leftRGBA + 4); } } @@ -844,34 +875,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + middleRGBA, + middleRGBA + 4); } -// quadVerticesXYZ.push_back(left); -// quadVerticesXYZ.push_back(topLeft); -// quadVerticesXYZ.push_back(z); -// if (m_identificationModeFlag) { -// quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), -// idRGBA, idRGBA + 4); -// } -// else { -// quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), -// m_fixedPipelineDrawing->m_foregroundColorFloat, -// m_fixedPipelineDrawing->m_foregroundColorFloat + 4); -// } -// -// quadVerticesXYZ.push_back(right); -// quadVerticesXYZ.push_back(topRight); -// quadVerticesXYZ.push_back(z); -// if (m_identificationModeFlag) { -// quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), -// idRGBA, idRGBA + 4); -// } -// else { -// quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), -// m_fixedPipelineDrawing->m_foregroundColorFloat, -// m_fixedPipelineDrawing->m_foregroundColorFloat + 4); -// } if (i == lastValueIndex) { quadVerticesXYZ.push_back(right); @@ -883,8 +889,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + rightRGBA, + rightRGBA + 4); } quadVerticesXYZ.push_back(right); @@ -896,8 +902,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + rightRGBA, + rightRGBA + 4); } } } @@ -963,8 +969,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } quadVerticesXYZ.push_back(left); quadVerticesXYZ.push_back(top); @@ -975,8 +981,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } } else { @@ -994,8 +1000,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } quadVerticesXYZ.push_back(left); @@ -1007,8 +1013,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } } } @@ -1025,8 +1031,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } quadVerticesXYZ.push_back(right); quadVerticesXYZ.push_back(top); @@ -1037,8 +1043,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } if (i == lastValueIndex) { @@ -1054,8 +1060,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } quadVerticesXYZ.push_back(right); quadVerticesXYZ.push_back(bottom); @@ -1066,8 +1072,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } } else { @@ -1085,8 +1091,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } quadVerticesXYZ.push_back(right); quadVerticesXYZ.push_back(yValues[i + 1]); @@ -1097,8 +1103,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr } else { quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - m_fixedPipelineDrawing->m_foregroundColorFloat, - m_fixedPipelineDrawing->m_foregroundColorFloat + 4); + envelopeSolidColorRGBA, + envelopeSolidColorRGBA + 4); } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index a4eeeeaf7..05b737c83 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -23,6 +23,7 @@ #include #include "BrainOpenGLChartTwoDrawingInterface.h" +#include "CaretColorEnum.h" #include "ChartAxisLocationEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" @@ -128,6 +129,7 @@ namespace caret { void drawHistogramChart(); void drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, + const CaretColorEnum::Enum envelopeColor, const bool drawHistogramBarsFlag, const bool drawHistogramEnvelopeFlag); diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index c66da330e..9239d5502 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -1075,7 +1075,7 @@ CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, /* * If selected, apply solid color to histogram */ - const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); + const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramBarsColor(); if (histogramColor != CaretColorEnum::CUSTOM) { float rgba[4]; CaretColorEnum::toRGBAFloat(histogramColor, rgba); diff --git a/src/GuiQt/CaretColorEnumComboBox.cxx b/src/GuiQt/CaretColorEnumComboBox.cxx index 0450c023a..a690d14eb 100644 --- a/src/GuiQt/CaretColorEnumComboBox.cxx +++ b/src/GuiQt/CaretColorEnumComboBox.cxx @@ -48,7 +48,8 @@ using namespace caret; CaretColorEnumComboBox::CaretColorEnumComboBox(QObject* parent) : WuQWidget(parent) { - initializeCaretColorComboBox(""); + initializeCaretColorComboBox("", + NULL); } /** @@ -65,7 +66,29 @@ CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelecti : WuQWidget(parent) { CaretAssert( ! customColorSelectionName.isEmpty()); - initializeCaretColorComboBox(customColorSelectionName); + initializeCaretColorComboBox(customColorSelectionName, + NULL); +} + +/** + * Constructor. + * + * @param customColorSelectionName + * CaretColorEnum::CUSTOM is added to the combo with this name as the text. + * Text must NOT be empty. + * @param customColorSelectionIcon + * ICon for custom color. + * @param parent + * Parent object. + */ +CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, + const QIcon& customColorSelectionIcon, + QObject* parent) +: WuQWidget(parent) +{ + CaretAssert( ! customColorSelectionName.isEmpty()); + initializeCaretColorComboBox(customColorSelectionName, + &customColorSelectionIcon); } /** @@ -81,9 +104,12 @@ CaretColorEnumComboBox::~CaretColorEnumComboBox() * * @param customColorSelectionName * If NOT empty, CaretColorEnum::CUSTOM is added with text from this name. + * @param customColorSelectionIcon + * ICON for custom color (ignored if NULL) */ void -CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorSelectionName) +CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorSelectionName, + const QIcon* customColorSelectionIcon) { this->colorComboBox = new QComboBox(); @@ -120,9 +146,11 @@ CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorS } else if (colorEnum == CaretColorEnum::CUSTOM) { /* - * No pixmap for CUSTOM + * If NO icon for CUSTOM */ - rgba[3] = 0.0; + if (customColorSelectionIcon == NULL) { + rgba[3] = 0.0; + } } else { rgba[3] = 1.0; @@ -131,6 +159,11 @@ CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorS if (rgba[3] > 0.0) { QPixmap pm(WuQtUtilities::createCaretColorEnumPixmap(getWidget(), 10, 10, colorEnum, rgba, false)); QIcon icon(pm); + if (colorEnum == CaretColorEnum::CUSTOM) { + if (customColorSelectionIcon != NULL) { + icon = *customColorSelectionIcon; + } + } this->colorComboBox->setItemIcon(indx, icon); } diff --git a/src/GuiQt/CaretColorEnumComboBox.h b/src/GuiQt/CaretColorEnumComboBox.h index 38b4cd8a1..0c5dac456 100644 --- a/src/GuiQt/CaretColorEnumComboBox.h +++ b/src/GuiQt/CaretColorEnumComboBox.h @@ -39,6 +39,10 @@ namespace caret { CaretColorEnumComboBox(const AString& customColorSelectionName, QObject* parent); + CaretColorEnumComboBox(const AString& customColorSelectionName, + const QIcon& customColorSelectionIcon, + QObject* parent); + virtual ~CaretColorEnumComboBox(); CaretColorEnum::Enum getSelectedColor(); @@ -61,7 +65,8 @@ namespace caret { private: QComboBox* colorComboBox; - void initializeCaretColorComboBox(const AString& customColorSelectionName); + void initializeCaretColorComboBox(const AString& customColorSelectionName, + const QIcon* customColorSelectionIcon); }; diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 2d6ccdad8..f8b638a44 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -747,12 +747,38 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() this->m_histogramHorizontalRangeComboBox->setup(); this->m_histogramHorizontalRangeComboBox->getWidget()->setToolTip("Horizontal range of histogram"); - QLabel* colorLabel = new QLabel("Bars Color"); - m_histogramColorComboBox = new CaretColorEnumComboBox("With Palette", - this); - WuQtUtilities::setToolTipAndStatusTip(m_histogramColorComboBox->getWidget(), - "Set histogram coloring"); - QObject::connect(m_histogramColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), + QIcon colorBarIcon; + const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", + colorBarIcon); + + QLabel* barsColorLabel = new QLabel("Bars Color"); + if (colorBarIconValid) { + m_histogramBarsColorComboBox = new CaretColorEnumComboBox("Palette", + colorBarIcon, + this); + } + else { + m_histogramBarsColorComboBox = new CaretColorEnumComboBox("Palette", + this); + } + WuQtUtilities::setToolTipAndStatusTip(m_histogramBarsColorComboBox->getWidget(), + "Set histogram bars coloring"); + QObject::connect(m_histogramBarsColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), + this, SLOT(applyAndUpdate())); + + QLabel* envelopeColorLabel = new QLabel("Envelope Color"); + if (colorBarIconValid) { + m_histogramEnvelopeColorComboBox = new CaretColorEnumComboBox("Palette", + colorBarIcon, + this); + } + else { + m_histogramEnvelopeColorComboBox = new CaretColorEnumComboBox("Palette", + this); + } + WuQtUtilities::setToolTipAndStatusTip(m_histogramEnvelopeColorComboBox->getWidget(), + "Set histogram envelope coloring"); + QObject::connect(m_histogramEnvelopeColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); const int32_t maxBuckets = 100000; @@ -768,8 +794,11 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() controlLayout->addWidget(showLabel, rowIndex, 0); controlLayout->addLayout(showLayout, rowIndex, 1); rowIndex++; - controlLayout->addWidget(colorLabel, rowIndex, 0); - controlLayout->addWidget(m_histogramColorComboBox->getWidget(), rowIndex, 1); + controlLayout->addWidget(barsColorLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramBarsColorComboBox->getWidget(), rowIndex, 1); + rowIndex++; + controlLayout->addWidget(envelopeColorLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramEnvelopeColorComboBox->getWidget(), rowIndex, 1); rowIndex++; controlLayout->addWidget(horizRangeLabel, rowIndex, 0); controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), rowIndex, 1); @@ -1721,7 +1750,8 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile this->interpolateColorsCheckBox->setChecked(this->paletteColorMapping->isInterpolatePaletteFlag()); - m_histogramColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramColor()); + m_histogramBarsColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramBarsColor()); + m_histogramEnvelopeColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramEnvelopeColor()); m_histogramBarsVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramBarsVisible()); m_histogramEnvelopeVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramEnvelopeVisible()); @@ -1902,6 +1932,10 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() this->thresholdPlot->detachItems(); + + if (this->paletteColorMapping == NULL) { + return; + } FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: @@ -1911,381 +1945,413 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); break; } + if (statistics == NULL) { + return; + } + if (this->paletteColorMapping->isHistogramBarsVisible() + || this->paletteColorMapping->isHistogramEnvelopeVisible()) { + /* okay */ + } + else { + /* nothing to display */ + return; + } - if ((this->paletteColorMapping != NULL) - && (statistics != NULL)) { - PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); - + PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); + /* + * Data values table + */ + const float statsMean = statistics->getMean(); + const float statsStdDev = statistics->getSampleStdDev(); + const float statsMin = statistics->getMin(); + const float statsMax = statistics->getMax(); + this->statisticsMeanValueLabel->setText(QString::number(statsMean, 'f', 4)); + this->statisticsStandardDeviationLabel->setText(QString::number(statsStdDev, 'f', 4)); + this->statisticsMaximumValueLabel->setText(QString::number(statsMax, 'f', 4)); + this->statisticsMinimumValueLabel->setText(QString::number(statsMin, 'f', 4)); + + /* + * Get data for this histogram. + */ + const Histogram* myHist = getHistogram(statistics); + //const int64_t* histogram = const_cast(statistics->getHistogram()); + float minValue, maxValue; + myHist->getRange(minValue, maxValue); + const std::vector& displayDataReference = myHist->getHistogramDisplay(); + std::vector displayData = displayDataReference; // may modify it + const int64_t numHistogramValues = (int64_t)(displayData.size()); + + /* + * Width of each 'bar' in the histogram + */ + float step = 1.0; + if (numHistogramValues > 1) { + step = ((maxValue - minValue) + / numHistogramValues); + } + + const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); + const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); + + float* dataValues = NULL; + float* dataRGBA = NULL; + if (numHistogramValues > 0) { /* - * Data values table + * Compute color for 'bar' in the histogram. + * Note that number of data values is one more + * than the number of histogram values due to that + * a data value is needed on the right of the last + * histogram bar. Otherwise, if there is an outlier + * value, the histogram will not be drawn + * correctly. */ - const float statsMean = statistics->getMean(); - const float statsStdDev = statistics->getSampleStdDev(); - const float statsMin = statistics->getMin(); - const float statsMax = statistics->getMax(); - this->statisticsMeanValueLabel->setText(QString::number(statsMean, 'f', 4)); - this->statisticsStandardDeviationLabel->setText(QString::number(statsStdDev, 'f', 4)); - this->statisticsMaximumValueLabel->setText(QString::number(statsMax, 'f', 4)); - this->statisticsMinimumValueLabel->setText(QString::number(statsMin, 'f', 4)); + const int64_t numDataValues = numHistogramValues + 1; + dataValues = new float[numDataValues]; + dataRGBA = new float[numDataValues * 4]; + for (int64_t ix = 0; ix < numDataValues; ix++) { + const float value = (minValue + + (ix * step)); + dataValues[ix] = value; + } + dataValues[0] = minValue; + dataValues[numDataValues - 1] = maxValue; - /* - * Get data for this histogram. - */ - const Histogram* myHist = getHistogram(statistics); - //const int64_t* histogram = const_cast(statistics->getHistogram()); - float minValue, maxValue; - myHist->getRange(minValue, maxValue); - const std::vector& displayDataReference = myHist->getHistogramDisplay(); - std::vector displayData = displayDataReference; // may modify it - const int64_t numHistogramValues = (int64_t)(displayData.size()); + const Palette* palette = paletteFile->getPaletteByName(this->paletteColorMapping->getSelectedPaletteName()); /* - * Width of each 'bar' in the histogram + * Color with palette so that alpha values are zero for regions not displayed */ - float step = 1.0; - if (numHistogramValues > 1) { - step = ((maxValue - minValue) - / numHistogramValues); - } - - float* dataValues = NULL; - float* dataRGBA = NULL; - if (numHistogramValues > 0) { - /* - * Compute color for 'bar' in the histogram. - * Note that number of data values is one more - * than the number of histogram values due to that - * a data value is needed on the right of the last - * histogram bar. Otherwise, if there is an outlier - * value, the histogram will not be drawn - * correctly. - */ - const int64_t numDataValues = numHistogramValues + 1; - dataValues = new float[numDataValues]; - dataRGBA = new float[numDataValues * 4]; - for (int64_t ix = 0; ix < numDataValues; ix++) { - const float value = (minValue - + (ix * step)); - dataValues[ix] = value; - } - dataValues[0] = minValue; - dataValues[numDataValues - 1] = maxValue; - - const Palette* palette = paletteFile->getPaletteByName(this->paletteColorMapping->getSelectedPaletteName()); + if (palette != NULL) { + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + dataValues, + dataValues, + numDataValues, + dataRGBA, + true); // ignore thresholding /* - * Color with palette so that alpha values are zero for regions not displayed + * If bucket is not colored (zero alpha) set bucket height to zero */ - if (palette != NULL) { - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - dataValues, - dataValues, - numDataValues, - dataRGBA, - true); // ignore thresholding - - /* - * If bucket is not colored (zero alpha) set bucket height to zero - */ - for (int32_t i = 0; i < numHistogramValues; i++) { - const int32_t alphaIndex = i * 4 + 3; - CaretAssertArrayIndex(dataRGBA, (numDataValues * 4), alphaIndex); - if (dataRGBA[alphaIndex] <= 0.0) { - CaretAssertVectorIndex(displayData, i); - displayData[i] = 0.0; - } - } - } - - const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); - if (histogramColor != CaretColorEnum::CUSTOM) { - /* - * DO NOT override RGBA - */ - float colorRGBA[4]; - CaretColorEnum::toRGBAFloat(histogramColor, - colorRGBA); - for (int64_t i = 0; i < numDataValues; i++) { - const int64_t i4 = i * 4; - dataRGBA[i4] = colorRGBA[0]; - dataRGBA[i4+1] = colorRGBA[1]; - dataRGBA[i4+2] = colorRGBA[2]; + for (int32_t i = 0; i < numHistogramValues; i++) { + const int32_t alphaIndex = i * 4 + 3; + CaretAssertArrayIndex(dataRGBA, (numDataValues * 4), alphaIndex); + if (dataRGBA[alphaIndex] <= 0.0) { + CaretAssertVectorIndex(displayData, i); + displayData[i] = 0.0; } } } -// const bool drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); -// bool drawEnvelopeFlag = false; -// const bool allowEnvelopeChartTypeFlag = true; -// if (allowEnvelopeChartTypeFlag) { -// drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); -// } - - const QPalette palette = this->thresholdPlot->palette(); - const QPalette::ColorRole foregroundRole = this->thresholdPlot->foregroundRole(); - const QBrush foregroundBrush = palette.brush(foregroundRole); - const QColor foregroundColor = foregroundBrush.color(); + // if (histogramColor != CaretColorEnum::CUSTOM) { + // /* + // * DO NOT override RGBA + // */ + // float colorRGBA[4]; + // CaretColorEnum::toRGBAFloat(histogramColor, + // colorRGBA); + // for (int64_t i = 0; i < numDataValues; i++) { + // const int64_t i4 = i * 4; + // dataRGBA[i4] = colorRGBA[0]; + // dataRGBA[i4+1] = colorRGBA[1]; + // dataRGBA[i4+2] = colorRGBA[2]; + // } + // } + } + + // const bool drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); + // bool drawEnvelopeFlag = false; + // const bool allowEnvelopeChartTypeFlag = true; + // if (allowEnvelopeChartTypeFlag) { + // drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); + // } + + // const QPalette palette = this->thresholdPlot->palette(); + // const QPalette::ColorRole foregroundRole = this->thresholdPlot->foregroundRole(); + // const QBrush foregroundBrush = palette.brush(foregroundRole); + // const QColor foregroundColor = foregroundBrush.color(); + + float z = 0.0; + float maxDataFrequency = 0.0; + for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { + bool drawBarsFlag = false; + bool drawEnvelopeFlag = false; + if (drawModeInt == 0) { + drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); + } + else if (drawModeInt == 1) { + drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); + } - float z = 0.0; - float maxDataFrequency = 0.0; - for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { - bool drawBarsFlag = false; - bool drawEnvelopeFlag = false; - if (drawModeInt == 0) { - drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); - } - else if (drawModeInt == 1) { - drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); - } + if (drawBarsFlag + || drawEnvelopeFlag) { + float barsSolidRGBA[4]; + CaretColorEnum::toRGBAFloat(histogramBarsColor, + barsSolidRGBA); + float envelopeSolidRGBA[4]; + CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, + envelopeSolidRGBA); - if (drawBarsFlag - || drawEnvelopeFlag) { - const int32_t lastIndex = numHistogramValues - 1; - for (int64_t ix = 0; ix < numHistogramValues; ix++) { - QColor color; - const int64_t ix4 = ix * 4; - if (drawBarsFlag) { + const int32_t lastIndex = numHistogramValues - 1; + for (int64_t ix = 0; ix < numHistogramValues; ix++) { + QColor color; + const int64_t ix4 = ix * 4; + if (drawBarsFlag) { + if (histogramBarsColor == CaretColorEnum::CUSTOM) { color.setRedF(dataRGBA[ix4]); color.setGreenF(dataRGBA[ix4+1]); color.setBlueF(dataRGBA[ix4+2]); color.setAlphaF(1.0); } - else if (drawEnvelopeFlag) { - color = foregroundColor; + else { + color.setRgbF(barsSolidRGBA[0], barsSolidRGBA[1], barsSolidRGBA[2]); } - - const float startValue = dataValues[ix]; - const float stopValue = dataValues[ix + 1]; - float dataFrequency = displayData[ix]; - - bool displayIt = true; - - if (dataFrequency > maxDataFrequency) { - maxDataFrequency = dataFrequency; + } + else if (drawEnvelopeFlag) { + if (histogramEnvelopeColor == CaretColorEnum::CUSTOM) { + color.setRedF(dataRGBA[ix4]); + color.setGreenF(dataRGBA[ix4+1]); + color.setBlueF(dataRGBA[ix4+2]); + color.setAlphaF(1.0); + } + else { + color.setRgbF(envelopeSolidRGBA[0], envelopeSolidRGBA[1], envelopeSolidRGBA[2]); } + } + else { + CaretAssert(0); + } + + const float startValue = dataValues[ix]; + const float stopValue = dataValues[ix + 1]; + float dataFrequency = displayData[ix]; + + bool displayIt = true; + + if (dataFrequency > maxDataFrequency) { + maxDataFrequency = dataFrequency; + } + + /* + * If color is not displayed ('none' or thresholded), + * set its frequncey value to a small value so that the plot + * retains its shape and color is still slightly visible + */ + //Qt::BrushStyle brushStyle = Qt::SolidPattern; + if (dataRGBA[ix4+3] <= 0.0) { + displayIt = false; + } + + if (displayIt == false) { + color.setAlpha(0); + } + + QVector samples; + + QwtPlotCurve* curve = new QwtPlotCurve(); + curve->setRenderHint(QwtPlotItem::RenderAntialiased); + curve->setVisible(true); + + curve->setPen(QPen(color)); + + if (drawBarsFlag) { + curve->setStyle(QwtPlotCurve::Steps); + curve->setBrush(QBrush(color)); + samples.push_back(QPointF(startValue, dataFrequency)); + samples.push_back(QPointF(stopValue, dataFrequency)); + } + if (drawEnvelopeFlag) { + curve->setStyle(QwtPlotCurve::Lines); + //curve->setBrush(QBrush(color)); /* - * If color is not displayed ('none' or thresholded), - * set its frequncey value to a small value so that the plot - * retains its shape and color is still slightly visible + * Left side */ - //Qt::BrushStyle brushStyle = Qt::SolidPattern; - if (dataRGBA[ix4+3] <= 0.0) { - displayIt = false; + if (ix == 0) { + samples.push_back(QPointF(startValue, 0.0)); + samples.push_back(QPointF(startValue, dataFrequency)); } - - if (displayIt == false) { - color.setAlpha(0); + else { + CaretAssertVectorIndex(displayData, ix - 1); + const float lastFrequency = displayData[ix - 1]; + if (dataFrequency > lastFrequency) { + samples.push_back(QPointF(startValue, lastFrequency)); + samples.push_back(QPointF(startValue, dataFrequency)); + } } - QVector samples; - - QwtPlotCurve* curve = new QwtPlotCurve(); - curve->setRenderHint(QwtPlotItem::RenderAntialiased); - curve->setVisible(true); - - curve->setPen(QPen(color)); + /* + * Horizontal Bar + */ + samples.push_back(QPointF(startValue, dataFrequency)); + samples.push_back(QPointF(stopValue, dataFrequency)); - if (drawBarsFlag) { - curve->setStyle(QwtPlotCurve::Steps); - curve->setBrush(QBrush(color)); - samples.push_back(QPointF(startValue, dataFrequency)); + /* + * Right side + */ + if (ix == lastIndex) { samples.push_back(QPointF(stopValue, dataFrequency)); + samples.push_back(QPointF(stopValue, 0.0)); } - if (drawEnvelopeFlag) { - curve->setStyle(QwtPlotCurve::Lines); - //curve->setBrush(QBrush(color)); - - /* - * Left side - */ - if (ix == 0) { - samples.push_back(QPointF(startValue, 0.0)); - samples.push_back(QPointF(startValue, dataFrequency)); - } - else { - CaretAssertVectorIndex(displayData, ix - 1); - const float lastFrequency = displayData[ix - 1]; - if (dataFrequency > lastFrequency) { - samples.push_back(QPointF(startValue, lastFrequency)); - samples.push_back(QPointF(startValue, dataFrequency)); - } - } - - /* - * Horizontal Bar - */ - samples.push_back(QPointF(startValue, dataFrequency)); - samples.push_back(QPointF(stopValue, dataFrequency)); - - /* - * Right side - */ - if (ix == lastIndex) { + else { + CaretAssertVectorIndex(displayData, ix + 1); + const float nextFrequency = displayData[ix + 1]; + if (dataFrequency > nextFrequency) { samples.push_back(QPointF(stopValue, dataFrequency)); - samples.push_back(QPointF(stopValue, 0.0)); - } - else { - CaretAssertVectorIndex(displayData, ix + 1); - const float nextFrequency = displayData[ix + 1]; - if (dataFrequency > nextFrequency) { - samples.push_back(QPointF(stopValue, dataFrequency)); - samples.push_back(QPointF(stopValue, nextFrequency)); - } + samples.push_back(QPointF(stopValue, nextFrequency)); } } - - curve->setSamples(samples); - - curve->attach(this->thresholdPlot); - - if (ix == 0) { - z = curve->z(); - } } + curve->setSamples(samples); + + curve->attach(this->thresholdPlot); + + if (ix == 0) { + z = curve->z(); + } } - z--; } - + z--; + } + + z--; + + if ((numHistogramValues > 2) + && (this->paletteColorMapping->getThresholdType() != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF)) { + float threshMinValue = this->paletteColorMapping->getThresholdNormalMinimum(); + float threshMaxValue = this->paletteColorMapping->getThresholdNormalMaximum(); - if ((numHistogramValues > 2) - && (this->paletteColorMapping->getThresholdType() != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF)) { - float threshMinValue = this->paletteColorMapping->getThresholdNormalMinimum(); - float threshMaxValue = this->paletteColorMapping->getThresholdNormalMaximum(); - - maxDataFrequency *= 1.05; - - switch (this->paletteColorMapping->getThresholdTest()) { - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: - { - const float plotMinValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).lowerBound(); - const float plotMaxValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).upperBound(); - - /* - * Draw shaded region to left of minimum threshold - */ - QVector minSamples; - minSamples.push_back(QPointF(plotMinValue, maxDataFrequency)); - minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); - - QwtPlotCurve* minBox = new QwtPlotCurve(); - minBox->setRenderHint(QwtPlotItem::RenderAntialiased); - minBox->setVisible(true); - minBox->setStyle(QwtPlotCurve::Dots); - - QColor minColor(100, 100, 255, 160); - minBox->setBrush(QBrush(minColor, Qt::Dense4Pattern)); - minBox->setPen(QPen(minColor)); - minBox->setSamples(minSamples); - - minBox->setZ(z); - minBox->attach(this->thresholdPlot); - - /* - * Draw shaded region to right of maximum threshold - */ - QVector maxSamples; - maxSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); - maxSamples.push_back(QPointF(plotMaxValue, maxDataFrequency)); - - QwtPlotCurve* maxBox = new QwtPlotCurve(); - maxBox->setRenderHint(QwtPlotItem::RenderAntialiased); - maxBox->setVisible(true); - maxBox->setStyle(QwtPlotCurve::Dots); - - QColor maxColor(100, 100, 255, 160); - maxBox->setBrush(QBrush(maxColor, Qt::Dense4Pattern)); - maxBox->setPen(QPen(maxColor)); - maxBox->setSamples(maxSamples); - - maxBox->setZ(z); - maxBox->attach(this->thresholdPlot); - } - break; - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: - { - /* - * Draw shaded region between minimum and maximum threshold - */ - QVector minSamples; - minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); - minSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); - - QwtPlotCurve* minBox = new QwtPlotCurve(); - minBox->setRenderHint(QwtPlotItem::RenderAntialiased); - minBox->setVisible(true); - - QColor minColor(100, 100, 255, 160); - minBox->setBrush(QBrush(minColor)); //, Qt::Dense4Pattern)); - minBox->setPen(QPen(minColor)); - minBox->setSamples(minSamples); - - minBox->setZ(z); - - minBox->attach(this->thresholdPlot); - } - break; - } - - const bool showLinesFlag = false; - if (showLinesFlag) { + maxDataFrequency *= 1.05; + + switch (this->paletteColorMapping->getThresholdTest()) { + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: + { + const float plotMinValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).lowerBound(); + const float plotMaxValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).upperBound(); + /* - * Line for high threshold + * Draw shaded region to left of minimum threshold */ QVector minSamples; - minSamples.push_back(QPointF(threshMinValue, 0)); + minSamples.push_back(QPointF(plotMinValue, maxDataFrequency)); minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); - QwtPlotCurve* minLine = new QwtPlotCurve(); - minLine->setRenderHint(QwtPlotItem::RenderAntialiased); - minLine->setVisible(true); - minLine->setStyle(QwtPlotCurve::Lines); + QwtPlotCurve* minBox = new QwtPlotCurve(); + minBox->setRenderHint(QwtPlotItem::RenderAntialiased); + minBox->setVisible(true); + minBox->setStyle(QwtPlotCurve::Dots); - QColor minColor(0.0, 0.0, 1.0); - minLine->setPen(QPen(minColor)); - minLine->setSamples(minSamples); + QColor minColor(100, 100, 255, 160); + minBox->setBrush(QBrush(minColor, Qt::Dense4Pattern)); + minBox->setPen(QPen(minColor)); + minBox->setSamples(minSamples); - minLine->setZ(1.0); - minLine->attach(this->thresholdPlot); + minBox->setZ(z); + minBox->attach(this->thresholdPlot); /* - * Line for high threshold + * Draw shaded region to right of maximum threshold */ QVector maxSamples; - maxSamples.push_back(QPointF(threshMaxValue, 0)); maxSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); + maxSamples.push_back(QPointF(plotMaxValue, maxDataFrequency)); + + QwtPlotCurve* maxBox = new QwtPlotCurve(); + maxBox->setRenderHint(QwtPlotItem::RenderAntialiased); + maxBox->setVisible(true); + maxBox->setStyle(QwtPlotCurve::Dots); + + QColor maxColor(100, 100, 255, 160); + maxBox->setBrush(QBrush(maxColor, Qt::Dense4Pattern)); + maxBox->setPen(QPen(maxColor)); + maxBox->setSamples(maxSamples); + + maxBox->setZ(z); + maxBox->attach(this->thresholdPlot); + } + break; + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: + { + /* + * Draw shaded region between minimum and maximum threshold + */ + QVector minSamples; + minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); + minSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); - QwtPlotCurve* maxLine = new QwtPlotCurve(); - maxLine->setRenderHint(QwtPlotItem::RenderAntialiased); - maxLine->setVisible(true); - maxLine->setStyle(QwtPlotCurve::Lines); + QwtPlotCurve* minBox = new QwtPlotCurve(); + minBox->setRenderHint(QwtPlotItem::RenderAntialiased); + minBox->setVisible(true); - QColor maxColor(1.0, 0.0, 0.0); - maxLine->setPen(QPen(maxColor)); - maxLine->setSamples(maxSamples); + QColor minColor(100, 100, 255, 160); + minBox->setBrush(QBrush(minColor)); //, Qt::Dense4Pattern)); + minBox->setPen(QPen(minColor)); + minBox->setSamples(minSamples); - maxLine->setZ(1.0); - maxLine->attach(this->thresholdPlot); + minBox->setZ(z); + + minBox->attach(this->thresholdPlot); } + break; } - if (dataValues != NULL) { - delete[] dataValues; - } - if (dataRGBA != NULL) { - delete[] dataRGBA; + const bool showLinesFlag = false; + if (showLinesFlag) { + /* + * Line for high threshold + */ + QVector minSamples; + minSamples.push_back(QPointF(threshMinValue, 0)); + minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); + + QwtPlotCurve* minLine = new QwtPlotCurve(); + minLine->setRenderHint(QwtPlotItem::RenderAntialiased); + minLine->setVisible(true); + minLine->setStyle(QwtPlotCurve::Lines); + + QColor minColor(0.0, 0.0, 1.0); + minLine->setPen(QPen(minColor)); + minLine->setSamples(minSamples); + + minLine->setZ(1.0); + minLine->attach(this->thresholdPlot); + + /* + * Line for high threshold + */ + QVector maxSamples; + maxSamples.push_back(QPointF(threshMaxValue, 0)); + maxSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); + + QwtPlotCurve* maxLine = new QwtPlotCurve(); + maxLine->setRenderHint(QwtPlotItem::RenderAntialiased); + maxLine->setVisible(true); + maxLine->setStyle(QwtPlotCurve::Lines); + + QColor maxColor(1.0, 0.0, 0.0); + maxLine->setPen(QPen(maxColor)); + maxLine->setSamples(maxSamples); + + maxLine->setZ(1.0); + maxLine->attach(this->thresholdPlot); } - - /* - * Causes updates of plots. - */ - this->thresholdPlot->replot(); } + + if (dataValues != NULL) { + delete[] dataValues; + } + if (dataRGBA != NULL) { + delete[] dataRGBA; + } + + /* + * Causes updates of plots. + */ + this->thresholdPlot->replot(); } /** @@ -2340,7 +2406,8 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setInterpolatePaletteFlag(this->interpolateColorsCheckBox->isChecked()); - this->paletteColorMapping->setHistogramColor(m_histogramColorComboBox->getSelectedColor()); + this->paletteColorMapping->setHistogramBarsColor(m_histogramBarsColorComboBox->getSelectedColor()); + this->paletteColorMapping->setHistogramEnvelopeColor(m_histogramEnvelopeColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramBarsVisible(m_histogramBarsVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramEnvelopeVisible(m_histogramEnvelopeVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index 486343b71..a23b47f55 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -199,7 +199,9 @@ namespace caret { EnumComboBoxTemplate* m_histogramHorizontalRangeComboBox; - CaretColorEnumComboBox* m_histogramColorComboBox; + CaretColorEnumComboBox* m_histogramBarsColorComboBox; + + CaretColorEnumComboBox* m_histogramEnvelopeColorComboBox; QCheckBox* m_histogramBarsVisibleCheckBox; diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index 4214b5557..df4ad438d 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -83,11 +83,11 @@ namespace caret { static QWidget* createHorizontalLineWidget(); - static QPixmap createCaretColorEnumPixmap(const QWidget* widgetForPixmap, + static QPixmap createCaretColorEnumPixmap(const QWidget* widget, const int32_t pixmapWidth, const int32_t pixmapHeight, const CaretColorEnum::Enum caretColor, - const float rgba[4], + const float customColorRGBA[4], const bool outlineFlag); static QSharedPointer createPixmapWidgetPainter(const QWidget* widget, diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 3e9df7396..f79954baf 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -137,7 +137,8 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->histogramRangeMode = pcm.histogramRangeMode; this->histogramBarsVisible = pcm.histogramBarsVisible; this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; - this->histogramColor = pcm.histogramColor; + this->histogramBarsColor = pcm.histogramBarsColor; + this->histogramEnvelopeColor = pcm.histogramEnvelopeColor; this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; this->colorBarPrecisionDigits = pcm.colorBarPrecisionDigits; @@ -189,7 +190,8 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->histogramRangeMode == pcm.histogramRangeMode) && (this->histogramBarsVisible == pcm.histogramBarsVisible) && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) - && (this->histogramColor == pcm.histogramColor) + && (this->histogramBarsColor == pcm.histogramBarsColor) + && (this->histogramEnvelopeColor == pcm.histogramEnvelopeColor) && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets) && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) && (this->colorBarPrecisionDigits == pcm.colorBarPrecisionDigits) @@ -238,7 +240,8 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; this->histogramBarsVisible = true; this->histogramEnvelopeVisible = false; - this->histogramColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette + this->histogramBarsColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette + this->histogramEnvelopeColor = CaretColorEnum::RED; this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; this->colorBarPrecisionDigits = 2; @@ -362,8 +365,10 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) this->histogramBarsVisible); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE, this->histogramEnvelopeVisible); - xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR, - CaretColorEnum::toName(this->histogramColor)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_COLOR, + CaretColorEnum::toName(this->histogramBarsColor)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_COLOR, + CaretColorEnum::toName(this->histogramEnvelopeColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS, this->histogramNumberOfBuckets); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, @@ -2810,25 +2815,49 @@ PaletteColorMapping::setHistogramEnvelopeVisible(const bool histogramEnvelopeVis } /** - * @return Color for drawing histogram. + * @return Color for drawing histogram bars */ CaretColorEnum::Enum -PaletteColorMapping::getHistogramColor() const +PaletteColorMapping::getHistogramBarsColor() const { - return histogramColor; + return histogramBarsColor; } /** - * Set the color for drawing the histogram. + * Set the color for drawing the histogram bars * - * @param histogramColor - * New color for the histogram. + * @param histogramBarsColor + * New color for the histogram bars */ void -PaletteColorMapping::setHistogramColor(const CaretColorEnum::Enum histogramColor) +PaletteColorMapping::setHistogramBarsColor(const CaretColorEnum::Enum histogramBarsColor) { - if (histogramColor != this->histogramColor) { - this->histogramColor = histogramColor; + if (histogramBarsColor != this->histogramBarsColor) { + this->histogramBarsColor = histogramBarsColor; + setModified(); + } +} + +/** + * @return Color for drawing histogram envelope + */ +CaretColorEnum::Enum +PaletteColorMapping::getHistogramEnvelopeColor() const +{ + return histogramEnvelopeColor; +} + +/** + * Set the color for drawing the histogram envelope + * + * @param histogramEnvelopeColor + * New color for the histogram envelope. + */ +void +PaletteColorMapping::setHistogramEnvelopeColor(const CaretColorEnum::Enum histogramEnvelopeColor) +{ + if (histogramEnvelopeColor != this->histogramEnvelopeColor) { + this->histogramEnvelopeColor = histogramEnvelopeColor; setModified(); } } diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index d281a6ba8..f7faa02ff 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -220,9 +220,13 @@ namespace caret { void setHistogramEnvelopeVisible(const bool histogramEnvelopeVisible); - CaretColorEnum::Enum getHistogramColor() const; + CaretColorEnum::Enum getHistogramBarsColor() const; - void setHistogramColor(const CaretColorEnum::Enum histogramColor); + void setHistogramBarsColor(const CaretColorEnum::Enum histogramBarsColor); + + CaretColorEnum::Enum getHistogramEnvelopeColor() const; + + void setHistogramEnvelopeColor(const CaretColorEnum::Enum histogramEnvelopeColor); int32_t getHistogramNumberOfBuckets() const; @@ -334,7 +338,9 @@ namespace caret { bool histogramEnvelopeVisible; - CaretColorEnum::Enum histogramColor; + CaretColorEnum::Enum histogramBarsColor; + + CaretColorEnum::Enum histogramEnvelopeColor; int32_t histogramNumberOfBuckets; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index a18a9376a..42e92e537 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -318,12 +318,25 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE) { this->paletteColorMapping->setHistogramEnvelopeVisible(toBool(this->elementText)); } - else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_COLOR) { + else if ((qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_COLOR) + || (qName == "HistogramColor")) { bool isValid = false; - CaretColorEnum::Enum histogramColor = CaretColorEnum::fromName(this->elementText, + CaretColorEnum::Enum histogramBarsColor = CaretColorEnum::fromName(this->elementText, &isValid); if (isValid) { - this->paletteColorMapping->setHistogramColor(histogramColor); + this->paletteColorMapping->setHistogramBarsColor(histogramBarsColor); + } + else { + throw XmlSaxParserException("Invalid CaretColorEnum::Enum: " + + this->elementText); + } + } + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_COLOR) { + bool isValid = false; + CaretColorEnum::Enum histogramEnvelopeColor = CaretColorEnum::fromName(this->elementText, + &isValid); + if (isValid) { + this->paletteColorMapping->setHistogramEnvelopeColor(histogramEnvelopeColor); } else { throw XmlSaxParserException("Invalid CaretColorEnum::Enum: " diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index babc6609f..1243a368d 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -48,7 +48,8 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; static const AString XML_TAG_HISTOGRAM_BARS_VISIBLE = "HistogramBarsVisible"; static const AString XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE = "HistogramEnvelopeVisible"; - static const AString XML_TAG_HISTOGRAM_COLOR = "HistogramColor"; + static const AString XML_TAG_HISTOGRAM_BARS_COLOR = "HistogramBarsColor"; + static const AString XML_TAG_HISTOGRAM_ENVELOPE_COLOR = "HistogramEnvelopeColor"; static const AString XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; -- GitLab From f06f77dc44ab043ca9649190f1a0c2907b4633cf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 11 Apr 2017 16:51:21 -0500 Subject: [PATCH 249/755] Revising drawing for Charts including new system for drawing OpenGL primitives. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 201 +++++++++------ src/Brain/CMakeLists.txt | 2 +- src/Brain/SessionManager.cxx | 8 + src/CMakeLists.txt | 1 + src/Charting/ChartTwoCartesianAxis.cxx | 2 + src/Charting/ChartTwoDataCartesianHistory.cxx | 6 +- .../ChartTwoMatrixDisplayProperties.cxx | 10 +- src/CommandLine/CMakeLists.txt | 1 + src/Desktop/CMakeLists.txt | 2 + src/Graphics/CMakeLists.txt | 60 +++++ src/{Brain => Graphics}/CaretOpenGLInclude.h | 0 src/Graphics/GraphicsEngine.cxx | 82 +++++++ src/Graphics/GraphicsEngine.h | 72 ++++++ src/Graphics/GraphicsEngineOpenGL.cxx | 229 ++++++++++++++++++ src/Graphics/GraphicsEngineOpenGL.h | 59 +++++ src/Graphics/GraphicsFactory.cxx | 168 +++++++++++++ src/Graphics/GraphicsFactory.h | 82 +++++++ src/Graphics/GraphicsPrimitive.cxx | 225 +++++++++++++++++ src/Graphics/GraphicsPrimitive.h | 149 ++++++++++++ src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 133 ++++++++++ src/Graphics/GraphicsPrimitiveV3fC4f.h | 69 ++++++ src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 133 ++++++++++ src/Graphics/GraphicsPrimitiveV3fC4ub.h | 67 +++++ src/GuiQt/CMakeLists.txt | 1 + src/OSMesaDummy/CMakeLists.txt | 2 +- src/Operations/CMakeLists.txt | 1 + src/Tests/CMakeLists.txt | 1 + 27 files changed, 1679 insertions(+), 87 deletions(-) create mode 100644 src/Graphics/CMakeLists.txt rename src/{Brain => Graphics}/CaretOpenGLInclude.h (100%) create mode 100644 src/Graphics/GraphicsEngine.cxx create mode 100644 src/Graphics/GraphicsEngine.h create mode 100644 src/Graphics/GraphicsEngineOpenGL.cxx create mode 100644 src/Graphics/GraphicsEngineOpenGL.h create mode 100644 src/Graphics/GraphicsFactory.cxx create mode 100644 src/Graphics/GraphicsFactory.h create mode 100644 src/Graphics/GraphicsPrimitive.cxx create mode 100644 src/Graphics/GraphicsPrimitive.h create mode 100644 src/Graphics/GraphicsPrimitiveV3fC4f.cxx create mode 100644 src/Graphics/GraphicsPrimitiveV3fC4f.h create mode 100644 src/Graphics/GraphicsPrimitiveV3fC4ub.cxx create mode 100644 src/Graphics/GraphicsPrimitiveV3fC4ub.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 3f2ed0ecf..d0650095b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -45,6 +45,10 @@ #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "FastStatistics.h" +#include "GraphicsEngineOpenGL.h" +#include "GraphicsFactory.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" #include "HistogramDrawingInfo.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" @@ -131,6 +135,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); + m_fixedPipelineDrawing->disableLighting(); + /* * Find color bars for this tab and decrease height of * viewport so chart is above color bars. @@ -1345,12 +1351,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT }; int32_t rgbaOffset = 0; - std::vector quadVerticesXYZ; - quadVerticesXYZ.reserve(numberOfRows * numberOfColumns * 3); - std::vector quadVerticesFloatRGBA; - quadVerticesFloatRGBA.reserve(numberOfRows * numberOfColumns * 4); - std::vector quadVerticesByteRGBA; - quadVerticesByteRGBA.reserve(numberOfRows * numberOfColumns * 4); +// std::vector quadVerticesXYZ; +// quadVerticesXYZ.reserve(numberOfRows * numberOfColumns * 3); +// std::vector quadVerticesFloatRGBA; +// quadVerticesFloatRGBA.reserve(numberOfRows * numberOfColumns * 4); +// std::vector quadVerticesByteRGBA; +// quadVerticesByteRGBA.reserve(numberOfRows * numberOfColumns * 4); + + std::unique_ptr quadsData4f + = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + std::unique_ptr quadsData4ub + = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { @@ -1445,68 +1456,76 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } if (m_identificationModeFlag) { - quadVerticesByteRGBA.push_back(idRGBA[0]); - quadVerticesByteRGBA.push_back(idRGBA[1]); - quadVerticesByteRGBA.push_back(idRGBA[2]); - quadVerticesByteRGBA.push_back(idRGBA[3]); +// quadVerticesByteRGBA.push_back(idRGBA[0]); +// quadVerticesByteRGBA.push_back(idRGBA[1]); +// quadVerticesByteRGBA.push_back(idRGBA[2]); +// quadVerticesByteRGBA.push_back(idRGBA[3]); + quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); } else { - quadVerticesFloatRGBA.push_back(rgba[0]); - quadVerticesFloatRGBA.push_back(rgba[1]); - quadVerticesFloatRGBA.push_back(rgba[2]); - quadVerticesFloatRGBA.push_back(rgba[3]); +// quadVerticesFloatRGBA.push_back(rgba[0]); +// quadVerticesFloatRGBA.push_back(rgba[1]); +// quadVerticesFloatRGBA.push_back(rgba[2]); +// quadVerticesFloatRGBA.push_back(rgba[3]); + quadsData4f->addVertex(cellX, cellY, 0.0, rgba); } - quadVerticesXYZ.push_back(cellX); - quadVerticesXYZ.push_back(cellY); - quadVerticesXYZ.push_back(0.0); +// quadVerticesXYZ.push_back(cellX); +// quadVerticesXYZ.push_back(cellY); +// quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { - quadVerticesByteRGBA.push_back(idRGBA[0]); - quadVerticesByteRGBA.push_back(idRGBA[1]); - quadVerticesByteRGBA.push_back(idRGBA[2]); - quadVerticesByteRGBA.push_back(idRGBA[3]); +// quadVerticesByteRGBA.push_back(idRGBA[0]); +// quadVerticesByteRGBA.push_back(idRGBA[1]); +// quadVerticesByteRGBA.push_back(idRGBA[2]); +// quadVerticesByteRGBA.push_back(idRGBA[3]); + quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); } else { - quadVerticesFloatRGBA.push_back(rgba[0]); - quadVerticesFloatRGBA.push_back(rgba[1]); - quadVerticesFloatRGBA.push_back(rgba[2]); - quadVerticesFloatRGBA.push_back(rgba[3]); +// quadVerticesFloatRGBA.push_back(rgba[0]); +// quadVerticesFloatRGBA.push_back(rgba[1]); +// quadVerticesFloatRGBA.push_back(rgba[2]); +// quadVerticesFloatRGBA.push_back(rgba[3]); + quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); } - quadVerticesXYZ.push_back(cellX + cellWidth); - quadVerticesXYZ.push_back(cellY); - quadVerticesXYZ.push_back(0.0); +// quadVerticesXYZ.push_back(cellX + cellWidth); +// quadVerticesXYZ.push_back(cellY); +// quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { - quadVerticesByteRGBA.push_back(idRGBA[0]); - quadVerticesByteRGBA.push_back(idRGBA[1]); - quadVerticesByteRGBA.push_back(idRGBA[2]); - quadVerticesByteRGBA.push_back(idRGBA[3]); +// quadVerticesByteRGBA.push_back(idRGBA[0]); +// quadVerticesByteRGBA.push_back(idRGBA[1]); +// quadVerticesByteRGBA.push_back(idRGBA[2]); +// quadVerticesByteRGBA.push_back(idRGBA[3]); + quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); } else { - quadVerticesFloatRGBA.push_back(rgba[0]); - quadVerticesFloatRGBA.push_back(rgba[1]); - quadVerticesFloatRGBA.push_back(rgba[2]); - quadVerticesFloatRGBA.push_back(rgba[3]); +// quadVerticesFloatRGBA.push_back(rgba[0]); +// quadVerticesFloatRGBA.push_back(rgba[1]); +// quadVerticesFloatRGBA.push_back(rgba[2]); +// quadVerticesFloatRGBA.push_back(rgba[3]); + quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); } - quadVerticesXYZ.push_back(cellX + cellWidth); - quadVerticesXYZ.push_back(cellY + cellHeight); - quadVerticesXYZ.push_back(0.0); +// quadVerticesXYZ.push_back(cellX + cellWidth); +// quadVerticesXYZ.push_back(cellY + cellHeight); +// quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { - quadVerticesByteRGBA.push_back(idRGBA[0]); - quadVerticesByteRGBA.push_back(idRGBA[1]); - quadVerticesByteRGBA.push_back(idRGBA[2]); - quadVerticesByteRGBA.push_back(idRGBA[3]); +// quadVerticesByteRGBA.push_back(idRGBA[0]); +// quadVerticesByteRGBA.push_back(idRGBA[1]); +// quadVerticesByteRGBA.push_back(idRGBA[2]); +// quadVerticesByteRGBA.push_back(idRGBA[3]); + quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); } else { - quadVerticesFloatRGBA.push_back(rgba[0]); - quadVerticesFloatRGBA.push_back(rgba[1]); - quadVerticesFloatRGBA.push_back(rgba[2]); - quadVerticesFloatRGBA.push_back(rgba[3]); +// quadVerticesFloatRGBA.push_back(rgba[0]); +// quadVerticesFloatRGBA.push_back(rgba[1]); +// quadVerticesFloatRGBA.push_back(rgba[2]); +// quadVerticesFloatRGBA.push_back(rgba[3]); + quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); } - quadVerticesXYZ.push_back(cellX); - quadVerticesXYZ.push_back(cellY + cellHeight); - quadVerticesXYZ.push_back(0.0); +// quadVerticesXYZ.push_back(cellX); +// quadVerticesXYZ.push_back(cellY + cellHeight); +// quadVerticesXYZ.push_back(0.0); } cellX += cellWidth; @@ -1515,24 +1534,30 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT cellY -= cellHeight; } - const float normalVector[3] = { 0.0, 0.0, 1.0 }; - std::vector quadVerticesNormals; - quadVerticesNormals.reserve(quadVerticesXYZ.size()); - const int32_t numberOfVertices = static_cast(quadVerticesXYZ.size() / 3); - for (int32_t iNormal = 0; iNormal < numberOfVertices; iNormal++) { - quadVerticesNormals.insert(quadVerticesNormals.end(), - normalVector, normalVector + 3); - } - CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); +// const float normalVector[3] = { 0.0, 0.0, 1.0 }; +// std::vector quadVerticesNormals; +// quadVerticesNormals.reserve(quadVerticesXYZ.size()); +// const int32_t numberOfVertices = static_cast(quadVerticesXYZ.size() / 3); +// for (int32_t iNormal = 0; iNormal < numberOfVertices; iNormal++) { +// quadVerticesNormals.insert(quadVerticesNormals.end(), +// normalVector, normalVector + 3); +// } +// CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); + + GraphicsEngineOpenGL* engineOpenGL = GraphicsFactory::get()->getGraphicsEngineOpenGL(); + CaretAssert(engineOpenGL); /* * Draw the matrix elements. */ if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesByteRGBA); +// CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); +// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, +// quadVerticesNormals, +// quadVerticesByteRGBA); + +// std::cout << "Quads: " << quadVerticesXYZ.size() << " Primitive: " << quadsData4ub->toString() << std::endl; + engineOpenGL->draw(quadsData4ub.get()); } else { /* @@ -1542,10 +1567,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesFloatRGBA); +// CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); +// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, +// quadVerticesNormals, +// quadVerticesFloatRGBA); +// std::cout << "Quads: " << quadVerticesXYZ.size() << " Primitive: " << quadsData4f->toString() << std::endl; + engineOpenGL->draw(quadsData4f.get()); + glDisable(GL_BLEND); @@ -1559,22 +1587,35 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, gridLineColorFloats); gridLineColorFloats[3] = 1.0; - std::vector outlineRGBA; - const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); - outlineRGBA.reserve(numberQuadVertices * 4); - for (int32_t i = 0; i < numberQuadVertices; i++) { - outlineRGBA.push_back(gridLineColorFloats[0]); - outlineRGBA.push_back(gridLineColorFloats[1]); - outlineRGBA.push_back(gridLineColorFloats[2]); - outlineRGBA.push_back(gridLineColorFloats[3]); - } - CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); +// std::vector outlineRGBA; + std::unique_ptr outlineData4f + = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); + const int32_t numCells = static_cast(gridXYZ.size() / 3); + for (int32_t i = 0; i < numCells; i++) { + CaretAssertVectorIndex(gridXYZ, i*3); + outlineData4f->addVertex(&gridXYZ[i*3], gridLineColorFloats); + } glPolygonMode(GL_FRONT, GL_LINE); glLineWidth(1.0); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - outlineRGBA); + engineOpenGL->draw(outlineData4f.get()); + +// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); +// outlineRGBA.reserve(numberQuadVertices * 4); +// for (int32_t i = 0; i < numberQuadVertices; i++) { +// outlineRGBA.push_back(gridLineColorFloats[0]); +// outlineRGBA.push_back(gridLineColorFloats[1]); +// outlineRGBA.push_back(gridLineColorFloats[2]); +// outlineRGBA.push_back(gridLineColorFloats[3]); +// } +// CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); +// +// glPolygonMode(GL_FRONT, GL_LINE); +// glLineWidth(1.0); +// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, +// quadVerticesNormals, +// outlineRGBA); } if ( (! selectedRowIndices.empty()) diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 3f8cca525..ed02b6c53 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -80,7 +80,6 @@ BrainStructureNodeAttributes.h BrowserTabContent.h CaretDataFileSelectionModel.h CaretMappableDataFileAndMapSelectionModel.h -CaretOpenGLInclude.h ChartTwoOverlay.h ChartTwoOverlaySet.h ChartTwoOverlaySetArray.h @@ -358,6 +357,7 @@ ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 1cd719d43..b1fa240f6 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -45,6 +45,7 @@ #include "EventModelDelete.h" #include "EventModelGetAll.h" #include "EventProgressUpdate.h" +#include "GraphicsFactory.h" #include "ImageCaptureSettings.h" #include "LogManager.h" #include "MapYokingGroupEnum.h" @@ -152,6 +153,11 @@ SessionManager::createSessionManager(const ApplicationTypeEnum::Enum application */ EventManager::createEventManager(); + /* + * Create the graphics factory. + */ + GraphicsFactory::createGraphicsFactory(); + /* * Create session manager. */ @@ -171,6 +177,8 @@ SessionManager::deleteSessionManager() delete s_singletonSessionManager; s_singletonSessionManager = NULL; + GraphicsFactory::deleteGraphicsFactory(); + /* * Session manager must be deleted before the event * manager is deleted. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0c5476249..6b5325a8f 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -459,6 +459,7 @@ ADD_SUBDIRECTORY ( OperationsBase ) ADD_SUBDIRECTORY ( Algorithms ) ADD_SUBDIRECTORY ( Operations ) ADD_SUBDIRECTORY ( Brain ) +ADD_SUBDIRECTORY ( Graphics ) IF (NOT Qwt_FOUND) ADD_SUBDIRECTORY ( Qwt ) ENDIF (NOT Qwt_FOUND) diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 49d6ee984..27d066694 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -49,6 +49,7 @@ using namespace caret; */ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum axisLocation) : CaretObject(), +SceneableInterface(), m_axisLocation(axisLocation) { /* @@ -100,6 +101,7 @@ ChartTwoCartesianAxis::~ChartTwoCartesianAxis() */ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj) : CaretObject(obj), +SceneableInterface(obj), m_axisLocation(obj.m_axisLocation) { this->copyHelperChartTwoCartesianAxis(obj); diff --git a/src/Charting/ChartTwoDataCartesianHistory.cxx b/src/Charting/ChartTwoDataCartesianHistory.cxx index 106cf95c2..b8f3eb1a8 100644 --- a/src/Charting/ChartTwoDataCartesianHistory.cxx +++ b/src/Charting/ChartTwoDataCartesianHistory.cxx @@ -43,7 +43,8 @@ using namespace caret; * Constructor. */ ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory() -: CaretObjectTracksModification() +: CaretObjectTracksModification(), +SceneableInterface() { initializeInstance(); } @@ -63,7 +64,8 @@ ChartTwoDataCartesianHistory::~ChartTwoDataCartesianHistory() * Object that is copied. */ ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj) -: CaretObjectTracksModification(obj) +: CaretObjectTracksModification(obj), +SceneableInterface(obj) { initializeInstance(); this->copyHelperChartTwoDataCartesianHistory(obj); diff --git a/src/Charting/ChartTwoMatrixDisplayProperties.cxx b/src/Charting/ChartTwoMatrixDisplayProperties.cxx index 5f3417a81..dc896c863 100644 --- a/src/Charting/ChartTwoMatrixDisplayProperties.cxx +++ b/src/Charting/ChartTwoMatrixDisplayProperties.cxx @@ -42,7 +42,9 @@ using namespace caret; * Constructor. */ ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties() -: CaretObject() +: CaretObject(), +EventListenerInterface(), +SceneableInterface() { initializeInstance(); } @@ -83,7 +85,9 @@ ChartTwoMatrixDisplayProperties::initializeInstance() * Object that is copied. */ ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj) -: CaretObject(obj) +: CaretObject(obj), +EventListenerInterface(), +SceneableInterface(obj) { initializeInstance(); @@ -138,7 +142,7 @@ ChartTwoMatrixDisplayProperties::toString() const * An event for which this instance is listening. */ void -ChartTwoMatrixDisplayProperties::receiveEvent(Event* event) +ChartTwoMatrixDisplayProperties::receiveEvent(Event* /*event*/) { } diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index 604751f38..75a7126ca 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -79,6 +79,7 @@ Operations Algorithms OperationsBase Brain +Graphics ${FTGL_LIBRARIES} Files Annotations diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 78f763f0f..f28af31be 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -125,6 +125,7 @@ OperationsBase ${Qwt_LIBRARIES} OSMesaDummy Brain +Graphics ${FTGL_LIBRARIES} Files Annotations @@ -196,6 +197,7 @@ ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Commands ${CMAKE_SOURCE_DIR}/GuiQt ${CMAKE_SOURCE_DIR}/Brain +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Palette diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt new file mode 100644 index 000000000..33b4d6f95 --- /dev/null +++ b/src/Graphics/CMakeLists.txt @@ -0,0 +1,60 @@ +# +# Name of Project +# +PROJECT (Graphics) + +# +# Need OpenGL +# +FIND_PACKAGE(OpenGL REQUIRED) +IF (OPENGL_FOUND) + # + # Need help finding includes on Apple + # + IF (APPLE) + # When searching for the include directory, find the location + # for the OpenGL framework rather than an individual header file. + FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework + /System/Library/Frameworks + /Library/Frameworks + ~/Library/Frameworks + ) + ENDIF (APPLE) + # + # OpenGL Include Directory + # + INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) +ELSE (OPENGL_FOUND) + MESSAGE(SEND_ERROR "OpenGL Libraries were not found") +ENDIF (OPENGL_FOUND) + +# +# Create a Library +# +ADD_LIBRARY(Graphics +CaretOpenGLInclude.h +GraphicsEngine.h +GraphicsEngineOpenGL.h +GraphicsFactory.h +GraphicsPrimitive.h +GraphicsPrimitiveV3fC4f.h +GraphicsPrimitiveV3fC4ub.h + +GraphicsEngine.cxx +GraphicsEngineOpenGL.cxx +GraphicsFactory.cxx +GraphicsPrimitive.cxx +GraphicsPrimitiveV3fC4f.cxx +GraphicsPrimitiveV3fC4ub.cxx +) + +# +# Find headers +# +INCLUDE_DIRECTORIES( +${CMAKE_SOURCE_DIR}/Common +${CMAKE_SOURCE_DIR}/Graphics +) + +TARGET_LINK_LIBRARIES(Graphics ${CARET_QT5_LINK}) + diff --git a/src/Brain/CaretOpenGLInclude.h b/src/Graphics/CaretOpenGLInclude.h similarity index 100% rename from src/Brain/CaretOpenGLInclude.h rename to src/Graphics/CaretOpenGLInclude.h diff --git a/src/Graphics/GraphicsEngine.cxx b/src/Graphics/GraphicsEngine.cxx new file mode 100644 index 000000000..d8523531d --- /dev/null +++ b/src/Graphics/GraphicsEngine.cxx @@ -0,0 +1,82 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_ENGINE_DECLARE__ +#include "GraphicsEngine.h" +#undef __GRAPHICS_ENGINE_DECLARE__ + +#include "CaretAssert.h" +#include "EventManager.h" +using namespace caret; + + + +/** + * \class caret::GraphicsEngine + * \brief Abstract class for rending graphics objects. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsEngine::GraphicsEngine() +: CaretObject() +{ + +// EventManager::get()->addEventListener(this, EventTypeEnum::); +} + +/** + * Destructor. + */ +GraphicsEngine::~GraphicsEngine() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsEngine::toString() const +{ + return "GraphicsEngine"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +GraphicsEngine::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + diff --git a/src/Graphics/GraphicsEngine.h b/src/Graphics/GraphicsEngine.h new file mode 100644 index 000000000..c4fd40e56 --- /dev/null +++ b/src/Graphics/GraphicsEngine.h @@ -0,0 +1,72 @@ +#ifndef __GRAPHICS_ENGINE_H__ +#define __GRAPHICS_ENGINE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "EventListenerInterface.h" + + +namespace caret { + + class GraphicsPrimitive; + + class GraphicsEngine : public CaretObject, public EventListenerInterface { + + public: + GraphicsEngine(); + + virtual ~GraphicsEngine(); + + /** + * Draw the given graphics primitive. + * + * @param primitive + * Primitive that is drawn. + */ + virtual void draw(GraphicsPrimitive* primitive) = 0; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + private: + GraphicsEngine(const GraphicsEngine&); + + GraphicsEngine& operator=(const GraphicsEngine&); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_ENGINE_DECLARE__ + // +#endif // __GRAPHICS_ENGINE_DECLARE__ + +} // namespace +#endif //__GRAPHICS_ENGINE_H__ diff --git a/src/Graphics/GraphicsEngineOpenGL.cxx b/src/Graphics/GraphicsEngineOpenGL.cxx new file mode 100644 index 000000000..34b946ad9 --- /dev/null +++ b/src/Graphics/GraphicsEngineOpenGL.cxx @@ -0,0 +1,229 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ +#include "GraphicsEngineOpenGL.h" +#undef __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ + +#include "CaretAssert.h" +#include "CaretOpenGLInclude.h" +#include "GraphicsPrimitive.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsEngineOpenGL + * \brief Render graphics objects using OpenGL. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsEngineOpenGL::GraphicsEngineOpenGL() +: GraphicsEngine() +{ + +} + +/** + * Destructor. + */ +GraphicsEngineOpenGL::~GraphicsEngineOpenGL() +{ +} + +/** + * Draw the given graphics primitive. + * + * @param primitive + * Primitive that is drawn. + */ +void +GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + if ( ! primitive->isValid()) { + return; + } + + GLenum coordinateDataType = GL_FLOAT; + GLint coordinatesPerVertex = 0; + GLuint vertexBufferID = 0; + GLsizei indicesCount = 0; + switch (primitive->m_vertexType) { + case GraphicsPrimitive::VertexType::FLOAT_XYZ: + coordinateDataType = GL_FLOAT; + coordinatesPerVertex = 3; // X, Y, Z + + indicesCount = primitive->m_xyz.size(); + const GLuint xyzSizeBytes = indicesCount * sizeof(float); + const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; + + glGenBuffers(1, &vertexBufferID); + glBindBuffer(GL_ARRAY_BUFFER, + vertexBufferID); + glBufferData(GL_ARRAY_BUFFER, + xyzSizeBytes, + xyzDataPointer, + GL_STREAM_DRAW); + break; + } + + GLenum normalVectorDataType = GL_FLOAT; + GLuint normalBufferID = 0; + switch (primitive->m_normalVectorType) { + case GraphicsPrimitive::NormalVectorType::NONE: + break; + case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: + { + normalVectorDataType = GL_FLOAT; + const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); + const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; + + glGenBuffers(1, &normalBufferID); + glBindBuffer(GL_ARRAY_BUFFER, + normalBufferID); + glBufferData(GL_ARRAY_BUFFER, + normalSizeBytes, + normalDataPointer, + GL_STREAM_DRAW); + } + break; + } + + GLenum colorDataType = GL_FLOAT; + GLint componentsPerColor = 0; + GLuint colorBufferID = 0; + glGenBuffers(1, &colorBufferID); + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + componentsPerColor = 4; + colorDataType = GL_FLOAT; + + const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + colorBufferID); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + componentsPerColor = 4; + colorDataType = GL_UNSIGNED_BYTE; + + const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); + const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + colorBufferID); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + } + break; + } + + /* + * Setup vertices for drawing + */ + glEnableClientState(GL_VERTEX_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, + vertexBufferID); + glVertexPointer(coordinatesPerVertex, + coordinateDataType, + 0, + (GLvoid*)0); + + /* + * Setup normals for drawing + */ + if (normalBufferID > 0) { + glEnableClientState(GL_NORMAL_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); + glNormalPointer(normalVectorDataType, 0, (GLvoid*)0); + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + + /* + * Setup colors for drawing + */ + glEnableClientState(GL_COLOR_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + + /* + * Unbind buffers + */ + glBindBuffer(GL_ARRAY_BUFFER, + 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + 0); + + /* + * Draw the primitive + */ + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::QUADS: + glDrawArrays(GL_QUADS, + 0, + indicesCount); + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLES: + glDrawArrays(GL_TRIANGLES, + 0, + indicesCount); + break; + } + + /* + * Disable drawing + */ + glDisableClientState(GL_VERTEX_ARRAY); + if (normalBufferID > 0) { + glDisableClientState(GL_NORMAL_ARRAY); + } + glDisableClientState(GL_COLOR_ARRAY); + + /* + * Delete buffers + */ + glDeleteBuffers(1, + &vertexBufferID); + if (normalBufferID > 0) { + glDeleteBuffers(1, + &normalBufferID); + } + glDeleteBuffers(1, + &colorBufferID); +} + diff --git a/src/Graphics/GraphicsEngineOpenGL.h b/src/Graphics/GraphicsEngineOpenGL.h new file mode 100644 index 000000000..f5cee58d8 --- /dev/null +++ b/src/Graphics/GraphicsEngineOpenGL.h @@ -0,0 +1,59 @@ +#ifndef __GRAPHICS_ENGINE_OPEN_G_L_H__ +#define __GRAPHICS_ENGINE_OPEN_G_L_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsEngine.h" + + + +namespace caret { + + class GraphicsEngineOpenGL : public GraphicsEngine { + + public: + GraphicsEngineOpenGL(); + + virtual ~GraphicsEngineOpenGL(); + + virtual void draw(GraphicsPrimitive* primitive); + + // ADD_NEW_METHODS_HERE + + private: + GraphicsEngineOpenGL(const GraphicsEngineOpenGL&); + + GraphicsEngineOpenGL& operator=(const GraphicsEngineOpenGL&); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ + // +#endif // __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ + +} // namespace +#endif //__GRAPHICS_ENGINE_OPEN_G_L_H__ diff --git a/src/Graphics/GraphicsFactory.cxx b/src/Graphics/GraphicsFactory.cxx new file mode 100644 index 000000000..1bf70a9f8 --- /dev/null +++ b/src/Graphics/GraphicsFactory.cxx @@ -0,0 +1,168 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_FACTORY_DECLARE__ +#include "GraphicsFactory.h" +#undef __GRAPHICS_FACTORY_DECLARE__ + +#include "CaretAssert.h" +#include "EventManager.h" +#include "GraphicsEngineOpenGL.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsFactory + * \brief Factory for creating/accessing graphics opertions. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsFactory::GraphicsFactory() +: CaretObject() +{ + m_graphicsEngineOpenGL = std::unique_ptr(new GraphicsEngineOpenGL()); + +// EventManager::get()->addEventListener(this, EventTypeEnum::); +} + +/** + * Destructor. + */ +GraphicsFactory::~GraphicsFactory() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Create the graphics factory. + * This should be called one time, not more, not less. + */ +void +GraphicsFactory::createGraphicsFactory() +{ + CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory == NULL), + "Graphics Factory has already been created."); + + GraphicsFactory::s_singletonGraphicsFactory = new GraphicsFactory(); +} + +/** + * Delete the graphics factory. + * + * This should be called one time after the graphics factory is created. + */ +void +GraphicsFactory::deleteGraphicsFactory() +{ + CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory != NULL), + "GraphicsFactory does not exist, cannot delete it."); + + delete GraphicsFactory::s_singletonGraphicsFactory; + GraphicsFactory::s_singletonGraphicsFactory= NULL; +} + +/** + * Get the one and only graphics factory + * + * @return Pointer to the graphics factory. + */ +GraphicsFactory* +GraphicsFactory::get() +{ + CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory != NULL), + "GraphicsFactory was not created or has been deleted.\n" + "It must be created with GraphicsFactory::createGraphicsFactory()."); + + return GraphicsFactory::s_singletonGraphicsFactory; +} + +/** + * @return The graphics engine for OpenGL. + */ +GraphicsEngineOpenGL* +GraphicsFactory::getGraphicsEngineOpenGL() +{ + CaretAssert(m_graphicsEngineOpenGL.get()); + return m_graphicsEngineOpenGL.get(); +} + +/** + * @return A new primitive for XYZ with float RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4f* +GraphicsFactory::newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType) +{ + GraphicsPrimitiveV3fC4f* primitive = new GraphicsPrimitiveV3fC4f(primitiveType); + return primitive; +} + +/** + * @return A new primitive for XYZ with unsigned byte RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4ub* +GraphicsFactory::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType) +{ + GraphicsPrimitiveV3fC4ub* primitive = new GraphicsPrimitiveV3fC4ub(primitiveType); + return primitive; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsFactory::toString() const +{ + return "GraphicsFactory"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +GraphicsFactory::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + diff --git a/src/Graphics/GraphicsFactory.h b/src/Graphics/GraphicsFactory.h new file mode 100644 index 000000000..d2eb98939 --- /dev/null +++ b/src/Graphics/GraphicsFactory.h @@ -0,0 +1,82 @@ +#ifndef __GRAPHICS_FACTORY_H__ +#define __GRAPHICS_FACTORY_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "EventListenerInterface.h" +#include "GraphicsPrimitive.h" + + +namespace caret { + class GraphicsEngineOpenGL; + class GraphicsPrimitiveV3fC4f; + class GraphicsPrimitiveV3fC4ub; + + class GraphicsFactory : public CaretObject, public EventListenerInterface { + + public: + GraphicsFactory(); + + virtual ~GraphicsFactory(); + + static void createGraphicsFactory(); + + static void deleteGraphicsFactory(); + + static GraphicsFactory* get(); + + GraphicsEngineOpenGL* getGraphicsEngineOpenGL(); + + GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); + + GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + private: + GraphicsFactory(const GraphicsFactory&); + + GraphicsFactory& operator=(const GraphicsFactory&); + + static GraphicsFactory* s_singletonGraphicsFactory; + + std::unique_ptr m_graphicsEngineOpenGL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_FACTORY_DECLARE__ + GraphicsFactory* GraphicsFactory::s_singletonGraphicsFactory = NULL; +#endif // __GRAPHICS_FACTORY_DECLARE__ + +} // namespace +#endif //__GRAPHICS_FACTORY_H__ diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx new file mode 100644 index 000000000..ddc08f667 --- /dev/null +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -0,0 +1,225 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_DECLARE__ +#include "GraphicsPrimitive.h" +#undef __GRAPHICS_PRIMITIVE_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventManager.h" +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitive + * \brief Abstract class for a graphics primitive. + * \ingroup Graphics + * + */ + +/** + * Constructs an instance with the given vertex, normal vector, and color type. + * + * @param vertexType + * Type of the vertices. + * @param normalVectorType + * Type of the normal vectors. + * @param colorType + * Type of the colors. + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitive::GraphicsPrimitive(const VertexType vertexType, + const NormalVectorType normalVectorType, + const ColorType colorType, + const PrimitiveType primitiveType) +: CaretObject(), + EventListenerInterface(), + m_vertexType(vertexType), + m_normalVectorType(normalVectorType), + m_colorType(colorType), + m_primitiveType(primitiveType) +{ + +} + +/** + * Destructor. + */ +GraphicsPrimitive::~GraphicsPrimitive() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Copy constructor for graphics primitive. + * @param obj + * Object that is copied. + */ +GraphicsPrimitive::GraphicsPrimitive(const GraphicsPrimitive& obj) +: CaretObject(obj), + EventListenerInterface(), + m_vertexType(obj.m_vertexType), + m_normalVectorType(obj.m_normalVectorType), + m_colorType(obj.m_colorType), +m_primitiveType(obj.m_primitiveType) +{ + this->copyHelperGraphicsPrimitive(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) +{ + m_xyz = obj.m_xyz; + m_floatRGBA = obj.m_floatRGBA; +} + +/** + * @return Is this graphics primitive valid. + * Primitive is valid if all of these conditions are met + * (A) ((count(xyz) * 3) == (count(rgba) * 4)) + * (B) (count(xyz) > 0) + * (C) ((count(xyz) == count(normals)) OR (count(normals) == 0) + */ +bool +GraphicsPrimitive::isValid() const +{ + switch (m_vertexType) { + case VertexType::FLOAT_XYZ: + break; + } + + const uint32_t numXYZ = m_xyz.size(); + if (numXYZ > 0) { + switch (m_normalVectorType) { + case NormalVectorType::NONE: + break; + case NormalVectorType::FLOAT_XYZ: + { + const uint32_t numNormalXYZ = m_floatNormalVectorXYZ.size(); + if (numNormalXYZ > 0) { + if (numNormalXYZ != numXYZ) { + CaretLogWarning("ERROR: GraphicsPrimitive XYZ size not matching surface normal size."); + return false; + } + } + } + break; + } + + uint32_t numColorRGBA = 0; + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + numColorRGBA = m_floatRGBA.size(); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + numColorRGBA = m_unsignedByteRGBA.size(); + break; + } + if ((numXYZ / 3) != (numColorRGBA / 4)) { + CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match RGBA size"); + return false; + } + + switch (m_primitiveType) { + case PrimitiveType::QUADS: + { + const uint32_t extraVertices = numXYZ % 4; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing quads ignored."); + } + } + break; + case PrimitiveType::TRIANGLES: + { + const uint32_t extraVertices = numXYZ % 3; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing triangles ignored."); + } + } + break; + } + return true; + } + + return false; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsPrimitive::toString() const +{ + AString s; + + switch (m_vertexType) { + case VertexType::FLOAT_XYZ: + s.append("Vertex: " + AString::number(m_xyz.size()) + " Float XYZ. "); + break; + } + + switch (m_normalVectorType) { + case NormalVectorType::FLOAT_XYZ: + s.append("Normal Vector: " + AString::number(m_floatNormalVectorXYZ.size()) + " Float XYZ. "); + break; + case NormalVectorType::NONE: + s.append("Normal Vector: None. "); + break; + } + + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + s.append("Color: " + AString::number(m_floatRGBA.size()) + " Float RGBA 0.0 to 1.0. "); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + s.append("Color: " + AString::number(m_unsignedByteRGBA.size()) + " Unsigned Byte RGBA 0 to 255"); + break; + } + + return s; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +GraphicsPrimitive::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h new file mode 100644 index 000000000..94114a51e --- /dev/null +++ b/src/Graphics/GraphicsPrimitive.h @@ -0,0 +1,149 @@ +#ifndef __GRAPHICS_PRIMITIVE_H__ +#define __GRAPHICS_PRIMITIVE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "EventListenerInterface.h" + + +namespace caret { + + class GraphicsPrimitive : public CaretObject, public EventListenerInterface { + + public: + /** + * Type of vertices + */ + enum class VertexType { + /** Vertices are three float values per vertex containing X, Y, Z */ + FLOAT_XYZ + }; + + /** + * Type of normal vectors + */ + enum class NormalVectorType { + /** No normal vectors */ + NONE, + /** Normal vectors are three float values per vertex contain X, Y, Z ranging 0.0 to 1.0 */ + FLOAT_XYZ + }; + + /** + * Type of colors + */ + enum class ColorType { + /** Four float values per vertex containing Red, Green, Blue, Alpha ranging 0.0 to 1.0 */ + FLOAT_RGBA, + /** Four unsigned byte values per vertex containing Red, Green, Blue, Alpha ranging 0 to 255 */ + UNSIGNED_BYTE_RGBA + }; + + enum class PrimitiveType { + /** Quads - Four vertices form one quad */ + QUADS, + /** Triangles - Three vertices form one triangle */ + TRIANGLES + }; + + protected: + GraphicsPrimitive(const VertexType vertexType, + const NormalVectorType normalVectorType, + const ColorType colorType, + const PrimitiveType primitiveType); + + GraphicsPrimitive(const GraphicsPrimitive& obj); + + private: + GraphicsPrimitive& operator=(const GraphicsPrimitive& obj); + + public: + virtual ~GraphicsPrimitive(); + + virtual void receiveEvent(Event* event); + + bool isValid() const; + + /** + * @return Type of the vertices. + */ + inline VertexType getVertexType() const { return m_vertexType; } + + /** + * @return Type of the normal vectors. + */ + inline NormalVectorType getNormalVectorType () const { return m_normalVectorType; } + + /** + * @return Type of the colors. + */ + inline ColorType getColorType() const { return m_colorType; } + + /** + * @return The float coordinates. + */ + const std::vector& getFloatXYZ() const { return m_xyz; } + + virtual AString toString() const; + + /** + * Clone this primitive. + */ + virtual GraphicsPrimitive* clone() const = 0; + + protected: + const VertexType m_vertexType; + + const NormalVectorType m_normalVectorType; + + const ColorType m_colorType; + + const PrimitiveType m_primitiveType; + + std::vector m_xyz; + + std::vector m_floatNormalVectorXYZ; + + std::vector m_floatRGBA; + + std::vector m_unsignedByteRGBA; + + private: + void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); + + friend class GraphicsEngineOpenGL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_H__ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx new file mode 100644 index 000000000..85d2b215d --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -0,0 +1,133 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ +#include "GraphicsPrimitiveV3fC4f.h" +#undef __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveV3fC4f + * \brief Primitive containing XYZ and Float RGBA. + * \ingroup Graphics + */ + +/** + * Constructor. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveType) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::NONE, + ColorType::FLOAT_RGBA, + primitiveType) +{ + +} + +/** + * Destructor. + */ +GraphicsPrimitiveV3fC4f::~GraphicsPrimitiveV3fC4f() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj) +: GraphicsPrimitive(obj) +{ + this->copyHelperGraphicsPrimitiveV3fC4f(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitiveV3fC4f::copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj) +{ + +} + +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3fC4f::addVertex(const float xyz[3], + const float rgba[4]) +{ + m_xyz.insert(m_xyz.end(), + xyz, xyz + 3); + m_floatRGBA.insert(m_floatRGBA.end(), + rgba, rgba + 4); +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3fC4f::addVertex(const float x, + const float y, + const float z, + const float rgba[4]) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(z); + m_floatRGBA.insert(m_floatRGBA.end(), + rgba, rgba + 4); +} + +/** + * Clone this primitive. + */ +GraphicsPrimitive* +GraphicsPrimitiveV3fC4f::clone() const +{ + GraphicsPrimitiveV3fC4f* obj = new GraphicsPrimitiveV3fC4f(*this); + return obj; +} + diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.h b/src/Graphics/GraphicsPrimitiveV3fC4f.h new file mode 100644 index 000000000..fbe17191b --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.h @@ -0,0 +1,69 @@ +#ifndef __GRAPHICS_PRIMITIVE_V3F_C4F_H__ +#define __GRAPHICS_PRIMITIVE_V3F_C4F_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsPrimitive.h" + + + +namespace caret { + + class GraphicsPrimitiveV3fC4f : public GraphicsPrimitive { + + public: + GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveType); + + virtual ~GraphicsPrimitiveV3fC4f(); + + GraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj); + + void addVertex(const float xyz[3], + const float rgba[4]); + + void addVertex(const float x, + const float y, + const float z, + const float rgba[4]); + + virtual GraphicsPrimitive* clone() const; + + // ADD_NEW_METHODS_HERE + + private: + GraphicsPrimitiveV3fC4f& operator=(const GraphicsPrimitiveV3fC4f& obj); + + void copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_V3F_C4F_H__ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx new file mode 100644 index 000000000..0c7576c0b --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -0,0 +1,133 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ +#include "GraphicsPrimitiveV3fC4ub.h" +#undef __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveV3fC4ub + * \brief Primitive containing XYZ and Float RGBA. + * \ingroup Graphics + */ + +/** + * Constructor. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const PrimitiveType primitiveType) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::NONE, + ColorType::UNSIGNED_BYTE_RGBA, + primitiveType) +{ + +} + +/** + * Destructor. + */ +GraphicsPrimitiveV3fC4ub::~GraphicsPrimitiveV3fC4ub() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj) +: GraphicsPrimitive(obj) +{ + this->copyHelperGraphicsPrimitiveV3fC4ub(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitiveV3fC4ub::copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj) +{ + +} + +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3fC4ub::addVertex(const float xyz[3], + const uint8_t rgba[4]) +{ + m_xyz.insert(m_xyz.end(), + xyz, xyz + 3); + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + rgba, rgba + 4); +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3fC4ub::addVertex(const float x, + const float y, + const float z, + const uint8_t rgba[4]) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(z); + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + rgba, rgba + 4); +} + +/** + * Clone this primitive. + */ +GraphicsPrimitive* +GraphicsPrimitiveV3fC4ub::clone() const +{ + GraphicsPrimitiveV3fC4ub* obj = new GraphicsPrimitiveV3fC4ub(*this); + return obj; +} + diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.h b/src/Graphics/GraphicsPrimitiveV3fC4ub.h new file mode 100644 index 000000000..b17781e6d --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.h @@ -0,0 +1,67 @@ +#ifndef __GRAPHICS_PRIMITIVE_V3F_C4UB_H__ +#define __GRAPHICS_PRIMITIVE_V3F_C4UB_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsPrimitive.h" + +namespace caret { + + class GraphicsPrimitiveV3fC4ub : public GraphicsPrimitive { + + public: + GraphicsPrimitiveV3fC4ub(const PrimitiveType primitiveType); + + virtual ~GraphicsPrimitiveV3fC4ub(); + + GraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj); + + void addVertex(const float xyz[3], + const uint8_t rgba[4]); + + void addVertex(const float x, + const float y, + const float z, + const uint8_t rgba[4]); + + virtual GraphicsPrimitive* clone() const; + + // ADD_NEW_METHODS_HERE + + private: + GraphicsPrimitiveV3fC4ub& operator=(const GraphicsPrimitiveV3fC4ub& obj); + + void copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_V3F_C4UB_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 88d791566..1102bcdd7 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -669,6 +669,7 @@ ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Gifti +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/OSMesaDummy ${CMAKE_SOURCE_DIR}/Operations diff --git a/src/OSMesaDummy/CMakeLists.txt b/src/OSMesaDummy/CMakeLists.txt index fdfeddb75..96ec58391 100644 --- a/src/OSMesaDummy/CMakeLists.txt +++ b/src/OSMesaDummy/CMakeLists.txt @@ -25,6 +25,6 @@ TARGET_LINK_LIBRARIES(OSMesaDummy ${CARET_QT5_LINK}) # Include directories # INCLUDE_DIRECTORIES( -${CMAKE_SOURCE_DIR}/Brain +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/OSMesaDummy ) diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt index e59d0c796..e70d576ad 100644 --- a/src/Operations/CMakeLists.txt +++ b/src/Operations/CMakeLists.txt @@ -214,6 +214,7 @@ ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Nifti ${QUAZIP_INCLUDE_DIRS} diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index 7aa8b45ff..ef1033c25 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -103,6 +103,7 @@ Algorithms OperationsBase GuiQt Brain +Graphics Files Annotations Cifti -- GitLab From 1ba8c3180849e802bc506d1aedf0f75716293749 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 13 Apr 2017 15:47:44 -0500 Subject: [PATCH 250/755] Continuing development of new OpenGL primitive drawing. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 651 ++---------------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 + src/Brain/BrainOpenGLFixedPipeline.cxx | 17 + src/Brain/BrainOpenGLFixedPipeline.h | 6 +- src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 +- src/Common/EventTypeEnum.h | 2 + src/Graphics/CMakeLists.txt | 8 + ...EventGraphicsEngineOpenGLDeleteBuffers.cxx | 78 +++ .../EventGraphicsEngineOpenGLDeleteBuffers.h | 64 ++ src/Graphics/GraphicsEngineData.cxx | 82 +++ src/Graphics/GraphicsEngineData.h | 63 ++ src/Graphics/GraphicsEngineDataOpenGL.cxx | 179 +++++ src/Graphics/GraphicsEngineDataOpenGL.h | 83 +++ src/Graphics/GraphicsEngineOpenGL.cxx | 313 ++++++--- src/Graphics/GraphicsEngineOpenGL.h | 14 +- src/Graphics/GraphicsFactory.cxx | 33 + src/Graphics/GraphicsFactory.h | 7 + src/Graphics/GraphicsPrimitive.cxx | 214 +++++- src/Graphics/GraphicsPrimitive.h | 78 ++- src/Graphics/GraphicsPrimitiveV3f.cxx | 203 ++++++ src/Graphics/GraphicsPrimitiveV3f.h | 78 +++ src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 22 + src/Graphics/GraphicsPrimitiveV3fC4f.h | 4 + 24 files changed, 1486 insertions(+), 723 deletions(-) create mode 100644 src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx create mode 100644 src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h create mode 100644 src/Graphics/GraphicsEngineData.cxx create mode 100644 src/Graphics/GraphicsEngineData.h create mode 100644 src/Graphics/GraphicsEngineDataOpenGL.cxx create mode 100644 src/Graphics/GraphicsEngineDataOpenGL.h create mode 100644 src/Graphics/GraphicsPrimitiveV3f.cxx create mode 100644 src/Graphics/GraphicsPrimitiveV3f.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index d0650095b..6c3fb07a7 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -47,6 +47,7 @@ #include "FastStatistics.h" #include "GraphicsEngineOpenGL.h" #include "GraphicsFactory.h" +#include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "HistogramDrawingInfo.h" @@ -77,6 +78,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline : BrainOpenGLChartTwoDrawingInterface() { m_preferences = SessionManager::get()->getCaretPreferences(); + m_graphicsFactory = GraphicsFactory::get(); + CaretAssert(m_graphicsFactory); + m_graphicsOpenGL = m_graphicsFactory->getGraphicsEngineOpenGL(); + CaretAssert(m_graphicsOpenGL); } /** @@ -565,67 +570,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() } } } - -// for (auto& drawInfo : drawingInfo) { -// if (drawInfo->m_histogramDrawingInfo->isValid()) { -// -// bool leftVerticalAxisFlag = true; -// switch (drawInfo->m_verticalAxisLocation) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// leftVerticalAxisFlag = false; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// break; -// } -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// if (leftVerticalAxisFlag) { -// glOrtho(xMin, xMax, -// yMinLeft, yMaxLeft, -// -10.0, 10.0); -// } -// else { -// glOrtho(xMin, xMax, -// yMinRight, yMaxRight, -// -10.0, 10.0); -// } -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool applyTransformationsFlag = false; -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = chartGraphicsDrawingViewport[2]; -// const float chartHeight = chartGraphicsDrawingViewport[3]; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// drawHistogramChartContent(drawInfo->m_histogramChart, -// drawInfo->m_mapIndex, -// *drawInfo->m_histogramDrawingInfo, -// true, -// true); -// } -// } } } @@ -708,8 +652,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr std::vector quadVerticesByteRGBA; -// const CaretMappableDataFile* cmdf = histogramChart->getCaretMappableDataFile(); -// CaretAssert(cmdf); if (drawHistogramBarsFlag) { /* * Reserve to prevent reszing of vectors @@ -1344,24 +1286,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT uint8_t highlightRGBByte[3]; m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); - const float highlightRGB[3] = { + const float highlightRGBA[4] = { highlightRGBByte[0] / 255.0, highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0 + highlightRGBByte[2] / 255.0, + 1.0 }; int32_t rgbaOffset = 0; -// std::vector quadVerticesXYZ; -// quadVerticesXYZ.reserve(numberOfRows * numberOfColumns * 3); -// std::vector quadVerticesFloatRGBA; -// quadVerticesFloatRGBA.reserve(numberOfRows * numberOfColumns * 4); -// std::vector quadVerticesByteRGBA; -// quadVerticesByteRGBA.reserve(numberOfRows * numberOfColumns * 4); std::unique_ptr quadsData4f - = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); std::unique_ptr quadsData4ub - = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { @@ -1456,76 +1393,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } if (m_identificationModeFlag) { -// quadVerticesByteRGBA.push_back(idRGBA[0]); -// quadVerticesByteRGBA.push_back(idRGBA[1]); -// quadVerticesByteRGBA.push_back(idRGBA[2]); -// quadVerticesByteRGBA.push_back(idRGBA[3]); quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); - } - else { -// quadVerticesFloatRGBA.push_back(rgba[0]); -// quadVerticesFloatRGBA.push_back(rgba[1]); -// quadVerticesFloatRGBA.push_back(rgba[2]); -// quadVerticesFloatRGBA.push_back(rgba[3]); - quadsData4f->addVertex(cellX, cellY, 0.0, rgba); - } -// quadVerticesXYZ.push_back(cellX); -// quadVerticesXYZ.push_back(cellY); -// quadVerticesXYZ.push_back(0.0); - - if (m_identificationModeFlag) { -// quadVerticesByteRGBA.push_back(idRGBA[0]); -// quadVerticesByteRGBA.push_back(idRGBA[1]); -// quadVerticesByteRGBA.push_back(idRGBA[2]); -// quadVerticesByteRGBA.push_back(idRGBA[3]); quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); - } - else { -// quadVerticesFloatRGBA.push_back(rgba[0]); -// quadVerticesFloatRGBA.push_back(rgba[1]); -// quadVerticesFloatRGBA.push_back(rgba[2]); -// quadVerticesFloatRGBA.push_back(rgba[3]); - quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); - } -// quadVerticesXYZ.push_back(cellX + cellWidth); -// quadVerticesXYZ.push_back(cellY); -// quadVerticesXYZ.push_back(0.0); - - if (m_identificationModeFlag) { -// quadVerticesByteRGBA.push_back(idRGBA[0]); -// quadVerticesByteRGBA.push_back(idRGBA[1]); -// quadVerticesByteRGBA.push_back(idRGBA[2]); -// quadVerticesByteRGBA.push_back(idRGBA[3]); quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); - } - else { -// quadVerticesFloatRGBA.push_back(rgba[0]); -// quadVerticesFloatRGBA.push_back(rgba[1]); -// quadVerticesFloatRGBA.push_back(rgba[2]); -// quadVerticesFloatRGBA.push_back(rgba[3]); - quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); - } -// quadVerticesXYZ.push_back(cellX + cellWidth); -// quadVerticesXYZ.push_back(cellY + cellHeight); -// quadVerticesXYZ.push_back(0.0); - - if (m_identificationModeFlag) { -// quadVerticesByteRGBA.push_back(idRGBA[0]); -// quadVerticesByteRGBA.push_back(idRGBA[1]); -// quadVerticesByteRGBA.push_back(idRGBA[2]); -// quadVerticesByteRGBA.push_back(idRGBA[3]); quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); } else { -// quadVerticesFloatRGBA.push_back(rgba[0]); -// quadVerticesFloatRGBA.push_back(rgba[1]); -// quadVerticesFloatRGBA.push_back(rgba[2]); -// quadVerticesFloatRGBA.push_back(rgba[3]); + quadsData4f->addVertex(cellX, cellY, 0.0, rgba); + quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); + quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); } -// quadVerticesXYZ.push_back(cellX); -// quadVerticesXYZ.push_back(cellY + cellHeight); -// quadVerticesXYZ.push_back(0.0); } cellX += cellWidth; @@ -1534,30 +1412,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT cellY -= cellHeight; } -// const float normalVector[3] = { 0.0, 0.0, 1.0 }; -// std::vector quadVerticesNormals; -// quadVerticesNormals.reserve(quadVerticesXYZ.size()); -// const int32_t numberOfVertices = static_cast(quadVerticesXYZ.size() / 3); -// for (int32_t iNormal = 0; iNormal < numberOfVertices; iNormal++) { -// quadVerticesNormals.insert(quadVerticesNormals.end(), -// normalVector, normalVector + 3); -// } -// CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); - - GraphicsEngineOpenGL* engineOpenGL = GraphicsFactory::get()->getGraphicsEngineOpenGL(); - CaretAssert(engineOpenGL); - /* * Draw the matrix elements. */ if (m_identificationModeFlag) { -// CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); -// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, -// quadVerticesNormals, -// quadVerticesByteRGBA); - -// std::cout << "Quads: " << quadVerticesXYZ.size() << " Primitive: " << quadsData4ub->toString() << std::endl; - engineOpenGL->draw(quadsData4ub.get()); + m_graphicsOpenGL->draw(quadsData4ub.get()); } else { /* @@ -1567,12 +1426,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -// CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); -// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, -// quadVerticesNormals, -// quadVerticesFloatRGBA); -// std::cout << "Quads: " << quadVerticesXYZ.size() << " Primitive: " << quadsData4f->toString() << std::endl; - engineOpenGL->draw(quadsData4f.get()); + m_graphicsOpenGL->draw(quadsData4f.get()); glDisable(GL_BLEND); @@ -1581,41 +1435,26 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT * Drawn an outline around the matrix elements. */ if (displayGridLinesFlag) { - uint8_t gridLineColorBytes[3]; + uint8_t gridLineColorBytes[4]; m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); float gridLineColorFloats[4]; CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, gridLineColorFloats); gridLineColorFloats[3] = 1.0; -// std::vector outlineRGBA; - std::unique_ptr outlineData4f - = std::unique_ptr(GraphicsFactory::get()->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + std::unique_ptr outlineData4f + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, + gridLineColorFloats)); const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); const int32_t numCells = static_cast(gridXYZ.size() / 3); for (int32_t i = 0; i < numCells; i++) { CaretAssertVectorIndex(gridXYZ, i*3); - outlineData4f->addVertex(&gridXYZ[i*3], gridLineColorFloats); + outlineData4f->addVertex(&gridXYZ[i*3]); } glPolygonMode(GL_FRONT, GL_LINE); glLineWidth(1.0); - engineOpenGL->draw(outlineData4f.get()); - -// const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); -// outlineRGBA.reserve(numberQuadVertices * 4); -// for (int32_t i = 0; i < numberQuadVertices; i++) { -// outlineRGBA.push_back(gridLineColorFloats[0]); -// outlineRGBA.push_back(gridLineColorFloats[1]); -// outlineRGBA.push_back(gridLineColorFloats[2]); -// outlineRGBA.push_back(gridLineColorFloats[3]); -// } -// CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); -// -// glPolygonMode(GL_FRONT, GL_LINE); -// glLineWidth(1.0); -// BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, -// quadVerticesNormals, -// outlineRGBA); + m_graphicsOpenGL->draw(outlineData4f.get()); + glPolygonMode(GL_FRONT, GL_FILL); } if ( (! selectedRowIndices.empty()) @@ -1640,32 +1479,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float minX = minColumn * cellWidth; const float maxX = maxColumn * cellWidth; - std::vector rowXYZ; - rowXYZ.reserve(12); - rowXYZ.push_back(minX); - rowXYZ.push_back(rowY); - rowXYZ.push_back(0.0); - - rowXYZ.push_back(minX); - rowXYZ.push_back(rowY + cellHeight); - rowXYZ.push_back(0.0); - - rowXYZ.push_back(maxX); - rowXYZ.push_back(rowY + cellHeight); - rowXYZ.push_back(0.0); - - rowXYZ.push_back(maxX); - rowXYZ.push_back(rowY); - rowXYZ.push_back(0.0); - - /* - * As cells get larger, increase linewidth for selected row - */ + std::unique_ptr rowOutlineData4f + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + + rowOutlineData4f->addVertex(minX, rowY); + rowOutlineData4f->addVertex(maxX, rowY); + rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); + rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - const float rgba[4] = { highlightRGB[0], highlightRGB[1], highlightRGB[2], 1.0f }; - BrainOpenGLPrimitiveDrawing::drawLineLoop(rowXYZ, - rgba, - highlightLineWidth); + glLineWidth(highlightLineWidth); + m_graphicsOpenGL->draw(rowOutlineData4f.get()); } glLineWidth(1.0); @@ -1693,33 +1517,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float minY = minRow * cellHeight; const float maxY = maxRow * cellHeight; + std::unique_ptr columnOutlineData4f + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); - std::vector columnXYZ; - columnXYZ.reserve(12); - columnXYZ.push_back(colX); - columnXYZ.push_back(minY); - columnXYZ.push_back(0.0); - - columnXYZ.push_back(colX + cellWidth); - columnXYZ.push_back(minY); - columnXYZ.push_back(0.0); - - columnXYZ.push_back(colX + cellWidth); - columnXYZ.push_back(maxY); - columnXYZ.push_back(0.0); - - columnXYZ.push_back(colX); - columnXYZ.push_back(maxY); - columnXYZ.push_back(0.0); - - /* - * As cells get larger, increase linewidth for selected row - */ + columnOutlineData4f->addVertex(colX, minY); + columnOutlineData4f->addVertex(colX + cellWidth, minY); + columnOutlineData4f->addVertex(colX + cellWidth, maxY); + columnOutlineData4f->addVertex(colX, maxY); const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - const float rgba[4] = { highlightRGB[0], highlightRGB[1], highlightRGB[2], 1.0f }; - BrainOpenGLPrimitiveDrawing::drawLineLoop(columnXYZ, - rgba, - highlightLineWidth); + glLineWidth(highlightLineWidth); + m_graphicsOpenGL->draw(columnOutlineData4f.get()); } glLineWidth(1.0); } @@ -2191,29 +1999,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + std::unique_ptr gridData + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + + gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); + gridData->addVertex(gridRight - halfGridLineWidth, gridTop); + gridData->addVertex(gridRight, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); + gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); glLineWidth(GRID_LINE_WIDTH); - - glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); - - glBegin(GL_LINES); - - /* bottom line */ - glVertex3f(gridLeft, gridBottom + halfGridLineWidth, 0.0); - glVertex3f(gridRight, gridBottom + halfGridLineWidth, 0.0); - - /* right line */ - glVertex3f(gridRight - halfGridLineWidth, gridBottom, 0.0); - glVertex3f(gridRight - halfGridLineWidth, gridTop, 0.0); - - /* top line */ - glVertex3f(gridRight, gridTop - halfGridLineWidth, 0.0); - glVertex3f(gridLeft, gridTop - halfGridLineWidth, 0.0); - - /* left line */ - glVertex3f(gridLeft + halfGridLineWidth, gridTop, 0.0); - glVertex3f(gridLeft + halfGridLineWidth, gridBottom, 0.0); - - glEnd(); + m_graphicsOpenGL->draw(gridData.get()); /* * Region inside the grid's box @@ -2231,330 +2030,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons chartGraphicsDrawingViewportOut[3] = graphicsHeight; } -///** -// * Draw the chart axes grid/box -// * -// * @param vpX -// * Viewport X for all chart content -// * @param vpY -// * Viewport Y for all chart content -// * @param vpWidth -// * Viewport width for all chart content -// * @param vpHeight -// * Viewport height for all chart content -// * @param margins -// * Margin around graphics region. The margin corresponding to the -// * axis may be changed so that all text in the axis is visible -// * (and not cut off). -// * @param axis -// * Axis that is drawn. -// * @param axisMinimumOut -// * Minimum value along the axis. -// * @param axisMaximumOut -// * Maximum value along the axis. -// * @return -// * True if the axis is valid and was drawn, else false. -// */ -//bool -//BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], -// const float vpX, -// const float vpY, -// const float vpWidth, -// const float vpHeight, -// const Margins& margins, -// ChartTwoCartesianAxis* axis, -// float& axisMinimumOut, -// float& axisMaximumOut) -//{ -// if (axis == NULL) { -// return false; -// } -// if ( ! axis->isVisible()) { -// return false; -// } -// -// float axisLength = 0.0; -// -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// axisLength = vpWidth - (margins.m_left + margins.m_right); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// axisLength = vpHeight - (margins.m_top + margins.m_bottom); -// break; -// } -// -// std::vector labelOffsetInPixels; -// std::vector labelTexts; -// const bool validAxisFlag = axis->getLabelsAndPositions(dataBounds, -// axisLength, -// axisMinimumOut, -// axisMaximumOut, -// labelOffsetInPixels, -// labelTexts); -// if ( ! validAxisFlag) { -// return false; -// } -// -// const float rgba[4] = { -// m_fixedPipelineDrawing->m_foregroundColorFloat[0], -// m_fixedPipelineDrawing->m_foregroundColorFloat[1], -// m_fixedPipelineDrawing->m_foregroundColorFloat[2], -// 1.0 -// }; -// -// const int32_t numLabelsToDraw = static_cast(labelTexts.size()); -// AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); -// annotationText.setCustomTextColor(rgba); -// annotationText.setTextColor(CaretColorEnum::CUSTOM); -// -// if (numLabelsToDraw > 0) { -// float labelX = 0.0; -// float labelY = 0.0; -// float labelOffsetMultiplierX = 0.0; -// float labelOffsetMultiplierY = 0.0; -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// -// /* -// * Viewport for axis name and numeric values -// */ -// int32_t axisVpX = vpX; -// int32_t axisVpY = vpY; -// int32_t axisVpWidth = vpWidth; -// int32_t axisVpHeight = vpHeight; -// -// float tickDeltaXY[2] = { 0.0, 0.0 }; -// const float tickLength = 5.0; -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// axisVpX = vpX; -// axisVpY = vpY; -// axisVpWidth = vpWidth; -// axisVpHeight = margins.m_bottom; -// labelX = margins.m_left; -// labelY = margins.m_bottom; -// labelOffsetMultiplierX = 1.0; -// labelOffsetMultiplierY = 0.0; -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// tickDeltaXY[0] = 0.0; -// tickDeltaXY[1] = -tickLength; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// axisVpX = vpX; -// axisVpY = vpY + vpHeight - margins.m_top; -// axisVpWidth = vpWidth; -// axisVpHeight = margins.m_top; -// labelX = margins.m_left; -// labelY = 0.0; -// labelOffsetMultiplierX = 1.0; -// labelOffsetMultiplierY = 0.0; -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// tickDeltaXY[0] = 0.0; -// tickDeltaXY[1] = tickLength; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// axisVpX = vpX; -// axisVpY = vpY; -// axisVpWidth = margins.m_left; -// axisVpHeight = vpHeight; -// labelX = margins.m_left; -// labelY = margins.m_bottom; -// labelOffsetMultiplierX = 0.0; -// labelOffsetMultiplierY = 1.0; -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// tickDeltaXY[0] = -tickLength; -// tickDeltaXY[1] = 0.0; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// axisVpX = vpX + vpWidth - margins.m_right; -// axisVpY = vpY; -// axisVpWidth = margins.m_right; -// axisVpHeight = vpHeight; -// labelX = 0.0; -// labelY = margins.m_bottom; -// labelOffsetMultiplierX = 0.0; -// labelOffsetMultiplierY = 1.0; -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// tickDeltaXY[0] = tickLength; -// tickDeltaXY[1] = 0.0; -// break; -// } -// -// /* -// * Viewport for axis text and numeric values -// */ -// const int viewport[4] = { -// axisVpX, -// axisVpY, -// axisVpWidth, -// axisVpHeight -// }; -// glViewport(viewport[0], -// viewport[1], -// viewport[2], -// viewport[3]); -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// glOrtho(0, axisVpWidth, 0, axisVpHeight, -1.0, 1.0); -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); -// -// const bool showTicksFlag = axis->isShowTickmarks(); -// -// const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; -// const int32_t firstIndex = 0; -// const int32_t lastIndex = numLabelsToDraw - 1; -// for (int32_t i = 0; i < numLabelsToDraw; i++) { -// float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; -// float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; -// float textOffsetX = 0.0; -// float textOffsetY = 0.0; -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// if (i == firstIndex) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// tickStartX += halfGridLineWidth; -// } -// else if (i == lastIndex) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// tickStartX -= halfGridLineWidth; -// } -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// tickStartX -= halfGridLineWidth; -// if (i == firstIndex) { -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// tickStartY += halfGridLineWidth; -// } -// else if (i == lastIndex) { -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// tickStartY -= halfGridLineWidth; -// } -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// tickStartX += halfGridLineWidth; -// if (i == firstIndex) { -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// tickStartY += halfGridLineWidth; -// } -// else if (i == lastIndex) { -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// tickStartY -= halfGridLineWidth; -// } -// textOffsetX = -2.0; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// if (i == firstIndex) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// tickStartX += halfGridLineWidth; -// } -// else if (i == lastIndex) { -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// tickStartX -= halfGridLineWidth; -// } -// textOffsetY = -2.0; -// break; -// } -// const float tickEndX = tickStartX + tickDeltaXY[0]; -// const float tickEndY = tickStartY + tickDeltaXY[1]; -// -// if (showTicksFlag) { -// glLineWidth(GRID_LINE_WIDTH); -// glBegin(GL_LINES); -// glVertex2f(tickStartX, -// tickStartY); -// glVertex2f(tickEndX, -// tickEndY); -// glEnd(); -// } -// -// const float textX = tickEndX + textOffsetX; -// const float textY = tickEndY + textOffsetY; -// annotationText.setText(labelTexts[i]); -// m_textRenderer->drawTextAtViewportCoords(textX, -// textY, -// 0.0, -// annotationText); -// } -// -// const AString axisText = axis->getLabelText(); -// if ( ! axisText.isEmpty()) { -// //AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -// -// bool drawAxisTextVerticalFlag = false; -// float axisTextCenterX = axisVpWidth / 2.0; -// float axisTextCenterY = axisVpHeight / 2.0; -// const float textMarginOffset = 5.0; -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// axisTextCenterX = margins.m_left + axisTextCenterX; -// axisTextCenterY = textMarginOffset; -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// axisTextCenterX = vpX + (vpWidth / 2.0); -// axisTextCenterY = margins.m_top - textMarginOffset; -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// axisTextCenterX = textMarginOffset; -// axisTextCenterY = margins.m_bottom + axisTextCenterY; -// //annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); -// annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); -// drawAxisTextVerticalFlag = true; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// axisTextCenterX = margins.m_right - textMarginOffset; -// axisTextCenterY = vpY + (vpHeight / 2.0); -// annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); -// drawAxisTextVerticalFlag = true; -// break; -// } -// if (drawAxisTextVerticalFlag) { -// //annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); -// annotationText.setRotationAngle(-90.0); -// annotationText.setText(axisText); -// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, -// axisTextCenterY, -// 0.0, -// annotationText); -// annotationText.setRotationAngle(0.0); -// } -// else { -// annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); -// annotationText.setText(axisText); -// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, -// axisTextCenterY, -// 0.0, -// annotationText); -// } -// } -// } -// -// return true; -//} - /** * Draw the chart axes grid/box * @@ -2730,6 +2205,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); + std::unique_ptr ticksData + = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + const bool showTicksEnabledFlag = axis->isShowTickmarks(); const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; @@ -2806,13 +2285,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data } if (showTickAtScaleValueFlag) { - glLineWidth(GRID_LINE_WIDTH); - glBegin(GL_LINES); - glVertex2f(tickStartX, - tickStartY); - glVertex2f(tickEndX, - tickEndY); - glEnd(); + ticksData->addVertex(tickStartX, tickStartY); + ticksData->addVertex(tickEndX, tickEndY); } const float textX = tickEndX + textOffsetX; @@ -2823,6 +2297,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data 0.0, annotationText); } + + if (ticksData->isValid()) { + glLineWidth(GRID_LINE_WIDTH); + m_graphicsOpenGL->draw(ticksData.get()); + } const AString axisTitle = axis->getAxisTitle(); if ( ! axisTitle.isEmpty()) { diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 05b737c83..ce3c4ae22 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -35,6 +35,8 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; + class GraphicsEngineOpenGL; + class GraphicsFactory; class HistogramDrawingInfo; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; @@ -190,6 +192,9 @@ namespace caret { bool m_identificationModeFlag; + GraphicsFactory* m_graphicsFactory = NULL; + GraphicsEngineOpenGL* m_graphicsOpenGL = NULL; + static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index e68a3d0e8..a820b5b2f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -102,6 +102,8 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" +#include "GraphicsEngineOpenGL.h" +#include "GraphicsFactory.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" @@ -494,6 +496,17 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vectorgetGraphicsEngineOpenGL()->deleteUnusedBuffers(); +} + + /** * Draw models in their respective viewports. * @@ -521,6 +534,8 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, this->checkForOpenGLError(NULL, "At beginning of drawModels()"); + deleteOpenGLGraphicsFactoryUnusedBuffers(); + /* * Default the background colors to first model * NOTE: If there are no models, the surface background color is used @@ -650,6 +665,8 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, drawWindowAnnotations(windowViewport); } + deleteOpenGLGraphicsFactoryUnusedBuffers(); + this->checkForOpenGLError(NULL, "At end of drawModels()"); m_brain = NULL; diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 6782c0d02..04d7a14e9 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -511,11 +511,7 @@ namespace caret { void setTabViewport(const BrainOpenGLViewportContent* vpContent); void setAnnotationColorBarsForDrawing(std::vector& viewportContents); - - void drawTabHighlighting(const float width, - const float height, - const float rgb[3]); - + /** Index of window */ const int32_t m_windowIndex; diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 8b9bef85a..06e2e1973 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -499,6 +499,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE: case EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW: case EventTypeEnum::EVENT_GET_VIEWPORT_SIZE: + case EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW: case EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 2dbecd050..e277aec27 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -160,7 +160,9 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_CHART_MATRIX_YOKING_VALIDATION, "EVENT_CHART_MATRIX_YOKING_VALIDATION", "Validate Yoking of matrix chart's rows/columns")); - + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, + "EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS", + "Request OpenGL Graphics Engine delete buffers")); enumData.push_back(EventTypeEnum(EVENT_CHART_OVERLAY_VALIDATE, "EVENT_CHART_OVERLAY_VALIDATE", "Validate a chart overlay for validity (it exists)")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index ecf392c93..94cc9b6aa 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -106,6 +106,8 @@ public: EVENT_GET_TEXT_RENDERER_FOR_WINDOW, /** Get the viewport size for model, tab, window */ EVENT_GET_VIEWPORT_SIZE, + /** OpenGL graphics engine delete buffers */ + EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, /** Update all graphics windows */ EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, /** Update graphics in a window */ diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 33b4d6f95..613d1b8c5 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -33,17 +33,25 @@ ENDIF (OPENGL_FOUND) # ADD_LIBRARY(Graphics CaretOpenGLInclude.h +EventGraphicsEngineOpenGLDeleteBuffers.h GraphicsEngine.h +GraphicsEngineData.h +GraphicsEngineDataOpenGL.h GraphicsEngineOpenGL.h GraphicsFactory.h GraphicsPrimitive.h +GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h +EventGraphicsEngineOpenGLDeleteBuffers.cxx GraphicsEngine.cxx +GraphicsEngineData.cxx +GraphicsEngineDataOpenGL.cxx GraphicsEngineOpenGL.cxx GraphicsFactory.cxx GraphicsPrimitive.cxx +GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx ) diff --git a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx b/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx new file mode 100644 index 000000000..970a4651c --- /dev/null +++ b/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx @@ -0,0 +1,78 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ +#include "EventGraphicsEngineOpenGLDeleteBuffers.h" +#undef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsEngineOpenGLDeleteBuffers + * \brief Event for deleting OpenGL buffers created by the OpenGL Graphics Engine + * \ingroup Graphics + */ + +/** + * Constructor. + * + * @param bufferIdentifiers + * Identifiers of buffers for deletion. + */ +EventGraphicsEngineOpenGLDeleteBuffers::EventGraphicsEngineOpenGLDeleteBuffers(const std::vector& bufferIdentifiers) +: Event(EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) +{ + m_bufferIdentifiers = bufferIdentifiers; +} + +/** + * Constructor. + * + * @param bufferIdentifier + * Identifier of buffer for deletion. + */ +EventGraphicsEngineOpenGLDeleteBuffers::EventGraphicsEngineOpenGLDeleteBuffers(const GLuint bufferIdentifier) +: Event(EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) +{ + m_bufferIdentifiers.push_back(bufferIdentifier); +} + +/** + * Destructor. + */ +EventGraphicsEngineOpenGLDeleteBuffers::~EventGraphicsEngineOpenGLDeleteBuffers() +{ +} + +/** + * @return Identifiers of OpenGL buffers for deletion. + */ +std::vector +EventGraphicsEngineOpenGLDeleteBuffers::getBufferIdentifiers() const +{ + return m_bufferIdentifiers; +} + diff --git a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h b/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h new file mode 100644 index 000000000..ea4a2f655 --- /dev/null +++ b/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h @@ -0,0 +1,64 @@ +#ifndef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ +#define __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretOpenGLInclude.h" +#include "Event.h" + + + +namespace caret { + + class EventGraphicsEngineOpenGLDeleteBuffers : public Event { + + public: + EventGraphicsEngineOpenGLDeleteBuffers(const std::vector& bufferIdentifiers); + + EventGraphicsEngineOpenGLDeleteBuffers(const GLuint bufferIdentifier); + + virtual ~EventGraphicsEngineOpenGLDeleteBuffers(); + + std::vector getBufferIdentifiers() const; + + // ADD_NEW_METHODS_HERE + + private: + EventGraphicsEngineOpenGLDeleteBuffers(const EventGraphicsEngineOpenGLDeleteBuffers&); + + EventGraphicsEngineOpenGLDeleteBuffers& operator=(const EventGraphicsEngineOpenGLDeleteBuffers&); + + std::vector m_bufferIdentifiers; + // ADD_NEW_MEMBERS_HERE + + + }; + +#ifdef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ + // +#endif // __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ + +} // namespace +#endif //__EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ diff --git a/src/Graphics/GraphicsEngineData.cxx b/src/Graphics/GraphicsEngineData.cxx new file mode 100644 index 000000000..29be1ed24 --- /dev/null +++ b/src/Graphics/GraphicsEngineData.cxx @@ -0,0 +1,82 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_ENGINE_DATA_DECLARE__ +#include "GraphicsEngineData.h" +#undef __GRAPHICS_ENGINE_DATA_DECLARE__ + +#include "CaretAssert.h" +#include "EventManager.h" +using namespace caret; + + + +/** + * \class caret::GraphicsEngineData + * \brief Base class for data a graphics engine may associate with primitive data. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsEngineData::GraphicsEngineData() +: CaretObject() +{ + +// EventManager::get()->addEventListener(this, EventTypeEnum::); +} + +/** + * Destructor. + */ +GraphicsEngineData::~GraphicsEngineData() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsEngineData::toString() const +{ + return "GraphicsEngineData"; +} + +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +GraphicsEngineData::receiveEvent(Event* event) +{ +// if (event->getEventType() == EventTypeEnum::) { +// eventName = dynamic_cast(event); +// CaretAssert(eventName); +// +// event->setEventProcessed(); +// } +} + diff --git a/src/Graphics/GraphicsEngineData.h b/src/Graphics/GraphicsEngineData.h new file mode 100644 index 000000000..a8a56759a --- /dev/null +++ b/src/Graphics/GraphicsEngineData.h @@ -0,0 +1,63 @@ +#ifndef __GRAPHICS_ENGINE_DATA_H__ +#define __GRAPHICS_ENGINE_DATA_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "EventListenerInterface.h" + + +namespace caret { + + class GraphicsEngineData : public CaretObject, public EventListenerInterface { + + public: + GraphicsEngineData(); + + virtual ~GraphicsEngineData(); + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual void receiveEvent(Event* event); + + private: + GraphicsEngineData(const GraphicsEngineData&); + + GraphicsEngineData& operator=(const GraphicsEngineData&); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_ENGINE_DATA_DECLARE__ + // +#endif // __GRAPHICS_ENGINE_DATA_DECLARE__ + +} // namespace +#endif //__GRAPHICS_ENGINE_DATA_H__ diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx new file mode 100644 index 000000000..5ac7ad6f6 --- /dev/null +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -0,0 +1,179 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ +#include "GraphicsEngineDataOpenGL.h" +#undef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ + +#include "CaretAssert.h" +#include "EventGraphicsEngineOpenGLDeleteBuffers.h" +#include "EventManager.h" +#include "GraphicsPrimitive.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsEngineDataOpenGL + * \brief Contains data the OpenGL Graphics Engine may associate with primtive data. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL() +: GraphicsEngineData() +{ + +} + +/** + * Destructor. + */ +GraphicsEngineDataOpenGL::~GraphicsEngineDataOpenGL() +{ + deleteBuffers(); +} + +void +GraphicsEngineDataOpenGL::deleteBuffers() +{ + std::vector bufferIDs; + + if (m_coordinateBufferID > 0) { + bufferIDs.push_back(m_coordinateBufferID); + } + m_coordinateBufferID = 0; + + if (m_normalVectorBufferID > 0) { + bufferIDs.push_back(m_normalVectorBufferID); + } + m_normalVectorBufferID = 0; + + if (m_colorBufferID > 0) { + bufferIDs.push_back(m_colorBufferID); + } + m_colorBufferID = 0; + + if ( ! bufferIDs.empty()) { + EventGraphicsEngineOpenGLDeleteBuffers buffersEvent(bufferIDs); + EventManager::get()->sendEvent(buffersEvent.getPointer()); + } +} + + +/** + * Load the buffers with data from the grpahics primitive. + * + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + GLsizei coordinateCount = 0; + switch (primitive->m_vertexType) { + case GraphicsPrimitive::VertexType::FLOAT_XYZ: + m_coordinateDataType = GL_FLOAT; + m_coordinatesPerVertex = 3; // X, Y, Z + + coordinateCount = primitive->m_xyz.size(); + const GLuint xyzSizeBytes = coordinateCount * sizeof(float); + const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; + + glGenBuffers(1, &m_coordinateBufferID); + glBindBuffer(GL_ARRAY_BUFFER, + m_coordinateBufferID); + glBufferData(GL_ARRAY_BUFFER, + xyzSizeBytes, + xyzDataPointer, + GL_STREAM_DRAW); + break; + } + + if (m_coordinatesPerVertex > 0) { + m_arrayIndicesCount = coordinateCount / m_coordinatesPerVertex; + } + else { + m_arrayIndicesCount = 0; + } + + switch (primitive->m_normalVectorType) { + case GraphicsPrimitive::NormalVectorType::NONE: + break; + case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: + { + m_normalVectorDataType = GL_FLOAT; + const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); + const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; + + glGenBuffers(1, &m_normalVectorBufferID); + glBindBuffer(GL_ARRAY_BUFFER, + m_normalVectorBufferID); + glBufferData(GL_ARRAY_BUFFER, + normalSizeBytes, + normalDataPointer, + GL_STREAM_DRAW); + } + break; + } + + glGenBuffers(1, &m_colorBufferID); + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + m_componentsPerColor = 4; + m_colorDataType = GL_FLOAT; + + const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + m_colorBufferID); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + m_componentsPerColor = 4; + m_colorDataType = GL_UNSIGNED_BYTE; + + const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); + const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + m_colorBufferID); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + } + break; + } +} + diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h new file mode 100644 index 000000000..5bb695e42 --- /dev/null +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -0,0 +1,83 @@ +#ifndef __GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ +#define __GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsEngineData.h" +#include "CaretOpenGLInclude.h" + + +namespace caret { + + class GraphicsPrimitive; + + class GraphicsEngineDataOpenGL : public GraphicsEngineData { + + public: + GraphicsEngineDataOpenGL(); + + virtual ~GraphicsEngineDataOpenGL(); + + void deleteBuffers(); + + void loadBuffers(GraphicsPrimitive* primitive); + + // ADD_NEW_METHODS_HERE + + private: + GraphicsEngineDataOpenGL(const GraphicsEngineDataOpenGL&); + + GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); + + GLsizei m_arrayIndicesCount = 0; + + GLuint m_coordinateBufferID = 0; + + GLenum m_coordinateDataType = GL_FLOAT; + + GLint m_coordinatesPerVertex = 0; + + GLuint m_normalVectorBufferID = 0; + + GLenum m_normalVectorDataType = GL_FLOAT; + + GLuint m_colorBufferID = 0; + + GLenum m_colorDataType = GL_FLOAT; + + GLint m_componentsPerColor = 0; + + friend class GraphicsEngineOpenGL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ + // +#endif // __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ + +} // namespace +#endif //__GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ diff --git a/src/Graphics/GraphicsEngineOpenGL.cxx b/src/Graphics/GraphicsEngineOpenGL.cxx index 34b946ad9..f2191b0db 100644 --- a/src/Graphics/GraphicsEngineOpenGL.cxx +++ b/src/Graphics/GraphicsEngineOpenGL.cxx @@ -23,8 +23,13 @@ #include "GraphicsEngineOpenGL.h" #undef __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ +#include + #include "CaretAssert.h" #include "CaretOpenGLInclude.h" +#include "GraphicsEngineDataOpenGL.h" +#include "EventGraphicsEngineOpenGLDeleteBuffers.h" +#include "EventManager.h" #include "GraphicsPrimitive.h" using namespace caret; @@ -43,7 +48,8 @@ using namespace caret; GraphicsEngineOpenGL::GraphicsEngineOpenGL() : GraphicsEngine() { - + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS); } /** @@ -51,8 +57,63 @@ GraphicsEngineOpenGL::GraphicsEngineOpenGL() */ GraphicsEngineOpenGL::~GraphicsEngineOpenGL() { + EventManager::get()->removeAllEventsFromListener(this); } +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +GraphicsEngineOpenGL::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) { + EventGraphicsEngineOpenGLDeleteBuffers* bufferEvent + = dynamic_cast(event); + CaretAssert(bufferEvent); + event->setEventProcessed(); + + std::vector bufferIDs = bufferEvent->getBufferIdentifiers(); + + QMutexLocker locker(&m_unusedBufferIdentifiersMutex); + + m_unusedBufferIdentifiers.insert(m_unusedBufferIdentifiers.end(), + bufferIDs.begin(), bufferIDs.end()); + } + else { + GraphicsEngine::receiveEvent(event); + } +} + +/** + * This method must be called only when the OpenGL context + * is current. + */ +void +GraphicsEngineOpenGL::deleteUnusedBuffers() +{ + const GLsizei numberOfIDs = m_unusedBufferIdentifiers.size(); + if (numberOfIDs > 0) { + QMutexLocker locker(&m_unusedBufferIdentifiersMutex); + + for (GLuint buffID : m_unusedBufferIdentifiers) { + if ( ! glIsBuffer(buffID)) { + std::cout << "Attempting to delete invalid buffer ID: " << buffID << std::endl; + } + } + + const GLuint* idsPointer = &m_unusedBufferIdentifiers[0]; + glDeleteBuffers(numberOfIDs, + idsPointer); + m_unusedBufferIdentifiers.clear(); + + std::cout << "Deleted " << numberOfIDs << " buffers." << std::endl; + } +} + + /** * Draw the given graphics primitive. * @@ -67,108 +128,116 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) return; } - GLenum coordinateDataType = GL_FLOAT; - GLint coordinatesPerVertex = 0; - GLuint vertexBufferID = 0; - GLsizei indicesCount = 0; - switch (primitive->m_vertexType) { - case GraphicsPrimitive::VertexType::FLOAT_XYZ: - coordinateDataType = GL_FLOAT; - coordinatesPerVertex = 3; // X, Y, Z - - indicesCount = primitive->m_xyz.size(); - const GLuint xyzSizeBytes = indicesCount * sizeof(float); - const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; - - glGenBuffers(1, &vertexBufferID); - glBindBuffer(GL_ARRAY_BUFFER, - vertexBufferID); - glBufferData(GL_ARRAY_BUFFER, - xyzSizeBytes, - xyzDataPointer, - GL_STREAM_DRAW); - break; + GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); + if (openglData == NULL) { + openglData = new GraphicsEngineDataOpenGL(); + primitive->setGraphicsEngineDataForOpenGL(openglData); + + openglData->loadBuffers(primitive); } - GLenum normalVectorDataType = GL_FLOAT; - GLuint normalBufferID = 0; - switch (primitive->m_normalVectorType) { - case GraphicsPrimitive::NormalVectorType::NONE: - break; - case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: - { - normalVectorDataType = GL_FLOAT; - const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); - const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; - - glGenBuffers(1, &normalBufferID); - glBindBuffer(GL_ARRAY_BUFFER, - normalBufferID); - glBufferData(GL_ARRAY_BUFFER, - normalSizeBytes, - normalDataPointer, - GL_STREAM_DRAW); - } - break; - } - - GLenum colorDataType = GL_FLOAT; - GLint componentsPerColor = 0; - GLuint colorBufferID = 0; - glGenBuffers(1, &colorBufferID); - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - { - componentsPerColor = 4; - colorDataType = GL_FLOAT; - - const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); - const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; - - glBindBuffer(GL_ARRAY_BUFFER, - colorBufferID); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); - } - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - { - componentsPerColor = 4; - colorDataType = GL_UNSIGNED_BYTE; - - const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); - const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; - - glBindBuffer(GL_ARRAY_BUFFER, - colorBufferID); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); - } - break; - } +// GLenum coordinateDataType = GL_FLOAT; +// GLint coordinatesPerVertex = 0; +// GLuint coordinateBufferID = 0; +// GLsizei coordinateCount = 0; +// switch (primitive->m_vertexType) { +// case GraphicsPrimitive::VertexType::FLOAT_XYZ: +// coordinateDataType = GL_FLOAT; +// coordinatesPerVertex = 3; // X, Y, Z +// +// coordinateCount = primitive->m_xyz.size(); +// const GLuint xyzSizeBytes = coordinateCount * sizeof(float); +// const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; +// +// glGenBuffers(1, &coordinateBufferID); +// glBindBuffer(GL_ARRAY_BUFFER, +// coordinateBufferID); +// glBufferData(GL_ARRAY_BUFFER, +// xyzSizeBytes, +// xyzDataPointer, +// GL_STREAM_DRAW); +// break; +// } +// +// GLenum normalVectorDataType = GL_FLOAT; +// GLuint normalBufferID = 0; +// switch (primitive->m_normalVectorType) { +// case GraphicsPrimitive::NormalVectorType::NONE: +// break; +// case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: +// { +// normalVectorDataType = GL_FLOAT; +// const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); +// const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; +// +// glGenBuffers(1, &normalBufferID); +// glBindBuffer(GL_ARRAY_BUFFER, +// normalBufferID); +// glBufferData(GL_ARRAY_BUFFER, +// normalSizeBytes, +// normalDataPointer, +// GL_STREAM_DRAW); +// } +// break; +// } +// +// GLenum colorDataType = GL_FLOAT; +// GLint componentsPerColor = 0; +// GLuint colorBufferID = 0; +// glGenBuffers(1, &colorBufferID); +// switch (primitive->m_colorType) { +// case GraphicsPrimitive::ColorType::FLOAT_RGBA: +// { +// componentsPerColor = 4; +// colorDataType = GL_FLOAT; +// +// const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); +// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; +// +// glBindBuffer(GL_ARRAY_BUFFER, +// colorBufferID); +// glBufferData(GL_ARRAY_BUFFER, +// colorSizeBytes, +// colorDataPointer, +// GL_STREAM_DRAW); +// } +// break; +// case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: +// { +// componentsPerColor = 4; +// colorDataType = GL_UNSIGNED_BYTE; +// +// const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); +// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; +// +// glBindBuffer(GL_ARRAY_BUFFER, +// colorBufferID); +// glBufferData(GL_ARRAY_BUFFER, +// colorSizeBytes, +// colorDataPointer, +// GL_STREAM_DRAW); +// } +// break; +// } /* * Setup vertices for drawing */ glEnableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, - vertexBufferID); - glVertexPointer(coordinatesPerVertex, - coordinateDataType, + openglData->m_coordinateBufferID); + glVertexPointer(openglData->m_coordinatesPerVertex, + openglData->m_coordinateDataType, 0, (GLvoid*)0); /* * Setup normals for drawing */ - if (normalBufferID > 0) { + if (openglData->m_normalVectorBufferID > 0) { glEnableClientState(GL_NORMAL_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); - glNormalPointer(normalVectorDataType, 0, (GLvoid*)0); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferID); + glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); } else { glDisableClientState(GL_NORMAL_ARRAY); @@ -178,8 +247,8 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) * Setup colors for drawing */ glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); - glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferID); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); /* * Unbind buffers @@ -192,38 +261,62 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) /* * Draw the primitive */ +// const GLsizei indicesCount = openglDatacoordinateCount / coordinatesPerVertex; + GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + openGLPrimitiveType = GL_LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + openGLPrimitiveType = GL_LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::LINES: + openGLPrimitiveType = GL_LINES; + break; + case GraphicsPrimitive::PrimitiveType::POINTS: + openGLPrimitiveType = GL_POINTS; + break; + case GraphicsPrimitive::PrimitiveType::POLYGON: + openGLPrimitiveType = GL_POLYGON; + break; + case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + openGLPrimitiveType = GL_QUAD_STRIP; + break; case GraphicsPrimitive::PrimitiveType::QUADS: - glDrawArrays(GL_QUADS, - 0, - indicesCount); + openGLPrimitiveType = GL_QUADS; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + openGLPrimitiveType = GL_TRIANGLE_FAN; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + openGLPrimitiveType = GL_TRIANGLE_STRIP; break; case GraphicsPrimitive::PrimitiveType::TRIANGLES: - glDrawArrays(GL_TRIANGLES, - 0, - indicesCount); + openGLPrimitiveType = GL_TRIANGLES; break; } + CaretAssert(openGLPrimitiveType != GL_INVALID_ENUM); + glDrawArrays(openGLPrimitiveType, 0, openglData->m_arrayIndicesCount); + /* * Disable drawing */ glDisableClientState(GL_VERTEX_ARRAY); - if (normalBufferID > 0) { - glDisableClientState(GL_NORMAL_ARRAY); - } + glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - /* - * Delete buffers - */ - glDeleteBuffers(1, - &vertexBufferID); - if (normalBufferID > 0) { - glDeleteBuffers(1, - &normalBufferID); - } - glDeleteBuffers(1, - &colorBufferID); + +// /* +// * Delete buffers +// */ +// glDeleteBuffers(1, +// &coordinateBufferID); +// if (normalBufferID > 0) { +// glDeleteBuffers(1, +// &normalBufferID); +// } +// glDeleteBuffers(1, +// &colorBufferID); } diff --git a/src/Graphics/GraphicsEngineOpenGL.h b/src/Graphics/GraphicsEngineOpenGL.h index f5cee58d8..146e7e0ae 100644 --- a/src/Graphics/GraphicsEngineOpenGL.h +++ b/src/Graphics/GraphicsEngineOpenGL.h @@ -21,10 +21,11 @@ */ /*LICENSE_END*/ - +#include #include +#include "CaretOpenGLInclude.h" #include "GraphicsEngine.h" @@ -38,8 +39,12 @@ namespace caret { virtual ~GraphicsEngineOpenGL(); + virtual void receiveEvent(Event* event); + virtual void draw(GraphicsPrimitive* primitive); + void deleteUnusedBuffers(); + // ADD_NEW_METHODS_HERE private: @@ -47,6 +52,13 @@ namespace caret { GraphicsEngineOpenGL& operator=(const GraphicsEngineOpenGL&); + /** prevents concurrent access to m_unusedBufferIdentifiers */ + QMutex m_unusedBufferIdentifiersMutex; + + /** use a mutex whenever accessing this member */ + std::vector m_unusedBufferIdentifiers; + + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsFactory.cxx b/src/Graphics/GraphicsFactory.cxx index 1bf70a9f8..78d8118ad 100644 --- a/src/Graphics/GraphicsFactory.cxx +++ b/src/Graphics/GraphicsFactory.cxx @@ -26,6 +26,7 @@ #include "CaretAssert.h" #include "EventManager.h" #include "GraphicsEngineOpenGL.h" +#include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" @@ -111,6 +112,38 @@ GraphicsFactory::getGraphicsEngineOpenGL() return m_graphicsEngineOpenGL.get(); } +/** + * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3f* +GraphicsFactory::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const float floatRGBA[4]) +{ + GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, + floatRGBA); + return primitive; +} + +/** + * @return A new primitive for XYZ with solid color unsigned byte RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3f* +GraphicsFactory::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]) +{ + GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, + unsignedByteRGBA); + return primitive; +} + /** * @return A new primitive for XYZ with float RGBA. Caller is responsible * for deleting the returned pointer. diff --git a/src/Graphics/GraphicsFactory.h b/src/Graphics/GraphicsFactory.h index d2eb98939..acd88ad86 100644 --- a/src/Graphics/GraphicsFactory.h +++ b/src/Graphics/GraphicsFactory.h @@ -33,6 +33,7 @@ namespace caret { class GraphicsEngineOpenGL; + class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; @@ -51,6 +52,12 @@ namespace caret { GraphicsEngineOpenGL* getGraphicsEngineOpenGL(); + GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const float floatRGBA[4]); + + GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]); + GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index ddc08f667..1605253fd 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -26,6 +26,8 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" +#include "GraphicsEngineDataOpenGL.h" + using namespace caret; @@ -68,7 +70,7 @@ GraphicsPrimitive::GraphicsPrimitive(const VertexType vertexType, */ GraphicsPrimitive::~GraphicsPrimitive() { - EventManager::get()->removeAllEventsFromListener(this); + EventManager::get()->removeAllEventsFromListener(this); } /** @@ -96,7 +98,10 @@ void GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) { m_xyz = obj.m_xyz; + m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; m_floatRGBA = obj.m_floatRGBA; + m_unsignedByteRGBA = obj.m_unsignedByteRGBA; + m_graphicsEngineDataForOpenGL.reset(); } /** @@ -147,64 +152,241 @@ GraphicsPrimitive::isValid() const } switch (m_primitiveType) { + case PrimitiveType::LINE_LOOP: + if (numXYZ < 3) { + CaretLogWarning("Line loop must have at least 3 vertices."); + } + break; + case PrimitiveType::LINE_STRIP: + if (numXYZ < 2) { + CaretLogWarning("Line strip must have at least 2 vertices."); + } + break; + case PrimitiveType::LINES: + if (numXYZ < 2) { + CaretLogWarning("Lines must have at least 2 vertices."); + } + else { + const uint32_t extraVertices = numXYZ % 2; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing lines ignored."); + } + } + break; + case PrimitiveType::POINTS: + break; + case PrimitiveType::POLYGON: + if (numXYZ < 3) { + CaretLogWarning("Polygon must have at least 3 vertices."); + } + break; + case PrimitiveType::QUAD_STRIP: + if (numXYZ < 4) { + CaretLogWarning("Quad strip must have at least 4 vertices."); + } + else { + const uint32_t extraVertices = numXYZ % 2; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing quads ignored."); + } + } + break; case PrimitiveType::QUADS: - { - const uint32_t extraVertices = numXYZ % 4; - if (extraVertices > 0) { - CaretLogWarning("Extra vertices for drawing quads ignored."); + if (numXYZ < 4) { + CaretLogWarning("Quads must have at least 4 vertices."); + } + else { + const uint32_t extraVertices = numXYZ % 4; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing quads ignored."); + } + } + break; + case PrimitiveType::TRIANGLE_FAN: + if (numXYZ < 3) { + CaretLogWarning("Triangle fan must have at least 3 vertices."); + } + break; + case PrimitiveType::TRIANGLE_STRIP: + if (numXYZ < 3) { + CaretLogWarning("Triangle strip must have at least 3 vertices."); } - } break; case PrimitiveType::TRIANGLES: - { - const uint32_t extraVertices = numXYZ % 3; - if (extraVertices > 0) { - CaretLogWarning("Extra vertices for drawing triangles ignored."); + if (numXYZ < 3) { + CaretLogWarning("Triangles must have at least 3 vertices."); + } + else { + const uint32_t extraVertices = numXYZ % 3; + if (extraVertices > 0) { + CaretLogWarning("Extra vertices for drawing triangles ignored."); + } } - } break; } + return true; } return false; } +/** + * Print the primitive's data, data may be long! + */ +void +GraphicsPrimitive::print() const +{ + std::cout << toStringPrivate(true) << std::endl; +} + + /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsPrimitive::toString() const +{ + return toStringPrivate(false); +} + +/** + * Convert to string. + * + * @param includeAllDataFlag + * If true, numerical values are included. Else, only type of data. + */ +AString +GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const { AString s; + switch (m_primitiveType) { + case PrimitiveType::LINE_LOOP: + s.appendWithNewLine("Primitive: Line Loop"); + break; + case PrimitiveType::LINE_STRIP: + s.appendWithNewLine("Primitive: Line Strip"); + break; + case PrimitiveType::LINES: + s.appendWithNewLine("Primitive: Lines"); + break; + case PrimitiveType::POINTS: + s.appendWithNewLine("Primitive: Points"); + break; + case PrimitiveType::POLYGON: + s.appendWithNewLine("Primitive: Polygon"); + break; + case PrimitiveType::QUAD_STRIP: + s.appendWithNewLine("Primitive: Quad Strip"); + break; + case PrimitiveType::QUADS: + s.appendWithNewLine("Primitive: Quads"); + break; + case PrimitiveType::TRIANGLE_FAN: + s.appendWithNewLine("Primitive: Triangle Fan"); + break; + case PrimitiveType::TRIANGLE_STRIP: + s.appendWithNewLine("Primitive: Triangle Strip"); + break; + case PrimitiveType::TRIANGLES: + s.appendWithNewLine("Primitive: Triangles"); + break; + } switch (m_vertexType) { case VertexType::FLOAT_XYZ: - s.append("Vertex: " + AString::number(m_xyz.size()) + " Float XYZ. "); + s.appendWithNewLine("Vertex: " + AString::number(m_xyz.size()) + " Float XYZ. "); + if (includeAllDataFlag ) { + s.append("\n "); + const int32_t count = static_cast(m_xyz.size()); + for (int32_t i = 0; i < count; i++) { + s.append(AString::number(m_xyz[i]) + " "); + if (((i+1) % 3) == 0) { + s.append("\n "); + } + } + s.append("\n"); + } break; } switch (m_normalVectorType) { case NormalVectorType::FLOAT_XYZ: - s.append("Normal Vector: " + AString::number(m_floatNormalVectorXYZ.size()) + " Float XYZ. "); + s.appendWithNewLine("Normal Vector: " + AString::number(m_floatNormalVectorXYZ.size()) + " Float XYZ. "); break; + if (includeAllDataFlag ) { + s.append("\n "); + const int32_t count = static_cast(m_floatNormalVectorXYZ.size()); + for (int32_t i = 0; i < count; i++) { + s.append(AString::number(m_floatNormalVectorXYZ[i]) + " "); + if (((i+1) % 3) == 0) { + s.append("\n "); + } + } + } case NormalVectorType::NONE: - s.append("Normal Vector: None. "); + s.appendWithNewLine("Normal Vector: None. "); break; } switch (m_colorType) { case ColorType::FLOAT_RGBA: - s.append("Color: " + AString::number(m_floatRGBA.size()) + " Float RGBA 0.0 to 1.0. "); + s.appendWithNewLine("Color: " + AString::number(m_floatRGBA.size()) + " Float RGBA 0.0 to 1.0. "); + if (includeAllDataFlag ) { + s.append("\n "); + const int32_t count = static_cast(m_floatRGBA.size()); + for (int32_t i = 0; i < count; i++) { + s.append(AString::number(m_floatRGBA[i]) + " "); + if (((i+1) % 4) == 0) { + s.append("\n "); + } + } + } break; case ColorType::UNSIGNED_BYTE_RGBA: - s.append("Color: " + AString::number(m_unsignedByteRGBA.size()) + " Unsigned Byte RGBA 0 to 255"); + s.appendWithNewLine("Color: " + AString::number(m_unsignedByteRGBA.size()) + " Unsigned Byte RGBA 0 to 255"); + if (includeAllDataFlag ) { + s.append("\n "); + const int32_t count = static_cast(m_unsignedByteRGBA.size()); + for (int32_t i = 0; i < count; i++) { + s.append(AString::number(m_unsignedByteRGBA[i]) + " "); + if (((i+1) % 4) == 0) { + s.append("\n "); + } + } + } break; } return s; } +/** + * Get the OpenGL graphics engine data in this instance. + * + * @return + * OpenGL graphics engine data or NULL if not found. + */ +GraphicsEngineDataOpenGL* +GraphicsPrimitive::getGraphicsEngineDataForOpenGL() +{ + return m_graphicsEngineDataForOpenGL.get(); +} + +/** + * Set the OpenGL graphics engine data in this instance. + * + * @param graphicsEngineForOpenGL + * OpenGLgraphics engine for which graphics engine data is desired. This value may + * NULL to remove graphics engine data for the given graphics engine. + * This instance will take ownership of this data and handle deletion of it. + */ +void +GraphicsPrimitive::setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL) +{ + m_graphicsEngineDataForOpenGL.reset(graphicsEngineDataForOpenGL); +} + /** * Receive an event. diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 94114a51e..293512498 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ - +#include #include #include "CaretObject.h" @@ -32,6 +32,9 @@ namespace caret { + class GraphicsEngine; + class GraphicsEngineDataOpenGL; + class GraphicsPrimitive : public CaretObject, public EventListenerInterface { public: @@ -63,10 +66,65 @@ namespace caret { UNSIGNED_BYTE_RGBA }; + /** + * Type of primitives for drawing + * Descriptions are copied from the glVertex man page. + */ enum class PrimitiveType { - /** Quads - Four vertices form one quad */ + /** + * Draws a connected group of line segments from the first vertex to the last. + * Vertices n and n+1 define line n. n-1 lines are drawn. + */ + LINE_LOOP, + /** + * Treats each pair of vertices as an independent line segment. + * Vertices 2n-1 and 2n define line n. n/2 lines are drawn. + */ + LINE_STRIP, + /** + * Draws a connected group of line segments from the first vertex to the last, then back + * to the first. Vertices n and n+1 define line n. The last line, however, is defined by + * vertices n and 1. n lines are drawn. + */ + LINES, + /** + * Treats each vertex as a single point. Vertex n defines point n. n points are drawn. + */ + POINTS, + /** + * Draws a single, convex polygon. Vertices 1 through n define this polygon. + */ + POLYGON, + /** + * Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair + * of vertices presented after the first pair. Vertices 2n-1, 2n, 2n+2, and 2n+1 define + * quadrilateral n. n/2 quadrilaterals are drawn. Note that the order in which vertices + * are used to construct a quadrilateral from strip data is different from that used with + * independent data. + */ + QUAD_STRIP, + /** + * Treats each group of four vertices as an independent quadrilateral. + * Vertices 4n-3, 4n-2, 4n-3, and 4n define quadrilateral n. n/4 quadrilaterals are drawn. + */ QUADS, - /** Triangles - Three vertices form one triangle */ + /** + * Draws a connected group of triangles. One triangle is defined for each vertex + * presented after the first two vertices. Vertices 1, n+1, and n+2 define triangle n. n-2 + * triangles are drawn. + */ + TRIANGLE_FAN, + /** + * Draws a connected group of triangles. One triangle is defined for each vertex + * presented after the first two vertices. For odd n, vertices n, n+1, and n+2 define + * triangle n. For even n, vertices n+1, n, and n+2 define triangle n. n-2 triangles are + * drawn. + */ + TRIANGLE_STRIP, + /** + * Treats each triplet of vertices as an independent triangle. Vertices 3n-2, 3n-1, and + * 3n define triangle n. n/3 triangles are drawn. + */ TRIANGLES }; @@ -108,7 +166,13 @@ namespace caret { */ const std::vector& getFloatXYZ() const { return m_xyz; } - virtual AString toString() const; + GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); + + void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); + + virtual AString toString() const override; + + virtual void print() const; /** * Clone this primitive. @@ -116,6 +180,8 @@ namespace caret { virtual GraphicsPrimitive* clone() const = 0; protected: + AString toStringPrivate(const bool includeAllDataFlag) const; + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; @@ -123,6 +189,8 @@ namespace caret { const ColorType m_colorType; const PrimitiveType m_primitiveType; + + std::unique_ptr m_graphicsEngineDataForOpenGL; std::vector m_xyz; @@ -135,6 +203,8 @@ namespace caret { private: void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); + friend class GraphicsEngineDataOpenGL; + friend class GraphicsEngineOpenGL; // ADD_NEW_MEMBERS_HERE diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx new file mode 100644 index 000000000..5bda3f4da --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -0,0 +1,203 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_V3F_DECLARE__ +#include "GraphicsPrimitiveV3f.h" +#undef __GRAPHICS_PRIMITIVE_V3F_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveV3f + * \brief Primitive containing XYZ with one color (float, unsigned byte) applied to all vertices. + * \ingroup Graphics + * + * When we move to using the programmable pipeline OpenGL, the color components + * can be passed to the shader to avoid adding the color to each vertex. + */ + +/** + * Constructor for solid color float RGBA. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, + const float rgba[4]) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::NONE, + ColorType::FLOAT_RGBA, + primitiveType) +{ + m_floatSolidRGBA[0] = rgba[0]; + m_floatSolidRGBA[1] = rgba[1]; + m_floatSolidRGBA[2] = rgba[2]; + m_floatSolidRGBA[3] = rgba[3]; +} + +/** + * Constructor for solid color unsigned byte RGBA. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, + const uint8_t rgba[4]) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::NONE, + ColorType::UNSIGNED_BYTE_RGBA, + primitiveType) +{ + m_unsignedByteSolidRGBA[0] = rgba[0]; + m_unsignedByteSolidRGBA[1] = rgba[1]; + m_unsignedByteSolidRGBA[2] = rgba[2]; + m_unsignedByteSolidRGBA[3] = rgba[3]; +} + +/** + * Destructor. + */ +GraphicsPrimitiveV3f::~GraphicsPrimitiveV3f() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) +: GraphicsPrimitive(obj) +{ + this->copyHelperGraphicsPrimitiveV3f(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) +{ + +} + +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + */ +void +GraphicsPrimitiveV3f::addVertex(const float xyz[3]) +{ + m_xyz.insert(m_xyz.end(), + xyz, xyz + 3); + + switch (m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + m_floatRGBA.insert(m_floatRGBA.end(), + m_floatSolidRGBA, m_floatSolidRGBA + 4); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); + break; + } +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + */ +void +GraphicsPrimitiveV3f::addVertex(const float x, + const float y, + const float z) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(z); + switch (m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + m_floatRGBA.insert(m_floatRGBA.end(), + m_floatSolidRGBA, m_floatSolidRGBA + 4); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); + break; + } +} + +/** + * Add a 2D vertex. Z will be zero. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3f::addVertex(const float x, + const float y) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(0.0); + switch (m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + m_floatRGBA.insert(m_floatRGBA.end(), + m_floatSolidRGBA, m_floatSolidRGBA + 4); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); + break; + } +} + +/** + * Clone this primitive. + */ +GraphicsPrimitive* +GraphicsPrimitiveV3f::clone() const +{ + GraphicsPrimitiveV3f* obj = new GraphicsPrimitiveV3f(*this); + return obj; +} + diff --git a/src/Graphics/GraphicsPrimitiveV3f.h b/src/Graphics/GraphicsPrimitiveV3f.h new file mode 100644 index 000000000..db4cd62e2 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3f.h @@ -0,0 +1,78 @@ +#ifndef __GRAPHICS_PRIMITIVE_V3F_H__ +#define __GRAPHICS_PRIMITIVE_V3F_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsPrimitive.h" + + + +namespace caret { + + class GraphicsPrimitiveV3f : public GraphicsPrimitive { + + public: + GraphicsPrimitiveV3f(const PrimitiveType primitiveType, + const float rgba[4]); + + GraphicsPrimitiveV3f(const PrimitiveType primitiveType, + const uint8_t rgba[4]); + + virtual ~GraphicsPrimitiveV3f(); + + GraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj); + + void addVertex(const float xyz[3]); + + void addVertex(const float x, + const float y, + const float z); + + void addVertex(const float x, + const float y); + + virtual GraphicsPrimitive* clone() const; + + // ADD_NEW_METHODS_HERE + + private: + GraphicsPrimitiveV3f& operator=(const GraphicsPrimitiveV3f& obj); + + void copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj); + + float m_floatSolidRGBA[4]; + + uint8_t m_unsignedByteSolidRGBA[4]; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_V3F_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_V3F_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_V3F_H__ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 85d2b215d..9f6f8be0b 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -121,6 +121,28 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, rgba, rgba + 4); } +/** + * Add a 2D vertex. Z will be zero. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +void +GraphicsPrimitiveV3fC4f::addVertex(const float x, + const float y, + const float rgba[4]) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(0.0); + m_floatRGBA.insert(m_floatRGBA.end(), + rgba, rgba + 4); +} + /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.h b/src/Graphics/GraphicsPrimitiveV3fC4f.h index fbe17191b..0de2cc905 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.h +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.h @@ -48,6 +48,10 @@ namespace caret { const float z, const float rgba[4]); + void addVertex(const float x, + const float y, + const float rgba[4]); + virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE -- GitLab From fc649a8858623df6d8f29a8f6092925cdb2d0b70 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 14 Apr 2017 15:12:35 -0500 Subject: [PATCH 251/755] When creating BrainOpenGLWidget, use an OpenGL sharing context so that all windows use the same OpenGL buffer objects. Otherwise, it would be very difficult to create/destroy buffer objects for each window. In addition, fixed crash if the user attempted to create more than 10 windows. --- src/GuiQt/BrainBrowserWindow.cxx | 40 ++++++++++++++++++++++++++- src/GuiQt/BrainBrowserWindow.h | 7 +++++ src/GuiQt/BrainOpenGLWidget.cxx | 4 ++- src/GuiQt/BrainOpenGLWidget.h | 1 + src/GuiQt/GuiManager.cxx | 47 ++++++++++++++++++++++++++++---- src/GuiQt/GuiManager.h | 3 +- 6 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 59bb7d1ea..082659851 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -149,8 +149,29 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, + AString::number(m_browserWindowIndex + 1)); setObjectName(windowTitle()); + BrainOpenGLWidget* shareOpenGLContextWidget = NULL; + if ( ! s_brainBrowserWindows.empty()) { + std::set::iterator iter = s_brainBrowserWindows.begin(); + CaretAssert(iter != s_brainBrowserWindows.end()); + shareOpenGLContextWidget = (*iter)->m_openGLWidget; + CaretAssert(shareOpenGLContextWidget); + } m_openGLWidget = new BrainOpenGLWidget(this, - browserWindowIndex); + shareOpenGLContextWidget, + browserWindowIndex); + if (shareOpenGLContextWidget != NULL) { + /* + * Need to know if OpenGL context sharing is enabled. + */ + m_openGLWidgetSharingContextFlag = m_openGLWidget->isSharing(); + } + else { + /* + * This is the first window so set OpenGL context + * to true since there are no other contexts + */ + m_openGLWidgetSharingContextFlag = true; + } const int openGLSizeX = 500; const int openGLSizeY = (WuQtUtilities::isSmallDisplay() ? 200 : 375); @@ -263,6 +284,7 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, Qt::Vertical); } #endif + s_brainBrowserWindows.insert(this); } /** @@ -270,6 +292,8 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, */ BrainBrowserWindow::~BrainBrowserWindow() { + s_brainBrowserWindows.erase(this); + EventManager::get()->removeAllEventsFromListener(this); delete m_defaultTileTabsConfiguration; @@ -4520,4 +4544,18 @@ BrainBrowserWindow::hasValidOpenGL() return m_openGLWidget->isValid(); } +/** + * @return True if this OpenGL widget in this window is sharing + * its OpenGL context. Note: the first window is considered + * sharing since it is the only context. Sharing is needed + * when there are multiple windows to simplify management + * of OpenGL Buffers, textures, etc. + */ +bool +BrainBrowserWindow::isOpenGLWidgetSharingContext() const +{ + return m_openGLWidgetSharingContextFlag; +} + + diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index b6a96311d..6e58874ae 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -22,6 +22,7 @@ */ /*LICENSE_END*/ +#include #include #include @@ -148,6 +149,8 @@ namespace caret { bool hasValidOpenGL(); + bool isOpenGLWidgetSharingContext() const; + protected: void closeEvent(QCloseEvent* event); void keyPressEvent(QKeyEvent* event); @@ -302,6 +305,8 @@ namespace caret { BrainOpenGLWidget* m_openGLWidget; + bool m_openGLWidgetSharingContextFlag; + BrainBrowserWindowToolBar* m_toolbar; QAction* m_aboutWorkbenchAction; @@ -432,8 +437,10 @@ namespace caret { /** Y position from scene file for first window */ static int32_t s_sceneFileFirstWindowY; + static std::set s_brainBrowserWindows; }; #ifdef __BRAIN_BROWSER_WINDOW_DECLARE__ + std::set BrainBrowserWindow::s_brainBrowserWindows; AString BrainBrowserWindow::s_previousOpenFileNameFilter; AString BrainBrowserWindow::s_previousOpenFileDirectory; QByteArray BrainBrowserWindow::s_previousOpenFileGeometry; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index e898d24b1..f9fec0099 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -98,11 +98,13 @@ using namespace caret; * The parent widget. */ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, + const BrainOpenGLWidget* shareWidget, const int32_t windowIndex) #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET : QOpenGLWidget(parent), #else -: QGLWidget(parent), +: QGLWidget(parent, + shareWidget), #endif windowIndex(windowIndex), m_textRenderer(NULL) diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index b3b7ce3ac..a426da116 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -71,6 +71,7 @@ namespace caret { public: BrainOpenGLWidget(QWidget* parent, + const BrainOpenGLWidget* shareWidget, const int32_t windowIndex); ~BrainOpenGLWidget(); diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 1ac0322e9..71e60d216 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -570,18 +570,27 @@ GuiManager::getBrowserWindowByWindowIndex(const int32_t browserWindowIndex) * Optional tab for initial windwo tab. * @param createDefaultTabs * If true, create the default tabs in the new window. + * @param errorMessageOut + * Contains message if window could not be created. + * @return + * Pointer to new window or NULL if unable to create a window. */ BrainBrowserWindow* GuiManager::newBrainBrowserWindow(QWidget* parent, BrowserTabContent* browserTabContent, - const bool createDefaultTabs) + const bool createDefaultTabs, + AString& errorMessageOut) { + errorMessageOut.clear(); + /* * If no tabs can be created, do not create a new window. */ EventBrowserTabGetAll getAllTabs; EventManager::get()->sendEvent(getAllTabs.getPointer()); if (getAllTabs.getNumberOfBrowserTabs() == BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS) { + errorMessageOut = ("All browser tabs are being used. " + "Close some browser tabs and then try creating a new window."); return NULL; } @@ -597,6 +606,15 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, } } + if (windowIndex < 0) { + if (numWindows >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) { + errorMessageOut = ("Unable to create a new window as the maximum number of windows (" + + AString::number(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) + + ") are currently open."); + return NULL; + } + } + BrainBrowserWindow* bbw = NULL; BrainBrowserWindow::CreateDefaultTabsMode tabsMode = (createDefaultTabs @@ -613,6 +631,18 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, m_brainBrowserWindows[windowIndex] = bbw; } + /* + * Did OpenGL Context sharing fail? + */ + if ( ! bbw->isOpenGLWidgetSharingContext()) { + delete bbw; + errorMessageOut = ("There has been a failure when creating an OpenGL Widget " + "with a \"shared context\" for the new window. " + "This may be caused by a limitation of the OpenGL graphics or the " + "windowing system on your computer."); + return NULL; + } + if (parent != NULL) { WuQtUtilities::moveWindowToOffset(parent, bbw, 20, 20); } @@ -1207,11 +1237,13 @@ GuiManager::receiveEvent(Event* event) dynamic_cast(event); CaretAssert(eventNewBrowser); + AString errorMessage; BrainBrowserWindow* bbw = this->newBrainBrowserWindow(eventNewBrowser->getParent(), eventNewBrowser->getBrowserTabContent(), - true); + true, + errorMessage); if (bbw == NULL) { - eventNewBrowser->setErrorMessage("Workench is exhausted. It cannot create any more windows."); + eventNewBrowser->setErrorMessage(errorMessage); eventNewBrowser->setEventProcessed(); return; } @@ -2415,19 +2447,24 @@ GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); BrainBrowserWindow* bbw = NULL; - if (availableWindows.empty() == false) { + AString errorMessage; + if ( ! availableWindows.empty()) { bbw = availableWindows.front(); availableWindows.pop_front(); } else { bbw = newBrainBrowserWindow(NULL, NULL, - false); + false, + errorMessage); } if (bbw != NULL) { bbw->restoreFromScene(sceneAttributes, browserClass); } + else { + sceneAttributes->addToErrorMessage("\n" + errorMessage); + } } } diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index fe5b089ab..f5e00e41a 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -214,7 +214,8 @@ namespace caret { BrainBrowserWindow* newBrainBrowserWindow(QWidget* parent, BrowserTabContent* browserTabContent, - const bool createDefaultTabs); + const bool createDefaultTabs, + AString& errorMessageOut); void reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindow); -- GitLab From aad4fd507cef85bb7209ad147ea4a108c9a623ad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 17 Apr 2017 15:41:39 -0500 Subject: [PATCH 252/755] Adding a module for using OpenGL Buffers that include creation of the buffers, delete of the buffers, loading of the buffers, and drawing of the buffers. --- src/Brain/BrainOpenGL.cxx | 209 ++++++++++++++++++ src/Brain/BrainOpenGL.h | 123 +++++++++-- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 28 ++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 3 + src/Brain/BrainOpenGLFixedPipeline.cxx | 23 +- src/Brain/BrainOpenGLFixedPipeline.h | 32 +-- src/Common/EventManager.cxx | 2 + src/Common/EventTypeEnum.cxx | 13 +- src/Common/EventTypeEnum.h | 4 + src/Graphics/CMakeLists.txt | 8 +- ...EventGraphicsEngineOpenGLDeleteBuffers.cxx | 78 ------- .../EventGraphicsOpenGLCreateBufferObject.cxx | 102 +++++++++ .../EventGraphicsOpenGLCreateBufferObject.h | 64 ++++++ .../EventGraphicsOpenGLDeleteBufferObject.cxx | 87 ++++++++ ...> EventGraphicsOpenGLDeleteBufferObject.h} | 38 ++-- src/Graphics/GraphicsEngine.h | 3 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 76 ++++--- src/Graphics/GraphicsEngineDataOpenGL.h | 10 +- src/Graphics/GraphicsEngineOpenGL.cxx | 167 ++------------ src/Graphics/GraphicsEngineOpenGL.h | 19 +- src/Graphics/GraphicsOpenGLBufferObject.cxx | 77 +++++++ src/Graphics/GraphicsOpenGLBufferObject.h | 75 +++++++ src/GuiQt/BrainOpenGLWidget.cxx | 5 + src/Operations/OperationShowScene.cxx | 2 + 24 files changed, 897 insertions(+), 351 deletions(-) delete mode 100644 src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx create mode 100644 src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx create mode 100644 src/Graphics/EventGraphicsOpenGLCreateBufferObject.h create mode 100644 src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx rename src/Graphics/{EventGraphicsEngineOpenGLDeleteBuffers.h => EventGraphicsOpenGLDeleteBufferObject.h} (52%) create mode 100644 src/Graphics/GraphicsOpenGLBufferObject.cxx create mode 100644 src/Graphics/GraphicsOpenGLBufferObject.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 3843f7179..3667c66c1 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -32,6 +32,10 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "DummyFontTextRenderer.h" +#include "EventGraphicsOpenGLCreateBufferObject.h" +#include "EventGraphicsOpenGLDeleteBufferObject.h" +#include "EventManager.h" +#include "GraphicsOpenGLBufferObject.h" #include "Model.h" #include "SessionManager.h" @@ -52,6 +56,9 @@ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) m_textRenderer = textRenderer; this->borderBeingDrawn = NULL; m_drawHighlightedEndPoints = false; + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT); } /** @@ -59,12 +66,214 @@ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) */ BrainOpenGL::~BrainOpenGL() { + EventManager::get()->removeAllEventsFromListener(this); + if (m_textRenderer != NULL) { delete m_textRenderer; m_textRenderer = NULL; } } +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +BrainOpenGL::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT) { + EventGraphicsOpenGLCreateBufferObject* createBufferEvent + = dynamic_cast(event); + CaretAssert(createBufferEvent); + + if (m_openGLContextPointer == NULL) { + AString msg("PROGRAM ERROR: " + "A request for a new OpenGL Buffer Object has been made. " + "However, there is no OpenGL context currently active so " + "a buffer cannot be created. This is an error in the " + "code and it is likely that the software will crash."); + createBufferEvent->setErrorMessage(msg); + createBufferEvent->setOpenGLBufferObject(NULL); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + GLuint bufferName = 0; + glGenBuffers(1, &bufferName); + + createBufferEvent->setOpenGLBufferObject(new GraphicsOpenGLBufferObject(m_openGLContextPointer, + bufferName)); + createBufferEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT) { + QMutexLocker locker(&m_buffersForDeletionLaterMutex); + + EventGraphicsOpenGLDeleteBufferObject* deleteBufferEvent + = dynamic_cast(event); + CaretAssert(deleteBufferEvent); + GraphicsOpenGLBufferObject* bufferObject = deleteBufferEvent->getOpenGLBufferObject(); + if (bufferObject != NULL) { + m_buffersForDeletionLater.emplace(m_buffersForDeletionLater.end(), + bufferObject->getOpenGLContextPointer(), + bufferObject->getBufferObjectName()); + } + + deleteBufferEvent->setEventProcessed(); + } +} + +/** + * Draw models in their respective viewports. + * + * @param brain + * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. + * @param viewportContents + * Viewport info for drawing. + */ +void BrainOpenGL::drawModels(Brain* brain, + void* openGLContextPointer, + std::vector& viewportContents) +{ + m_openGLContextPointer = openGLContextPointer; + + drawModelsImplementation(brain, + viewportContents); + + deleteUnusedBuffers(); + + m_openGLContextPointer = NULL; +} + +/** + * Selection on a model. + * + * @param brain + * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. + * @param viewportContent + * Viewport content in which mouse was clicked + * @param mouseX + * X position of mouse click + * @param mouseY + * Y position of mouse click + * @param applySelectionBackgroundFiltering + * If true (which is in most cases), if there are multiple items + * selected, those items "behind" other items are not reported. + * For example, suppose a focus is selected and there is a node + * the focus. If this parameter is true, the node will NOT be + * selected. If this parameter is false, the node will be + * selected. + */ +void BrainOpenGL::selectModel(Brain* brain, + void* openGLContextPointer, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering) +{ + m_openGLContextPointer = openGLContextPointer; + + selectModelImplementation(brain, + viewportContent, + mouseX, + mouseY, + applySelectionBackgroundFiltering); + + deleteUnusedBuffers(); + + m_openGLContextPointer = NULL; +} + +/** + * Project the given window coordinate to the active models. + * If the projection is successful, The 'original' XYZ + * coordinate in 'projectionOut' will be valid. In addition, + * the barycentric coordinate may also be valid in 'projectionOut'. + * + * @param brain + * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. + * @param viewportContent + * Viewport content in which mouse was clicked + * @param mouseX + * X position of mouse click + * @param mouseY + * Y position of mouse click + */ +void BrainOpenGL::projectToModel(Brain* brain, + void* openGLContextPointer, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) +{ + m_openGLContextPointer = openGLContextPointer; + + projectToModelImplementation(brain, + viewportContent, + mouseX, + mouseY, + projectionOut); + deleteUnusedBuffers(); + + m_openGLContextPointer = NULL; +} + + +/** + * This method must be called only when the OpenGL context + * is current. + */ +void +BrainOpenGL::deleteUnusedBuffers() +{ + //if ( ! m_unusedBufferIdentifiers.empty()) { + if ( ! m_buffersForDeletionLater.empty()) { + QMutexLocker locker(&m_buffersForDeletionLaterMutex); + + std::vector otherContextBufferIdentifiers; + + std::vector bufferNames; + + for (auto bufferInfo : m_buffersForDeletionLater) { + if (bufferInfo.m_openglContextPointer == m_openGLContextPointer) { + if (glIsBuffer(bufferInfo.m_bufferName)) { + bufferNames.push_back(bufferInfo.m_bufferName); + } + else { + CaretLogWarning("Attempting to delete invalid OpenGL buffer ID: " + + AString::number(bufferInfo.m_bufferName)); + } + } + else { + otherContextBufferIdentifiers.push_back(bufferInfo); + } + } + + if ( ! bufferNames.empty()) { + const GLuint* namesPointer = &bufferNames[0]; + glDeleteBuffers(bufferNames.size(), + namesPointer); + m_buffersForDeletionLater.clear(); + + std::cout << "Deleted " << bufferNames.size() << " buffers." << std::endl; + } + + m_buffersForDeletionLater = otherContextBufferIdentifiers; + if ( ! m_buffersForDeletionLater.empty()) { + std::cout << "Not deleting " << m_buffersForDeletionLater.size() << " in another OpenGL Context." << std::endl; + } + } +} + + /** * @return The active text renderer. */ diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index b4dfcc725..701dbf7d9 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -22,6 +22,9 @@ */ /*LICENSE_END*/ +#include + +#include #include #include @@ -55,7 +58,9 @@ #endif // GL_VERSION_4_0 + #include "CaretObject.h" +#include "EventListenerInterface.h" namespace caret { @@ -70,7 +75,7 @@ namespace caret { /** * Performs drawing of graphics using OpenGL. */ - class BrainOpenGL : public CaretObject { + class BrainOpenGL : public CaretObject, public EventListenerInterface { protected: BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer); @@ -104,17 +109,22 @@ namespace caret { * * @param brain * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. * @param viewportContents * Viewport info for drawing. */ - virtual void drawModels(Brain* brain, - std::vector& viewportContents) = 0; + void drawModels(Brain* brain, + void* openGLContextPointer, + std::vector& viewportContents); /** * Selection on a model. * * @param brain * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX @@ -129,11 +139,12 @@ namespace caret { * selected. If this parameter is false, the node will be * selected. */ - virtual void selectModel(Brain* brain, - BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - const bool applySelectionBackgroundFiltering) = 0; + void selectModel(Brain* brain, + void* openGLContextPointer, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering); /** * Project the given window coordinate to the active models. @@ -143,6 +154,8 @@ namespace caret { * * @param brain * The brain (must be valid!) + * @param openGLContextPointer + * Pointer to the active OpenGL context. * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX @@ -150,11 +163,12 @@ namespace caret { * @param mouseY * Y position of mouse click */ - virtual void projectToModel(Brain* brain, - BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - SurfaceProjectedItem& projectionOut) = 0; + void projectToModel(Brain* brain, + void* openGLContextPointer, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut); virtual BrainOpenGLTextureManager* getTextureManager() = 0; @@ -212,12 +226,95 @@ namespace caret { virtual AString getStateOfOpenGL() const; + virtual void receiveEvent(Event* event); + + inline void* getOpenGLContextPointer() { return m_openGLContextPointer; } + private: + class DeleteBufferNameInfo { + public: + DeleteBufferNameInfo(void* openglContextPointer, + const GLuint bufferName) + : m_openglContextPointer(openglContextPointer), + m_bufferName(bufferName) { } + + void* m_openglContextPointer; + GLuint m_bufferName; + }; + + void deleteUnusedBuffers(); + + /** prevents concurrent access to m_buffersForDeletionLater */ + QMutex m_buffersForDeletionLaterMutex; + + /** use a mutex whenever accessing this member */ + std::vector m_buffersForDeletionLater; + + /** Pointer to the current OpenGL Context */ + void* m_openGLContextPointer = 0; + BrainOpenGL(const BrainOpenGL&); BrainOpenGL& operator=(const BrainOpenGL&); protected: + /** + * Draw models in their respective viewports. + * + * @param brain + * The brain (must be valid!) + * @param viewportContents + * Viewport info for drawing. + */ + virtual void drawModelsImplementation(Brain* brain, + std::vector& viewportContents) = 0; + + /** + * Selection on a model. + * + * @param brain + * The brain (must be valid!) + * @param viewportContent + * Viewport content in which mouse was clicked + * @param mouseX + * X position of mouse click + * @param mouseY + * Y position of mouse click + * @param applySelectionBackgroundFiltering + * If true (which is in most cases), if there are multiple items + * selected, those items "behind" other items are not reported. + * For example, suppose a focus is selected and there is a node + * the focus. If this parameter is true, the node will NOT be + * selected. If this parameter is false, the node will be + * selected. + */ + virtual void selectModelImplementation(Brain* brain, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering) = 0; + + /** + * Project the given window coordinate to the active models. + * If the projection is successful, The 'original' XYZ + * coordinate in 'projectionOut' will be valid. In addition, + * the barycentric coordinate may also be valid in 'projectionOut'. + * + * @param brain + * The brain (must be valid!) + * @param viewportContent + * Viewport content in which mouse was clicked + * @param mouseX + * X position of mouse click + * @param mouseY + * Y position of mouse click + */ + virtual void projectToModelImplementation(Brain* brain, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) = 0; + AString getOpenGLEnabledEnumAsText(const AString& enumName, const GLenum enumValue) const; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 6c3fb07a7..cfa800053 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1416,7 +1416,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT * Draw the matrix elements. */ if (m_identificationModeFlag) { - m_graphicsOpenGL->draw(quadsData4ub.get()); + drawPrimitivePrivate(quadsData4ub.get()); } else { /* @@ -1426,7 +1426,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_graphicsOpenGL->draw(quadsData4f.get()); + drawPrimitivePrivate(quadsData4f.get()); glDisable(GL_BLEND); @@ -1453,7 +1453,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } glPolygonMode(GL_FRONT, GL_LINE); glLineWidth(1.0); - m_graphicsOpenGL->draw(outlineData4f.get()); + drawPrimitivePrivate(outlineData4f.get()); glPolygonMode(GL_FRONT, GL_FILL); } @@ -1489,7 +1489,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); glLineWidth(highlightLineWidth); - m_graphicsOpenGL->draw(rowOutlineData4f.get()); + drawPrimitivePrivate(rowOutlineData4f.get()); } glLineWidth(1.0); @@ -1527,7 +1527,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnOutlineData4f->addVertex(colX, maxY); const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); glLineWidth(highlightLineWidth); - m_graphicsOpenGL->draw(columnOutlineData4f.get()); + drawPrimitivePrivate(columnOutlineData4f.get()); } glLineWidth(1.0); } @@ -2012,7 +2012,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); glLineWidth(GRID_LINE_WIDTH); - m_graphicsOpenGL->draw(gridData.get()); + drawPrimitivePrivate(gridData.get()); /* * Region inside the grid's box @@ -2300,7 +2300,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data if (ticksData->isValid()) { glLineWidth(GRID_LINE_WIDTH); - m_graphicsOpenGL->draw(ticksData.get()); + drawPrimitivePrivate(ticksData.get()); } const AString axisTitle = axis->getAxisTitle(); @@ -2359,6 +2359,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data return true; } +/** + * Draw the graphics primitive. + * + * @param primitive + * Primitive that will be drawn. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* primitive) +{ + m_graphicsOpenGL->draw(m_fixedPipelineDrawing->getOpenGLContextPointer(), + primitive); +} + + BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, const ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index ce3c4ae22..036e66adb 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -37,6 +37,7 @@ namespace caret { class ChartableTwoFileMatrixChart; class GraphicsEngineOpenGL; class GraphicsFactory; + class GraphicsPrimitive; class HistogramDrawingInfo; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; @@ -158,6 +159,8 @@ namespace caret { double& widthOut, double& heightOut); + void drawPrimitivePrivate(GraphicsPrimitive* primitive); + Brain* m_brain; ModelChartTwo* m_chartTwoModel; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index a820b5b2f..1ab3689b9 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -252,7 +252,7 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() * * @param brain * The brain (must be valid!) - * @param viewportConent + * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click @@ -267,7 +267,7 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() * selected. */ void -BrainOpenGLFixedPipeline::selectModel(Brain* brain, +BrainOpenGLFixedPipeline::selectModelImplementation(Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, @@ -339,7 +339,7 @@ BrainOpenGLFixedPipeline::selectModel(Brain* brain, * Contains projection result upon exit. */ void -BrainOpenGLFixedPipeline::projectToModel(Brain* brain, +BrainOpenGLFixedPipeline::projectToModelImplementation(Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, @@ -496,17 +496,6 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vectorgetGraphicsEngineOpenGL()->deleteUnusedBuffers(); -} - - /** * Draw models in their respective viewports. * @@ -516,7 +505,7 @@ BrainOpenGLFixedPipeline::deleteOpenGLGraphicsFactoryUnusedBuffers() * Viewport info for drawing. */ void -BrainOpenGLFixedPipeline::drawModels(Brain* brain, +BrainOpenGLFixedPipeline::drawModelsImplementation(Brain* brain, std::vector& viewportContents) { m_brain = brain; @@ -534,8 +523,6 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, this->checkForOpenGLError(NULL, "At beginning of drawModels()"); - deleteOpenGLGraphicsFactoryUnusedBuffers(); - /* * Default the background colors to first model * NOTE: If there are no models, the surface background color is used @@ -665,8 +652,6 @@ BrainOpenGLFixedPipeline::drawModels(Brain* brain, drawWindowAnnotations(windowViewport); } - deleteOpenGLGraphicsFactoryUnusedBuffers(); - this->checkForOpenGLError(NULL, "At end of drawModels()"); m_brain = NULL; diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 04d7a14e9..32db1f74d 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -104,20 +104,6 @@ namespace caret { ~BrainOpenGLFixedPipeline(); - void drawModels(Brain* brain, - std::vector& viewportContents); - - void selectModel(Brain* brain, - BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - const bool applySelectionBackgroundFiltering); - - void projectToModel(Brain* brain, - BrainOpenGLViewportContent* viewportContent, - const int32_t mouseX, - const int32_t mouseY, - SurfaceProjectedItem& projectionOut); void initializeOpenGL(); @@ -132,6 +118,22 @@ namespace caret { virtual BrainOpenGLTextureManager* getTextureManager(); + protected: + void drawModelsImplementation(Brain* brain, + std::vector& viewportContents) override; + + void selectModelImplementation(Brain* brain, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + const bool applySelectionBackgroundFiltering) override; + + void projectToModelImplementation(Brain* brain, + BrainOpenGLViewportContent* viewportContent, + const int32_t mouseX, + const int32_t mouseY, + SurfaceProjectedItem& projectionOut) override; + private: class VolumeDrawInfo { public: @@ -511,7 +513,7 @@ namespace caret { void setTabViewport(const BrainOpenGLViewportContent* vpContent); void setAnnotationColorBarsForDrawing(std::vector& viewportContents); - + /** Index of window */ const int32_t m_windowIndex; diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 06e2e1973..648328a9f 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -500,6 +500,8 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW: case EventTypeEnum::EVENT_GET_VIEWPORT_SIZE: case EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS: + case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT: + case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW: case EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index e277aec27..b194a5f89 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -23,6 +23,7 @@ #undef __EVENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" using namespace caret; @@ -160,6 +161,12 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_CHART_MATRIX_YOKING_VALIDATION, "EVENT_CHART_MATRIX_YOKING_VALIDATION", "Validate Yoking of matrix chart's rows/columns")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, + "EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT", + "Create an OpenGL Buffer Object for an OpenGL Context")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, + "EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT", + "Delete an OpenGL Buffer Object for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, "EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS", "Request OpenGL Graphics Engine delete buffers")); @@ -360,7 +367,11 @@ EventTypeEnum::findData(const Enum enumValue) } } - return NULL; + AString msg("Failed to find EventTypeEnum for an enumerated value. The most likely causes is a failure " + "to add the enumerated value in EventTypeEnum::initialize()"); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return &enumData[0]; // prevent crash } /** diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 94cc9b6aa..d635d3d87 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -108,6 +108,10 @@ public: EVENT_GET_VIEWPORT_SIZE, /** OpenGL graphics engine delete buffers */ EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, + /** Create a buffer object for an OpenGL context */ + EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, + /** Delete a buffer object for an OpenGL context */ + EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, /** Update all graphics windows */ EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, /** Update graphics in a window */ diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 613d1b8c5..274c82d3a 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -33,23 +33,27 @@ ENDIF (OPENGL_FOUND) # ADD_LIBRARY(Graphics CaretOpenGLInclude.h -EventGraphicsEngineOpenGLDeleteBuffers.h +EventGraphicsOpenGLCreateBufferObject.h +EventGraphicsOpenGLDeleteBufferObject.h GraphicsEngine.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsEngineOpenGL.h GraphicsFactory.h +GraphicsOpenGLBufferObject.h GraphicsPrimitive.h GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h -EventGraphicsEngineOpenGLDeleteBuffers.cxx +EventGraphicsOpenGLCreateBufferObject.cxx +EventGraphicsOpenGLDeleteBufferObject.cxx GraphicsEngine.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsEngineOpenGL.cxx GraphicsFactory.cxx +GraphicsOpenGLBufferObject.cxx GraphicsPrimitive.cxx GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx diff --git a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx b/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx deleted file mode 100644 index 970a4651c..000000000 --- a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.cxx +++ /dev/null @@ -1,78 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ -#include "EventGraphicsEngineOpenGLDeleteBuffers.h" -#undef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ - -#include "CaretAssert.h" -#include "EventTypeEnum.h" - -using namespace caret; - - - -/** - * \class caret::EventGraphicsEngineOpenGLDeleteBuffers - * \brief Event for deleting OpenGL buffers created by the OpenGL Graphics Engine - * \ingroup Graphics - */ - -/** - * Constructor. - * - * @param bufferIdentifiers - * Identifiers of buffers for deletion. - */ -EventGraphicsEngineOpenGLDeleteBuffers::EventGraphicsEngineOpenGLDeleteBuffers(const std::vector& bufferIdentifiers) -: Event(EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) -{ - m_bufferIdentifiers = bufferIdentifiers; -} - -/** - * Constructor. - * - * @param bufferIdentifier - * Identifier of buffer for deletion. - */ -EventGraphicsEngineOpenGLDeleteBuffers::EventGraphicsEngineOpenGLDeleteBuffers(const GLuint bufferIdentifier) -: Event(EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) -{ - m_bufferIdentifiers.push_back(bufferIdentifier); -} - -/** - * Destructor. - */ -EventGraphicsEngineOpenGLDeleteBuffers::~EventGraphicsEngineOpenGLDeleteBuffers() -{ -} - -/** - * @return Identifiers of OpenGL buffers for deletion. - */ -std::vector -EventGraphicsEngineOpenGLDeleteBuffers::getBufferIdentifiers() const -{ - return m_bufferIdentifiers; -} - diff --git a/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx new file mode 100644 index 000000000..4d4a155bf --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx @@ -0,0 +1,102 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ +#include "EventGraphicsOpenGLCreateBufferObject.h" +#undef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventGraphicsOpenGLDeleteBufferObject.h" +#include "EventManager.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsOpenGLCreateBufferObject + * \brief Create an OpenGL Buffer Object + * \ingroup Graphics + * + * Creates an OpenGL Buffer Object for the current context. + * There MUST BE an active OpenGL context when this event + * is processed. Otherwise, a buffer object cannot be + * created and a program will likely occur. + */ + +/** + * Constructor. + */ +EventGraphicsOpenGLCreateBufferObject::EventGraphicsOpenGLCreateBufferObject() +: Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT) +{ + +} + +/** + * Destructor. + */ +EventGraphicsOpenGLCreateBufferObject::~EventGraphicsOpenGLCreateBufferObject() +{ + if (m_openglBufferObject != NULL) { + /* + * If the caller did not get the buffer object we need to delete it. + */ + CaretLogSevere("Create OpenGL Buffer Object Event never had buffer object retrieved. Will attempt to delete it."); + EventGraphicsOpenGLDeleteBufferObject deleteEvent(m_openglBufferObject); + EventManager::get()->sendEvent(deleteEvent.getPointer()); + } +} + +/** + * Set the OpenGL Buffer Object. + * + * @param openglBufferObject + * The OpenGL Buffer Object. This instance will take ownership of the buffer so the caller + * MUST NOT ever reference the buffer object after calling this method. + */ +void +EventGraphicsOpenGLCreateBufferObject::setOpenGLBufferObject(GraphicsOpenGLBufferObject* openglBufferObject) +{ + m_openglBufferObject = openglBufferObject; +} + +/** + * @return OpenGL Buffer Object that was created or NULL if + * unable to create buffer object due to no valid context. + * Caller takes ownership of the buffer object. If this method + * is called more than once for an instance, NULL will be + * returned the second and all subsequent times. + */ +GraphicsOpenGLBufferObject* +EventGraphicsOpenGLCreateBufferObject::getOpenGLBufferObject() const +{ + /* + * Do not let buffer object be retrieved more than once. + */ + GraphicsOpenGLBufferObject* bufferObjectPointer = m_openglBufferObject; + m_openglBufferObject = NULL; + + return bufferObjectPointer; +} + diff --git a/src/Graphics/EventGraphicsOpenGLCreateBufferObject.h b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.h new file mode 100644 index 000000000..127f53336 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.h @@ -0,0 +1,64 @@ +#ifndef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ +#define __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "Event.h" + + + +namespace caret { + + class GraphicsOpenGLBufferObject; + + class EventGraphicsOpenGLCreateBufferObject : public Event { + + public: + EventGraphicsOpenGLCreateBufferObject(); + + virtual ~EventGraphicsOpenGLCreateBufferObject(); + + void setOpenGLBufferObject(GraphicsOpenGLBufferObject* openglBufferObject); + + GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; + + // ADD_NEW_METHODS_HERE + + private: + EventGraphicsOpenGLCreateBufferObject(const EventGraphicsOpenGLCreateBufferObject&); + + EventGraphicsOpenGLCreateBufferObject& operator=(const EventGraphicsOpenGLCreateBufferObject&); + + mutable GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; + + mutable bool m_openglBufferObjectWasTakenFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ + // +#endif // __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ + +} // namespace +#endif //__EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ diff --git a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx new file mode 100644 index 000000000..7d587ad23 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx @@ -0,0 +1,87 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ +#include "EventGraphicsOpenGLDeleteBufferObject.h" +#undef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventTypeEnum.h" +#include "GraphicsOpenGLBufferObject.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsOpenGLDeleteBufferObject + * \brief Delete an OpenGL Buffer Object + * \ingroup Graphics + * + * Deletes an OpenGL Buffer Object for the current context. + */ +/** + * Constructor. + * + * @param openglBufferObject + * The OpenGL Buffer Object. This instance will take ownership of the buffer so the caller + * MUST NOT ever reference the buffer object after calling this method. + */ +EventGraphicsOpenGLDeleteBufferObject::EventGraphicsOpenGLDeleteBufferObject(GraphicsOpenGLBufferObject* openglBufferObject) +: Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT), +m_openglBufferObject(openglBufferObject) +{ + +} + +/** + * Destructor. + */ +EventGraphicsOpenGLDeleteBufferObject::~EventGraphicsOpenGLDeleteBufferObject() +{ + if (m_openglBufferObject != NULL) { + CaretLogSevere("Failure to delete OpenGL Buffer Object Name=" + + AString::number(m_openglBufferObject->getBufferObjectName()) + + ", context pointer=" + + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer())); + } +} + +/** + * @return OpenGL Buffer Object that was created or NULL if + * unable to create buffer object due to no valid context. + * Caller takes ownership of the buffer object. If this method + * is called more than once, NULL will be returned the second + * and all subsequent times. + */ +GraphicsOpenGLBufferObject* +EventGraphicsOpenGLDeleteBufferObject::getOpenGLBufferObject() const +{ + /* + * Do not let buffer object be retrieved more than once. + */ + GraphicsOpenGLBufferObject* bufferObjectPointer = m_openglBufferObject; + m_openglBufferObject = NULL; + + return bufferObjectPointer; +} + diff --git a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h similarity index 52% rename from src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h rename to src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h index ea4a2f655..103370a3b 100644 --- a/src/Graphics/EventGraphicsEngineOpenGLDeleteBuffers.h +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h @@ -1,5 +1,5 @@ -#ifndef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ -#define __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ +#ifndef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ +#define __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ /*LICENSE_START*/ /* @@ -22,43 +22,39 @@ /*LICENSE_END*/ - -#include - -#include "CaretOpenGLInclude.h" #include "Event.h" namespace caret { - class EventGraphicsEngineOpenGLDeleteBuffers : public Event { + class GraphicsOpenGLBufferObject; + + class EventGraphicsOpenGLDeleteBufferObject : public Event { public: - EventGraphicsEngineOpenGLDeleteBuffers(const std::vector& bufferIdentifiers); + EventGraphicsOpenGLDeleteBufferObject(GraphicsOpenGLBufferObject* openglBufferObject); - EventGraphicsEngineOpenGLDeleteBuffers(const GLuint bufferIdentifier); + virtual ~EventGraphicsOpenGLDeleteBufferObject(); + + GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; - virtual ~EventGraphicsEngineOpenGLDeleteBuffers(); - - std::vector getBufferIdentifiers() const; - // ADD_NEW_METHODS_HERE - + private: - EventGraphicsEngineOpenGLDeleteBuffers(const EventGraphicsEngineOpenGLDeleteBuffers&); + EventGraphicsOpenGLDeleteBufferObject(const EventGraphicsOpenGLDeleteBufferObject&); - EventGraphicsEngineOpenGLDeleteBuffers& operator=(const EventGraphicsEngineOpenGLDeleteBuffers&); + EventGraphicsOpenGLDeleteBufferObject& operator=(const EventGraphicsOpenGLDeleteBufferObject&); - std::vector m_bufferIdentifiers; - // ADD_NEW_MEMBERS_HERE + mutable GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; + // ADD_NEW_MEMBERS_HERE }; -#ifdef __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ +#ifdef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ // -#endif // __EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_DECLARE__ +#endif // __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ } // namespace -#endif //__EVENT_GRAPHICS_ENGINE_OPEN_G_L_DELETE_BUFFERS_H__ +#endif //__EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ diff --git a/src/Graphics/GraphicsEngine.h b/src/Graphics/GraphicsEngine.h index c4fd40e56..0cb4e7aa7 100644 --- a/src/Graphics/GraphicsEngine.h +++ b/src/Graphics/GraphicsEngine.h @@ -47,7 +47,8 @@ namespace caret { * @param primitive * Primitive that is drawn. */ - virtual void draw(GraphicsPrimitive* primitive) = 0; + virtual void draw(void* graphicsContextPointer, + GraphicsPrimitive* primitive) = 0; // ADD_NEW_METHODS_HERE diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 5ac7ad6f6..587618ddd 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -24,8 +24,9 @@ #undef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ #include "CaretAssert.h" -#include "EventGraphicsEngineOpenGLDeleteBuffers.h" +#include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventManager.h" +#include "GraphicsOpenGLBufferObject.h" #include "GraphicsPrimitive.h" using namespace caret; @@ -55,30 +56,34 @@ GraphicsEngineDataOpenGL::~GraphicsEngineDataOpenGL() deleteBuffers(); } +/** + * Delete an OpenGL buffer object. + * + * @param bufferObject + * Reference to pointer of buffer object for deletion. + * If NULL, no action is taken. + * Will be NULL upon exit. + */ void -GraphicsEngineDataOpenGL::deleteBuffers() +GraphicsEngineDataOpenGL::deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject) { - std::vector bufferIDs; - - if (m_coordinateBufferID > 0) { - bufferIDs.push_back(m_coordinateBufferID); + if (bufferObject != NULL) { + delete bufferObject; + bufferObject = NULL; } - m_coordinateBufferID = 0; - - if (m_normalVectorBufferID > 0) { - bufferIDs.push_back(m_normalVectorBufferID); - } - m_normalVectorBufferID = 0; +} + +/** + * Delete the OpenGL buffer objects. + */ +void +GraphicsEngineDataOpenGL::deleteBuffers() +{ + deleteBufferObjectHelper(m_coordinateBufferObject); - if (m_colorBufferID > 0) { - bufferIDs.push_back(m_colorBufferID); - } - m_colorBufferID = 0; + deleteBufferObjectHelper(m_normalVectorBufferObject); - if ( ! bufferIDs.empty()) { - EventGraphicsEngineOpenGLDeleteBuffers buffersEvent(bufferIDs); - EventManager::get()->sendEvent(buffersEvent.getPointer()); - } + deleteBufferObjectHelper(m_colorBufferObject); } @@ -103,9 +108,13 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) const GLuint xyzSizeBytes = coordinateCount * sizeof(float); const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; - glGenBuffers(1, &m_coordinateBufferID); + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_coordinateBufferObject->getBufferObjectName()); + glBindBuffer(GL_ARRAY_BUFFER, - m_coordinateBufferID); + m_coordinateBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, xyzSizeBytes, xyzDataPointer, @@ -129,9 +138,13 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; - glGenBuffers(1, &m_normalVectorBufferID); + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_normalVectorBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_normalVectorBufferObject->getBufferObjectName()); + glBindBuffer(GL_ARRAY_BUFFER, - m_normalVectorBufferID); + m_normalVectorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, normalSizeBytes, normalDataPointer, @@ -140,10 +153,14 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) break; } - glGenBuffers(1, &m_colorBufferID); switch (primitive->m_colorType) { case GraphicsPrimitive::ColorType::FLOAT_RGBA: { + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_colorBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_colorBufferObject->getBufferObjectName()); + m_componentsPerColor = 4; m_colorDataType = GL_FLOAT; @@ -151,7 +168,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, - m_colorBufferID); + m_colorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, @@ -160,6 +177,11 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) break; case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: { + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_colorBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_colorBufferObject->getBufferObjectName()); + m_componentsPerColor = 4; m_colorDataType = GL_UNSIGNED_BYTE; @@ -167,7 +189,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, - m_colorBufferID); + m_colorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 5bb695e42..b51bae9f7 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -31,6 +31,7 @@ namespace caret { + class GraphicsOpenGLBufferObject; class GraphicsPrimitive; class GraphicsEngineDataOpenGL : public GraphicsEngineData { @@ -51,19 +52,22 @@ namespace caret { GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); + void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); + GLsizei m_arrayIndicesCount = 0; - GLuint m_coordinateBufferID = 0; + /** Coordinate buffer object WE DO NOT DELETE THIS */ + GraphicsOpenGLBufferObject* m_coordinateBufferObject = NULL; GLenum m_coordinateDataType = GL_FLOAT; GLint m_coordinatesPerVertex = 0; - GLuint m_normalVectorBufferID = 0; + GraphicsOpenGLBufferObject* m_normalVectorBufferObject = NULL; GLenum m_normalVectorDataType = GL_FLOAT; - GLuint m_colorBufferID = 0; + GraphicsOpenGLBufferObject* m_colorBufferObject = NULL; GLenum m_colorDataType = GL_FLOAT; diff --git a/src/Graphics/GraphicsEngineOpenGL.cxx b/src/Graphics/GraphicsEngineOpenGL.cxx index f2191b0db..9a7df9cdd 100644 --- a/src/Graphics/GraphicsEngineOpenGL.cxx +++ b/src/Graphics/GraphicsEngineOpenGL.cxx @@ -26,10 +26,11 @@ #include #include "CaretAssert.h" +#include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "GraphicsEngineDataOpenGL.h" -#include "EventGraphicsEngineOpenGLDeleteBuffers.h" #include "EventManager.h" +#include "GraphicsOpenGLBufferObject.h" #include "GraphicsPrimitive.h" using namespace caret; @@ -48,8 +49,6 @@ using namespace caret; GraphicsEngineOpenGL::GraphicsEngineOpenGL() : GraphicsEngine() { - EventManager::get()->addEventListener(this, - EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS); } /** @@ -57,7 +56,6 @@ GraphicsEngineOpenGL::GraphicsEngineOpenGL() */ GraphicsEngineOpenGL::~GraphicsEngineOpenGL() { - EventManager::get()->removeAllEventsFromListener(this); } /** @@ -69,59 +67,20 @@ GraphicsEngineOpenGL::~GraphicsEngineOpenGL() void GraphicsEngineOpenGL::receiveEvent(Event* event) { - if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS) { - EventGraphicsEngineOpenGLDeleteBuffers* bufferEvent - = dynamic_cast(event); - CaretAssert(bufferEvent); - event->setEventProcessed(); - - std::vector bufferIDs = bufferEvent->getBufferIdentifiers(); - - QMutexLocker locker(&m_unusedBufferIdentifiersMutex); - - m_unusedBufferIdentifiers.insert(m_unusedBufferIdentifiers.end(), - bufferIDs.begin(), bufferIDs.end()); - } - else { - GraphicsEngine::receiveEvent(event); - } -} - -/** - * This method must be called only when the OpenGL context - * is current. - */ -void -GraphicsEngineOpenGL::deleteUnusedBuffers() -{ - const GLsizei numberOfIDs = m_unusedBufferIdentifiers.size(); - if (numberOfIDs > 0) { - QMutexLocker locker(&m_unusedBufferIdentifiersMutex); - - for (GLuint buffID : m_unusedBufferIdentifiers) { - if ( ! glIsBuffer(buffID)) { - std::cout << "Attempting to delete invalid buffer ID: " << buffID << std::endl; - } - } - - const GLuint* idsPointer = &m_unusedBufferIdentifiers[0]; - glDeleteBuffers(numberOfIDs, - idsPointer); - m_unusedBufferIdentifiers.clear(); - - std::cout << "Deleted " << numberOfIDs << " buffers." << std::endl; - } + GraphicsEngine::receiveEvent(event); } - /** * Draw the given graphics primitive. * + * @param openglContextPointer + * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. */ void -GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) +GraphicsEngineOpenGL::draw(void* openglContextPointer, + GraphicsPrimitive* primitive) { CaretAssert(primitive); if ( ! primitive->isValid()) { @@ -136,96 +95,18 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) openglData->loadBuffers(primitive); } -// GLenum coordinateDataType = GL_FLOAT; -// GLint coordinatesPerVertex = 0; -// GLuint coordinateBufferID = 0; -// GLsizei coordinateCount = 0; -// switch (primitive->m_vertexType) { -// case GraphicsPrimitive::VertexType::FLOAT_XYZ: -// coordinateDataType = GL_FLOAT; -// coordinatesPerVertex = 3; // X, Y, Z -// -// coordinateCount = primitive->m_xyz.size(); -// const GLuint xyzSizeBytes = coordinateCount * sizeof(float); -// const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; -// -// glGenBuffers(1, &coordinateBufferID); -// glBindBuffer(GL_ARRAY_BUFFER, -// coordinateBufferID); -// glBufferData(GL_ARRAY_BUFFER, -// xyzSizeBytes, -// xyzDataPointer, -// GL_STREAM_DRAW); -// break; -// } -// -// GLenum normalVectorDataType = GL_FLOAT; -// GLuint normalBufferID = 0; -// switch (primitive->m_normalVectorType) { -// case GraphicsPrimitive::NormalVectorType::NONE: -// break; -// case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: -// { -// normalVectorDataType = GL_FLOAT; -// const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); -// const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; -// -// glGenBuffers(1, &normalBufferID); -// glBindBuffer(GL_ARRAY_BUFFER, -// normalBufferID); -// glBufferData(GL_ARRAY_BUFFER, -// normalSizeBytes, -// normalDataPointer, -// GL_STREAM_DRAW); -// } -// break; -// } -// -// GLenum colorDataType = GL_FLOAT; -// GLint componentsPerColor = 0; -// GLuint colorBufferID = 0; -// glGenBuffers(1, &colorBufferID); -// switch (primitive->m_colorType) { -// case GraphicsPrimitive::ColorType::FLOAT_RGBA: -// { -// componentsPerColor = 4; -// colorDataType = GL_FLOAT; -// -// const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); -// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; -// -// glBindBuffer(GL_ARRAY_BUFFER, -// colorBufferID); -// glBufferData(GL_ARRAY_BUFFER, -// colorSizeBytes, -// colorDataPointer, -// GL_STREAM_DRAW); -// } -// break; -// case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: -// { -// componentsPerColor = 4; -// colorDataType = GL_UNSIGNED_BYTE; -// -// const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); -// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; -// -// glBindBuffer(GL_ARRAY_BUFFER, -// colorBufferID); -// glBufferData(GL_ARRAY_BUFFER, -// colorSizeBytes, -// colorDataPointer, -// GL_STREAM_DRAW); -// } -// break; -// } - + const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); + CaretAssert(coordBufferID); + if ( ! glIsBuffer(coordBufferID)) { + std::cout << "Coordinate buffer is INVALID" << std::endl; + } + /* * Setup vertices for drawing */ glEnableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, - openglData->m_coordinateBufferID); + coordBufferID); glVertexPointer(openglData->m_coordinatesPerVertex, openglData->m_coordinateDataType, 0, @@ -234,9 +115,9 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) /* * Setup normals for drawing */ - if (openglData->m_normalVectorBufferID > 0) { + if (openglData->m_normalVectorBufferObject != NULL) { glEnableClientState(GL_NORMAL_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferID); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferObject->getBufferObjectName()); glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); } else { @@ -247,7 +128,7 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) * Setup colors for drawing */ glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferID); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); /* @@ -261,7 +142,6 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) /* * Draw the primitive */ -// const GLsizei indicesCount = openglDatacoordinateCount / coordinatesPerVertex; GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::LINE_LOOP: @@ -305,18 +185,5 @@ GraphicsEngineOpenGL::draw(GraphicsPrimitive* primitive) glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - - -// /* -// * Delete buffers -// */ -// glDeleteBuffers(1, -// &coordinateBufferID); -// if (normalBufferID > 0) { -// glDeleteBuffers(1, -// &normalBufferID); -// } -// glDeleteBuffers(1, -// &colorBufferID); } diff --git a/src/Graphics/GraphicsEngineOpenGL.h b/src/Graphics/GraphicsEngineOpenGL.h index 146e7e0ae..81d77dab4 100644 --- a/src/Graphics/GraphicsEngineOpenGL.h +++ b/src/Graphics/GraphicsEngineOpenGL.h @@ -21,10 +21,6 @@ */ /*LICENSE_END*/ -#include - -#include - #include "CaretOpenGLInclude.h" #include "GraphicsEngine.h" @@ -32,6 +28,8 @@ namespace caret { + class GraphicsOpenGLBufferObject; + class GraphicsEngineOpenGL : public GraphicsEngine { public: @@ -41,24 +39,17 @@ namespace caret { virtual void receiveEvent(Event* event); - virtual void draw(GraphicsPrimitive* primitive); + virtual void draw(void* openglContextPointer, + GraphicsPrimitive* primitive); - void deleteUnusedBuffers(); - // ADD_NEW_METHODS_HERE private: + GraphicsEngineOpenGL(const GraphicsEngineOpenGL&); GraphicsEngineOpenGL& operator=(const GraphicsEngineOpenGL&); - /** prevents concurrent access to m_unusedBufferIdentifiers */ - QMutex m_unusedBufferIdentifiersMutex; - - /** use a mutex whenever accessing this member */ - std::vector m_unusedBufferIdentifiers; - - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsOpenGLBufferObject.cxx b/src/Graphics/GraphicsOpenGLBufferObject.cxx new file mode 100644 index 000000000..988259a17 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLBufferObject.cxx @@ -0,0 +1,77 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ +#include "GraphicsOpenGLBufferObject.h" +#undef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ + +#include "CaretAssert.h" +#include "EventGraphicsOpenGLDeleteBufferObject.h" +#include "EventManager.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLBufferObject + * \brief Contains the OpenGL Buffer ID and the context in which it was created. + * \ingroup Graphics + */ + +/** + * Constructor. + * + * @param openglContextPointer + * Pointer to OpenGL context in which buffer object name was created. + * @param bufferObjectName + * The OpenGL buffer object name. + */ +GraphicsOpenGLBufferObject::GraphicsOpenGLBufferObject(void* openglContextPointer, + const GLuint bufferObjectName) +: CaretObject(), +m_openglContextPointer(openglContextPointer), +m_bufferObjectName(bufferObjectName) +{ + +} + +/** + * Destructor. + */ +GraphicsOpenGLBufferObject::~GraphicsOpenGLBufferObject() +{ + if (m_bufferObjectName > 0) { + EventGraphicsOpenGLDeleteBufferObject deleteEvent(this); + EventManager::get()->sendEvent(deleteEvent.getPointer()); + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsOpenGLBufferObject::toString() const +{ + return "GraphicsOpenGLBufferObject"; +} + diff --git a/src/Graphics/GraphicsOpenGLBufferObject.h b/src/Graphics/GraphicsOpenGLBufferObject.h new file mode 100644 index 000000000..68f7f2a70 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLBufferObject.h @@ -0,0 +1,75 @@ +#ifndef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ +#define __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretOpenGLInclude.h" +#include "CaretObject.h" + + + +namespace caret { + + class GraphicsOpenGLBufferObject : public CaretObject { + + private: + GraphicsOpenGLBufferObject(void* openglContextPointer, + const GLuint bufferObjectName); + + public: + virtual ~GraphicsOpenGLBufferObject(); + + /** + * @return Pointer to OpenGL context in which buffer object was created. + */ + inline void* getOpenGLContextPointer() const { return m_openglContextPointer; } + + /** + * @return The OpenGL Buffer Object Name. + * While it is an unsigned interger, OpenGL refers to it as a "name". + */ + inline GLuint getBufferObjectName() const { return m_bufferObjectName; } + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + GraphicsOpenGLBufferObject(const GraphicsOpenGLBufferObject&); + + GraphicsOpenGLBufferObject& operator=(const GraphicsOpenGLBufferObject&); + + void* m_openglContextPointer = NULL; + + const GLuint m_bufferObjectName = 0; + + friend class BrainOpenGL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ + // +#endif // __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index f9fec0099..8c15e71e6 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -559,6 +559,7 @@ BrainOpenGLWidget::paintGL() this->openGL->setBorderBeingDrawn(NULL); } this->openGL->drawModels(GuiManager::get()->getBrain(), + this->context(), this->drawingViewportContents); /* @@ -1088,6 +1089,7 @@ BrainOpenGLWidget::performIdentification(const int x, if (idViewport != NULL) { this->openGL->selectModel(GuiManager::get()->getBrain(), + this->context(), idViewport, x, y, @@ -1148,6 +1150,7 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int idY = y - vp[1]; */ this->openGL->selectModel(GuiManager::get()->getBrain(), + this->context(), idViewport, x, y, @@ -1210,6 +1213,7 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi const int idY = y - vp[1]; */ this->openGL->selectModel(GuiManager::get()->getBrain(), + this->context(), idViewport, x, y, @@ -1263,6 +1267,7 @@ BrainOpenGLWidget::performProjection(const int x, const int idY = y - vp[1]; */ this->openGL->projectToModel(GuiManager::get()->getBrain(), + this->context(), projectionViewport, x, y, diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 80e608143..504b22d20 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -479,6 +479,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, tabIndexToHighlight); brainOpenGL->drawModels(brain, + mesaContext, viewports); const int32_t outputImageIndex = ((numBrowserClasses > 1) @@ -535,6 +536,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, viewportContents.push_back(content); brainOpenGL->drawModels(brain, + mesaContext, viewportContents); const int32_t outputImageIndex = ((numBrowserClasses > 1) -- GitLab From 4bb2f57060aa6b7967fcf9abf31c51bf99b7d960 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 18 Apr 2017 16:28:56 -0500 Subject: [PATCH 253/755] Cleanup and consolidation of the Graphics module and its classes. --- src/Brain/BrainOpenGL.cxx | 8 +- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 25 +-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 - src/Brain/BrainOpenGLFixedPipeline.cxx | 2 - src/Brain/SessionManager.cxx | 8 - src/Graphics/CMakeLists.txt | 6 - .../EventGraphicsOpenGLCreateBufferObject.cxx | 2 +- .../EventGraphicsOpenGLDeleteBufferObject.cxx | 22 +- .../EventGraphicsOpenGLDeleteBufferObject.h | 6 +- src/Graphics/GraphicsEngine.cxx | 82 ------- src/Graphics/GraphicsEngine.h | 73 ------- src/Graphics/GraphicsEngineDataOpenGL.cxx | 149 ++++++++++++- src/Graphics/GraphicsEngineDataOpenGL.h | 12 +- src/Graphics/GraphicsEngineOpenGL.cxx | 189 ---------------- src/Graphics/GraphicsEngineOpenGL.h | 62 ------ src/Graphics/GraphicsFactory.cxx | 201 ------------------ src/Graphics/GraphicsFactory.h | 89 -------- src/Graphics/GraphicsPrimitive.cxx | 63 ++++++ src/Graphics/GraphicsPrimitive.h | 16 +- 19 files changed, 255 insertions(+), 765 deletions(-) delete mode 100644 src/Graphics/GraphicsEngine.cxx delete mode 100644 src/Graphics/GraphicsEngine.h delete mode 100644 src/Graphics/GraphicsEngineOpenGL.cxx delete mode 100644 src/Graphics/GraphicsEngineOpenGL.h delete mode 100644 src/Graphics/GraphicsFactory.cxx delete mode 100644 src/Graphics/GraphicsFactory.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 3667c66c1..75e8b47e7 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -114,7 +114,7 @@ BrainOpenGL::receiveEvent(Event* event) EventGraphicsOpenGLDeleteBufferObject* deleteBufferEvent = dynamic_cast(event); CaretAssert(deleteBufferEvent); - GraphicsOpenGLBufferObject* bufferObject = deleteBufferEvent->getOpenGLBufferObject(); + const GraphicsOpenGLBufferObject* bufferObject = deleteBufferEvent->getOpenGLBufferObject(); if (bufferObject != NULL) { m_buffersForDeletionLater.emplace(m_buffersForDeletionLater.end(), bufferObject->getOpenGLContextPointer(), @@ -262,13 +262,13 @@ BrainOpenGL::deleteUnusedBuffers() glDeleteBuffers(bufferNames.size(), namesPointer); m_buffersForDeletionLater.clear(); - - std::cout << "Deleted " << bufferNames.size() << " buffers." << std::endl; } m_buffersForDeletionLater = otherContextBufferIdentifiers; if ( ! m_buffersForDeletionLater.empty()) { - std::cout << "Not deleting " << m_buffersForDeletionLater.size() << " in another OpenGL Context." << std::endl; + CaretLogWarning("Not deleting " + + AString::number(m_buffersForDeletionLater.size()) + + " in another OpenGL Context."); } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index cfa800053..6ac952bd6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -45,8 +45,7 @@ #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "FastStatistics.h" -#include "GraphicsEngineOpenGL.h" -#include "GraphicsFactory.h" +#include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" @@ -78,10 +77,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline : BrainOpenGLChartTwoDrawingInterface() { m_preferences = SessionManager::get()->getCaretPreferences(); - m_graphicsFactory = GraphicsFactory::get(); - CaretAssert(m_graphicsFactory); - m_graphicsOpenGL = m_graphicsFactory->getGraphicsEngineOpenGL(); - CaretAssert(m_graphicsOpenGL); } /** @@ -1296,9 +1291,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT int32_t rgbaOffset = 0; std::unique_ptr quadsData4f - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); std::unique_ptr quadsData4ub - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { @@ -1443,7 +1438,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT gridLineColorFloats[3] = 1.0; std::unique_ptr outlineData4f - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, gridLineColorFloats)); const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); const int32_t numCells = static_cast(gridXYZ.size() / 3); @@ -1480,7 +1475,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float maxX = maxColumn * cellWidth; std::unique_ptr rowOutlineData4f - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, highlightRGBA)); rowOutlineData4f->addVertex(minX, rowY); @@ -1518,7 +1513,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float maxY = maxRow * cellHeight; std::unique_ptr columnOutlineData4f - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, highlightRGBA)); columnOutlineData4f->addVertex(colX, minY); @@ -2000,7 +1995,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons glLoadIdentity(); std::unique_ptr gridData - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); @@ -2206,7 +2201,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); std::unique_ptr ticksData - = std::unique_ptr(m_graphicsFactory->newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); const bool showTicksEnabledFlag = axis->isShowTickmarks(); @@ -2368,8 +2363,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data void BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* primitive) { - m_graphicsOpenGL->draw(m_fixedPipelineDrawing->getOpenGLContextPointer(), - primitive); + GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getOpenGLContextPointer(), + primitive); } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 036e66adb..c7d338791 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -35,8 +35,6 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; - class GraphicsEngineOpenGL; - class GraphicsFactory; class GraphicsPrimitive; class HistogramDrawingInfo; class SelectionItemChartTwoHistogram; @@ -195,9 +193,6 @@ namespace caret { bool m_identificationModeFlag; - GraphicsFactory* m_graphicsFactory = NULL; - GraphicsEngineOpenGL* m_graphicsOpenGL = NULL; - static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 1ab3689b9..c407ed93f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -102,8 +102,6 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" -#include "GraphicsEngineOpenGL.h" -#include "GraphicsFactory.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index b1fa240f6..1cd719d43 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -45,7 +45,6 @@ #include "EventModelDelete.h" #include "EventModelGetAll.h" #include "EventProgressUpdate.h" -#include "GraphicsFactory.h" #include "ImageCaptureSettings.h" #include "LogManager.h" #include "MapYokingGroupEnum.h" @@ -153,11 +152,6 @@ SessionManager::createSessionManager(const ApplicationTypeEnum::Enum application */ EventManager::createEventManager(); - /* - * Create the graphics factory. - */ - GraphicsFactory::createGraphicsFactory(); - /* * Create session manager. */ @@ -177,8 +171,6 @@ SessionManager::deleteSessionManager() delete s_singletonSessionManager; s_singletonSessionManager = NULL; - GraphicsFactory::deleteGraphicsFactory(); - /* * Session manager must be deleted before the event * manager is deleted. diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 274c82d3a..d7a9b62f4 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -35,11 +35,8 @@ ADD_LIBRARY(Graphics CaretOpenGLInclude.h EventGraphicsOpenGLCreateBufferObject.h EventGraphicsOpenGLDeleteBufferObject.h -GraphicsEngine.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h -GraphicsEngineOpenGL.h -GraphicsFactory.h GraphicsOpenGLBufferObject.h GraphicsPrimitive.h GraphicsPrimitiveV3f.h @@ -48,11 +45,8 @@ GraphicsPrimitiveV3fC4ub.h EventGraphicsOpenGLCreateBufferObject.cxx EventGraphicsOpenGLDeleteBufferObject.cxx -GraphicsEngine.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx -GraphicsEngineOpenGL.cxx -GraphicsFactory.cxx GraphicsOpenGLBufferObject.cxx GraphicsPrimitive.cxx GraphicsPrimitiveV3f.cxx diff --git a/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx index 4d4a155bf..db65fe6ef 100644 --- a/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx +++ b/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx @@ -41,7 +41,7 @@ using namespace caret; * Creates an OpenGL Buffer Object for the current context. * There MUST BE an active OpenGL context when this event * is processed. Otherwise, a buffer object cannot be - * created and a program will likely occur. + * created and a program failure will likely occur. */ /** diff --git a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx index 7d587ad23..110a45244 100644 --- a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx @@ -43,10 +43,10 @@ using namespace caret; * Constructor. * * @param openglBufferObject - * The OpenGL Buffer Object. This instance will take ownership of the buffer so the caller - * MUST NOT ever reference the buffer object after calling this method. + * The OpenGL Buffer Object whose buffer name is deleted. + * After this event the openglBufferObject should be deleted by the caller. */ -EventGraphicsOpenGLDeleteBufferObject::EventGraphicsOpenGLDeleteBufferObject(GraphicsOpenGLBufferObject* openglBufferObject) +EventGraphicsOpenGLDeleteBufferObject::EventGraphicsOpenGLDeleteBufferObject(const GraphicsOpenGLBufferObject* openglBufferObject) : Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT), m_openglBufferObject(openglBufferObject) { @@ -67,21 +67,11 @@ EventGraphicsOpenGLDeleteBufferObject::~EventGraphicsOpenGLDeleteBufferObject() } /** - * @return OpenGL Buffer Object that was created or NULL if - * unable to create buffer object due to no valid context. - * Caller takes ownership of the buffer object. If this method - * is called more than once, NULL will be returned the second - * and all subsequent times. + * @return OpenGL Buffer Object that was deletedc */ -GraphicsOpenGLBufferObject* +const GraphicsOpenGLBufferObject* EventGraphicsOpenGLDeleteBufferObject::getOpenGLBufferObject() const { - /* - * Do not let buffer object be retrieved more than once. - */ - GraphicsOpenGLBufferObject* bufferObjectPointer = m_openglBufferObject; - m_openglBufferObject = NULL; - - return bufferObjectPointer; + return m_openglBufferObject; } diff --git a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h index 103370a3b..9efb4cdee 100644 --- a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h @@ -33,11 +33,11 @@ namespace caret { class EventGraphicsOpenGLDeleteBufferObject : public Event { public: - EventGraphicsOpenGLDeleteBufferObject(GraphicsOpenGLBufferObject* openglBufferObject); + EventGraphicsOpenGLDeleteBufferObject(const GraphicsOpenGLBufferObject* openglBufferObject); virtual ~EventGraphicsOpenGLDeleteBufferObject(); - GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; + const GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; // ADD_NEW_METHODS_HERE @@ -46,7 +46,7 @@ namespace caret { EventGraphicsOpenGLDeleteBufferObject& operator=(const EventGraphicsOpenGLDeleteBufferObject&); - mutable GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; + const GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; // ADD_NEW_MEMBERS_HERE diff --git a/src/Graphics/GraphicsEngine.cxx b/src/Graphics/GraphicsEngine.cxx deleted file mode 100644 index d8523531d..000000000 --- a/src/Graphics/GraphicsEngine.cxx +++ /dev/null @@ -1,82 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __GRAPHICS_ENGINE_DECLARE__ -#include "GraphicsEngine.h" -#undef __GRAPHICS_ENGINE_DECLARE__ - -#include "CaretAssert.h" -#include "EventManager.h" -using namespace caret; - - - -/** - * \class caret::GraphicsEngine - * \brief Abstract class for rending graphics objects. - * \ingroup Graphics - */ - -/** - * Constructor. - */ -GraphicsEngine::GraphicsEngine() -: CaretObject() -{ - -// EventManager::get()->addEventListener(this, EventTypeEnum::); -} - -/** - * Destructor. - */ -GraphicsEngine::~GraphicsEngine() -{ - EventManager::get()->removeAllEventsFromListener(this); -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -GraphicsEngine::toString() const -{ - return "GraphicsEngine"; -} - -/** - * Receive an event. - * - * @param event - * An event for which this instance is listening. - */ -void -GraphicsEngine::receiveEvent(Event* event) -{ -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } -} - diff --git a/src/Graphics/GraphicsEngine.h b/src/Graphics/GraphicsEngine.h deleted file mode 100644 index 0cb4e7aa7..000000000 --- a/src/Graphics/GraphicsEngine.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __GRAPHICS_ENGINE_H__ -#define __GRAPHICS_ENGINE_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "CaretObject.h" - -#include "EventListenerInterface.h" - - -namespace caret { - - class GraphicsPrimitive; - - class GraphicsEngine : public CaretObject, public EventListenerInterface { - - public: - GraphicsEngine(); - - virtual ~GraphicsEngine(); - - /** - * Draw the given graphics primitive. - * - * @param primitive - * Primitive that is drawn. - */ - virtual void draw(void* graphicsContextPointer, - GraphicsPrimitive* primitive) = 0; - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - virtual void receiveEvent(Event* event); - - private: - GraphicsEngine(const GraphicsEngine&); - - GraphicsEngine& operator=(const GraphicsEngine&); - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __GRAPHICS_ENGINE_DECLARE__ - // -#endif // __GRAPHICS_ENGINE_DECLARE__ - -} // namespace -#endif //__GRAPHICS_ENGINE_H__ diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 587618ddd..dd7eb4b8f 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -24,6 +24,7 @@ #undef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" @@ -41,9 +42,16 @@ using namespace caret; /** * Constructor. + * + * @param openglContextPointer + * Context to which the OpenGL buffers apply. The current usage of QGLWidget + * shares the OpenGL context among all QGLWidgets. However, in the event + * OpenGL contexts are not shared, this implementation will need to be + * updated. */ -GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL() -: GraphicsEngineData() +GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL(const void* openglContextPointer) +: GraphicsEngineData(), +m_openglContextPointer(openglContextPointer) { } @@ -199,3 +207,140 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) } } +/** + * Draw the given graphics primitive. + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + */ +void +GraphicsEngineDataOpenGL::draw(void* openglContextPointer, + GraphicsPrimitive* primitive) +{ + CaretAssert(openglContextPointer); + CaretAssert(primitive); + if ( ! primitive->isValid()) { + return; + } + + GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); + if (openglData == NULL) { + openglData = new GraphicsEngineDataOpenGL(openglContextPointer); + primitive->setGraphicsEngineDataForOpenGL(openglData); + + openglData->loadBuffers(primitive); + } + + if (openglContextPointer != openglData->getOpenGLContextPointer()) { + const AString msg("Only one OpenGL graphics context is allowed. Have there been " + "changes made to QGLWidget creation?"); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); + CaretAssert(coordBufferID); + if ( ! glIsBuffer(coordBufferID)) { + std::cout << "Coordinate buffer is INVALID" << std::endl; + } + + /* + * Setup vertices for drawing + */ + glEnableClientState(GL_VERTEX_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, + coordBufferID); + glVertexPointer(openglData->m_coordinatesPerVertex, + openglData->m_coordinateDataType, + 0, + (GLvoid*)0); + + /* + * Setup normals for drawing + */ + if (openglData->m_normalVectorBufferObject != NULL) { + glEnableClientState(GL_NORMAL_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferObject->getBufferObjectName()); + glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + + /* + * Setup colors for drawing + */ + glEnableClientState(GL_COLOR_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); + + /* + * Unbind buffers + */ + glBindBuffer(GL_ARRAY_BUFFER, + 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + 0); + + /* + * Draw the primitive + */ + GLenum openGLPrimitiveType = GL_INVALID_ENUM; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + openGLPrimitiveType = GL_LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + openGLPrimitiveType = GL_LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::LINES: + openGLPrimitiveType = GL_LINES; + break; + case GraphicsPrimitive::PrimitiveType::POINTS: + openGLPrimitiveType = GL_POINTS; + break; + case GraphicsPrimitive::PrimitiveType::POLYGON: + openGLPrimitiveType = GL_POLYGON; + break; + case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + openGLPrimitiveType = GL_QUAD_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::QUADS: + openGLPrimitiveType = GL_QUADS; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + openGLPrimitiveType = GL_TRIANGLE_FAN; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + openGLPrimitiveType = GL_TRIANGLE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLES: + openGLPrimitiveType = GL_TRIANGLES; + break; + } + + CaretAssert(openGLPrimitiveType != GL_INVALID_ENUM); + glDrawArrays(openGLPrimitiveType, 0, openglData->m_arrayIndicesCount); + + /* + * Disable drawing + */ + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); +} + +/** + * @return Pointer to the OpenGL graphics context to which the buffers belong. + */ +const void* +GraphicsEngineDataOpenGL::getOpenGLContextPointer() const +{ + return m_openglContextPointer; +} + + + diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index b51bae9f7..623617b2e 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -37,7 +37,7 @@ namespace caret { class GraphicsEngineDataOpenGL : public GraphicsEngineData { public: - GraphicsEngineDataOpenGL(); + GraphicsEngineDataOpenGL(const void* openglContextPointer); virtual ~GraphicsEngineDataOpenGL(); @@ -45,6 +45,11 @@ namespace caret { void loadBuffers(GraphicsPrimitive* primitive); + static void draw(void* openglContextPointer, + GraphicsPrimitive* primitive); + + const void* getOpenGLContextPointer() const; + // ADD_NEW_METHODS_HERE private: @@ -54,9 +59,10 @@ namespace caret { void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); + const void* m_openglContextPointer; + GLsizei m_arrayIndicesCount = 0; - /** Coordinate buffer object WE DO NOT DELETE THIS */ GraphicsOpenGLBufferObject* m_coordinateBufferObject = NULL; GLenum m_coordinateDataType = GL_FLOAT; @@ -73,8 +79,6 @@ namespace caret { GLint m_componentsPerColor = 0; - friend class GraphicsEngineOpenGL; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsEngineOpenGL.cxx b/src/Graphics/GraphicsEngineOpenGL.cxx deleted file mode 100644 index 9a7df9cdd..000000000 --- a/src/Graphics/GraphicsEngineOpenGL.cxx +++ /dev/null @@ -1,189 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ -#include "GraphicsEngineOpenGL.h" -#undef __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ - -#include - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "CaretOpenGLInclude.h" -#include "GraphicsEngineDataOpenGL.h" -#include "EventManager.h" -#include "GraphicsOpenGLBufferObject.h" -#include "GraphicsPrimitive.h" - -using namespace caret; - - - -/** - * \class caret::GraphicsEngineOpenGL - * \brief Render graphics objects using OpenGL. - * \ingroup Graphics - */ - -/** - * Constructor. - */ -GraphicsEngineOpenGL::GraphicsEngineOpenGL() -: GraphicsEngine() -{ -} - -/** - * Destructor. - */ -GraphicsEngineOpenGL::~GraphicsEngineOpenGL() -{ -} - -/** - * Receive an event. - * - * @param event - * An event for which this instance is listening. - */ -void -GraphicsEngineOpenGL::receiveEvent(Event* event) -{ - GraphicsEngine::receiveEvent(event); -} - -/** - * Draw the given graphics primitive. - * - * @param openglContextPointer - * Pointer to the active OpenGL context. - * @param primitive - * Primitive that is drawn. - */ -void -GraphicsEngineOpenGL::draw(void* openglContextPointer, - GraphicsPrimitive* primitive) -{ - CaretAssert(primitive); - if ( ! primitive->isValid()) { - return; - } - - GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); - if (openglData == NULL) { - openglData = new GraphicsEngineDataOpenGL(); - primitive->setGraphicsEngineDataForOpenGL(openglData); - - openglData->loadBuffers(primitive); - } - - const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); - CaretAssert(coordBufferID); - if ( ! glIsBuffer(coordBufferID)) { - std::cout << "Coordinate buffer is INVALID" << std::endl; - } - - /* - * Setup vertices for drawing - */ - glEnableClientState(GL_VERTEX_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, - coordBufferID); - glVertexPointer(openglData->m_coordinatesPerVertex, - openglData->m_coordinateDataType, - 0, - (GLvoid*)0); - - /* - * Setup normals for drawing - */ - if (openglData->m_normalVectorBufferObject != NULL) { - glEnableClientState(GL_NORMAL_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferObject->getBufferObjectName()); - glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); - } - else { - glDisableClientState(GL_NORMAL_ARRAY); - } - - /* - * Setup colors for drawing - */ - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); - - /* - * Unbind buffers - */ - glBindBuffer(GL_ARRAY_BUFFER, - 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - 0); - - /* - * Draw the primitive - */ - GLenum openGLPrimitiveType = GL_INVALID_ENUM; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::LINE_LOOP: - openGLPrimitiveType = GL_LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::LINE_STRIP: - openGLPrimitiveType = GL_LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::LINES: - openGLPrimitiveType = GL_LINES; - break; - case GraphicsPrimitive::PrimitiveType::POINTS: - openGLPrimitiveType = GL_POINTS; - break; - case GraphicsPrimitive::PrimitiveType::POLYGON: - openGLPrimitiveType = GL_POLYGON; - break; - case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: - openGLPrimitiveType = GL_QUAD_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::QUADS: - openGLPrimitiveType = GL_QUADS; - break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: - openGLPrimitiveType = GL_TRIANGLE_FAN; - break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: - openGLPrimitiveType = GL_TRIANGLE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::TRIANGLES: - openGLPrimitiveType = GL_TRIANGLES; - break; - } - - CaretAssert(openGLPrimitiveType != GL_INVALID_ENUM); - glDrawArrays(openGLPrimitiveType, 0, openglData->m_arrayIndicesCount); - - /* - * Disable drawing - */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); -} - diff --git a/src/Graphics/GraphicsEngineOpenGL.h b/src/Graphics/GraphicsEngineOpenGL.h deleted file mode 100644 index 81d77dab4..000000000 --- a/src/Graphics/GraphicsEngineOpenGL.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef __GRAPHICS_ENGINE_OPEN_G_L_H__ -#define __GRAPHICS_ENGINE_OPEN_G_L_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include "CaretOpenGLInclude.h" -#include "GraphicsEngine.h" - - - -namespace caret { - - class GraphicsOpenGLBufferObject; - - class GraphicsEngineOpenGL : public GraphicsEngine { - - public: - GraphicsEngineOpenGL(); - - virtual ~GraphicsEngineOpenGL(); - - virtual void receiveEvent(Event* event); - - virtual void draw(void* openglContextPointer, - GraphicsPrimitive* primitive); - - // ADD_NEW_METHODS_HERE - - private: - - GraphicsEngineOpenGL(const GraphicsEngineOpenGL&); - - GraphicsEngineOpenGL& operator=(const GraphicsEngineOpenGL&); - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ - // -#endif // __GRAPHICS_ENGINE_OPEN_G_L_DECLARE__ - -} // namespace -#endif //__GRAPHICS_ENGINE_OPEN_G_L_H__ diff --git a/src/Graphics/GraphicsFactory.cxx b/src/Graphics/GraphicsFactory.cxx deleted file mode 100644 index 78d8118ad..000000000 --- a/src/Graphics/GraphicsFactory.cxx +++ /dev/null @@ -1,201 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __GRAPHICS_FACTORY_DECLARE__ -#include "GraphicsFactory.h" -#undef __GRAPHICS_FACTORY_DECLARE__ - -#include "CaretAssert.h" -#include "EventManager.h" -#include "GraphicsEngineOpenGL.h" -#include "GraphicsPrimitiveV3f.h" -#include "GraphicsPrimitiveV3fC4f.h" -#include "GraphicsPrimitiveV3fC4ub.h" - -using namespace caret; - - - -/** - * \class caret::GraphicsFactory - * \brief Factory for creating/accessing graphics opertions. - * \ingroup Graphics - */ - -/** - * Constructor. - */ -GraphicsFactory::GraphicsFactory() -: CaretObject() -{ - m_graphicsEngineOpenGL = std::unique_ptr(new GraphicsEngineOpenGL()); - -// EventManager::get()->addEventListener(this, EventTypeEnum::); -} - -/** - * Destructor. - */ -GraphicsFactory::~GraphicsFactory() -{ - EventManager::get()->removeAllEventsFromListener(this); -} - -/** - * Create the graphics factory. - * This should be called one time, not more, not less. - */ -void -GraphicsFactory::createGraphicsFactory() -{ - CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory == NULL), - "Graphics Factory has already been created."); - - GraphicsFactory::s_singletonGraphicsFactory = new GraphicsFactory(); -} - -/** - * Delete the graphics factory. - * - * This should be called one time after the graphics factory is created. - */ -void -GraphicsFactory::deleteGraphicsFactory() -{ - CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory != NULL), - "GraphicsFactory does not exist, cannot delete it."); - - delete GraphicsFactory::s_singletonGraphicsFactory; - GraphicsFactory::s_singletonGraphicsFactory= NULL; -} - -/** - * Get the one and only graphics factory - * - * @return Pointer to the graphics factory. - */ -GraphicsFactory* -GraphicsFactory::get() -{ - CaretAssertMessage((GraphicsFactory::s_singletonGraphicsFactory != NULL), - "GraphicsFactory was not created or has been deleted.\n" - "It must be created with GraphicsFactory::createGraphicsFactory()."); - - return GraphicsFactory::s_singletonGraphicsFactory; -} - -/** - * @return The graphics engine for OpenGL. - */ -GraphicsEngineOpenGL* -GraphicsFactory::getGraphicsEngineOpenGL() -{ - CaretAssert(m_graphicsEngineOpenGL.get()); - return m_graphicsEngineOpenGL.get(); -} - -/** - * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible - * for deleting the returned pointer. - * - * @param primitiveType - * Type of primitive drawn (triangles, lines, etc.) - */ -GraphicsPrimitiveV3f* -GraphicsFactory::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, - const float floatRGBA[4]) -{ - GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, - floatRGBA); - return primitive; -} - -/** - * @return A new primitive for XYZ with solid color unsigned byte RGBA. Caller is responsible - * for deleting the returned pointer. - * - * @param primitiveType - * Type of primitive drawn (triangles, lines, etc.) - */ -GraphicsPrimitiveV3f* -GraphicsFactory::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, - const uint8_t unsignedByteRGBA[4]) -{ - GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, - unsignedByteRGBA); - return primitive; -} - -/** - * @return A new primitive for XYZ with float RGBA. Caller is responsible - * for deleting the returned pointer. - * - * @param primitiveType - * Type of primitive drawn (triangles, lines, etc.) - */ -GraphicsPrimitiveV3fC4f* -GraphicsFactory::newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType) -{ - GraphicsPrimitiveV3fC4f* primitive = new GraphicsPrimitiveV3fC4f(primitiveType); - return primitive; -} - -/** - * @return A new primitive for XYZ with unsigned byte RGBA. Caller is responsible - * for deleting the returned pointer. - * - * @param primitiveType - * Type of primitive drawn (triangles, lines, etc.) - */ -GraphicsPrimitiveV3fC4ub* -GraphicsFactory::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType) -{ - GraphicsPrimitiveV3fC4ub* primitive = new GraphicsPrimitiveV3fC4ub(primitiveType); - return primitive; -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -GraphicsFactory::toString() const -{ - return "GraphicsFactory"; -} - -/** - * Receive an event. - * - * @param event - * An event for which this instance is listening. - */ -void -GraphicsFactory::receiveEvent(Event* event) -{ -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } -} - diff --git a/src/Graphics/GraphicsFactory.h b/src/Graphics/GraphicsFactory.h deleted file mode 100644 index acd88ad86..000000000 --- a/src/Graphics/GraphicsFactory.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __GRAPHICS_FACTORY_H__ -#define __GRAPHICS_FACTORY_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "CaretObject.h" - -#include "EventListenerInterface.h" -#include "GraphicsPrimitive.h" - - -namespace caret { - class GraphicsEngineOpenGL; - class GraphicsPrimitiveV3f; - class GraphicsPrimitiveV3fC4f; - class GraphicsPrimitiveV3fC4ub; - - class GraphicsFactory : public CaretObject, public EventListenerInterface { - - public: - GraphicsFactory(); - - virtual ~GraphicsFactory(); - - static void createGraphicsFactory(); - - static void deleteGraphicsFactory(); - - static GraphicsFactory* get(); - - GraphicsEngineOpenGL* getGraphicsEngineOpenGL(); - - GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, - const float floatRGBA[4]); - - GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, - const uint8_t unsignedByteRGBA[4]); - - GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); - - GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - virtual void receiveEvent(Event* event); - - private: - GraphicsFactory(const GraphicsFactory&); - - GraphicsFactory& operator=(const GraphicsFactory&); - - static GraphicsFactory* s_singletonGraphicsFactory; - - std::unique_ptr m_graphicsEngineOpenGL; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __GRAPHICS_FACTORY_DECLARE__ - GraphicsFactory* GraphicsFactory::s_singletonGraphicsFactory = NULL; -#endif // __GRAPHICS_FACTORY_DECLARE__ - -} // namespace -#endif //__GRAPHICS_FACTORY_H__ diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 1605253fd..0a25c3537 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -27,6 +27,9 @@ #include "CaretLogger.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitiveV3f.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" using namespace caret; @@ -405,3 +408,63 @@ GraphicsPrimitive::receiveEvent(Event* event) // } } +/** + * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3f* +GraphicsPrimitive::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const float floatRGBA[4]) +{ + GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, + floatRGBA); + return primitive; +} + +/** + * @return A new primitive for XYZ with solid color unsigned byte RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3f* +GraphicsPrimitive::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]) +{ + GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, + unsignedByteRGBA); + return primitive; +} + +/** + * @return A new primitive for XYZ with float RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4f* +GraphicsPrimitive::newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType) +{ + GraphicsPrimitiveV3fC4f* primitive = new GraphicsPrimitiveV3fC4f(primitiveType); + return primitive; +} + +/** + * @return A new primitive for XYZ with unsigned byte RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fC4ub* +GraphicsPrimitive::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType) +{ + GraphicsPrimitiveV3fC4ub* primitive = new GraphicsPrimitiveV3fC4ub(primitiveType); + return primitive; +} + diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 293512498..a4afa0c7f 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -32,8 +32,10 @@ namespace caret { - class GraphicsEngine; class GraphicsEngineDataOpenGL; + class GraphicsPrimitiveV3f; + class GraphicsPrimitiveV3fC4f; + class GraphicsPrimitiveV3fC4ub; class GraphicsPrimitive : public CaretObject, public EventListenerInterface { @@ -140,6 +142,16 @@ namespace caret { GraphicsPrimitive& operator=(const GraphicsPrimitive& obj); public: + static GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const float floatRGBA[4]); + + static GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]); + + static GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); + + static GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); + virtual ~GraphicsPrimitive(); virtual void receiveEvent(Event* event); @@ -205,8 +217,6 @@ namespace caret { friend class GraphicsEngineDataOpenGL; - friend class GraphicsEngineOpenGL; - // ADD_NEW_MEMBERS_HERE }; -- GitLab From cc2167a994e995eec2baf3c9ef07fa9714b2dd09 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 19 Apr 2017 11:22:57 -0500 Subject: [PATCH 254/755] Removed use of BrainOpenGLPrimitiveDrawing from chart two drawing and replaced with new primitive drawing that uses OpenGL buffers. --- src/Brain/BrainOpenGL.cxx | 4 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 392 ++++-------------- .../EventGraphicsOpenGLDeleteBufferObject.cxx | 11 +- src/Graphics/GraphicsPrimitive.cxx | 37 ++ src/Graphics/GraphicsPrimitive.h | 2 + src/Graphics/GraphicsPrimitiveV3f.cxx | 18 + src/Graphics/GraphicsPrimitiveV3f.h | 3 + 7 files changed, 145 insertions(+), 322 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 75e8b47e7..4c6f2a563 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -116,6 +116,10 @@ BrainOpenGL::receiveEvent(Event* event) CaretAssert(deleteBufferEvent); const GraphicsOpenGLBufferObject* bufferObject = deleteBufferEvent->getOpenGLBufferObject(); if (bufferObject != NULL) { + /* + * Buffers are created within an OpenGL context and must + * be deleted within that OpenGL context. + */ m_buffersForDeletionLater.emplace(m_buffersForDeletionLater.end(), bufferObject->getOpenGLContextPointer(), bufferObject->getBufferObjectName()); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 6ac952bd6..fa076f064 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -29,7 +29,6 @@ #include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" -#include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrowserTabContent.h" #include "CaretAssert.h" @@ -629,24 +628,23 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr const std::vector& histogramOneXYZ = histogramDrawingInfo.getThresholdOneBounds(); if (histogramOneXYZ.size() == 12) { - BrainOpenGLPrimitiveDrawing::drawPolygon(histogramOneXYZ, - histogramNormals, - histogramRGBA); + std::unique_ptr threshPrim + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGON, histogramRGBA)); + threshPrim->addVertices(&histogramOneXYZ[0], + 4); + drawPrimitivePrivate(threshPrim.get()); } const std::vector& histogramTwoXYZ = histogramDrawingInfo.getThresholdTwoBounds(); if (histogramTwoXYZ.size() == 12) { - BrainOpenGLPrimitiveDrawing::drawPolygon(histogramTwoXYZ, - histogramNormals, - histogramRGBA); + std::unique_ptr threshPrim + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGON, histogramRGBA)); + threshPrim->addVertices(&histogramTwoXYZ[0], + 4); + drawPrimitivePrivate(threshPrim.get()); } } - std::vector quadVerticesXYZ; - std::vector quadVerticesFloatRGBA; - std::vector quadVerticesByteRGBA; - - if (drawHistogramBarsFlag) { /* * Reserve to prevent reszing of vectors @@ -654,12 +652,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr */ const int32_t verticesPerBar = 4; const int32_t totalVertices = verticesPerBar * numValues; - quadVerticesXYZ.reserve(totalVertices * 3); - std::vector quadVerticesNormals; - quadVerticesNormals.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - const float normalVector[3] = { 0.0, 0.0, 1.0 }; + + std::unique_ptr histogramFloatRGBA + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + std::unique_ptr histogramByteRGBA + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + + + if(m_identificationModeFlag) { + histogramByteRGBA->reserveForNumberOfVertices(totalVertices); + } + else { + histogramFloatRGBA->reserveForNumberOfVertices(totalVertices); + } const float z = 0.; @@ -674,38 +679,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr CaretAssertVectorIndex(yValues, i); float top = yValues[i]; - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - - for (int32_t iNormal = 0; iNormal < verticesPerBar; iNormal++) { - quadVerticesNormals.insert(quadVerticesNormals.end(), - normalVector, normalVector + 3); - } - if (m_identificationModeFlag) { uint8_t idRGBA[4]; addToHistogramIdentification(mapIndex, i, idRGBA); - - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } + histogramByteRGBA->addVertex(left, bottom, z, idRGBA); + histogramByteRGBA->addVertex(right, bottom, z, idRGBA); + histogramByteRGBA->addVertex(right, top, z, idRGBA); + histogramByteRGBA->addVertex(left, top, z, idRGBA); } else { - for (int32_t iRGB = 0; iRGB < verticesPerBar; iRGB++) { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rgba, rgba + 4); - } + histogramFloatRGBA->addVertex(left, bottom, z, rgba); + histogramFloatRGBA->addVertex(right, bottom, z, rgba); + histogramFloatRGBA->addVertex(right, top, z, rgba); + histogramFloatRGBA->addVertex(left, top, z, rgba); } } } @@ -713,34 +699,32 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr /* * Draw the bar elements. */ - CaretAssert(quadVerticesXYZ.size() == quadVerticesNormals.size()); if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesByteRGBA); + drawPrimitivePrivate(histogramByteRGBA.get()); } else { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - BrainOpenGLPrimitiveDrawing::drawQuads(quadVerticesXYZ, - quadVerticesNormals, - quadVerticesFloatRGBA); + drawPrimitivePrivate(histogramFloatRGBA.get()); } } - const bool smoothFlag = true; - - if (drawHistogramEnvelopeFlag - && smoothFlag) { + if (drawHistogramEnvelopeFlag) { + std::unique_ptr histogramFloatRGBA + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); + std::unique_ptr histogramByteRGBA + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); + /* * Reserve to prevent reszing of vectors * as elements are added. */ const int32_t verticesPerBar = 2; const int32_t totalVertices = verticesPerBar * numValues + 4; - quadVerticesXYZ.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); + if (m_identificationModeFlag) { + histogramByteRGBA->reserveForNumberOfVertices(totalVertices); + } + else { + histogramFloatRGBA->reserveForNumberOfVertices(totalVertices); + } const float z = 0.0; @@ -782,71 +766,41 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr addToHistogramIdentification(mapIndex, i, idRGBA); } if (i == 0) { - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + histogramByteRGBA->addVertex(left, bottom, z, idRGBA); } else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - leftRGBA, - leftRGBA + 4); + histogramFloatRGBA->addVertex(left, bottom, z, leftRGBA); } - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(topLeft); - quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + histogramByteRGBA->addVertex(left, topLeft, z, idRGBA); } else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - leftRGBA, - leftRGBA + 4); + histogramFloatRGBA->addVertex(left, topLeft, z, leftRGBA); } } - quadVerticesXYZ.push_back((left + right) / 2.0); - quadVerticesXYZ.push_back(topLeft); - quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + histogramByteRGBA->addVertex((left+right)/2.0, topLeft, z, idRGBA); } else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - middleRGBA, - middleRGBA + 4); + histogramFloatRGBA->addVertex((left+right)/2.0, topLeft, z, middleRGBA); } if (i == lastValueIndex) { - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(topRight); - quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + histogramByteRGBA->addVertex(right, topRight, z, idRGBA); } else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rightRGBA, - rightRGBA + 4); + histogramFloatRGBA->addVertex(right, topRight, z, rightRGBA); } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); + histogramByteRGBA->addVertex(right, bottom, z, idRGBA); } else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - rightRGBA, - rightRGBA + 4); + histogramFloatRGBA->addVertex(right, bottom, z, rightRGBA); } } } @@ -855,222 +809,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const Histogr * Draw the elements. */ if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - - const float lineWidth = 5.0; - BrainOpenGLPrimitiveDrawing::drawLineStrip(quadVerticesXYZ, - quadVerticesByteRGBA, - lineWidth); + glLineWidth(5.0); + drawPrimitivePrivate(histogramByteRGBA.get()); } else { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - - const float lineWidth = 2.0; - BrainOpenGLPrimitiveDrawing::drawLineStrip(quadVerticesXYZ, - quadVerticesFloatRGBA, - lineWidth); - } - } - else if (drawHistogramEnvelopeFlag) { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 2; - const int32_t totalVertices = verticesPerBar * numValues + 4; - quadVerticesXYZ.reserve(totalVertices * 3); - quadVerticesFloatRGBA.reserve(totalVertices * 4); - quadVerticesByteRGBA.reserve(totalVertices * 4); - - const float z = 0.0; - - const int32_t lastValueIndex = numValues - 1; - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i + 1]; - CaretAssert(right >= left); - float bottom = 0; - CaretAssertVectorIndex(yValues, i); - float top = yValues[i]; - - uint8_t idRGBA[4]; - if (m_identificationModeFlag) { - addToHistogramIdentification(mapIndex, i, idRGBA); - } - - if (i == 0) { - /* - * Left side of first bar - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - } - else { - if (top > yValues[i - 1]) { - /* - * Line from previous bar that is lower in - * height than this bar - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(yValues[i - 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - } - } - - /* - * Draw line across top - */ - quadVerticesXYZ.push_back(left); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - - if (i == lastValueIndex) { - /* - * Right side of last bar - */ - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(bottom); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - } - else { - if (top > yValues[i + 1]) { - /* - * Line from bar down to next bar - * with a lower height - */ - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(top); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - quadVerticesXYZ.push_back(right); - quadVerticesXYZ.push_back(yValues[i + 1]); - quadVerticesXYZ.push_back(z); - if (m_identificationModeFlag) { - quadVerticesByteRGBA.insert(quadVerticesByteRGBA.end(), - idRGBA, idRGBA + 4); - } - else { - quadVerticesFloatRGBA.insert(quadVerticesFloatRGBA.end(), - envelopeSolidColorRGBA, - envelopeSolidColorRGBA + 4); - } - } - } - } - - /* - * Draw the elements. - */ - if (m_identificationModeFlag) { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); - - const float lineWidth = 5.0; - BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, - quadVerticesByteRGBA, - lineWidth); - } - else { - CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); - - const float lineWidth = 1.0; - BrainOpenGLPrimitiveDrawing::drawLines(quadVerticesXYZ, - quadVerticesFloatRGBA, - lineWidth); + glLineWidth(2.0); + drawPrimitivePrivate(histogramFloatRGBA.get()); } } } @@ -1294,6 +1038,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); std::unique_ptr quadsData4ub = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + const int32_t numberOfCells = numberOfColumns * numberOfRows; + if (m_identificationModeFlag) { + quadsData4ub->reserveForNumberOfVertices(numberOfCells); + } + else { + quadsData4f->reserveForNumberOfVertices(numberOfCells); + } float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { @@ -1437,11 +1188,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT gridLineColorFloats); gridLineColorFloats[3] = 1.0; + const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); + const int32_t numCells = static_cast(gridXYZ.size() / 3); + std::unique_ptr outlineData4f = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, gridLineColorFloats)); - const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); - const int32_t numCells = static_cast(gridXYZ.size() / 3); + outlineData4f->reserveForNumberOfVertices(numCells); for (int32_t i = 0; i < numCells; i++) { CaretAssertVectorIndex(gridXYZ, i*3); outlineData4f->addVertex(&gridXYZ[i*3]); @@ -1477,6 +1230,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT std::unique_ptr rowOutlineData4f = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, highlightRGBA)); + rowOutlineData4f->reserveForNumberOfVertices(4); rowOutlineData4f->addVertex(minX, rowY); rowOutlineData4f->addVertex(maxX, rowY); @@ -1515,6 +1269,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT std::unique_ptr columnOutlineData4f = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, highlightRGBA)); + columnOutlineData4f->reserveForNumberOfVertices(4); columnOutlineData4f->addVertex(colX, minY); columnOutlineData4f->addVertex(colX + cellWidth, minY); @@ -1997,7 +1752,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons std::unique_ptr gridData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); - + gridData->reserveForNumberOfVertices(8); gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); @@ -2203,6 +1958,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data std::unique_ptr ticksData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); + ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); const bool showTicksEnabledFlag = axis->isShowTickmarks(); diff --git a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx index 110a45244..26d11ed6f 100644 --- a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx @@ -58,16 +58,19 @@ m_openglBufferObject(openglBufferObject) */ EventGraphicsOpenGLDeleteBufferObject::~EventGraphicsOpenGLDeleteBufferObject() { - if (m_openglBufferObject != NULL) { - CaretLogSevere("Failure to delete OpenGL Buffer Object Name=" + if (this->getEventProcessCount() <= 0) { + CaretLogSevere("Deletion of OpenGL Buffer Object Name=" + AString::number(m_openglBufferObject->getBufferObjectName()) + ", context pointer=" - + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer())); + + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer()) + + " appears to have failed. The events processed count is zero and that " + "indicates that the event was not received in any listener or the " + "listener failed to set the event as processed."); } } /** - * @return OpenGL Buffer Object that was deletedc + * @return OpenGL Buffer Object that was deleted */ const GraphicsOpenGLBufferObject* EventGraphicsOpenGLDeleteBufferObject::getOpenGLBufferObject() const diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 0a25c3537..80b266683 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -107,6 +107,43 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) m_graphicsEngineDataForOpenGL.reset(); } +/** + * Request the capacity of the primitive for the given number of vertices. + * Using this method can help reduce reallocations as data is added + * to the primitive. Note: the primitive data is stored in + * std::vector's and this method functions identically to + * std::vector::reserve(). + * + * @param numberOfVertices + * Number of vertices + */ +void +GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) +{ + switch (m_vertexType) { + case VertexType::FLOAT_XYZ: + m_xyz.reserve(numberOfVertices * 3); + break; + } + + switch (m_normalVectorType) { + case NormalVectorType::FLOAT_XYZ: + m_floatNormalVectorXYZ.reserve(numberOfVertices * 3); + break; + case NormalVectorType::NONE: + break; + } + + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + m_floatRGBA.reserve(numberOfVertices * 4); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + m_unsignedByteRGBA.reserve(numberOfVertices * 4); + break; + } +} + /** * @return Is this graphics primitive valid. * Primitive is valid if all of these conditions are met diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index a4afa0c7f..dd8db9de3 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -154,6 +154,8 @@ namespace caret { virtual ~GraphicsPrimitive(); + void reserveForNumberOfVertices(const int32_t numberOfVertices); + virtual void receiveEvent(Event* event); bool isValid() const; diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index 5bda3f4da..6fb8412f8 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -191,6 +191,24 @@ GraphicsPrimitiveV3f::addVertex(const float x, } } +/** + * Add XYZ vertices from an array. + * + * @param xyzArray + * Array containing XYZ vertex data. + * @param numberOfVertices + * Number of vertices (xyz triplets) to add + */ +void +GraphicsPrimitiveV3f::addVertices(const float xyzArray[], + const int32_t numberOfVertices) +{ + for (int32_t i = 0; i < numberOfVertices; i++) { + addVertex(&xyzArray[i*3]); + } +} + + /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3f.h b/src/Graphics/GraphicsPrimitiveV3f.h index db4cd62e2..f11925420 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.h +++ b/src/Graphics/GraphicsPrimitiveV3f.h @@ -52,6 +52,9 @@ namespace caret { void addVertex(const float x, const float y); + + void addVertices(const float xyzArray[], + const int32_t numberOfVertices); virtual GraphicsPrimitive* clone() const; -- GitLab From 3f7c282e2727fac279568f0020fd1b08d3e4edfc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 19 Apr 2017 14:54:34 -0500 Subject: [PATCH 255/755] When exiting wb_view, reset the brain so that all files are destroyed before BrainOpenGL is destroyed. Files release GraphicsOpenGLBufferObject's via an event sent to BrainOpenGL and if BrainOpenGL is not around to receive the event, message are printed indicating destruction of GraphicsOpenGLBufferObject failed. --- src/GuiQt/GuiManager.cxx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 71e60d216..7a193d3f0 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -954,6 +954,17 @@ GuiManager::exitProgram(BrainBrowserWindow* parent) } if (okToExit) { + /* + * While resetting the brain is not absolutely necessary, + * some files may use GraphicsOpenGLBufferObject that are + * created by BrainOpenGL. Resetting the brain will close + * all files which results in the GraphicsOpenGLBufferObject + * being released. If the brain is not reset, the files + * are deleted after BrainOpenGL so BrainOpenGL will report + * that GraphicsOpenGLBufferObjects were not deleted. + */ + get()->getBrain()->resetBrain(); + std::vector bws = this->getAllOpenBrainBrowserWindows(); for (int i = 0; i < static_cast(bws.size()); i++) { bws[i]->deleteLater(); -- GitLab From de9a2e30c630b11b402b3dc8ab3dc66e24d072bd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 20 Apr 2017 12:56:11 -0500 Subject: [PATCH 256/755] Using new primitives with OpenGL Buffer Object for Matrix drawing that is substantially faster than the previous implementation. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1030 ++++++++++++----- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 6 + src/Brain/BrainOpenGLFixedPipeline.cxx | 88 ++ src/Brain/BrainOpenGLFixedPipeline.h | 5 + src/Files/CMakeLists.txt | 1 + src/Files/ChartableTwoFileMatrixChart.cxx | 17 + src/Files/ChartableTwoFileMatrixChart.h | 4 + src/Files/CiftiMappableDataFile.cxx | 121 ++ src/Files/CiftiMappableDataFile.h | 7 + src/Graphics/GraphicsEngineDataOpenGL.cxx | 114 +- src/Graphics/GraphicsEngineDataOpenGL.h | 9 + src/Graphics/GraphicsPrimitive.cxx | 23 +- src/Graphics/GraphicsPrimitive.h | 28 + src/GuiQt/ChartTwoOverlayViewController.cxx | 11 + 14 files changed, 1196 insertions(+), 268 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index fa076f064..b2689eda0 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -978,318 +978,828 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float cellHeight, const float zooming) { + GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType); + if (matrixPrimitive == NULL) { + return; + } + if (m_identificationModeFlag) { resetIdentification(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - int32_t numberOfRows = 0; - int32_t numberOfColumns = 0; - std::vector matrixRGBA; - if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, - numberOfColumns, - matrixRGBA)) { - CaretLogWarning("Matrix RGBA invalid"); - return; - } - if ((numberOfRows <= 0) - || (numberOfColumns <= 0)) { - return; - } + glPushMatrix(); + glScalef(cellWidth, cellHeight, 1.0); + /* + * Enable alpha blending so voxels that are not drawn from higher layers + * allow voxels from lower layers to be seen. + */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + drawPrimitivePrivate(matrixPrimitive); const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); - bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); - const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); - - - std::vector selectedColumnIndices; - std::vector selectedRowIndices; - ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; - matrixChart->getSelectedRowColumnIndices(m_tabIndex, - selectedRowColumnDimension, - selectedRowIndices, - selectedColumnIndices); - std::map columnRangesForRow; - for (int32_t rowIndex : selectedRowIndices) { - columnRangesForRow[rowIndex] = RowColumnMinMax(); + if (matrixProperties->isGridLinesDisplayed()) { + glPolygonMode(GL_FRONT, + GL_LINE); + uint8_t gridLineColorBytes[4]; + m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); + float gridLineColorFloats[4]; + CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, + gridLineColorFloats); + gridLineColorFloats[3] = 1.0; + GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), + matrixPrimitive, + gridLineColorFloats); + glPolygonMode(GL_FRONT, + GL_FILL); } - const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); - std::map rowRangesForColumn; - for (int32_t columnIndex : selectedColumnIndices) { - rowRangesForColumn[columnIndex] = RowColumnMinMax(); - } - const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + matrixChart->getMatrixDimensions(numberOfRows, + numberOfColumns); - uint8_t highlightRGBByte[3]; - m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); - const float highlightRGBA[4] = { - highlightRGBByte[0] / 255.0, - highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0, - 1.0 - }; + if (matrixProperties->isSelectedRowColumnHighlighted()) { + uint8_t highlightRGBByte[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); + const float highlightRGBA[4] = { + highlightRGBByte[0] / 255.0, + highlightRGBByte[1] / 255.0, + highlightRGBByte[2] / 255.0, + 1.0 + }; + + std::vector selectedColumnIndices; + std::vector selectedRowIndices; + ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; + matrixChart->getSelectedRowColumnIndices(m_tabIndex, + selectedRowColumnDimension, + selectedRowIndices, + selectedColumnIndices); + for (auto rowIndex : selectedRowIndices) { + std::unique_ptr rowOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + rowOutlineData4f->reserveForNumberOfVertices(4); + + float minX = 0; + float maxX = numberOfColumns; + const float minY = numberOfRows - rowIndex - 1; + const float maxY = minY + 1.0f; - int32_t rgbaOffset = 0; - - std::unique_ptr quadsData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); - std::unique_ptr quadsData4ub - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); - const int32_t numberOfCells = numberOfColumns * numberOfRows; - if (m_identificationModeFlag) { - quadsData4ub->reserveForNumberOfVertices(numberOfCells); - } - else { - quadsData4f->reserveForNumberOfVertices(numberOfCells); + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxX = rowIndex; // matrix is symmetric + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minX = rowIndex + 1; // matrix is symmetric + break; + } + + rowOutlineData4f->addVertex(minX, minY); + rowOutlineData4f->addVertex(maxX, minY); + rowOutlineData4f->addVertex(maxX, maxY); + rowOutlineData4f->addVertex(minX, maxY); + const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(rowOutlineData4f.get()); + } + + for (auto columnIndex : selectedColumnIndices) { + std::unique_ptr columnOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + columnOutlineData4f->reserveForNumberOfVertices(4); + + const float minX = columnIndex; + const float maxX = columnIndex + 1; + float minY = 0; + float maxY = numberOfRows;; + + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxY = columnIndex; // matrix is symmetric + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minY = columnIndex + 1; // matrix is symmetric + break; + } + columnOutlineData4f->addVertex(minX, minY); + columnOutlineData4f->addVertex(maxX, minY); + columnOutlineData4f->addVertex(maxX, maxY); + columnOutlineData4f->addVertex(minX, maxY); + const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(columnOutlineData4f.get()); + } } - float cellY = (numberOfRows - 1) * cellHeight; - for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { - float cellX = 0; - for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { - CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); - const float* rgba = &matrixRGBA[rgbaOffset]; - rgbaOffset += 4; - - bool drawCellFlag = true; - if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { - if (numberOfRows == numberOfColumns) { - drawCellFlag = false; - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - if (rowIndex != columnIndex) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - if (rowIndex > columnIndex) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - if (rowIndex < columnIndex) { - drawCellFlag = true; - } - break; - } - } - else { - drawCellFlag = false; - const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); - const int32_t diagonalRow = static_cast(slope * columnIndex); + if (m_identificationModeFlag) { + /* + * + */ + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + GLdouble projectionMatrix[16]; + glGetDoublev(GL_PROJECTION_MATRIX, + projectionMatrix); + GLdouble modelMatrix[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, + modelMatrix); + GLdouble windowXYZ[3] = { m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, 0.0 }; + + GLdouble matrixXYZ[3]; + if (gluUnProject(windowXYZ[0], windowXYZ[1], windowXYZ[2], + modelMatrix, projectionMatrix, viewport, + &matrixXYZ[0], &matrixXYZ[1], &matrixXYZ[2])) { + const int32_t rowOriginBottomIndex = static_cast(matrixXYZ[1]); + const int32_t columnIndex = static_cast(matrixXYZ[0]); + if ((rowOriginBottomIndex >= 0) + && (rowOriginBottomIndex < numberOfRows) + && (columnIndex >= 0) + && (columnIndex < numberOfColumns)) { + const int32_t rowIndex = numberOfRows - rowOriginBottomIndex - 1; + + float pixelRGBA[4]; + float pixelDepth = 0.0; + if (m_fixedPipelineDrawing->getPixelDepthAndRGBA(m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + pixelDepth, + pixelRGBA)) { - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - drawCellFlag = true; - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - if (rowIndex != diagonalRow) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - if (rowIndex > diagonalRow) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - if (rowIndex < diagonalRow) { - drawCellFlag = true; - } - break; + std::cout << "Pixel Depth/RGBA: " << pixelDepth << ", " << AString::fromNumbers(pixelRGBA, 4, ",") << std::endl; + if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(pixelDepth)) { + if (pixelRGBA[3] > 0.0) { + m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), + rowIndex, + columnIndex); + } } } } - - if (drawCellFlag) { - if (haveSelectedRowsFlag) { - std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); - if (minMaxIter != columnRangesForRow.end()) { - if (columnIndex < minMaxIter->second.m_min) { - minMaxIter->second.m_min = columnIndex; + } + } + + glDisable(GL_BLEND); + glPopMatrix(); + + + const bool drawOLD = false; + if (drawOLD) { + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + std::vector matrixRGBA; + if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, + numberOfColumns, + matrixRGBA)) { + CaretLogWarning("Matrix RGBA invalid"); + return; + } + if ((numberOfRows <= 0) + || (numberOfColumns <= 0)) { + return; + } + + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + CaretAssert(matrixProperties); + + bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); + const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); + + + std::vector selectedColumnIndices; + std::vector selectedRowIndices; + ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; + matrixChart->getSelectedRowColumnIndices(m_tabIndex, + selectedRowColumnDimension, + selectedRowIndices, + selectedColumnIndices); + std::map columnRangesForRow; + for (int32_t rowIndex : selectedRowIndices) { + columnRangesForRow[rowIndex] = RowColumnMinMax(); + } + const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); + + std::map rowRangesForColumn; + for (int32_t columnIndex : selectedColumnIndices) { + rowRangesForColumn[columnIndex] = RowColumnMinMax(); + } + const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); + + uint8_t highlightRGBByte[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); + const float highlightRGBA[4] = { + highlightRGBByte[0] / 255.0, + highlightRGBByte[1] / 255.0, + highlightRGBByte[2] / 255.0, + 1.0 + }; + + int32_t rgbaOffset = 0; + + std::unique_ptr quadsData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + std::unique_ptr quadsData4ub + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + const int32_t numberOfCells = numberOfColumns * numberOfRows; + if (m_identificationModeFlag) { + quadsData4ub->reserveForNumberOfVertices(numberOfCells); + } + else { + quadsData4f->reserveForNumberOfVertices(numberOfCells); + } + + float cellY = (numberOfRows - 1) * cellHeight; + for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { + float cellX = 0; + for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { + CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); + const float* rgba = &matrixRGBA[rgbaOffset]; + rgbaOffset += 4; + + bool drawCellFlag = true; + if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { + if (numberOfRows == numberOfColumns) { + drawCellFlag = false; + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < columnIndex) { + drawCellFlag = true; + } + break; } - if (columnIndex > minMaxIter->second.m_max) { - minMaxIter->second.m_max = columnIndex; + } + else { + drawCellFlag = false; + const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); + const int32_t diagonalRow = static_cast(slope * columnIndex); + + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + drawCellFlag = true; + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != diagonalRow) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > diagonalRow) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < diagonalRow) { + drawCellFlag = true; + } + break; } } } - if (haveSelectedColumnsFlag) { - std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); - if (minMaxIter != rowRangesForColumn.end()) { - if (rowIndex < minMaxIter->second.m_min) { - minMaxIter->second.m_min = rowIndex; + if (drawCellFlag) { + if (haveSelectedRowsFlag) { + std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); + if (minMaxIter != columnRangesForRow.end()) { + if (columnIndex < minMaxIter->second.m_min) { + minMaxIter->second.m_min = columnIndex; + } + if (columnIndex > minMaxIter->second.m_max) { + minMaxIter->second.m_max = columnIndex; + } } - if (rowIndex > minMaxIter->second.m_max) { - minMaxIter->second.m_max = rowIndex; + } + + if (haveSelectedColumnsFlag) { + std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); + if (minMaxIter != rowRangesForColumn.end()) { + if (rowIndex < minMaxIter->second.m_min) { + minMaxIter->second.m_min = rowIndex; + } + if (rowIndex > minMaxIter->second.m_max) { + minMaxIter->second.m_max = rowIndex; + } } } + + uint8_t idRGBA[4]; + if (m_identificationModeFlag) { + addToChartMatrixIdentification(rowIndex, + columnIndex, + idRGBA); + } + + if (m_identificationModeFlag) { + quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); + quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); + quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); + quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); + } + else { + quadsData4f->addVertex(cellX, cellY, 0.0, rgba); + quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); + quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); + quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); + } } - uint8_t idRGBA[4]; - if (m_identificationModeFlag) { - addToChartMatrixIdentification(rowIndex, - columnIndex, - idRGBA); - } - - if (m_identificationModeFlag) { - quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); - quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); - quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); - quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); - } - else { - quadsData4f->addVertex(cellX, cellY, 0.0, rgba); - quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); - quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); - quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); - } + cellX += cellWidth; } - cellX += cellWidth; + cellY -= cellHeight; } - cellY -= cellHeight; - } - - /* - * Draw the matrix elements. - */ - if (m_identificationModeFlag) { - drawPrimitivePrivate(quadsData4ub.get()); - } - else { /* - * Enable alpha blending so voxels that are not drawn from higher layers - * allow voxels from lower layers to be seen. + * Draw the matrix elements. */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - drawPrimitivePrivate(quadsData4f.get()); - - glDisable(GL_BLEND); - - - /* - * Drawn an outline around the matrix elements. - */ - if (displayGridLinesFlag) { - uint8_t gridLineColorBytes[4]; - m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); - float gridLineColorFloats[4]; - CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, - gridLineColorFloats); - gridLineColorFloats[3] = 1.0; - - const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); - const int32_t numCells = static_cast(gridXYZ.size() / 3); - - std::unique_ptr outlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, - gridLineColorFloats)); - outlineData4f->reserveForNumberOfVertices(numCells); - for (int32_t i = 0; i < numCells; i++) { - CaretAssertVectorIndex(gridXYZ, i*3); - outlineData4f->addVertex(&gridXYZ[i*3]); - } - glPolygonMode(GL_FRONT, GL_LINE); - glLineWidth(1.0); - drawPrimitivePrivate(outlineData4f.get()); - glPolygonMode(GL_FRONT, GL_FILL); + if (m_identificationModeFlag) { + drawPrimitivePrivate(quadsData4ub.get()); } - - if ( (! selectedRowIndices.empty()) - && highlightSelectedRowColumnFlag) { - for (auto rowIndex : selectedRowIndices) { - const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; + else { + /* + * Enable alpha blending so voxels that are not drawn from higher layers + * allow voxels from lower layers to be seen. + */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + drawPrimitivePrivate(quadsData4f.get()); + + glDisable(GL_BLEND); + + + /* + * Drawn an outline around the matrix elements. + */ + if (displayGridLinesFlag) { + uint8_t gridLineColorBytes[4]; + m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); + float gridLineColorFloats[4]; + CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, + gridLineColorFloats); + gridLineColorFloats[3] = 1.0; + + const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); + const int32_t numCells = static_cast(gridXYZ.size() / 3); - int32_t minColumn = 0; - int32_t maxColumn = numberOfColumns; - if (haveSelectedRowsFlag) { - std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); - if (minMaxIter != columnRangesForRow.end()) { - const int32_t minValue = minMaxIter->second.m_min; - const int32_t rowMaxColumn = minMaxIter->second.m_max; - if (minValue < rowMaxColumn) { - minColumn = minValue; - maxColumn = rowMaxColumn + 1; + std::unique_ptr outlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, + gridLineColorFloats)); + outlineData4f->reserveForNumberOfVertices(numCells); + for (int32_t i = 0; i < numCells; i++) { + CaretAssertVectorIndex(gridXYZ, i*3); + outlineData4f->addVertex(&gridXYZ[i*3]); + } + glPolygonMode(GL_FRONT, GL_LINE); + glLineWidth(1.0); + drawPrimitivePrivate(outlineData4f.get()); + glPolygonMode(GL_FRONT, GL_FILL); + } + + if ( (! selectedRowIndices.empty()) + && highlightSelectedRowColumnFlag) { + for (auto rowIndex : selectedRowIndices) { + const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; + + int32_t minColumn = 0; + int32_t maxColumn = numberOfColumns; + if (haveSelectedRowsFlag) { + std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); + if (minMaxIter != columnRangesForRow.end()) { + const int32_t minValue = minMaxIter->second.m_min; + const int32_t rowMaxColumn = minMaxIter->second.m_max; + if (minValue < rowMaxColumn) { + minColumn = minValue; + maxColumn = rowMaxColumn + 1; + } } } + + const float minX = minColumn * cellWidth; + const float maxX = maxColumn * cellWidth; + + std::unique_ptr rowOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + rowOutlineData4f->reserveForNumberOfVertices(4); + + rowOutlineData4f->addVertex(minX, rowY); + rowOutlineData4f->addVertex(maxX, rowY); + rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); + rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(rowOutlineData4f.get()); } - const float minX = minColumn * cellWidth; - const float maxX = maxColumn * cellWidth; - - std::unique_ptr rowOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - rowOutlineData4f->reserveForNumberOfVertices(4); - - rowOutlineData4f->addVertex(minX, rowY); - rowOutlineData4f->addVertex(maxX, rowY); - rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); - rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(rowOutlineData4f.get()); + glLineWidth(1.0); } - glLineWidth(1.0); - } - - if ( (! selectedColumnIndices.empty()) - && highlightSelectedRowColumnFlag) { - for (auto columnIndex : selectedColumnIndices) { - const float colX = columnIndex * cellWidth; - - int32_t minRow = 0; - int32_t maxRow = numberOfRows; - if (haveSelectedColumnsFlag) { - std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); - if (minMaxIter != rowRangesForColumn.end()) { - const int32_t minValue = minMaxIter->second.m_min; - const int32_t maxValue = minMaxIter->second.m_max; - if (minValue < maxValue) { - minRow = minValue; - maxRow = maxValue + 1; + if ( (! selectedColumnIndices.empty()) + && highlightSelectedRowColumnFlag) { + for (auto columnIndex : selectedColumnIndices) { + const float colX = columnIndex * cellWidth; + + int32_t minRow = 0; + int32_t maxRow = numberOfRows; + if (haveSelectedColumnsFlag) { + std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); + if (minMaxIter != rowRangesForColumn.end()) { + const int32_t minValue = minMaxIter->second.m_min; + const int32_t maxValue = minMaxIter->second.m_max; + if (minValue < maxValue) { + minRow = minValue; + maxRow = maxValue + 1; + } } } + + const float minY = minRow * cellHeight; + const float maxY = maxRow * cellHeight; + + std::unique_ptr columnOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + columnOutlineData4f->reserveForNumberOfVertices(4); + + columnOutlineData4f->addVertex(colX, minY); + columnOutlineData4f->addVertex(colX + cellWidth, minY); + columnOutlineData4f->addVertex(colX + cellWidth, maxY); + columnOutlineData4f->addVertex(colX, maxY); + const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(columnOutlineData4f.get()); } - - const float minY = minRow * cellHeight; - const float maxY = maxRow * cellHeight; - - std::unique_ptr columnOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - columnOutlineData4f->reserveForNumberOfVertices(4); - - columnOutlineData4f->addVertex(colX, minY); - columnOutlineData4f->addVertex(colX + cellWidth, minY); - columnOutlineData4f->addVertex(colX + cellWidth, maxY); - columnOutlineData4f->addVertex(colX, maxY); - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(columnOutlineData4f.get()); + glLineWidth(1.0); } - glLineWidth(1.0); + + glPolygonMode(GL_FRONT, GL_FILL); } - glPolygonMode(GL_FRONT, GL_FILL); - } - - if (m_identificationModeFlag) { - processMatrixIdentification(matrixChart); + if (m_identificationModeFlag) { + processMatrixIdentification(matrixChart); + } } } +///* +// * Draw a matrix chart. +// * +// * @param matrixChart +// * Matrix chart that is drawn. +// * @param chartViewingType +// * Type of chart viewing. +// * @param cellWidth +// * Width of cell. +// * @param cellHeight +// * Height of cell. +// * @param zooming +// * Current zooming. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::OLDdrawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, +// const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, +// const float cellWidth, +// const float cellHeight, +// const float zooming) +//{ +// if (m_identificationModeFlag) { +// resetIdentification(); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// +// int32_t numberOfRows = 0; +// int32_t numberOfColumns = 0; +// std::vector matrixRGBA; +// if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, +// numberOfColumns, +// matrixRGBA)) { +// CaretLogWarning("Matrix RGBA invalid"); +// return; +// } +// if ((numberOfRows <= 0) +// || (numberOfColumns <= 0)) { +// return; +// } +// +// const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); +// CaretAssert(matrixProperties); +// +// bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); +// const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); +// +// +// std::vector selectedColumnIndices; +// std::vector selectedRowIndices; +// ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; +// matrixChart->getSelectedRowColumnIndices(m_tabIndex, +// selectedRowColumnDimension, +// selectedRowIndices, +// selectedColumnIndices); +// std::map columnRangesForRow; +// for (int32_t rowIndex : selectedRowIndices) { +// columnRangesForRow[rowIndex] = RowColumnMinMax(); +// } +// const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); +// +// std::map rowRangesForColumn; +// for (int32_t columnIndex : selectedColumnIndices) { +// rowRangesForColumn[columnIndex] = RowColumnMinMax(); +// } +// const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); +// +// uint8_t highlightRGBByte[3]; +// m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); +// const float highlightRGBA[4] = { +// highlightRGBByte[0] / 255.0, +// highlightRGBByte[1] / 255.0, +// highlightRGBByte[2] / 255.0, +// 1.0 +// }; +// +// int32_t rgbaOffset = 0; +// +// std::unique_ptr quadsData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); +// std::unique_ptr quadsData4ub +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); +// const int32_t numberOfCells = numberOfColumns * numberOfRows; +// if (m_identificationModeFlag) { +// quadsData4ub->reserveForNumberOfVertices(numberOfCells); +// } +// else { +// quadsData4f->reserveForNumberOfVertices(numberOfCells); +// } +// +// float cellY = (numberOfRows - 1) * cellHeight; +// for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { +// float cellX = 0; +// for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { +// CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); +// const float* rgba = &matrixRGBA[rgbaOffset]; +// rgbaOffset += 4; +// +// bool drawCellFlag = true; +// if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { +// if (numberOfRows == numberOfColumns) { +// drawCellFlag = false; +// switch (chartViewingType) { +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: +// if (rowIndex != columnIndex) { +// drawCellFlag = true; +// } +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: +// if (rowIndex > columnIndex) { +// drawCellFlag = true; +// } +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: +// if (rowIndex < columnIndex) { +// drawCellFlag = true; +// } +// break; +// } +// } +// else { +// drawCellFlag = false; +// const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); +// const int32_t diagonalRow = static_cast(slope * columnIndex); +// +// switch (chartViewingType) { +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: +// drawCellFlag = true; +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: +// if (rowIndex != diagonalRow) { +// drawCellFlag = true; +// } +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: +// if (rowIndex > diagonalRow) { +// drawCellFlag = true; +// } +// break; +// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: +// if (rowIndex < diagonalRow) { +// drawCellFlag = true; +// } +// break; +// } +// } +// } +// +// if (drawCellFlag) { +// if (haveSelectedRowsFlag) { +// std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); +// if (minMaxIter != columnRangesForRow.end()) { +// if (columnIndex < minMaxIter->second.m_min) { +// minMaxIter->second.m_min = columnIndex; +// } +// if (columnIndex > minMaxIter->second.m_max) { +// minMaxIter->second.m_max = columnIndex; +// } +// } +// } +// +// if (haveSelectedColumnsFlag) { +// std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); +// if (minMaxIter != rowRangesForColumn.end()) { +// if (rowIndex < minMaxIter->second.m_min) { +// minMaxIter->second.m_min = rowIndex; +// } +// if (rowIndex > minMaxIter->second.m_max) { +// minMaxIter->second.m_max = rowIndex; +// } +// } +// } +// +// uint8_t idRGBA[4]; +// if (m_identificationModeFlag) { +// addToChartMatrixIdentification(rowIndex, +// columnIndex, +// idRGBA); +// } +// +// if (m_identificationModeFlag) { +// quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); +// quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); +// quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); +// quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); +// } +// else { +// quadsData4f->addVertex(cellX, cellY, 0.0, rgba); +// quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); +// quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); +// quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); +// } +// } +// +// cellX += cellWidth; +// } +// +// cellY -= cellHeight; +// } +// +// /* +// * Draw the matrix elements. +// */ +// if (m_identificationModeFlag) { +// drawPrimitivePrivate(quadsData4ub.get()); +// } +// else { +// /* +// * Enable alpha blending so voxels that are not drawn from higher layers +// * allow voxels from lower layers to be seen. +// */ +// glEnable(GL_BLEND); +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// +// drawPrimitivePrivate(quadsData4f.get()); +// +// glDisable(GL_BLEND); +// +// +// /* +// * Drawn an outline around the matrix elements. +// */ +// if (displayGridLinesFlag) { +// uint8_t gridLineColorBytes[4]; +// m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); +// float gridLineColorFloats[4]; +// CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, +// gridLineColorFloats); +// gridLineColorFloats[3] = 1.0; +// +// const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); +// const int32_t numCells = static_cast(gridXYZ.size() / 3); +// +// std::unique_ptr outlineData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, +// gridLineColorFloats)); +// outlineData4f->reserveForNumberOfVertices(numCells); +// for (int32_t i = 0; i < numCells; i++) { +// CaretAssertVectorIndex(gridXYZ, i*3); +// outlineData4f->addVertex(&gridXYZ[i*3]); +// } +// glPolygonMode(GL_FRONT, GL_LINE); +// glLineWidth(1.0); +// drawPrimitivePrivate(outlineData4f.get()); +// glPolygonMode(GL_FRONT, GL_FILL); +// } +// +// if ( (! selectedRowIndices.empty()) +// && highlightSelectedRowColumnFlag) { +// for (auto rowIndex : selectedRowIndices) { +// const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; +// +// int32_t minColumn = 0; +// int32_t maxColumn = numberOfColumns; +// if (haveSelectedRowsFlag) { +// std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); +// if (minMaxIter != columnRangesForRow.end()) { +// const int32_t minValue = minMaxIter->second.m_min; +// const int32_t rowMaxColumn = minMaxIter->second.m_max; +// if (minValue < rowMaxColumn) { +// minColumn = minValue; +// maxColumn = rowMaxColumn + 1; +// } +// } +// } +// +// const float minX = minColumn * cellWidth; +// const float maxX = maxColumn * cellWidth; +// +// std::unique_ptr rowOutlineData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// highlightRGBA)); +// rowOutlineData4f->reserveForNumberOfVertices(4); +// +// rowOutlineData4f->addVertex(minX, rowY); +// rowOutlineData4f->addVertex(maxX, rowY); +// rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); +// rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); +// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); +// glLineWidth(highlightLineWidth); +// drawPrimitivePrivate(rowOutlineData4f.get()); +// } +// +// glLineWidth(1.0); +// } +// +// if ( (! selectedColumnIndices.empty()) +// && highlightSelectedRowColumnFlag) { +// for (auto columnIndex : selectedColumnIndices) { +// const float colX = columnIndex * cellWidth; +// +// int32_t minRow = 0; +// int32_t maxRow = numberOfRows; +// if (haveSelectedColumnsFlag) { +// std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); +// if (minMaxIter != rowRangesForColumn.end()) { +// const int32_t minValue = minMaxIter->second.m_min; +// const int32_t maxValue = minMaxIter->second.m_max; +// if (minValue < maxValue) { +// minRow = minValue; +// maxRow = maxValue + 1; +// } +// } +// } +// +// const float minY = minRow * cellHeight; +// const float maxY = maxRow * cellHeight; +// +// std::unique_ptr columnOutlineData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// highlightRGBA)); +// columnOutlineData4f->reserveForNumberOfVertices(4); +// +// columnOutlineData4f->addVertex(colX, minY); +// columnOutlineData4f->addVertex(colX + cellWidth, minY); +// columnOutlineData4f->addVertex(colX + cellWidth, maxY); +// columnOutlineData4f->addVertex(colX, maxY); +// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); +// glLineWidth(highlightLineWidth); +// drawPrimitivePrivate(columnOutlineData4f.get()); +// } +// glLineWidth(1.0); +// } +// +// glPolygonMode(GL_FRONT, GL_FILL); +// } +// +// if (m_identificationModeFlag) { +// processMatrixIdentification(matrixChart); +// } +//} + /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index c7d338791..dda530118 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -127,6 +127,12 @@ namespace caret { const float cellHeight, const float zooming); +// void OLDdrawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, +// const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, +// const float cellWidth, +// const float cellHeight, +// const float zooming); + void drawHistogramChart(); void drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c407ed93f..ba292e46c 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5686,6 +5686,94 @@ BrainOpenGLFixedPipeline::checkForOpenGLError(const Model* model, // } } +/** + * Get the depth and RGBA value at the given pixel position. + * + * @param pixelX + * The pixel X-coordinate + * @param pixelY + * The pixel Y-coordinate + * @param depthOut + * Output containing depth at pixel. + * @param rgbaOut + * Output containing RGBA components at pixel. + * @return + * True if output is valid, else false. + * Invalid could be due to an invalid pixel XY. + * + */ +bool +BrainOpenGLFixedPipeline::getPixelDepthAndRGBA(const int32_t pixelX, + const int32_t pixelY, + float& depthOut, + float rgbaOut[4]) +{ + depthOut = -1.0; + rgbaOut[0] = 0.0; + rgbaOut[1] = 0.0; + rgbaOut[2] = 0.0; + rgbaOut[3] = 0.0; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + if ((pixelX >= viewport[0]) + && (pixelX < viewport[2]) + && (pixelY >= viewport[1]) + && (pixelY < viewport[3])) { + /* OK */ + } + else { + /* + * Invalid pixel XY + */ + return false; + } + + /* + * Saves glPixelStore parameters + */ + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + + /* + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else + glReadBuffer(GL_BACK); +#endif + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 4); // float is 4 bytes + glReadPixels(pixelX, + pixelY, + 1, + 1, + GL_RGBA, + GL_FLOAT, + rgbaOut); + + /* + * Get depth from depth buffer + */ + glReadPixels(pixelX, + pixelY, + 1, + 1, + GL_DEPTH_COMPONENT, + GL_FLOAT, + &depthOut); + + glPopClientAttrib(); + + return true; +} + + /** * Analyze color information to extract identification data. * @param dataType diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 32db1f74d..927854d20 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -337,6 +337,11 @@ namespace caret { void disableLineAntiAliasing(); + bool getPixelDepthAndRGBA(const int32_t pixelX, + const int32_t pixelY, + float& depthOut, + float rgbaOut[4]); + void getIndexFromColorSelection(const SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index 0b3bcce7e..ebab25029 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -287,6 +287,7 @@ ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/FilesBase +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Gifti diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 314498dab..6061b3f44 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -398,6 +398,23 @@ ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, rgbaOut); } +/** + * @return The graphics primitive containing the matrix representation of the file. + * All cells are of dimension 1.0 x 1.0 + * + * @param matrixViewMode + * The matrix visualization mode (upper/lower). + */ +GraphicsPrimitiveV3fC4f* +ChartableTwoFileMatrixChart::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const +{ + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + + return ciftiMapFile->getMatrixChartingGraphicsPrimitive(matrixViewMode); +} + + /** * @return The selected row/column dimension. */ diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 11e984bcc..9b02b5ef4 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -24,6 +24,7 @@ #include "BrainConstants.h" #include "ChartTwoMatrixContentTypeEnum.h" #include "ChartTwoMatrixLoadingDimensionEnum.h" +#include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "ChartableTwoFileBaseChart.h" namespace caret { @@ -33,6 +34,7 @@ namespace caret { class CiftiParcelScalarFile; class CiftiParcelSeriesFile; class CiftiScalarDataSeriesFile; + class GraphicsPrimitiveV3fC4f; class ChartableTwoFileMatrixChart : public ChartableTwoFileBaseChart { @@ -56,6 +58,8 @@ namespace caret { int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; + GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + bool isMatrixTriangularViewingModeSupported() const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 927acaa6f..baf6cbd92 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -48,6 +48,7 @@ #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" +#include "GraphicsPrimitiveV3fC4f.h" #include "GroupAndNameHierarchyModel.h" #include "Histogram.h" #include "NodeAndVoxelColoring.h" @@ -1396,6 +1397,11 @@ CiftiMappableDataFile::invalidateColoringInAllMaps() CaretAssertVectorIndex(m_mapContent, i); m_mapContent[i]->m_rgbaValid = false; } + + /* + * Force recreation of matrix so that it receives updates to coloring. + */ + m_matrixGraphicsPrimitive.reset(); } /** @@ -1475,6 +1481,116 @@ CiftiMappableDataFile::getMatrixRGBA(std::vector &rgba, } } +/** + * @return The graphics primitive containing the matrix representation of the file. + * All cells are of dimension 1.0 x 1.0 + * + * @param matrixViewMode + * The matrix visualization mode (upper/lower). + */ +GraphicsPrimitiveV3fC4f* +CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const +{ + if (m_matrixGraphicsPrimitive == NULL) { + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + std::vector matrixRGBA; + if (getMatrixForChartingRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { + const int32_t numberOfCells = numberOfRows * numberOfColumns; + if (numberOfCells > 0) { + m_matrixGraphicsPrimitive + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + m_matrixGraphicsPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS + m_matrixGraphicsPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + + int32_t rgbaOffset = 0; + const float cellHeight = 1.0; + const float cellWidth = 1.0; + float cellY = (numberOfRows - 1) * cellHeight; + for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { + float cellX = 0; + for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { + CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); + const float* rgba = &matrixRGBA[rgbaOffset]; + rgbaOffset += 4; + + bool drawCellFlag = true; + if (matrixViewMode != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { + if (numberOfRows == numberOfColumns) { + drawCellFlag = false; + switch (matrixViewMode) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > columnIndex) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < columnIndex) { + drawCellFlag = true; + } + break; + } + } + else { + drawCellFlag = true; + const bool allowNonSquareMatrixDiagonalsFlag = false; + if (allowNonSquareMatrixDiagonalsFlag) { + drawCellFlag = false; + const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); + const int32_t diagonalRow = static_cast(slope * columnIndex); + + switch (matrixViewMode) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + drawCellFlag = true; + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + if (rowIndex != diagonalRow) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + if (rowIndex > diagonalRow) { + drawCellFlag = true; + } + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + if (rowIndex < diagonalRow) { + drawCellFlag = true; + } + break; + } + } + } + } + + if (drawCellFlag) { + m_matrixGraphicsPrimitive->addVertex(cellX, cellY, 0.0, rgba); + m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, rgba); + m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); + m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); + } + + cellX += cellWidth; + } + + cellY -= cellHeight; + } + } + + } + } + + return m_matrixGraphicsPrimitive.get(); +} + + /** * Get the matrix RGBA coloring for this matrix data creator. * @@ -2292,6 +2408,11 @@ CiftiMappableDataFile::updateScalarColoringForMap(const int32_t mapIndex, else { CaretAssert(0); } + + /* + * Force recreation of matrix so that it receives updates to coloring. + */ + m_matrixGraphicsPrimitive.reset(); } /** diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 4150c08d6..0c87d3351 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -24,11 +24,13 @@ #include "CaretMappableDataFile.h" #include "CaretPointer.h" #include "CaretObjectTracksModification.h" +#include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "CiftiMappingType.h" #include "CiftiXMLElements.h" #include "DisplayGroupEnum.h" #include "VolumeMappableInterface.h" +#include #include namespace caret { @@ -39,6 +41,7 @@ namespace caret { class CiftiParcelsMap; class CiftiXML; class FastStatistics; + class GraphicsPrimitiveV3fC4f; class GroupAndNameHierarchyModel; class Histogram; class SparseVolumeIndexer; @@ -480,6 +483,8 @@ namespace caret { int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; + GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + virtual void getFileData(std::vector& data) const; const CiftiFile* getCiftiFile() const { return m_ciftiFile; } @@ -738,6 +743,8 @@ namespace caret { /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; + mutable std::unique_ptr m_matrixGraphicsPrimitive; + int32_t m_fileHistogramNumberOfBuckets = 100; /** Histogram with limited values used when statistics computed on all data in file */ diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index dd7eb4b8f..a2bc7b8e5 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -106,6 +106,19 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) { CaretAssert(primitive); + GLenum usageHint = GL_STREAM_DRAW; + switch (primitive->getUsageType()) { + case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES: + usageHint = GL_STREAM_DRAW; + break; + case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES: + usageHint = GL_STATIC_DRAW; + break; + case GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES: + usageHint = GL_DYNAMIC_DRAW; + break; + } + GLsizei coordinateCount = 0; switch (primitive->m_vertexType) { case GraphicsPrimitive::VertexType::FLOAT_XYZ: @@ -126,7 +139,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) glBufferData(GL_ARRAY_BUFFER, xyzSizeBytes, xyzDataPointer, - GL_STREAM_DRAW); + usageHint); break; } @@ -156,7 +169,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) glBufferData(GL_ARRAY_BUFFER, normalSizeBytes, normalDataPointer, - GL_STREAM_DRAW); + usageHint); } break; } @@ -180,7 +193,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, - GL_STREAM_DRAW); + usageHint); } break; case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: @@ -201,7 +214,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, - GL_STREAM_DRAW); + usageHint); } break; } @@ -218,6 +231,53 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) void GraphicsEngineDataOpenGL::draw(void* openglContextPointer, GraphicsPrimitive* primitive) +{ + const float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + drawPrivate(openglContextPointer, + primitive, + dummyRGBA, + false); +} + +/** + * Draw the given graphics primitive. + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + * @param solidColorOverrideRGBA + * Color that is applied to all vertices. + */ +void +GraphicsEngineDataOpenGL::drawWithOverrideColor(void* openglContextPointer, + GraphicsPrimitive* primitive, + const float solidColorOverrideRGBA[4]) +{ + drawPrivate(openglContextPointer, + primitive, + solidColorOverrideRGBA, + true); +} + + +/** + * Draw the graphics primitive. + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + * @param solidColorOverrideRGBA + * RGBA for overriding primitive's internal color data. + * @param solidColorOverrideValid + * If true, color with the override color instead of the internal color. + */ +void +GraphicsEngineDataOpenGL::drawPrivate(void* openglContextPointer, + GraphicsPrimitive* primitive, + const float solidColorOverrideRGBA[4], + const bool solidColorOverrideValid) { CaretAssert(openglContextPointer); CaretAssert(primitive); @@ -225,6 +285,7 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, return; } + GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); if (openglData == NULL) { openglData = new GraphicsEngineDataOpenGL(openglContextPointer); @@ -273,9 +334,44 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, /* * Setup colors for drawing */ - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); + GLuint overrideColorBufferName = 0; + if (solidColorOverrideValid) { + const int32_t numberOfVertices = primitive->m_xyz.size() / 3; + if (numberOfVertices > 0) { + glGenBuffers(1, &overrideColorBufferName); + CaretAssert(overrideColorBufferName > 0); + + const GLint componentsPerColor = 4; + const GLenum colorDataType = GL_FLOAT; + + + std::vector colorRGBA(numberOfVertices * componentsPerColor); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(colorRGBA, i4 + 3); + colorRGBA[i4] = solidColorOverrideRGBA[0]; + colorRGBA[i4+1] = solidColorOverrideRGBA[1]; + colorRGBA[i4+2] = solidColorOverrideRGBA[2]; + colorRGBA[i4+3] = solidColorOverrideRGBA[3]; + } + + const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; + glBindBuffer(GL_ARRAY_BUFFER, + overrideColorBufferName); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + } + } + else { + glEnableClientState(GL_COLOR_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); + } /* * Unbind buffers @@ -331,6 +427,10 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + + if (overrideColorBufferName > 0) { + glDeleteBuffers(1, &overrideColorBufferName); + } } /** diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 623617b2e..ff43f701c 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -48,6 +48,10 @@ namespace caret { static void draw(void* openglContextPointer, GraphicsPrimitive* primitive); + static void drawWithOverrideColor(void* openglContextPointer, + GraphicsPrimitive* primitive, + const float solidColorOverrideRGBA[4]); + const void* getOpenGLContextPointer() const; // ADD_NEW_METHODS_HERE @@ -59,6 +63,11 @@ namespace caret { void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); + static void drawPrivate(void* openglContextPointer, + GraphicsPrimitive* primitive, + const float solidColorOverrideRGBA[4], + const bool solidColorOverrideValid); + const void* m_openglContextPointer; GLsizei m_arrayIndicesCount = 0; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 80b266683..7a738dd50 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -144,6 +144,28 @@ GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) } } +/** + * @return The usage type hint for graphics system. + */ +GraphicsPrimitive::UsageType +GraphicsPrimitive::getUsageType() const +{ + return m_usageType; +} + +/** + * Set the usage type hint for graphics system. + * + * @param usageType + * New value for usage type. + */ +void +GraphicsPrimitive::setUsageType(const UsageType usageType) +{ + m_usageType = usageType; +} + + /** * @return Is this graphics primitive valid. * Primitive is valid if all of these conditions are met @@ -427,7 +449,6 @@ GraphicsPrimitive::setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* grap m_graphicsEngineDataForOpenGL.reset(graphicsEngineDataForOpenGL); } - /** * Receive an event. * diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index dd8db9de3..090f95fe5 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -130,6 +130,28 @@ namespace caret { TRIANGLES }; + /** + * Hint to graphics engine on how the primitive is used. + * The hint must be set prior to loading of buffers. + */ + enum class UsageType { + /** + * Buffer is modified once and used a few times + * Like OpenGL STREAM_DRAW + */ + MODIFIED_ONCE_DRAWN_FEW_TIMES, + /** + * Buffer is modified once and used many times + * Like OpenGL STATIC_DRAW + */ + MODIFIED_ONCE_DRAWN_MANY_TIMES, + /** + * Buffer is modified many times and used many times + * Like OpenGL DYNAMIC_DRAW + */ + MODIFIED_MANY_DRAWN_MANY_TIMES + }; + protected: GraphicsPrimitive(const VertexType vertexType, const NormalVectorType normalVectorType, @@ -156,6 +178,10 @@ namespace caret { void reserveForNumberOfVertices(const int32_t numberOfVertices); + UsageType getUsageType() const; + + void setUsageType(const UsageType usage); + virtual void receiveEvent(Event* event); bool isValid() const; @@ -204,6 +230,8 @@ namespace caret { const PrimitiveType m_primitiveType; + UsageType m_usageType = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; + std::unique_ptr m_graphicsEngineDataForOpenGL; std::vector m_xyz; diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 315e9e426..1568b0251 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -38,6 +38,7 @@ using namespace caret; #include "AnnotationColorBar.h" +#include "Brain.h" #include "CaretMappableDataFile.h" #include "ChartTwoOverlay.h" #include "ChartableTwoFileDelegate.h" @@ -939,6 +940,16 @@ ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* ac if (valid) { m_chartOverlay->setMatrixTriangularViewingMode(viewMode); updateMatrixTriangularViewModeAction(viewMode); + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + if (mapFile != NULL) { + PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); + mapFile->updateScalarColoringForAllMaps(paletteFile); + } this->updateGraphicsWindow(); } } -- GitLab From 936f63bd24b1a4055b35d514263dca4ded0166a9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 21 Apr 2017 11:57:39 -0500 Subject: [PATCH 257/755] Added GraphicsPrimitiveSelectionHelper that is used to simplify selection of new OpenGL primitives during an identification operation. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 323 ++++++++++-------- src/Files/CiftiMappableDataFile.cxx | 20 ++ src/Graphics/CMakeLists.txt | 2 + src/Graphics/GraphicsEngineDataOpenGL.cxx | 221 +++++++++--- src/Graphics/GraphicsEngineDataOpenGL.h | 21 +- src/Graphics/GraphicsPrimitive.h | 6 + .../GraphicsPrimitiveSelectionHelper.cxx | 223 ++++++++++++ .../GraphicsPrimitiveSelectionHelper.h | 77 +++++ 8 files changed, 695 insertions(+), 198 deletions(-) create mode 100644 src/Graphics/GraphicsPrimitiveSelectionHelper.cxx create mode 100644 src/Graphics/GraphicsPrimitiveSelectionHelper.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index b2689eda0..b72ffbc0e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -997,162 +997,197 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - drawPrimitivePrivate(matrixPrimitive); - - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); - CaretAssert(matrixProperties); - - if (matrixProperties->isGridLinesDisplayed()) { - glPolygonMode(GL_FRONT, - GL_LINE); - uint8_t gridLineColorBytes[4]; - m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); - float gridLineColorFloats[4]; - CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, - gridLineColorFloats); - gridLineColorFloats[3] = 1.0; - GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), - matrixPrimitive, - gridLineColorFloats); - glPolygonMode(GL_FRONT, - GL_FILL); - } - - int32_t numberOfRows = 0; - int32_t numberOfColumns = 0; - matrixChart->getMatrixDimensions(numberOfRows, - numberOfColumns); - - if (matrixProperties->isSelectedRowColumnHighlighted()) { - uint8_t highlightRGBByte[3]; - m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); - const float highlightRGBA[4] = { - highlightRGBByte[0] / 255.0, - highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0, - 1.0 - }; - - std::vector selectedColumnIndices; - std::vector selectedRowIndices; - ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; - matrixChart->getSelectedRowColumnIndices(m_tabIndex, - selectedRowColumnDimension, - selectedRowIndices, - selectedColumnIndices); - for (auto rowIndex : selectedRowIndices) { - std::unique_ptr rowOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - rowOutlineData4f->reserveForNumberOfVertices(4); - - float minX = 0; - float maxX = numberOfColumns; - const float minY = numberOfRows - rowIndex - 1; - const float maxY = minY + 1.0f; - - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxX = rowIndex; // matrix is symmetric - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minX = rowIndex + 1; // matrix is symmetric - break; - } - - rowOutlineData4f->addVertex(minX, minY); - rowOutlineData4f->addVertex(maxX, minY); - rowOutlineData4f->addVertex(maxX, maxY); - rowOutlineData4f->addVertex(minX, maxY); - const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(rowOutlineData4f.get()); - } - - for (auto columnIndex : selectedColumnIndices) { - std::unique_ptr columnOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - columnOutlineData4f->reserveForNumberOfVertices(4); + if (m_identificationModeFlag) { + int32_t primitiveIndex = -1; + float primitiveDepth = 0.0; + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + matrixPrimitive, + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + //std::cout << "Matrix selection: " << primitiveIndex << std::endl; + if (primitiveIndex >= 0) { + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + matrixChart->getMatrixDimensions(numberOfRows, + numberOfColumns); - const float minX = columnIndex; - const float maxX = columnIndex + 1; - float minY = 0; - float maxY = numberOfRows;; + const int32_t rowIndex = primitiveIndex / numberOfColumns; + const int32_t colIndex = primitiveIndex % numberOfColumns; + //std::cout << " row=" << rowIndex << " col=" << colIndex << std::endl; - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxY = columnIndex; // matrix is symmetric - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minY = columnIndex + 1; // matrix is symmetric - break; + if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(primitiveDepth)) { + m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), + rowIndex, + colIndex); } - columnOutlineData4f->addVertex(minX, minY); - columnOutlineData4f->addVertex(maxX, minY); - columnOutlineData4f->addVertex(maxX, maxY); - columnOutlineData4f->addVertex(minX, maxY); - const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(columnOutlineData4f.get()); } } - - if (m_identificationModeFlag) { - /* - * - */ - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - GLdouble projectionMatrix[16]; - glGetDoublev(GL_PROJECTION_MATRIX, - projectionMatrix); - GLdouble modelMatrix[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, - modelMatrix); - GLdouble windowXYZ[3] = { m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, 0.0 }; + else { + drawPrimitivePrivate(matrixPrimitive); + + const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + CaretAssert(matrixProperties); + + if (matrixProperties->isGridLinesDisplayed()) { + glPolygonMode(GL_FRONT, + GL_LINE); + uint8_t gridLineColorBytes[4]; + m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); + float gridLineColorFloats[4]; + CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, + gridLineColorFloats); + gridLineColorFloats[3] = 1.0; + GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), + matrixPrimitive, + gridLineColorFloats); + glPolygonMode(GL_FRONT, + GL_FILL); + } - GLdouble matrixXYZ[3]; - if (gluUnProject(windowXYZ[0], windowXYZ[1], windowXYZ[2], - modelMatrix, projectionMatrix, viewport, - &matrixXYZ[0], &matrixXYZ[1], &matrixXYZ[2])) { - const int32_t rowOriginBottomIndex = static_cast(matrixXYZ[1]); - const int32_t columnIndex = static_cast(matrixXYZ[0]); - if ((rowOriginBottomIndex >= 0) - && (rowOriginBottomIndex < numberOfRows) - && (columnIndex >= 0) - && (columnIndex < numberOfColumns)) { - const int32_t rowIndex = numberOfRows - rowOriginBottomIndex - 1; + int32_t numberOfRows = 0; + int32_t numberOfColumns = 0; + matrixChart->getMatrixDimensions(numberOfRows, + numberOfColumns); + + if (matrixProperties->isSelectedRowColumnHighlighted()) { + uint8_t highlightRGBByte[3]; + m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); + const float highlightRGBA[4] = { + highlightRGBByte[0] / 255.0, + highlightRGBByte[1] / 255.0, + highlightRGBByte[2] / 255.0, + 1.0 + }; + + std::vector selectedColumnIndices; + std::vector selectedRowIndices; + ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; + matrixChart->getSelectedRowColumnIndices(m_tabIndex, + selectedRowColumnDimension, + selectedRowIndices, + selectedColumnIndices); + for (auto rowIndex : selectedRowIndices) { + std::unique_ptr rowOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + rowOutlineData4f->reserveForNumberOfVertices(4); - float pixelRGBA[4]; - float pixelDepth = 0.0; - if (m_fixedPipelineDrawing->getPixelDepthAndRGBA(m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - pixelDepth, - pixelRGBA)) { - - std::cout << "Pixel Depth/RGBA: " << pixelDepth << ", " << AString::fromNumbers(pixelRGBA, 4, ",") << std::endl; - if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(pixelDepth)) { - if (pixelRGBA[3] > 0.0) { - m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), - rowIndex, - columnIndex); - } - } + float minX = 0; + float maxX = numberOfColumns; + const float minY = numberOfRows - rowIndex - 1; + const float maxY = minY + 1.0f; + + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxX = rowIndex; // matrix is symmetric + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minX = rowIndex + 1; // matrix is symmetric + break; } + + rowOutlineData4f->addVertex(minX, minY); + rowOutlineData4f->addVertex(maxX, minY); + rowOutlineData4f->addVertex(maxX, maxY); + rowOutlineData4f->addVertex(minX, maxY); + const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(rowOutlineData4f.get()); + } + + for (auto columnIndex : selectedColumnIndices) { + std::unique_ptr columnOutlineData4f + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + highlightRGBA)); + columnOutlineData4f->reserveForNumberOfVertices(4); + + const float minX = columnIndex; + const float maxX = columnIndex + 1; + float minY = 0; + float maxY = numberOfRows; + + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxY = columnIndex; // matrix is symmetric + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minY = columnIndex + 1; // matrix is symmetric + break; + } + columnOutlineData4f->addVertex(minX, minY); + columnOutlineData4f->addVertex(maxX, minY); + columnOutlineData4f->addVertex(maxX, maxY); + columnOutlineData4f->addVertex(minX, maxY); + const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); + glLineWidth(highlightLineWidth); + drawPrimitivePrivate(columnOutlineData4f.get()); } } } +// if (m_identificationModeFlag) { +// int32_t numberOfRows = 0; +// int32_t numberOfColumns = 0; +// matrixChart->getMatrixDimensions(numberOfRows, +// numberOfColumns); +// +// /* +// * While this works, it uses OpenGL functions (gluUnproject) that +// * are removed in in the programmable pipeline OpenGL +// */ +// GLint viewport[4]; +// glGetIntegerv(GL_VIEWPORT, +// viewport); +// GLdouble projectionMatrix[16]; +// glGetDoublev(GL_PROJECTION_MATRIX, +// projectionMatrix); +// GLdouble modelMatrix[16]; +// glGetDoublev(GL_MODELVIEW_MATRIX, +// modelMatrix); +// GLdouble windowXYZ[3] = { m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, 0.0 }; +// +// GLdouble matrixXYZ[3]; +// if (gluUnProject(windowXYZ[0], windowXYZ[1], windowXYZ[2], +// modelMatrix, projectionMatrix, viewport, +// &matrixXYZ[0], &matrixXYZ[1], &matrixXYZ[2])) { +// const int32_t rowOriginBottomIndex = static_cast(matrixXYZ[1]); +// const int32_t columnIndex = static_cast(matrixXYZ[0]); +// if ((rowOriginBottomIndex >= 0) +// && (rowOriginBottomIndex < numberOfRows) +// && (columnIndex >= 0) +// && (columnIndex < numberOfColumns)) { +// const int32_t rowIndex = numberOfRows - rowOriginBottomIndex - 1; +// +// float pixelRGBA[4]; +// float pixelDepth = 0.0; +// if (m_fixedPipelineDrawing->getPixelDepthAndRGBA(m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// pixelDepth, +// pixelRGBA)) { +// +// std::cout << "Pixel Depth/RGBA: " << pixelDepth << ", " << AString::fromNumbers(pixelRGBA, 4, ",") << std::endl; +// if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(pixelDepth)) { +// if (pixelRGBA[3] > 0.0) { +// m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), +// rowIndex, +// columnIndex); +// } +// } +// } +// } +// } +// } + glDisable(GL_BLEND); glPopMatrix(); diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index baf6cbd92..0bc316425 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1503,6 +1503,20 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr m_matrixGraphicsPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS m_matrixGraphicsPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + /* + * NOTE: All matrix cells receive coloring, event those that are + * not displayed due to the triangular view selection. + * The reason is that it greatly simplifies identification as + * one can derive the row and column from the primitive index. + * Using quads also simplifies identification. Lastly, since + * OpenGL buffers are used, drawing is very fast. + */ + + /* + * Alpha zero for cells that are "not drawn" + */ + const float cellNotDrawRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + int32_t rgbaOffset = 0; const float cellHeight = 1.0; const float cellWidth = 1.0; @@ -1576,6 +1590,12 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); } + else { + m_matrixGraphicsPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); + m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); + m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); + m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); + } cellX += cellWidth; } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index d7a9b62f4..d8f11d61e 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -39,6 +39,7 @@ GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h GraphicsPrimitive.h +GraphicsPrimitiveSelectionHelper.h GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h @@ -49,6 +50,7 @@ GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx GraphicsPrimitive.cxx +GraphicsPrimitiveSelectionHelper.cxx GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index a2bc7b8e5..de8adf863 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -29,6 +29,7 @@ #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" #include "GraphicsPrimitive.h" +#include "GraphicsPrimitiveSelectionHelper.h" using namespace caret; @@ -232,13 +233,96 @@ void GraphicsEngineDataOpenGL::draw(void* openglContextPointer, GraphicsPrimitive* primitive) { - const float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - drawPrivate(openglContextPointer, + float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + drawPrivate(PrivateDrawMode::DRAW_NORMAL, + openglContextPointer, primitive, - dummyRGBA, - false); + NULL, + dummyRGBA); } +void +GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, + GraphicsPrimitive* primitive, + const int32_t pixelX, + const int32_t pixelY, + int32_t& selectedPrimitiveIndexOut, + float& selectedPrimitiveDepthOut) +{ + CaretAssert(primitive); + + selectedPrimitiveIndexOut = -1; + selectedPrimitiveDepthOut = 0.0; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + if ((pixelX >= viewport[0]) + && (pixelX < viewport[2]) + && (pixelY >= viewport[1]) + && (pixelY < viewport[3])) { + /* + * Saves glPixelStore parameters + */ + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + glPushAttrib(GL_LIGHTING_BIT); + + glShadeModel(GL_FLAT); + glDisable(GL_LIGHTING); + + float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + GraphicsPrimitiveSelectionHelper selectionHelper(primitive); + selectionHelper.setupSelectionBeforeDrawing(); + drawPrivate(PrivateDrawMode::DRAW_SELECTION, + openglContextPointer, + primitive, + &selectionHelper, + dummyRGBA); + + /* + * QOpenGLWidget Note: The QOpenGLWidget always renders in a + * frame buffer object (see its documentation). This is + * probably why calls to glReadBuffer() always cause an + * OpenGL error. + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* do not call glReadBuffer() */ +#else + glReadBuffer(GL_BACK); +#endif + uint8_t pixelRGBA[4]; + + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); // bytes + glReadPixels(pixelX, + pixelY, + 1, + 1, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixelRGBA); + + /* + * Get depth from depth buffer + */ + glPixelStorei(GL_PACK_ALIGNMENT, 4); // float + glReadPixels(pixelX, + pixelY, + 1, + 1, + GL_DEPTH_COMPONENT, + GL_FLOAT, + &selectedPrimitiveDepthOut); + + glPopAttrib(); + glPopClientAttrib(); + + selectedPrimitiveIndexOut = selectionHelper.getPrimitiveIndexFromEncodedRGBA(pixelRGBA); + } +} + + /** * Draw the given graphics primitive. * @@ -254,30 +338,33 @@ GraphicsEngineDataOpenGL::drawWithOverrideColor(void* openglContextPointer, GraphicsPrimitive* primitive, const float solidColorOverrideRGBA[4]) { - drawPrivate(openglContextPointer, + drawPrivate(PrivateDrawMode::DRAW_COLOR_SOLID, + openglContextPointer, primitive, - solidColorOverrideRGBA, - true); + NULL, + solidColorOverrideRGBA); } - /** * Draw the graphics primitive. * + * @param drawMode + * Mode for drawing. * @param openglContextPointer * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. - * @param solidColorOverrideRGBA - * RGBA for overriding primitive's internal color data. - * @param solidColorOverrideValid - * If true, color with the override color instead of the internal color. + * @param primitiveSelectionHelper + * Selection helper when draw mode is selection. + * @param solidColorRGBA + * Color for solid color mode. */ void -GraphicsEngineDataOpenGL::drawPrivate(void* openglContextPointer, +GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, + void* openglContextPointer, GraphicsPrimitive* primitive, - const float solidColorOverrideRGBA[4], - const bool solidColorOverrideValid) + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, + const float solidColorRGBA[4]) { CaretAssert(openglContextPointer); CaretAssert(primitive); @@ -334,43 +421,75 @@ GraphicsEngineDataOpenGL::drawPrivate(void* openglContextPointer, /* * Setup colors for drawing */ - GLuint overrideColorBufferName = 0; - if (solidColorOverrideValid) { - const int32_t numberOfVertices = primitive->m_xyz.size() / 3; - if (numberOfVertices > 0) { - glGenBuffers(1, &overrideColorBufferName); - CaretAssert(overrideColorBufferName > 0); - - const GLint componentsPerColor = 4; - const GLenum colorDataType = GL_FLOAT; - - - std::vector colorRGBA(numberOfVertices * componentsPerColor); - for (int32_t i = 0; i < numberOfVertices; i++) { - const int32_t i4 = i * 4; - CaretAssertVectorIndex(colorRGBA, i4 + 3); - colorRGBA[i4] = solidColorOverrideRGBA[0]; - colorRGBA[i4+1] = solidColorOverrideRGBA[1]; - colorRGBA[i4+2] = solidColorOverrideRGBA[2]; - colorRGBA[i4+3] = solidColorOverrideRGBA[3]; + GLuint localColorBufferName = 0; + switch (drawMode) { + case PrivateDrawMode::DRAW_COLOR_SOLID: + { + const int32_t numberOfVertices = primitive->m_xyz.size() / 3; + if (numberOfVertices > 0) { + glGenBuffers(1, &localColorBufferName); + CaretAssert(localColorBufferName > 0); + + const GLint componentsPerColor = 4; + const GLenum colorDataType = GL_FLOAT; + + + std::vector colorRGBA(numberOfVertices * componentsPerColor); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(colorRGBA, i4 + 3); + colorRGBA[i4] = solidColorRGBA[0]; + colorRGBA[i4+1] = solidColorRGBA[1]; + colorRGBA[i4+2] = solidColorRGBA[2]; + colorRGBA[i4+3] = solidColorRGBA[3]; + } + + const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; + glBindBuffer(GL_ARRAY_BUFFER, + localColorBufferName); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); } - - const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); - const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; - glBindBuffer(GL_ARRAY_BUFFER, - overrideColorBufferName); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); + } + break; + case PrivateDrawMode::DRAW_NORMAL: + { glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); } - } - else { - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); + break; + case PrivateDrawMode::DRAW_SELECTION: + { + const int32_t numberOfVertices = primitive->m_xyz.size() / 3; + if (numberOfVertices > 0) { + glGenBuffers(1, &localColorBufferName); + CaretAssert(localColorBufferName > 0); + + const GLint componentsPerColor = 4; + const GLenum colorDataType = GL_UNSIGNED_BYTE; + + const std::vector selectionRGBA = primitiveSelectionHelper->getSelectionEncodedRGBA(); + CaretAssert((selectionRGBA.size() / 4) == numberOfVertices); + + const GLuint colorSizeBytes = selectionRGBA.size() * sizeof(GLubyte); + const GLvoid* colorDataPointer = (const GLvoid*)&selectionRGBA[0]; + glBindBuffer(GL_ARRAY_BUFFER, + localColorBufferName); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + } + } + break; } /* @@ -428,8 +547,8 @@ GraphicsEngineDataOpenGL::drawPrivate(void* openglContextPointer, glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - if (overrideColorBufferName > 0) { - glDeleteBuffers(1, &overrideColorBufferName); + if (localColorBufferName > 0) { + glDeleteBuffers(1, &localColorBufferName); } } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index ff43f701c..216399d10 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -33,6 +33,7 @@ namespace caret { class GraphicsOpenGLBufferObject; class GraphicsPrimitive; + class GraphicsPrimitiveSelectionHelper; class GraphicsEngineDataOpenGL : public GraphicsEngineData { @@ -48,6 +49,13 @@ namespace caret { static void draw(void* openglContextPointer, GraphicsPrimitive* primitive); + static void drawWithSelection(void* openglContextPointer, + GraphicsPrimitive* primitive, + const int32_t pixelX, + const int32_t pixelY, + int32_t& selectedPrimitiveIndexOut, + float& selectedPrimitiveDepthOut); + static void drawWithOverrideColor(void* openglContextPointer, GraphicsPrimitive* primitive, const float solidColorOverrideRGBA[4]); @@ -57,16 +65,23 @@ namespace caret { // ADD_NEW_METHODS_HERE private: + enum class PrivateDrawMode { + DRAW_COLOR_SOLID, + DRAW_NORMAL, + DRAW_SELECTION + }; + GraphicsEngineDataOpenGL(const GraphicsEngineDataOpenGL&); GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); - static void drawPrivate(void* openglContextPointer, + static void drawPrivate(const PrivateDrawMode drawMode, + void* openglContextPointer, GraphicsPrimitive* primitive, - const float solidColorOverrideRGBA[4], - const bool solidColorOverrideValid); + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, + const float solidColorRGBA[4]); const void* m_openglContextPointer; diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 090f95fe5..9d987c96e 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -201,6 +201,11 @@ namespace caret { */ inline ColorType getColorType() const { return m_colorType; } + /** + * @return Type of primitive. + */ + inline PrimitiveType getPrimitiveType() const { return m_primitiveType; } + /** * @return The float coordinates. */ @@ -246,6 +251,7 @@ namespace caret { void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); friend class GraphicsEngineDataOpenGL; + friend class GraphicsPrimitiveSelectionHelper; // ADD_NEW_MEMBERS_HERE diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx new file mode 100644 index 000000000..131df6542 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -0,0 +1,223 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ +#include "GraphicsPrimitiveSelectionHelper.h" +#undef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "GraphicsPrimitive.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveSelectionHelper + * \brief Helps with identification of graphics primitives + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsPrimitiveSelectionHelper::GraphicsPrimitiveSelectionHelper(GraphicsPrimitive* parentGraphicsPrimitive) +: CaretObject(), +m_parentGraphicsPrimitive(parentGraphicsPrimitive) +{ + CaretAssert(m_parentGraphicsPrimitive); +} + +/** + * Destructor. + */ +GraphicsPrimitiveSelectionHelper::~GraphicsPrimitiveSelectionHelper() +{ + +} + +/** + * Setup selection data just before drawing. + */ +void +GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() +{ + m_numberOfVerticesPerPrimitive = 0; + + switch (m_parentGraphicsPrimitive->getPrimitiveType()) { + case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::LINES: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::POINTS: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::POLYGON: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::QUADS: + m_numberOfVerticesPerPrimitive = 4; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + CaretAssertMessage(0, "Not yet implemented"); + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLES: + CaretAssertMessage(0, "Not yet implemented"); + break; + } + + int32_t numberOfVertices = 0; + + switch (m_parentGraphicsPrimitive->getVertexType()) { + case GraphicsPrimitive::VertexType::FLOAT_XYZ: + numberOfVertices = m_parentGraphicsPrimitive->getFloatXYZ().size() / 3; + break; + } + if (numberOfVertices > 0) { + const int32_t numberOfPrimitives = numberOfVertices / m_numberOfVerticesPerPrimitive; + const int32_t maxPrimitivesSupported = 255 * 255 * 255; + if (numberOfPrimitives > maxPrimitivesSupported) { + const AString msg("Number of primitives for selection=" + + AString::number(numberOfPrimitives) + + " exceeds maximum allowed=" + + AString::number(maxPrimitivesSupported)); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + else { + const int32_t selectionRgbaSize = numberOfVertices * 4; + + if (selectionRgbaSize != static_cast(m_selectionEncodedRGBA.size())) { + const GraphicsPrimitive::ColorType colorType = m_parentGraphicsPrimitive->getColorType(); + + m_selectionEncodedRGBA.resize(selectionRgbaSize); + + /* + * Encode the primitive index into the RGBA selection data + */ + int32_t indexRGBA = 0; + for (int32_t primitiveIndex = 0; primitiveIndex < numberOfPrimitives; primitiveIndex++) { + uint8_t blue = (uint8_t)(primitiveIndex & 0xff); + uint8_t green = (uint8_t)((primitiveIndex >> 8) & 0xff); + uint8_t red = (uint8_t)((primitiveIndex >> 16) & 0xff); + + /* + * Same ID color at all vertices of a primitive + */ + for (int32_t j = 0; j < m_numberOfVerticesPerPrimitive; j++) { + CaretAssertVectorIndex(m_selectionEncodedRGBA, indexRGBA+3); + m_selectionEncodedRGBA[indexRGBA] = red; + m_selectionEncodedRGBA[indexRGBA+1] = green; + m_selectionEncodedRGBA[indexRGBA+2] = blue; + + uint8_t vertexAlpha = 0.0; + const int32_t vertexAlphaIndex = indexRGBA + 3; + switch (colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_floatRGBA, + vertexAlphaIndex); + vertexAlpha = static_cast(m_parentGraphicsPrimitive->m_floatRGBA[vertexAlphaIndex] * 255); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_unsignedByteRGBA, + vertexAlphaIndex); + vertexAlpha = m_parentGraphicsPrimitive->m_unsignedByteRGBA[vertexAlphaIndex]; + break; + } + + m_selectionEncodedRGBA[indexRGBA+3] = vertexAlpha; + indexRGBA += 4; + } + } + } + } + } + else { + m_selectionEncodedRGBA.clear(); + } +} + +/** + * Get the index of the primitive that was selected using the encoded RGBA. + * + * @param rgba + * RGBA with encoded selection information. + * @return + * Index of selected primitive or -1 if none selected. + */ +int32_t +GraphicsPrimitiveSelectionHelper::getPrimitiveIndexFromEncodedRGBA(const uint8_t rgba[4]) const +{ + int32_t primitiveIndex(-1); + + const int32_t numberOfVertices = static_cast(m_selectionEncodedRGBA.size() / 4); + if (numberOfVertices > 0) { + CaretAssert(m_numberOfVerticesPerPrimitive > 0); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(m_selectionEncodedRGBA, i4+3); + if ((rgba[0] == m_selectionEncodedRGBA[i4]) + && (rgba[1] == m_selectionEncodedRGBA[i4+1]) + && (rgba[2] == m_selectionEncodedRGBA[i4+2])) { + if (m_selectionEncodedRGBA[i4+3] > 0) { + primitiveIndex = i / m_numberOfVerticesPerPrimitive; + } + break; + } + } + } + + return primitiveIndex; +} + +/** + * @return The RGBA data in which identification information is encoded. + */ +const +std::vector& +GraphicsPrimitiveSelectionHelper::getSelectionEncodedRGBA() const +{ + return m_selectionEncodedRGBA; +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsPrimitiveSelectionHelper::toString() const +{ + return "GraphicsPrimitiveSelectionHelper"; +} + diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.h b/src/Graphics/GraphicsPrimitiveSelectionHelper.h new file mode 100644 index 000000000..68f3bf2e0 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.h @@ -0,0 +1,77 @@ +#ifndef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ +#define __GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class GraphicsPrimitive; + + class GraphicsPrimitiveSelectionHelper : public CaretObject { + + public: + GraphicsPrimitiveSelectionHelper(GraphicsPrimitive* parentGraphicsPrimitive); + + virtual ~GraphicsPrimitiveSelectionHelper(); + + void setupSelectionBeforeDrawing(); + + const std::vector& getSelectionEncodedRGBA() const; + + int32_t getPrimitiveIndexFromEncodedRGBA(const uint8_t rgba[4]) const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + GraphicsPrimitiveSelectionHelper(const GraphicsPrimitiveSelectionHelper&); + + GraphicsPrimitiveSelectionHelper& operator=(const GraphicsPrimitiveSelectionHelper&); + + GraphicsPrimitive* m_parentGraphicsPrimitive; + + int32_t m_numberOfVerticesPerPrimitive = 0; + + //int32_t m_numberOfSelectionIndicesPerPrimitive = 0; + + std::vector m_selectionEncodedRGBA; + + //std::vector m_selectionIndices; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ -- GitLab From 91b6df87c24e78cfc15792d5e5e57305d090d3c1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 May 2017 15:39:21 -0500 Subject: [PATCH 258/755] Add event to get the Caret Preferences --- src/Brain/SessionManager.cxx | 11 +++- src/Common/CMakeLists.txt | 2 + src/Common/EventCaretPreferencesGet.cxx | 75 +++++++++++++++++++++++++ src/Common/EventCaretPreferencesGet.h | 65 +++++++++++++++++++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 ++ src/Common/EventTypeEnum.h | 2 + 7 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/Common/EventCaretPreferencesGet.cxx create mode 100644 src/Common/EventCaretPreferencesGet.h diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 1cd719d43..045ed9061 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -41,6 +41,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventBrowserTabNew.h" +#include "EventCaretPreferencesGet.h" #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventModelGetAll.h" @@ -76,12 +77,12 @@ SessionManager::SessionManager() m_browserTabs[i] = NULL; } - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_PREFERENCES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL); @@ -340,6 +341,14 @@ SessionManager::receiveEvent(Event* event) } } } + else if (event->getEventType() == EventTypeEnum::EVENT_CARET_PREFERENCES_GET) { + EventCaretPreferencesGet* preferencesEvent = + dynamic_cast(event); + CaretAssert(preferencesEvent); + + preferencesEvent->setCaretPreferences(m_caretPreferences); + preferencesEvent->setEventProcessed(); + } else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_ADD) { EventModelAdd* addModelsEvent = dynamic_cast(event); diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index e97045e39..a5e79a362 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -99,6 +99,7 @@ ElapsedTimer.h Event.h EventAlertUser.h EventBrowserTabIndicesGetAll.h +EventCaretPreferencesGet.h EventGetViewportSize.h EventListenerInterface.h EventManager.h @@ -198,6 +199,7 @@ ElapsedTimer.cxx Event.cxx EventAlertUser.cxx EventBrowserTabIndicesGetAll.cxx +EventCaretPreferencesGet.cxx EventGetViewportSize.cxx EventManager.cxx EventPaletteGetByName.cxx diff --git a/src/Common/EventCaretPreferencesGet.cxx b/src/Common/EventCaretPreferencesGet.cxx new file mode 100644 index 000000000..1ce82069b --- /dev/null +++ b/src/Common/EventCaretPreferencesGet.cxx @@ -0,0 +1,75 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CARET_PREFERENCES_GET_DECLARE__ +#include "EventCaretPreferencesGet.h" +#undef __EVENT_CARET_PREFERENCES_GET_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventCaretPreferencesGet + * \brief Event to get the Caret Preferences + * \ingroup Common + */ + +/** + * Constructor. + */ +EventCaretPreferencesGet::EventCaretPreferencesGet() +: Event(EventTypeEnum::EVENT_CARET_PREFERENCES_GET) +{ + +} + +/** + * Destructor. + */ +EventCaretPreferencesGet::~EventCaretPreferencesGet() +{ +} + +/** + * Set the caret preferences. + * + * @param caretPreferences + * Pointer to Caret Preferences + */ +void +EventCaretPreferencesGet::setCaretPreferences(CaretPreferences* caretPreferences) +{ + m_caretPreferences = caretPreferences; +} + +/** + * @return The caret preferences (NULL if caret preferences are invalid) + */ +CaretPreferences* +EventCaretPreferencesGet::getCaretPreferences() const +{ + return m_caretPreferences; +} + diff --git a/src/Common/EventCaretPreferencesGet.h b/src/Common/EventCaretPreferencesGet.h new file mode 100644 index 000000000..f381205c1 --- /dev/null +++ b/src/Common/EventCaretPreferencesGet.h @@ -0,0 +1,65 @@ +#ifndef __EVENT_CARET_PREFERENCES_GET_H__ +#define __EVENT_CARET_PREFERENCES_GET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class CaretPreferences; + + class EventCaretPreferencesGet : public Event { + + public: + EventCaretPreferencesGet(); + + virtual ~EventCaretPreferencesGet(); + + void setCaretPreferences(CaretPreferences* caretPreferences); + + CaretPreferences* getCaretPreferences() const; + + // ADD_NEW_METHODS_HERE + + private: + EventCaretPreferencesGet(const EventCaretPreferencesGet&); + + EventCaretPreferencesGet& operator=(const EventCaretPreferencesGet&); + + CaretPreferences* m_caretPreferences = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CARET_PREFERENCES_GET_DECLARE__ + // +#endif // __EVENT_CARET_PREFERENCES_GET_DECLARE__ + +} // namespace +#endif //__EVENT_CARET_PREFERENCES_GET_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 648328a9f..e665c71c0 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -488,6 +488,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_BROWSER_WINDOW_NEW: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS: + case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_DATA_FILE_ADD: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index b194a5f89..d715ce018 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -157,6 +157,10 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, "EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS", "Get Caret Mappable data file maps viewed in overlays")); + + enumData.push_back(EventTypeEnum(EVENT_CARET_PREFERENCES_GET, + "EVENT_CARET_PREFERENCES_GET", + "Get the Caret Preferences")); enumData.push_back(EventTypeEnum(EVENT_CHART_MATRIX_YOKING_VALIDATION, "EVENT_CHART_MATRIX_YOKING_VALIDATION", diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index d635d3d87..3ae6f72a3 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -84,6 +84,8 @@ public: EVENT_CARET_MAPPABLE_DATA_FILES_GET, /** Get CaretMappableDataFiles and their maps viewed as overlays */ EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, + /** Event to get the Caret Preferences */ + EVENT_CARET_PREFERENCES_GET, /** Event for yoking the loading of matrix chart rows/columns */ EVENT_CHART_MATRIX_YOKING_VALIDATION, /** Validate that chart overlay is valid (it exists). */ -- GitLab From b3fc9c01b56489fb994a0da013da3eb525d02cca Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 May 2017 15:39:56 -0500 Subject: [PATCH 259/755] Add "alternative coloring" to graphics primitive. Use the alternative coloring for matrix grid outline. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 23 +- src/Files/ChartableTwoFileMatrixChart.cxx | 11 + src/Files/ChartableTwoFileMatrixChart.h | 2 + .../CiftiConnectivityMatrixParcelFile.cxx | 5 +- src/Files/CiftiConnectivityMatrixParcelFile.h | 4 +- src/Files/CiftiMappableDataFile.cxx | 71 +++++- src/Files/CiftiMappableDataFile.h | 7 + src/Files/CiftiScalarDataSeriesFile.cxx | 2 + src/Files/CiftiScalarDataSeriesFile.h | 3 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 237 +++++++++++++++++- src/Graphics/GraphicsEngineDataOpenGL.h | 17 +- src/Graphics/GraphicsPrimitive.cxx | 202 ++++++++++++++- src/Graphics/GraphicsPrimitive.h | 24 ++ src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 17 ++ src/Graphics/GraphicsPrimitiveV3fC4f.h | 3 + src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 17 ++ src/Graphics/GraphicsPrimitiveV3fC4ub.h | 3 + src/GuiQt/PreferencesDialog.cxx | 2 + 18 files changed, 610 insertions(+), 40 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index b72ffbc0e..391395cb5 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1031,17 +1031,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { +// uint8_t gridLineColorBytes[4]; +// m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); +// float gridLineColorFloats[4]; +// CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, +// gridLineColorFloats); +// gridLineColorFloats[3] = 1.0; +// GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), +// matrixPrimitive, +// gridLineColorFloats); + glPolygonMode(GL_FRONT, GL_LINE); - uint8_t gridLineColorBytes[4]; - m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); - float gridLineColorFloats[4]; - CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, - gridLineColorFloats); - gridLineColorFloats[3] = 1.0; - GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), - matrixPrimitive, - gridLineColorFloats); + + GraphicsEngineDataOpenGL::drawWithAlternativeColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), + matrixPrimitive, + matrixChart->getMatrixChartGraphicsPrimitiveGridColorIdentifier()); glPolygonMode(GL_FRONT, GL_FILL); } diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 6061b3f44..032aed803 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -414,6 +414,17 @@ ChartableTwoFileMatrixChart::getMatrixChartingGraphicsPrimitive(const ChartTwoMa return ciftiMapFile->getMatrixChartingGraphicsPrimitive(matrixViewMode); } +/** + * @return Identifier for the matrix primitives alternative color used for the grid coloring + */ +int32_t +ChartableTwoFileMatrixChart::getMatrixChartGraphicsPrimitiveGridColorIdentifier() const +{ + const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); + CaretAssert(ciftiMapFile); + + return ciftiMapFile->getMatrixChartGraphicsPrimitiveGridColorIdentifier(); +} /** * @return The selected row/column dimension. diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 9b02b5ef4..0596efcf5 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -60,6 +60,8 @@ namespace caret { GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const; + bool isMatrixTriangularViewingModeSupported() const; // ADD_NEW_METHODS_HERE diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.cxx b/src/Files/CiftiConnectivityMatrixParcelFile.cxx index 1f69edefa..4ac29498a 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.cxx +++ b/src/Files/CiftiConnectivityMatrixParcelFile.cxx @@ -59,8 +59,7 @@ using namespace caret; */ CiftiConnectivityMatrixParcelFile::CiftiConnectivityMatrixParcelFile() : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL), -ChartableMatrixParcelInterface(), -EventListenerInterface() +ChartableMatrixParcelInterface() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; @@ -170,6 +169,8 @@ CiftiConnectivityMatrixParcelFile::receiveEvent(Event* event) } } } + + CiftiMappableConnectivityMatrixDataFile::receiveEvent(event); } /** diff --git a/src/Files/CiftiConnectivityMatrixParcelFile.h b/src/Files/CiftiConnectivityMatrixParcelFile.h index f98f645b0..72c4c2964 100644 --- a/src/Files/CiftiConnectivityMatrixParcelFile.h +++ b/src/Files/CiftiConnectivityMatrixParcelFile.h @@ -24,7 +24,6 @@ #include "BrainConstants.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "ChartableMatrixParcelInterface.h" -#include "EventListenerInterface.h" namespace caret { @@ -34,8 +33,7 @@ namespace caret { class CiftiConnectivityMatrixParcelFile : public CiftiMappableConnectivityMatrixDataFile, - public ChartableMatrixParcelInterface, - public EventListenerInterface { + public ChartableMatrixParcelInterface { public: CiftiConnectivityMatrixParcelFile(); diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 0bc316425..0fb8ae02b 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -24,9 +24,11 @@ #include "CiftiMappableDataFile.h" #undef __CIFTI_MAPPABLE_DATA_FILE_DECLARE__ +#include "BackgroundAndForegroundColors.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" +#include "CaretPreferences.h" #include "ChartDataCartesian.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" @@ -42,7 +44,9 @@ #include "CiftiXML.h" #include "DataFileContentInformation.h" #include "EventManager.h" +#include "EventCaretPreferencesGet.h" #include "EventPaletteGetByName.h" +#include "EventSurfaceColoringInvalidate.h" #include "FastStatistics.h" #include "FileInformation.h" #include "GiftiLabel.h" @@ -264,6 +268,8 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi setupCiftiReadingMappingDirection(); m_classNameHierarchy.grabNew(new GroupAndNameHierarchyModel()); + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** @@ -271,9 +277,29 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi */ CiftiMappableDataFile::~CiftiMappableDataFile() { + EventManager::get()->removeAllEventsFromListener(this); + clearPrivate(); } +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +CiftiMappableDataFile::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { + EventSurfaceColoringInvalidate* colorInvalidateEvent + = dynamic_cast(event); + CaretAssert(colorInvalidateEvent); + colorInvalidateEvent->setEventProcessed(); + + invalidateColoringInAllMaps(); + } +} /** * Create a new instance of a CIFTI file from the given CIFTI data file type @@ -1399,7 +1425,8 @@ CiftiMappableDataFile::invalidateColoringInAllMaps() } /* - * Force recreation of matrix so that it receives updates to coloring. + * Force recreation of matrix so that it receives updates to coloring + * and in particular, matrix grid outline coloring */ m_matrixGraphicsPrimitive.reset(); } @@ -1504,19 +1531,36 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr m_matrixGraphicsPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); /* - * NOTE: All matrix cells receive coloring, event those that are - * not displayed due to the triangular view selection. - * The reason is that it greatly simplifies identification as - * one can derive the row and column from the primitive index. - * Using quads also simplifies identification. Lastly, since - * OpenGL buffers are used, drawing is very fast. + * RGBA for grid outline */ + EventCaretPreferencesGet preferencesEvent; + EventManager::get()->sendEvent(preferencesEvent.getPointer()); + CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); + float cellOutlineRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; + if (caretPreferences != NULL) { + uint8_t gridByteRGBA[4]; + caretPreferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridByteRGBA); + cellOutlineRGBA[0] = static_cast(gridByteRGBA[0]) / 255.0f; + cellOutlineRGBA[1] = static_cast(gridByteRGBA[1]) / 255.0f; + cellOutlineRGBA[2] = static_cast(gridByteRGBA[2]) / 255.0f; + cellOutlineRGBA[3] = 1.0; + } + std::vector gridOutlineRGBA; + gridOutlineRGBA.reserve(numberOfCells * 4 * 4); // four vertices per cell, four color components per vertex /* * Alpha zero for cells that are "not drawn" */ const float cellNotDrawRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + /* + * NOTE: All matrix cells receive coloring, event those that are + * not displayed due to the triangular view selection. + * The reason is that it greatly simplifies identification as + * one can derive the row and column from the primitive index. + * Using quads also simplifies identification. Lastly, since + * OpenGL buffers are used, drawing is very fast. + */ int32_t rgbaOffset = 0; const float cellHeight = 1.0; const float cellWidth = 1.0; @@ -1554,6 +1598,10 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr } else { drawCellFlag = true; + + /* + * Diagonals for non-square matrices not allowed + */ const bool allowNonSquareMatrixDiagonalsFlag = false; if (allowNonSquareMatrixDiagonalsFlag) { drawCellFlag = false; @@ -1589,12 +1637,18 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, rgba); m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); + for (int32_t i4 = 0; i4 < 4; i4++) { + gridOutlineRGBA.insert(gridOutlineRGBA.end(), cellOutlineRGBA, cellOutlineRGBA + 4); + } } else { m_matrixGraphicsPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); + for (int32_t i4 = 0; i4 < 4; i4++) { + gridOutlineRGBA.insert(gridOutlineRGBA.end(), cellNotDrawRGBA, cellNotDrawRGBA + 4); + } } cellX += cellWidth; @@ -1602,6 +1656,9 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr cellY -= cellHeight; } + + m_matrixGraphicsPrimitive->setAlternativeFloatRGBA(getMatrixChartGraphicsPrimitiveGridColorIdentifier(), + gridOutlineRGBA); } } diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 0c87d3351..89e1c39ea 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -28,6 +28,7 @@ #include "CiftiMappingType.h" #include "CiftiXMLElements.h" #include "DisplayGroupEnum.h" +#include "EventListenerInterface.h" #include "VolumeMappableInterface.h" #include @@ -49,6 +50,7 @@ namespace caret { class CiftiMappableDataFile : public CaretMappableDataFile, + public EventListenerInterface, public VolumeMappableInterface { protected: @@ -151,6 +153,8 @@ namespace caret { const int32_t numberOfNodes, AString& errorMessageOut); + virtual void receiveEvent(Event* event); + virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); static void addCiftiXmlToDataFileContentInformation(DataFileContentInformation& dataFileInformation, @@ -485,6 +489,9 @@ namespace caret { GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + /** Identifier for the matrix primitives alternative color used for the grid coloring */ + int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const { return 1; } + virtual void getFileData(std::vector& data) const; const CiftiFile* getCiftiFile() const { return m_ciftiFile; } diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index 26564b1b2..e018950ef 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -141,6 +141,8 @@ CiftiScalarDataSeriesFile::receiveEvent(Event* event) selectMapEvent->setEventProcessed(); } + + CiftiMappableDataFile::receiveEvent(event); } /** diff --git a/src/Files/CiftiScalarDataSeriesFile.h b/src/Files/CiftiScalarDataSeriesFile.h index 3e28c69fa..d917f8619 100644 --- a/src/Files/CiftiScalarDataSeriesFile.h +++ b/src/Files/CiftiScalarDataSeriesFile.h @@ -35,8 +35,7 @@ namespace caret { class CiftiScalarDataSeriesFile : public CiftiMappableDataFile, public ChartableLineSeriesRowColumnInterface, - public ChartableMatrixSeriesInterface, - public EventListenerInterface { + public ChartableMatrixSeriesInterface { public: CiftiScalarDataSeriesFile(); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index de8adf863..7c8069e8a 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -93,20 +93,24 @@ GraphicsEngineDataOpenGL::deleteBuffers() deleteBufferObjectHelper(m_normalVectorBufferObject); deleteBufferObjectHelper(m_colorBufferObject); + + for (auto mapBuff: m_alternativeColorBufferObjectMap) { + deleteBufferObjectHelper(mapBuff.second); + } + m_alternativeColorBufferObjectMap.clear(); } - /** - * Load the buffers with data from the grpahics primitive. + * Get the OpenGL Buffer Usage Hint from the primitive. * * @param primitive - * The graphics primitive that will be drawn. + * The graphics primitive + * @return + * The OpenGL Buffer Usage Hint. */ -void -GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) +GLenum +GraphicsEngineDataOpenGL::getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const { - CaretAssert(primitive); - GLenum usageHint = GL_STREAM_DRAW; switch (primitive->getUsageType()) { case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES: @@ -120,6 +124,22 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) break; } + return usageHint; +} + +/** + * Load the buffers with data from the grpahics primitive. + * + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLsizei coordinateCount = 0; switch (primitive->m_vertexType) { case GraphicsPrimitive::VertexType::FLOAT_XYZ: @@ -221,6 +241,112 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) } } +/** + * Load the buffer for the given alternative color identifier. If the buffer + * was previously loaded, no action is taken. + * + * @param primitive + * The graphics primitive that will be drawn. + * @param alternativeColorIdentifier + * Identifier for the alternative color. + * @return + * True if the alternative color buffer is valid for the given alternative + * color identifier so drawing can be performed. Otherwise, false is returned. + */ +GraphicsOpenGLBufferObject* +GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitive, + const int32_t alternativeColorIdentifier) +{ + std::map::iterator iter = m_alternativeColorBufferObjectMap.find(alternativeColorIdentifier); + if (iter != m_alternativeColorBufferObjectMap.end()) { + return iter->second; + } + + GraphicsOpenGLBufferObject* outputOpenGLBufferObject = NULL; + + GLenum usageHint = getOpeGLBufferUsageHint(primitive); + + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + const std::vector& alternativeFloatRGBA = primitive->getAlternativeFloatRGBAProtected(alternativeColorIdentifier); + if ((alternativeFloatRGBA.size() / 4) != (primitive->m_xyz.size() / 3)) { + const AString msg("Number of alternative RGBA values is for " + + AString::number((alternativeFloatRGBA.size() / 4)) + + " vertices but should be for " + + AString::number((primitive->m_xyz.size() / 3)) + + " vertices."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return NULL; + } + + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + GraphicsOpenGLBufferObject* bufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(bufferObject->getBufferObjectName()); + + m_componentsPerColor = 4; + m_colorDataType = GL_FLOAT; + + const GLuint colorSizeBytes = alternativeFloatRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&alternativeFloatRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + bufferObject->getBufferObjectName()); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + usageHint); + + m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, + bufferObject)); + outputOpenGLBufferObject = bufferObject; + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + const std::vector& alternativeUnsignedByteRGBA = primitive->getAlternativeUnsignedByteRGBAProtected(alternativeColorIdentifier); + if ((alternativeUnsignedByteRGBA.size() / 4) != (primitive->m_xyz.size() / 3)) { + const AString msg("Number of alternative RGBA values is for " + + AString::number((alternativeUnsignedByteRGBA.size() / 4)) + + " vertices but should be for " + + AString::number((primitive->m_xyz.size() / 3)) + + " vertices."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return NULL; + } + + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + GraphicsOpenGLBufferObject* bufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(bufferObject->getBufferObjectName()); + + m_componentsPerColor = 4; + m_colorDataType = GL_UNSIGNED_BYTE; + + const GLuint colorSizeBytes = alternativeUnsignedByteRGBA.size() * sizeof(uint8_t); + const GLvoid* colorDataPointer = (const GLvoid*)&alternativeUnsignedByteRGBA[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + bufferObject->getBufferObjectName()); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + usageHint); + + m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, + bufferObject)); + outputOpenGLBufferObject = bufferObject; + } + break; + } + + return outputOpenGLBufferObject; +} + + /** * Draw the given graphics primitive. * @@ -238,9 +364,26 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, openglContextPointer, primitive, NULL, + -1, dummyRGBA); } +/** + * Draw to determine the index of primitive at the given (X, Y) location + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + * @param pixelX + * X location for selection. + * @param pixelY + * Y location for selection. + * @param selectedPrimitiveIndexOut + * Output with the index of the primitive (invalid no primitve at location + * @param selectedPrimitiveDepthOut + * Output with depth at the location. + */ void GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, GraphicsPrimitive* primitive, @@ -277,6 +420,7 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, openglContextPointer, primitive, &selectionHelper, + -1, dummyRGBA); /* @@ -324,7 +468,7 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, /** - * Draw the given graphics primitive. + * Draw the given graphics primitive using a solid color. * * @param openglContextPointer * Pointer to the active OpenGL context. @@ -342,9 +486,34 @@ GraphicsEngineDataOpenGL::drawWithOverrideColor(void* openglContextPointer, openglContextPointer, primitive, NULL, + -1, solidColorOverrideRGBA); } +/** + * Draw the given graphics primitive using an alternative color. + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + * @param alternativeColorIdentifier + * Identifier for the alternative color. + */ +void +GraphicsEngineDataOpenGL::drawWithAlternativeColor(void* openglContextPointer, + GraphicsPrimitive* primitive, + const int32_t alternativeColorIdentifier) +{ + float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + drawPrivate(PrivateDrawMode::DRAW_COLOR_ALTERNATIVE, + openglContextPointer, + primitive, NULL, + alternativeColorIdentifier, + dummyRGBA); +} + + /** * Draw the graphics primitive. * @@ -356,6 +525,8 @@ GraphicsEngineDataOpenGL::drawWithOverrideColor(void* openglContextPointer, * Primitive that is drawn. * @param primitiveSelectionHelper * Selection helper when draw mode is selection. + * @param alternativeColorIdentifier + * Identifier for the alternative color. * @param solidColorRGBA * Color for solid color mode. */ @@ -364,6 +535,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, + const int32_t alternativeColorIdentifier, const float solidColorRGBA[4]) { CaretAssert(openglContextPointer); @@ -372,6 +544,21 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, return; } + switch (drawMode) { + case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: + if ( ! primitive->isAlternativeColoringValid(alternativeColorIdentifier)) { + CaretLogSevere("Alternative coloring is invalid for index=" + + AString::number(alternativeColorIdentifier)); + return; + } + break; + case PrivateDrawMode::DRAW_COLOR_SOLID: + break; + case PrivateDrawMode::DRAW_NORMAL: + break; + case PrivateDrawMode::DRAW_SELECTION: + break; + } GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); if (openglData == NULL) { @@ -392,13 +579,34 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); CaretAssert(coordBufferID); if ( ! glIsBuffer(coordBufferID)) { - std::cout << "Coordinate buffer is INVALID" << std::endl; + CaretAssertMessage(0, "Coordinate buffer is INVALID"); + CaretLogSevere("Coordinate buffer is INVALID"); + return; } + GraphicsOpenGLBufferObject* alternativeColorBufferObject = NULL; + switch (drawMode) { + case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: + alternativeColorBufferObject = openglData->loadAlternativeColorBuffer(primitive, + alternativeColorIdentifier); + if (alternativeColorBufferObject == NULL) { + CaretAssertMessage(0, "Coordinate buffer is INVALID"); + CaretLogSevere("Coordinate buffer is INVALID"); + return; + } + break; + case PrivateDrawMode::DRAW_COLOR_SOLID: + break; + case PrivateDrawMode::DRAW_NORMAL: + break; + case PrivateDrawMode::DRAW_SELECTION: + break; + } /* * Setup vertices for drawing */ glEnableClientState(GL_VERTEX_ARRAY); + CaretAssert(glIsBuffer(coordBufferID)); glBindBuffer(GL_ARRAY_BUFFER, coordBufferID); glVertexPointer(openglData->m_coordinatesPerVertex, @@ -411,6 +619,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, */ if (openglData->m_normalVectorBufferObject != NULL) { glEnableClientState(GL_NORMAL_ARRAY); + CaretAssert(glIsBuffer(openglData->m_normalVectorBufferObject->getBufferObjectName())); glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferObject->getBufferObjectName()); glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); } @@ -423,6 +632,14 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, */ GLuint localColorBufferName = 0; switch (drawMode) { + case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: + { + glEnableClientState(GL_COLOR_ARRAY); + CaretAssert(glIsBuffer(alternativeColorBufferObject->getBufferObjectName())); + glBindBuffer(GL_ARRAY_BUFFER, alternativeColorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); + } + break; case PrivateDrawMode::DRAW_COLOR_SOLID: { const int32_t numberOfVertices = primitive->m_xyz.size() / 3; @@ -433,7 +650,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, const GLint componentsPerColor = 4; const GLenum colorDataType = GL_FLOAT; - std::vector colorRGBA(numberOfVertices * componentsPerColor); for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i4 = i * 4; @@ -460,6 +676,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, case PrivateDrawMode::DRAW_NORMAL: { glEnableClientState(GL_COLOR_ARRAY); + CaretAssert(glIsBuffer(openglData->m_colorBufferObject->getBufferObjectName())); glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 216399d10..dc8b135ff 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -21,14 +21,12 @@ */ /*LICENSE_END*/ - - +#include #include #include "GraphicsEngineData.h" #include "CaretOpenGLInclude.h" - namespace caret { class GraphicsOpenGLBufferObject; @@ -46,6 +44,9 @@ namespace caret { void loadBuffers(GraphicsPrimitive* primitive); + GraphicsOpenGLBufferObject* loadAlternativeColorBuffer(GraphicsPrimitive* primitive, + const int32_t alternativeColorIdentifier); + static void draw(void* openglContextPointer, GraphicsPrimitive* primitive); @@ -60,12 +61,17 @@ namespace caret { GraphicsPrimitive* primitive, const float solidColorOverrideRGBA[4]); + static void drawWithAlternativeColor(void* openglContextPointer, + GraphicsPrimitive* primitive, + const int32_t alternativeColorIdentifier); + const void* getOpenGLContextPointer() const; // ADD_NEW_METHODS_HERE private: enum class PrivateDrawMode { + DRAW_COLOR_ALTERNATIVE, DRAW_COLOR_SOLID, DRAW_NORMAL, DRAW_SELECTION @@ -81,8 +87,11 @@ namespace caret { void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, + const int32_t alternativeColorIdentifier, const float solidColorRGBA[4]); + GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; + const void* m_openglContextPointer; GLsizei m_arrayIndicesCount = 0; @@ -99,6 +108,8 @@ namespace caret { GraphicsOpenGLBufferObject* m_colorBufferObject = NULL; + std::map m_alternativeColorBufferObjectMap; + GLenum m_colorDataType = GL_FLOAT; GLint m_componentsPerColor = 0; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 7a738dd50..c9853e260 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -100,10 +100,12 @@ m_primitiveType(obj.m_primitiveType) void GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) { - m_xyz = obj.m_xyz; - m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; - m_floatRGBA = obj.m_floatRGBA; - m_unsignedByteRGBA = obj.m_unsignedByteRGBA; + m_xyz = obj.m_xyz; + m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; + m_floatRGBA = obj.m_floatRGBA; + m_unsignedByteRGBA = obj.m_unsignedByteRGBA; + m_alternativeFloatRGBA = obj.m_alternativeFloatRGBA; + m_alternativeUnsignedByteRGBA = obj.m_alternativeUnsignedByteRGBA; m_graphicsEngineDataForOpenGL.reset(); } @@ -423,6 +425,198 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const return s; } + +/** + * @return Is the alternative coloring with the given identifier valid? + * + * @param identifier + * Identifier of the alternative coloring. + */ +bool +GraphicsPrimitive::isAlternativeColoringValid(const int32_t identifier) const +{ + bool validFlag = false; + + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + validFlag = isAlternativeFloatRGBAValidProtected(identifier); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + validFlag = isAlternativeUnsignedByteRGBAValidProtected(identifier); + break; + } + + return validFlag; +} + + +/** + * @return Is the alternative float coloring valid for the given identifier? + * + * @param identifier + * Identifier for alternative coloring. + */ +bool +GraphicsPrimitive::isAlternativeFloatRGBAValidProtected(const int32_t identifier) const +{ + std::map>::const_iterator iter = m_alternativeFloatRGBA.find(identifier); + + if (iter != m_alternativeFloatRGBA.end()) { + const int32_t numVerticesFromXYZ = m_xyz.size() / 3; + const int32_t numVerticesFromRGBA = iter->second.size() / 4; + if (numVerticesFromRGBA == numVerticesFromXYZ) { + return true; + } + } + + return false; +} + +/** + * @return Is the alternative unsigned byte coloring valid for the given identifier? + * + * @param identifier + * Identifier for alternative coloring. + */ +bool +GraphicsPrimitive::isAlternativeUnsignedByteRGBAValidProtected(const int32_t identifier) const +{ + std::map>::const_iterator iter = m_alternativeUnsignedByteRGBA.find(identifier); + + if (iter != m_alternativeUnsignedByteRGBA.end()) { + const int32_t numVerticesFromXYZ = m_xyz.size() / 3; + const int32_t numVerticesFromRGBA = iter->second.size() / 4; + if (numVerticesFromRGBA == numVerticesFromXYZ) { + return true; + } + } + + return false; +} + +/** + * @return A reference to the alternative coloring. An empty vector is returned + * if the alternative coloring data is invalid. + * + * @param identifier + * Identifier for alternative coloring. + */ +const std::vector& +GraphicsPrimitive::getAlternativeFloatRGBAProtected(const int32_t identifier) const +{ + std::map>::const_iterator iter = m_alternativeFloatRGBA.find(identifier); + + if (iter != m_alternativeFloatRGBA.end()) { + return iter->second; + } + + return m_dummyFloatRGBAVector; +} + +/** + * @return A reference to the alternative coloring. An empty vector is returned + * if the alternative coloring data is invalid. + * + * @param identifier + * Identifier for alternative coloring. + */ +const std::vector& +GraphicsPrimitive::getAlternativeUnsignedByteRGBAProtected(const int32_t identifier) const +{ + std::map>::const_iterator iter = m_alternativeUnsignedByteRGBA.find(identifier); + + if (iter != m_alternativeUnsignedByteRGBA.end()) { + return iter->second; + } + + return m_dummyUnsignedByteRGBAVector; +} + +/** + * Set alternative RGBA coloring with float data. + * + * @param identifier + * Any integer value used to identify the alternative coloring. + * @param rgbaFloat + * The alternative coloring that must contain the correct number of + * RGBA components for the primitive's number of vertices. + */ +void +GraphicsPrimitive::setAlternativeFloatRGBAProtected(const int32_t identifier, + const std::vector& rgbaFloat) +{ + const int32_t numVerticesFromXYZ = m_xyz.size() / 3; + const int32_t numVerticesFromRGBA = rgbaFloat.size() / 4; + if (numVerticesFromRGBA != numVerticesFromXYZ) { + const AString msg("Number of alternative RGBA values is for " + + AString::number(numVerticesFromRGBA) + + " vertices but should be for " + + AString::number(numVerticesFromXYZ) + + " vertices."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + break; + case ColorType::UNSIGNED_BYTE_RGBA: + { + const AString msg("Alternative RGBA must match primitive color type which is unsigned byte"); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + break; + } + + m_alternativeFloatRGBA.insert(std::make_pair(identifier, + rgbaFloat)); +} + +/** + * Set alternative RGBA coloring with float data. + * + * @param identifier + * Any integer value used to identify the alternative coloring. + * @param rgbaByte + * The alternative coloring that must contain the correct number of + * RGBA components for the primitive's number of vertices. + */ +void +GraphicsPrimitive::setAlternativeUnsignedByteRGBAProtected(const int32_t identifier, + const std::vector& rgbaByte) +{ + const int32_t numVerticesFromXYZ = m_xyz.size() / 3; + const int32_t numVerticesFromRGBA = rgbaByte.size() / 4; + if (numVerticesFromRGBA != numVerticesFromXYZ) { + const AString msg("Number of alternative RGBA values is for " + + AString::number(numVerticesFromRGBA) + + " vertices but should be for " + + AString::number(numVerticesFromXYZ) + + " vertices."); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + switch (m_colorType) { + case ColorType::FLOAT_RGBA: + { + const AString msg("Alternative RGBA must match primitive color type which is float"); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + } + break; + case ColorType::UNSIGNED_BYTE_RGBA: + break; + } + + m_alternativeUnsignedByteRGBA.insert(std::make_pair(identifier, + rgbaByte)); +} + + /** * Get the OpenGL graphics engine data in this instance. * diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 9d987c96e..c683aa390 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -186,6 +186,8 @@ namespace caret { bool isValid() const; + bool isAlternativeColoringValid(const int32_t identifier) const; + /** * @return Type of the vertices. */ @@ -227,6 +229,20 @@ namespace caret { protected: AString toStringPrivate(const bool includeAllDataFlag) const; + void setAlternativeFloatRGBAProtected(const int32_t identifier, + const std::vector& rgbaFloat); + + void setAlternativeUnsignedByteRGBAProtected(const int32_t identifier, + const std::vector& rgbaByte); + + const std::vector& getAlternativeFloatRGBAProtected(const int32_t identifier) const; + + const std::vector& getAlternativeUnsignedByteRGBAProtected(const int32_t identifier) const; + + bool isAlternativeFloatRGBAValidProtected(const int32_t identifier) const; + + bool isAlternativeUnsignedByteRGBAValidProtected(const int32_t identifier) const; + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; @@ -247,12 +263,20 @@ namespace caret { std::vector m_unsignedByteRGBA; + std::map> m_alternativeFloatRGBA; + + std::map> m_alternativeUnsignedByteRGBA; + private: void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); friend class GraphicsEngineDataOpenGL; friend class GraphicsPrimitiveSelectionHelper; + std::vector m_dummyFloatRGBAVector; + + std::vector m_dummyUnsignedByteRGBAVector; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 9f6f8be0b..103414ed8 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -143,6 +143,23 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, rgba, rgba + 4); } +/** + * Set alternative RGBA coloring with float data. + * + * @param identifier + * Any integer value used to identify the alternative coloring. + * @param rgbaFloat + * The alternative coloring that must contain the correct number of + * RGBA components for the primitive's number of vertices. + */ +void +GraphicsPrimitiveV3fC4f::setAlternativeFloatRGBA(const int32_t identifier, + const std::vector& rgbaFloat) +{ + setAlternativeFloatRGBAProtected(identifier, + rgbaFloat); +} + /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.h b/src/Graphics/GraphicsPrimitiveV3fC4f.h index 0de2cc905..f5bd03fdf 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.h +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.h @@ -52,6 +52,9 @@ namespace caret { const float y, const float rgba[4]); + void setAlternativeFloatRGBA(const int32_t identifier, + const std::vector& rgbaFloat); + virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 0c7576c0b..44614edad 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -121,6 +121,23 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, rgba, rgba + 4); } +/** + * Set alternative RGBA coloring with unsigned byte data. + * + * @param identifier + * Any integer value used to identify the alternative coloring. + * @param rgbaUnsignedByte + * The alternative coloring that must contain the correct number of + * RGBA components for the primitive's number of vertices. + */ +void +GraphicsPrimitiveV3fC4ub::setAlternativeUnsignedByteRGBA(const int32_t identifier, + const std::vector& rgbaUnsignedByte) +{ + setAlternativeUnsignedByteRGBAProtected(identifier, + rgbaUnsignedByte); +} + /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.h b/src/Graphics/GraphicsPrimitiveV3fC4ub.h index b17781e6d..b86e57b65 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.h +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.h @@ -46,6 +46,9 @@ namespace caret { const float z, const uint8_t rgba[4]); + void setAlternativeUnsignedByteRGBA(const int32_t identifier, + const std::vector& rgbaUnsignedByte); + virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/PreferencesDialog.cxx b/src/GuiQt/PreferencesDialog.cxx index 73adaf469..13e2d6e9a 100644 --- a/src/GuiQt/PreferencesDialog.cxx +++ b/src/GuiQt/PreferencesDialog.cxx @@ -43,6 +43,7 @@ #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" +#include "EventSurfaceColoringInvalidate.h" #include "GuiManager.h" #include "ImageCaptureMethodEnum.h" #include "OpenGLDrawingMethodEnum.h" @@ -868,6 +869,7 @@ PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) updateColorWidget(prefs); + EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } -- GitLab From 67f7a0bd20f4358d5d008793de9ed6174baa2f1b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 May 2017 16:07:26 -0500 Subject: [PATCH 260/755] Fixed crash that occurred when loading a scene and trying to restore a 'model one chart' to a 'model two chart'. There was no test to see if the 'model one chart' was valid and a test for validity has been added to prevent the crash. --- src/Brain/Brain.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index f605b1bf7..7ae7b0c9d 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -7295,12 +7295,12 @@ Brain::restoreModelChartOneToModelChartTwo() { CaretAssert(m_modelChartTwo); if ( ! m_modelChartTwo->isRestoredFromScene()) { - CaretAssert(m_modelChart); - if (m_modelChart->isRestoredFromScene()) { - m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); + if (m_modelChart != NULL) { + if (m_modelChart->isRestoredFromScene()) { + m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); + } } } - } /** -- GitLab From d3c7ba7d19db9523b74d65f8222051d97792ec1c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 4 May 2017 11:18:20 -0500 Subject: [PATCH 261/755] Cleaned up code in new chart drawing. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 790 +----------------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 11 - 2 files changed, 18 insertions(+), 783 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 391395cb5..4411708da 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1031,16 +1031,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { -// uint8_t gridLineColorBytes[4]; -// m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); -// float gridLineColorFloats[4]; -// CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, -// gridLineColorFloats); -// gridLineColorFloats[3] = 1.0; -// GraphicsEngineDataOpenGL::drawWithOverrideColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), -// matrixPrimitive, -// gridLineColorFloats); - glPolygonMode(GL_FRONT, GL_LINE); @@ -1140,706 +1130,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } } -// if (m_identificationModeFlag) { -// int32_t numberOfRows = 0; -// int32_t numberOfColumns = 0; -// matrixChart->getMatrixDimensions(numberOfRows, -// numberOfColumns); -// -// /* -// * While this works, it uses OpenGL functions (gluUnproject) that -// * are removed in in the programmable pipeline OpenGL -// */ -// GLint viewport[4]; -// glGetIntegerv(GL_VIEWPORT, -// viewport); -// GLdouble projectionMatrix[16]; -// glGetDoublev(GL_PROJECTION_MATRIX, -// projectionMatrix); -// GLdouble modelMatrix[16]; -// glGetDoublev(GL_MODELVIEW_MATRIX, -// modelMatrix); -// GLdouble windowXYZ[3] = { m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, 0.0 }; -// -// GLdouble matrixXYZ[3]; -// if (gluUnProject(windowXYZ[0], windowXYZ[1], windowXYZ[2], -// modelMatrix, projectionMatrix, viewport, -// &matrixXYZ[0], &matrixXYZ[1], &matrixXYZ[2])) { -// const int32_t rowOriginBottomIndex = static_cast(matrixXYZ[1]); -// const int32_t columnIndex = static_cast(matrixXYZ[0]); -// if ((rowOriginBottomIndex >= 0) -// && (rowOriginBottomIndex < numberOfRows) -// && (columnIndex >= 0) -// && (columnIndex < numberOfColumns)) { -// const int32_t rowIndex = numberOfRows - rowOriginBottomIndex - 1; -// -// float pixelRGBA[4]; -// float pixelDepth = 0.0; -// if (m_fixedPipelineDrawing->getPixelDepthAndRGBA(m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// pixelDepth, -// pixelRGBA)) { -// -// std::cout << "Pixel Depth/RGBA: " << pixelDepth << ", " << AString::fromNumbers(pixelRGBA, 4, ",") << std::endl; -// if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(pixelDepth)) { -// if (pixelRGBA[3] > 0.0) { -// m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), -// rowIndex, -// columnIndex); -// } -// } -// } -// } -// } -// } - glDisable(GL_BLEND); glPopMatrix(); - - - const bool drawOLD = false; - if (drawOLD) { - int32_t numberOfRows = 0; - int32_t numberOfColumns = 0; - std::vector matrixRGBA; - if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, - numberOfColumns, - matrixRGBA)) { - CaretLogWarning("Matrix RGBA invalid"); - return; - } - if ((numberOfRows <= 0) - || (numberOfColumns <= 0)) { - return; - } - - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); - CaretAssert(matrixProperties); - - bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); - const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); - - - std::vector selectedColumnIndices; - std::vector selectedRowIndices; - ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; - matrixChart->getSelectedRowColumnIndices(m_tabIndex, - selectedRowColumnDimension, - selectedRowIndices, - selectedColumnIndices); - std::map columnRangesForRow; - for (int32_t rowIndex : selectedRowIndices) { - columnRangesForRow[rowIndex] = RowColumnMinMax(); - } - const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); - - std::map rowRangesForColumn; - for (int32_t columnIndex : selectedColumnIndices) { - rowRangesForColumn[columnIndex] = RowColumnMinMax(); - } - const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); - - uint8_t highlightRGBByte[3]; - m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); - const float highlightRGBA[4] = { - highlightRGBByte[0] / 255.0, - highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0, - 1.0 - }; - - int32_t rgbaOffset = 0; - - std::unique_ptr quadsData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); - std::unique_ptr quadsData4ub - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); - const int32_t numberOfCells = numberOfColumns * numberOfRows; - if (m_identificationModeFlag) { - quadsData4ub->reserveForNumberOfVertices(numberOfCells); - } - else { - quadsData4f->reserveForNumberOfVertices(numberOfCells); - } - - float cellY = (numberOfRows - 1) * cellHeight; - for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { - float cellX = 0; - for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { - CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); - const float* rgba = &matrixRGBA[rgbaOffset]; - rgbaOffset += 4; - - bool drawCellFlag = true; - if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { - if (numberOfRows == numberOfColumns) { - drawCellFlag = false; - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - if (rowIndex != columnIndex) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - if (rowIndex > columnIndex) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - if (rowIndex < columnIndex) { - drawCellFlag = true; - } - break; - } - } - else { - drawCellFlag = false; - const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); - const int32_t diagonalRow = static_cast(slope * columnIndex); - - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - drawCellFlag = true; - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - if (rowIndex != diagonalRow) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - if (rowIndex > diagonalRow) { - drawCellFlag = true; - } - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - if (rowIndex < diagonalRow) { - drawCellFlag = true; - } - break; - } - } - } - - if (drawCellFlag) { - if (haveSelectedRowsFlag) { - std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); - if (minMaxIter != columnRangesForRow.end()) { - if (columnIndex < minMaxIter->second.m_min) { - minMaxIter->second.m_min = columnIndex; - } - if (columnIndex > minMaxIter->second.m_max) { - minMaxIter->second.m_max = columnIndex; - } - } - } - - if (haveSelectedColumnsFlag) { - std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); - if (minMaxIter != rowRangesForColumn.end()) { - if (rowIndex < minMaxIter->second.m_min) { - minMaxIter->second.m_min = rowIndex; - } - if (rowIndex > minMaxIter->second.m_max) { - minMaxIter->second.m_max = rowIndex; - } - } - } - - uint8_t idRGBA[4]; - if (m_identificationModeFlag) { - addToChartMatrixIdentification(rowIndex, - columnIndex, - idRGBA); - } - - if (m_identificationModeFlag) { - quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); - quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); - quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); - quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); - } - else { - quadsData4f->addVertex(cellX, cellY, 0.0, rgba); - quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); - quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); - quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); - } - } - - cellX += cellWidth; - } - - cellY -= cellHeight; - } - - /* - * Draw the matrix elements. - */ - if (m_identificationModeFlag) { - drawPrimitivePrivate(quadsData4ub.get()); - } - else { - /* - * Enable alpha blending so voxels that are not drawn from higher layers - * allow voxels from lower layers to be seen. - */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - drawPrimitivePrivate(quadsData4f.get()); - - glDisable(GL_BLEND); - - - /* - * Drawn an outline around the matrix elements. - */ - if (displayGridLinesFlag) { - uint8_t gridLineColorBytes[4]; - m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); - float gridLineColorFloats[4]; - CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, - gridLineColorFloats); - gridLineColorFloats[3] = 1.0; - - const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); - const int32_t numCells = static_cast(gridXYZ.size() / 3); - - std::unique_ptr outlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, - gridLineColorFloats)); - outlineData4f->reserveForNumberOfVertices(numCells); - for (int32_t i = 0; i < numCells; i++) { - CaretAssertVectorIndex(gridXYZ, i*3); - outlineData4f->addVertex(&gridXYZ[i*3]); - } - glPolygonMode(GL_FRONT, GL_LINE); - glLineWidth(1.0); - drawPrimitivePrivate(outlineData4f.get()); - glPolygonMode(GL_FRONT, GL_FILL); - } - - if ( (! selectedRowIndices.empty()) - && highlightSelectedRowColumnFlag) { - for (auto rowIndex : selectedRowIndices) { - const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; - - int32_t minColumn = 0; - int32_t maxColumn = numberOfColumns; - if (haveSelectedRowsFlag) { - std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); - if (minMaxIter != columnRangesForRow.end()) { - const int32_t minValue = minMaxIter->second.m_min; - const int32_t rowMaxColumn = minMaxIter->second.m_max; - if (minValue < rowMaxColumn) { - minColumn = minValue; - maxColumn = rowMaxColumn + 1; - } - } - } - - const float minX = minColumn * cellWidth; - const float maxX = maxColumn * cellWidth; - - std::unique_ptr rowOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - rowOutlineData4f->reserveForNumberOfVertices(4); - - rowOutlineData4f->addVertex(minX, rowY); - rowOutlineData4f->addVertex(maxX, rowY); - rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); - rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(rowOutlineData4f.get()); - } - - glLineWidth(1.0); - } - - if ( (! selectedColumnIndices.empty()) - && highlightSelectedRowColumnFlag) { - for (auto columnIndex : selectedColumnIndices) { - const float colX = columnIndex * cellWidth; - - int32_t minRow = 0; - int32_t maxRow = numberOfRows; - if (haveSelectedColumnsFlag) { - std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); - if (minMaxIter != rowRangesForColumn.end()) { - const int32_t minValue = minMaxIter->second.m_min; - const int32_t maxValue = minMaxIter->second.m_max; - if (minValue < maxValue) { - minRow = minValue; - maxRow = maxValue + 1; - } - } - } - - const float minY = minRow * cellHeight; - const float maxY = maxRow * cellHeight; - - std::unique_ptr columnOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - columnOutlineData4f->reserveForNumberOfVertices(4); - - columnOutlineData4f->addVertex(colX, minY); - columnOutlineData4f->addVertex(colX + cellWidth, minY); - columnOutlineData4f->addVertex(colX + cellWidth, maxY); - columnOutlineData4f->addVertex(colX, maxY); - const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); - drawPrimitivePrivate(columnOutlineData4f.get()); - } - glLineWidth(1.0); - } - - glPolygonMode(GL_FRONT, GL_FILL); - } - - if (m_identificationModeFlag) { - processMatrixIdentification(matrixChart); - } - } } -///* -// * Draw a matrix chart. -// * -// * @param matrixChart -// * Matrix chart that is drawn. -// * @param chartViewingType -// * Type of chart viewing. -// * @param cellWidth -// * Width of cell. -// * @param cellHeight -// * Height of cell. -// * @param zooming -// * Current zooming. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::OLDdrawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, -// const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, -// const float cellWidth, -// const float cellHeight, -// const float zooming) -//{ -// if (m_identificationModeFlag) { -// resetIdentification(); -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// -// int32_t numberOfRows = 0; -// int32_t numberOfColumns = 0; -// std::vector matrixRGBA; -// if ( ! matrixChart->getMatrixDataRGBA(numberOfRows, -// numberOfColumns, -// matrixRGBA)) { -// CaretLogWarning("Matrix RGBA invalid"); -// return; -// } -// if ((numberOfRows <= 0) -// || (numberOfColumns <= 0)) { -// return; -// } -// -// const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); -// CaretAssert(matrixProperties); -// -// bool displayGridLinesFlag = matrixProperties->isGridLinesDisplayed(); -// const bool highlightSelectedRowColumnFlag = matrixProperties->isSelectedRowColumnHighlighted(); -// -// -// std::vector selectedColumnIndices; -// std::vector selectedRowIndices; -// ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; -// matrixChart->getSelectedRowColumnIndices(m_tabIndex, -// selectedRowColumnDimension, -// selectedRowIndices, -// selectedColumnIndices); -// std::map columnRangesForRow; -// for (int32_t rowIndex : selectedRowIndices) { -// columnRangesForRow[rowIndex] = RowColumnMinMax(); -// } -// const bool haveSelectedRowsFlag = ( ! columnRangesForRow.empty()); -// -// std::map rowRangesForColumn; -// for (int32_t columnIndex : selectedColumnIndices) { -// rowRangesForColumn[columnIndex] = RowColumnMinMax(); -// } -// const bool haveSelectedColumnsFlag = ( ! rowRangesForColumn.empty()); -// -// uint8_t highlightRGBByte[3]; -// m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); -// const float highlightRGBA[4] = { -// highlightRGBByte[0] / 255.0, -// highlightRGBByte[1] / 255.0, -// highlightRGBByte[2] / 255.0, -// 1.0 -// }; -// -// int32_t rgbaOffset = 0; -// -// std::unique_ptr quadsData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); -// std::unique_ptr quadsData4ub -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); -// const int32_t numberOfCells = numberOfColumns * numberOfRows; -// if (m_identificationModeFlag) { -// quadsData4ub->reserveForNumberOfVertices(numberOfCells); -// } -// else { -// quadsData4f->reserveForNumberOfVertices(numberOfCells); -// } -// -// float cellY = (numberOfRows - 1) * cellHeight; -// for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { -// float cellX = 0; -// for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { -// CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); -// const float* rgba = &matrixRGBA[rgbaOffset]; -// rgbaOffset += 4; -// -// bool drawCellFlag = true; -// if (chartViewingType != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { -// if (numberOfRows == numberOfColumns) { -// drawCellFlag = false; -// switch (chartViewingType) { -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: -// if (rowIndex != columnIndex) { -// drawCellFlag = true; -// } -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: -// if (rowIndex > columnIndex) { -// drawCellFlag = true; -// } -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: -// if (rowIndex < columnIndex) { -// drawCellFlag = true; -// } -// break; -// } -// } -// else { -// drawCellFlag = false; -// const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); -// const int32_t diagonalRow = static_cast(slope * columnIndex); -// -// switch (chartViewingType) { -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: -// drawCellFlag = true; -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: -// if (rowIndex != diagonalRow) { -// drawCellFlag = true; -// } -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: -// if (rowIndex > diagonalRow) { -// drawCellFlag = true; -// } -// break; -// case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: -// if (rowIndex < diagonalRow) { -// drawCellFlag = true; -// } -// break; -// } -// } -// } -// -// if (drawCellFlag) { -// if (haveSelectedRowsFlag) { -// std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); -// if (minMaxIter != columnRangesForRow.end()) { -// if (columnIndex < minMaxIter->second.m_min) { -// minMaxIter->second.m_min = columnIndex; -// } -// if (columnIndex > minMaxIter->second.m_max) { -// minMaxIter->second.m_max = columnIndex; -// } -// } -// } -// -// if (haveSelectedColumnsFlag) { -// std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); -// if (minMaxIter != rowRangesForColumn.end()) { -// if (rowIndex < minMaxIter->second.m_min) { -// minMaxIter->second.m_min = rowIndex; -// } -// if (rowIndex > minMaxIter->second.m_max) { -// minMaxIter->second.m_max = rowIndex; -// } -// } -// } -// -// uint8_t idRGBA[4]; -// if (m_identificationModeFlag) { -// addToChartMatrixIdentification(rowIndex, -// columnIndex, -// idRGBA); -// } -// -// if (m_identificationModeFlag) { -// quadsData4ub->addVertex(cellX, cellY, 0.0, idRGBA); -// quadsData4ub->addVertex(cellX + cellWidth, cellY, 0.0, idRGBA); -// quadsData4ub->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, idRGBA); -// quadsData4ub->addVertex(cellX, cellY + cellHeight, 0.0, idRGBA); -// } -// else { -// quadsData4f->addVertex(cellX, cellY, 0.0, rgba); -// quadsData4f->addVertex(cellX + cellWidth, cellY, 0.0, rgba); -// quadsData4f->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); -// quadsData4f->addVertex(cellX, cellY + cellHeight, 0.0, rgba); -// } -// } -// -// cellX += cellWidth; -// } -// -// cellY -= cellHeight; -// } -// -// /* -// * Draw the matrix elements. -// */ -// if (m_identificationModeFlag) { -// drawPrimitivePrivate(quadsData4ub.get()); -// } -// else { -// /* -// * Enable alpha blending so voxels that are not drawn from higher layers -// * allow voxels from lower layers to be seen. -// */ -// glEnable(GL_BLEND); -// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -// -// drawPrimitivePrivate(quadsData4f.get()); -// -// glDisable(GL_BLEND); -// -// -// /* -// * Drawn an outline around the matrix elements. -// */ -// if (displayGridLinesFlag) { -// uint8_t gridLineColorBytes[4]; -// m_preferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); -// float gridLineColorFloats[4]; -// CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, -// gridLineColorFloats); -// gridLineColorFloats[3] = 1.0; -// -// const std::vector& gridXYZ = quadsData4f->getFloatXYZ(); -// const int32_t numCells = static_cast(gridXYZ.size() / 3); -// -// std::unique_ptr outlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, -// gridLineColorFloats)); -// outlineData4f->reserveForNumberOfVertices(numCells); -// for (int32_t i = 0; i < numCells; i++) { -// CaretAssertVectorIndex(gridXYZ, i*3); -// outlineData4f->addVertex(&gridXYZ[i*3]); -// } -// glPolygonMode(GL_FRONT, GL_LINE); -// glLineWidth(1.0); -// drawPrimitivePrivate(outlineData4f.get()); -// glPolygonMode(GL_FRONT, GL_FILL); -// } -// -// if ( (! selectedRowIndices.empty()) -// && highlightSelectedRowColumnFlag) { -// for (auto rowIndex : selectedRowIndices) { -// const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; -// -// int32_t minColumn = 0; -// int32_t maxColumn = numberOfColumns; -// if (haveSelectedRowsFlag) { -// std::map::iterator minMaxIter = columnRangesForRow.find(rowIndex); -// if (minMaxIter != columnRangesForRow.end()) { -// const int32_t minValue = minMaxIter->second.m_min; -// const int32_t rowMaxColumn = minMaxIter->second.m_max; -// if (minValue < rowMaxColumn) { -// minColumn = minValue; -// maxColumn = rowMaxColumn + 1; -// } -// } -// } -// -// const float minX = minColumn * cellWidth; -// const float maxX = maxColumn * cellWidth; -// -// std::unique_ptr rowOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, -// highlightRGBA)); -// rowOutlineData4f->reserveForNumberOfVertices(4); -// -// rowOutlineData4f->addVertex(minX, rowY); -// rowOutlineData4f->addVertex(maxX, rowY); -// rowOutlineData4f->addVertex(maxX, rowY + cellHeight, 0.0); -// rowOutlineData4f->addVertex(minX, rowY + cellHeight, 0.0); -// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); -// glLineWidth(highlightLineWidth); -// drawPrimitivePrivate(rowOutlineData4f.get()); -// } -// -// glLineWidth(1.0); -// } -// -// if ( (! selectedColumnIndices.empty()) -// && highlightSelectedRowColumnFlag) { -// for (auto columnIndex : selectedColumnIndices) { -// const float colX = columnIndex * cellWidth; -// -// int32_t minRow = 0; -// int32_t maxRow = numberOfRows; -// if (haveSelectedColumnsFlag) { -// std::map::iterator minMaxIter = rowRangesForColumn.find(columnIndex); -// if (minMaxIter != rowRangesForColumn.end()) { -// const int32_t minValue = minMaxIter->second.m_min; -// const int32_t maxValue = minMaxIter->second.m_max; -// if (minValue < maxValue) { -// minRow = minValue; -// maxRow = maxValue + 1; -// } -// } -// } -// -// const float minY = minRow * cellHeight; -// const float maxY = maxRow * cellHeight; -// -// std::unique_ptr columnOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, -// highlightRGBA)); -// columnOutlineData4f->reserveForNumberOfVertices(4); -// -// columnOutlineData4f->addVertex(colX, minY); -// columnOutlineData4f->addVertex(colX + cellWidth, minY); -// columnOutlineData4f->addVertex(colX + cellWidth, maxY); -// columnOutlineData4f->addVertex(colX, maxY); -// const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); -// glLineWidth(highlightLineWidth); -// drawPrimitivePrivate(columnOutlineData4f.get()); -// } -// glLineWidth(1.0); -// } -// -// glPolygonMode(GL_FRONT, GL_FILL); -// } -// -// if (m_identificationModeFlag) { -// processMatrixIdentification(matrixChart); -// } -//} - /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). @@ -2067,67 +1361,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const C } -/** - * Add an item for matrix identification. - * - * @param matrixRowIndex - * Index of the row - * @param matrixColumnIndex - * Index of the column - * @param rgbaForColorIdentificationOut - * Encoded identification in RGBA color OUTPUT - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::addToChartMatrixIdentification(const int32_t matrixRowIndex, - const int32_t matrixColumnIndex, - uint8_t rgbaForColorIdentificationOut[4]) -{ - const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; - - m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, - m_selectionItemDataType, - idIndex); - rgbaForColorIdentificationOut[3] = 255; - - /* - * If these items change, need to update reset and - * processing of identification. - */ - m_identificationIndices.push_back(matrixRowIndex); - m_identificationIndices.push_back(matrixColumnIndex); -} - -/** - * Process identification for matrix. - * - * @param matrixChart - * The matrix chart. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart) -{ - if (matrixChart != NULL) { - int32_t identifiedItemIndex; - float depth = -1.0; - m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, - m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - identifiedItemIndex, - depth); - if (identifiedItemIndex >= 0) { - const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; - const int32_t rowIndex = m_identificationIndices[idIndex]; - const int32_t columnIndex = m_identificationIndices[idIndex + 1]; - - if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(depth)) { - m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), - rowIndex, - columnIndex); - } - } - } -} - /** * Estimate the size of the axis' text. * @@ -2673,11 +1906,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* primitive); } - +/** + * Constructor. + * + * @param histogramDrawingInfo + * Drawing information for histogram + * @param histogramChart + * The file's histogram charting + * @param mapIndex + * Index of the map for which histogram is displayed. + * @param verticalAxisLocation + * Location of vertical axis for the histogram + */ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - const ChartableTwoFileHistogramChart* histogramChart, - int32_t mapIndex, - ChartAxisLocationEnum::Enum verticalAxisLocation) + const ChartableTwoFileHistogramChart* histogramChart, + int32_t mapIndex, + ChartAxisLocationEnum::Enum verticalAxisLocation) : m_histogramDrawingInfo(histogramDrawingInfo), m_histogramChart(histogramChart), m_mapIndex(mapIndex), @@ -2685,7 +1929,9 @@ m_verticalAxisLocation(verticalAxisLocation) { } - +/** + * Destructor. + */ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() { delete m_histogramDrawingInfo; } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index dda530118..8d33f2b7e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -114,11 +114,6 @@ namespace caret { void processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart); - void addToChartMatrixIdentification(const int32_t matrixRowIndex, - const int32_t matrixColumnIndex, - uint8_t rgbaForColorIdentificationOut[4]); - void processMatrixIdentification(const ChartableTwoFileMatrixChart* matrixChart); - void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, @@ -127,12 +122,6 @@ namespace caret { const float cellHeight, const float zooming); -// void OLDdrawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, -// const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, -// const float cellWidth, -// const float cellHeight, -// const float zooming); - void drawHistogramChart(); void drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, -- GitLab From 1ff9fef64767bd4433a028108d93709af787165f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 8 May 2017 16:09:07 -0500 Subject: [PATCH 262/755] Added method to get the bucket display value and height for a specified bucket index. --- src/Common/Histogram.cxx | 46 +++++++++++++++++++++ src/Common/Histogram.h | 4 ++ src/GuiQt/ChartTwoOverlayViewController.cxx | 10 +++++ 3 files changed, 60 insertions(+) diff --git a/src/Common/Histogram.cxx b/src/Common/Histogram.cxx index db8ecb1cf..671f65dce 100644 --- a/src/Common/Histogram.cxx +++ b/src/Common/Histogram.cxx @@ -325,3 +325,49 @@ void Histogram::computeCumulative() m_cumulative[i] = accum; } } + +/** + * Get the data value and height for the histogram's bucket index. + * + * @param bucketIndex + * The bucket index. + * @param bucketDataValueOut + * Output with data value at the bucket (x-axis) + * @param bucketHeightOut + * Output with height of bucket (y-axis) + * @return + * True if output values are positive, else false. + */ +bool +Histogram::getHistogramDisplayBucketDataValueAndHeight( const int32_t bucketIndex, + float& bucketDataValueOut, + float& bucketHeightOut) const +{ + bucketDataValueOut = 0.0; + bucketHeightOut = 0.0; + + const std::vector& buckets = getHistogramDisplay(); + const int32_t numberOfBuckets = static_cast(buckets.size()); + if ((bucketIndex >= 0) + && (bucketIndex < numberOfBuckets)) { + CaretAssertVectorIndex(buckets, + bucketIndex); + + float rangeMin = 0.0; + float rangeMax = 0.0; + getRange(rangeMin, rangeMax); + bucketDataValueOut = rangeMin; + if (rangeMax > rangeMin) { + const float range = rangeMax - rangeMin; + const float bucketWidth = range / numberOfBuckets; + bucketDataValueOut = (rangeMin + + (bucketIndex * bucketWidth)); + } + + bucketHeightOut = buckets[bucketIndex]; + + return true; + } + + return false; +} diff --git a/src/Common/Histogram.h b/src/Common/Histogram.h index be1f59b48..203ba8d6a 100644 --- a/src/Common/Histogram.h +++ b/src/Common/Histogram.h @@ -77,6 +77,10 @@ namespace caret ///get display values - counts divided by bucket widths - will be consistent on the same data regardless of number of buckets or const std::vector& getHistogramDisplay() const { return m_display; } + bool getHistogramDisplayBucketDataValueAndHeight( const int32_t bucketIndex, + float& bucketDataValueOut, + float& bucketHeightOut) const; + int getNumberOfBuckets() const { return (int)m_buckets.size(); } void getCounts(int64_t& posCount, int64_t& zeroCount, int64_t& negCount, int64_t& infCount, int64_t& negInfCount, int64_t& nanCount) const diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 1568b0251..34e18ab2b 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -480,6 +480,16 @@ ChartTwoOverlayViewController::allMapsCheckBoxClicked(bool status) return; } + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + m_chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + if (mapFile != NULL) { + mapFile->invalidateHistogramChartColoring(); + } + m_chartOverlay->setAllMapsSelected(status); this->updateGraphicsWindow(); -- GitLab From 9ad11fbd2c48f853a19c57e5fd42353ea0f0c03d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 8 May 2017 16:11:15 -0500 Subject: [PATCH 263/755] Revising new charting histogram drawing to use the new graphics primitives. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 510 +++---------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 23 +- src/Brain/IdentificationTextGenerator.cxx | 124 ++-- src/Brain/SelectionItemChartTwoHistogram.cxx | 56 +- src/Brain/SelectionItemChartTwoHistogram.h | 8 +- src/Files/CaretMappableDataFile.cxx | 16 +- src/Files/CaretMappableDataFile.h | 2 + src/Files/ChartableTwoFileHistogramChart.cxx | 680 +++++++++++++++++- src/Files/ChartableTwoFileHistogramChart.h | 64 +- src/Files/CiftiMappableDataFile.cxx | 3 + src/Files/GiftiTypeFile.cxx | 2 +- src/Files/VolumeFile.cxx | 2 + 12 files changed, 986 insertions(+), 504 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 4411708da..1174f56c4 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -221,8 +221,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, saveStateOfOpenGL(); - resetIdentification(); - if (m_chartOverlaySet != NULL) { const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); if (numberOfOverlays > 0) { @@ -313,8 +311,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() continue; } - const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); - const ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); if (histogramChart->isValid()) { CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); @@ -328,7 +326,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramDrawingInfo, histogramChart, selectedIndex, - chartOverlay->getCartesianVerticalAxisLocation()))); + chartOverlay->getCartesianVerticalAxisLocation(), + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())))); float bounds[4]; if (histogramDrawingInfo->getBounds(bounds)) { @@ -488,340 +488,107 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Draw the bars for all histogram and then draw the envelopes * so the envelopes are not obscured by the bars */ - for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { - for (auto& drawInfo : drawingInfo) { - if (drawInfo->m_histogramDrawingInfo->isValid()) { - const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); - CaretAssert(cmdf); - const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); - bool drawBarsFlag = false; - bool drawEnvelopeFlag = false; - if (drawModeInt == 0) { - drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); - } - else if (drawModeInt == 1) { - drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); - } - - if (drawBarsFlag - || drawEnvelopeFlag) { - bool leftVerticalAxisFlag = true; - switch (drawInfo->m_verticalAxisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - leftVerticalAxisFlag = false; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - break; - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (leftVerticalAxisFlag) { - glOrtho(xMin, xMax, - yMinLeft, yMaxLeft, - -10.0, 10.0); - } - else { - glOrtho(xMin, xMax, - yMinRight, yMaxRight, - -10.0, 10.0); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - bool applyTransformationsFlag = false; - if (applyTransformationsFlag) { - glTranslatef(m_translation[0], - m_translation[1], - 0.0); - - const float chartWidth = chartGraphicsDrawingViewport[2]; - const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; - glTranslatef(halfWidth, - halfHeight, - 0.0); - glScalef(m_zooming, - m_zooming, - 1.0); - glTranslatef(-halfWidth, - -halfHeight, - 0.0); - } - - const CaretColorEnum::Enum envelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); - drawHistogramChartContent(drawInfo.get(), - envelopeColor, - drawBarsFlag, - drawEnvelopeFlag); - } - } - } - } - } -} - -/* - * Draw the given histogram chart. - * - * @param drawingInfo - * Histogram drawing information. - * @param envelopeColor - * Color for drawing envelope. - * @param drawHistogramBarsFlag - * Draw the histogram as bars. - * @param drawHistogramEnvelopeFlag - * Draw the histogram as an envelope. - * - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, - const CaretColorEnum::Enum envelopeColor, - const bool drawHistogramBarsFlag, - const bool drawHistogramEnvelopeFlag) -{ - float envelopeSolidColorRGBA[4]; - CaretColorEnum::toRGBAFloat(envelopeColor, - envelopeSolidColorRGBA); - - const ChartableTwoFileHistogramChart* histogramChart = drawingInfo->m_histogramChart; - const int32_t mapIndex = drawingInfo->m_mapIndex; - const HistogramDrawingInfo& histogramDrawingInfo = *drawingInfo->m_histogramDrawingInfo; - - if ( ! histogramDrawingInfo.isValid()) { - return; - } - float bounds[4]; - if ( ! histogramDrawingInfo.getBounds(bounds)) { - return; - } - if (m_identificationModeFlag) { - resetIdentification(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - const std::vector& xValues = histogramDrawingInfo.getDataX(); - const std::vector& yValues = histogramDrawingInfo.getDataY(); - const std::vector& rgbaValues = histogramDrawingInfo.getDataRGBA(); - CaretAssert(xValues.size() == yValues.size()); - CaretAssert((xValues.size() * 4) == rgbaValues.size()); - - const int32_t numValues = static_cast(xValues.size() - 1); - if (numValues > 1) { - { - uint8_t thresholdRGBByte[3]; - m_preferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(thresholdRGBByte); - const float histogramRGBA[4] = { - thresholdRGBByte[0] / 255.0, - thresholdRGBByte[1] / 255.0, - thresholdRGBByte[2] / 255.0, - 1.0 - }; - std::vector histogramNormals = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 }; - CaretAssert(histogramNormals.size() == 12); - - const std::vector& histogramOneXYZ = histogramDrawingInfo.getThresholdOneBounds(); - if (histogramOneXYZ.size() == 12) { - std::unique_ptr threshPrim - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGON, histogramRGBA)); - threshPrim->addVertices(&histogramOneXYZ[0], - 4); - drawPrimitivePrivate(threshPrim.get()); - } - - const std::vector& histogramTwoXYZ = histogramDrawingInfo.getThresholdTwoBounds(); - if (histogramTwoXYZ.size() == 12) { - std::unique_ptr threshPrim - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGON, histogramRGBA)); - threshPrim->addVertices(&histogramTwoXYZ[0], - 4); - drawPrimitivePrivate(threshPrim.get()); - } - } - - if (drawHistogramBarsFlag) { - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 4; - const int32_t totalVertices = verticesPerBar * numValues; - - std::unique_ptr histogramFloatRGBA - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); - std::unique_ptr histogramByteRGBA - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); - - - if(m_identificationModeFlag) { - histogramByteRGBA->reserveForNumberOfVertices(totalVertices); - } - else { - histogramFloatRGBA->reserveForNumberOfVertices(totalVertices); - } - - const float z = 0.; - - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(rgbaValues, i*4 + 3); - const float* rgba = &rgbaValues[i * 4]; - if (rgba[3] > 0.0) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i+1]; - float bottom = 0; - CaretAssertVectorIndex(yValues, i); - float top = yValues[i]; - - if (m_identificationModeFlag) { - uint8_t idRGBA[4]; - addToHistogramIdentification(mapIndex, i, idRGBA); - histogramByteRGBA->addVertex(left, bottom, z, idRGBA); - histogramByteRGBA->addVertex(right, bottom, z, idRGBA); - histogramByteRGBA->addVertex(right, top, z, idRGBA); - histogramByteRGBA->addVertex(left, top, z, idRGBA); - } - else { - histogramFloatRGBA->addVertex(left, bottom, z, rgba); - histogramFloatRGBA->addVertex(right, bottom, z, rgba); - histogramFloatRGBA->addVertex(right, top, z, rgba); - histogramFloatRGBA->addVertex(left, top, z, rgba); - } - } - } - - /* - * Draw the bar elements. - */ - if (m_identificationModeFlag) { - drawPrimitivePrivate(histogramByteRGBA.get()); - } - else { - drawPrimitivePrivate(histogramFloatRGBA.get()); - } - } - - if (drawHistogramEnvelopeFlag) { - std::unique_ptr histogramFloatRGBA - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); - std::unique_ptr histogramByteRGBA - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); - - /* - * Reserve to prevent reszing of vectors - * as elements are added. - */ - const int32_t verticesPerBar = 2; - const int32_t totalVertices = verticesPerBar * numValues + 4; - if (m_identificationModeFlag) { - histogramByteRGBA->reserveForNumberOfVertices(totalVertices); - } - else { - histogramFloatRGBA->reserveForNumberOfVertices(totalVertices); - } - - const float z = 0.0; - - const int32_t lastValueIndex = numValues - 1; - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(xValues, i + 1); - float left = xValues[i]; - float right = xValues[i + 1]; - - CaretAssert(right >= left); - float bottom = 0; + for (auto& drawInfo : drawingInfo) { + if (drawInfo->m_histogramDrawingInfo->isValid()) { + const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); + CaretAssert(cmdf); + const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); + const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); + const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); - CaretAssertVectorIndex(yValues, i + 1); - float topLeft = yValues[i]; - float topRight = yValues[i+1]; - - float leftRGBA[4]; - float rightRGBA[4]; - float middleRGBA[4]; - if (envelopeColor == CaretColorEnum::CUSTOM) { - CaretAssertVectorIndex(rgbaValues, (i + 1) * 4 + 3); - const float* leftColorPtr = &rgbaValues[i * 4]; - const float* rightColorPtr = &rgbaValues[i * 4]; - for (int32_t m = 0; m < 4; m++) { - leftRGBA[m] = leftColorPtr[m]; - rightRGBA[m] = rightColorPtr[m]; - middleRGBA[m] = (leftColorPtr[m] + rightColorPtr[m]) / 2.0; - }; - } - else { - for (int32_t m = 0; m < 4; m++) { - leftRGBA[m] = envelopeSolidColorRGBA[m]; - rightRGBA[m] = envelopeSolidColorRGBA[m]; - middleRGBA[m] = envelopeSolidColorRGBA[m]; - }; - } - uint8_t idRGBA[4]; - if (m_identificationModeFlag) { - addToHistogramIdentification(mapIndex, i, idRGBA); - } - if (i == 0) { - if (m_identificationModeFlag) { - histogramByteRGBA->addVertex(left, bottom, z, idRGBA); - } - else { - histogramFloatRGBA->addVertex(left, bottom, z, leftRGBA); + if (drawBarsFlag + || drawEnvelopeFlag) { + bool leftVerticalAxisFlag = true; + switch (drawInfo->m_verticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + leftVerticalAxisFlag = false; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; } - if (m_identificationModeFlag) { - histogramByteRGBA->addVertex(left, topLeft, z, idRGBA); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (leftVerticalAxisFlag) { + glOrtho(xMin, xMax, + yMinLeft, yMaxLeft, + -10.0, 10.0); } else { - histogramFloatRGBA->addVertex(left, topLeft, z, leftRGBA); + glOrtho(xMin, xMax, + yMinRight, yMaxRight, + -10.0, 10.0); } - } - - if (m_identificationModeFlag) { - histogramByteRGBA->addVertex((left+right)/2.0, topLeft, z, idRGBA); - } - else { - histogramFloatRGBA->addVertex((left+right)/2.0, topLeft, z, middleRGBA); - } - - if (i == lastValueIndex) { - if (m_identificationModeFlag) { - histogramByteRGBA->addVertex(right, topRight, z, idRGBA); - } - else { - histogramFloatRGBA->addVertex(right, topRight, z, rightRGBA); - } - - if (m_identificationModeFlag) { - histogramByteRGBA->addVertex(right, bottom, z, idRGBA); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = false; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); } - else { - histogramFloatRGBA->addVertex(right, bottom, z, rightRGBA); + + ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = + drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, + drawInfo->m_allMapsSelected); + if (histogramPrimitives != NULL) { + if (m_identificationModeFlag) { + int32_t primitiveIndex = -1; + float primitiveDepth = 0.0; + glPushMatrix(); + glScalef(1.0, 1000.0, 1.0); // exagerrage height of bars for identification + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + histogramPrimitives->getBarsPrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + glPopMatrix(); + std::cout << "Histogram selection: " << primitiveIndex << std::endl; + if (primitiveIndex >= 0) { + if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { + m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), + drawInfo->m_mapIndex, + primitiveIndex, + drawInfo->m_allMapsSelected); + } + } + } + else { + drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); + if (drawBarsFlag) { + drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); + } + if (drawEnvelopeFlag) { + m_fixedPipelineDrawing->enableLineAntiAliasing(); + drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); + } + } } } } - - /* - * Draw the elements. - */ - if (m_identificationModeFlag) { - glLineWidth(5.0); - drawPrimitivePrivate(histogramByteRGBA.get()); - } - else { - glLineWidth(2.0); - drawPrimitivePrivate(histogramFloatRGBA.get()); - } } } - - if (m_identificationModeFlag) { - processHistogramIdentification(histogramChart); - } } /** @@ -984,7 +751,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } if (m_identificationModeFlag) { - resetIdentification(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @@ -1176,80 +942,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() } -/** - * Reset identification. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::resetIdentification() -{ - m_identificationIndices.clear(); - - if (m_identificationModeFlag) { - const int32_t estimatedNumberOfItems = 1000; - m_identificationIndices.reserve(estimatedNumberOfItems); - } -} -/** - * Add an item for matrix identification. - * - * @param mapIndex - * Index of the map whose histogram is displayed (negative indicates all maps). - * @param bucketIndex - * Index of the histogram bar. - * @param rgbaForColorIdentificationOut - * Encoded identification in RGBA color OUTPUT - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::addToHistogramIdentification(const int32_t mapIndex, - const int32_t bucketIndex, - uint8_t rgbaForColorIdentificationOut[4]) -{ - const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_HISTOGRAM; - - m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, - m_selectionItemDataType, - idIndex); - rgbaForColorIdentificationOut[3] = 255; - - /* - * If these items change, need to update reset and - * processing of identification. - */ - m_identificationIndices.push_back(mapIndex); - m_identificationIndices.push_back(bucketIndex); -} - -/** - * Process identification for histogram. - * - * @param histogramChart - * The histogram chart. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart) -{ - if (histogramChart != NULL) { - int32_t identifiedItemIndex; - float depth = -1.0; - m_fixedPipelineDrawing->getIndexFromColorSelection(m_selectionItemDataType, - m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - identifiedItemIndex, - depth); - if (identifiedItemIndex >= 0) { - const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_HISTOGRAM; - const int32_t mapIndex = m_identificationIndices[idIndex]; - const int32_t bucketIndex = m_identificationIndices[idIndex+1]; - - if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(depth)) { - m_selectionItemHistogram->setHistogramChart(const_cast(histogramChart), - mapIndex, - bucketIndex); - } - } - } -} - /** * Process identification for line-series. * @@ -1902,6 +1594,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data void BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* primitive) { + if (primitive == NULL) { + return; + } + GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getOpenGLContextPointer(), primitive); } @@ -1917,15 +1613,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* * Index of the map for which histogram is displayed. * @param verticalAxisLocation * Location of vertical axis for the histogram + * @param allMapsSelected + * True if ALL MAPS selected for histogram, else false. */ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - const ChartableTwoFileHistogramChart* histogramChart, + ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, - ChartAxisLocationEnum::Enum verticalAxisLocation) + ChartAxisLocationEnum::Enum verticalAxisLocation, + const bool allMapsSelected) : m_histogramDrawingInfo(histogramDrawingInfo), m_histogramChart(histogramChart), m_mapIndex(mapIndex), -m_verticalAxisLocation(verticalAxisLocation) +m_verticalAxisLocation(verticalAxisLocation), +m_allMapsSelected(allMapsSelected) { } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 8d33f2b7e..be7953dfc 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -61,14 +61,16 @@ namespace caret { class HistogramChartDrawingInfo { public: HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - const ChartableTwoFileHistogramChart* histogramChart, + ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, - ChartAxisLocationEnum::Enum verticalAxisLocation); + ChartAxisLocationEnum::Enum verticalAxisLocation, + const bool allMapsSelected); HistogramDrawingInfo* m_histogramDrawingInfo; - const ChartableTwoFileHistogramChart* m_histogramChart; + ChartableTwoFileHistogramChart* m_histogramChart; int32_t m_mapIndex; ChartAxisLocationEnum::Enum m_verticalAxisLocation; + const bool m_allMapsSelected; ~HistogramChartDrawingInfo(); }; @@ -104,14 +106,6 @@ namespace caret { void saveStateOfOpenGL(); - void resetIdentification(); - - void addToHistogramIdentification(const int32_t mapIndex, - const int32_t bucketIndex, - uint8_t rgbaForColorIdentificationOut[4]); - - void processHistogramIdentification(const ChartableTwoFileHistogramChart* histogramChart); - void processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart); void drawMatrixChart(); @@ -124,11 +118,6 @@ namespace caret { void drawHistogramChart(); - void drawHistogramChartContent(const HistogramChartDrawingInfo* drawingInfo, - const CaretColorEnum::Enum envelopeColor, - const bool drawHistogramBarsFlag, - const bool drawHistogramEnvelopeFlag); - void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, @@ -174,8 +163,6 @@ namespace caret { float m_zooming; - std::vector m_identificationIndices; - CaretPreferences* m_preferences; SelectionItemChartTwoHistogram* m_selectionItemHistogram; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index cb4dc4246..8b03d5142 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -33,6 +33,7 @@ #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartableMatrixInterface.h" +#include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" @@ -46,7 +47,6 @@ #include "Focus.h" #include "GiftiLabel.h" #include "Histogram.h" -#include "HistogramDrawingInfo.h" #include "ImageFile.h" #include "OverlaySet.h" #include "SelectionItemBorderSurface.h" @@ -801,72 +801,78 @@ void IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoHistogram* idChartTwoHistogram) const { + const int32_t mapIndex = idChartTwoHistogram->getMapIndex(); + const int32_t bucketIndex = idChartTwoHistogram->getBucketIndex(); + const bool allMapsFlag = idChartTwoHistogram->isAllMapsSelected(); + if (idChartTwoHistogram->isValid()) { ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); - const int32_t mapIndex = idChartTwoHistogram->getMapIndex(); - const int32_t bucketIndex = idChartTwoHistogram->getBucketIndex(); + CaretAssert(fileHistogramChart); CaretMappableDataFile* mapFile = fileHistogramChart->getCaretMappableDataFile(); CaretAssert(mapFile); - - const bool allMapsFlag = (mapIndex < 0); - HistogramDrawingInfo histogramDrawingInfo; - AString errorMessage; - if (mapFile->getMapHistogramDrawingInfo(mapIndex, - allMapsFlag, - false, - histogramDrawingInfo, - errorMessage)) { - if (histogramDrawingInfo.isValid()) { + + { + ChartableTwoFileHistogramChart* chartingDelegate = mapFile->getChartingDelegate()->getHistogramCharting(); + CaretAssert(chartingDelegate); + const Histogram* histogram = chartingDelegate->getHistogramForChartDrawing(mapIndex, + allMapsFlag); + CaretAssert(histogram); + + float bucketValue = 0.0; + float bucketHeight = 0.0; + if (histogram->getHistogramDisplayBucketDataValueAndHeight(bucketIndex, bucketValue, bucketHeight)) { + AString boldText("Histogram"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); - float bucketValue = 0.0; - float bucketHeight = 0.0; - if (histogramDrawingInfo.getBucketDataValueAndCount(bucketIndex, - bucketValue, - bucketHeight)) { - - AString boldText("Histogram"); - idText.addLine(false, - boldText, - mapFile->getFileNameNoPath()); - idText.addLine(true, - "Bucket Index", - (AString::number(bucketIndex))); - idText.addLine(true, - "Data Value at Bucket", - (AString::number(bucketValue))); - - idText.addLine(true, - "Bucket Count", - (AString::number(bucketHeight))); - } + idText.addLine(true, + "Bucket Index", + (AString::number(bucketIndex))); + + idText.addLine(true, + "Data Value at Bucket", + (AString::number(bucketValue))); + + const int64_t bucketHeightInteger = static_cast(bucketHeight); + idText.addLine(true, + "Bucket Count", + (AString::number(bucketHeightInteger))); } } -// if (mapFile->getNumberOfMaps() > 0) { -// const Histogram* histogram = ((mapIndex >= 0) -// ? mapFile->getMapHistogram(mapIndex) -// : mapFile->getFileHistogram()); -// -// float bucketValue = 0.0; -// float bucketHeight = 0.0; -// if (histogram->getBucketDataValueAndCount(bucketIndex, -// bucketValue, -// bucketHeight)) { -// AString boldText("Histogram"); -// idText.addLine(false, -// boldText, -// mapFile->getFileNameNoPath()); -// -// idText.addLine(true, -// "Bucket Index", -// (AString::number(bucketIndex))); -// -// idText.addLine(true, -// "Data Value at Bucket", -// (AString::number(bucketValue))); + + +// HistogramDrawingInfo histogramDrawingInfo; +// AString errorMessage; +// if (mapFile->getMapHistogramDrawingInfo(mapIndex, +// allMapsFlag, +// false, +// histogramDrawingInfo, +// errorMessage)) { +// if (histogramDrawingInfo.isValid()) { // -// idText.addLine(true, -// "Bucket Count", -// (AString::number(bucketHeight))); +// float bucketValue = 0.0; +// float bucketHeight = 0.0; +// if (histogramDrawingInfo.getBucketDataValueAndCount(bucketIndex, +// bucketValue, +// bucketHeight)) { +// +// AString boldText("OLD Histogram"); +// idText.addLine(false, +// boldText, +// mapFile->getFileNameNoPath()); +// idText.addLine(true, +// "Bucket Index", +// (AString::number(bucketIndex))); +// idText.addLine(true, +// "Data Value at Bucket", +// (AString::number(bucketValue))); +// +// const int64_t bucketHeightInteger = static_cast(bucketHeight); +// idText.addLine(true, +// "Bucket Count", +// (AString::number(bucketHeightInteger))); +// } // } // } } diff --git a/src/Brain/SelectionItemChartTwoHistogram.cxx b/src/Brain/SelectionItemChartTwoHistogram.cxx index 396918730..d54b50778 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.cxx +++ b/src/Brain/SelectionItemChartTwoHistogram.cxx @@ -40,9 +40,7 @@ using namespace caret; SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_HISTOGRAM) { - m_fileHistogramChart = NULL; - m_mapIndex = -1; - m_bucketIndex = -1; + resetPrivate(); } /** @@ -88,9 +86,10 @@ SelectionItemChartTwoHistogram::operator=(const SelectionItemChartTwoHistogram& void SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) { - m_fileHistogramChart = obj.m_fileHistogramChart; - m_mapIndex = obj.m_mapIndex; - m_bucketIndex = obj.m_bucketIndex; + m_fileHistogramChart = obj.m_fileHistogramChart; + m_mapIndex = obj.m_mapIndex; + m_bucketIndex = obj.m_bucketIndex; + m_allMapsSelectedFlag = obj.m_allMapsSelectedFlag; } @@ -101,7 +100,8 @@ SelectionItemChartTwoHistogram::getFileHistogramChart() const } /** - * @return Index of map index selected. + * @return Index of map index selected. Also + * should test isAllMapsSelected() */ int32_t SelectionItemChartTwoHistogram::getMapIndex() const @@ -118,6 +118,16 @@ SelectionItemChartTwoHistogram::getBucketIndex() const return m_bucketIndex; } +/** + * @return Is all maps selected? + */ +bool +SelectionItemChartTwoHistogram::isAllMapsSelected() const +{ + return m_allMapsSelectedFlag; +} + + /* * Set histogram identification. * @@ -127,15 +137,19 @@ SelectionItemChartTwoHistogram::getBucketIndex() const * Index of the map whose histogram is displayed (negative indicates all maps). * @param bucketIndex * Index of the histogram bucket. + * @param allMapsSelected + * True if all maps selected, else false. */ void SelectionItemChartTwoHistogram::setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, const int32_t mapIndex, - const int32_t bucketIndex) + const int32_t bucketIndex, + const bool allMapsSelected) { - m_fileHistogramChart = fileHistogramChart; - m_mapIndex = mapIndex; - m_bucketIndex = bucketIndex; + m_fileHistogramChart = fileHistogramChart; + m_mapIndex = mapIndex; + m_bucketIndex = bucketIndex; + m_allMapsSelectedFlag = allMapsSelected; } /** @@ -148,7 +162,9 @@ SelectionItemChartTwoHistogram::isValid() const * Map index is negative if all maps selected. */ if ((m_fileHistogramChart != NULL) - && (m_bucketIndex >= 0)) { + && (m_bucketIndex >= 0) + && ((m_mapIndex >= 0) + || m_allMapsSelectedFlag)) { return true; } @@ -156,14 +172,26 @@ SelectionItemChartTwoHistogram::isValid() const } /** - * Reset the selections. + * Reset the selections PRIVATE. + * Note that reset() is virtual and cannot + * be called from constructor. */ void -SelectionItemChartTwoHistogram::reset() +SelectionItemChartTwoHistogram::resetPrivate() { m_fileHistogramChart = NULL; m_mapIndex = -1; m_bucketIndex = -1; + m_allMapsSelectedFlag = false; +} + +/** + * Reset the selections. + */ +void +SelectionItemChartTwoHistogram::reset() +{ + resetPrivate(); } diff --git a/src/Brain/SelectionItemChartTwoHistogram.h b/src/Brain/SelectionItemChartTwoHistogram.h index dcde564b8..2f424a9be 100644 --- a/src/Brain/SelectionItemChartTwoHistogram.h +++ b/src/Brain/SelectionItemChartTwoHistogram.h @@ -51,19 +51,25 @@ namespace caret { int32_t getMapIndex() const; + bool isAllMapsSelected() const; + void setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, const int32_t mapIndex, - const int32_t bucketIndex); + const int32_t bucketIndex, + const bool allMapsSelected); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); + void resetPrivate(); + ChartableTwoFileHistogramChart* m_fileHistogramChart; int32_t m_mapIndex; int32_t m_bucketIndex; + bool m_allMapsSelectedFlag; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 9239d5502..11b40ab97 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -27,7 +27,8 @@ #include "CaretLogger.h" #include "ChartDataCartesian.h" -#include "ChartTwoDataCartesianHistory.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" @@ -206,8 +207,10 @@ CaretMappableDataFile::updateScalarColoringForAllMaps(const PaletteFile* palette const int32_t numMaps = getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { updateScalarColoringForMap(iMap, - paletteFile); + paletteFile); } + + invalidateHistogramChartColoring(); } /** @@ -255,6 +258,15 @@ CaretMappableDataFile::isPaletteColorMappingEqualForAllMaps() const return true; } +/** + * Invalidate all histogram coloring for this file. + */ +void +CaretMappableDataFile::invalidateHistogramChartColoring() +{ + m_chartingDelegate->getHistogramCharting()->invalidateAllColoring(); +} + // note: method is documented in header file NiftiTimeUnitsEnum::Enum CaretMappableDataFile::getMapIntervalUnits() const diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index 60ef3da8d..e3601dd36 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -420,6 +420,8 @@ namespace caret { virtual void updateScalarColoringForMap(const int32_t mapIndex, const PaletteFile* paletteFile) = 0; + void invalidateHistogramChartColoring(); + virtual bool isPaletteColorMappingEqualForAllMaps() const; /** diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 0e9dfbcdc..a993b23e8 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -25,8 +25,15 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" -//#include "ChartTwoDataHistogram.h" +#include "CaretLogger.h" +#include "CaretPreferences.h" +#include "EventCaretPreferencesGet.h" +#include "EventManager.h" +#include "EventPaletteGetByName.h" +#include "FastStatistics.h" #include "Histogram.h" +#include "NodeAndVoxelColoring.h" +#include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -116,6 +123,638 @@ ChartableTwoFileHistogramChart::isEmpty() const return false; } +/** + * Invalidate coloring for all histograms. + */ +void +ChartableTwoFileHistogramChart::invalidateAllColoring() +{ + m_mapHistogramBarsPrimitive.clear(); + std::cout << "Invalidating histograms..." << std::endl; +} + +/** + * Get the histogram for drawing histogram as a chart + * + * @param mapIndex + * Index of the map. + * @param useDataFromAllMapsFlag + * If true, include data from all maps for histogram chart. + * @return + * Histogram for histogram chart drawing. May be NULL if map is not + * mapped with a color palette or the map index is invalid. + */ +const Histogram* +ChartableTwoFileHistogramChart::getHistogramForChartDrawing(const int32_t mapIndex, + const bool useDataFromAllMapsFlag) +{ + CaretMappableDataFile* myMapFile = getCaretMappableDataFile(); + CaretAssert(myMapFile); + + const Histogram* histogramOut= NULL; + + if ( ! myMapFile->isMappedWithPalette()) { + return histogramOut; + } + if ((mapIndex < 0) + || (mapIndex >= myMapFile->getNumberOfMaps())) { + return histogramOut; + } + + PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); + CaretAssert(paletteColorMapping); + + EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); + EventManager::get()->sendEvent(paletteEvent.getPointer()); + const Palette* palette = paletteEvent.getPalette(); + if (palette == NULL) { + CaretLogSevere("Unable to find palette named: " + + paletteColorMapping->getSelectedPaletteName()); + return histogramOut; + } + + FastStatistics* statistics = NULL; + if (useDataFromAllMapsFlag) { + statistics = const_cast(myMapFile->getFileFastStatistics()); + } + else { + switch (myMapFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(myMapFile->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); + break; + } + } + + /* + * Statistics may be NULL for connectivity files (dense, dense dynamic) + * that have not yet loaded any data caused by the user clicking + * brainordinates. + */ + if (statistics == NULL) { + return histogramOut; + } + + CaretAssert(statistics); + float mostPos = 0.0; + float leastPos = 0.0; + float leastNeg = 0.0; + float mostNeg = 0.0; + bool matchFlag = false; + + switch (paletteColorMapping->getHistogramRangeMode()) { + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: + { + float dummy; + statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); + } + break; + case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: + { + matchFlag = true; + switch (paletteColorMapping->getScaleMode()) { + case PaletteScaleModeEnum::MODE_AUTO_SCALE: + mostPos = statistics->getMax(); + leastPos = 0.0; + leastNeg = 0.0; + mostNeg = statistics->getMin(); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: + mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); + leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); + leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); + mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); + break; + case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: + mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); + leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); + leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); + mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); + break; + case PaletteScaleModeEnum::MODE_USER_SCALE: + mostPos = paletteColorMapping->getUserScalePositiveMaximum(); + leastPos = paletteColorMapping->getUserScalePositiveMinimum(); + leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); + mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); + break; + } + } + break; + } + + /* + * Remove data that is not displayed + */ + bool isZeroIncluded = true; + if (matchFlag) { + isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); + + if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { + mostNeg = 0.0; + leastNeg = 0.0; + } + if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { + mostPos = 0.0; + leastPos = 0.0; + } + + if (useDataFromAllMapsFlag) { + histogramOut = myMapFile->getFileHistogram(mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + } + else { + switch (myMapFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogramOut = myMapFile->getFileHistogram(mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogramOut = myMapFile->getMapHistogram(mapIndex, + mostPos, + leastPos, + leastNeg, + mostNeg, + isZeroIncluded); + break; + } + } + } + else { + if (useDataFromAllMapsFlag) { + histogramOut = myMapFile->getFileHistogram(); + } + else { + switch (myMapFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + histogramOut = myMapFile->getFileHistogram(); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + histogramOut = myMapFile->getMapHistogram(mapIndex); + break; + } + } + } + + CaretAssert(histogramOut); + + return histogramOut; +} + +/** + * Get the graphics primitive for drawing bars for the given map index. + * + * @param mapIndex + * Index of the map. + * @return + * Primitives for drawing the histogram, bars, and envelope. May be NULL if map is not + * mapped with a color palette or the map index is invalid. + */ +ChartableTwoFileHistogramChart::HistogramPrimitives* +ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t mapIndex, + const bool useDataFromAllMapsFlag) +{ + MapIndexPrimitiveContainer::iterator iter = m_mapHistogramBarsPrimitive.find(mapIndex); + if (iter != m_mapHistogramBarsPrimitive.end()) { + HistogramPrimitives* histogramPrimitives = iter->second.get(); + if (histogramPrimitives != NULL) { + return histogramPrimitives; + } + } + + CaretMappableDataFile* myMapFile = getCaretMappableDataFile(); + CaretAssert(myMapFile); + + const Histogram* histogram = getHistogramForChartDrawing(mapIndex, + useDataFromAllMapsFlag); + if (histogram == NULL) { + return NULL; + } + +// if ( ! myMapFile->isMappedWithPalette()) { +// return histogramPrimitives; +// } +// if ((mapIndex < 0) +// || (mapIndex >= myMapFile->getNumberOfMaps())) { +// return histogramPrimitives; +// } +// +// PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); +// CaretAssert(paletteColorMapping); +// +// EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); +// EventManager::get()->sendEvent(paletteEvent.getPointer()); +// const Palette* palette = paletteEvent.getPalette(); +// if (palette == NULL) { +// CaretLogSevere("Unable to find palette named: " +// + paletteColorMapping->getSelectedPaletteName()); +// return histogramPrimitives; +// } +// +// FastStatistics* statistics = NULL; +// if (useDataFromAllMapsFlag) { +// statistics = const_cast(myMapFile->getFileFastStatistics()); +// } +// else { +// switch (myMapFile->getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// statistics = const_cast(myMapFile->getFileFastStatistics()); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); +// break; +// } +// } +// +// /* +// * Statistics may be NULL for connectivity files (dense, dense dynamic) +// * that have not yet loaded any data caused by the user clicking +// * brainordinates. +// */ +// if (statistics == NULL) { +// return histogramPrimitives; +// } +// +// MapIndexPrimitiveContainer::iterator iter = m_mapHistogramBarsPrimitive.find(mapIndex); +// if (iter != m_mapHistogramBarsPrimitive.end()) { +// histogramPrimitives = iter->second.get(); +// } +// +// if (histogramPrimitives == NULL) { +// CaretAssert(statistics); +// float mostPos = 0.0; +// float leastPos = 0.0; +// float leastNeg = 0.0; +// float mostNeg = 0.0; +// bool matchFlag = false; +// +// switch (paletteColorMapping->getHistogramRangeMode()) { +// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: +// { +// float dummy; +// statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); +// } +// break; +// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: +// { +// matchFlag = true; +// switch (paletteColorMapping->getScaleMode()) { +// case PaletteScaleModeEnum::MODE_AUTO_SCALE: +// mostPos = statistics->getMax(); +// leastPos = 0.0; +// leastNeg = 0.0; +// mostNeg = statistics->getMin(); +// break; +// case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: +// mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); +// leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); +// leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); +// mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); +// break; +// case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: +// mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); +// leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); +// leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); +// mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); +// break; +// case PaletteScaleModeEnum::MODE_USER_SCALE: +// mostPos = paletteColorMapping->getUserScalePositiveMaximum(); +// leastPos = paletteColorMapping->getUserScalePositiveMinimum(); +// leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); +// mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); +// break; +// } +// } +// break; +// } +// +// /* +// * Remove data that is not displayed +// */ +// bool isZeroIncluded = true; +// const Histogram* histogram = NULL; +// if (matchFlag) { +// isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); +// +// if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { +// mostNeg = 0.0; +// leastNeg = 0.0; +// } +// if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { +// mostPos = 0.0; +// leastPos = 0.0; +// } +// +// if (useDataFromAllMapsFlag) { +// histogram = myMapFile->getFileHistogram(mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// } +// else { +// switch (myMapFile->getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// histogram = myMapFile->getFileHistogram(mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// histogram = myMapFile->getMapHistogram(mapIndex, +// mostPos, +// leastPos, +// leastNeg, +// mostNeg, +// isZeroIncluded); +// break; +// } +// } +// } +// else { +// if (useDataFromAllMapsFlag) { +// histogram = myMapFile->getFileHistogram(); +// } +// else { +// switch (myMapFile->getPaletteNormalizationMode()) { +// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: +// histogram = myMapFile->getFileHistogram(); +// break; +// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: +// histogram = myMapFile->getMapHistogram(mapIndex); +// break; +// } +// } +// } + + CaretAssert(histogram); + + /* CUT HERE */ + /* + * Move this code to a function + */ + { + FastStatistics* statistics = NULL; + if (useDataFromAllMapsFlag) { + statistics = const_cast(myMapFile->getFileFastStatistics()); + } + else { + switch (myMapFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(myMapFile->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); + break; + } + } + + PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); + CaretAssert(paletteColorMapping); + + EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); + EventManager::get()->sendEvent(paletteEvent.getPointer()); + const Palette* palette = paletteEvent.getPalette(); + if (palette == NULL) { + CaretLogSevere("Unable to find palette named: " + + paletteColorMapping->getSelectedPaletteName()); + return NULL; + } + + float minValueX = 0.0; + float maxValueX = 0.0; + histogram->getRange(minValueX, + maxValueX); + const float valueRangeX = maxValueX - minValueX; + if (valueRangeX <= 0.0) { + CaretLogSevere("Range of histogram X-values is zero"); + return NULL; + } + + if ((paletteColorMapping != NULL) + && (statistics != NULL) + && (palette != NULL) + && (histogram != NULL)) { + std::vector histogramBuckets = histogram->getHistogramDisplay(); + const int32_t numBucketValues = static_cast(histogramBuckets.size()); + if (numBucketValues < 2) { + CaretLogSevere("Histogram must contain two or more values"); + return NULL; + } + + const float bucketWidth = valueRangeX / (numBucketValues - 1); + std::vector xValuesAtBuckets; + xValuesAtBuckets.reserve(numBucketValues); + for (int32_t i = 0; i < numBucketValues; i++) { + xValuesAtBuckets.push_back(minValueX + (bucketWidth * i)); + } + CaretAssert(xValuesAtBuckets.size() == histogramBuckets.size()); + + std::vector histogramRGBA; + histogramRGBA.resize(numBucketValues * 4, + 0.0f); + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + &xValuesAtBuckets[0], + &xValuesAtBuckets[0], + numBucketValues, + &histogramRGBA[0], + true); // ignore thresholding + + + const int32_t estimatedNumberOfVertices = (numBucketValues * 4); // four vertices per quad + + GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVertices); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_STRIP); + GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; + + bool setThresholdingFlag = false; + switch (paletteColorMapping->getThresholdType()) { + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: + setThresholdingFlag = true; + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: + break; + } + + if (setThresholdingFlag) { + /* + * RGBA for thresholding + */ + EventCaretPreferencesGet preferencesEvent; + EventManager::get()->sendEvent(preferencesEvent.getPointer()); + CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); + float threshRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; + if (caretPreferences != NULL) { + uint8_t threshByteRGBA[4]; + caretPreferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(threshByteRGBA); + threshRGBA[0] = static_cast(threshByteRGBA[0]) / 255.0f; + threshRGBA[1] = static_cast(threshByteRGBA[1]) / 255.0f; + threshRGBA[2] = static_cast(threshByteRGBA[2]) / 255.0f; + threshRGBA[3] = 1.0; + } + const float minX = -1000000.0f; //minValueX; + const float maxX = 1000000.0f; + const float minY = 0.0; + const float maxY = *std::max_element(histogramBuckets.begin(), + histogramBuckets.end()); + + float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); + float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); + + thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + + switch (paletteColorMapping->getThresholdTest()) { + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: + { + thresholdPrimitive->reserveForNumberOfVertices(8); + thresholdPrimitive->addVertex(minX, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(minX, maxY, threshRGBA); + + thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); + thresholdPrimitive->addVertex(maxX, minY, threshRGBA); + thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + } + break; + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: + { + thresholdPrimitive->reserveForNumberOfVertices(4); + thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + } + break; + } + } + + /* + * If selected, apply solid color to envelope histogram + */ + const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); + float envelopeSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; + bool envelopeSolidColorFlag = false; + if (histogramEnvelopeColor != CaretColorEnum::CUSTOM) { + CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, + envelopeSolidColorRGBA); + envelopeSolidColorFlag = true; + } + + /* + * If selected, apply solid color to bars histogram + */ + const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); + float barsSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; + bool barsSolidColorFlag = false; + if (histogramBarsColor != CaretColorEnum::CUSTOM) { + CaretColorEnum::toRGBAFloat(histogramBarsColor, + barsSolidColorRGBA); + barsSolidColorFlag = true; + } + + /* + * Move start one-half of bucket width so that bar's + * X-value is centered within the bar + */ + const float halfBucketWidth = bucketWidth / 2.0f; + const float startX = minValueX - halfBucketWidth; + + + float x = startX; + for (int32_t i = 0; i < numBucketValues; i++) { + CaretAssertVectorIndex(histogramBuckets, i); + const float xMin = x; + const float xMax = x + bucketWidth; + const float yMin = 0.0f; + float yMax = histogramBuckets[i]; + + CaretAssertVectorIndex(histogramRGBA, i*4+3); + const float* rgba = &histogramRGBA[i * 4]; + const float alpha = rgba[3]; + + /* + * Use a height of zero when there is no coloring + * (apha == 0) for a bar since the bars will be + * smoothed to create the envelope. + */ + if (alpha <= 0.0) { + yMax = 0.0; + } + + if (barsSolidColorFlag) { + /* + * Use alpha from normal coloring + */ + barsSolidColorRGBA[3] = rgba[3]; + barsPrimitive->addVertex(xMin, yMin, barsSolidColorRGBA); + barsPrimitive->addVertex(xMax, yMin, barsSolidColorRGBA); + barsPrimitive->addVertex(xMax, yMax, barsSolidColorRGBA); + barsPrimitive->addVertex(xMin, yMax, barsSolidColorRGBA); + } + else { + barsPrimitive->addVertex(xMin, yMin, rgba); + barsPrimitive->addVertex(xMax, yMin, rgba); + barsPrimitive->addVertex(xMax, yMax, rgba); + barsPrimitive->addVertex(xMin, yMax, rgba); + } + + if (envelopeSolidColorFlag) { + const float envelopeX = x + halfBucketWidth; + if (i == 0) { + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + } + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + } + } + else { + const float envelopeX = x + halfBucketWidth; + if (i == 0) { + envelopePrimitive->addVertex(envelopeX, yMin, rgba); + } + envelopePrimitive->addVertex(envelopeX, yMax, rgba); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMin, rgba); + } + } + + x += bucketWidth; + } + + HistogramPrimitives* histogramPrimitives = new HistogramPrimitives(thresholdPrimitive, + barsPrimitive, + envelopePrimitive); + + std::cout << "Created new histograms" << std::endl; + m_mapHistogramBarsPrimitive.insert(std::make_pair(mapIndex, + std::unique_ptr(histogramPrimitives))); + + return histogramPrimitives; + + } + } + + return NULL; +} + ///** // * Get the histogram chart for the given map index. // * @@ -192,3 +831,42 @@ ChartableTwoFileHistogramChart::restoreSubClassDataFromScene(const SceneAttribut sceneClass); } +/** + * Default constructor. + */ +ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives() +{ +} + +/** + * Constructor for primitives + * + * @param thresholdPrimitive + * Graphics Primitive for drawing threshold ranges. + * @param barsPrimitive + * Graphics Primitive for drawing histogram bars. + * @param envelopePrimitive + * Graphics Primitive for drawing histogram envelope. + */ +ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, + GraphicsPrimitiveV3fC4f* barsPrimitive, + GraphicsPrimitiveV3fC4f* envelopePrimitive) +{ +// if (thresholdPrimitive != NULL) { + m_thresholdPrimitive.reset(thresholdPrimitive); +// } +// if (barsPrimitive != NULL) { + m_barsPrimitive.reset(barsPrimitive); +// } +// if (envelopePrimitive != NULL) { + m_envelopePrimitive.reset(envelopePrimitive); +// } +} + +/* + * Destructor. + */ +ChartableTwoFileHistogramChart::HistogramPrimitives::~HistogramPrimitives() +{ + +} diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index bbfa8228d..4afc36635 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -21,19 +21,57 @@ */ /*LICENSE_END*/ +#include #include #include "ChartableTwoFileBaseChart.h" #include "ChartTwoHistogramContentTypeEnum.h" - +#include "GraphicsPrimitiveV3fC4f.h" // forward declaration has problems namespace caret { - - //class ChartTwoDataHistogram; + class Histogram; class ChartableTwoFileHistogramChart : public ChartableTwoFileBaseChart { public: + /** + * Contains the graphics primitives for drawing + * the histogram threshold, bars, and envelope. + */ + class HistogramPrimitives { + public: + HistogramPrimitives(); + + HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, + GraphicsPrimitiveV3fC4f* barsPrimitive, + GraphicsPrimitiveV3fC4f* envelopePrimitive); + + ~HistogramPrimitives(); + + /* + * @return Graphics primitive for drawing threshlold. + * NULL if invalid. + */ + GraphicsPrimitiveV3fC4f* getThresholdPrimitive() { return m_thresholdPrimitive.get(); } + + /* + * @return Graphics primitive for drawing histogram bars. + * NULL if invalid. + */ + GraphicsPrimitiveV3fC4f* getBarsPrimitive() { return m_barsPrimitive.get(); } + + /* + * @return Graphics primitive for drawing histogram envelope. + * NULL if invalid. + */ + GraphicsPrimitiveV3fC4f* getEnvelopePrimitive() { return m_envelopePrimitive.get(); } + + private: + std::unique_ptr m_thresholdPrimitive; + std::unique_ptr m_barsPrimitive; + std::unique_ptr m_envelopePrimitive; + }; + ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, CaretMappableDataFile* parentCaretMappableDataFile); @@ -45,6 +83,14 @@ namespace caret { virtual bool isEmpty() const override; + const Histogram* getHistogramForChartDrawing(const int32_t mapIndex, + const bool useDataFromAllMapsFlag); + + HistogramPrimitives* getMapHistogramDrawingPrimitives(const int32_t mapIndex, + const bool useDataFromAllMapsFlag); + + void invalidateAllColoring(); + //const ChartTwoDataHistogram* getMapHistogramChart(const int32_t mapIndex) const; // ADD_NEW_METHODS_HERE @@ -65,6 +111,18 @@ namespace caret { const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; +// std::unique_ptr m_fileHistogramBarsPrimitive; +// +// std::unique_ptr m_fileHistogramBarsLimitiedValuesPrimitive; + + typedef std::map> MapIndexPrimitiveContainer; + + MapIndexPrimitiveContainer m_mapHistogramBarsPrimitive; + + MapIndexPrimitiveContainer m_mapHistogramThresholdPrimitive; + + //std::map> m_mapHistogramBarsLimitedValuesPrimitive; + // mutable std::map m_indexHistogramsMap; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 0fb8ae02b..b752893ba 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1429,6 +1429,7 @@ CiftiMappableDataFile::invalidateColoringInAllMaps() * and in particular, matrix grid outline coloring */ m_matrixGraphicsPrimitive.reset(); + invalidateHistogramChartColoring(); } /** @@ -2489,6 +2490,8 @@ CiftiMappableDataFile::updateScalarColoringForMap(const int32_t mapIndex, /* * Force recreation of matrix so that it receives updates to coloring. */ + + invalidateHistogramChartColoring(); m_matrixGraphicsPrimitive.reset(); } diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 75ad31ac1..db2f28a71 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -966,7 +966,7 @@ void GiftiTypeFile::updateScalarColoringForMap(const int32_t /*mapIndex*/, const PaletteFile* /*paletteFile*/) { - /* no volumes in gifti */ + invalidateHistogramChartColoring(); } /** diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 263d71a83..57ac9a5e8 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -1455,6 +1455,8 @@ VolumeFile::updateScalarColoringForMap(const int32_t mapIndex, palette, this, mapIndex); + + invalidateHistogramChartColoring(); } /** -- GitLab From c80f692ffe18d770a5aca1445c18607689c7f55a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 8 May 2017 16:23:13 -0500 Subject: [PATCH 264/755] Fixed identification of histogram bars in tile tabs and on the far right tail. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 7c8069e8a..06ddfa4f4 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -401,9 +401,9 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, glGetIntegerv(GL_VIEWPORT, viewport); if ((pixelX >= viewport[0]) - && (pixelX < viewport[2]) + && (pixelX < (viewport[0] + viewport[2])) && (pixelY >= viewport[1]) - && (pixelY < viewport[3])) { + && (pixelY < (viewport[1] + viewport[3]))) { /* * Saves glPixelStore parameters */ -- GitLab From 5f74ce9d8cb9f7f3b4ce4cdd409164f198d548e7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 9 May 2017 09:59:41 -0500 Subject: [PATCH 265/755] Added identification using histogram envelopes. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 44 ++++++++++++++---- src/Files/ChartableTwoFileHistogramChart.cxx | 46 +++++++++++++++---- .../GraphicsPrimitiveSelectionHelper.cxx | 27 +++++------ 3 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 1174f56c4..a03bc7489 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -552,19 +552,41 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, drawInfo->m_allMapsSelected); if (histogramPrimitives != NULL) { + const float ENVELOPE_LINE_WIDTH = 1.0; + if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; - glPushMatrix(); - glScalef(1.0, 1000.0, 1.0); // exagerrage height of bars for identification - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), - histogramPrimitives->getBarsPrimitive(), - m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - primitiveIndex, - primitiveDepth); - glPopMatrix(); - std::cout << "Histogram selection: " << primitiveIndex << std::endl; + + if (drawBarsFlag) { + /* + * Scale histogram bars in Y-axis so that identification + * will function when mouse is above a bar. This is helpful + * for identification of bars with a very small height. + */ + glPushMatrix(); + glScalef(1.0, 1000.0, 1.0); + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + histogramPrimitives->getBarsPrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + glPopMatrix(); + } + else if (drawEnvelopeFlag) { + /* + * Increase line width for identification + */ + glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + histogramPrimitives->getEnvelopePrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + } + if (primitiveIndex >= 0) { if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), @@ -580,8 +602,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { + glLineWidth(ENVELOPE_LINE_WIDTH); m_fixedPipelineDrawing->enableLineAntiAliasing(); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); + m_fixedPipelineDrawing->disableLineAntiAliasing(); } } } diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index a993b23e8..2d5809fed 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -571,11 +571,18 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m true); // ignore thresholding - const int32_t estimatedNumberOfVertices = (numBucketValues * 4); // four vertices per quad + const int32_t estimatedNumberOfVerticesForQuads = (numBucketValues * 4); // four vertices per quad + const int32_t estimatedNumberOfVerticesForEnvelope = (numBucketValues * 2) + 4; // 2 vertices per line segment plus start/end + /* + * Use Quads when drawing bars (four vertices quad). + * Use Lines when drawing envelope (two vertices per line) + * Using quads and lines simplifies identification of individual bars in the histogram + */ GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); - barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVertices); - GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_STRIP); + barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES); + envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; bool setThresholdingFlag = false; @@ -719,20 +726,40 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m const float envelopeX = x + halfBucketWidth; if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); } - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + else { + const float xPrevious = envelopeX - bucketWidth; + CaretAssertVectorIndex(histogramBuckets, i - 1); + const float yPrevious = histogramBuckets[i - 1]; + + envelopePrimitive->addVertex(xPrevious, yPrevious, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + } } } else { const float envelopeX = x + halfBucketWidth; if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, rgba); + envelopePrimitive->addVertex(envelopeX, yMax, rgba); } - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMin, rgba); + else { + const float xPrevious = envelopeX - bucketWidth; + CaretAssertVectorIndex(histogramBuckets, i - 1); + const float yPrevious = histogramBuckets[i - 1]; + CaretAssertVectorIndex(histogramRGBA, (i - 1) * 4 + 3); + + envelopePrimitive->addVertex(xPrevious, yPrevious, &histogramRGBA[(i - 1) * 4]); + envelopePrimitive->addVertex(envelopeX, yMax, rgba); + + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMax, rgba); + envelopePrimitive->addVertex(envelopeX, yMin, rgba); + } } } @@ -743,7 +770,6 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m barsPrimitive, envelopePrimitive); - std::cout << "Created new histograms" << std::endl; m_mapHistogramBarsPrimitive.insert(std::make_pair(mapIndex, std::unique_ptr(histogramPrimitives))); diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index 131df6542..b13a28161 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -61,23 +61,31 @@ GraphicsPrimitiveSelectionHelper::~GraphicsPrimitiveSelectionHelper() void GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() { + int32_t numberOfVertices = 0; + + switch (m_parentGraphicsPrimitive->getVertexType()) { + case GraphicsPrimitive::VertexType::FLOAT_XYZ: + numberOfVertices = m_parentGraphicsPrimitive->getFloatXYZ().size() / 3; + break; + } + m_numberOfVerticesPerPrimitive = 0; switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::LINE_LOOP: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::LINE_STRIP: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::LINES: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::POINTS: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = 1; break; case GraphicsPrimitive::PrimitiveType::POLYGON: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: CaretAssertMessage(0, "Not yet implemented"); @@ -92,17 +100,10 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() CaretAssertMessage(0, "Not yet implemented"); break; case GraphicsPrimitive::PrimitiveType::TRIANGLES: - CaretAssertMessage(0, "Not yet implemented"); + m_numberOfVerticesPerPrimitive = 3; break; } - int32_t numberOfVertices = 0; - - switch (m_parentGraphicsPrimitive->getVertexType()) { - case GraphicsPrimitive::VertexType::FLOAT_XYZ: - numberOfVertices = m_parentGraphicsPrimitive->getFloatXYZ().size() / 3; - break; - } if (numberOfVertices > 0) { const int32_t numberOfPrimitives = numberOfVertices / m_numberOfVerticesPerPrimitive; const int32_t maxPrimitivesSupported = 255 * 255 * 255; -- GitLab From 97abde04644781b0608e39bcff3b02a031974b14 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 9 May 2017 14:24:38 -0500 Subject: [PATCH 266/755] Cleaned up code and removed several histogram classes that were no longer needed. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 80 +- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 +- src/Brain/IdentificationTextGenerator.cxx | 35 - src/Charting/CMakeLists.txt | 2 - src/Charting/ChartTwoCartesianAxis.h | 1 - src/Charting/ChartTwoDataHistogram.cxx | 197 ----- src/Charting/ChartTwoDataHistogram.h | 77 -- src/Common/CMakeLists.txt | 2 - src/Common/Histogram.cxx | 11 + src/Common/Histogram.h | 13 + src/Common/HistogramDrawingInfo.cxx | 223 ----- src/Common/HistogramDrawingInfo.h | 105 --- src/Files/CaretMappableDataFile.cxx | 782 ------------------ src/Files/CaretMappableDataFile.h | 7 - src/Files/ChartableTwoFileHistogramChart.cxx | 719 ++++++---------- src/Files/ChartableTwoFileHistogramChart.h | 10 - 16 files changed, 316 insertions(+), 1953 deletions(-) delete mode 100644 src/Charting/ChartTwoDataHistogram.cxx delete mode 100644 src/Charting/ChartTwoDataHistogram.h delete mode 100644 src/Common/HistogramDrawingInfo.cxx delete mode 100644 src/Common/HistogramDrawingInfo.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index a03bc7489..8574714b6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -48,7 +48,6 @@ #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" -#include "HistogramDrawingInfo.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "ModelChartTwo.h" @@ -317,46 +316,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() if (histogramChart->isValid()) { CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); AString errorMessage; - HistogramDrawingInfo* histogramDrawingInfo = new HistogramDrawingInfo(); - if (mapFile->getMapHistogramDrawingInfo(selectedIndex, - chartOverlay->isAllMapsSelected(), - false, - *histogramDrawingInfo, - errorMessage)) { - drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramDrawingInfo, - histogramChart, - selectedIndex, - chartOverlay->getCartesianVerticalAxisLocation(), - (chartOverlay->isAllMapsSupported() - && chartOverlay->isAllMapsSelected())))); + drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, + selectedIndex, + chartOverlay->getCartesianVerticalAxisLocation(), + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())))); + const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())); + CaretAssert(histogram); + float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; + histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); + if (histogramMaxX > histogramMinX) { + xMin = std::min(xMin, histogramMinX); + xMax = std::max(xMax, histogramMaxX); - float bounds[4]; - if (histogramDrawingInfo->getBounds(bounds)) { - xMin = std::min(xMin, bounds[0]); - xMax = std::max(xMax, bounds[1]); - - switch (chartOverlay->getCartesianVerticalAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - yMinRight = std::min(yMinRight, bounds[2]); - yMaxRight = std::max(yMaxRight, bounds[3]); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - yMinLeft = std::min(yMinLeft, bounds[2]); - yMaxLeft = std::max(yMaxLeft, bounds[3]); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); - break; - } + switch (chartOverlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yMinRight = std::min(yMinRight, 0.0f); + yMaxRight = std::max(yMaxRight, histogramMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + yMinLeft = std::min(yMinLeft, 0.0f); + yMaxLeft = std::max(yMaxLeft, histogramMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); + break; } } - else { - delete histogramDrawingInfo; - CaretLogWarning(errorMessage + mapFile->getFileName()); - } } } @@ -489,7 +480,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * so the envelopes are not obscured by the bars */ for (auto& drawInfo : drawingInfo) { - if (drawInfo->m_histogramDrawingInfo->isValid()) { + if (drawInfo->m_histogramChart->isValid()) { const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); CaretAssert(cmdf); const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); @@ -1629,8 +1620,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* /** * Constructor. * - * @param histogramDrawingInfo - * Drawing information for histogram * @param histogramChart * The file's histogram charting * @param mapIndex @@ -1640,12 +1629,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* * @param allMapsSelected * True if ALL MAPS selected for histogram, else false. */ -BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - ChartableTwoFileHistogramChart* histogramChart, +BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, ChartAxisLocationEnum::Enum verticalAxisLocation, const bool allMapsSelected) -: m_histogramDrawingInfo(histogramDrawingInfo), +: m_histogramChart(histogramChart), m_mapIndex(mapIndex), m_verticalAxisLocation(verticalAxisLocation), @@ -1656,6 +1644,6 @@ m_allMapsSelected(allMapsSelected) /** * Destructor. */ -BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() { - delete m_histogramDrawingInfo; +BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() +{ } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index be7953dfc..f56c3dd2d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -36,7 +36,6 @@ namespace caret { class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class GraphicsPrimitive; - class HistogramDrawingInfo; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; @@ -60,13 +59,11 @@ namespace caret { private: class HistogramChartDrawingInfo { public: - HistogramChartDrawingInfo(HistogramDrawingInfo* histogramDrawingInfo, - ChartableTwoFileHistogramChart* histogramChart, + HistogramChartDrawingInfo(ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, ChartAxisLocationEnum::Enum verticalAxisLocation, const bool allMapsSelected); - HistogramDrawingInfo* m_histogramDrawingInfo; ChartableTwoFileHistogramChart* m_histogramChart; int32_t m_mapIndex; ChartAxisLocationEnum::Enum m_verticalAxisLocation; diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 8b03d5142..441069c6e 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -840,41 +840,6 @@ IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(Identif (AString::number(bucketHeightInteger))); } } - - -// HistogramDrawingInfo histogramDrawingInfo; -// AString errorMessage; -// if (mapFile->getMapHistogramDrawingInfo(mapIndex, -// allMapsFlag, -// false, -// histogramDrawingInfo, -// errorMessage)) { -// if (histogramDrawingInfo.isValid()) { -// -// float bucketValue = 0.0; -// float bucketHeight = 0.0; -// if (histogramDrawingInfo.getBucketDataValueAndCount(bucketIndex, -// bucketValue, -// bucketHeight)) { -// -// AString boldText("OLD Histogram"); -// idText.addLine(false, -// boldText, -// mapFile->getFileNameNoPath()); -// idText.addLine(true, -// "Bucket Index", -// (AString::number(bucketIndex))); -// idText.addLine(true, -// "Data Value at Bucket", -// (AString::number(bucketValue))); -// -// const int64_t bucketHeightInteger = static_cast(bucketHeight); -// idText.addLine(true, -// "Bucket Count", -// (AString::number(bucketHeightInteger))); -// } -// } -// } } } diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 3989fa70a..aebdf2d0b 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -44,7 +44,6 @@ ChartTwoCompoundDataType.h ChartTwoData.h ChartTwoDataCartesian.h ChartTwoDataCartesianHistory.h -ChartTwoDataHistogram.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h @@ -82,7 +81,6 @@ ChartTwoCompoundDataType.cxx ChartTwoData.cxx ChartTwoDataCartesian.cxx ChartTwoDataCartesianHistory.cxx -ChartTwoDataHistogram.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index eef502e9d..3fe5364ea 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -27,7 +27,6 @@ #include "ChartAxisLocationEnum.h" #include "ChartAxisUnitsEnum.h" #include "ChartTwoAxisScaleRangeModeEnum.h" -#include "HistogramDrawingInfo.h" #include "NumericFormatModeEnum.h" #include "SceneableInterface.h" diff --git a/src/Charting/ChartTwoDataHistogram.cxx b/src/Charting/ChartTwoDataHistogram.cxx deleted file mode 100644 index c2c3a87bd..000000000 --- a/src/Charting/ChartTwoDataHistogram.cxx +++ /dev/null @@ -1,197 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHART_TWO_DATA_HISTOGRAM_DECLARE__ -#include "ChartTwoDataHistogram.h" -#undef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ - -#include "CaretAssert.h" -#include "Histogram.h" -#include "SceneClass.h" -#include "SceneClassAssistant.h" - -using namespace caret; - - - -/** - * \class caret::ChartTwoDataHistogram - * \brief Chart histogram chart data. - * \ingroup Charting - */ - -/** - * Constructor. - */ -ChartTwoDataHistogram::ChartTwoDataHistogram() -: ChartTwoData(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM) -{ - initializeMembersChartTwoDataHistogram(); -} - -/** - * Destructor. - */ -ChartTwoDataHistogram::~ChartTwoDataHistogram() -{ - delete m_sceneAssistant; -} - -/** - * Initialize members of a new instance. - */ -void -ChartTwoDataHistogram::initializeMembersChartTwoDataHistogram() -{ - m_histogram = NULL; - - m_sceneAssistant = new SceneClassAssistant(); -} - -/** - * At times a copy of chart data will be needed BUT it must be - * the proper subclass so copy constructor and assignment operator - * will no function when this abstract, base class is used. Each - * subclass will override this method so that the returned class - * is of the proper type. - * - * @return Copy of this instance that is the actual subclass. - */ -ChartTwoData* -ChartTwoDataHistogram::clone() const -{ - ChartTwoDataHistogram* cloneCopy = new ChartTwoDataHistogram(*this); - return cloneCopy; -} - -/** - * Copy constructor. - * @param obj - * Object that is copied. - */ -ChartTwoDataHistogram::ChartTwoDataHistogram(const ChartTwoDataHistogram& obj) -: ChartTwoData(obj) -{ - initializeMembersChartTwoDataHistogram(); - this->copyHelperChartTwoDataHistogram(obj); -} - -/** - * Assignment operator. - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -ChartTwoDataHistogram& -ChartTwoDataHistogram::operator=(const ChartTwoDataHistogram& obj) -{ - if (this != &obj) { - ChartTwoData::operator=(obj); - this->copyHelperChartTwoDataHistogram(obj); - } - return *this; -} - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -ChartTwoDataHistogram::copyHelperChartTwoDataHistogram(const ChartTwoDataHistogram& obj) -{ - CaretAssert(0); - //m_histogram = obj.m_histogram; -} - -/** - * @return The actual histogram (may be NULL). - */ -const Histogram* -ChartTwoDataHistogram::getHistogram() const -{ - return m_histogram; -} - -/** - * Set the histogram for charting. - * - * @param histogram - * Updated histogram (may be NULL). - */ -void -ChartTwoDataHistogram::setHistogram(Histogram* histogram) -{ - m_histogram = histogram; -} - -/** - * Save subclass data to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass to which data members should be added. Will always - * be valid (non-NULL). - */ -void -ChartTwoDataHistogram::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) -{ - SceneClass* chartDataHistogram = new SceneClass("chartDataHistogram", - "ChartTwoDataHistogram", - 1); - - m_sceneAssistant->saveMembers(sceneAttributes, - chartDataHistogram); - - - sceneClass->addClass(chartDataHistogram); -} - -/** - * Restore file data from the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass for the instance of a class that implements - * this interface. Will NEVER be NULL. - */ -void -ChartTwoDataHistogram::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - const SceneClass* chartDataHistogram = sceneClass->getClass("chartDataCartesian"); - if (chartDataHistogram == NULL) { - return; - } - - m_sceneAssistant->restoreMembers(sceneAttributes, chartDataHistogram); -} - diff --git a/src/Charting/ChartTwoDataHistogram.h b/src/Charting/ChartTwoDataHistogram.h deleted file mode 100644 index d63433251..000000000 --- a/src/Charting/ChartTwoDataHistogram.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef __CHART_TWO_DATA_HISTOGRAM_H__ -#define __CHART_TWO_DATA_HISTOGRAM_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include "ChartAxisUnitsEnum.h" -#include "ChartTwoData.h" - -namespace caret { - - class ChartPoint; - class Histogram; - - class ChartTwoDataHistogram : public ChartTwoData { - - public: - ChartTwoDataHistogram(); - - virtual ~ChartTwoDataHistogram(); - - virtual ChartTwoData* clone() const; - - const Histogram* getHistogram() const; - - void setHistogram(Histogram* histogram); - - // ADD_NEW_METHODS_HERE - - protected: - virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); - - virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - - - private: - ChartTwoDataHistogram(const ChartTwoDataHistogram& obj); - - ChartTwoDataHistogram& operator=(const ChartTwoDataHistogram& obj); - - void copyHelperChartTwoDataHistogram(const ChartTwoDataHistogram& obj); - - void initializeMembersChartTwoDataHistogram(); - - Histogram* m_histogram; - - SceneClassAssistant* m_sceneAssistant; - - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __CHART_TWO_DATA_HISTOGRAM_DECLARE__ -#endif // __CHART_TWO_DATA_HISTOGRAM_DECLARE__ - -} // namespace -#endif //__CHART_TWO_DATA_HISTOGRAM_H__ diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index a5e79a362..93e28eda1 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -112,7 +112,6 @@ FileAdapter.h FileInformation.h FloatMatrix.h Histogram.h -HistogramDrawingInfo.h HtmlStringBuilder.h ImageCaptureMethodEnum.h Logger.h @@ -211,7 +210,6 @@ FileAdapter.cxx FileInformation.cxx FloatMatrix.cxx Histogram.cxx -HistogramDrawingInfo.cxx HtmlStringBuilder.cxx ImageCaptureMethodEnum.cxx Logger.cxx diff --git a/src/Common/Histogram.cxx b/src/Common/Histogram.cxx index 671f65dce..8f3887a38 100644 --- a/src/Common/Histogram.cxx +++ b/src/Common/Histogram.cxx @@ -73,6 +73,9 @@ void Histogram::reset() m_cumulative[i] = 0; m_display[i] = 0.0f; } + m_displayHeightMax = 0.0; + m_bucketMin = 0.0; + m_bucketMax = 0.0; } void Histogram::update(const int& numBuckets, const float* data, const int64_t& dataCount) @@ -170,9 +173,13 @@ void Histogram::update(const float* data, const int64_t& dataCount) ++m_buckets[bucket]; } computeCumulative(); + m_displayHeightMax = 0.0; for (int i = 0; i < numBuckets; ++i) {//compute display values by normalizing by bucket size m_display[i] = m_buckets[i] / bucketsize; + if (m_display[i] > m_displayHeightMax) { + m_displayHeightMax = m_display[i]; + } } } @@ -309,9 +316,13 @@ void Histogram::update(const float* data, const int64_t& dataCount, float mostPo ++m_buckets[bucket]; } computeCumulative(); + m_displayHeightMax = 0.0; for (int i = 0; i < numBuckets; ++i) {//compute display values by normalizing by bucket size m_display[i] = m_buckets[i] / bucketsize; + if (m_display[i] > m_displayHeightMax) { + m_displayHeightMax = m_display[i]; + } } } diff --git a/src/Common/Histogram.h b/src/Common/Histogram.h index 203ba8d6a..51b2d46ae 100644 --- a/src/Common/Histogram.h +++ b/src/Common/Histogram.h @@ -32,6 +32,8 @@ namespace caret std::vector m_buckets, m_cumulative; std::vector m_display; float m_bucketMin, m_bucketMax; + float m_displayHeightMax; + ///counts of each class of number int64_t m_posCount, m_zeroCount, m_negCount, m_infCount, m_negInfCount, m_nanCount; @@ -93,6 +95,17 @@ namespace caret nanCount = m_nanCount; } + /** + * Get the low edge of the low bucket (x-min), and the high edge of the high bucket (x-max) + * and the maximum display height (y-max). Low Y is always zero. + */ + void getRangeAndMaxDisplayHeight(float& histMin, float& histMax, float& displayHeightMax) const + { + histMin = m_bucketMin; + histMax = m_bucketMax; + displayHeightMax = m_displayHeightMax; + } + ///returns the low edge of the low bucket, and the high edge of the high bucket void getRange(float& histMin, float& histMax) const { diff --git a/src/Common/HistogramDrawingInfo.cxx b/src/Common/HistogramDrawingInfo.cxx deleted file mode 100644 index 7f09dd24a..000000000 --- a/src/Common/HistogramDrawingInfo.cxx +++ /dev/null @@ -1,223 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __HISTOGRAM_DRAWING_INFO_DECLARE__ -#include "HistogramDrawingInfo.h" -#undef __HISTOGRAM_DRAWING_INFO_DECLARE__ - -#include - -#include "CaretAssert.h" -using namespace caret; - - - -/** - * \class caret::HistogramDrawingInfo - * \brief Contains data and metadata for drawing a histogram - * \ingroup Common - */ - -/** - * Constructor creates invalid instance. - */ -HistogramDrawingInfo::HistogramDrawingInfo() -: CaretObject() -{ - reset(); -} - -/** - * Destructor. - */ -HistogramDrawingInfo::~HistogramDrawingInfo() -{ -} - -/** - * Initialize for the given number of data points. - * - * @param numberOfDataPoints - * Number of data points for the histogram. - */ -void -HistogramDrawingInfo::initialize(const int32_t numberOfDataPoints) -{ - CaretAssert(numberOfDataPoints > 0); - m_dataX.resize(numberOfDataPoints, 0.0); - m_dataY.resize(numberOfDataPoints, 0.0); - m_dataRGBA.resize(numberOfDataPoints * 4, 0.0); -} - -/** - * Reset the histogram drawing information. - */ -void -HistogramDrawingInfo::reset() -{ - m_dataX.clear(); - m_dataY.clear(); - m_dataRGBA.clear(); - m_boundsValid = false; - m_thresholdOneBoundsXYZ.clear(); - m_thresholdTwoBoundsXYZ.clear(); - m_thresholdOneBoundsValid = false; - m_thresholdOneBoundsValid = false; -} - - -/** - * @return Is the histogram drawing information valid? - */ -bool -HistogramDrawingInfo::isValid() const -{ - if ( ! m_dataX.empty()) { - CaretAssert(m_dataX.size() == m_dataY.size()); - CaretAssert((m_dataX.size() * 4) == m_dataRGBA.size()); - if ((m_dataX.size() == m_dataY.size()) - && (m_dataX.size() * 4) == m_dataRGBA.size()) { - return true; - } - } - - return false; -} - -/** - * Get the bounds for the data. - * - * @param boundsOut - * Output with bounds (minX, maxX, minY, maxY) - * @return - * True if bounds valid, else false. - */ -bool -HistogramDrawingInfo::getBounds(float boundsOut[4]) const -{ - - if ( ! m_boundsValid) { - if (isValid()) { - m_bounds[0] = *std::min_element(m_dataX.begin(), m_dataX.end()); - m_bounds[1] = *std::max_element(m_dataX.begin(), m_dataX.end()); - m_bounds[2] = *std::min_element(m_dataY.begin(), m_dataY.end()); - m_bounds[3] = *std::max_element(m_dataY.begin(), m_dataY.end()); - m_boundsValid = true; - } - } - - boundsOut[0] = m_bounds[0]; - boundsOut[1] = m_bounds[1]; - boundsOut[2] = m_bounds[2]; - boundsOut[3] = m_bounds[3]; - - return m_boundsValid; -} - -///** -// * Get the bounds for the threshold one. -// * -// * @param boundsOut -// * Output with bounds (minX, maxX, minY, maxY) -// * @return -// * True if bounds valid, else false. -// */ -//const -//HistogramDrawingInfo::getThresholdOneBounds(float boundsOut[4]) const -//{ -// boundsOut[0] = m_thresholdOneBounds[0]; -// boundsOut[1] = m_thresholdOneBounds[1]; -// boundsOut[2] = m_thresholdOneBounds[2]; -// boundsOut[3] = m_thresholdOneBounds[3]; -// -// return m_thresholdOneBoundsValid; -//} - -///** -// * Get the bounds for threshold two. -// * -// * @param boundsOut -// * Output with bounds (minX, maxX, minY, maxY) -// * @return -// * True if bounds valid, else false. -// */ -//bool -//HistogramDrawingInfo::getThresholdTwoBounds(float boundsOut[4]) const -//{ -// boundsOut[0] = m_thresholdTwoBounds[0]; -// boundsOut[1] = m_thresholdTwoBounds[1]; -// boundsOut[2] = m_thresholdTwoBounds[2]; -// boundsOut[3] = m_thresholdTwoBounds[3]; -// -// return m_thresholdTwoBoundsValid; -//} - -/** - * @return Number of data points in the histogram. - */ -int32_t -HistogramDrawingInfo::getNumberOfDataPoints() const -{ - CaretAssert(m_dataX.size() == m_dataY.size()); - CaretAssert((m_dataX.size() * 4) == m_dataRGBA.size()); - - return m_dataX.size(); -} - -/** - * Get the bucket value (x-axis) and bucket display value (y-axis) - * for the given bucket index. - * - * @param bucketIndex - * Index of the bucket. - * @param bucketValueOut - * Output with bucket value (x-axis) - * @param bucketHeightOut - * Output with bucket height (y-axis) - * @return - * True if output values are valid, else false. - */ -bool -HistogramDrawingInfo::getBucketDataValueAndCount(const int32_t bucketIndex, - float& bucketValueOut, - float& bucketDisplayValueOut) const -{ - if ((bucketIndex >= 0) - && (bucketIndex < static_cast(m_dataX.size()))) { - bucketValueOut = m_dataX[bucketIndex]; - CaretAssert(m_dataX.size() == m_dataY.size()); - bucketDisplayValueOut = m_dataY[bucketIndex]; - return true; - } - - return false; -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -HistogramDrawingInfo::toString() const -{ - return "HistogramDrawingInfo"; -} - diff --git a/src/Common/HistogramDrawingInfo.h b/src/Common/HistogramDrawingInfo.h deleted file mode 100644 index accbe5bca..000000000 --- a/src/Common/HistogramDrawingInfo.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef __HISTOGRAM_DRAWING_INFO_H__ -#define __HISTOGRAM_DRAWING_INFO_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include "CaretObject.h" - - - -namespace caret { - - class HistogramDrawingInfo : public CaretObject { - - public: - HistogramDrawingInfo(); - - virtual ~HistogramDrawingInfo(); - - void initialize(const int32_t numberOfDataPoints); - - void reset(); - - bool getBounds(float boundsOut[4]) const; - - int32_t getNumberOfDataPoints() const; - - bool isValid() const; - - /** @return X-coordinates of histogram bars */ - const std::vector& getDataX() const { return m_dataX; } - - /** @return Y-coordinates of histogram bars */ - const std::vector& getDataY() const { return m_dataY; } - - /** @return RGBA data for histogram bars */ - const std::vector& getDataRGBA() const { return m_dataRGBA; } - - /** @return XYZ coordinates for threshold one bounds, may be empty ! */ - const std::vector& getThresholdOneBounds() const { return m_thresholdOneBoundsXYZ; } - - /** @return XYZ coordinates for threshold two bounds, may be empty ! */ - const std::vector& getThresholdTwoBounds() const { return m_thresholdTwoBoundsXYZ; } - - bool getBucketDataValueAndCount(const int32_t bucketIndex, - float& bucketValueOut, - float& bucketDisplayValueOut) const; - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - private: - HistogramDrawingInfo(const HistogramDrawingInfo& obj); - - HistogramDrawingInfo& operator=(const HistogramDrawingInfo&); - - - mutable float m_bounds[4]; - - mutable bool m_boundsValid = false; - - std::vector m_dataX; - - std::vector m_dataY; - - std::vector m_dataRGBA; - - std::vector m_thresholdOneBoundsXYZ; - - bool m_thresholdOneBoundsValid = false; - - std::vector m_thresholdTwoBoundsXYZ; - - bool m_thresholdTwoBoundsValid = false; - - // ADD_NEW_MEMBERS_HERE - - friend class CaretMappableDataFile; - }; - -#ifdef __HISTOGRAM_DRAWING_INFO_DECLARE__ - // -#endif // __HISTOGRAM_DRAWING_INFO_DECLARE__ - -} // namespace -#endif //__HISTOGRAM_DRAWING_INFO_H__ diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 11b40ab97..928b71e00 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -39,7 +39,6 @@ #include "GiftiLabelTable.h" #include "GiftiMetaDataXmlElements.h" #include "Histogram.h" -#include "HistogramDrawingInfo.h" #include "LabelDrawingProperties.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" @@ -817,787 +816,6 @@ CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformatio } } -/** - * Get the histogram bounds, heights, and RGBA coloring. - * - * @param mapIndex - * Index of map. - * @param useDataFromAllMapsFlag - * If true, data from ALL maps is used not just the map specified by map index. - * @param addEndPointForQwtFlag - * If true, add point at end for drawing with Qwt. - * @param histogramDrawingInfoOut - * Output containing histogram drawing information. - * @return - * True if output data is valid, else false. - */ -bool -CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, - const bool useDataFromAllMapsFlag, - const bool addEndPointForQwtFlag, - HistogramDrawingInfo& histogramDrawingInfoOut, - AString& errorMessageOut) -{ - errorMessageOut.clear(); - histogramDrawingInfoOut.reset(); - - if ( ! isMappedWithPalette()) { - errorMessageOut = "File is not mapped with palette!"; - return false; - } - if ((mapIndex < 0) - || (mapIndex >= getNumberOfMaps())) { - CaretAssertMessage(0, "Invalid map index."); - errorMessageOut = "Invalid map index."; - return false; - } - - PaletteColorMapping* paletteColorMapping = getMapPaletteColorMapping(mapIndex); - CaretAssert(paletteColorMapping); - - EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); - EventManager::get()->sendEvent(paletteEvent.getPointer()); - const Palette* palette = paletteEvent.getPalette(); - if (palette == NULL) { - errorMessageOut = ("Unable to find palette named: " - + paletteColorMapping->getSelectedPaletteName()); - return false; - } - - FastStatistics* statistics = NULL; - if (useDataFromAllMapsFlag) { - statistics = const_cast(getFileFastStatistics()); - } - else { - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(getFileFastStatistics()); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(getMapFastStatistics(mapIndex)); - break; - } - } - - /* - * Statistics may be NULL for connectivity files (dense, dense dynamic) - * that have not yet loaded any data caused by the user clicking - * brainordinates. - */ - if (statistics == NULL) { - return false; - } - - CaretAssert(statistics); - float mostPos = 0.0; - float leastPos = 0.0; - float leastNeg = 0.0; - float mostNeg = 0.0; - bool matchFlag = false; - - switch (paletteColorMapping->getHistogramRangeMode()) { - case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: - { - float dummy; - statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); - } - break; - case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: - { - matchFlag = true; - switch (paletteColorMapping->getScaleMode()) { - case PaletteScaleModeEnum::MODE_AUTO_SCALE: - mostPos = statistics->getMax(); - leastPos = 0.0; - leastNeg = 0.0; - mostNeg = statistics->getMin(); - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: - mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); - leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); - leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); - mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: - mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); - leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); - leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); - mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); - break; - case PaletteScaleModeEnum::MODE_USER_SCALE: - mostPos = paletteColorMapping->getUserScalePositiveMaximum(); - leastPos = paletteColorMapping->getUserScalePositiveMinimum(); - leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); - mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); - break; - } - } - break; - } - - /* - * Remove data that is not displayed - */ - bool isZeroIncluded = true; - const Histogram* histogram = NULL; - if (matchFlag) { - isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); - - if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { - mostNeg = 0.0; - leastNeg = 0.0; - } - if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { - mostPos = 0.0; - leastPos = 0.0; - } - - if (useDataFromAllMapsFlag) { - histogram = getFileHistogram(mostPos, - leastPos, - leastNeg, - mostNeg, - isZeroIncluded); - } - else { - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - histogram = getFileHistogram(mostPos, - leastPos, - leastNeg, - mostNeg, - isZeroIncluded); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - histogram = getMapHistogram(mapIndex, - mostPos, - leastPos, - leastNeg, - mostNeg, - isZeroIncluded); - break; - } - } - } - else { - if (useDataFromAllMapsFlag) { - histogram = getFileHistogram(); - } - else { - switch (getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - histogram = getFileHistogram(); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - histogram = getMapHistogram(mapIndex); - break; - } - } - } - - CaretAssert(histogram); - - - float minValueX = 0.0; - float maxValueX = 0.0; - histogram->getRange(minValueX, - maxValueX); - const float valueRangeX = maxValueX - minValueX; - if (valueRangeX <= 0.0) { - errorMessageOut = "Range of histogram X-values is zero"; - return false; - } - - if ((paletteColorMapping != NULL) - && (statistics != NULL) - && (palette != NULL) - && (histogram != NULL)) { - std::vector histogramBuckets = histogram->getHistogramDisplay(); - const int32_t numBucketValues = static_cast(histogramBuckets.size()); - if (numBucketValues < 2) { - errorMessageOut = "Histogram must contain two or more values"; - return false; - } - - int32_t numberOfDataPoints = (addEndPointForQwtFlag - ? (numBucketValues + 1) - : numBucketValues); - - /* - * Set up vectors for X/Y values and coloring - */ - histogramDrawingInfoOut.initialize(numberOfDataPoints); - - const float stepX = (valueRangeX - / static_cast(numBucketValues)); - for (int64_t ix = 0; ix < numBucketValues; ix++) { - float valueX = (minValueX - + (ix * stepX)); - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); - histogramDrawingInfoOut.m_dataX[ix] = valueX; - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, ix); - CaretAssertVectorIndex(histogramBuckets, ix); - histogramDrawingInfoOut.m_dataY[ix] = histogramBuckets[ix]; - } - if (addEndPointForQwtFlag) { - /* - * Duplicate last point for Qwt or else Qwt may not draw correctly - */ - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, numBucketValues); - histogramDrawingInfoOut.m_dataX[numBucketValues] = histogramDrawingInfoOut.m_dataX[numBucketValues - 1]; - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, numBucketValues); - histogramDrawingInfoOut.m_dataY[numBucketValues] = histogramDrawingInfoOut.m_dataY[numBucketValues - 1]; - } - - /* - * Adjust X-value of first and last points - */ - histogramDrawingInfoOut.m_dataX[0] = minValueX; - histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValueX; - - - /* - * Always color using palette and it will assign a zero alpha - * value to buckets that do not fall in the palette negative - * postive min/max ranges. - */ - const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; - float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - xValuesArray, - xValuesArray, - numberOfDataPoints, - dataRGBA, - true); // ignore thresholding - - /* - * If bucket is not colored (zero alpha) set bucket height to zero - */ - for (int32_t i = 0; i < numberOfDataPoints; i++) { - const int32_t alphaIndex = i * 4 + 3; - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, alphaIndex); - if (histogramDrawingInfoOut.m_dataRGBA[alphaIndex] <= 0.0) { - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, i); - histogramDrawingInfoOut.m_dataY[i] = 0.0; - } - } - - /* - * If selected, apply solid color to histogram - */ - const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramBarsColor(); - if (histogramColor != CaretColorEnum::CUSTOM) { - float rgba[4]; - CaretColorEnum::toRGBAFloat(histogramColor, rgba); - - /* - * Note: DO NOT override alpha value that was set - * using palette coloring - */ - for (int32_t i = 0; i < numberOfDataPoints; i++) { - const int32_t i4 = i * 4; - CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, i4 + 3); - histogramDrawingInfoOut.m_dataRGBA[i4] = rgba[0]; - histogramDrawingInfoOut.m_dataRGBA[i4+1] = rgba[1]; - histogramDrawingInfoOut.m_dataRGBA[i4+2] = rgba[2]; - } - } - - bool setThresholdingFlag = false; - switch (paletteColorMapping->getThresholdType()) { - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: - setThresholdingFlag = true; - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: - break; - } - - if (setThresholdingFlag) { - float bounds[4]; - if (histogramDrawingInfoOut.getBounds(bounds)) { - const float minX = bounds[0]; - const float maxX = bounds[1]; - const float minY = bounds[2]; - const float maxY = bounds[3]; - - float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); - float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); - switch (paletteColorMapping->getThresholdTest()) { - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: - { - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = minX; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMinValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMinValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = minX; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; - - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ.resize(12); - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[0] = threshMaxValue; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[1] = minY; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[2] = 0.0; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[3] = maxX; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[4] = minY; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[5] = 0.0; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[6] = maxX; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[7] = maxY; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[8] = 0.0; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[9] = threshMaxValue; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[10] = maxY; - histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[11] = 0.0; - } - break; - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: - { - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = threshMinValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMaxValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMaxValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = threshMinValue; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; - histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; - } - break; - } - - switch (paletteColorMapping->getThresholdRangeMode()) { - case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE: - break; - case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP: - break; - case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED: - break; - } - } - } - - CaretAssert(histogramDrawingInfoOut.isValid()); - return histogramDrawingInfoOut.isValid(); - } - - return false; -} - -///** -// * Get the histogram bounds, heights, and RGBA coloring. -// * -// * @param mapIndex -// * Index of map. -// * @param useDataFromAllMapsFlag -// * If true, data from ALL maps is used not just the map specified by map index. -// * @param addEndPointForQwtFlag -// * If true, add point at end for drawing with Qwt. -// * @param histogramDrawingInfoOut -// * Output containing histogram drawing information. -// * @return -// * True if output data is valid, else false. -// */ -//bool -//CaretMappableDataFile::getMapHistogramDrawingInfo(const int32_t mapIndex, -// const bool useDataFromAllMapsFlag, -// const bool addEndPointForQwtFlag, -// HistogramDrawingInfo& histogramDrawingInfoOut, -// AString& errorMessageOut) -//{ -// errorMessageOut.clear(); -// histogramDrawingInfoOut.reset(); -// -// if ( ! isMappedWithPalette()) { -// errorMessageOut = "File is not mapped with palette!"; -// return false; -// } -// if ((mapIndex < 0) -// || (mapIndex >= getNumberOfMaps())) { -// CaretAssertMessage(0, "Invalid map index."); -// errorMessageOut = "Invalid map index."; -// return false; -// } -// -// PaletteColorMapping* paletteColorMapping = getMapPaletteColorMapping(mapIndex); -// CaretAssert(paletteColorMapping); -// -// EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); -// EventManager::get()->sendEvent(paletteEvent.getPointer()); -// const Palette* palette = paletteEvent.getPalette(); -// if (palette == NULL) { -// errorMessageOut = ("Unable to find palette named: " -// + paletteColorMapping->getSelectedPaletteName()); -// return false; -// } -// -// FastStatistics* statistics = NULL; -// if (useDataFromAllMapsFlag) { -// statistics = const_cast(getFileFastStatistics()); -// } -// else { -// switch (getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// statistics = const_cast(getFileFastStatistics()); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// statistics = const_cast(getMapFastStatistics(mapIndex)); -// break; -// } -// } -// -// /* -// * Statistics may be NULL for connectivity files (dense, dense dynamic) -// * that have not yet loaded any data caused by the user clicking -// * brainordinates. -// */ -// if (statistics == NULL) { -// return false; -// } -// -// CaretAssert(statistics); -// float mostPos = 0.0; -// float leastPos = 0.0; -// float leastNeg = 0.0; -// float mostNeg = 0.0; -// bool matchFlag = false; -// -// switch (paletteColorMapping->getHistogramRangeMode()) { -// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: -// { -// float dummy; -// statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); -// } -// break; -// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: -// { -// matchFlag = true; -// switch (paletteColorMapping->getScaleMode()) { -// case PaletteScaleModeEnum::MODE_AUTO_SCALE: -// mostPos = statistics->getMax(); -// leastPos = 0.0; -// leastNeg = 0.0; -// mostNeg = statistics->getMin(); -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: -// mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); -// leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); -// leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); -// mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: -// mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); -// leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); -// leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); -// mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); -// break; -// case PaletteScaleModeEnum::MODE_USER_SCALE: -// mostPos = paletteColorMapping->getUserScalePositiveMaximum(); -// leastPos = paletteColorMapping->getUserScalePositiveMinimum(); -// leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); -// mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); -// break; -// } -// } -// break; -// } -// -// /* -// * Remove data that is not displayed -// */ -// bool isZeroIncluded = true; -// const Histogram* histogram = NULL; -// if (matchFlag) { -// isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); -// -// if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { -// mostNeg = 0.0; -// leastNeg = 0.0; -// } -// if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { -// mostPos = 0.0; -// leastPos = 0.0; -// } -// -// if (useDataFromAllMapsFlag) { -// histogram = getFileHistogram(mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// } -// else { -// switch (getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// histogram = getFileHistogram(mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// histogram = getMapHistogram(mapIndex, -// mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// break; -// } -// } -// } -// else { -// if (useDataFromAllMapsFlag) { -// histogram = getFileHistogram(); -// } -// else { -// switch (getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// histogram = getFileHistogram(); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// histogram = getMapHistogram(mapIndex); -// break; -// } -// } -// } -// -// CaretAssert(histogram); -// -// -// float minValueX = 0.0; -// float maxValueX = 0.0; -// histogram->getRange(minValueX, -// maxValueX); -// const float valueRangeX = maxValueX - minValueX; -// if (valueRangeX <= 0.0) { -// errorMessageOut = "Range of histogram X-values is zero"; -// return false; -// } -// -// if ((paletteColorMapping != NULL) -// && (statistics != NULL) -// && (palette != NULL) -// && (histogram != NULL)) { -// std::vector histogramBuckets = histogram->getHistogramDisplay(); -// const int32_t numBucketValues = static_cast(histogramBuckets.size()); -// if (numBucketValues < 2) { -// errorMessageOut = "Histogram must contain two or more values"; -// return false; -// } -// -// int32_t numberOfDataPoints = (addEndPointForQwtFlag -// ? (numBucketValues + 1) -// : numBucketValues); -// -// histogramDrawingInfoOut.initialize(numberOfDataPoints); -// -// if (addEndPointForQwtFlag) { -// /* -// * Duplicate last point for Qwt or else Qwt may not draw correctly -// */ -// histogramBuckets.push_back(histogramBuckets[histogramBuckets.size() - 1]); -// } -// histogramDrawingInfoOut.m_dataY = histogramBuckets; -// -// const bool hideZerosFlag = ( ! paletteColorMapping->isDisplayZeroDataFlag()); -// const float stepX = ((valueRangeX) -// / static_cast(numberOfDataPoints)); -// -// /* -// * Need to find zero (or near zero if there is not an exact zero value) -// */ -// int32_t indexZeroX = -1; -// float indexZeroDistance = std::numeric_limits::max(); -// -// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { -// float valueX = (minValueX -// + (ix * stepX)); -// -// if (hideZerosFlag) { -// const float zeroDistance = ((valueX >= 0) ? valueX : -valueX); -// if (zeroDistance < indexZeroDistance) { -// indexZeroX = ix; -// indexZeroDistance = zeroDistance; -// } -// } -// -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); -// histogramDrawingInfoOut.m_dataX[ix] = valueX; -// } -// -// if (indexZeroX >= 0) { -// const float posZero = 0.05; -// const float negZero = -posZero; -// int32_t negZeroIndex = -1; -// -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, indexZeroX); -// const float xValue = histogramDrawingInfoOut.m_dataX[indexZeroX]; -// if (xValue <= 0.0) { -// negZeroIndex = indexZeroX; -// } -// else { -// negZeroIndex = indexZeroX - 1; -// } -// -// if ((negZeroIndex >= 0) -// && (negZeroIndex < (numberOfDataPoints - 1))) { -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, negZeroIndex + 1); -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataY, negZeroIndex + 1); -// histogramDrawingInfoOut.m_dataX[negZeroIndex] = negZero; -// histogramDrawingInfoOut.m_dataY[negZeroIndex] = 0.0; -// -// histogramDrawingInfoOut.m_dataX.insert(histogramDrawingInfoOut.m_dataX.begin() + negZeroIndex + 1, posZero); -// histogramDrawingInfoOut.m_dataY.insert(histogramDrawingInfoOut.m_dataY.begin() + negZeroIndex + 1, 0.0); -// } -// numberOfDataPoints = static_cast(histogramDrawingInfoOut.m_dataX.size()); -// CaretAssert(histogramDrawingInfoOut.m_dataX.size() == histogramDrawingInfoOut.m_dataY.size()); -// histogramDrawingInfoOut.m_dataRGBA.resize(numberOfDataPoints * 4); -// } -// -//// for (int64_t ix = 0; ix < numberOfDataPoints; ix++) { -//// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataX, ix); -//// std::cout << "value " << ix << ": " << histogramDrawingInfoOut.m_dataX[ix] << "," << histogramDrawingInfoOut.m_dataX[ix] << std::endl; -//// } -// -// histogramDrawingInfoOut.m_dataX[0] = minValueX; -// histogramDrawingInfoOut.m_dataX[numberOfDataPoints - 1] = maxValueX; -// -// const float* xValuesArray = &histogramDrawingInfoOut.m_dataX[0]; -// -// const CaretColorEnum::Enum histogramColor = paletteColorMapping->getHistogramColor(); -// if (histogramColor != CaretColorEnum::CUSTOM) { -// float rgba[4]; -// CaretColorEnum::toRGBAFloat(histogramColor, rgba); -// rgba[3] = 1.0; -// -// for (int32_t i = 0; i < numberOfDataPoints; i++) { -// const int32_t i4 = i * 4; -// CaretAssertVectorIndex(histogramDrawingInfoOut.m_dataRGBA, i4 + 3); -// histogramDrawingInfoOut.m_dataRGBA[i4] = rgba[0]; -// histogramDrawingInfoOut.m_dataRGBA[i4+1] = rgba[1]; -// histogramDrawingInfoOut.m_dataRGBA[i4+2] = rgba[2]; -// histogramDrawingInfoOut.m_dataRGBA[i4+3] = rgba[3]; -// } -// } -// else { -// float* dataRGBA = &histogramDrawingInfoOut.m_dataRGBA[0]; -// -// NodeAndVoxelColoring::colorScalarsWithPalette(statistics, -// paletteColorMapping, -// palette, -// xValuesArray, -// xValuesArray, -// numberOfDataPoints, -// dataRGBA, -// true); // ignore thresholding -// } -// -// bool setThresholdingFlag = false; -// switch (paletteColorMapping->getThresholdType()) { -// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: -// break; -// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: -// break; -// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: -// setThresholdingFlag = true; -// break; -// case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: -// break; -// } -// -// if (setThresholdingFlag) { -// float bounds[4]; -// if (histogramDrawingInfoOut.getBounds(bounds)) { -// const float minX = bounds[0]; -// const float maxX = bounds[1]; -// const float minY = bounds[2]; -// const float maxY = bounds[3]; -// -// float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); -// float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); -// switch (paletteColorMapping->getThresholdTest()) { -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: -// { -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = minX; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMinValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMinValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = minX; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; -// -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ.resize(12); -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[0] = threshMaxValue; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[1] = minY; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[2] = 0.0; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[3] = maxX; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[4] = minY; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[5] = 0.0; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[6] = maxX; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[7] = maxY; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[8] = 0.0; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[9] = threshMaxValue; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[10] = maxY; -// histogramDrawingInfoOut.m_thresholdTwoBoundsXYZ[11] = 0.0; -// } -// break; -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: -// { -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ.resize(12); -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[0] = threshMinValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[1] = minY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[2] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[3] = threshMaxValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[4] = minY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[5] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[6] = threshMaxValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[7] = maxY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[8] = 0.0; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[9] = threshMinValue; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[10] = maxY; -// histogramDrawingInfoOut.m_thresholdOneBoundsXYZ[11] = 0.0; -// } -// break; -// } -// -// switch (paletteColorMapping->getThresholdRangeMode()) { -// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE: -// break; -// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP: -// break; -// case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED: -// break; -// } -// } -// } -// -// CaretAssert(histogramDrawingInfoOut.isValid()); -// return histogramDrawingInfoOut.isValid(); -// } -// -// return false; -//} - /** * @return File histogram number of buckets. */ diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index e3601dd36..f0b33a974 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -38,7 +38,6 @@ namespace caret { class GiftiMetaData; class GiftiLabelTable; class Histogram; - class HistogramDrawingInfo; class LabelDrawingProperties; class PaletteColorMapping; class PaletteFile; @@ -273,12 +272,6 @@ namespace caret { */ virtual const FastStatistics* getFileFastStatistics() = 0; - bool getMapHistogramDrawingInfo(const int32_t mapIndex, - const bool useDataFromAllMapsFlag, - const bool addEndPointForQwtFlag, - HistogramDrawingInfo& histogramDrawingInfoOut, - AString& errorMessageOut); - /** * Get histogram describing the distribution of data * mapped with a color palette for all data within diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 2d5809fed..9c20819bf 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -130,7 +130,7 @@ void ChartableTwoFileHistogramChart::invalidateAllColoring() { m_mapHistogramBarsPrimitive.clear(); - std::cout << "Invalidating histograms..." << std::endl; + //std::cout << "Invalidating histograms..." << std::endl; } /** @@ -338,485 +338,286 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m return NULL; } -// if ( ! myMapFile->isMappedWithPalette()) { -// return histogramPrimitives; -// } -// if ((mapIndex < 0) -// || (mapIndex >= myMapFile->getNumberOfMaps())) { -// return histogramPrimitives; -// } -// -// PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); -// CaretAssert(paletteColorMapping); -// -// EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); -// EventManager::get()->sendEvent(paletteEvent.getPointer()); -// const Palette* palette = paletteEvent.getPalette(); -// if (palette == NULL) { -// CaretLogSevere("Unable to find palette named: " -// + paletteColorMapping->getSelectedPaletteName()); -// return histogramPrimitives; -// } -// -// FastStatistics* statistics = NULL; -// if (useDataFromAllMapsFlag) { -// statistics = const_cast(myMapFile->getFileFastStatistics()); -// } -// else { -// switch (myMapFile->getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// statistics = const_cast(myMapFile->getFileFastStatistics()); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); -// break; -// } -// } -// -// /* -// * Statistics may be NULL for connectivity files (dense, dense dynamic) -// * that have not yet loaded any data caused by the user clicking -// * brainordinates. -// */ -// if (statistics == NULL) { -// return histogramPrimitives; -// } -// -// MapIndexPrimitiveContainer::iterator iter = m_mapHistogramBarsPrimitive.find(mapIndex); -// if (iter != m_mapHistogramBarsPrimitive.end()) { -// histogramPrimitives = iter->second.get(); -// } -// -// if (histogramPrimitives == NULL) { -// CaretAssert(statistics); -// float mostPos = 0.0; -// float leastPos = 0.0; -// float leastNeg = 0.0; -// float mostNeg = 0.0; -// bool matchFlag = false; -// -// switch (paletteColorMapping->getHistogramRangeMode()) { -// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: -// { -// float dummy; -// statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); -// } -// break; -// case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: -// { -// matchFlag = true; -// switch (paletteColorMapping->getScaleMode()) { -// case PaletteScaleModeEnum::MODE_AUTO_SCALE: -// mostPos = statistics->getMax(); -// leastPos = 0.0; -// leastNeg = 0.0; -// mostNeg = statistics->getMin(); -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: -// mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); -// leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); -// leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); -// mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); -// break; -// case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: -// mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); -// leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); -// leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); -// mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); -// break; -// case PaletteScaleModeEnum::MODE_USER_SCALE: -// mostPos = paletteColorMapping->getUserScalePositiveMaximum(); -// leastPos = paletteColorMapping->getUserScalePositiveMinimum(); -// leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); -// mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); -// break; -// } -// } -// break; -// } -// -// /* -// * Remove data that is not displayed -// */ -// bool isZeroIncluded = true; -// const Histogram* histogram = NULL; -// if (matchFlag) { -// isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); -// -// if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { -// mostNeg = 0.0; -// leastNeg = 0.0; -// } -// if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { -// mostPos = 0.0; -// leastPos = 0.0; -// } -// -// if (useDataFromAllMapsFlag) { -// histogram = myMapFile->getFileHistogram(mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// } -// else { -// switch (myMapFile->getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// histogram = myMapFile->getFileHistogram(mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// histogram = myMapFile->getMapHistogram(mapIndex, -// mostPos, -// leastPos, -// leastNeg, -// mostNeg, -// isZeroIncluded); -// break; -// } -// } -// } -// else { -// if (useDataFromAllMapsFlag) { -// histogram = myMapFile->getFileHistogram(); -// } -// else { -// switch (myMapFile->getPaletteNormalizationMode()) { -// case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: -// histogram = myMapFile->getFileHistogram(); -// break; -// case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: -// histogram = myMapFile->getMapHistogram(mapIndex); -// break; -// } -// } -// } + CaretAssert(histogram); + + FastStatistics* statistics = NULL; + if (useDataFromAllMapsFlag) { + statistics = const_cast(myMapFile->getFileFastStatistics()); + } + else { + switch (myMapFile->getPaletteNormalizationMode()) { + case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: + statistics = const_cast(myMapFile->getFileFastStatistics()); + break; + case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: + statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); + break; + } + } + + PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); + CaretAssert(paletteColorMapping); + + EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); + EventManager::get()->sendEvent(paletteEvent.getPointer()); + const Palette* palette = paletteEvent.getPalette(); + if (palette == NULL) { + CaretLogSevere("Unable to find palette named: " + + paletteColorMapping->getSelectedPaletteName()); + return NULL; + } + + float minValueX = 0.0; + float maxValueX = 0.0; + histogram->getRange(minValueX, + maxValueX); + const float valueRangeX = maxValueX - minValueX; + if (valueRangeX <= 0.0) { + CaretLogSevere("Range of histogram X-values is zero"); + return NULL; + } - CaretAssert(histogram); + if ((paletteColorMapping != NULL) + && (statistics != NULL) + && (palette != NULL) + && (histogram != NULL)) { + std::vector histogramBuckets = histogram->getHistogramDisplay(); + const int32_t numBucketValues = static_cast(histogramBuckets.size()); + if (numBucketValues < 2) { + CaretLogSevere("Histogram must contain two or more values"); + return NULL; + } + + const float bucketWidth = valueRangeX / (numBucketValues - 1); + std::vector xValuesAtBuckets; + xValuesAtBuckets.reserve(numBucketValues); + for (int32_t i = 0; i < numBucketValues; i++) { + xValuesAtBuckets.push_back(minValueX + (bucketWidth * i)); + } + CaretAssert(xValuesAtBuckets.size() == histogramBuckets.size()); + + std::vector histogramRGBA; + histogramRGBA.resize(numBucketValues * 4, + 0.0f); + NodeAndVoxelColoring::colorScalarsWithPalette(statistics, + paletteColorMapping, + palette, + &xValuesAtBuckets[0], + &xValuesAtBuckets[0], + numBucketValues, + &histogramRGBA[0], + true); // ignore thresholding + + + const int32_t estimatedNumberOfVerticesForQuads = (numBucketValues * 4); // four vertices per quad + const int32_t estimatedNumberOfVerticesForEnvelope = (numBucketValues * 2) + 4; // 2 vertices per line segment plus start/end - /* CUT HERE */ /* - * Move this code to a function + * Use Quads when drawing bars (four vertices quad). + * Use Lines when drawing envelope (two vertices per line) + * Using quads and lines simplifies identification of individual bars in the histogram */ - { - FastStatistics* statistics = NULL; - if (useDataFromAllMapsFlag) { - statistics = const_cast(myMapFile->getFileFastStatistics()); - } - else { - switch (myMapFile->getPaletteNormalizationMode()) { - case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: - statistics = const_cast(myMapFile->getFileFastStatistics()); - break; - case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: - statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); - break; - } + GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES); + envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); + GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; + + bool setThresholdingFlag = false; + switch (paletteColorMapping->getThresholdType()) { + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: + setThresholdingFlag = true; + break; + case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: + break; + } + + if (setThresholdingFlag) { + /* + * RGBA for thresholding + */ + EventCaretPreferencesGet preferencesEvent; + EventManager::get()->sendEvent(preferencesEvent.getPointer()); + CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); + float threshRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; + if (caretPreferences != NULL) { + uint8_t threshByteRGBA[4]; + caretPreferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(threshByteRGBA); + threshRGBA[0] = static_cast(threshByteRGBA[0]) / 255.0f; + threshRGBA[1] = static_cast(threshByteRGBA[1]) / 255.0f; + threshRGBA[2] = static_cast(threshByteRGBA[2]) / 255.0f; + threshRGBA[3] = 1.0; } + const float minX = -1000000.0f; //minValueX; + const float maxX = 1000000.0f; + const float minY = 0.0; + const float maxY = *std::max_element(histogramBuckets.begin(), + histogramBuckets.end()); - PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); - CaretAssert(paletteColorMapping); + float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); + float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); - EventPaletteGetByName paletteEvent(paletteColorMapping->getSelectedPaletteName()); - EventManager::get()->sendEvent(paletteEvent.getPointer()); - const Palette* palette = paletteEvent.getPalette(); - if (palette == NULL) { - CaretLogSevere("Unable to find palette named: " - + paletteColorMapping->getSelectedPaletteName()); - return NULL; + thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + + switch (paletteColorMapping->getThresholdTest()) { + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: + { + thresholdPrimitive->reserveForNumberOfVertices(8); + thresholdPrimitive->addVertex(minX, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(minX, maxY, threshRGBA); + + thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); + thresholdPrimitive->addVertex(maxX, minY, threshRGBA); + thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + } + break; + case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: + { + thresholdPrimitive->reserveForNumberOfVertices(4); + thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + } + break; } + } + + /* + * If selected, apply solid color to envelope histogram + */ + const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); + float envelopeSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; + bool envelopeSolidColorFlag = false; + if (histogramEnvelopeColor != CaretColorEnum::CUSTOM) { + CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, + envelopeSolidColorRGBA); + envelopeSolidColorFlag = true; + } + + /* + * If selected, apply solid color to bars histogram + */ + const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); + float barsSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; + bool barsSolidColorFlag = false; + if (histogramBarsColor != CaretColorEnum::CUSTOM) { + CaretColorEnum::toRGBAFloat(histogramBarsColor, + barsSolidColorRGBA); + barsSolidColorFlag = true; + } + + /* + * Move start one-half of bucket width so that bar's + * X-value is centered within the bar + */ + const float halfBucketWidth = bucketWidth / 2.0f; + const float startX = minValueX - halfBucketWidth; + + + float x = startX; + for (int32_t i = 0; i < numBucketValues; i++) { + CaretAssertVectorIndex(histogramBuckets, i); + const float xMin = x; + const float xMax = x + bucketWidth; + const float yMin = 0.0f; + float yMax = histogramBuckets[i]; - float minValueX = 0.0; - float maxValueX = 0.0; - histogram->getRange(minValueX, - maxValueX); - const float valueRangeX = maxValueX - minValueX; - if (valueRangeX <= 0.0) { - CaretLogSevere("Range of histogram X-values is zero"); - return NULL; + CaretAssertVectorIndex(histogramRGBA, i*4+3); + const float* rgba = &histogramRGBA[i * 4]; + const float alpha = rgba[3]; + + /* + * Use a height of zero when there is no coloring + * (apha == 0) for a bar since the bars will be + * smoothed to create the envelope. + */ + if (alpha <= 0.0) { + yMax = 0.0; } - if ((paletteColorMapping != NULL) - && (statistics != NULL) - && (palette != NULL) - && (histogram != NULL)) { - std::vector histogramBuckets = histogram->getHistogramDisplay(); - const int32_t numBucketValues = static_cast(histogramBuckets.size()); - if (numBucketValues < 2) { - CaretLogSevere("Histogram must contain two or more values"); - return NULL; - } - - const float bucketWidth = valueRangeX / (numBucketValues - 1); - std::vector xValuesAtBuckets; - xValuesAtBuckets.reserve(numBucketValues); - for (int32_t i = 0; i < numBucketValues; i++) { - xValuesAtBuckets.push_back(minValueX + (bucketWidth * i)); - } - CaretAssert(xValuesAtBuckets.size() == histogramBuckets.size()); - - std::vector histogramRGBA; - histogramRGBA.resize(numBucketValues * 4, - 0.0f); - NodeAndVoxelColoring::colorScalarsWithPalette(statistics, - paletteColorMapping, - palette, - &xValuesAtBuckets[0], - &xValuesAtBuckets[0], - numBucketValues, - &histogramRGBA[0], - true); // ignore thresholding - - - const int32_t estimatedNumberOfVerticesForQuads = (numBucketValues * 4); // four vertices per quad - const int32_t estimatedNumberOfVerticesForEnvelope = (numBucketValues * 2) + 4; // 2 vertices per line segment plus start/end - + if (barsSolidColorFlag) { /* - * Use Quads when drawing bars (four vertices quad). - * Use Lines when drawing envelope (two vertices per line) - * Using quads and lines simplifies identification of individual bars in the histogram + * Use alpha from normal coloring */ - GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); - barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); - GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES); - envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); - GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; - - bool setThresholdingFlag = false; - switch (paletteColorMapping->getThresholdType()) { - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: - setThresholdingFlag = true; - break; - case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: - break; + barsSolidColorRGBA[3] = rgba[3]; + barsPrimitive->addVertex(xMin, yMin, barsSolidColorRGBA); + barsPrimitive->addVertex(xMax, yMin, barsSolidColorRGBA); + barsPrimitive->addVertex(xMax, yMax, barsSolidColorRGBA); + barsPrimitive->addVertex(xMin, yMax, barsSolidColorRGBA); + } + else { + barsPrimitive->addVertex(xMin, yMin, rgba); + barsPrimitive->addVertex(xMax, yMin, rgba); + barsPrimitive->addVertex(xMax, yMax, rgba); + barsPrimitive->addVertex(xMin, yMax, rgba); + } + + if (envelopeSolidColorFlag) { + const float envelopeX = x + halfBucketWidth; + if (i == 0) { + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); } - - if (setThresholdingFlag) { - /* - * RGBA for thresholding - */ - EventCaretPreferencesGet preferencesEvent; - EventManager::get()->sendEvent(preferencesEvent.getPointer()); - CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); - float threshRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; - if (caretPreferences != NULL) { - uint8_t threshByteRGBA[4]; - caretPreferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(threshByteRGBA); - threshRGBA[0] = static_cast(threshByteRGBA[0]) / 255.0f; - threshRGBA[1] = static_cast(threshByteRGBA[1]) / 255.0f; - threshRGBA[2] = static_cast(threshByteRGBA[2]) / 255.0f; - threshRGBA[3] = 1.0; - } - const float minX = -1000000.0f; //minValueX; - const float maxX = 1000000.0f; - const float minY = 0.0; - const float maxY = *std::max_element(histogramBuckets.begin(), - histogramBuckets.end()); + else { + const float xPrevious = envelopeX - bucketWidth; + CaretAssertVectorIndex(histogramBuckets, i - 1); + const float yPrevious = histogramBuckets[i - 1]; - float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); - float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); - - thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); - - switch (paletteColorMapping->getThresholdTest()) { - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: - { - thresholdPrimitive->reserveForNumberOfVertices(8); - thresholdPrimitive->addVertex(minX, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); - thresholdPrimitive->addVertex(minX, maxY, threshRGBA); - - thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); - thresholdPrimitive->addVertex(maxX, minY, threshRGBA); - thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); - thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); - } - break; - case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: - { - thresholdPrimitive->reserveForNumberOfVertices(4); - thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); - thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); - } - break; - } - } - - /* - * If selected, apply solid color to envelope histogram - */ - const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); - float envelopeSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; - bool envelopeSolidColorFlag = false; - if (histogramEnvelopeColor != CaretColorEnum::CUSTOM) { - CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, - envelopeSolidColorRGBA); - envelopeSolidColorFlag = true; + envelopePrimitive->addVertex(xPrevious, yPrevious, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); + } } - - /* - * If selected, apply solid color to bars histogram - */ - const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); - float barsSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; - bool barsSolidColorFlag = false; - if (histogramBarsColor != CaretColorEnum::CUSTOM) { - CaretColorEnum::toRGBAFloat(histogramBarsColor, - barsSolidColorRGBA); - barsSolidColorFlag = true; + } + else { + const float envelopeX = x + halfBucketWidth; + if (i == 0) { + envelopePrimitive->addVertex(envelopeX, yMin, rgba); + envelopePrimitive->addVertex(envelopeX, yMax, rgba); } - - /* - * Move start one-half of bucket width so that bar's - * X-value is centered within the bar - */ - const float halfBucketWidth = bucketWidth / 2.0f; - const float startX = minValueX - halfBucketWidth; - - - float x = startX; - for (int32_t i = 0; i < numBucketValues; i++) { - CaretAssertVectorIndex(histogramBuckets, i); - const float xMin = x; - const float xMax = x + bucketWidth; - const float yMin = 0.0f; - float yMax = histogramBuckets[i]; + else { + const float xPrevious = envelopeX - bucketWidth; + CaretAssertVectorIndex(histogramBuckets, i - 1); + const float yPrevious = histogramBuckets[i - 1]; + CaretAssertVectorIndex(histogramRGBA, (i - 1) * 4 + 3); - CaretAssertVectorIndex(histogramRGBA, i*4+3); - const float* rgba = &histogramRGBA[i * 4]; - const float alpha = rgba[3]; - - /* - * Use a height of zero when there is no coloring - * (apha == 0) for a bar since the bars will be - * smoothed to create the envelope. - */ - if (alpha <= 0.0) { - yMax = 0.0; - } - - if (barsSolidColorFlag) { - /* - * Use alpha from normal coloring - */ - barsSolidColorRGBA[3] = rgba[3]; - barsPrimitive->addVertex(xMin, yMin, barsSolidColorRGBA); - barsPrimitive->addVertex(xMax, yMin, barsSolidColorRGBA); - barsPrimitive->addVertex(xMax, yMax, barsSolidColorRGBA); - barsPrimitive->addVertex(xMin, yMax, barsSolidColorRGBA); - } - else { - barsPrimitive->addVertex(xMin, yMin, rgba); - barsPrimitive->addVertex(xMax, yMin, rgba); - barsPrimitive->addVertex(xMax, yMax, rgba); - barsPrimitive->addVertex(xMin, yMax, rgba); - } + envelopePrimitive->addVertex(xPrevious, yPrevious, &histogramRGBA[(i - 1) * 4]); + envelopePrimitive->addVertex(envelopeX, yMax, rgba); - if (envelopeSolidColorFlag) { - const float envelopeX = x + halfBucketWidth; - if (i == 0) { - envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - } - else { - const float xPrevious = envelopeX - bucketWidth; - CaretAssertVectorIndex(histogramBuckets, i - 1); - const float yPrevious = histogramBuckets[i - 1]; - - envelopePrimitive->addVertex(xPrevious, yPrevious, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); - } - } + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMax, rgba); + envelopePrimitive->addVertex(envelopeX, yMin, rgba); } - else { - const float envelopeX = x + halfBucketWidth; - if (i == 0) { - envelopePrimitive->addVertex(envelopeX, yMin, rgba); - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - } - else { - const float xPrevious = envelopeX - bucketWidth; - CaretAssertVectorIndex(histogramBuckets, i - 1); - const float yPrevious = histogramBuckets[i - 1]; - CaretAssertVectorIndex(histogramRGBA, (i - 1) * 4 + 3); - - envelopePrimitive->addVertex(xPrevious, yPrevious, &histogramRGBA[(i - 1) * 4]); - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - envelopePrimitive->addVertex(envelopeX, yMin, rgba); - } - } - } - - x += bucketWidth; } - - HistogramPrimitives* histogramPrimitives = new HistogramPrimitives(thresholdPrimitive, - barsPrimitive, - envelopePrimitive); - - m_mapHistogramBarsPrimitive.insert(std::make_pair(mapIndex, - std::unique_ptr(histogramPrimitives))); - - return histogramPrimitives; - } + + x += bucketWidth; } + + HistogramPrimitives* histogramPrimitives = new HistogramPrimitives(thresholdPrimitive, + barsPrimitive, + envelopePrimitive); + + m_mapHistogramBarsPrimitive.insert(std::make_pair(mapIndex, + std::unique_ptr(histogramPrimitives))); + + return histogramPrimitives; + + } return NULL; } -///** -// * Get the histogram chart for the given map index. -// * -// * @param mapIndex -// * Index for the map. -// * @return -// * Histogram for the map with the given index. NULL if the file -// * does not support a histogram. -// */ -//const ChartTwoDataHistogram* -//ChartableTwoFileHistogramChart::getMapHistogramChart(const int32_t mapIndex) const -//{ -// CaretAssertToDoFatal(); // This class may not be needed -// -// ChartTwoDataHistogram* histogramChartOut = NULL; -// -// std::map::iterator iter = m_indexHistogramsMap.find(mapIndex); -// if (iter != m_indexHistogramsMap.end()) { -// histogramChartOut = iter->second; -// } -// else { -// histogramChartOut = new ChartTwoDataHistogram(); -// m_indexHistogramsMap.insert(std::make_pair(mapIndex, -// histogramChartOut)); -// } -// -// /* -// * Update with histogram from the file even if it is NULL. -// */ -// CaretMappableDataFile* mapFile = const_cast(getCaretMappableDataFile()); -// CaretAssert(mapFile); -// histogramChartOut->setHistogram(const_cast(mapFile->getMapHistogram(mapIndex))); -// -// return histogramChartOut; -//} - /** * Save subclass data to the scene. * @@ -878,15 +679,9 @@ ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives(Graphic GraphicsPrimitiveV3fC4f* barsPrimitive, GraphicsPrimitiveV3fC4f* envelopePrimitive) { -// if (thresholdPrimitive != NULL) { - m_thresholdPrimitive.reset(thresholdPrimitive); -// } -// if (barsPrimitive != NULL) { - m_barsPrimitive.reset(barsPrimitive); -// } -// if (envelopePrimitive != NULL) { - m_envelopePrimitive.reset(envelopePrimitive); -// } + m_thresholdPrimitive.reset(thresholdPrimitive); + m_barsPrimitive.reset(barsPrimitive); + m_envelopePrimitive.reset(envelopePrimitive); } /* diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index 4afc36635..7e6ecbf8d 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -91,8 +91,6 @@ namespace caret { void invalidateAllColoring(); - //const ChartTwoDataHistogram* getMapHistogramChart(const int32_t mapIndex) const; - // ADD_NEW_METHODS_HERE protected: @@ -111,20 +109,12 @@ namespace caret { const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; -// std::unique_ptr m_fileHistogramBarsPrimitive; -// -// std::unique_ptr m_fileHistogramBarsLimitiedValuesPrimitive; - typedef std::map> MapIndexPrimitiveContainer; MapIndexPrimitiveContainer m_mapHistogramBarsPrimitive; MapIndexPrimitiveContainer m_mapHistogramThresholdPrimitive; - //std::map> m_mapHistogramBarsLimitedValuesPrimitive; - - // mutable std::map m_indexHistogramsMap; - // ADD_NEW_MEMBERS_HERE }; -- GitLab From 1f61c37927e6523c75b081fa8209fa2a05eb9b28 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 May 2017 08:35:38 -0500 Subject: [PATCH 267/755] Do not copy histogram display attributes when palettes are copied to all map with "Apply to All Maps" selected on Palette Color Mapping Editor. --- src/Files/CaretMappableDataFile.cxx | 3 +- src/Files/CiftiBrainordinateScalarFile.cxx | 3 +- .../MapSettingsPaletteColorMappingWidget.cxx | 6 +- src/Palette/PaletteColorMapping.cxx | 64 +++++++++++++------ src/Palette/PaletteColorMapping.h | 6 +- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 928b71e00..626b2b40a 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -532,7 +532,8 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr pcm.decodeFromStringXML(pcmString); PaletteColorMapping* pcmMap = getMapPaletteColorMapping(restoreMapIndex); - pcmMap->copy(pcm); + pcmMap->copy(pcm, + true); pcmMap->clearModified(); /* diff --git a/src/Files/CiftiBrainordinateScalarFile.cxx b/src/Files/CiftiBrainordinateScalarFile.cxx index 3ef05d4fe..13a48fb8c 100644 --- a/src/Files/CiftiBrainordinateScalarFile.cxx +++ b/src/Files/CiftiBrainordinateScalarFile.cxx @@ -196,7 +196,8 @@ CiftiBrainordinateScalarFile::newInstanceFromRowInCiftiConnectivityMatrixFile(co CaretAssert(scalarPalette); const PaletteColorMapping* densePalette = sourceCiftiMatrixFile->getMapPaletteColorMapping(0); CaretAssert(densePalette); - scalarPalette->copy(*densePalette); + scalarPalette->copy(*densePalette, + true); scalarFile->setModified(); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index f8b638a44..8ec3d04c8 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -2442,7 +2442,8 @@ void MapSettingsPaletteColorMappingWidget::applySelections() for (int32_t i = 0; i < numMaps; i++) { PaletteColorMapping* pcm = this->caretMappableDataFile->getMapPaletteColorMapping(i); if (pcm != this->paletteColorMapping) { - pcm->copy(*this->paletteColorMapping); + pcm->copy(*this->paletteColorMapping, + false); } } PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); @@ -2717,7 +2718,8 @@ MapSettingsPaletteColorMappingWidget::applyToMultipleFilesPushbuttonClicked() for (int32_t iMap = 0; iMap < numMaps; iMap++) { PaletteColorMapping* pcm = cmdf->getMapPaletteColorMapping(iMap); if (pcm != this->paletteColorMapping) { - pcm->copy(*this->paletteColorMapping); + pcm->copy(*this->paletteColorMapping, + false); } } diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index f79954baf..62b2969ad 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -71,7 +71,8 @@ PaletteColorMapping::PaletteColorMapping(const PaletteColorMapping& o) : CaretObject(o) { this->initializeMembersPaletteColorMapping(); - this->copyHelper(o); + this->copyHelper(o, + true); } /** @@ -82,7 +83,8 @@ PaletteColorMapping::operator=(const PaletteColorMapping& o) { if (this != &o) { CaretObject::operator=(o); - this->copyHelper(o); + this->copyHelper(o, + true); }; return *this; } @@ -92,19 +94,29 @@ PaletteColorMapping::operator=(const PaletteColorMapping& o) * color mapping. * @param pcm * Color mapping that is copied to this. + * @param copyHistogramAttributesFlag + * If true copy histogram attributes. */ void -PaletteColorMapping::copy(const PaletteColorMapping& pcm) +PaletteColorMapping::copy(const PaletteColorMapping& pcm, + const bool copyHistogramAttributesFlag) { - this->copyHelper(pcm); + this->copyHelper(pcm, + copyHistogramAttributesFlag); setModified(); } /** * Helps with copy constructor and assignment operator. + * + * @param pcm + * Color mapping that is copied to this. + * @param copyHistogramAttributesFlag + * If true copy histogram attributes. */ void -PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) +PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm, + const bool copyHistogramAttributesFlag) { this->autoScalePercentageNegativeMaximum = pcm.autoScalePercentageNegativeMaximum; this->autoScalePercentageNegativeMinimum = pcm.autoScalePercentageNegativeMinimum; @@ -134,12 +146,14 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) this->thresholdShowFailureInGreen = pcm.thresholdShowFailureInGreen; this->thresholdRangeMode = pcm.thresholdRangeMode; this->thresholdNegMinPosMaxLinked = pcm.thresholdNegMinPosMaxLinked; - this->histogramRangeMode = pcm.histogramRangeMode; - this->histogramBarsVisible = pcm.histogramBarsVisible; - this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; - this->histogramBarsColor = pcm.histogramBarsColor; - this->histogramEnvelopeColor = pcm.histogramEnvelopeColor; - this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; + if (copyHistogramAttributesFlag) { + this->histogramRangeMode = pcm.histogramRangeMode; + this->histogramBarsVisible = pcm.histogramBarsVisible; + this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; + this->histogramBarsColor = pcm.histogramBarsColor; + this->histogramEnvelopeColor = pcm.histogramEnvelopeColor; + this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; + } this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; this->colorBarPrecisionDigits = pcm.colorBarPrecisionDigits; this->colorBarNumericSubdivisionCount = pcm.colorBarNumericSubdivisionCount; @@ -159,6 +173,8 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm) bool PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const { + bool allMatchFlag = false; + if ((this->autoScalePercentageNegativeMaximum == pcm.autoScalePercentageNegativeMaximum) && (this->autoScalePercentageNegativeMinimum == pcm.autoScalePercentageNegativeMinimum) && (this->autoScalePercentagePositiveMaximum == pcm.autoScalePercentagePositiveMaximum) @@ -187,21 +203,31 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->thresholdShowFailureInGreen == pcm.thresholdShowFailureInGreen) && (this->thresholdRangeMode == pcm.thresholdRangeMode) && (this->thresholdNegMinPosMaxLinked == pcm.thresholdNegMinPosMaxLinked) - && (this->histogramRangeMode == pcm.histogramRangeMode) - && (this->histogramBarsVisible == pcm.histogramBarsVisible) - && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) - && (this->histogramBarsColor == pcm.histogramBarsColor) - && (this->histogramEnvelopeColor == pcm.histogramEnvelopeColor) - && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets) && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) && (this->colorBarPrecisionDigits == pcm.colorBarPrecisionDigits) && (this->colorBarNumericSubdivisionCount == pcm.colorBarNumericSubdivisionCount) && (this->colorBarValuesMode == pcm.colorBarValuesMode) && (this->colorBarShowTickMarksSelected == pcm.colorBarShowTickMarksSelected)) { - return true; + + allMatchFlag = true; + + const bool includeHistogramAttributesFlag = false; + if (includeHistogramAttributesFlag) { + if ((this->histogramRangeMode == pcm.histogramRangeMode) + && (this->histogramBarsVisible == pcm.histogramBarsVisible) + && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) + && (this->histogramBarsColor == pcm.histogramBarsColor) + && (this->histogramEnvelopeColor == pcm.histogramEnvelopeColor) + && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets)) { + allMatchFlag = true; + } + else { + allMatchFlag = false; + } + } } - return false; + return allMatchFlag; } diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index f7faa02ff..8d8860090 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -58,10 +58,12 @@ namespace caret { virtual ~PaletteColorMapping(); - void copy(const PaletteColorMapping& pcm); + void copy(const PaletteColorMapping& pcm, + const bool copyHistogramAttributesFlag); private: - void copyHelper(const PaletteColorMapping& o); + void copyHelper(const PaletteColorMapping& o, + const bool copyHistogramAttributesFlag); void initializeMembersPaletteColorMapping(); -- GitLab From 051575e884f951d506f65f0fbe8c719d333959e4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 May 2017 15:45:03 -0500 Subject: [PATCH 268/755] Corrections to ensure that OpenGL contexts are shared in all windows so that OpenGL buffer objects (used by the new OpenGL Primitives) do not need creation for all windows. --- src/Brain/BrainOpenGL.cxx | 58 +++--- src/Brain/BrainOpenGL.h | 89 +++------ ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 10 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 40 ++-- src/Brain/BrainOpenGLFixedPipeline.h | 14 +- src/GuiQt/BrainBrowserWindow.cxx | 187 ++---------------- src/GuiQt/BrainBrowserWindow.h | 8 +- src/GuiQt/BrainOpenGLWidget.cxx | 102 +++++++--- src/GuiQt/BrainOpenGLWidget.h | 22 ++- src/GuiQt/GuiManager.cxx | 13 +- src/Operations/OperationShowScene.cxx | 17 +- src/Operations/OperationShowScene.h | 2 +- 12 files changed, 236 insertions(+), 326 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 4c6f2a563..9742462db 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -88,7 +88,7 @@ BrainOpenGL::receiveEvent(Event* event) = dynamic_cast(event); CaretAssert(createBufferEvent); - if (m_openGLContextPointer == NULL) { + if (m_contextSharingGroupPointer == NULL) { AString msg("PROGRAM ERROR: " "A request for a new OpenGL Buffer Object has been made. " "However, there is no OpenGL context currently active so " @@ -104,7 +104,7 @@ BrainOpenGL::receiveEvent(Event* event) GLuint bufferName = 0; glGenBuffers(1, &bufferName); - createBufferEvent->setOpenGLBufferObject(new GraphicsOpenGLBufferObject(m_openGLContextPointer, + createBufferEvent->setOpenGLBufferObject(new GraphicsOpenGLBufferObject(m_contextSharingGroupPointer, bufferName)); createBufferEvent->setEventProcessed(); } @@ -132,34 +132,40 @@ BrainOpenGL::receiveEvent(Event* event) /** * Draw models in their respective viewports. * + * @param windowIndex + * Index of window for drawing. * @param brain * The brain (must be valid!) - * @param openGLContextPointer + * @param contextSharingGroupPointer * Pointer to the active OpenGL context. * @param viewportContents * Viewport info for drawing. */ -void BrainOpenGL::drawModels(Brain* brain, - void* openGLContextPointer, +void BrainOpenGL::drawModels(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, std::vector& viewportContents) { - m_openGLContextPointer = openGLContextPointer; + m_contextSharingGroupPointer = contextSharingGroupPointer; - drawModelsImplementation(brain, + drawModelsImplementation(windowIndex, + brain, viewportContents); deleteUnusedBuffers(); - m_openGLContextPointer = NULL; + m_contextSharingGroupPointer = NULL; } /** * Selection on a model. * + * @param windowIndex + * Index of window for selection. * @param brain * The brain (must be valid!) - * @param openGLContextPointer - * Pointer to the active OpenGL context. + * @param contextSharingGroupPointer + * Pointer to the active OpenGL context * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX @@ -174,16 +180,18 @@ void BrainOpenGL::drawModels(Brain* brain, * selected. If this parameter is false, the node will be * selected. */ -void BrainOpenGL::selectModel(Brain* brain, - void* openGLContextPointer, +void BrainOpenGL::selectModel(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) { - m_openGLContextPointer = openGLContextPointer; + m_contextSharingGroupPointer = contextSharingGroupPointer; - selectModelImplementation(brain, + selectModelImplementation(windowIndex, + brain, viewportContent, mouseX, mouseY, @@ -191,7 +199,7 @@ void BrainOpenGL::selectModel(Brain* brain, deleteUnusedBuffers(); - m_openGLContextPointer = NULL; + m_contextSharingGroupPointer = NULL; } /** @@ -200,9 +208,11 @@ void BrainOpenGL::selectModel(Brain* brain, * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * + * @param windowIndex + * Index of window for projection * @param brain * The brain (must be valid!) - * @param openGLContextPointer + * @param contextSharingGroupPointer * Pointer to the active OpenGL context. * @param viewportContent * Viewport content in which mouse was clicked @@ -210,24 +220,28 @@ void BrainOpenGL::selectModel(Brain* brain, * X position of mouse click * @param mouseY * Y position of mouse click + * @param projectionOut + * Output with projection result. */ -void BrainOpenGL::projectToModel(Brain* brain, - void* openGLContextPointer, +void BrainOpenGL::projectToModel(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) { - m_openGLContextPointer = openGLContextPointer; + m_contextSharingGroupPointer = contextSharingGroupPointer; - projectToModelImplementation(brain, + projectToModelImplementation(windowIndex, + brain, viewportContent, mouseX, mouseY, projectionOut); deleteUnusedBuffers(); - m_openGLContextPointer = NULL; + m_contextSharingGroupPointer = NULL; } @@ -247,7 +261,7 @@ BrainOpenGL::deleteUnusedBuffers() std::vector bufferNames; for (auto bufferInfo : m_buffersForDeletionLater) { - if (bufferInfo.m_openglContextPointer == m_openGLContextPointer) { + if (bufferInfo.m_openglContextPointer == m_contextSharingGroupPointer) { if (glIsBuffer(bufferInfo.m_bufferName)) { bufferNames.push_back(bufferInfo.m_bufferName); } diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 701dbf7d9..4190c5f32 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -104,67 +104,22 @@ namespace caret { void setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer); - /** - * Draw models in their respective viewports. - * - * @param brain - * The brain (must be valid!) - * @param openGLContextPointer - * Pointer to the active OpenGL context. - * @param viewportContents - * Viewport info for drawing. - */ - void drawModels(Brain* brain, - void* openGLContextPointer, + void drawModels(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, std::vector& viewportContents); - /** - * Selection on a model. - * - * @param brain - * The brain (must be valid!) - * @param openGLContextPointer - * Pointer to the active OpenGL context. - * @param viewportContent - * Viewport content in which mouse was clicked - * @param mouseX - * X position of mouse click - * @param mouseY - * Y position of mouse click - * @param applySelectionBackgroundFiltering - * If true (which is in most cases), if there are multiple items - * selected, those items "behind" other items are not reported. - * For example, suppose a focus is selected and there is a node - * the focus. If this parameter is true, the node will NOT be - * selected. If this parameter is false, the node will be - * selected. - */ - void selectModel(Brain* brain, - void* openGLContextPointer, + void selectModel(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering); - /** - * Project the given window coordinate to the active models. - * If the projection is successful, The 'original' XYZ - * coordinate in 'projectionOut' will be valid. In addition, - * the barycentric coordinate may also be valid in 'projectionOut'. - * - * @param brain - * The brain (must be valid!) - * @param openGLContextPointer - * Pointer to the active OpenGL context. - * @param viewportContent - * Viewport content in which mouse was clicked - * @param mouseX - * X position of mouse click - * @param mouseY - * Y position of mouse click - */ - void projectToModel(Brain* brain, - void* openGLContextPointer, + void projectToModel(const int32_t windowIndex, + Brain* brain, + void* contextSharingGroupPointer, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, @@ -228,7 +183,10 @@ namespace caret { virtual void receiveEvent(Event* event); - inline void* getOpenGLContextPointer() { return m_openGLContextPointer; } + /** + * @return Pointer to OpenGL context sharing group pointer. + */ + inline void* getContextSharingGroupPointer() { return m_contextSharingGroupPointer; } private: class DeleteBufferNameInfo { @@ -250,8 +208,8 @@ namespace caret { /** use a mutex whenever accessing this member */ std::vector m_buffersForDeletionLater; - /** Pointer to the current OpenGL Context */ - void* m_openGLContextPointer = 0; + /** Pointer to the current OpenGL Context sharing group */ + void* m_contextSharingGroupPointer = 0; BrainOpenGL(const BrainOpenGL&); BrainOpenGL& operator=(const BrainOpenGL&); @@ -261,17 +219,22 @@ namespace caret { /** * Draw models in their respective viewports. * + * @param windowIndex + * Index of window for drawing * @param brain * The brain (must be valid!) * @param viewportContents * Viewport info for drawing. */ - virtual void drawModelsImplementation(Brain* brain, + virtual void drawModelsImplementation(const int32_t windowIndex, + Brain* brain, std::vector& viewportContents) = 0; /** * Selection on a model. * + * @param windowIndex + * Index of window for selection * @param brain * The brain (must be valid!) * @param viewportContent @@ -288,7 +251,8 @@ namespace caret { * selected. If this parameter is false, the node will be * selected. */ - virtual void selectModelImplementation(Brain* brain, + virtual void selectModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, @@ -300,6 +264,8 @@ namespace caret { * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * + * @param windowIndex + * Index of window for projection * @param brain * The brain (must be valid!) * @param viewportContent @@ -308,8 +274,11 @@ namespace caret { * X position of mouse click * @param mouseY * Y position of mouse click + * @param projectionOut + * Output with projection result. */ - virtual void projectToModelImplementation(Brain* brain, + virtual void projectToModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 8574714b6..dd821a59e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -557,7 +557,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() */ glPushMatrix(); glScalef(1.0, 1000.0, 1.0); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), histogramPrimitives->getBarsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -570,7 +570,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() * Increase line width for identification */ glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -781,7 +781,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getOpenGLContextPointer(), + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), matrixPrimitive, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -815,7 +815,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glPolygonMode(GL_FRONT, GL_LINE); - GraphicsEngineDataOpenGL::drawWithAlternativeColor(m_fixedPipelineDrawing->getOpenGLContextPointer(), + GraphicsEngineDataOpenGL::drawWithAlternativeColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), matrixPrimitive, matrixChart->getMatrixChartGraphicsPrimitiveGridColorIdentifier()); glPolygonMode(GL_FRONT, @@ -1613,7 +1613,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* return; } - GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getOpenGLContextPointer(), + GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), primitive); } diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index ba292e46c..5136d2144 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -161,23 +161,18 @@ static bool drawTabAnnotationsAfterTabContentFlag = true; /** * Constructor. * - * @param parentGLWidget + * @param textRenderer * The optional text renderer is used for text rendering. * This parameter may be NULL in which case no text * rendering is performed. */ -BrainOpenGLFixedPipeline::BrainOpenGLFixedPipeline(const int32_t windowIndex, - BrainOpenGLTextRenderInterface* textRenderer) -: BrainOpenGL(textRenderer), -m_windowIndex(windowIndex) +BrainOpenGLFixedPipeline::BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterface* textRenderer) +: BrainOpenGL(textRenderer) { - CaretAssert((m_windowIndex >= 0) - && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); - this->initializeMembersBrainOpenGL(); this->colorIdentification = new IdentificationWithColor(); m_annotationDrawing.grabNew(new BrainOpenGLAnnotationDrawingFixedPipeline(this)); - m_textureManager.grabNew(new BrainOpenGLTextureManager(m_windowIndex)); + m_textureManager.grabNew(new BrainOpenGLTextureManager(0)); //m_windowIndex)); m_shapeSphere = NULL; m_shapeCone = NULL; @@ -248,6 +243,8 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() /** * Selection on a model. * + * @param windowIndex + * Index of window for selection * @param brain * The brain (must be valid!) * @param viewportContent @@ -265,14 +262,18 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() * selected. */ void -BrainOpenGLFixedPipeline::selectModelImplementation(Brain* brain, +BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) { m_brain = brain; + m_windowIndex = windowIndex; CaretAssert(m_brain); + CaretAssert((m_windowIndex >= 0) + && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(viewportContent); @@ -317,6 +318,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(Brain* brain, m_brain->getSelectionManager()->filterSelections(applySelectionBackgroundFiltering); m_brain = NULL; + m_windowIndex = -1; } /** @@ -325,6 +327,8 @@ BrainOpenGLFixedPipeline::selectModelImplementation(Brain* brain, * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * + * @param windowIndex + * Index of window for projection * @param brain * The brain (must be valid!) * @param viewportContent @@ -337,14 +341,18 @@ BrainOpenGLFixedPipeline::selectModelImplementation(Brain* brain, * Contains projection result upon exit. */ void -BrainOpenGLFixedPipeline::projectToModelImplementation(Brain* brain, +BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) { m_brain = brain; + m_windowIndex = windowIndex; CaretAssert(m_brain); + CaretAssert((m_windowIndex >= 0) + && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(viewportContent); @@ -373,6 +381,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(Brain* brain, this->modeProjectionData = NULL; m_brain = NULL; + m_windowIndex = -1; } /** @@ -497,17 +506,23 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vector& viewportContents) { m_brain = brain; + m_windowIndex = windowIndex; CaretAssert(m_brain); + CaretAssert((m_windowIndex >= 0) + && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(NULL); @@ -653,6 +668,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(Brain* brain, this->checkForOpenGLError(NULL, "At end of drawModels()"); m_brain = NULL; + m_windowIndex = -1; } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 927854d20..ecf93fc20 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -99,8 +99,7 @@ namespace caret { BrainOpenGLFixedPipeline& operator=(const BrainOpenGLFixedPipeline&); public: - BrainOpenGLFixedPipeline(const int32_t windowIndex, - BrainOpenGLTextRenderInterface* textRenderer); + BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterface* textRenderer); ~BrainOpenGLFixedPipeline(); @@ -119,16 +118,19 @@ namespace caret { virtual BrainOpenGLTextureManager* getTextureManager(); protected: - void drawModelsImplementation(Brain* brain, + void drawModelsImplementation(const int32_t windowIndex, + Brain* brain, std::vector& viewportContents) override; - void selectModelImplementation(Brain* brain, + void selectModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) override; - void projectToModelImplementation(Brain* brain, + void projectToModelImplementation(const int32_t windowIndex, + Brain* brain, BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, @@ -520,7 +522,7 @@ namespace caret { void setAnnotationColorBarsForDrawing(std::vector& viewportContents); /** Index of window */ - const int32_t m_windowIndex; + int32_t m_windowIndex = -1; /** Indicates OpenGL has been initialized */ bool initializedOpenGLFlag; diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 082659851..dc257ccdc 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -159,20 +159,7 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, m_openGLWidget = new BrainOpenGLWidget(this, shareOpenGLContextWidget, browserWindowIndex); - if (shareOpenGLContextWidget != NULL) { - /* - * Need to know if OpenGL context sharing is enabled. - */ - m_openGLWidgetSharingContextFlag = m_openGLWidget->isSharing(); - } - else { - /* - * This is the first window so set OpenGL context - * to true since there are no other contexts - */ - m_openGLWidgetSharingContextFlag = true; - } - + const int openGLSizeX = 500; const int openGLSizeY = (WuQtUtilities::isSmallDisplay() ? 200 : 375); m_openGLWidget->setMinimumSize(openGLSizeX, @@ -292,9 +279,12 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, */ BrainBrowserWindow::~BrainBrowserWindow() { + EventManager::get()->removeAllEventsFromListener(this); + s_brainBrowserWindows.erase(this); - EventManager::get()->removeAllEventsFromListener(this); + if (s_brainBrowserWindows.empty()) { + } delete m_defaultTileTabsConfiguration; delete m_sceneTileTabsConfiguration; @@ -466,131 +456,6 @@ BrainBrowserWindow::receiveEvent(Event* event) viewportSizeEvent->setViewportSize(viewport); } } -// else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET_VIEWPORT_SIZE) { -// EventBrowserTabGetViewportSize* viewportSizeEvent = dynamic_cast(event); -// CaretAssert(viewportSizeEvent); -// -// std::vector allTabContent; -// m_toolbar->getAllTabContent(allTabContent); -// -// const std::vector allViewportContent = m_openGLWidget->getViewportContent(); -// -// int32_t tabViewport[4] = { 0, 0, 0, 0 }; -// bool tabViewportValid = false; -// -// int32_t notBestTabViewport[4] = { 0, 0, 0, 0 }; -// bool notBestTabViewportValid = false; -// -// /* -// * Find the viewport content containing the specified tab by index -// */ -// for (std::vector::iterator tabIter = allTabContent.begin(); -// tabIter != allTabContent.end(); -// tabIter++) { -// const BrowserTabContent* btc = *tabIter; -// CaretAssert(btc); -// -// switch (viewportSizeEvent->getMode()) { -// case EventBrowserTabGetViewportSize::MODE_SURFACE_MONTAGE: -// { -// const Model* model = btc->getModelForDisplay(); -// if (model->getModelType() == ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE) { -// for (std::vector::const_iterator vpIter = allViewportContent.begin(); -// vpIter != allViewportContent.end(); -// vpIter++) { -// const BrainOpenGLViewportContent* vpContent = *vpIter; -// if (vpContent->getTabIndex() == btc->getTabNumber()) { -// vpContent->getTabViewportBeforeApplyingMargins(tabViewport); -// tabViewportValid = true; -// break; -// } -// } -// } -// } -// break; -// case EventBrowserTabGetViewportSize::MODE_TAB_INDEX: -// if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { -// for (std::vector::const_iterator vpIter = allViewportContent.begin(); -// vpIter != allViewportContent.end(); -// vpIter++) { -// const BrainOpenGLViewportContent* vpContent = *vpIter; -// if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { -// vpContent->getTabViewportBeforeApplyingMargins(tabViewport); -// tabViewportValid = true; -// break; -// } -// } -// } -// break; -// case EventBrowserTabGetViewportSize::MODE_VOLUME_MONTAGE: -// { -// const Model* model = btc->getModelForDisplay(); -// if (model->getModelType() == ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES) { -// for (std::vector::const_iterator vpIter = allViewportContent.begin(); -// vpIter != allViewportContent.end(); -// vpIter++) { -// const BrainOpenGLViewportContent* vpContent = *vpIter; -// if (vpContent->getTabIndex() == btc->getTabNumber()) { -// if (btc->getSliceDrawingType() == VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE) { -// vpContent->getTabViewportBeforeApplyingMargins(tabViewport); -// tabViewportValid = true; -// break; -// } -// else { -// vpContent->getTabViewportBeforeApplyingMargins(notBestTabViewport); -// notBestTabViewportValid = true; -// } -// } -// } -// } -// } -// break; -// case EventBrowserTabGetViewportSize::MODE_WINDOW_INDEX: -// if (m_browserWindowIndex == viewportSizeEvent->getIndex()) { -// for (std::vector::const_iterator vpIter = allViewportContent.begin(); -// vpIter != allViewportContent.end(); -// vpIter++) { -// const BrainOpenGLViewportContent* vpContent = *vpIter; -// if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { -// vpContent->getTabViewportBeforeApplyingMargins(tabViewport); -// tabViewportValid = true; -// break; -// } -// } -// } -// break; -// } -// -// if (tabViewportValid) { -// break; -// } -// } -// -// if ( ! tabViewportValid) { -// if (notBestTabViewportValid) { -// tabViewport[0] = notBestTabViewport[0]; -// tabViewport[1] = notBestTabViewport[1]; -// tabViewport[2] = notBestTabViewport[2]; -// tabViewport[3] = notBestTabViewport[3]; -// tabViewportValid = true; -// } -// else { -// /* -// * Tab is in this window but not the active tab. -// * So, use the active tab's viewport -// */ -// if ( ! allViewportContent.empty()) { -// CaretAssertVectorIndex(allViewportContent, 0); -// allViewportContent[0]->getTabViewportBeforeApplyingMargins(tabViewport); -// tabViewportValid = true; -// } -// } -// } -// -// if (tabViewportValid) { -// viewportSizeEvent->setViewportSize(tabViewport); -// } -// } else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS)) { /* @@ -608,6 +473,18 @@ BrainBrowserWindow::receiveEvent(Event* event) } } +/** + * @return True if OpenGL Context Sharing is valid among + * multiple graphics windows. + * Note: If there is one window, we declare sharing valid. + */ +bool +BrainBrowserWindow::isOpenGLContextSharingValid() const +{ + CaretAssert(m_openGLWidget); + return m_openGLWidget->isOpenGLContextSharingValid(); +} + /** * Reset the graphics window size. * When the window is created, the graphics is set to a reasonable size @@ -712,21 +589,6 @@ BrainBrowserWindow::getGraphicsWidgetSize(int32_t& xOut, } } } - -// float aspectLockedWidth = aspectViewport[2]; -// float aspectLockedHeight = aspectViewport[3]; -// if ((aspectLockedWidth > 0) -// && (aspectLockedHeight > 0)) { -// if ((widthOut != aspectLockedWidth) -// || (heightOut != aspectLockedHeight)) { -// -// std::cout << "Viewport adjusted from << " << AString::number(widthOut) << ", " << AString::number(heightOut) -// << " to " << aspectLockedWidth << ", " << aspectLockedHeight << std::endl; -// -// widthOut = aspectLockedWidth; -// heightOut = aspectLockedHeight; -// } -// } } } @@ -4544,18 +4406,3 @@ BrainBrowserWindow::hasValidOpenGL() return m_openGLWidget->isValid(); } -/** - * @return True if this OpenGL widget in this window is sharing - * its OpenGL context. Note: the first window is considered - * sharing since it is the only context. Sharing is needed - * when there are multiple windows to simplify management - * of OpenGL Buffers, textures, etc. - */ -bool -BrainBrowserWindow::isOpenGLWidgetSharingContext() const -{ - return m_openGLWidgetSharingContextFlag; -} - - - diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 6e58874ae..3fe64d89e 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -110,8 +110,6 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); -// void getViewportSize(int &w, int &h); - TileTabsConfiguration* getSelectedTileTabsConfiguration(); void setSelectedTileTabsConfiguration(TileTabsConfiguration* configuration); @@ -149,8 +147,8 @@ namespace caret { bool hasValidOpenGL(); - bool isOpenGLWidgetSharingContext() const; - + bool isOpenGLContextSharingValid() const; + protected: void closeEvent(QCloseEvent* event); void keyPressEvent(QKeyEvent* event); @@ -305,8 +303,6 @@ namespace caret { BrainOpenGLWidget* m_openGLWidget; - bool m_openGLWidgetSharingContextFlag; - BrainBrowserWindowToolBar* m_toolbar; QAction* m_aboutWorkbenchAction; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 8c15e71e6..2495214be 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -25,8 +25,8 @@ #include #include #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -#include #endif +#include #include #include @@ -109,7 +109,6 @@ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, windowIndex(windowIndex), m_textRenderer(NULL) { - this->openGL = NULL; this->borderBeingDrawn = new Border(); m_mousePositionValid = false; @@ -162,6 +161,31 @@ m_textRenderer(NULL) */ setFormat(QSurfaceFormat::defaultFormat()); #endif + + /* + * Test to see if OpenGL context sharing is valid. + * If there is no sharingWidget, then this is the + * first window opened. + */ + m_openGLContextSharingValid = true; + if (shareWidget != NULL) { + if ( ! isSharing()) { + m_openGLContextSharingValid = false; + } + } + +// std::cout << "Share widget: " << std::hex << (uint64_t)shareWidget +// << ", Context Pointer: " << std::hex << (uint64_t)context() +// << ", Share Group: " << std::hex << (uint64_t)context()->contextHandle()->shareGroup() +// << ", Sharing enabled: " << (isSharing() ? "Yes" : "No") +// << std::endl; + + CaretAssert(context()); + CaretAssert(context()->contextHandle()); + m_contextShareGroupPointer = context()->contextHandle()->shareGroup(); + CaretAssert(m_contextShareGroupPointer); + + s_brainOpenGLWidgets.insert(this); } /** @@ -176,10 +200,6 @@ BrainOpenGLWidget::~BrainOpenGLWidget() this->clearDrawingViewportContents(); - if (this->openGL != NULL) { - delete this->openGL; - this->openGL = NULL; - } delete this->userInputViewModeProcessor; delete this->userInputAnnotationsModeProcessor; delete this->userInputBordersModeProcessor; @@ -191,17 +211,36 @@ BrainOpenGLWidget::~BrainOpenGLWidget() delete this->borderBeingDrawn; EventManager::get()->removeAllEventsFromListener(this); + + s_brainOpenGLWidgets.erase(this); + if (s_brainOpenGLWidgets.empty()) { + if (s_singletonOpenGL != NULL) { + delete s_singletonOpenGL; + s_singletonOpenGL = NULL; + } + } +} + +/** + * @return True if OpenGL Context Sharing is valid among + * multiple graphics windows. + * Note: If there is one window, we declare sharing valid. + */ +bool +BrainOpenGLWidget::isOpenGLContextSharingValid() const +{ + return m_openGLContextSharingValid; } + /** * Initializes graphics. */ void BrainOpenGLWidget::initializeGL() { - if (this->openGL == NULL) { - this->openGL = new BrainOpenGLFixedPipeline(this->windowIndex, - createTextRenderer()); + if (s_singletonOpenGL == NULL) { + s_singletonOpenGL = new BrainOpenGLFixedPipeline(createTextRenderer()); } else { /* @@ -213,10 +252,10 @@ BrainOpenGLWidget::initializeGL() * recreated. Otherwise, fonts will be garbage in the * image produced by QGLWidget::renderPixmap(). */ - this->openGL->setTextRenderer(createTextRenderer()); + s_singletonOpenGL->setTextRenderer(createTextRenderer()); } - this->openGL->initializeOpenGL(); + s_singletonOpenGL->initializeOpenGL(); this->lastMouseX = 0; this->lastMouseY = 0; @@ -328,7 +367,7 @@ BrainOpenGLWidget::getOpenGLInformation() + "\n Minor Version: " + AString::number(format.minorVersion())); #endif - info += ("\n\n" + this->openGL->getOpenGLInformation()); + info += ("\n\n" + s_singletonOpenGL->getOpenGLInformation()); #if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS int32_t numDisplayLists = 0; @@ -496,9 +535,9 @@ BrainOpenGLWidget::paintGL() /* * Highlighting of border points */ - this->openGL->setDrawHighlightedEndPoints(false); + s_singletonOpenGL->setDrawHighlightedEndPoints(false); if (this->selectedUserInputProcessor == this->userInputBordersModeProcessor) { - this->openGL->setDrawHighlightedEndPoints(this->userInputBordersModeProcessor->isHighlightBorderEndPoints()); + s_singletonOpenGL->setDrawHighlightedEndPoints(this->userInputBordersModeProcessor->isHighlightBorderEndPoints()); } const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); @@ -553,13 +592,14 @@ BrainOpenGLWidget::paintGL() } if (this->selectedUserInputProcessor == userInputBordersModeProcessor) { - this->openGL->setBorderBeingDrawn(this->borderBeingDrawn); + s_singletonOpenGL->setBorderBeingDrawn(this->borderBeingDrawn); } else { - this->openGL->setBorderBeingDrawn(NULL); + s_singletonOpenGL->setBorderBeingDrawn(NULL); } - this->openGL->drawModels(GuiManager::get()->getBrain(), - this->context(), + s_singletonOpenGL->drawModels(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, this->drawingViewportContents); /* @@ -1088,8 +1128,9 @@ BrainOpenGLWidget::performIdentification(const int x, idManager->getVoxelEditingIdentification()->setEnabledForSelection(false); if (idViewport != NULL) { - this->openGL->selectModel(GuiManager::get()->getBrain(), - this->context(), + s_singletonOpenGL->selectModel(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, idViewport, x, y, @@ -1149,8 +1190,9 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int idX = x - vp[0]; const int idY = y - vp[1]; */ - this->openGL->selectModel(GuiManager::get()->getBrain(), - this->context(), + s_singletonOpenGL->selectModel(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, idViewport, x, y, @@ -1212,8 +1254,9 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi const int idX = x - vp[0]; const int idY = y - vp[1]; */ - this->openGL->selectModel(GuiManager::get()->getBrain(), - this->context(), + s_singletonOpenGL->selectModel(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, idViewport, x, y, @@ -1266,8 +1309,9 @@ BrainOpenGLWidget::performProjection(const int x, const int idX = x - vp[0]; const int idY = y - vp[1]; */ - this->openGL->projectToModel(GuiManager::get()->getBrain(), - this->context(), + s_singletonOpenGL->projectToModel(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, projectionViewport, x, y, @@ -1678,7 +1722,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) * region caused by aspect locking that needs to * be excluded. */ - BrainOpenGLTextureManager* textureManager = this->openGL->getTextureManager(); + BrainOpenGLTextureManager* textureManager = s_singletonOpenGL->getTextureManager(); CaretAssert(textureManager); textureManager->deleteAllTexturesForWindow(this->windowIndex); @@ -1686,7 +1730,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) outputImageHeight); image = pixmap.toImage(); textureManager->deleteAllTexturesForWindow(this->windowIndex); - this->openGL->setTextRenderer(createTextRenderer()); + s_singletonOpenGL->setTextRenderer(createTextRenderer()); #endif } break; @@ -1700,7 +1744,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) imageCaptureEvent->setImage(image); uint8_t backgroundColor[3]; - this->openGL->getBackgroundColor(backgroundColor); + s_singletonOpenGL->getBackgroundColor(backgroundColor); imageCaptureEvent->setBackgroundColor(backgroundColor); } diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index a426da116..6d4961b0c 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -22,6 +22,8 @@ */ /*LICENSE_END*/ +#include + #include "CaretOpenGLInclude.h" #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET @@ -103,6 +105,8 @@ namespace caret { std::vector getViewportContent() const; + bool isOpenGLContextSharingValid() const; + protected: virtual void initializeGL(); @@ -148,8 +152,6 @@ namespace caret { void captureImage(EventImageCapture* imageCaptureEvent); - BrainOpenGL* openGL; - const int32_t windowIndex; /** Do not own text renderer so DO NOT delete */ @@ -192,12 +194,24 @@ namespace caret { bool m_mousePositionValid; CaretPointer m_mousePositionEvent; + bool m_openGLContextSharingValid = false; + + void* m_contextShareGroupPointer = NULL; + static bool s_defaultGLFormatInitialized; + + static std::set s_brainOpenGLWidgets; + + static BrainOpenGL* s_singletonOpenGL; + + }; #ifdef __BRAIN_OPENGL_WIDGET_DEFINE__ - const int32_t BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE = 0; //10; - bool BrainOpenGLWidget::s_defaultGLFormatInitialized = false; + const int32_t BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE = 0; //10; + bool BrainOpenGLWidget::s_defaultGLFormatInitialized = false; + std::set BrainOpenGLWidget::s_brainOpenGLWidgets; + BrainOpenGL* BrainOpenGLWidget::s_singletonOpenGL = NULL; #endif // __BRAIN_OPENGL_WIDGET_DEFINE__ } // namespace diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 7a193d3f0..80f603155 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -634,12 +634,21 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, /* * Did OpenGL Context sharing fail? */ - if ( ! bbw->isOpenGLWidgetSharingContext()) { + if ( ! bbw->isOpenGLContextSharingValid()) { delete bbw; errorMessageOut = ("There has been a failure when creating an OpenGL Widget " "with a \"shared context\" for the new window. " "This may be caused by a limitation of the OpenGL graphics or the " - "windowing system on your computer."); + "windowing system on your computer.\n" + "\n" + "Please restart wb_view and report this problem as a bug using " + "Help Menu --> Report a Workbench Bug...\n" + "\n" + "You will be able to continue using wb_view but you will not " + "be able to have more than one window open."); + if (windowIndex >= 0) { + m_brainBrowserWindows[windowIndex] = NULL; + } return NULL; } diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 504b22d20..0cf4ab365 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -420,7 +420,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration */ if (restoreToTabTiles) { - CaretPointer brainOpenGL(createBrainOpenGL(windowIndex)); + CaretPointer brainOpenGL(createBrainOpenGL()); const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! tileTabsConfigString.isEmpty()) { @@ -478,7 +478,8 @@ OperationShowScene::useParameters(OperationParameters* myParams, windowViewport, tabIndexToHighlight); - brainOpenGL->drawModels(brain, + brainOpenGL->drawModels(windowIndex, + brain, mesaContext, viewports); @@ -505,7 +506,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, } } else { - CaretPointer brainOpenGL(createBrainOpenGL(windowIndex)); + CaretPointer brainOpenGL(createBrainOpenGL()); /* * Restore toolbar @@ -535,7 +536,8 @@ OperationShowScene::useParameters(OperationParameters* myParams, std::vector viewportContents; viewportContents.push_back(content); - brainOpenGL->drawModels(brain, + brainOpenGL->drawModels(windowIndex, + brain, mesaContext, viewportContents); @@ -708,13 +710,11 @@ OperationShowScene::getToolBoxSize(const SceneClass* toolBoxClass, /** * Create OpenGL Rendering. * - * @param windowIndex - * Index of window. * @return * BrainOpenGL. */ BrainOpenGLFixedPipeline* -OperationShowScene::createBrainOpenGL(const int32_t windowIndex) +OperationShowScene::createBrainOpenGL() { /* * The OpenGL rendering takes ownership of the text renderer @@ -742,8 +742,7 @@ OperationShowScene::createBrainOpenGL(const int32_t windowIndex) * will occur as the OpenGL context is invalid when things such as * display lists or buffers are deleted. */ - BrainOpenGLFixedPipeline* brainOpenGL = new BrainOpenGLFixedPipeline(windowIndex, - textRenderer); + BrainOpenGLFixedPipeline* brainOpenGL = new BrainOpenGLFixedPipeline(textRenderer); brainOpenGL->initializeOpenGL(); return brainOpenGL; diff --git a/src/Operations/OperationShowScene.h b/src/Operations/OperationShowScene.h index 0c09eacb6..30e177cc6 100644 --- a/src/Operations/OperationShowScene.h +++ b/src/Operations/OperationShowScene.h @@ -43,7 +43,7 @@ namespace caret { static bool isShowSceneCommandAvailable(); private: - static BrainOpenGLFixedPipeline* createBrainOpenGL(const int32_t windowIndex); + static BrainOpenGLFixedPipeline* createBrainOpenGL(); static void writeImage(const AString& imageFileName, const int32_t imageIndex, -- GitLab From f5a7c4cda479ad4d74fa48b435dd15497c52d26f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 12 May 2017 11:30:22 -0500 Subject: [PATCH 269/755] Fixed crash when no files loaded (except scene) and Save/Manage Files launched. Crash due to no Chart Overlays valid. --- src/Brain/BrowserTabContent.cxx | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 9dee387dd..0b25e281d 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1886,19 +1886,21 @@ BrowserTabContent::getFilesDisplayedInTab(std::vector& displayed case ModelTypeEnum::MODEL_TYPE_CHART_TWO: { const ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(tabIndex); - const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); - for (int32_t i = 0; i < numOverlays; i++) { - const ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); - if (chartOverlay->isEnabled()) { - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; - int32_t selectedIndex = -1; - chartOverlay->getSelectionData(mapFile, - selectedIndexType, - selectedIndex); - - if (mapFile != NULL) { - displayedDataFiles.insert(mapFile); + if (overlaySet != NULL) { + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + const ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); + if (chartOverlay->isEnabled()) { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + + if (mapFile != NULL) { + displayedDataFiles.insert(mapFile); + } } } } -- GitLab From d115187f85fc8813cfebab0f3a3419a5ab19d199 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 12 May 2017 11:43:26 -0500 Subject: [PATCH 270/755] Revising management of textures since all OpenGL windows share an OpenGL context. Also added a graphics primitive for use with a texture. --- src/Annotations/AnnotationImage.cxx | 27 + src/Annotations/AnnotationImage.h | 6 + src/Annotations/CMakeLists.txt | 1 + src/Brain/BrainOpenGL.cxx | 105 +++- src/Brain/BrainOpenGL.h | 20 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 35 +- src/Common/EventManager.cxx | 3 +- src/Common/EventTypeEnum.cxx | 9 +- src/Common/EventTypeEnum.h | 6 +- src/Graphics/CMakeLists.txt | 8 + .../EventGraphicsOpenGLCreateTextureName.cxx | 102 ++++ .../EventGraphicsOpenGLCreateTextureName.h | 64 ++ .../EventGraphicsOpenGLDeleteTextureName.cxx | 80 +++ .../EventGraphicsOpenGLDeleteTextureName.h | 60 ++ src/Graphics/GraphicsEngineDataOpenGL.cxx | 561 +++++++++++++++--- src/Graphics/GraphicsEngineDataOpenGL.h | 35 +- src/Graphics/GraphicsOpenGLTextureName.cxx | 77 +++ src/Graphics/GraphicsOpenGLTextureName.h | 75 +++ src/Graphics/GraphicsPrimitive.cxx | 153 ++++- src/Graphics/GraphicsPrimitive.h | 40 ++ .../GraphicsPrimitiveSelectionHelper.cxx | 5 +- src/Graphics/GraphicsPrimitiveV3f.cxx | 16 +- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 3 +- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 3 +- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 176 ++++++ src/Graphics/GraphicsPrimitiveV3fT3f.h | 78 +++ 26 files changed, 1626 insertions(+), 122 deletions(-) create mode 100644 src/Graphics/EventGraphicsOpenGLCreateTextureName.cxx create mode 100644 src/Graphics/EventGraphicsOpenGLCreateTextureName.h create mode 100644 src/Graphics/EventGraphicsOpenGLDeleteTextureName.cxx create mode 100644 src/Graphics/EventGraphicsOpenGLDeleteTextureName.h create mode 100644 src/Graphics/GraphicsOpenGLTextureName.cxx create mode 100644 src/Graphics/GraphicsOpenGLTextureName.h create mode 100644 src/Graphics/GraphicsPrimitiveV3fT3f.cxx create mode 100644 src/Graphics/GraphicsPrimitiveV3fT3f.h diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index 8baf0e515..d7135f1ed 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -24,7 +24,9 @@ #undef __ANNOTATION_IMAGE_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" #include "DrawnWithOpenGLTextureInfo.h" +#include "GraphicsPrimitiveV3fT3F.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -270,6 +272,31 @@ AnnotationImage::getDrawWithOpenGLTextureInfo() const return m_drawnWithOpenGLTextureInfo; } +/** + * @return The graphics primitive for drawing the image as a texture. + */ +GraphicsPrimitiveV3fT3F* +AnnotationImage::getGraphicsPrimitive() const +{ + if (m_graphicsPrimitive == NULL) { + if ( ! m_imageBytesRGBA.empty()) { + GraphicsPrimitiveV3fT3F* primitive = GraphicsPrimitive::newPrimitiveV3fT3F(GraphicsPrimitive::PrimitiveType::QUADS, + &m_imageBytesRGBA[0], + m_imageWidth, + m_imageHeight); + primitive->addVertex(50, 50, 0.0, 0.0); + primitive->addVertex(250, 50, 1.0, 0.0); + primitive->addVertex(250, 250, 1.0, 1.0); + primitive->addVertex(50, 250, 0.0, 1.0); + m_graphicsPrimitive.reset(primitive); + + CaretLogWarning("Need to be able to override coordinates"); + } + } + + return m_graphicsPrimitive.get(); +} + /** * Save subclass data to the scene. * diff --git a/src/Annotations/AnnotationImage.h b/src/Annotations/AnnotationImage.h index f5c2316d5..8cb036f78 100644 --- a/src/Annotations/AnnotationImage.h +++ b/src/Annotations/AnnotationImage.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include "AnnotationTwoDimensionalShape.h" #include "CaretPointer.h" @@ -30,6 +31,8 @@ namespace caret { + class GraphicsPrimitiveV3fT3F; + class AnnotationImage : public AnnotationTwoDimensionalShape, public DrawnWithOpenGLTextureInterface { public: @@ -63,6 +66,7 @@ namespace caret { virtual const DrawnWithOpenGLTextureInfo* getDrawWithOpenGLTextureInfo() const; + GraphicsPrimitiveV3fT3F* getGraphicsPrimitive() const; // ADD_NEW_METHODS_HERE @@ -93,6 +97,8 @@ namespace caret { CaretPointer m_drawnWithOpenGLTextureInfo; + mutable std::unique_ptr m_graphicsPrimitive; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 5d4e5c1b7..324754d60 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -114,6 +114,7 @@ TARGET_LINK_LIBRARIES(Annotations ${CARET_QT5_LINK}) # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Nifti ) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 9742462db..26543ab0e 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -33,9 +33,12 @@ #include "CaretPreferences.h" #include "DummyFontTextRenderer.h" #include "EventGraphicsOpenGLCreateBufferObject.h" +#include "EventGraphicsOpenGLCreateTextureName.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" +#include "EventGraphicsOpenGLDeleteTextureName.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" +#include "GraphicsOpenGLTextureName.h" #include "Model.h" #include "SessionManager.h" @@ -58,7 +61,9 @@ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) m_drawHighlightedEndPoints = false; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME); } /** @@ -108,6 +113,31 @@ BrainOpenGL::receiveEvent(Event* event) bufferName)); createBufferEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME) { + EventGraphicsOpenGLCreateTextureName* createTextureEvent + = dynamic_cast(event); + CaretAssert(createTextureEvent); + + if (m_contextSharingGroupPointer == NULL) { + AString msg("PROGRAM ERROR: " + "A request for a new OpenGL Texture Name has been made. " + "However, there is no OpenGL context currently active so " + "a texture cannot be created. This is an error in the " + "code and it is likely that the software will crash."); + createTextureEvent->setErrorMessage(msg); + createTextureEvent->setOpenGLTextureName(NULL); + CaretAssertMessage(0, msg); + CaretLogSevere(msg); + return; + } + + GLuint textureName = 0; + glGenTextures(1, &textureName); + + createTextureEvent->setOpenGLTextureName(new GraphicsOpenGLTextureName(m_contextSharingGroupPointer, + textureName)); + createTextureEvent->setEventProcessed(); + } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT) { QMutexLocker locker(&m_buffersForDeletionLaterMutex); @@ -127,6 +157,25 @@ BrainOpenGL::receiveEvent(Event* event) deleteBufferEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME) { + QMutexLocker locker(&m_texturesForDeletionLaterMutex); + + EventGraphicsOpenGLDeleteTextureName* deleteTextureEvent + = dynamic_cast(event); + CaretAssert(deleteTextureEvent); + const GraphicsOpenGLTextureName* textureName = deleteTextureEvent->getOpenGLTextureName(); + if (textureName != NULL) { + /* + * Textures names are created within an OpenGL context and must + * be deleted within that OpenGL context. + */ + m_texturesForDeletionLater.emplace(m_texturesForDeletionLater.end(), + textureName->getOpenGLContextPointer(), + textureName->getTextureName()); + } + + deleteTextureEvent->setEventProcessed(); + } } /** @@ -152,7 +201,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, brain, viewportContents); - deleteUnusedBuffers(); + deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } @@ -197,7 +246,7 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, mouseY, applySelectionBackgroundFiltering); - deleteUnusedBuffers(); + deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } @@ -239,7 +288,7 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, mouseX, mouseY, projectionOut); - deleteUnusedBuffers(); + deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } @@ -250,24 +299,23 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, * is current. */ void -BrainOpenGL::deleteUnusedBuffers() +BrainOpenGL::deleteUnusedOpenGLNames() { - //if ( ! m_unusedBufferIdentifiers.empty()) { if ( ! m_buffersForDeletionLater.empty()) { QMutexLocker locker(&m_buffersForDeletionLaterMutex); - std::vector otherContextBufferIdentifiers; + std::vector otherContextBufferIdentifiers; std::vector bufferNames; for (auto bufferInfo : m_buffersForDeletionLater) { if (bufferInfo.m_openglContextPointer == m_contextSharingGroupPointer) { - if (glIsBuffer(bufferInfo.m_bufferName)) { - bufferNames.push_back(bufferInfo.m_bufferName); + if (glIsBuffer(bufferInfo.m_name)) { + bufferNames.push_back(bufferInfo.m_name); } else { CaretLogWarning("Attempting to delete invalid OpenGL buffer ID: " - + AString::number(bufferInfo.m_bufferName)); + + AString::number(bufferInfo.m_name)); } } else { @@ -286,7 +334,44 @@ BrainOpenGL::deleteUnusedBuffers() if ( ! m_buffersForDeletionLater.empty()) { CaretLogWarning("Not deleting " + AString::number(m_buffersForDeletionLater.size()) - + " in another OpenGL Context."); + + " buffers in another OpenGL Context."); + } + } + + if ( ! m_texturesForDeletionLater.empty()) { + QMutexLocker locker(&m_texturesForDeletionLaterMutex); + + std::vector otherContextTextureIdentifiers; + + std::vector textureNames; + + for (auto textureInfo : m_texturesForDeletionLater) { + if (textureInfo.m_openglContextPointer == m_contextSharingGroupPointer) { + if (glIsTexture(textureInfo.m_name)) { + textureNames.push_back(textureInfo.m_name); + } + else { + CaretLogWarning("Attempting to delete invalid OpenGL Texture Name: " + + AString::number(textureInfo.m_name)); + } + } + else { + otherContextTextureIdentifiers.push_back(textureInfo); + } + } + + if ( ! textureNames.empty()) { + const GLuint* namesPointer = &textureNames[0]; + glDeleteTextures(textureNames.size(), + namesPointer); + m_texturesForDeletionLater.clear(); + } + + m_texturesForDeletionLater = otherContextTextureIdentifiers; + if ( ! m_texturesForDeletionLater.empty()) { + CaretLogWarning("Not deleting " + + AString::number(m_texturesForDeletionLater.size()) + + " textures in another OpenGL Context."); } } } diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 4190c5f32..6678604b5 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -189,24 +189,30 @@ namespace caret { inline void* getContextSharingGroupPointer() { return m_contextSharingGroupPointer; } private: - class DeleteBufferNameInfo { + class OpenGLNameInfo { public: - DeleteBufferNameInfo(void* openglContextPointer, - const GLuint bufferName) + OpenGLNameInfo(void* openglContextPointer, + const GLuint name) : m_openglContextPointer(openglContextPointer), - m_bufferName(bufferName) { } + m_name(name) { } void* m_openglContextPointer; - GLuint m_bufferName; + GLuint m_name; }; - void deleteUnusedBuffers(); + void deleteUnusedOpenGLNames(); /** prevents concurrent access to m_buffersForDeletionLater */ QMutex m_buffersForDeletionLaterMutex; /** use a mutex whenever accessing this member */ - std::vector m_buffersForDeletionLater; + std::vector m_buffersForDeletionLater; + + /** prevents concurrent access to m_texturesForDeletionLater */ + QMutex m_texturesForDeletionLaterMutex; + + /** use a mutex whenever accessing this member */ + std::vector m_texturesForDeletionLater; /** Pointer to the current OpenGL Context sharing group */ void* m_contextSharingGroupPointer = 0; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 2cd544820..bd92ba121 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -54,6 +54,8 @@ #include "DisplayPropertiesAnnotation.h" #include "EventBrowserTabGet.h" #include "EventManager.h" +#include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitiveV3fT3F.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -2494,15 +2496,30 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } } - drawImageBytesWithTexture(image->getDrawWithOpenGLTextureInfo(), - bottomLeft, - bottomRight, - topRight, - topLeft, - imageRgbaBytes, - imageWidth, - imageHeight); - drawnFlag = true; + GraphicsPrimitiveV3fT3F* primitive = image->getGraphicsPrimitive(); + if (primitive != NULL) { + if (primitive->isValid()) { + std::vector xyz; + xyz.insert(xyz.end(), bottomLeft, bottomLeft + 3); + xyz.insert(xyz.end(), bottomRight, bottomRight + 3); + xyz.insert(xyz.end(), topRight, topRight + 3); + xyz.insert(xyz.end(), topLeft, topLeft + 3); + primitive->replaceFloatXYZ(xyz); + + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + primitive); + } + drawnFlag = true; + } + +// drawImageBytesWithTexture(image->getDrawWithOpenGLTextureInfo(), +// bottomLeft, +// bottomRight, +// topRight, +// topLeft, +// imageRgbaBytes, +// imageWidth, +// imageHeight); if (drawForegroundFlag) { BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index e665c71c0..f6dd7541a 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -500,9 +500,10 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE: case EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW: case EventTypeEnum::EVENT_GET_VIEWPORT_SIZE: - case EventTypeEnum::EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT: + case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT: + case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW: case EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index d715ce018..a5aa58f96 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -168,12 +168,15 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, "EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT", "Create an OpenGL Buffer Object for an OpenGL Context")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME, + "EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME", + "Create an OpenGL Texture Name for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, "EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT", "Delete an OpenGL Buffer Object for an OpenGL Context")); - enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, - "EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS", - "Request OpenGL Graphics Engine delete buffers")); + enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, + "EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME", + "Delete an OpenGL Texture Name for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_CHART_OVERLAY_VALIDATE, "EVENT_CHART_OVERLAY_VALIDATE", "Validate a chart overlay for validity (it exists)")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 3ae6f72a3..25d589da1 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -108,12 +108,14 @@ public: EVENT_GET_TEXT_RENDERER_FOR_WINDOW, /** Get the viewport size for model, tab, window */ EVENT_GET_VIEWPORT_SIZE, - /** OpenGL graphics engine delete buffers */ - EVENT_GRAPHICS_ENGINE_OPENGL_DELETE_BUFFERS, /** Create a buffer object for an OpenGL context */ EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, + /** Create a texture name for an OpenGL context */ + EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME, /** Delete a buffer object for an OpenGL context */ EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, + /** Delete a texture name for an OpenGL context */ + EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, /** Update all graphics windows */ EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, /** Update graphics in a window */ diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index d8f11d61e..aad89faa0 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -34,26 +34,34 @@ ENDIF (OPENGL_FOUND) ADD_LIBRARY(Graphics CaretOpenGLInclude.h EventGraphicsOpenGLCreateBufferObject.h +EventGraphicsOpenGLCreateTextureName.h EventGraphicsOpenGLDeleteBufferObject.h +EventGraphicsOpenGLDeleteTextureName.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h +GraphicsOpenGLTextureName.h GraphicsPrimitive.h GraphicsPrimitiveSelectionHelper.h GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h +GraphicsPrimitiveV3fT3f.h EventGraphicsOpenGLCreateBufferObject.cxx +EventGraphicsOpenGLCreateTextureName.cxx EventGraphicsOpenGLDeleteBufferObject.cxx +EventGraphicsOpenGLDeleteTextureName.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx +GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx GraphicsPrimitiveSelectionHelper.cxx GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx +GraphicsPrimitiveV3fT3f.cxx ) # diff --git a/src/Graphics/EventGraphicsOpenGLCreateTextureName.cxx b/src/Graphics/EventGraphicsOpenGLCreateTextureName.cxx new file mode 100644 index 000000000..03ce073c8 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLCreateTextureName.cxx @@ -0,0 +1,102 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ +#include "EventGraphicsOpenGLCreateTextureName.h" +#undef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventGraphicsOpenGLDeleteTextureName.h" +#include "EventManager.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsOpenGLCreateTextureName + * \brief Create an OpenGL Texture Name + * \ingroup Graphics + * + * Creates an OpenGL Texture Name for the current context. + * There MUST BE an active OpenGL context when this event + * is processed. Otherwise, a texture name cannot be + * created and a program failure will likely occur. + */ + +/** + * Constructor. + */ +EventGraphicsOpenGLCreateTextureName::EventGraphicsOpenGLCreateTextureName() +: Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME) +{ + +} + +/** + * Destructor. + */ +EventGraphicsOpenGLCreateTextureName::~EventGraphicsOpenGLCreateTextureName() +{ + if (m_openglTextureName != NULL) { + /* + * If the caller did not get the texture name we need to delete it. + */ + CaretLogSevere("Create OpenGL Texture Name Event never had texture name retrieved. Will attempt to delete it."); + EventGraphicsOpenGLDeleteTextureName deleteEvent(m_openglTextureName); + EventManager::get()->sendEvent(deleteEvent.getPointer()); + } +} + +/** + * Set the OpenGL Texture Name + * + * @param openglTextureName + * The OpenGL Texture Name. This instance will take ownership of the texture so the caller + * MUST NOT ever reference the texture name after calling this method. + */ +void +EventGraphicsOpenGLCreateTextureName::setOpenGLTextureName(GraphicsOpenGLTextureName* openglTextureName) +{ + m_openglTextureName = openglTextureName; +} + +/** + * @return OpenGL Texture Name that was created or NULL if + * unable to create texture name due to no valid context. + * Caller takes ownership of the texture name. If this method + * is called more than once for an instance, NULL will be + * returned the second and all subsequent times. + */ +GraphicsOpenGLTextureName* +EventGraphicsOpenGLCreateTextureName::getOpenGLTextureName() const +{ + /* + * Do not let texture name be retrieved more than once. + */ + GraphicsOpenGLTextureName* textureNamePointer = m_openglTextureName; + m_openglTextureName = NULL; + + return textureNamePointer; +} + diff --git a/src/Graphics/EventGraphicsOpenGLCreateTextureName.h b/src/Graphics/EventGraphicsOpenGLCreateTextureName.h new file mode 100644 index 000000000..422303378 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLCreateTextureName.h @@ -0,0 +1,64 @@ +#ifndef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ +#define __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "Event.h" + + + +namespace caret { + + class GraphicsOpenGLTextureName; + + class EventGraphicsOpenGLCreateTextureName : public Event { + + public: + EventGraphicsOpenGLCreateTextureName(); + + virtual ~EventGraphicsOpenGLCreateTextureName(); + + void setOpenGLTextureName(GraphicsOpenGLTextureName* openglTextureName); + + GraphicsOpenGLTextureName* getOpenGLTextureName() const; + + // ADD_NEW_METHODS_HERE + + private: + EventGraphicsOpenGLCreateTextureName(const EventGraphicsOpenGLCreateTextureName&); + + EventGraphicsOpenGLCreateTextureName& operator=(const EventGraphicsOpenGLCreateTextureName&); + + mutable GraphicsOpenGLTextureName* m_openglTextureName = NULL; + + mutable bool m_openglTextureNameWasTakenFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ + // +#endif // __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ + +} // namespace +#endif //__EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ diff --git a/src/Graphics/EventGraphicsOpenGLDeleteTextureName.cxx b/src/Graphics/EventGraphicsOpenGLDeleteTextureName.cxx new file mode 100644 index 000000000..93c080114 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLDeleteTextureName.cxx @@ -0,0 +1,80 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ +#include "EventGraphicsOpenGLDeleteTextureName.h" +#undef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventTypeEnum.h" +#include "GraphicsOpenGLTextureName.h" + +using namespace caret; + + + +/** + * \class caret::EventGraphicsOpenGLDeleteTextureName + * \brief Delete an OpenGL Texture Name + * \ingroup Graphics + * + * Deletes an OpenGL Texture Name for the current context. + */ +/** + * Constructor. + * + * @param openglTextureName + * The OpenGL Texture Name whose texture name is deleted. + * After this event the openglTextureName should be deleted by the caller. + */ +EventGraphicsOpenGLDeleteTextureName::EventGraphicsOpenGLDeleteTextureName(const GraphicsOpenGLTextureName* openglTextureName) +: Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME), +m_openglTextureName(openglTextureName) +{ + +} + +/** + * Destructor. + */ +EventGraphicsOpenGLDeleteTextureName::~EventGraphicsOpenGLDeleteTextureName() +{ + if (this->getEventProcessCount() <= 0) { + CaretLogSevere("Deletion of OpenGL Texture Name=" + + AString::number(m_openglTextureName->getTextureName()) + + ", context pointer=" + + AString::number((qulonglong)m_openglTextureName->getOpenGLContextPointer()) + + " appears to have failed. The events processed count is zero and that " + "indicates that the event was not received in any listener or the " + "listener failed to set the event as processed."); + } +} + +/** + * @return OpenGL Texture Name that was deleted + */ +const GraphicsOpenGLTextureName* +EventGraphicsOpenGLDeleteTextureName::getOpenGLTextureName() const +{ + return m_openglTextureName; +} + diff --git a/src/Graphics/EventGraphicsOpenGLDeleteTextureName.h b/src/Graphics/EventGraphicsOpenGLDeleteTextureName.h new file mode 100644 index 000000000..a13ae67e4 --- /dev/null +++ b/src/Graphics/EventGraphicsOpenGLDeleteTextureName.h @@ -0,0 +1,60 @@ +#ifndef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ +#define __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "Event.h" + + + +namespace caret { + + class GraphicsOpenGLTextureName; + + class EventGraphicsOpenGLDeleteTextureName : public Event { + + public: + EventGraphicsOpenGLDeleteTextureName(const GraphicsOpenGLTextureName* openglTextureName); + + virtual ~EventGraphicsOpenGLDeleteTextureName(); + + const GraphicsOpenGLTextureName* getOpenGLTextureName() const; + + // ADD_NEW_METHODS_HERE + + private: + EventGraphicsOpenGLDeleteTextureName(const EventGraphicsOpenGLDeleteTextureName&); + + EventGraphicsOpenGLDeleteTextureName& operator=(const EventGraphicsOpenGLDeleteTextureName&); + + const GraphicsOpenGLTextureName* m_openglTextureName = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ + // +#endif // __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ + +} // namespace +#endif //__EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 06ddfa4f4..62a57a401 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -26,8 +26,10 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventGraphicsOpenGLCreateBufferObject.h" +#include "EventGraphicsOpenGLCreateTextureName.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" +#include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" @@ -94,10 +96,27 @@ GraphicsEngineDataOpenGL::deleteBuffers() deleteBufferObjectHelper(m_colorBufferObject); + deleteBufferObjectHelper(m_textureCoordinatesBufferObject); + for (auto mapBuff: m_alternativeColorBufferObjectMap) { deleteBufferObjectHelper(mapBuff.second); } m_alternativeColorBufferObjectMap.clear(); + + if (m_textureImageDataName != NULL) { + delete m_textureImageDataName; + m_textureImageDataName = NULL; + } +} + +/** + * Invalidate the coordinates after they have + * changed in the graphics primitive. + */ +void +GraphicsEngineDataOpenGL::invalidateCoordinates() +{ + m_reloadCoordinatesFlag = true; } /** @@ -128,18 +147,19 @@ GraphicsEngineDataOpenGL::getOpeGLBufferUsageHint(const GraphicsPrimitive* primi } /** - * Load the buffers with data from the grpahics primitive. + * Load the coordinate buffer. * * @param primitive * The graphics primitive that will be drawn. */ void -GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) +GraphicsEngineDataOpenGL::loadCoordinateBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLsizei coordinateCount = 0; switch (primitive->m_vertexType) { case GraphicsPrimitive::VertexType::FLOAT_XYZ: @@ -148,11 +168,20 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) coordinateCount = primitive->m_xyz.size(); const GLuint xyzSizeBytes = coordinateCount * sizeof(float); + CaretAssert(xyzSizeBytes > 0); const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; - EventGraphicsOpenGLCreateBufferObject createEvent; - EventManager::get()->sendEvent(createEvent.getPointer()); - m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); + /* + * Coordinate buffer may have been created. + * Coordinates may change but the number of coordinates does not change. + */ + if (m_coordinateBufferObject == NULL) { + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_coordinateBufferObject); + } + CaretAssert(m_coordinateBufferObject->getBufferObjectName()); glBindBuffer(GL_ARRAY_BUFFER, @@ -171,6 +200,23 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) m_arrayIndicesCount = 0; } + m_reloadCoordinatesFlag = false; +} + +/** + * Load the normal vector buffer. + * + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadNormalVectorBuffer(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + GLenum usageHint = getOpeGLBufferUsageHint(primitive); + + switch (primitive->m_normalVectorType) { case GraphicsPrimitive::NormalVectorType::NONE: break; @@ -178,6 +224,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) { m_normalVectorDataType = GL_FLOAT; const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); + CaretAssert(normalSizeBytes > 0); const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; EventGraphicsOpenGLCreateBufferObject createEvent; @@ -194,8 +241,24 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) } break; } +} + +/** + * Load the color buffer. + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + GLenum usageHint = getOpeGLBufferUsageHint(primitive); + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: { EventGraphicsOpenGLCreateBufferObject createEvent; @@ -207,6 +270,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) m_colorDataType = GL_FLOAT; const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); + CaretAssert(colorSizeBytes > 0); const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, @@ -228,6 +292,7 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) m_colorDataType = GL_UNSIGNED_BYTE; const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); + CaretAssert(colorSizeBytes > 0); const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, @@ -241,6 +306,294 @@ GraphicsEngineDataOpenGL::loadBuffers(GraphicsPrimitive* primitive) } } +/** + * Load the texture coordinate buffer. + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + GLenum usageHint = getOpeGLBufferUsageHint(primitive); + + switch (primitive->m_textureType) { + case GraphicsPrimitive::TextureType::FLOAT_STR: + { + EventGraphicsOpenGLCreateBufferObject createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_textureCoordinatesBufferObject = createEvent.getOpenGLBufferObject(); + CaretAssert(m_textureCoordinatesBufferObject->getBufferObjectName()); + + m_textureCoordinatesDataType = GL_FLOAT; + const GLuint textureSizeBytes = primitive->m_floatTextureSTR.size() * sizeof(float); + CaretAssert(textureSizeBytes > 0); + const GLvoid* textureDataPointer = (const GLvoid*)&primitive->m_floatTextureSTR[0]; + + glBindBuffer(GL_ARRAY_BUFFER, + m_textureCoordinatesBufferObject->getBufferObjectName()); + glBufferData(GL_ARRAY_BUFFER, + textureSizeBytes, + textureDataPointer, + usageHint); + + } + break; + case GraphicsPrimitive::TextureType::NONE: + break; + } +} + + +/** + * Load the buffers with data from the grpahics primitive. + * + * @param primitive + * The graphics primitive that will be drawn. + */ +void +GraphicsEngineDataOpenGL::loadAllBuffers(GraphicsPrimitive* primitive) +{ + loadCoordinateBuffer(primitive); + loadNormalVectorBuffer(primitive); + loadColorBuffer(primitive); + loadTextureCoordinateBuffer(primitive); + +// CaretAssert(primitive); +// +// GLenum usageHint = getOpeGLBufferUsageHint(primitive); +// +// GLsizei coordinateCount = 0; +// switch (primitive->m_vertexType) { +// case GraphicsPrimitive::VertexType::FLOAT_XYZ: +// m_coordinateDataType = GL_FLOAT; +// m_coordinatesPerVertex = 3; // X, Y, Z +// +// coordinateCount = primitive->m_xyz.size(); +// const GLuint xyzSizeBytes = coordinateCount * sizeof(float); +// CaretAssert(xyzSizeBytes > 0); +// const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; +// +// EventGraphicsOpenGLCreateBufferObject createEvent; +// EventManager::get()->sendEvent(createEvent.getPointer()); +// m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); +// CaretAssert(m_coordinateBufferObject->getBufferObjectName()); +// +// glBindBuffer(GL_ARRAY_BUFFER, +// m_coordinateBufferObject->getBufferObjectName()); +// glBufferData(GL_ARRAY_BUFFER, +// xyzSizeBytes, +// xyzDataPointer, +// usageHint); +// break; +// } +// +// if (m_coordinatesPerVertex > 0) { +// m_arrayIndicesCount = coordinateCount / m_coordinatesPerVertex; +// } +// else { +// m_arrayIndicesCount = 0; +// } +// +// switch (primitive->m_normalVectorType) { +// case GraphicsPrimitive::NormalVectorType::NONE: +// break; +// case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: +// { +// m_normalVectorDataType = GL_FLOAT; +// const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); +// CaretAssert(normalSizeBytes > 0); +// const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; +// +// EventGraphicsOpenGLCreateBufferObject createEvent; +// EventManager::get()->sendEvent(createEvent.getPointer()); +// m_normalVectorBufferObject = createEvent.getOpenGLBufferObject(); +// CaretAssert(m_normalVectorBufferObject->getBufferObjectName()); +// +// glBindBuffer(GL_ARRAY_BUFFER, +// m_normalVectorBufferObject->getBufferObjectName()); +// glBufferData(GL_ARRAY_BUFFER, +// normalSizeBytes, +// normalDataPointer, +// usageHint); +// } +// break; +// } +// +// switch (primitive->m_colorType) { +// case GraphicsPrimitive::ColorType::NONE: +// break; +// case GraphicsPrimitive::ColorType::FLOAT_RGBA: +// { +// EventGraphicsOpenGLCreateBufferObject createEvent; +// EventManager::get()->sendEvent(createEvent.getPointer()); +// m_colorBufferObject = createEvent.getOpenGLBufferObject(); +// CaretAssert(m_colorBufferObject->getBufferObjectName()); +// +// m_componentsPerColor = 4; +// m_colorDataType = GL_FLOAT; +// +// const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); +// CaretAssert(colorSizeBytes > 0); +// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; +// +// glBindBuffer(GL_ARRAY_BUFFER, +// m_colorBufferObject->getBufferObjectName()); +// glBufferData(GL_ARRAY_BUFFER, +// colorSizeBytes, +// colorDataPointer, +// usageHint); +// } +// break; +// case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: +// { +// EventGraphicsOpenGLCreateBufferObject createEvent; +// EventManager::get()->sendEvent(createEvent.getPointer()); +// m_colorBufferObject = createEvent.getOpenGLBufferObject(); +// CaretAssert(m_colorBufferObject->getBufferObjectName()); +// +// m_componentsPerColor = 4; +// m_colorDataType = GL_UNSIGNED_BYTE; +// +// const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); +// CaretAssert(colorSizeBytes > 0); +// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; +// +// glBindBuffer(GL_ARRAY_BUFFER, +// m_colorBufferObject->getBufferObjectName()); +// glBufferData(GL_ARRAY_BUFFER, +// colorSizeBytes, +// colorDataPointer, +// usageHint); +// } +// break; +// } +// +// switch (primitive->m_textureType) { +// case GraphicsPrimitive::TextureType::FLOAT_STR: +// { +// EventGraphicsOpenGLCreateBufferObject createEvent; +// EventManager::get()->sendEvent(createEvent.getPointer()); +// m_textureCoordinatesBufferObject = createEvent.getOpenGLBufferObject(); +// CaretAssert(m_textureCoordinatesBufferObject->getBufferObjectName()); +// +// m_textureCoordinatesDataType = GL_FLOAT; +// const GLuint textureSizeBytes = primitive->m_floatTextureSTR.size() * sizeof(float); +// CaretAssert(textureSizeBytes > 0); +// const GLvoid* textureDataPointer = (const GLvoid*)&primitive->m_floatTextureSTR[0]; +// +// glBindBuffer(GL_ARRAY_BUFFER, +// m_textureCoordinatesBufferObject->getBufferObjectName()); +// glBufferData(GL_ARRAY_BUFFER, +// textureSizeBytes, +// textureDataPointer, +// usageHint); +// +// } +// break; +// case GraphicsPrimitive::TextureType::NONE: +// break; +// } +} + +/** + * If needed, load the texture buffer. + * Note that the texture buffer may be invalidated when + * an image is captures as the image capture wipes out all + * textures. + * + * @param primitive + * The graphics primitive that will be drawn. +*/ +void +GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitive) +{ + if (m_textureImageDataName != NULL) { + return; + } + + switch (primitive->m_textureType) { + case GraphicsPrimitive::TextureType::FLOAT_STR: + { + const int32_t imageWidth = primitive->m_textureImageWidth; + const int32_t imageHeight = primitive->m_textureImageHeight; + const int32_t imageNumberOfBytes = imageWidth * imageHeight * 4; + if (imageNumberOfBytes <= 0) { + CaretLogWarning("Invalid texture (empty data) for drawing primitive with texture"); + return; + } + if (imageNumberOfBytes != static_cast(primitive->m_textureImageBytesRGBA.size())) { + CaretLogWarning("Image bytes size incorrect for image width/height"); + return; + } + + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + + const GLubyte* imageBytesRGBA = &primitive->m_textureImageBytesRGBA[0]; + EventGraphicsOpenGLCreateTextureName createEvent; + EventManager::get()->sendEvent(createEvent.getPointer()); + m_textureImageDataName = createEvent.getOpenGLTextureName(); + CaretAssert(m_textureImageDataName); + + const GLuint openGLTextureName = m_textureImageDataName->getTextureName(); + + glBindTexture(GL_TEXTURE_2D, openGLTextureName); + + + bool useMipMapFlag = true; + if (useMipMapFlag) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + const int errorCode = gluBuild2DMipmaps(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D + GL_RGBA, // number of components + imageWidth, // width of image + imageHeight, // height of image + GL_RGBA, // format of the pixel data + GL_UNSIGNED_BYTE, // data type of pixel data + imageBytesRGBA); // pointer to image data + if (errorCode != 0) { + useMipMapFlag = false; + + const GLubyte* errorChars = gluErrorString(errorCode); + if (errorChars != NULL) { + const QString errorText = ("ERROR building mipmaps for annotation image: " + + AString((char*)errorChars)); + CaretLogSevere(errorText); + } + } + } + + if ( ! useMipMapFlag) { + CaretAssertToDoFatal(); // image must be 2^N by 2^M + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D + 0, // level of detail 0=base, n is nth mipmap reduction + GL_RGBA, // number of components + imageWidth, // width of image + imageHeight, // height of image + 0, // border + GL_RGBA, // format of the pixel data + GL_UNSIGNED_BYTE, // data type of pixel data + imageBytesRGBA); // pointer to image data + } + + glBindTexture(GL_TEXTURE_2D, 0); + glPopClientAttrib(); + } + break; + case GraphicsPrimitive::TextureType::NONE: + break; + } +} + + /** * Load the buffer for the given alternative color identifier. If the buffer * was previously loaded, no action is taken. @@ -267,6 +620,9 @@ GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitiv GLenum usageHint = getOpeGLBufferUsageHint(primitive); switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: { const std::vector& alternativeFloatRGBA = primitive->getAlternativeFloatRGBAProtected(alternativeColorIdentifier); @@ -565,9 +921,19 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, openglData = new GraphicsEngineDataOpenGL(openglContextPointer); primitive->setGraphicsEngineDataForOpenGL(openglData); - openglData->loadBuffers(primitive); + openglData->loadAllBuffers(primitive); + } + else { + /* + * Coordinates may get updated. + */ + if (openglData->m_reloadCoordinatesFlag) { + openglData->loadCoordinateBuffer(primitive); + } } + openglData->loadTextureImageDataBuffer(primitive); + if (openglContextPointer != openglData->getOpenGLContextPointer()) { const AString msg("Only one OpenGL graphics context is allowed. Have there been " "changes made to QGLWidget creation?"); @@ -602,6 +968,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, case PrivateDrawMode::DRAW_SELECTION: break; } + /* * Setup vertices for drawing */ @@ -627,88 +994,126 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, glDisableClientState(GL_NORMAL_ARRAY); } + bool hasColorFlag = false; + switch (primitive->getColorType()) { + case GraphicsPrimitive::ColorType::NONE: + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + hasColorFlag = true; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + hasColorFlag = true; + break; + } /* * Setup colors for drawing */ GLuint localColorBufferName = 0; - switch (drawMode) { - case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: - { - glEnableClientState(GL_COLOR_ARRAY); - CaretAssert(glIsBuffer(alternativeColorBufferObject->getBufferObjectName())); - glBindBuffer(GL_ARRAY_BUFFER, alternativeColorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); - } - break; - case PrivateDrawMode::DRAW_COLOR_SOLID: - { - const int32_t numberOfVertices = primitive->m_xyz.size() / 3; - if (numberOfVertices > 0) { - glGenBuffers(1, &localColorBufferName); - CaretAssert(localColorBufferName > 0); - - const GLint componentsPerColor = 4; - const GLenum colorDataType = GL_FLOAT; - - std::vector colorRGBA(numberOfVertices * componentsPerColor); - for (int32_t i = 0; i < numberOfVertices; i++) { - const int32_t i4 = i * 4; - CaretAssertVectorIndex(colorRGBA, i4 + 3); - colorRGBA[i4] = solidColorRGBA[0]; - colorRGBA[i4+1] = solidColorRGBA[1]; - colorRGBA[i4+2] = solidColorRGBA[2]; - colorRGBA[i4+3] = solidColorRGBA[3]; - } - - const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); - const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; - glBindBuffer(GL_ARRAY_BUFFER, - localColorBufferName); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); + if (hasColorFlag) { + switch (drawMode) { + case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: + { glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + CaretAssert(glIsBuffer(alternativeColorBufferObject->getBufferObjectName())); + glBindBuffer(GL_ARRAY_BUFFER, alternativeColorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); } - } - break; - case PrivateDrawMode::DRAW_NORMAL: - { - glEnableClientState(GL_COLOR_ARRAY); - CaretAssert(glIsBuffer(openglData->m_colorBufferObject->getBufferObjectName())); - glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); - } - break; - case PrivateDrawMode::DRAW_SELECTION: - { - const int32_t numberOfVertices = primitive->m_xyz.size() / 3; - if (numberOfVertices > 0) { - glGenBuffers(1, &localColorBufferName); - CaretAssert(localColorBufferName > 0); - - const GLint componentsPerColor = 4; - const GLenum colorDataType = GL_UNSIGNED_BYTE; - - const std::vector selectionRGBA = primitiveSelectionHelper->getSelectionEncodedRGBA(); - CaretAssert((selectionRGBA.size() / 4) == numberOfVertices); - - const GLuint colorSizeBytes = selectionRGBA.size() * sizeof(GLubyte); - const GLvoid* colorDataPointer = (const GLvoid*)&selectionRGBA[0]; - glBindBuffer(GL_ARRAY_BUFFER, - localColorBufferName); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); + break; + case PrivateDrawMode::DRAW_COLOR_SOLID: + { + const int32_t numberOfVertices = primitive->m_xyz.size() / 3; + if (numberOfVertices > 0) { + glGenBuffers(1, &localColorBufferName); + CaretAssert(localColorBufferName > 0); + + const GLint componentsPerColor = 4; + const GLenum colorDataType = GL_FLOAT; + + std::vector colorRGBA(numberOfVertices * componentsPerColor); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(colorRGBA, i4 + 3); + colorRGBA[i4] = solidColorRGBA[0]; + colorRGBA[i4+1] = solidColorRGBA[1]; + colorRGBA[i4+2] = solidColorRGBA[2]; + colorRGBA[i4+3] = solidColorRGBA[3]; + } + + const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); + const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; + glBindBuffer(GL_ARRAY_BUFFER, + localColorBufferName); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + } + } + break; + case PrivateDrawMode::DRAW_NORMAL: + { glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + CaretAssert(glIsBuffer(openglData->m_colorBufferObject->getBufferObjectName())); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); + glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); } + break; + case PrivateDrawMode::DRAW_SELECTION: + { + const int32_t numberOfVertices = primitive->m_xyz.size() / 3; + if (numberOfVertices > 0) { + glGenBuffers(1, &localColorBufferName); + CaretAssert(localColorBufferName > 0); + + const GLint componentsPerColor = 4; + const GLenum colorDataType = GL_UNSIGNED_BYTE; + + const std::vector selectionRGBA = primitiveSelectionHelper->getSelectionEncodedRGBA(); + CaretAssert((selectionRGBA.size() / 4) == numberOfVertices); + + const GLuint colorSizeBytes = selectionRGBA.size() * sizeof(GLubyte); + const GLvoid* colorDataPointer = (const GLvoid*)&selectionRGBA[0]; + glBindBuffer(GL_ARRAY_BUFFER, + localColorBufferName); + glBufferData(GL_ARRAY_BUFFER, + colorSizeBytes, + colorDataPointer, + GL_STREAM_DRAW); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); + } + } + break; } + } + + bool hasTextureFlag = false; + switch (primitive->getTextureType()) { + case GraphicsPrimitive::TextureType::NONE: + break; + case GraphicsPrimitive::TextureType::FLOAT_STR: + hasTextureFlag = true; break; } + /* + * Setup textures for drawing + */ + if (hasTextureFlag + && (drawMode == PrivateDrawMode::DRAW_NORMAL) + && (openglData->m_textureImageDataName->getTextureName())) { + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, openglData->m_textureImageDataName->getTextureName()); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + CaretAssert(glIsBuffer(openglData->m_textureCoordinatesBufferObject->getBufferObjectName())); + glBindBuffer(GL_ARRAY_BUFFER, openglData->m_textureCoordinatesBufferObject->getBufferObjectName()); + glTexCoordPointer(3, openglData->m_textureCoordinatesDataType, 0, (GLvoid*)0); + } + /* * Unbind buffers */ @@ -763,10 +1168,14 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (localColorBufferName > 0) { glDeleteBuffers(1, &localColorBufferName); } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); } /** diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index dc8b135ff..eb1d93a6a 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -30,6 +30,7 @@ namespace caret { class GraphicsOpenGLBufferObject; + class GraphicsOpenGLTextureName; class GraphicsPrimitive; class GraphicsPrimitiveSelectionHelper; @@ -42,11 +43,6 @@ namespace caret { void deleteBuffers(); - void loadBuffers(GraphicsPrimitive* primitive); - - GraphicsOpenGLBufferObject* loadAlternativeColorBuffer(GraphicsPrimitive* primitive, - const int32_t alternativeColorIdentifier); - static void draw(void* openglContextPointer, GraphicsPrimitive* primitive); @@ -67,6 +63,8 @@ namespace caret { const void* getOpenGLContextPointer() const; + void invalidateCoordinates(); + // ADD_NEW_METHODS_HERE private: @@ -74,13 +72,28 @@ namespace caret { DRAW_COLOR_ALTERNATIVE, DRAW_COLOR_SOLID, DRAW_NORMAL, - DRAW_SELECTION + DRAW_SELECTION, }; GraphicsEngineDataOpenGL(const GraphicsEngineDataOpenGL&); GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); + void loadAllBuffers(GraphicsPrimitive* primitive); + + void loadCoordinateBuffer(GraphicsPrimitive* primitive); + + void loadNormalVectorBuffer(GraphicsPrimitive* primitive); + + void loadColorBuffer(GraphicsPrimitive* primitive); + + void loadTextureCoordinateBuffer(GraphicsPrimitive* primitive); + + GraphicsOpenGLBufferObject* loadAlternativeColorBuffer(GraphicsPrimitive* primitive, + const int32_t alternativeColorIdentifier); + + void loadTextureImageDataBuffer(GraphicsPrimitive* primitive); + void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); static void drawPrivate(const PrivateDrawMode drawMode, @@ -102,6 +115,8 @@ namespace caret { GLint m_coordinatesPerVertex = 0; + bool m_reloadCoordinatesFlag = false; + GraphicsOpenGLBufferObject* m_normalVectorBufferObject = NULL; GLenum m_normalVectorDataType = GL_FLOAT; @@ -114,7 +129,13 @@ namespace caret { GLint m_componentsPerColor = 0; - // ADD_NEW_MEMBERS_HERE + GraphicsOpenGLBufferObject* m_textureCoordinatesBufferObject = NULL; + + GLenum m_textureCoordinatesDataType = GL_FLOAT; + + GraphicsOpenGLTextureName* m_textureImageDataName = NULL; + +// ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsOpenGLTextureName.cxx b/src/Graphics/GraphicsOpenGLTextureName.cxx new file mode 100644 index 000000000..2240fdbef --- /dev/null +++ b/src/Graphics/GraphicsOpenGLTextureName.cxx @@ -0,0 +1,77 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ +#include "GraphicsOpenGLTextureName.h" +#undef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ + +#include "CaretAssert.h" +#include "EventGraphicsOpenGLDeleteTextureName.h" +#include "EventManager.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLTextureName + * \brief Contains the OpenGL Texture Name and the context in which it was created. + * \ingroup Graphics + */ + +/** + * Constructor. + * + * @param openglContextPointer + * Pointer to OpenGL context in which texture name was created. + * @param textureName + * The OpenGL texture name. + */ +GraphicsOpenGLTextureName::GraphicsOpenGLTextureName(void* openglContextPointer, + const GLuint textureName) +: CaretObject(), +m_openglContextPointer(openglContextPointer), +m_textureName(textureName) +{ + +} + +/** + * Destructor. + */ +GraphicsOpenGLTextureName::~GraphicsOpenGLTextureName() +{ + if (m_textureName > 0) { + EventGraphicsOpenGLDeleteTextureName deleteEvent(this); + EventManager::get()->sendEvent(deleteEvent.getPointer()); + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsOpenGLTextureName::toString() const +{ + return "GraphicsOpenGLTextureName"; +} + diff --git a/src/Graphics/GraphicsOpenGLTextureName.h b/src/Graphics/GraphicsOpenGLTextureName.h new file mode 100644 index 000000000..b72157b30 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLTextureName.h @@ -0,0 +1,75 @@ +#ifndef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ +#define __GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretOpenGLInclude.h" +#include "CaretObject.h" + + + +namespace caret { + + class GraphicsOpenGLTextureName : public CaretObject { + + private: + GraphicsOpenGLTextureName(void* openglContextPointer, + const GLuint textureName); + + public: + virtual ~GraphicsOpenGLTextureName(); + + /** + * @return Pointer to OpenGL context in which texture name was created. + */ + inline void* getOpenGLContextPointer() const { return m_openglContextPointer; } + + /** + * @return The OpenGL Texture Name Name. + * While it is an unsigned interger, OpenGL refers to it as a "name". + */ + inline GLuint getTextureName() const { return m_textureName; } + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + GraphicsOpenGLTextureName(const GraphicsOpenGLTextureName&); + + GraphicsOpenGLTextureName& operator=(const GraphicsOpenGLTextureName&); + + void* m_openglContextPointer = NULL; + + const GLuint m_textureName = 0; + + friend class BrainOpenGL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ + // +#endif // __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index c9853e260..64dd63ced 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -30,6 +30,7 @@ #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsPrimitiveV3fT3F.h" using namespace caret; @@ -51,18 +52,22 @@ using namespace caret; * Type of the normal vectors. * @param colorType * Type of the colors. + * @param textureType + * Type of texture coordinates. * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitive::GraphicsPrimitive(const VertexType vertexType, const NormalVectorType normalVectorType, const ColorType colorType, + const TextureType textureType, const PrimitiveType primitiveType) : CaretObject(), EventListenerInterface(), m_vertexType(vertexType), m_normalVectorType(normalVectorType), m_colorType(colorType), + m_textureType(textureType), m_primitiveType(primitiveType) { @@ -87,6 +92,7 @@ GraphicsPrimitive::GraphicsPrimitive(const GraphicsPrimitive& obj) m_vertexType(obj.m_vertexType), m_normalVectorType(obj.m_normalVectorType), m_colorType(obj.m_colorType), +m_textureType(obj.m_textureType), m_primitiveType(obj.m_primitiveType) { this->copyHelperGraphicsPrimitive(obj); @@ -106,6 +112,11 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) m_unsignedByteRGBA = obj.m_unsignedByteRGBA; m_alternativeFloatRGBA = obj.m_alternativeFloatRGBA; m_alternativeUnsignedByteRGBA = obj.m_alternativeUnsignedByteRGBA; + m_floatTextureSTR = obj.m_floatTextureSTR; + m_textureImageBytesRGBA = obj.m_textureImageBytesRGBA; + m_textureImageWidth = obj.m_textureImageWidth; + m_textureImageHeight = obj.m_textureImageHeight; + m_graphicsEngineDataForOpenGL.reset(); } @@ -137,6 +148,8 @@ GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) } switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + break; case ColorType::FLOAT_RGBA: m_floatRGBA.reserve(numberOfVertices * 4); break; @@ -144,6 +157,14 @@ GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) m_unsignedByteRGBA.reserve(numberOfVertices * 4); break; } + + switch (m_textureType) { + case GraphicsPrimitive::TextureType::NONE: + break; + case GraphicsPrimitive::TextureType::FLOAT_STR: + m_floatTextureSTR.reserve(numberOfVertices * 3); + break; + } } /** @@ -201,18 +222,47 @@ GraphicsPrimitive::isValid() const break; } + bool haveRgbaFlag = false; uint32_t numColorRGBA = 0; switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + haveRgbaFlag = false; + break; case ColorType::FLOAT_RGBA: numColorRGBA = m_floatRGBA.size(); + haveRgbaFlag = true; break; case ColorType::UNSIGNED_BYTE_RGBA: numColorRGBA = m_unsignedByteRGBA.size(); + haveRgbaFlag = true; break; } - if ((numXYZ / 3) != (numColorRGBA / 4)) { - CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match RGBA size"); - return false; + if (haveRgbaFlag) { + if ((numXYZ / 3) != (numColorRGBA / 4)) { + CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match RGBA size"); + return false; + } + } + + bool haveTextureFlag = false; + uint32_t numTextureSTR = 0; + switch (m_textureType) { + case TextureType::NONE: + break; + case TextureType::FLOAT_STR: + numTextureSTR = m_floatTextureSTR.size(); + haveTextureFlag = true; + break; + } + if (haveTextureFlag) { + if (numXYZ != numTextureSTR) { + CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match Texture STR size"); + return false; + } + + if (m_textureImageBytesRGBA.empty()) { + CaretLogWarning("ERROR: GraphicsPrimitive has invalid texture data"); + } } switch (m_primitiveType) { @@ -395,6 +445,8 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const } switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + break; case ColorType::FLOAT_RGBA: s.appendWithNewLine("Color: " + AString::number(m_floatRGBA.size()) + " Float RGBA 0.0 to 1.0. "); if (includeAllDataFlag ) { @@ -423,6 +475,26 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } + switch (m_textureType) { + case TextureType::NONE: + break; + case TextureType::FLOAT_STR: + s.appendWithNewLine("Texture: " + AString::number(m_floatTextureSTR.size()) + " Float Texture 0.0 to 1.0. "); + s.appendWithNewLine(" Width: " + AString::number(m_textureImageWidth) + + " Height: " + AString::number(m_textureImageHeight)); + if (includeAllDataFlag ) { + s.append("\n "); + const int32_t count = static_cast(m_floatTextureSTR.size()); + for (int32_t i = 0; i < count; i++) { + s.append(AString::number(m_floatTextureSTR[i]) + " "); + if (((i+1) % 3) == 0) { + s.append("\n "); + } + } + } + break; + } + return s; } @@ -438,6 +510,8 @@ GraphicsPrimitive::isAlternativeColoringValid(const int32_t identifier) const bool validFlag = false; switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + break; case ColorType::FLOAT_RGBA: validFlag = isAlternativeFloatRGBAValidProtected(identifier); break; @@ -494,6 +568,32 @@ GraphicsPrimitive::isAlternativeUnsignedByteRGBAValidProtected(const int32_t ide return false; } +/** + * Replace the existing XYZ coordinates with the given + * XYZ coordinates. The existing and new coordinates + * MUST BE the same size. + * + * @param xyz + * The new XYZ coordinates. + */ +void +GraphicsPrimitive::replaceFloatXYZ(const std::vector& xyz) +{ + if (xyz.size() == m_xyz.size()) { + m_xyz = xyz; + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateCoordinates(); + } + } + else { + const AString msg("Replacement XYZ must be same size as existing xyz"); + CaretLogWarning(msg); + CaretAssertMessage(0, msg); + } +} + + /** * @return A reference to the alternative coloring. An empty vector is returned * if the alternative coloring data is invalid. @@ -559,6 +659,9 @@ GraphicsPrimitive::setAlternativeFloatRGBAProtected(const int32_t identifier, } switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case ColorType::FLOAT_RGBA: break; case ColorType::UNSIGNED_BYTE_RGBA: @@ -601,6 +704,9 @@ GraphicsPrimitive::setAlternativeUnsignedByteRGBAProtected(const int32_t identif } switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case ColorType::FLOAT_RGBA: { const AString msg("Alternative RGBA must match primitive color type which is float"); @@ -616,6 +722,34 @@ GraphicsPrimitive::setAlternativeUnsignedByteRGBAProtected(const int32_t identif rgbaByte)); } +/** + * Set the image for the texture. + * + * @param imageBytesRGBA + * Bytes containing the image data. 4 bytes per pixel. + * @param imageWidth + * Width of the actual image. + * @param imageHeight + * Height of the image. + */ +void +GraphicsPrimitive::setTextureImage(const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight) +{ + m_textureImageBytesRGBA.clear(); + m_textureImageWidth = -1; + m_textureImageHeight = -1; + + const int32_t numBytes = imageWidth * imageHeight * 4; + if (numBytes > 0) { + m_textureImageBytesRGBA.reserve(numBytes); + m_textureImageWidth = imageWidth; + m_textureImageHeight = imageHeight; + m_textureImageBytesRGBA.insert(m_textureImageBytesRGBA.end(), + imageBytesRGBA, imageBytesRGBA + numBytes); + } +} /** * Get the OpenGL graphics engine data in this instance. @@ -720,3 +854,16 @@ GraphicsPrimitive::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType pr return primitive; } +GraphicsPrimitiveV3fT3F* +GraphicsPrimitive::newPrimitiveV3fT3F(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight) +{ + GraphicsPrimitiveV3fT3F* primitive = new GraphicsPrimitiveV3fT3F(primitiveType, + imageBytesRGBA, + imageWidth, + imageHeight); + return primitive; +} + diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index c683aa390..5588e6da3 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -36,6 +36,7 @@ namespace caret { class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; + class GraphicsPrimitiveV3fT3F; class GraphicsPrimitive : public CaretObject, public EventListenerInterface { @@ -62,12 +63,24 @@ namespace caret { * Type of colors */ enum class ColorType { + /** No color components */ + NONE, /** Four float values per vertex containing Red, Green, Blue, Alpha ranging 0.0 to 1.0 */ FLOAT_RGBA, /** Four unsigned byte values per vertex containing Red, Green, Blue, Alpha ranging 0 to 255 */ UNSIGNED_BYTE_RGBA }; + /** + * Type of texture components + */ + enum class TextureType { + /** No texture coordinates */ + NONE, + /** Three float values per vertex contains S, T, and R texture coordinates */ + FLOAT_STR + }; + /** * Type of primitives for drawing * Descriptions are copied from the glVertex man page. @@ -156,6 +169,7 @@ namespace caret { GraphicsPrimitive(const VertexType vertexType, const NormalVectorType normalVectorType, const ColorType colorType, + const TextureType textureType, const PrimitiveType primitiveType); GraphicsPrimitive(const GraphicsPrimitive& obj); @@ -174,6 +188,11 @@ namespace caret { static GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); + static GraphicsPrimitiveV3fT3F* newPrimitiveV3fT3F(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight); + virtual ~GraphicsPrimitive(); void reserveForNumberOfVertices(const int32_t numberOfVertices); @@ -208,11 +227,18 @@ namespace caret { */ inline PrimitiveType getPrimitiveType() const { return m_primitiveType; } + /** + * @return Type of texture. + */ + inline TextureType getTextureType() const { return m_textureType; } + /** * @return The float coordinates. */ const std::vector& getFloatXYZ() const { return m_xyz; } + void replaceFloatXYZ(const std::vector& xyz); + GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); @@ -243,12 +269,18 @@ namespace caret { bool isAlternativeUnsignedByteRGBAValidProtected(const int32_t identifier) const; + void setTextureImage(const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight); + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; const ColorType m_colorType; + const TextureType m_textureType; + const PrimitiveType m_primitiveType; UsageType m_usageType = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; @@ -267,6 +299,14 @@ namespace caret { std::map> m_alternativeUnsignedByteRGBA; + std::vector m_floatTextureSTR; + + std::vector m_textureImageBytesRGBA; + + int32_t m_textureImageWidth = -1; + + int32_t m_textureImageHeight = -1; + private: void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index b13a28161..5dd2ca201 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -141,9 +141,12 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() m_selectionEncodedRGBA[indexRGBA+1] = green; m_selectionEncodedRGBA[indexRGBA+2] = blue; - uint8_t vertexAlpha = 0.0; + uint8_t vertexAlpha = 0; const int32_t vertexAlphaIndex = indexRGBA + 3; switch (colorType) { + case GraphicsPrimitive::ColorType::NONE: + vertexAlpha = 255; + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_floatRGBA, vertexAlphaIndex); diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index 6fb8412f8..919f210a0 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -50,6 +50,7 @@ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, : GraphicsPrimitive(VertexType::FLOAT_XYZ, NormalVectorType::NONE, ColorType::FLOAT_RGBA, + TextureType::NONE, primitiveType) { m_floatSolidRGBA[0] = rgba[0]; @@ -71,6 +72,7 @@ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, : GraphicsPrimitive(VertexType::FLOAT_XYZ, NormalVectorType::NONE, ColorType::UNSIGNED_BYTE_RGBA, + TextureType::NONE, primitiveType) { m_unsignedByteSolidRGBA[0] = rgba[0]; @@ -105,7 +107,10 @@ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) void GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) { - + for (int32_t i = 0; i < 4; i++) { + m_floatSolidRGBA[i] = obj.m_floatSolidRGBA[i]; + m_unsignedByteSolidRGBA[i] = obj.m_unsignedByteSolidRGBA[i]; + } } /** @@ -121,6 +126,9 @@ GraphicsPrimitiveV3f::addVertex(const float xyz[3]) xyz, xyz + 3); switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: m_floatRGBA.insert(m_floatRGBA.end(), m_floatSolidRGBA, m_floatSolidRGBA + 4); @@ -151,6 +159,9 @@ GraphicsPrimitiveV3f::addVertex(const float x, m_xyz.push_back(y); m_xyz.push_back(z); switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: m_floatRGBA.insert(m_floatRGBA.end(), m_floatSolidRGBA, m_floatSolidRGBA + 4); @@ -180,6 +191,9 @@ GraphicsPrimitiveV3f::addVertex(const float x, m_xyz.push_back(y); m_xyz.push_back(0.0); switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; case GraphicsPrimitive::ColorType::FLOAT_RGBA: m_floatRGBA.insert(m_floatRGBA.end(), m_floatSolidRGBA, m_floatSolidRGBA + 4); diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 103414ed8..1ccff81f3 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -44,6 +44,7 @@ GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveTy : GraphicsPrimitive(VertexType::FLOAT_XYZ, NormalVectorType::NONE, ColorType::FLOAT_RGBA, + TextureType::NONE, primitiveType) { @@ -73,7 +74,7 @@ GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& * Object that is copied. */ void -GraphicsPrimitiveV3fC4f::copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj) +GraphicsPrimitiveV3fC4f::copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& /*obj*/) { } diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 44614edad..017c83f3a 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -44,6 +44,7 @@ GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const PrimitiveType primitive : GraphicsPrimitive(VertexType::FLOAT_XYZ, NormalVectorType::NONE, ColorType::UNSIGNED_BYTE_RGBA, + TextureType::NONE, primitiveType) { @@ -73,7 +74,7 @@ GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4u * Object that is copied. */ void -GraphicsPrimitiveV3fC4ub::copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj) +GraphicsPrimitiveV3fC4ub::copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& /*obj*/) { } diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx new file mode 100644 index 000000000..313e245a1 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -0,0 +1,176 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ +#include "GraphicsPrimitiveV3fT3F.h" +#undef __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveV3fT3F + * \brief Primitive containing XYZ with and texture coordinates applied to all vertices. + * \ingroup Graphics + */ + +/** + * Constructor for solid color float RGBA. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + * @param imageBytesRGBA + * Bytes containing the image data. + * @param imageWidth + * Width of the actual image. + * @param imageHeight + * Height of the image. + */ +GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const PrimitiveType primitiveType, + const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::NONE, + ColorType::NONE, + TextureType::FLOAT_STR, + primitiveType) +{ + setTextureImage(imageBytesRGBA, + imageWidth, + imageHeight); +} + +/** + * Destructor. + */ +GraphicsPrimitiveV3fT3F::~GraphicsPrimitiveV3fT3F() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj) +: GraphicsPrimitive(obj) +{ + this->copyHelperGraphicsPrimitiveV3fT3F(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitiveV3fT3F::copyHelperGraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& /*obj*/) +{ + +} + +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + * @parma st + * Texture coordinates + */ +void +GraphicsPrimitiveV3fT3F::addVertex(const float xyz[3], + const float st[2]) +{ + m_xyz.insert(m_xyz.end(), + xyz, xyz + 3); + m_floatTextureSTR.push_back(st[0]); + m_floatTextureSTR.push_back(st[1]); + m_floatTextureSTR.push_back(0.0f); +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + * @param s + * S-coordinate of texture + * @param t + * T-coordinate of texture + */ +void +GraphicsPrimitiveV3fT3F::addVertex(const float x, + const float y, + const float z, + const float s, + const float t) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(z); + m_floatTextureSTR.push_back(s); + m_floatTextureSTR.push_back(t); + m_floatTextureSTR.push_back(0.0f); +} + +/** + * Add a 2D vertex. Z will be zero. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param s + * S-coordinate of texture + * @param t + * T-coordinate of texture + */ +void +GraphicsPrimitiveV3fT3F::addVertex(const float x, + const float y, + const float s, + const float t) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(0.0f); + m_floatTextureSTR.push_back(s); + m_floatTextureSTR.push_back(t); + m_floatTextureSTR.push_back(0.0f); +} + +/** + * Clone this primitive. + */ +GraphicsPrimitive* +GraphicsPrimitiveV3fT3F::clone() const +{ + GraphicsPrimitiveV3fT3F* obj = new GraphicsPrimitiveV3fT3F(*this); + return obj; +} + diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.h b/src/Graphics/GraphicsPrimitiveV3fT3f.h new file mode 100644 index 000000000..75907aef5 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.h @@ -0,0 +1,78 @@ +#ifndef __GRAPHICS_PRIMITIVE_V3F_T3F_H__ +#define __GRAPHICS_PRIMITIVE_V3F_T3F_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsPrimitive.h" + + + +namespace caret { + + class GraphicsPrimitiveV3fT3F : public GraphicsPrimitive { + + public: + GraphicsPrimitiveV3fT3F(const PrimitiveType primitiveType, + const uint8_t* imageBytesRGBA, + const int32_t imageWidth, + const int32_t imageHeight); + + virtual ~GraphicsPrimitiveV3fT3F(); + + GraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj); + + void addVertex(const float xyz[3], + const float st[2]); + + void addVertex(const float x, + const float y, + const float z, + const float s, + const float t); + + void addVertex(const float x, + const float y, + const float s, + const float t); + + virtual GraphicsPrimitive* clone() const; + + // ADD_NEW_METHODS_HERE + + private: + GraphicsPrimitiveV3fT3F& operator=(const GraphicsPrimitiveV3fT3F& obj); + + void copyHelperGraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_V3F_T3F_H__ -- GitLab From ad6cb8f9b5c3eb6026a6f45d1f2a0879230b528d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 31 May 2017 15:10:51 -0500 Subject: [PATCH 271/755] All OpenGL Graphics windows now share a common graphics context. As a result, there is no need to create textures, fonts, or buffers for each windows since they are now shared. --- src/Annotations/AnnotationImage.cxx | 44 +--- src/Annotations/AnnotationImage.h | 20 +- src/Brain/BrainOpenGL.cxx | 33 +-- src/Brain/BrainOpenGL.h | 5 - ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 234 +----------------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 17 -- src/Brain/BrainOpenGLFixedPipeline.cxx | 15 +- src/Brain/BrainOpenGLFixedPipeline.h | 10 +- src/Brain/BrainOpenGLTextureManager.cxx | 230 ----------------- src/Brain/BrainOpenGLTextureManager.h | 80 ------ src/Brain/CMakeLists.txt | 2 - src/Brain/EventGetBrainOpenGLTextRenderer.cxx | 14 +- src/Brain/EventGetBrainOpenGLTextRenderer.h | 6 +- src/Common/CMakeLists.txt | 5 - src/Common/DrawnWithOpenGLTextureInfo.cxx | 210 ---------------- src/Common/DrawnWithOpenGLTextureInfo.h | 68 ----- .../DrawnWithOpenGLTextureInterface.cxx | 92 ------- src/Common/DrawnWithOpenGLTextureInterface.h | 87 ------- src/Common/EventManager.cxx | 1 - src/Common/EventOpenGLTexture.cxx | 128 ---------- src/Common/EventOpenGLTexture.h | 78 ------ src/Common/EventTypeEnum.cxx | 4 - src/Common/EventTypeEnum.h | 2 - src/Graphics/GraphicsEngineDataOpenGL.cxx | 159 ++---------- src/Graphics/GraphicsPrimitive.cxx | 10 +- src/Graphics/GraphicsPrimitive.h | 4 +- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 24 +- src/Graphics/GraphicsPrimitiveV3fT3f.h | 12 +- src/GuiQt/AnnotationMenuArrange.cxx | 4 +- src/GuiQt/BrainOpenGLWidget.cxx | 106 ++------ src/GuiQt/BrainOpenGLWidget.h | 6 - src/Tests/CMakeLists.txt | 5 +- 32 files changed, 106 insertions(+), 1609 deletions(-) delete mode 100644 src/Brain/BrainOpenGLTextureManager.cxx delete mode 100644 src/Brain/BrainOpenGLTextureManager.h delete mode 100644 src/Common/DrawnWithOpenGLTextureInfo.cxx delete mode 100644 src/Common/DrawnWithOpenGLTextureInfo.h delete mode 100644 src/Common/DrawnWithOpenGLTextureInterface.cxx delete mode 100644 src/Common/DrawnWithOpenGLTextureInterface.h delete mode 100644 src/Common/EventOpenGLTexture.cxx delete mode 100644 src/Common/EventOpenGLTexture.h diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index d7135f1ed..a4e6859cb 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -25,8 +25,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" -#include "DrawnWithOpenGLTextureInfo.h" -#include "GraphicsPrimitiveV3fT3F.h" +#include "GraphicsPrimitiveV3fT3f.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -48,8 +47,7 @@ using namespace caret; */ AnnotationImage::AnnotationImage(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::IMAGE, - attributeDefaultType), -DrawnWithOpenGLTextureInterface() + attributeDefaultType) { initializeMembersAnnotationImage(); @@ -69,8 +67,7 @@ AnnotationImage::~AnnotationImage() * Object that is copied. */ AnnotationImage::AnnotationImage(const AnnotationImage& obj) -: AnnotationTwoDimensionalShape(obj), -DrawnWithOpenGLTextureInterface() +: AnnotationTwoDimensionalShape(obj) { initializeMembersAnnotationImage(); this->copyHelperAnnotationImage(obj); @@ -104,7 +101,6 @@ AnnotationImage::copyHelperAnnotationImage(const AnnotationImage& obj) m_imageBytesRGBA = obj.m_imageBytesRGBA; m_imageWidth = obj.m_imageWidth; m_imageHeight = obj.m_imageHeight; - m_drawnWithOpenGLTextureInfo = obj.m_drawnWithOpenGLTextureInfo; } /** @@ -190,9 +186,6 @@ AnnotationImage::initializeMembersAnnotationImage() m_imageHeight = 0; m_sceneAssistant = new SceneClassAssistant(); - - /* Texture info not saved to scenes */ - m_drawnWithOpenGLTextureInfo.grabNew(new DrawnWithOpenGLTextureInfo); } /** @@ -252,45 +245,28 @@ AnnotationImage::getFixedAspectRatio() const return aspectRatio; } -/** - * @return The OpenGL texture information used for managing - * texture resources. - */ -DrawnWithOpenGLTextureInfo* -AnnotationImage::getDrawWithOpenGLTextureInfo() -{ - return m_drawnWithOpenGLTextureInfo; -} - -/** - * @return The OpenGL texture information used for managing - * texture resources (const method) - */ -const DrawnWithOpenGLTextureInfo* -AnnotationImage::getDrawWithOpenGLTextureInfo() const -{ - return m_drawnWithOpenGLTextureInfo; -} - /** * @return The graphics primitive for drawing the image as a texture. */ -GraphicsPrimitiveV3fT3F* +GraphicsPrimitiveV3fT3f* AnnotationImage::getGraphicsPrimitive() const { if (m_graphicsPrimitive == NULL) { if ( ! m_imageBytesRGBA.empty()) { - GraphicsPrimitiveV3fT3F* primitive = GraphicsPrimitive::newPrimitiveV3fT3F(GraphicsPrimitive::PrimitiveType::QUADS, + GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::QUADS, &m_imageBytesRGBA[0], m_imageWidth, m_imageHeight); + /* + * Four coordinates are needed but XY values do not mattter. + * These XY values are replaced when the image is drawn. + * The texture (S, T) do matter. + */ primitive->addVertex(50, 50, 0.0, 0.0); primitive->addVertex(250, 50, 1.0, 0.0); primitive->addVertex(250, 250, 1.0, 1.0); primitive->addVertex(50, 250, 0.0, 1.0); m_graphicsPrimitive.reset(primitive); - - CaretLogWarning("Need to be able to override coordinates"); } } diff --git a/src/Annotations/AnnotationImage.h b/src/Annotations/AnnotationImage.h index 8cb036f78..56465f798 100644 --- a/src/Annotations/AnnotationImage.h +++ b/src/Annotations/AnnotationImage.h @@ -24,16 +24,12 @@ #include #include "AnnotationTwoDimensionalShape.h" -#include "CaretPointer.h" -#include "DrawnWithOpenGLTextureInfo.h" -#include "DrawnWithOpenGLTextureInterface.h" - namespace caret { - class GraphicsPrimitiveV3fT3F; + class GraphicsPrimitiveV3fT3f; - class AnnotationImage : public AnnotationTwoDimensionalShape, public DrawnWithOpenGLTextureInterface { + class AnnotationImage : public AnnotationTwoDimensionalShape { public: AnnotationImage(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); @@ -62,11 +58,7 @@ namespace caret { const uint8_t* getImageBytesRGBA() const; - virtual DrawnWithOpenGLTextureInfo* getDrawWithOpenGLTextureInfo(); - - virtual const DrawnWithOpenGLTextureInfo* getDrawWithOpenGLTextureInfo() const; - - GraphicsPrimitiveV3fT3F* getGraphicsPrimitive() const; + GraphicsPrimitiveV3fT3f* getGraphicsPrimitive() const; // ADD_NEW_METHODS_HERE @@ -94,10 +86,8 @@ namespace caret { int32_t m_imageWidth; int32_t m_imageHeight; - - CaretPointer m_drawnWithOpenGLTextureInfo; - - mutable std::unique_ptr m_graphicsPrimitive; + + mutable std::unique_ptr m_graphicsPrimitive; // ADD_NEW_MEMBERS_HERE diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 26543ab0e..4fdbb2864 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -32,6 +32,7 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "DummyFontTextRenderer.h" +#include "EventGetBrainOpenGLTextRenderer.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" @@ -60,6 +61,7 @@ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) this->borderBeingDrawn = NULL; m_drawHighlightedEndPoints = false; + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT); @@ -176,6 +178,13 @@ BrainOpenGL::receiveEvent(Event* event) deleteTextureEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW) { + EventGetBrainOpenGLTextRenderer* textRenderEvent = dynamic_cast(event); + CaretAssert(textRenderEvent); + + textRenderEvent->setTextRenderer(m_textRenderer); + textRenderEvent->setEventProcessed(); + } } /** @@ -386,30 +395,6 @@ BrainOpenGL::getTextRenderer() return m_textRenderer; } -/** - * Set the text renderer. The existing text renderer will - * be destroyed. This instance will take ownership of - * the text renderer passed in and destory it at the - * proper time. - * - * @param textRenderer - * The text renderer is used for text rendering. - * This parameter MUST NOT be NULL. It must be - * a pointer to a text renderer. - */ -void -BrainOpenGL::setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer) -{ - CaretAssert(textRenderer); - - if (m_textRenderer != NULL) { - delete m_textRenderer; - m_textRenderer = NULL; - } - - m_textRenderer = textRenderer; -} - /** * Get the minimum and maximum values for the size of a point. * @param minPointSizeOut diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 6678604b5..b71c7117a 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -67,7 +67,6 @@ namespace caret { class Border; class Brain; class BrainOpenGLTextRenderInterface; - class BrainOpenGLTextureManager; class BrainOpenGLViewportContent; class Model; class SurfaceProjectedItem; @@ -102,8 +101,6 @@ namespace caret { BrainOpenGLTextRenderInterface* getTextRenderer(); - void setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer); - void drawModels(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, @@ -125,8 +122,6 @@ namespace caret { const int32_t mouseY, SurfaceProjectedItem& projectionOut); - virtual BrainOpenGLTextureManager* getTextureManager() = 0; - /** * @return Half-size of the model window height. */ diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index bd92ba121..bf0114707 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -45,7 +45,6 @@ #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLShapeRing.h" #include "BrainOpenGLTextRenderInterface.h" -#include "BrainOpenGLTextureManager.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnum.h" @@ -55,7 +54,7 @@ #include "EventBrowserTabGet.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" -#include "GraphicsPrimitiveV3fT3F.h" +#include "GraphicsPrimitiveV3fT3f.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -226,24 +225,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A float offsetUnitVector[3] = { 0.0, 0.0, 0.0 }; -// const bool useNormalVectorForOffsetFlag = false; -// if (useNormalVectorForOffsetFlag) { -// const float* normalVector = surfaceDisplayed->getNormalVector(annotationNodeIndex); -// offsetUnitVector[0] = normalVector[0]; -// offsetUnitVector[1] = normalVector[1]; -// offsetUnitVector[2] = normalVector[2]; -// } -// else { -// BoundingBox boundingBox; -// surfaceDisplayed->getBounds(boundingBox); -// float surfaceCenter[3] = { 0.0, 0.0, 0.0 }; -// boundingBox.getCenter(surfaceCenter); -// -// MathFunctions::subtractVectors(nodeXYZ, -// surfaceCenter, -// offsetUnitVector); -// MathFunctions::normalizeVector(offsetUnitVector); -// } /* * For a flat surface, ALWAYS use the normal vector. @@ -287,30 +268,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A case AnnotationCoordinateSpaceEnum::TAB: viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); windowXYZValid = true; -// { -// GLint viewport[4]; -// glGetIntegerv(GL_VIEWPORT, -// viewport); -// windowXYZ[0] = viewport[2] * (annotationXYZ[0] / 100.0); -// windowXYZ[1] = viewport[3] * (annotationXYZ[1] / 100.0); -//// windowXYZ[2] = annotationXYZ[2] / 100.0; -// windowXYZ[2] = toWindowZ(annotationXYZ[2]); -// windowXYZValid = true; -// } break; case AnnotationCoordinateSpaceEnum::WINDOW: viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); windowXYZValid = true; -// { -// GLint viewport[4]; -// glGetIntegerv(GL_VIEWPORT, -// viewport); -// windowXYZ[0] = viewport[2] * (annotationXYZ[0] / 100.0); -// windowXYZ[1] = viewport[3] * (annotationXYZ[1] / 100.0); -//// windowXYZ[2] = annotationXYZ[2] / 100.0; -// windowXYZ[2] = toWindowZ(annotationXYZ[2]); -// windowXYZValid = true; -// } break; } @@ -407,7 +368,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::convertModelToWindowCoordinate(const else { windowXYZOut[2] = -(windowZ + eyeAdjustment); } -// std::cout << "Z adjusted for eye/near/far=" << windowXYZOut[2] << std::endl; } } @@ -443,10 +403,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationTwoDimShapeBounds(const { float viewportWidth = m_modelSpaceViewport[2]; float viewportHeight = m_modelSpaceViewport[3]; -// if (annotation2D->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::STEREOTAXIC) { -// viewportWidth = m_inputs->m_tabViewport[2]; -// viewportHeight = m_inputs->m_tabViewport[3]; -// } /* * Only use text characters when the text is NOT empty @@ -649,9 +605,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case Inputs::WINDOW_DRAWING_YES: break; } -// if ( ! m_inputs->m_drawWindowAnnotationsFlag) { -// drawAnnotationsFromFilesFlag = false; -// } break; } @@ -1297,13 +1250,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati return; } -// /* -// * NO SELECTION OF COLOR BAR ANNOTATIONS -// */ -// if (m_selectionModeFlag) { -// return; -// } - float bottomLeft[3]; float bottomRight[3]; float topRight[3]; @@ -2496,9 +2442,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } } - GraphicsPrimitiveV3fT3F* primitive = image->getGraphicsPrimitive(); + GraphicsPrimitiveV3fT3f* primitive = image->getGraphicsPrimitive(); if (primitive != NULL) { if (primitive->isValid()) { + /* + * Replace the primitive's XYZ values here + * Image ALWAYS has four coordinates + */ std::vector xyz; xyz.insert(xyz.end(), bottomLeft, bottomLeft + 3); xyz.insert(xyz.end(), bottomRight, bottomRight + 3); @@ -2547,178 +2497,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF return drawnFlag; } - - -/** - * Draw image annoation using a textured quad. - * - * @param textureInfo - * Information for OpenGL texture usage. - * @param bottomLeft - * Bottom left corner of annotation. - * @param bottomRight - * Bottom right corner of annotation. - * @param topRight - * Top right corner of annotation. - * @param topLeft - * Top left corner of annotation. - * @param imageBytesRGBA - * Bytes containing the image data. - * @param imageWidth - * Width of the actual image. - * @param imageHeight - * Height of the image. - */ -void -BrainOpenGLAnnotationDrawingFixedPipeline::drawImageBytesWithTexture(DrawnWithOpenGLTextureInfo* textureInfo, - const float bottomLeft[3], - const float bottomRight[3], - const float topRight[3], - const float topLeft[3], - const uint8_t* imageBytesRGBA, - const int32_t imageWidth, - const int32_t imageHeight) -{ - /* - * Images may be invalid such as when the user is - * dragging the mouse to create an annotation image - */ - if ((imageBytesRGBA == NULL) - || (imageWidth <= 0) - || (imageHeight <= 0)) { - return; - } - - m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At beginning of annotation drawImageBytesWithTexture()")); - - /* - * Saves glPixelStore parameters - */ - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - - static bool useMipMapFlag = true; - - BrainOpenGLTextureManager* textureManager = m_brainOpenGLFixedPipeline->getTextureManager(); - CaretAssert(textureManager); - - GLuint textureName = 0; - bool newTextureNameFlag = false; - textureManager->getTextureName(textureInfo, - textureName, - newTextureNameFlag); - - if (newTextureNameFlag) { - glBindTexture(GL_TEXTURE_2D, textureName); - if (useMipMapFlag) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - const int errorCode = gluBuild2DMipmaps(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D - GL_RGBA, // number of components - imageWidth, // width of image - imageHeight, // height of image - GL_RGBA, // format of the pixel data - GL_UNSIGNED_BYTE, // data type of pixel data - imageBytesRGBA); // pointer to image data - if (errorCode != 0) { - useMipMapFlag = false; - - const GLubyte* errorChars = gluErrorString(errorCode); - if (errorChars != NULL) { - const QString errorText = ("ERROR building mipmaps for annotation image: " - + AString((char*)errorChars)); - CaretLogSevere(errorText); - } - } - } - - if ( ! useMipMapFlag) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D - 0, // level of detail 0=base, n is nth mipmap reduction - GL_RGBA, // number of components - imageWidth, // width of image - imageHeight, // height of image - 0, // border - GL_RGBA, // format of the pixel data - GL_UNSIGNED_BYTE, // data type of pixel data - imageBytesRGBA); // pointer to image data - } - } - - glEnable(GL_TEXTURE_2D); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glBindTexture(GL_TEXTURE_2D, textureName); - - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); - glVertex3fv(bottomLeft); - glTexCoord2f(1.0, 0.0); - glVertex3fv(bottomRight); - glTexCoord2f(1.0, 1.0); - glVertex3fv(topRight); - glTexCoord2f(0.0, 1.0); - glVertex3fv(topLeft); - glEnd(); - - /* - * - */ - glBindTexture(GL_TEXTURE_2D, 0); - - glDisable(GL_TEXTURE_2D); - - glPopClientAttrib(); - - m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At end of annotation drawImageBytesWithTexture()")); -} - -/** - * Draw an image texture by drawing pixels. - * DOES NOT WORK IF BOTTOM LEFT CORNER OF IMAGE HAS A NEGATIVE VALUE !! - */ -void -BrainOpenGLAnnotationDrawingFixedPipeline::drawImageBytes(const float windowX, - const float windowY, - const float windowZ, - const uint8_t* imageBytesRGBA, - const int32_t imageWidth, - const int32_t imageHeight) -{ - /* - * Reset orthographic projection to viewport size - */ - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - const float drawX = windowX - (imageWidth / 2.0); - const float drawY = windowY - (imageHeight / 2.0); - - /* - * Saves glPixelStore parameters - */ - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - - // - // Draw image near far clipping plane - // - glRasterPos3f(drawX, drawY, windowZ); //-500.0); // set Z so image behind surface - - glDrawPixels(imageWidth, imageHeight, - GL_RGBA, GL_UNSIGNED_BYTE, - (GLvoid*)imageBytesRGBA); - - glPopClientAttrib(); - - glPopMatrix(); -} - /** * Create the coordinates for drawing a line with optional arrows at the end points. * diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 6d0414338..cd684d24b 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -47,7 +47,6 @@ namespace caret { class BrainOpenGLFixedPipeline; class BrainOpenGLShapeRing; - class DrawnWithOpenGLTextureInfo; class Surface; class BrainOpenGLAnnotationDrawingFixedPipeline : public CaretObject { @@ -209,22 +208,6 @@ namespace caret { AnnotationImage* image, const Surface* surfaceDisplayed); - void drawImageBytes(const float windowX, - const float windowY, - const float windowZ, - const uint8_t* imageBytesRGBA, - const int32_t imageWidth, - const int32_t imageHeight); - - void drawImageBytesWithTexture(DrawnWithOpenGLTextureInfo* textureInfo, - const float bottomLeft[3], - const float bottomRight[3], - const float topRight[3], - const float topLeft[3], - const uint8_t* imageBytesRGBA, - const int32_t imageWidth, - const int32_t imageHeight); - bool drawLine(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 5136d2144..6cbc76f7f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -45,7 +45,6 @@ #include "BrainOpenGLChartDrawingFixedPipeline.h" #include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" -#include "BrainOpenGLTextureManager.h" #include "BrainOpenGLVolumeObliqueSliceDrawing.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "BrainOpenGLShapeCone.h" @@ -172,8 +171,7 @@ BrainOpenGLFixedPipeline::BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterfac this->initializeMembersBrainOpenGL(); this->colorIdentification = new IdentificationWithColor(); m_annotationDrawing.grabNew(new BrainOpenGLAnnotationDrawingFixedPipeline(this)); - m_textureManager.grabNew(new BrainOpenGLTextureManager(0)); //m_windowIndex)); - + m_shapeSphere = NULL; m_shapeCone = NULL; m_shapeCylinder = NULL; @@ -995,17 +993,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, } } -/** - * @return Get the texture manager. - */ -BrainOpenGLTextureManager* -BrainOpenGLFixedPipeline::getTextureManager() -{ - BrainOpenGLTextureManager* tm = m_textureManager.getPointer(); - CaretAssert(tm); - return tm; -} - /** * Set the viewport. * diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index ecf93fc20..ff8df04b0 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -52,7 +52,6 @@ namespace caret { class BrainOpenGLShapeRing; class BrainOpenGLShapeRingOutline; class BrainOpenGLShapeSphere; - class BrainOpenGLTextureManager; class BrainOpenGLViewportContent; class BrowserTabContent; class CaretMappableDataFile; @@ -115,8 +114,6 @@ namespace caret { int32_t& subViewportSizeOut, int32_t& gapOut); - virtual BrainOpenGLTextureManager* getTextureManager(); - protected: void drawModelsImplementation(const int32_t windowIndex, Brain* brain, @@ -521,6 +518,10 @@ namespace caret { void setAnnotationColorBarsForDrawing(std::vector& viewportContents); + void drawTabHighlighting(const float width, + const float height, + const float rgb[3]); + /** Index of window */ int32_t m_windowIndex = -1; @@ -620,9 +621,6 @@ namespace caret { std::vector m_annotationColorBarsForDrawing; - /** The texture manager. */ - CaretPointer m_textureManager; - static bool s_staticInitialized; static const float s_gluLookAtCenterFromEyeOffsetDistance; diff --git a/src/Brain/BrainOpenGLTextureManager.cxx b/src/Brain/BrainOpenGLTextureManager.cxx deleted file mode 100644 index 38efe3d8d..000000000 --- a/src/Brain/BrainOpenGLTextureManager.cxx +++ /dev/null @@ -1,230 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#define __BRAIN_OPEN_G_L_TEXTURE_MANAGER_DECLARE__ -#include "BrainOpenGLTextureManager.h" -#undef __BRAIN_OPEN_G_L_TEXTURE_MANAGER_DECLARE__ - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "DrawnWithOpenGLTextureInfo.h" -#include "EventManager.h" -#include "EventOpenGLTexture.h" -using namespace caret; - - - -/** - * \class caret::BrainOpenGLTextureManager - * \brief Manages allocated OpenGL Textures. - * \ingroup Brain - * - * This texture manager helps out with tracking OpenGL - * textures. There are instance in which textures need - * to be deleted such as when QGLWidget::renderPixmap() - * is used to capture an image of the graphics region. - * - * Note that the FTGL text rendering code also uses - * texture and this texture manager does not interact - * in any way with FTGL. - */ - -/** - * Constructor. - * - * @param windowIndex - * Index of window for which textures are managed. - */ -BrainOpenGLTextureManager::BrainOpenGLTextureManager(const int32_t windowIndex) -: CaretObject(), -m_windowIndex(windowIndex) -{ - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPENGL_TEXTURE); -} - -/** - * Destructor. - */ -BrainOpenGLTextureManager::~BrainOpenGLTextureManager() -{ - /* - * We do not need to worry about deleting texture names - * since when a instance of this class is deleted, the - * OpenGL context is also deleted which deletes all - * of the texture names. - */ - EventManager::get()->removeAllEventsFromListener(this); -} - -/** - * Receive an event. - * - * @param event - * The event that the receive can respond to. - */ -void -BrainOpenGLTextureManager::receiveEvent(Event* event) -{ - if (event->getEventType() == EventTypeEnum::EVENT_OPENGL_TEXTURE) { - EventOpenGLTexture* textureEvent = dynamic_cast(event); - CaretAssert(textureEvent); - - switch (textureEvent->getMode()) { - case EventOpenGLTexture::MODE_NONE: - break; - case EventOpenGLTexture::MODE_DELETE_ALL_TEXTURES_IN_WINDOW: - break; - case EventOpenGLTexture::MODE_DELETE_TEXTURE: - { - int32_t windowIndex = -1; - int32_t textureName = 0; - textureEvent->getModeDeleteTexture(windowIndex, - textureName); - if (m_windowIndex == windowIndex) { - deleteTextureName(textureName); - - textureEvent->setEventProcessed(); - } - } - break; - } - } -} - -/** - * Delete all textures for a given window index. - * - * @param windowIndex - * Index of the window. - */ -void -BrainOpenGLTextureManager::deleteAllTexturesForWindow(const int32_t windowIndex) -{ - EventOpenGLTexture textureEvent; - textureEvent.setModeDeleteAllTexturesInWindow(windowIndex); - EventManager::get()->sendEvent(textureEvent.getPointer()); -} - - -/** - * Get the texture name for the given texture info. - * - * @param textureInfo - * The texture information. - * @param textureNameOut - * Output containing OpenGL texture name for use with glBindTexture. - * @param newTextureNameFlagOut - * If true, the texture name is new and the caller must create - * or recreate the texture image. Recreation may be necessary - * after an image capture operation due to it creating a new - * OpenGL context. - */ -void -BrainOpenGLTextureManager::getTextureName(DrawnWithOpenGLTextureInfo* textureInfo, - GLuint& textureNameOut, - bool& newTextureNameFlagOut) -{ - textureNameOut = 0; - newTextureNameFlagOut = false; - - CaretAssert(m_windowIndex >= 0); - textureNameOut = textureInfo->getTextureNameForWindow(m_windowIndex); - if (textureNameOut > 0) { - /* - * Verify texture is still valid (could be deleted during image capture - * which recreates the OpenGL context). - */ - if (glIsTexture(textureNameOut)) { - return; - } - } - - textureNameOut = createNewTextureName(); - textureInfo->setTextureNameForWindow(m_windowIndex, - textureNameOut); - newTextureNameFlagOut = true; -} - -/** - * @return A new texture name. - */ -GLuint -BrainOpenGLTextureManager::createNewTextureName() -{ - /* - * Each workbench window has its own, unique OpenGL context. - * Identical OpenGL texture names may exist in each OpenGL - * context. To simplify management of textures, we do not - * want the same texture name in more than one OpenGL - * context. - * - * So, we do not use glGenTexture() to create texture - * names. Instead, we use our own generator that - * ensures each name is never used in more than one - * OpenGL context. This simplifies management of textures - * and especially the removal of textures when an - * object drawn using a texture is deleted. - * - * In addition, other modules (such as FTGL font - * rendering) may use textures, so we need to - * ensure that a new name is not used elsewhere. - */ - s_textureNameGenerator++; - if (s_textureNameGenerator == std::numeric_limits::max()) { - s_textureNameGenerator = 1; - } - while (glIsTexture(s_textureNameGenerator) == GL_TRUE) { - s_textureNameGenerator++; - if (s_textureNameGenerator == std::numeric_limits::max()) { - s_textureNameGenerator = 1; - } - } - - return s_textureNameGenerator; -} - - -/** - * Delete a texture name. - * - * @param textureName - * Texture name that is deleted. - */ -void -BrainOpenGLTextureManager::deleteTextureName(GLuint textureName) -{ - if (glIsTexture(textureName) == GL_TRUE) { - glDeleteTextures(1, &textureName); - } -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -BrainOpenGLTextureManager::toString() const -{ - return "BrainOpenGLTextureManager"; -} - diff --git a/src/Brain/BrainOpenGLTextureManager.h b/src/Brain/BrainOpenGLTextureManager.h deleted file mode 100644 index 818044296..000000000 --- a/src/Brain/BrainOpenGLTextureManager.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __BRAIN_OPEN_G_L_TEXTURE_MANAGER_H__ -#define __BRAIN_OPEN_G_L_TEXTURE_MANAGER_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include -#include - -#include "CaretObject.h" -#include "CaretOpenGLInclude.h" -#include "EventListenerInterface.h" - - -namespace caret { - - class DrawnWithOpenGLTextureInfo; - - class BrainOpenGLTextureManager : public CaretObject, public EventListenerInterface { - - public: - BrainOpenGLTextureManager(const int32_t windowIndex); - - virtual ~BrainOpenGLTextureManager(); - - virtual void receiveEvent(Event* event); - - void getTextureName(DrawnWithOpenGLTextureInfo* textureInfo, - GLuint& textureNameOut, - bool& newTextureNameFlagOut); - - void deleteAllTexturesForWindow(const int32_t windowIndex); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - private: - BrainOpenGLTextureManager(const BrainOpenGLTextureManager&); - - BrainOpenGLTextureManager& operator=(const BrainOpenGLTextureManager&); - - GLuint createNewTextureName(); - - void deleteTextureName(GLuint textureName); - - const int32_t m_windowIndex; - - /** - * Generates the texture names - */ - static int32_t s_textureNameGenerator; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __BRAIN_OPEN_G_L_TEXTURE_MANAGER_DECLARE__ - int32_t BrainOpenGLTextureManager::s_textureNameGenerator = 0; -#endif // __BRAIN_OPEN_G_L_TEXTURE_MANAGER_DECLARE__ - -} // namespace -#endif //__BRAIN_OPEN_G_L_TEXTURE_MANAGER_H__ diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index ed02b6c53..fd4e1447a 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -71,7 +71,6 @@ BrainOpenGLShapeRing.h BrainOpenGLShapeRingOutline.h BrainOpenGLShapeSphere.h BrainOpenGLTextRenderInterface.h -BrainOpenGLTextureManager.h BrainOpenGLViewportContent.h BrainOpenGLVolumeObliqueSliceDrawing.h BrainOpenGLVolumeSliceDrawing.h @@ -218,7 +217,6 @@ BrainOpenGLShapeRing.cxx BrainOpenGLShapeRingOutline.cxx BrainOpenGLShapeSphere.cxx BrainOpenGLTextRenderInterface.cxx -BrainOpenGLTextureManager.cxx BrainOpenGLViewportContent.cxx BrainOpenGLVolumeObliqueSliceDrawing.cxx BrainOpenGLVolumeSliceDrawing.cxx diff --git a/src/Brain/EventGetBrainOpenGLTextRenderer.cxx b/src/Brain/EventGetBrainOpenGLTextRenderer.cxx index 8779f62db..ce59cd09c 100644 --- a/src/Brain/EventGetBrainOpenGLTextRenderer.cxx +++ b/src/Brain/EventGetBrainOpenGLTextRenderer.cxx @@ -39,9 +39,8 @@ using namespace caret; /** * Constructor. */ -EventGetBrainOpenGLTextRenderer::EventGetBrainOpenGLTextRenderer(const int32_t windowIndex) -: Event(EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW), -m_windowIndex(windowIndex) +EventGetBrainOpenGLTextRenderer::EventGetBrainOpenGLTextRenderer() +: Event(EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW) { m_textRenderer = NULL; } @@ -53,15 +52,6 @@ EventGetBrainOpenGLTextRenderer::~EventGetBrainOpenGLTextRenderer() { } -/** - * @return Index of the window. - */ -int32_t -EventGetBrainOpenGLTextRenderer::getWindowIndex() const -{ - return m_windowIndex; -} - /** * @return The text renderer found for the window. * (NULL if not found). diff --git a/src/Brain/EventGetBrainOpenGLTextRenderer.h b/src/Brain/EventGetBrainOpenGLTextRenderer.h index 19dfd9105..fc19eae3f 100644 --- a/src/Brain/EventGetBrainOpenGLTextRenderer.h +++ b/src/Brain/EventGetBrainOpenGLTextRenderer.h @@ -33,12 +33,10 @@ namespace caret { class EventGetBrainOpenGLTextRenderer : public Event { public: - EventGetBrainOpenGLTextRenderer(const int32_t windowIndex); + EventGetBrainOpenGLTextRenderer(); virtual ~EventGetBrainOpenGLTextRenderer(); - int32_t getWindowIndex() const; - BrainOpenGLTextRenderInterface* getTextRenderer() const; void setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer); @@ -50,8 +48,6 @@ namespace caret { EventGetBrainOpenGLTextRenderer& operator=(const EventGetBrainOpenGLTextRenderer&); - const int32_t m_windowIndex; - BrainOpenGLTextRenderInterface* m_textRenderer; // ADD_NEW_MEMBERS_HERE diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 93e28eda1..b9b06d47a 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -93,8 +93,6 @@ DescriptiveStatistics.h DeveloperFlagsEnum.h DisplayGroupAndTabItemInterface.h DisplayGroupEnum.h -DrawnWithOpenGLTextureInfo.h -DrawnWithOpenGLTextureInterface.h ElapsedTimer.h Event.h EventAlertUser.h @@ -105,7 +103,6 @@ EventListenerInterface.h EventManager.h EventPaletteGetByName.h EventProgressUpdate.h -EventOpenGLTexture.h EventTypeEnum.h FastStatistics.h FileAdapter.h @@ -193,7 +190,6 @@ DescriptiveStatistics.cxx DeveloperFlagsEnum.cxx DisplayGroupAndTabItemInterface.cxx DisplayGroupEnum.cxx -DrawnWithOpenGLTextureInfo.cxx ElapsedTimer.cxx Event.cxx EventAlertUser.cxx @@ -203,7 +199,6 @@ EventGetViewportSize.cxx EventManager.cxx EventPaletteGetByName.cxx EventProgressUpdate.cxx -EventOpenGLTexture.cxx EventTypeEnum.cxx FastStatistics.cxx FileAdapter.cxx diff --git a/src/Common/DrawnWithOpenGLTextureInfo.cxx b/src/Common/DrawnWithOpenGLTextureInfo.cxx deleted file mode 100644 index 92431b8b7..000000000 --- a/src/Common/DrawnWithOpenGLTextureInfo.cxx +++ /dev/null @@ -1,210 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __DRAWN_WITH_OPENGL_TEXTURE_INFO_DECLARE__ -#include "DrawnWithOpenGLTextureInfo.h" -#undef __DRAWN_WITH_OPENGL_TEXTURE_INFO_DECLARE__ - -#include "CaretAssert.h" -#include "EventManager.h" -#include "EventOpenGLTexture.h" - -using namespace caret; - - - -/** - * \class caret::DrawnWithOpenGLTextureInfo - * \brief Assists with managing texture names for items drawn as textures. - * \ingroup Common - * - * OpenGL textures use resources in the graphics system. Classes - * implementing this interface must contain an instance of - * DrawnWithOpenGLTextureInfo which contains information about - * the OpenGL texture. When an instance of DrawnWithOpenGLTextureInfo - * goes out of scope (deleted), it will send a message to - * OpenGL rendering to free up any associated resources with the - * OpenGL texture. - */ - -/** - * Constructor. - */ -DrawnWithOpenGLTextureInfo::DrawnWithOpenGLTextureInfo() -: CaretObject(), - EventListenerInterface() -{ - resetTextureNames(); - - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPENGL_TEXTURE); -} - -/** - * Destructor. - */ -DrawnWithOpenGLTextureInfo::~DrawnWithOpenGLTextureInfo() -{ - EventManager::get()->removeAllEventsFromListener(this); - - /* - * Need to release the texture names since no longer needed. - */ - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { - CaretAssertArrayIndex(m_textureNamesForWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, i); - if (m_textureNamesForWindow[i] > 0) { - EventOpenGLTexture textureEvent; - textureEvent.setModeDeleteTexture(i, m_textureNamesForWindow[i]); - EventManager::get()->sendEvent(textureEvent.getPointer()); - } - } -} - -/** - * Copy constructor. - * @param obj - * Object that is copied. - */ -DrawnWithOpenGLTextureInfo::DrawnWithOpenGLTextureInfo(const DrawnWithOpenGLTextureInfo& obj) -: CaretObject(obj), EventListenerInterface() -{ - this->copyHelperDrawnWithOpenGLTextureInfo(obj); -} - -/** - * Assignment operator. - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -DrawnWithOpenGLTextureInfo& -DrawnWithOpenGLTextureInfo::operator=(const DrawnWithOpenGLTextureInfo& obj) -{ - if (this != &obj) { - CaretObject::operator=(obj); - this->copyHelperDrawnWithOpenGLTextureInfo(obj); - } - return *this; -} - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -DrawnWithOpenGLTextureInfo::copyHelperDrawnWithOpenGLTextureInfo(const DrawnWithOpenGLTextureInfo& /*obj*/) -{ - /* - * Do not copy the texture identfiers. - */ - resetTextureNames(); -} - -/** - * Receive an event. - * - * @param event - * The event that the receive can respond to. - */ -void -DrawnWithOpenGLTextureInfo::receiveEvent(Event* event) -{ - if (event->getEventType() == EventTypeEnum::EVENT_OPENGL_TEXTURE) { - EventOpenGLTexture* textureEvent = dynamic_cast(event); - CaretAssert(textureEvent); - - switch (textureEvent->getMode()) { - case EventOpenGLTexture::MODE_NONE: - break; - case EventOpenGLTexture::MODE_DELETE_ALL_TEXTURES_IN_WINDOW: - { - int32_t windowIndex = 0; - textureEvent->getModeDeleteAllTexturesInWindow(windowIndex); - if ((windowIndex >= 0) - && (windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { - m_textureNamesForWindow[windowIndex] = 0; - textureEvent->setEventProcessed(); - } - } - break; - case EventOpenGLTexture::MODE_DELETE_TEXTURE: - break; - } - } -} - -/** - * Reset the texture names. - */ -void -DrawnWithOpenGLTextureInfo::resetTextureNames() -{ - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { - CaretAssertArrayIndex(m_textureNamesForWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, i); - m_textureNamesForWindow[i] = -1; - } -} - - -/** - * Get the texture name for the given window index. - * - * @param windowIndex - * Index of the window. - * @return - * The texture name. Valid texture names are always - * greater than zero. - */ -int32_t -DrawnWithOpenGLTextureInfo::getTextureNameForWindow(const int32_t windowIndex) const -{ - CaretAssertArrayIndex(m_textureNamesForWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); - return m_textureNamesForWindow[windowIndex]; -} - -/** - * Set the texture name for the given window index. - * - * @param windowIndex - * Index of the window. - * @param textureName - * The texture name. Valid texture name are always - * greater than zero. - */ -void -DrawnWithOpenGLTextureInfo::setTextureNameForWindow(const int32_t windowIndex, - const int32_t textureName) -{ - CaretAssertArrayIndex(m_textureNamesForWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); - m_textureNamesForWindow[windowIndex] = textureName; -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -DrawnWithOpenGLTextureInfo::toString() const -{ - return "DrawnWithOpenGLTextureInfo"; -} - diff --git a/src/Common/DrawnWithOpenGLTextureInfo.h b/src/Common/DrawnWithOpenGLTextureInfo.h deleted file mode 100644 index 4527df9fb..000000000 --- a/src/Common/DrawnWithOpenGLTextureInfo.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef __DRAWN_WITH_OPENGL_TEXTURE_INFO_H__ -#define __DRAWN_WITH_OPENGL_TEXTURE_INFO_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include "BrainConstants.h" -#include "CaretObject.h" -#include "EventListenerInterface.h" - -namespace caret { - - class DrawnWithOpenGLTextureInfo : public CaretObject, public EventListenerInterface { - - public: - DrawnWithOpenGLTextureInfo(); - - virtual ~DrawnWithOpenGLTextureInfo(); - - virtual void receiveEvent(Event* event); - - DrawnWithOpenGLTextureInfo(const DrawnWithOpenGLTextureInfo& obj); - - DrawnWithOpenGLTextureInfo& operator=(const DrawnWithOpenGLTextureInfo& obj); - - int32_t getTextureNameForWindow(const int32_t windowIndex) const; - - void setTextureNameForWindow(const int32_t windowIndex, - const int32_t textureName); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - private: - void copyHelperDrawnWithOpenGLTextureInfo(const DrawnWithOpenGLTextureInfo& obj); - - void resetTextureNames(); - - int64_t m_textureNamesForWindow[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __DRAWN_WITH_OPENGL_TEXTURE_INFO_DECLARE__ - // -#endif // __DRAWN_WITH_OPENGL_TEXTURE_INFO_DECLARE__ - -} // namespace -#endif //__DRAWN_WITH_OPENGL_TEXTURE_INFO_H__ diff --git a/src/Common/DrawnWithOpenGLTextureInterface.cxx b/src/Common/DrawnWithOpenGLTextureInterface.cxx deleted file mode 100644 index 968823aa9..000000000 --- a/src/Common/DrawnWithOpenGLTextureInterface.cxx +++ /dev/null @@ -1,92 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __DRAWN_WITH_TEXTURE_INTERFACE_DECLARE__ -#include "DrawnWithTextureInterface.h" -#undef __DRAWN_WITH_TEXTURE_INTERFACE_DECLARE__ - -#include "CaretAssert.h" -using namespace caret; - - - -/** - * \class caret::DrawnWithTextureInterface - * \brief - * \ingroup Common - * - * - */ - -/** - * Constructor. - */ -DrawnWithTextureInterface::DrawnWithTextureInterface() -{ - -} - -/** - * Destructor. - */ -DrawnWithTextureInterface::~DrawnWithTextureInterface() -{ -} - -/** - * Copy constructor. - * @param obj - * Object that is copied. - */ -DrawnWithTextureInterface::DrawnWithTextureInterface(const DrawnWithTextureInterface& obj) -: (obj) -{ - this->copyHelperDrawnWithTextureInterface(obj); -} - -/** - * Assignment operator. - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -DrawnWithTextureInterface& -DrawnWithTextureInterface::operator=(const DrawnWithTextureInterface& obj) -{ - if (this != &obj) { - ::operator=(obj); - this->copyHelperDrawnWithTextureInterface(obj); - } - return *this; -} - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -DrawnWithTextureInterface::copyHelperDrawnWithTextureInterface(const DrawnWithTextureInterface& obj) -{ - -} - diff --git a/src/Common/DrawnWithOpenGLTextureInterface.h b/src/Common/DrawnWithOpenGLTextureInterface.h deleted file mode 100644 index ec13708ab..000000000 --- a/src/Common/DrawnWithOpenGLTextureInterface.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __DRAWN_WITH_OPENGL_TEXTURE_INTERFACE_H__ -#define __DRAWN_WITH_OPENGL_TEXTURE_INTERFACE_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -/** - * \class caret::DrawnWithOpenGLTextureInterface - * \brief Interface for items that are drawn with an OpenGL texture. - * \ingroup Common - * - * OpenGL textures use resources in the graphics system. Classes - * implementing this interface must contain an instance of - * DrawnWithOpenGLTextureInfo which contains information about - * the OpenGL texture. When an instance of DrawnWithOpenGLTextureInfo - * goes out of scope (deleted), it will send a message to - * OpenGL rendering to free up any associated resources with the - * OpenGL texture. - */ - - - -namespace caret { - - class DrawnWithOpenGLTextureInfo; - - class DrawnWithOpenGLTextureInterface { - - public: - /** - * Constructor. - */ - DrawnWithOpenGLTextureInterface() { } - - /** - * Destructor. - */ - virtual ~DrawnWithOpenGLTextureInterface() { } - - /** - * @return The OpenGL texture information used for managing - * texture resources. - */ - virtual DrawnWithOpenGLTextureInfo* getDrawWithOpenGLTextureInfo() = 0; - - /** - * @return The OpenGL texture information used for managing - * texture resources (const method) - */ - virtual const DrawnWithOpenGLTextureInfo* getDrawWithOpenGLTextureInfo() const = 0; - - // ADD_NEW_METHODS_HERE - - private: - DrawnWithOpenGLTextureInterface(const DrawnWithOpenGLTextureInterface& /*obj*/); - - DrawnWithOpenGLTextureInterface& operator=(const DrawnWithOpenGLTextureInterface& /*obj*/); - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __DRAWN_WITH_OPENGL_TEXTURE_INTERFACE_DECLARE__ - // -#endif // __DRAWN_WITH_OPENGL_TEXTURE_INTERFACE_DECLARE__ - -} // namespace -#endif //__DRAWN_WITH_OPENGL_TEXTURE_INTERFACE_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index f6dd7541a..6fd3d54dd 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -519,7 +519,6 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_MODEL_GET_ALL: case EventTypeEnum::EVENT_MODEL_SURFACE_GET: case EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS: - case EventTypeEnum::EVENT_OPENGL_TEXTURE: case EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE: case EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW: case EventTypeEnum::EVENT_OVERLAY_VALIDATE: diff --git a/src/Common/EventOpenGLTexture.cxx b/src/Common/EventOpenGLTexture.cxx deleted file mode 100644 index 724f9a25a..000000000 --- a/src/Common/EventOpenGLTexture.cxx +++ /dev/null @@ -1,128 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __EVENT_OPENGL_TEXTURE_DECLARE__ -#include "EventOpenGLTexture.h" -#undef __EVENT_OPENGL_TEXTURE_DECLARE__ - -#include "CaretAssert.h" -#include "EventTypeEnum.h" - -using namespace caret; - - - -/** - * \class caret::EventOpenGLTexture - * \brief Event that assists with management of OpenGL textures. - * \ingroup Common - * - * When an object is destroyed that used texture resources, the - * texture resources need to be released. This event can be - * sent by the object to the texture manager to free these - * texture resources. - */ - -/** - * Constructor. - */ -EventOpenGLTexture::EventOpenGLTexture() -: Event(EventTypeEnum::EVENT_OPENGL_TEXTURE), -m_mode(MODE_NONE), -m_windowIndex(-1), -m_textureName(0) -{ -} - -/** - * Destructor. - */ -EventOpenGLTexture::~EventOpenGLTexture() -{ -} - -/** - * @return The mode. - */ -EventOpenGLTexture::Mode -EventOpenGLTexture::getMode() const -{ - return m_mode; -} - -/** - * Set the mode to delete all textures for a given window. - * - * @param windowIndex - * Index of the window. - */ -void -EventOpenGLTexture::setModeDeleteAllTexturesInWindow(const int32_t windowIndex) -{ - m_mode = MODE_DELETE_ALL_TEXTURES_IN_WINDOW; - m_windowIndex = windowIndex; -} - -/** - * Get the mode to delete all textures for a given window. - * - * @param windowIndex - * Index of the window. - */ -void -EventOpenGLTexture::getModeDeleteAllTexturesInWindow(int32_t windowIndexOut) const -{ - windowIndexOut = m_windowIndex; -} - -/** - * Set the mode to delete texture name for window. - * - * @param windowIndex - * Index of window in which texture is used. - * @param textureName - * OpenGL texture name. - */ -void -EventOpenGLTexture::setModeDeleteTexture(const int32_t windowIndex, - const int32_t textureName) -{ - m_mode = MODE_DELETE_TEXTURE; - m_windowIndex = windowIndex; - m_textureName = textureName; -} - -/** - * Get the mode to delete texture name for window. - * - * @param windowIndex - * Index of window in which texture is used. - * @param textureName - * OpenGL texture name. - */ -void -EventOpenGLTexture::getModeDeleteTexture(int32_t& windowIndexOut, - int32_t& textureNameOut) const -{ - windowIndexOut = m_windowIndex; - textureNameOut = m_textureName; -} - diff --git a/src/Common/EventOpenGLTexture.h b/src/Common/EventOpenGLTexture.h deleted file mode 100644 index accfbb47c..000000000 --- a/src/Common/EventOpenGLTexture.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __EVENT_OPENGL_TEXTURE_H__ -#define __EVENT_OPENGL_TEXTURE_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2016 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include "Event.h" - - - -namespace caret { - - class EventOpenGLTexture : public Event { - - public: - enum Mode { - MODE_NONE, - MODE_DELETE_ALL_TEXTURES_IN_WINDOW, - MODE_DELETE_TEXTURE - }; - - EventOpenGLTexture(); - - virtual ~EventOpenGLTexture(); - - Mode getMode() const; - - void setModeDeleteAllTexturesInWindow(const int32_t windowIndex); - - void getModeDeleteAllTexturesInWindow(int32_t windowIndexOut) const; - - void setModeDeleteTexture(const int32_t windowIndex, - const int32_t textureName); - - void getModeDeleteTexture(int32_t& windowIndexOut, - int32_t& textureNameOut) const; - - // ADD_NEW_METHODS_HERE - - private: - EventOpenGLTexture(const EventOpenGLTexture&); - - EventOpenGLTexture& operator=(const EventOpenGLTexture&); - - Mode m_mode; - - int32_t m_windowIndex; - - int32_t m_textureName; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __EVENT_OPENGL_TEXTURE_DECLARE__ - // -#endif // __EVENT_OPENGL_TEXTURE_DECLARE__ - -} // namespace -#endif //__EVENT_OPENGL_TEXTURE_H__ diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index a5aa58f96..07e8f08aa 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -277,10 +277,6 @@ EventTypeEnum::initialize() "EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS", "Get the color for node identification symbols from all charts that contain nodes")); - enumData.push_back(EventTypeEnum(EVENT_OPENGL_TEXTURE, - "EVENT_OPENGL_TEXTURE", - "OpenGL Texture Event")); - enumData.push_back(EventTypeEnum(EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, "EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE", "Operating system requests open data file (Mac only)")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 25d589da1..3b7f45f5e 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -146,8 +146,6 @@ public: EVENT_MODEL_SURFACE_GET, /** Get the color for a node's identification symbol from a chart that contains the node */ EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, - /** OpenGL Texture related event */ - EVENT_OPENGL_TEXTURE, /** open file request from the operating system (Mac only) for now */ EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, /** request display of overlay settings editor */ diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 62a57a401..26469fb30 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -358,143 +358,7 @@ GraphicsEngineDataOpenGL::loadAllBuffers(GraphicsPrimitive* primitive) loadCoordinateBuffer(primitive); loadNormalVectorBuffer(primitive); loadColorBuffer(primitive); - loadTextureCoordinateBuffer(primitive); - -// CaretAssert(primitive); -// -// GLenum usageHint = getOpeGLBufferUsageHint(primitive); -// -// GLsizei coordinateCount = 0; -// switch (primitive->m_vertexType) { -// case GraphicsPrimitive::VertexType::FLOAT_XYZ: -// m_coordinateDataType = GL_FLOAT; -// m_coordinatesPerVertex = 3; // X, Y, Z -// -// coordinateCount = primitive->m_xyz.size(); -// const GLuint xyzSizeBytes = coordinateCount * sizeof(float); -// CaretAssert(xyzSizeBytes > 0); -// const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; -// -// EventGraphicsOpenGLCreateBufferObject createEvent; -// EventManager::get()->sendEvent(createEvent.getPointer()); -// m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); -// CaretAssert(m_coordinateBufferObject->getBufferObjectName()); -// -// glBindBuffer(GL_ARRAY_BUFFER, -// m_coordinateBufferObject->getBufferObjectName()); -// glBufferData(GL_ARRAY_BUFFER, -// xyzSizeBytes, -// xyzDataPointer, -// usageHint); -// break; -// } -// -// if (m_coordinatesPerVertex > 0) { -// m_arrayIndicesCount = coordinateCount / m_coordinatesPerVertex; -// } -// else { -// m_arrayIndicesCount = 0; -// } -// -// switch (primitive->m_normalVectorType) { -// case GraphicsPrimitive::NormalVectorType::NONE: -// break; -// case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: -// { -// m_normalVectorDataType = GL_FLOAT; -// const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); -// CaretAssert(normalSizeBytes > 0); -// const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; -// -// EventGraphicsOpenGLCreateBufferObject createEvent; -// EventManager::get()->sendEvent(createEvent.getPointer()); -// m_normalVectorBufferObject = createEvent.getOpenGLBufferObject(); -// CaretAssert(m_normalVectorBufferObject->getBufferObjectName()); -// -// glBindBuffer(GL_ARRAY_BUFFER, -// m_normalVectorBufferObject->getBufferObjectName()); -// glBufferData(GL_ARRAY_BUFFER, -// normalSizeBytes, -// normalDataPointer, -// usageHint); -// } -// break; -// } -// -// switch (primitive->m_colorType) { -// case GraphicsPrimitive::ColorType::NONE: -// break; -// case GraphicsPrimitive::ColorType::FLOAT_RGBA: -// { -// EventGraphicsOpenGLCreateBufferObject createEvent; -// EventManager::get()->sendEvent(createEvent.getPointer()); -// m_colorBufferObject = createEvent.getOpenGLBufferObject(); -// CaretAssert(m_colorBufferObject->getBufferObjectName()); -// -// m_componentsPerColor = 4; -// m_colorDataType = GL_FLOAT; -// -// const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); -// CaretAssert(colorSizeBytes > 0); -// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; -// -// glBindBuffer(GL_ARRAY_BUFFER, -// m_colorBufferObject->getBufferObjectName()); -// glBufferData(GL_ARRAY_BUFFER, -// colorSizeBytes, -// colorDataPointer, -// usageHint); -// } -// break; -// case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: -// { -// EventGraphicsOpenGLCreateBufferObject createEvent; -// EventManager::get()->sendEvent(createEvent.getPointer()); -// m_colorBufferObject = createEvent.getOpenGLBufferObject(); -// CaretAssert(m_colorBufferObject->getBufferObjectName()); -// -// m_componentsPerColor = 4; -// m_colorDataType = GL_UNSIGNED_BYTE; -// -// const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); -// CaretAssert(colorSizeBytes > 0); -// const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; -// -// glBindBuffer(GL_ARRAY_BUFFER, -// m_colorBufferObject->getBufferObjectName()); -// glBufferData(GL_ARRAY_BUFFER, -// colorSizeBytes, -// colorDataPointer, -// usageHint); -// } -// break; -// } -// -// switch (primitive->m_textureType) { -// case GraphicsPrimitive::TextureType::FLOAT_STR: -// { -// EventGraphicsOpenGLCreateBufferObject createEvent; -// EventManager::get()->sendEvent(createEvent.getPointer()); -// m_textureCoordinatesBufferObject = createEvent.getOpenGLBufferObject(); -// CaretAssert(m_textureCoordinatesBufferObject->getBufferObjectName()); -// -// m_textureCoordinatesDataType = GL_FLOAT; -// const GLuint textureSizeBytes = primitive->m_floatTextureSTR.size() * sizeof(float); -// CaretAssert(textureSizeBytes > 0); -// const GLvoid* textureDataPointer = (const GLvoid*)&primitive->m_floatTextureSTR[0]; -// -// glBindBuffer(GL_ARRAY_BUFFER, -// m_textureCoordinatesBufferObject->getBufferObjectName()); -// glBufferData(GL_ARRAY_BUFFER, -// textureSizeBytes, -// textureDataPointer, -// usageHint); -// -// } -// break; -// case GraphicsPrimitive::TextureType::NONE: -// break; -// } + loadTextureCoordinateBuffer(primitive); } /** @@ -540,13 +404,30 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv glBindTexture(GL_TEXTURE_2D, openGLTextureName); - bool useMipMapFlag = true; if (useMipMapFlag) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + + /* + * This code seems to work if OpenGL 3.0 or later and + * replaces gluBuild2DMipmaps() + * + * glTexImage2D(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D + * 0, // level of detail 0=base, n is nth mipmap reduction + * GL_RGBA, // number of components + * imageWidth, // width of image + * imageHeight, // height of image + * 0, // border + * GL_RGBA, // format of the pixel data + * GL_UNSIGNED_BYTE, // data type of pixel data + * imageBytesRGBA); // pointer to image data + * glGenerateMipmap(GL_TEXTURE_2D); + */ + + const int errorCode = gluBuild2DMipmaps(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D GL_RGBA, // number of components imageWidth, // width of image @@ -1103,7 +984,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, */ if (hasTextureFlag && (drawMode == PrivateDrawMode::DRAW_NORMAL) - && (openglData->m_textureImageDataName->getTextureName())) { + && (openglData->m_textureImageDataName->getTextureName() > 0)) { glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, openglData->m_textureImageDataName->getTextureName()); diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 64dd63ced..d2ce8e283 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -30,7 +30,7 @@ #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" -#include "GraphicsPrimitiveV3fT3F.h" +#include "GraphicsPrimitiveV3fT3f.h" using namespace caret; @@ -784,7 +784,7 @@ GraphicsPrimitive::setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* grap * An event for which this instance is listening. */ void -GraphicsPrimitive::receiveEvent(Event* event) +GraphicsPrimitive::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); @@ -854,13 +854,13 @@ GraphicsPrimitive::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType pr return primitive; } -GraphicsPrimitiveV3fT3F* -GraphicsPrimitive::newPrimitiveV3fT3F(const GraphicsPrimitive::PrimitiveType primitiveType, +GraphicsPrimitiveV3fT3f* +GraphicsPrimitive::newPrimitiveV3fT3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) { - GraphicsPrimitiveV3fT3F* primitive = new GraphicsPrimitiveV3fT3F(primitiveType, + GraphicsPrimitiveV3fT3f* primitive = new GraphicsPrimitiveV3fT3f(primitiveType, imageBytesRGBA, imageWidth, imageHeight); diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 5588e6da3..d968950d8 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -36,7 +36,7 @@ namespace caret { class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; - class GraphicsPrimitiveV3fT3F; + class GraphicsPrimitiveV3fT3f; class GraphicsPrimitive : public CaretObject, public EventListenerInterface { @@ -188,7 +188,7 @@ namespace caret { static GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); - static GraphicsPrimitiveV3fT3F* newPrimitiveV3fT3F(const GraphicsPrimitive::PrimitiveType primitiveType, + static GraphicsPrimitiveV3fT3f* newPrimitiveV3fT3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 313e245a1..56e60489c 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -20,7 +20,7 @@ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ -#include "GraphicsPrimitiveV3fT3F.h" +#include "GraphicsPrimitiveV3fT3f.h" #undef __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ #include "CaretAssert.h" @@ -29,7 +29,7 @@ using namespace caret; /** - * \class caret::GraphicsPrimitiveV3fT3F + * \class caret::GraphicsPrimitiveV3fT3f * \brief Primitive containing XYZ with and texture coordinates applied to all vertices. * \ingroup Graphics */ @@ -46,7 +46,7 @@ using namespace caret; * @param imageHeight * Height of the image. */ -GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const PrimitiveType primitiveType, +GraphicsPrimitiveV3fT3f::GraphicsPrimitiveV3fT3f(const PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) @@ -64,7 +64,7 @@ GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const PrimitiveType primitiveTy /** * Destructor. */ -GraphicsPrimitiveV3fT3F::~GraphicsPrimitiveV3fT3F() +GraphicsPrimitiveV3fT3f::~GraphicsPrimitiveV3fT3f() { } @@ -73,10 +73,10 @@ GraphicsPrimitiveV3fT3F::~GraphicsPrimitiveV3fT3F() * @param obj * Object that is copied. */ -GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj) +GraphicsPrimitiveV3fT3f::GraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj) : GraphicsPrimitive(obj) { - this->copyHelperGraphicsPrimitiveV3fT3F(obj); + this->copyHelperGraphicsPrimitiveV3fT3f(obj); } /** @@ -85,7 +85,7 @@ GraphicsPrimitiveV3fT3F::GraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& * Object that is copied. */ void -GraphicsPrimitiveV3fT3F::copyHelperGraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& /*obj*/) +GraphicsPrimitiveV3fT3f::copyHelperGraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& /*obj*/) { } @@ -99,7 +99,7 @@ GraphicsPrimitiveV3fT3F::copyHelperGraphicsPrimitiveV3fT3F(const GraphicsPrimiti * Texture coordinates */ void -GraphicsPrimitiveV3fT3F::addVertex(const float xyz[3], +GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], const float st[2]) { m_xyz.insert(m_xyz.end(), @@ -124,7 +124,7 @@ GraphicsPrimitiveV3fT3F::addVertex(const float xyz[3], * T-coordinate of texture */ void -GraphicsPrimitiveV3fT3F::addVertex(const float x, +GraphicsPrimitiveV3fT3f::addVertex(const float x, const float y, const float z, const float s, @@ -151,7 +151,7 @@ GraphicsPrimitiveV3fT3F::addVertex(const float x, * T-coordinate of texture */ void -GraphicsPrimitiveV3fT3F::addVertex(const float x, +GraphicsPrimitiveV3fT3f::addVertex(const float x, const float y, const float s, const float t) @@ -168,9 +168,9 @@ GraphicsPrimitiveV3fT3F::addVertex(const float x, * Clone this primitive. */ GraphicsPrimitive* -GraphicsPrimitiveV3fT3F::clone() const +GraphicsPrimitiveV3fT3f::clone() const { - GraphicsPrimitiveV3fT3F* obj = new GraphicsPrimitiveV3fT3F(*this); + GraphicsPrimitiveV3fT3f* obj = new GraphicsPrimitiveV3fT3f(*this); return obj; } diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.h b/src/Graphics/GraphicsPrimitiveV3fT3f.h index 75907aef5..a0845280b 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.h +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.h @@ -31,17 +31,17 @@ namespace caret { - class GraphicsPrimitiveV3fT3F : public GraphicsPrimitive { + class GraphicsPrimitiveV3fT3f : public GraphicsPrimitive { public: - GraphicsPrimitiveV3fT3F(const PrimitiveType primitiveType, + GraphicsPrimitiveV3fT3f(const PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); - virtual ~GraphicsPrimitiveV3fT3F(); + virtual ~GraphicsPrimitiveV3fT3f(); - GraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj); + GraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj); void addVertex(const float xyz[3], const float st[2]); @@ -62,9 +62,9 @@ namespace caret { // ADD_NEW_METHODS_HERE private: - GraphicsPrimitiveV3fT3F& operator=(const GraphicsPrimitiveV3fT3F& obj); + GraphicsPrimitiveV3fT3f& operator=(const GraphicsPrimitiveV3fT3f& obj); - void copyHelperGraphicsPrimitiveV3fT3F(const GraphicsPrimitiveV3fT3F& obj); + void copyHelperGraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj); // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index ce0ec5eac..a5b9f9e3d 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -247,7 +247,7 @@ AnnotationMenuArrange::menuActionTriggered(QAction* action) void AnnotationMenuArrange::applyAlignment(const AnnotationAlignmentEnum::Enum alignment) { - EventGetBrainOpenGLTextRenderer textRendererEvent(m_browserWindowIndex); + EventGetBrainOpenGLTextRenderer textRendererEvent; EventManager::get()->sendEvent(textRendererEvent.getPointer()); BrainOpenGLTextRenderInterface* textRenderer = textRendererEvent.getTextRenderer(); if (textRenderer == NULL) { @@ -281,7 +281,7 @@ AnnotationMenuArrange::applyAlignment(const AnnotationAlignmentEnum::Enum alignm void AnnotationMenuArrange::applyDistribute(const AnnotationDistributeEnum::Enum distribute) { - EventGetBrainOpenGLTextRenderer textRendererEvent(m_browserWindowIndex); + EventGetBrainOpenGLTextRenderer textRendererEvent; EventManager::get()->sendEvent(textRendererEvent.getPointer()); BrainOpenGLTextRenderInterface* textRenderer = textRendererEvent.getTextRenderer(); if (textRenderer == NULL) { diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 2495214be..af2ee9b1c 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -39,7 +39,6 @@ #include "BrainBrowserWindow.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLShape.h" -#include "BrainOpenGLTextureManager.h" #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" #include "BrowserTabContent.h" @@ -54,12 +53,10 @@ #include "EventManager.h" #include "EventBrowserWindowContentGet.h" #include "EventBrowserWindowGraphicsRedrawn.h" -#include "EventGetBrainOpenGLTextRenderer.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventIdentificationRequest.h" -#include "EventOpenGLTexture.h" #include "EventUserInterfaceUpdate.h" #include "FtglFontTextRenderer.h" #include "GuiManager.h" @@ -68,7 +65,6 @@ #include "Matrix4x4.h" #include "Model.h" #include "MouseEvent.h" -#include "QGLWidgetTextRenderer.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" #include "SelectionItemSurfaceNode.h" @@ -106,8 +102,7 @@ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, : QGLWidget(parent, shareWidget), #endif -windowIndex(windowIndex), -m_textRenderer(NULL) +windowIndex(windowIndex) { this->borderBeingDrawn = new Border(); @@ -150,7 +145,6 @@ m_textRenderer(NULL) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_REQUEST); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IMAGE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); @@ -195,9 +189,6 @@ BrainOpenGLWidget::~BrainOpenGLWidget() { makeCurrent(); - /** DO NOT delete since not owned by this */ - m_textRenderer = NULL; - this->clearDrawingViewportContents(); delete this->userInputViewModeProcessor; @@ -240,19 +231,23 @@ void BrainOpenGLWidget::initializeGL() { if (s_singletonOpenGL == NULL) { - s_singletonOpenGL = new BrainOpenGLFixedPipeline(createTextRenderer()); - } - else { /* - * You would think Qt would need to call initializedGL() only once. - * However, if QGLWidget::renderPixmap() is called, it calls - * this method since it needs to create a new OpenGL context. - * Since the OpenGL context contains textures (and the font - * rendering may use textures), The text renderer must be - * recreated. Otherwise, fonts will be garbage in the - * image produced by QGLWidget::renderPixmap(). + * OpenGL drawing will take ownership of the text renderer + * and handle deletion of the text renderer. */ - s_singletonOpenGL->setTextRenderer(createTextRenderer()); + BrainOpenGLTextRenderInterface* textRenderer = new FtglFontTextRenderer(); + if (! textRenderer->isValid()) { + delete textRenderer; + textRenderer = NULL; + CaretLogWarning("Unable to create FTGL Font Renderer.\n" + "No text will be available in graphics window."); + } + if (textRenderer == NULL) { + textRenderer = new DummyFontTextRenderer(); + } + CaretAssert(textRenderer); + + s_singletonOpenGL = new BrainOpenGLFixedPipeline(textRenderer); } s_singletonOpenGL->initializeOpenGL(); @@ -404,53 +399,6 @@ BrainOpenGLWidget::getOpenGLInformation() return info; } -/** - * @return A new text renderer. - */ -BrainOpenGLTextRenderInterface* -BrainOpenGLWidget::createTextRenderer() -{ - BrainOpenGLTextRenderInterface* textRendererOut = NULL; - - /* - * Create a FTGL font renderer - */ - if (textRendererOut == NULL){ - textRendererOut = new FtglFontTextRenderer(); - if ( ! textRendererOut->isValid()) { - CaretLogWarning("Failed to create FTGL text renderer."); - delete textRendererOut; - textRendererOut = NULL; - } - } - -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - /* No Qt Text Renderer in QOpenGLWidget */ -#else - /* - * Create a Qt text renderer - */ - if (textRendererOut == NULL) { - textRendererOut = new QGLWidgetTextRenderer(this); - if ( ! textRendererOut->isValid()) { - CaretLogWarning("Failed to create Qt text renderer."); - delete textRendererOut; - textRendererOut = NULL; - } - } -#endif - - if (textRendererOut == NULL) { - CaretLogSevere("Unable to create a text renderer for OpenGL. " - "No text will be drawn (dummy text renderer)."); - textRendererOut = new DummyFontTextRenderer(); - } - - m_textRenderer = textRendererOut; - - return textRendererOut; -} - /** * Called when widget is resized. */ @@ -1480,15 +1428,6 @@ BrainOpenGLWidget::receiveEvent(Event* event) brainResetEvent->setEventProcessed(); } - else if (event->getEventType() == EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW) { - EventGetBrainOpenGLTextRenderer* textRenderEvent = dynamic_cast(event); - CaretAssert(textRenderEvent); - - if (this->windowIndex == textRenderEvent->getWindowIndex()) { - textRenderEvent->setTextRenderer(m_textRenderer); - textRenderEvent->setEventProcessed(); - } - } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) { EventGraphicsUpdateAllWindows* updateAllEvent = dynamic_cast(event); @@ -1708,13 +1647,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) WuQMessageBox::errorOk(this, "Render PixMap not implemented with Qt5"); #else /* - * Note 1: QGLWidget::renderPixmap() creates a new OpenGL - * Context which destroys any textures in the existing - * OpenGL context. So, after execution of - * QGLWidget::renderPixmap(), we need to create a - * new text renderer. - * - * Note 2: When the user chooses to exclude regions + * When the user chooses to exclude regions * caused by locking of tab/window aspect ratio, * the pixmap is rendered to the output width and * height and in the correct aspect ratio so when @@ -1722,15 +1655,10 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) * region caused by aspect locking that needs to * be excluded. */ - BrainOpenGLTextureManager* textureManager = s_singletonOpenGL->getTextureManager(); - CaretAssert(textureManager); - textureManager->deleteAllTexturesForWindow(this->windowIndex); QPixmap pixmap = this->renderPixmap(outputImageWidth, outputImageHeight); image = pixmap.toImage(); - textureManager->deleteAllTexturesForWindow(this->windowIndex); - s_singletonOpenGL->setTextRenderer(createTextRenderer()); #endif } break; diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 6d4961b0c..2c9c8a39e 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -46,7 +46,6 @@ namespace caret { class Border; class BrainOpenGL; - class BrainOpenGLTextRenderInterface; class BrainOpenGLViewportContent; class BrowserTabContent; class EventImageCapture; @@ -138,8 +137,6 @@ namespace caret { private: - BrainOpenGLTextRenderInterface* createTextRenderer(); - void clearDrawingViewportContents(); BrainOpenGLViewportContent* getViewportContentAtXY(const int x, @@ -154,9 +151,6 @@ namespace caret { const int32_t windowIndex; - /** Do not own text renderer so DO NOT delete */ - BrainOpenGLTextRenderInterface* m_textRenderer; - std::vector drawingViewportContents; int32_t windowWidth[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index ef1033c25..da2e4d97d 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -103,9 +103,9 @@ Algorithms OperationsBase GuiQt Brain -Graphics Files Annotations +Graphics Cifti Gifti Nifti @@ -117,6 +117,9 @@ Xml Common ${QT5_LINK_LIBS} ${QT_LIBRARIES} +${OSMESA_OFFSCREEN_LIBRARY} +${OSMESA_GL_LIBRARY} +${OSMESA_GLU_LIBRARY} ${ZLIB_LIBRARIES} #${LIBS} ) -- GitLab From 59b29e328ed4ac5452c53c0e38384c2aaa7ad5ac Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 1 Jun 2017 09:20:37 -0500 Subject: [PATCH 272/755] Add checkbox to Chart Axis controls in toolbar so that user may turn off the display of an axis. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 25 ++++++++-- src/Brain/ChartTwoOverlaySet.cxx | 28 +++++------ src/Charting/ChartTwoCartesianAxis.cxx | 47 ++++++++++++++----- src/Charting/ChartTwoCartesianAxis.h | 13 +++-- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 10 +++- .../BrainBrowserWindowToolBarChartTwoAxes.h | 2 + 6 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index dd821a59e..3075caccb 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1095,10 +1095,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH if (cartesianAxis == NULL) { return; } - if ( ! cartesianAxis->isVisible()) { + if ( ! cartesianAxis->isEnabledByChart()) { return; } - /* * The length of the axis does not matter here. * We are just estimating the width and height of the axes text labels. @@ -1114,6 +1113,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH maximumValue, scaleValueOffsetInPixels, scaleValuesText); + + if ( ! cartesianAxis->isDisplayedByUser()) { + return; + } + for (std::vector::iterator iter = scaleValuesText.begin(); iter != scaleValuesText.end(); iter++) { @@ -1308,11 +1312,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data if (axis == NULL) { return false; } - if ( ! axis->isVisible()) { + if ( ! axis->isEnabledByChart()) { return false; } - int32_t axisVpX = 0; int32_t axisVpY = 0; int32_t axisVpWidth = 0; @@ -1367,6 +1370,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data return false; } + /* + * If user has disabled display of axis no further action is needed + * as the axisMinimumOut and axisMaximumOut have been calculated + */ + if ( ! axis->isDisplayedByUser()) { + /* + * Even though axis is not displayed, declare the axis as valid + * so that axisMinimumOut and axisMaximumOut are used by caller + * of this method. Otherwise, height of chart will 'jump' as + * axis is turned on/off + */ + return true; + } + const float rgba[4] = { m_fixedPipelineDrawing->m_foregroundColorFloat[0], m_fixedPipelineDrawing->m_foregroundColorFloat[1], diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 304d04ffd..7c1529bc4 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -71,15 +71,15 @@ m_tabIndex(tabIndex) m_chartAxisRight = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT)); m_chartAxisBottom = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); - m_chartAxisLeft->setVisible(false); - m_chartAxisRight->setVisible(false); - m_chartAxisBottom->setVisible(false); + m_chartAxisLeft->setEnabledByChart(false); + m_chartAxisRight->setEnabledByChart(false); + m_chartAxisBottom->setEnabledByChart(false); switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { - m_chartAxisLeft->setVisible(true); + m_chartAxisLeft->setEnabledByChart(true); m_chartAxisLeft->setAxisTitle("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); float rangeMin = 0.0, rangeMax = 0.0; @@ -87,21 +87,21 @@ m_tabIndex(tabIndex) rangeMin = 0.0; m_chartAxisLeft->setRange(rangeMin, rangeMax); - m_chartAxisRight->setVisible(false); + m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setAxisTitle("Counts"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); - m_chartAxisBottom->setVisible(true); + m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setAxisTitle("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - m_chartAxisLeft->setVisible(true); - m_chartAxisBottom->setVisible(true); + m_chartAxisLeft->setEnabledByChart(true); + m_chartAxisBottom->setEnabledByChart(true); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; @@ -659,17 +659,17 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const } } - m_chartAxisBottom->setVisible(showBottomFlag); - m_chartAxisLeft->setVisible(showLeftFlag); - m_chartAxisRight->setVisible(showRightFlag); + m_chartAxisBottom->setEnabledByChart(showBottomFlag); + m_chartAxisLeft->setEnabledByChart(showLeftFlag); + m_chartAxisRight->setEnabledByChart(showRightFlag); - if (m_chartAxisBottom->isVisible()) { + if (m_chartAxisBottom->isEnabledByChart()) { axes.push_back(m_chartAxisBottom.get()); } - if (m_chartAxisLeft->isVisible()) { + if (m_chartAxisLeft->isEnabledByChart()) { axes.push_back(m_chartAxisLeft.get()); } - if (m_chartAxisRight->isVisible()) { + if (m_chartAxisRight->isEnabledByChart()) { axes.push_back(m_chartAxisRight.get()); } diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 27d066694..bf343893a 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -60,6 +60,8 @@ m_axisLocation(axisLocation) m_rangeMaximumValue = std::numeric_limits::max(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_displayedByUser", + &m_displayedByUser); m_sceneAssistant->add("m_userScaleMinimumValue", &m_userScaleMinimumValue); m_sceneAssistant->add("m_userScaleMaximumValue", @@ -81,8 +83,8 @@ m_axisLocation(axisLocation) &m_userNumberOfSubdivisions); m_sceneAssistant->add("m_axisTitle", &m_axisTitle); - m_sceneAssistant->add("m_visible", - &m_visible); + m_sceneAssistant->add("m_enabledByChart", + &m_enabledByChart); m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); } @@ -134,6 +136,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx { CaretAssert(m_axisLocation == obj.m_axisLocation); + m_displayedByUser = obj.m_displayedByUser; m_rangeMinimumValue = obj.m_rangeMinimumValue; m_rangeMaximumValue = obj.m_rangeMaximumValue; m_userScaleMinimumValue = obj.m_userScaleMinimumValue; @@ -146,7 +149,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_autoSubdivisionsEnabled = obj.m_autoSubdivisionsEnabled; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_axisTitle = obj.m_axisTitle; - m_visible = obj.m_visible; + m_enabledByChart = obj.m_enabledByChart; m_showTickmarks = obj.m_showTickmarks; limitUserScaleMinMaxToValidRange(); } @@ -160,6 +163,25 @@ ChartTwoCartesianAxis::getAxisLocation() const return m_axisLocation; } +/** + * @return display the axis selected by user + */ +bool +ChartTwoCartesianAxis::isDisplayedByUser() const +{ + return m_displayedByUser; +} + +/** + * Set display the axis by user + * @param displayedByUser + * New value for display the axis + */ +void +ChartTwoCartesianAxis::setDisplayedByUser(const bool displayedByUser) +{ + m_displayedByUser = displayedByUser; +} /** * Get the range of values allowed. * @@ -313,24 +335,24 @@ ChartTwoCartesianAxis::setUserScaleMinimumValue(const float userScaleMinimumValu } /** - * @return Is the axis visible + * @return Is the axis enabled because a chart is using it */ bool -ChartTwoCartesianAxis::isVisible() const +ChartTwoCartesianAxis::isEnabledByChart() const { - return m_visible; + return m_enabledByChart; } /** - * Set visibility for the axis + * Set the axis enabled because a chart is using it * - * @param visible - * New value for axis visibility + * @param enabled + * New enabled status */ void -ChartTwoCartesianAxis::setVisible(const bool visible) +ChartTwoCartesianAxis::setEnabledByChart(const bool enabled) { - m_visible = visible; + m_enabledByChart = enabled; } /** @@ -494,6 +516,9 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + // may not be in older scenes + m_displayedByUser = true; + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 3fe5364ea..db6d7def8 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -47,6 +47,10 @@ namespace caret { ChartAxisLocationEnum::Enum getAxisLocation() const; + bool isDisplayedByUser() const; + + void setDisplayedByUser(const bool displayed); + void getRange(float& rangeMinimumOut, float& rangeMaximumOut) const; @@ -85,9 +89,9 @@ namespace caret { void setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions); - bool isVisible() const; + bool isEnabledByChart() const; - void setVisible(const bool visible); + void setEnabledByChart(const bool enabled); bool isShowTickmarks() const; @@ -170,10 +174,13 @@ namespace caret { AString m_axisTitle; - bool m_visible = false; + bool m_enabledByChart = false; bool m_showTickmarks = true; + /** user display the axis*/ + bool m_displayedByUser = true; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 81c01add5..93c5fb5c8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -67,6 +67,11 @@ using namespace caret; BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar) { + m_axisDisplayedByUserCheckBox = new QCheckBox("Axis"); + m_axisDisplayedByUserCheckBox->setToolTip("Show/Hide the axis"); + QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + /* * Axes selection */ @@ -133,6 +138,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Group widgets for blocking signals */ m_widgetGroup = new WuQWidgetObjectGroup(this); + m_widgetGroup->add(m_axisDisplayedByUserCheckBox); m_widgetGroup->add(m_axisNameToolButton); m_widgetGroup->add(m_autoUserRangeComboBox->getWidget()); m_widgetGroup->add(m_userMinimumValueSpinBox); @@ -155,7 +161,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QGridLayout* layout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); int leftRow = 0; - layout->addWidget(new QLabel("Axis"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_axisDisplayedByUserCheckBox, leftRow, COLUMN_ONE, Qt::AlignLeft); layout->addWidget(m_axisComboBox->getWidget(), leftRow, COLUMN_TWO); leftRow++; layout->addWidget(new QLabel("Range"), leftRow, COLUMN_ONE, Qt::AlignLeft); @@ -348,6 +354,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* cha if (m_chartAxis != NULL) { m_widgetGroup->blockAllSignals(true); + m_axisDisplayedByUserCheckBox->setChecked(chartAxis->isDisplayedByUser()); //m_axisNameToolButton->setText(m_chartAxis->getLabelText()); m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); float rangeMin(0.0), rangeMax(0.0); @@ -377,6 +384,7 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() { CaretAssert(m_chartAxis); if (m_chartAxis != NULL) { + m_chartAxis->setDisplayedByUser(m_axisDisplayedByUserCheckBox->isChecked()); m_chartAxis->setScaleRangeMode(m_autoUserRangeComboBox->getSelectedItem()); m_chartAxis->setUserScaleMinimumValue(m_userMinimumValueSpinBox->value()); m_chartAxis->setUserScaleMaximumValue(m_userMaximumValueSpinBox->value()); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index bc99de50c..8a9bdf9f4 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -82,6 +82,8 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + QCheckBox* m_axisDisplayedByUserCheckBox; + EnumComboBoxTemplate* m_axisComboBox; QToolButton* m_axisNameToolButton; -- GitLab From 98f964bc8231ee8645626d33938a2beaa0e95912 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 1 Jun 2017 12:30:54 -0500 Subject: [PATCH 273/755] Improvements to layout of the Chart Axes controls in the toolbar. --- src/Charting/CMakeLists.txt | 2 + src/Charting/ChartTwoCartesianAxis.cxx | 42 +- src/Charting/ChartTwoCartesianAxis.h | 8 +- .../ChartTwoNumericSubdivisionsModeEnum.cxx | 373 ++++++++++++++++++ .../ChartTwoNumericSubdivisionsModeEnum.h | 104 +++++ .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 165 +++++--- .../BrainBrowserWindowToolBarChartTwoAxes.h | 2 +- 7 files changed, 627 insertions(+), 69 deletions(-) create mode 100644 src/Charting/ChartTwoNumericSubdivisionsModeEnum.cxx create mode 100644 src/Charting/ChartTwoNumericSubdivisionsModeEnum.h diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index aebdf2d0b..ec85bed1b 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -51,6 +51,7 @@ ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixDisplayProperties.h ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h +ChartTwoNumericSubdivisionsModeEnum.h ChartTwoAxisScaleRangeModeEnum.cxx ChartAxis.cxx @@ -88,6 +89,7 @@ ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixDisplayProperties.cxx ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx +ChartTwoNumericSubdivisionsModeEnum.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index bf343893a..2be44f399 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -77,8 +77,8 @@ m_axisLocation(axisLocation) &m_units); m_sceneAssistant->add("m_userNumericFormat", &m_userNumericFormat); - m_sceneAssistant->add("m_autoSubdivisionsEnabled", - &m_autoSubdivisionsEnabled); + m_sceneAssistant->add("m_numericSubdivsionsMode", + &m_numericSubdivsionsMode); m_sceneAssistant->add("m_userNumberOfSubdivisions", &m_userNumberOfSubdivisions); m_sceneAssistant->add("m_axisTitle", @@ -146,7 +146,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_scaleRangeMode = obj.m_scaleRangeMode; m_units = obj.m_units; m_userNumericFormat = obj.m_userNumericFormat; - m_autoSubdivisionsEnabled = obj.m_autoSubdivisionsEnabled; + m_numericSubdivsionsMode = obj.m_numericSubdivsionsMode; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_axisTitle = obj.m_axisTitle; m_enabledByChart = obj.m_enabledByChart; @@ -272,24 +272,24 @@ ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivi } /** - * @return auto subdivisions enabled + * @return numeric subdivisions mode */ -bool -ChartTwoCartesianAxis::isAutoSubdivisionsEnabled() const +ChartTwoNumericSubdivisionsModeEnum::Enum +ChartTwoCartesianAxis::getNumericSubdivsionsMode() const { - return m_autoSubdivisionsEnabled; + return m_numericSubdivsionsMode; } /** - * Set auto subdivisions enabled + * Set numeric subdivisions mode * - * @param autoSubdivisionsEnabled - * New value for auto subdivisions enabled + * @param numericSubdivsionsMode + * New value for numeric subdivisions mode */ void -ChartTwoCartesianAxis::setAutoSubdivisionsEnabled(const bool autoSubdivisionsEnabled) +ChartTwoCartesianAxis::setNumericSubdivsionsMode(const ChartTwoNumericSubdivisionsModeEnum::Enum numericSubdivsionsMode) { - m_autoSubdivisionsEnabled = autoSubdivisionsEnabled; + m_numericSubdivsionsMode = numericSubdivsionsMode; } /** @@ -687,13 +687,19 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], break; } - if ( ! m_autoSubdivisionsEnabled) { - const float labelsRange = labelsEnd - labelsStart; - if (labelsRange <= 0.0) { - return false; + switch (m_numericSubdivsionsMode) { + case ChartTwoNumericSubdivisionsModeEnum::AUTO: + break; + case ChartTwoNumericSubdivisionsModeEnum::USER: + { + const float labelsRange = labelsEnd - labelsStart; + if (labelsRange <= 0.0) { + return false; + } + const float dividend = (1.0 + m_userNumberOfSubdivisions); + labelsStep = labelsRange / dividend; } - const float dividend = (1.0 + m_userNumberOfSubdivisions); - labelsStep = labelsRange / dividend; + break; } minimumOut = labelsStart; diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index db6d7def8..8ab96fcf9 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -27,6 +27,7 @@ #include "ChartAxisLocationEnum.h" #include "ChartAxisUnitsEnum.h" #include "ChartTwoAxisScaleRangeModeEnum.h" +#include "ChartTwoNumericSubdivisionsModeEnum.h" #include "NumericFormatModeEnum.h" #include "SceneableInterface.h" @@ -81,9 +82,9 @@ namespace caret { void setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat); - bool isAutoSubdivisionsEnabled() const; + ChartTwoNumericSubdivisionsModeEnum::Enum getNumericSubdivsionsMode() const; - void setAutoSubdivisionsEnabled(const bool autoSubdivisionsEnabled); + void setNumericSubdivsionsMode(const ChartTwoNumericSubdivisionsModeEnum::Enum numericSubdivsionsMode); int32_t getUserNumberOfSubdivisions() const; @@ -168,7 +169,8 @@ namespace caret { NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; - bool m_autoSubdivisionsEnabled = true; + /** numeric subdivisions mode*/ + ChartTwoNumericSubdivisionsModeEnum::Enum m_numericSubdivsionsMode = ChartTwoNumericSubdivisionsModeEnum::AUTO; int32_t m_userNumberOfSubdivisions = 2; diff --git a/src/Charting/ChartTwoNumericSubdivisionsModeEnum.cxx b/src/Charting/ChartTwoNumericSubdivisionsModeEnum.cxx new file mode 100644 index 000000000..cdffdd5a4 --- /dev/null +++ b/src/Charting/ChartTwoNumericSubdivisionsModeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ +#include "ChartTwoNumericSubdivisionsModeEnum.h" +#undef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::ChartTwoNumericSubdivisionsModeEnum + * \brief Enumerated type for charting numeric subdivisions + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_chartTwoNumericSubdivisionsModeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void chartTwoNumericSubdivisionsModeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "ChartTwoNumericSubdivisionsModeEnum.h" + * + * Instatiate: + * m_chartTwoNumericSubdivisionsModeEnumComboBox = new EnumComboBoxTemplate(this); + * m_chartTwoNumericSubdivisionsModeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_chartTwoNumericSubdivisionsModeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(chartTwoNumericSubdivisionsModeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_chartTwoNumericSubdivisionsModeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const ChartTwoNumericSubdivisionsModeEnum::Enum VARIABLE = m_chartTwoNumericSubdivisionsModeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +ChartTwoNumericSubdivisionsModeEnum::ChartTwoNumericSubdivisionsModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +ChartTwoNumericSubdivisionsModeEnum::~ChartTwoNumericSubdivisionsModeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +ChartTwoNumericSubdivisionsModeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(ChartTwoNumericSubdivisionsModeEnum(AUTO, + "AUTO", + "Auto")); + + enumData.push_back(ChartTwoNumericSubdivisionsModeEnum(USER, + "USER", + "User")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const ChartTwoNumericSubdivisionsModeEnum* +ChartTwoNumericSubdivisionsModeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const ChartTwoNumericSubdivisionsModeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoNumericSubdivisionsModeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoNumericSubdivisionsModeEnum::Enum +ChartTwoNumericSubdivisionsModeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoNumericSubdivisionsModeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +ChartTwoNumericSubdivisionsModeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +ChartTwoNumericSubdivisionsModeEnum::Enum +ChartTwoNumericSubdivisionsModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoNumericSubdivisionsModeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +ChartTwoNumericSubdivisionsModeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +ChartTwoNumericSubdivisionsModeEnum::Enum +ChartTwoNumericSubdivisionsModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const ChartTwoNumericSubdivisionsModeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +ChartTwoNumericSubdivisionsModeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoNumericSubdivisionsModeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(ChartTwoNumericSubdivisionsModeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +ChartTwoNumericSubdivisionsModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(ChartTwoNumericSubdivisionsModeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Charting/ChartTwoNumericSubdivisionsModeEnum.h b/src/Charting/ChartTwoNumericSubdivisionsModeEnum.h new file mode 100644 index 000000000..605dd09c5 --- /dev/null +++ b/src/Charting/ChartTwoNumericSubdivisionsModeEnum.h @@ -0,0 +1,104 @@ +#ifndef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ +#define __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class ChartTwoNumericSubdivisionsModeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Automatic */ + AUTO, + /** User-defined subdivisions */ + USER + }; + + + ~ChartTwoNumericSubdivisionsModeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + ChartTwoNumericSubdivisionsModeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const ChartTwoNumericSubdivisionsModeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ +std::vector ChartTwoNumericSubdivisionsModeEnum::enumData; +bool ChartTwoNumericSubdivisionsModeEnum::initializedFlag = false; +int32_t ChartTwoNumericSubdivisionsModeEnum::integerCodeCounter = 0; +#endif // __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ + +} // namespace +#endif //__CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 93c5fb5c8..31358a29e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -85,7 +86,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Controls for axis parameters */ m_axisNameToolButton = new QToolButton(); - m_axisNameToolButton->setText("Edit Axis Title"); + m_axisNameToolButton->setText("Edit Title"); QObject::connect(m_axisNameToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); @@ -124,10 +125,11 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userDigitsRightOfDecimalSpinBox->setToolTip("Set digits right of decimal for\ndecimal or scientific format"); - m_autoSubdivisionsCheckBox = new QCheckBox("Auto"); - QObject::connect(m_autoSubdivisionsCheckBox, &QCheckBox::clicked, - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); - m_autoSubdivisionsCheckBox->setToolTip("Enable auto subdivisions"); + m_numericSubdivisionsModeComboBox = new EnumComboBoxTemplate(this); + m_numericSubdivisionsModeComboBox->setup(); + QObject::connect(m_numericSubdivisionsModeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + m_numericSubdivisionsModeComboBox->getWidget()->setToolTip("Numeric subdivisions mode"); m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 100, 1); QObject::connect(m_userSubdivisionsSpinBox, static_cast(&QSpinBox::valueChanged), @@ -146,54 +148,123 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_widgetGroup->add(m_showTickMarksCheckBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); - m_widgetGroup->add(m_autoSubdivisionsCheckBox); + m_widgetGroup->add(m_numericSubdivisionsModeComboBox->getWidget()); m_widgetGroup->add(m_userSubdivisionsSpinBox); - const int COLUMN_ONE = 0; - const int COLUMN_TWO = 1; - const int COLUMN_THREE = 2; - const int COLUMN_FOUR = 3; - const int COLUMN_FIVE = 4; - const int COLUMN_SIX = 5; /* * Layouts */ - QGridLayout* layout = new QGridLayout(); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); - int leftRow = 0; - layout->addWidget(m_axisDisplayedByUserCheckBox, leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_axisComboBox->getWidget(), leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Range"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_autoUserRangeComboBox->getWidget(), leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Maximum"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_userMaximumValueSpinBox, leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Minimum"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_userMinimumValueSpinBox, leftRow, COLUMN_TWO); - leftRow++; + QLayout* widgetsLayout = NULL; - layout->setColumnMinimumWidth(COLUMN_THREE, 7); - - int rightRow = 0; - layout->addWidget(m_axisNameToolButton, rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Format"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Decimals"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Subdivisions"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_autoSubdivisionsCheckBox, rightRow, COLUMN_FIVE, Qt::AlignHCenter); - layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_SIX, Qt::AlignRight); - rightRow++; + const int layoutStyle = 0; + if (layoutStyle == 0) { + QWidget* rangeWidget = new QWidget(); + { + QGridLayout* rangeLayout = new QGridLayout(rangeWidget); + WuQtUtilities::setLayoutSpacingAndMargins(rangeLayout, 3, 0); + int row = 0; + rangeLayout->addWidget(new QLabel("Range Mode"), row, 0); + m_autoUserRangeComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + rangeLayout->addWidget(m_autoUserRangeComboBox->getWidget(), row, 1); + row++; + m_userMinimumValueSpinBox->setFixedWidth(90); + m_userMaximumValueSpinBox->setFixedWidth(90); + rangeLayout->addWidget(new QLabel("User Max"), row, 0); + rangeLayout->addWidget(m_userMaximumValueSpinBox, row, 1); + row++; + rangeLayout->addWidget(new QLabel("User Min"), row, 0); + rangeLayout->addWidget(m_userMinimumValueSpinBox, row, 1); + } + + QWidget* numericsWidget = new QWidget(); + { + QGridLayout* numericsLayout = new QGridLayout(numericsWidget); + WuQtUtilities::setLayoutSpacingAndMargins(numericsLayout, 3, 0); + int COLUMN_ONE = 0; + int COLUMN_TWO = 1; + int COLUMN_THREE = 2; + int row = 0; + numericsLayout->addWidget(new QLabel("Format"), row, COLUMN_ONE); + numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), row, COLUMN_TWO, 1, 2); + row++; + numericsLayout->addWidget(new QLabel("Decimals"), row, COLUMN_ONE); + numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, row, COLUMN_TWO, 1, 2); + row++; + numericsLayout->addWidget(new QLabel("Subdivisions"), row, COLUMN_ONE); + numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), row, COLUMN_TWO); + numericsLayout->addWidget(m_userSubdivisionsSpinBox, row, COLUMN_THREE); + } + + QHBoxLayout* axisLayout = new QHBoxLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(axisLayout, 3, 0); + axisLayout->addWidget(new QLabel("Axis ")); + axisLayout->addWidget(m_axisComboBox->getWidget()); + axisLayout->addSpacing(5); + axisLayout->addStretch(); + m_axisDisplayedByUserCheckBox->setText("Show Axis"); + axisLayout->addWidget(m_axisDisplayedByUserCheckBox); + axisLayout->addSpacing(10); + axisLayout->addWidget(m_showTickMarksCheckBox); + axisLayout->addSpacing(5); + axisLayout->addStretch(); + axisLayout->addWidget(m_axisNameToolButton); + + QGridLayout* gridLayout = new QGridLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 3, 0); + gridLayout->addLayout(axisLayout, 0, 0, 1, 3); + gridLayout->addWidget(rangeWidget, 1, 0); //, Qt::AlignHCenter | Qt::AlignTop); + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1); + gridLayout->addWidget(numericsWidget, 1, 2); + + widgetsLayout = gridLayout; + } + else { + const int COLUMN_ONE = 0; + const int COLUMN_TWO = 1; + const int COLUMN_THREE = 2; + const int COLUMN_FOUR = 3; + const int COLUMN_FIVE = 4; + const int COLUMN_SIX = 5; + + QGridLayout* layout = new QGridLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); + int leftRow = 0; + layout->addWidget(m_axisDisplayedByUserCheckBox, leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_axisComboBox->getWidget(), leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Range"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_autoUserRangeComboBox->getWidget(), leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Maximum"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_userMaximumValueSpinBox, leftRow, COLUMN_TWO); + leftRow++; + layout->addWidget(new QLabel("Minimum"), leftRow, COLUMN_ONE, Qt::AlignLeft); + layout->addWidget(m_userMinimumValueSpinBox, leftRow, COLUMN_TWO); + leftRow++; + + layout->setColumnMinimumWidth(COLUMN_THREE, 7); + + int rightRow = 0; + layout->addWidget(m_axisNameToolButton, rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE, 1, 2); + rightRow++; + layout->addWidget(new QLabel("Format"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE, 1, 2); + rightRow++; + layout->addWidget(new QLabel("Decimals"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE, 1, 2); + rightRow++; + layout->addWidget(new QLabel("Subdivisions"), rightRow, COLUMN_FOUR, Qt::AlignLeft); + layout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), rightRow, COLUMN_FIVE, Qt::AlignHCenter); + layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_SIX, Qt::AlignRight); + rightRow++; + + widgetsLayout = layout; + } QVBoxLayout* dialogLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); - dialogLayout->addLayout(layout); + dialogLayout->addLayout(widgetsLayout); dialogLayout->addStretch(); EventManager::get()->addEventListener(this, @@ -368,9 +439,9 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* cha m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); - m_autoSubdivisionsCheckBox->setChecked(m_chartAxis->isAutoSubdivisionsEnabled()); + m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); - m_userSubdivisionsSpinBox->setEnabled( ! m_chartAxis->isAutoSubdivisionsEnabled()); + m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); m_widgetGroup->blockAllSignals(false); } @@ -391,7 +462,7 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); - m_chartAxis->setAutoSubdivisionsEnabled(m_autoSubdivisionsCheckBox->isChecked()); + m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 8a9bdf9f4..665d5ffaa 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -100,7 +100,7 @@ namespace caret { QSpinBox* m_userDigitsRightOfDecimalSpinBox; - QCheckBox* m_autoSubdivisionsCheckBox; + EnumComboBoxTemplate* m_numericSubdivisionsModeComboBox; QSpinBox* m_userSubdivisionsSpinBox; -- GitLab From e36407e8833bd44e25fa5018b8f6ae832d9e61b7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 5 Jun 2017 16:19:13 -0500 Subject: [PATCH 274/755] Creating a new annotation type "chart label" so that user can select chart labels and change its text like a text annotation. --- src/Annotations/Annotation.cxx | 73 ++++++ src/Annotations/Annotation.h | 6 + .../AnnotationChartTwoAxisLabel.cxx | 138 ++++++++++ src/Annotations/AnnotationChartTwoAxisLabel.h | 62 +++++ .../AnnotationCoordinateSpaceEnum.cxx | 8 + .../AnnotationCoordinateSpaceEnum.h | 2 + .../AnnotationFontAttributesInterface.h | 2 +- src/Annotations/AnnotationGroup.cxx | 8 + .../AnnotationOneDimensionalShape.cxx | 6 + src/Annotations/AnnotationPercentSizeText.cxx | 56 ++++ src/Annotations/AnnotationPercentSizeText.h | 10 +- src/Annotations/AnnotationRedoUndoCommand.cxx | 4 + src/Annotations/AnnotationText.cxx | 74 +++++- src/Annotations/AnnotationText.h | 10 +- .../AnnotationTextFontSizeTypeEnum.cxx | 11 +- .../AnnotationTextFontSizeTypeEnum.h | 8 +- .../AnnotationTwoDimensionalShape.cxx | 17 +- src/Annotations/AnnotationTypeEnum.cxx | 6 +- src/Annotations/AnnotationTypeEnum.h | 2 + src/Annotations/CMakeLists.txt | 2 + src/Brain/AnnotationArrangerExecutor.cxx | 4 + src/Brain/AnnotationManager.cxx | 4 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 247 +++++++++++++++--- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 31 ++- .../BrainOpenGLChartDrawingFixedPipeline.cxx | 13 +- .../BrainOpenGLChartDrawingFixedPipeline.h | 1 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 109 ++++++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 9 +- .../BrainOpenGLChartTwoDrawingInterface.h | 7 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 24 +- src/Brain/BrainOpenGLFixedPipeline.h | 3 + src/Brain/BrainOpenGLTextRenderInterface.cxx | 4 + src/Brain/BrainOpenGLTextRenderInterface.h | 9 + src/Brain/ChartTwoOverlaySet.cxx | 7 +- src/Brain/DisplayPropertiesAnnotation.cxx | 5 + src/Brain/DummyFontTextRenderer.cxx | 5 +- src/Brain/DummyFontTextRenderer.h | 2 + src/Brain/FtglFontTextRenderer.cxx | 47 +++- src/Brain/FtglFontTextRenderer.h | 6 + src/Charting/ChartTwoCartesianAxis.cxx | 74 +++++- src/Charting/ChartTwoCartesianAxis.h | 10 +- src/Files/AnnotationFile.cxx | 14 + src/Files/AnnotationFileXmlFormatBase.h | 4 + src/Files/AnnotationFileXmlReader.cxx | 29 +- src/Files/AnnotationFileXmlWriter.cxx | 6 + .../AnnotationChangeCoordinateDialog.cxx | 2 + src/GuiQt/AnnotationColorWidget.cxx | 2 + src/GuiQt/AnnotationCoordinateInformation.cxx | 17 ++ .../AnnotationCoordinateSelectionWidget.cxx | 18 ++ src/GuiQt/AnnotationCoordinateSpaceWidget.cxx | 3 + src/GuiQt/AnnotationCoordinateWidget.cxx | 6 + src/GuiQt/AnnotationCreateDialog.cxx | 12 + src/GuiQt/AnnotationFontWidget.cxx | 2 + src/GuiQt/AnnotationInsertNewWidget.cxx | 9 + src/GuiQt/AnnotationPasteDialog.cxx | 2 + src/GuiQt/AnnotationRotationWidget.cxx | 4 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 5 +- src/GuiQt/QGLWidgetTextRenderer.cxx | 18 +- src/GuiQt/QGLWidgetTextRenderer.h | 6 + src/GuiQt/UserInputModeAnnotations.cxx | 7 + .../UserInputModeAnnotationsContextMenu.cxx | 2 + 61 files changed, 1163 insertions(+), 131 deletions(-) create mode 100644 src/Annotations/AnnotationChartTwoAxisLabel.cxx create mode 100644 src/Annotations/AnnotationChartTwoAxisLabel.h diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 5191ed201..7a103954e 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -24,6 +24,7 @@ #undef __ANNOTATION_DECLARE__ #include "AnnotationBox.h" +#include "AnnotationChartTwoAxisLabel.h" #include "AnnotationColorBar.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" @@ -124,6 +125,10 @@ Annotation::copyHelperAnnotation(const Annotation& obj) m_coordinateSpace = obj.m_coordinateSpace; m_tabIndex = obj.m_tabIndex; m_windowIndex = obj.m_windowIndex; + m_viewportCoordinateSpaceViewport[0] = obj.m_viewportCoordinateSpaceViewport[0]; + m_viewportCoordinateSpaceViewport[1] = obj.m_viewportCoordinateSpaceViewport[1]; + m_viewportCoordinateSpaceViewport[2] = obj.m_viewportCoordinateSpaceViewport[2]; + m_viewportCoordinateSpaceViewport[3] = obj.m_viewportCoordinateSpaceViewport[3]; m_lineWidth = obj.m_lineWidth; m_colorLine = obj.m_colorLine; m_colorBackground = obj.m_colorBackground; @@ -169,6 +174,13 @@ Annotation::clone() const myClone = new AnnotationBox(*box); } break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + { + const AnnotationChartTwoAxisLabel* axisLabel = dynamic_cast(this); + CaretAssert(axisLabel); + myClone = new AnnotationChartTwoAxisLabel(*axisLabel); + } + break; case AnnotationTypeEnum::COLOR_BAR: { const AnnotationColorBar* colorBar = dynamic_cast(this); @@ -204,6 +216,13 @@ Annotation::clone() const switch (text->getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: + { + const AnnotationPercentSizeText* pctText = dynamic_cast(text); + CaretAssert(pctText); + myClone = new AnnotationPercentSizeText(*pctText); + } + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: { const AnnotationPercentSizeText* pctText = dynamic_cast(text); CaretAssert(pctText); @@ -327,6 +346,10 @@ Annotation::newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, case AnnotationTypeEnum::BOX: annotation = new AnnotationBox(attributeDefaultType); break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + annotation = new AnnotationChartTwoAxisLabel(attributeDefaultType, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + break; case AnnotationTypeEnum::COLOR_BAR: annotation = new AnnotationColorBar(attributeDefaultType); break; @@ -366,6 +389,10 @@ Annotation::initializeAnnotationMembers() m_tabIndex = -1; m_windowIndex = -1; + m_viewportCoordinateSpaceViewport[0] = 0; + m_viewportCoordinateSpaceViewport[1] = 0; + m_viewportCoordinateSpaceViewport[2] = 0; + m_viewportCoordinateSpaceViewport[3] = 0; m_displayGroupAndTabItemHelper = new DisplayGroupAndTabItemHelper(); @@ -391,6 +418,9 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + m_colorBackground = CaretColorEnum::BLACK; + break; case AnnotationTypeEnum::COLOR_BAR: m_colorBackground = CaretColorEnum::BLACK; break; @@ -442,6 +472,8 @@ Annotation::initializeAnnotationMembers() m_colorBackground = defaultColor; } break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -487,6 +519,8 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + break; case AnnotationTypeEnum::COLOR_BAR: disallowLineColorNoneFlag = true; break; @@ -575,6 +609,8 @@ Annotation::getTextForPasteMenuItems(AString& pasteMenuItemText, switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -679,6 +715,41 @@ Annotation::setWindowIndex(const int32_t windowIndex) } } +/** + * Get the viewport used by an annotation in viewport coordinate space. + * + * @param viewportOut + * Ouput with the viewport. + */ +void +Annotation::getViewportCoordinateSpaceViewport(int viewportOut[4]) const +{ + viewportOut[0] = m_viewportCoordinateSpaceViewport[0]; + viewportOut[1] = m_viewportCoordinateSpaceViewport[1]; + viewportOut[2] = m_viewportCoordinateSpaceViewport[2]; + viewportOut[3] = m_viewportCoordinateSpaceViewport[3]; +} + +/** + * Set the viewport used by an annotation in viewport coordinate space. + * + * @param viewport + * Input with the viewport. + */ +void +Annotation::setViewportCoordinateSpaceViewport(const int viewport[4]) +{ + if ((m_viewportCoordinateSpaceViewport[0] != viewport[0]) + || (m_viewportCoordinateSpaceViewport[1] != viewport[1]) + || (m_viewportCoordinateSpaceViewport[2] != viewport[2]) + || (m_viewportCoordinateSpaceViewport[3] != viewport[3])) { + m_viewportCoordinateSpaceViewport[0] = viewport[0]; + m_viewportCoordinateSpaceViewport[1] = viewport[1]; + m_viewportCoordinateSpaceViewport[2] = viewport[2]; + m_viewportCoordinateSpaceViewport[3] = viewport[3]; + } +} + /** * Get a description of this object's content. * @return String describing this object's content. @@ -1154,6 +1225,8 @@ Annotation::textAnnotationResetName() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index d867e0ca1..ff90472a4 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -83,6 +83,10 @@ namespace caret { void setWindowIndex(const int32_t windowIndex); + void getViewportCoordinateSpaceViewport(int viewportOut[4]) const; + + void setViewportCoordinateSpaceViewport(const int viewport[4]); + CaretColorEnum::Enum getLineColor() const; void setLineColor(const CaretColorEnum::Enum color); @@ -279,6 +283,8 @@ namespace caret { int32_t m_windowIndex; + int32_t m_viewportCoordinateSpaceViewport[4]; + CaretColorEnum::Enum m_colorLine; CaretColorEnum::Enum m_colorBackground; diff --git a/src/Annotations/AnnotationChartTwoAxisLabel.cxx b/src/Annotations/AnnotationChartTwoAxisLabel.cxx new file mode 100644 index 000000000..65824695c --- /dev/null +++ b/src/Annotations/AnnotationChartTwoAxisLabel.cxx @@ -0,0 +1,138 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ +#include "AnnotationChartTwoAxisLabel.h" +#undef __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ + +#include "AnnotationCoordinate.h" +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::AnnotationChartTwoAxisLabel + * \brief Contains text for a chart two axis label + * \ingroup Annotations + */ + +/** + * Constructor. + * + * @param attributeDefaultType + * Defaults for new instances. + * @param fontSizeType + * Type of font sizing (percent width or height) + */ +AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) +: AnnotationPercentSizeText(AnnotationTypeEnum::CHART_AXIS_LABEL, + attributeDefaultType, + fontSizeType) +{ + setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); + setTextColor(CaretColorEnum::RED); + setLineColor(CaretColorEnum::NONE); + setBackgroundColor(CaretColorEnum::NONE); +} + +/** + * Destructor. + */ +AnnotationChartTwoAxisLabel::~AnnotationChartTwoAxisLabel() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj) +: AnnotationPercentSizeText(obj) +{ + this->copyHelperAnnotationChartTwoAxisLabel(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +AnnotationChartTwoAxisLabel& +AnnotationChartTwoAxisLabel::operator=(const AnnotationChartTwoAxisLabel& obj) +{ + if (this != &obj) { + AnnotationPercentSizeText::operator=(obj); + this->copyHelperAnnotationChartTwoAxisLabel(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +AnnotationChartTwoAxisLabel::copyHelperAnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj) +{ +// m_axisViewport[0] = obj.m_axisViewport[0]; +// m_axisViewport[1] = obj.m_axisViewport[1]; +// m_axisViewport[2] = obj.m_axisViewport[2]; +// m_axisViewport[3] = obj.m_axisViewport[3]; +} + +///** +// * Set the viewport in which the axis data is drawn. +// * +// * @param axisViewport +// * Values for viewport. +// */ +//void +//AnnotationChartTwoAxisLabel::setAxisViewport(const int32_t axisViewport[4]) +//{ +// m_axisViewport[0] = axisViewport[0]; +// m_axisViewport[1] = axisViewport[1]; +// m_axisViewport[2] = axisViewport[2]; +// m_axisViewport[3] = axisViewport[3]; +//} +// +///* +// * Get the viewport in which the axis is drawn. +// * +// * @param axisViewportOut +// * Output with the axis viewport. +// */ +//void +//AnnotationChartTwoAxisLabel::getAxisViewport(int32_t axisViewportOut[4]) const +//{ +// axisViewportOut[0] = m_axisViewport[0]; +// axisViewportOut[1] = m_axisViewport[1]; +// axisViewportOut[2] = m_axisViewport[2]; +// axisViewportOut[3] = m_axisViewport[3]; +//} +// + diff --git a/src/Annotations/AnnotationChartTwoAxisLabel.h b/src/Annotations/AnnotationChartTwoAxisLabel.h new file mode 100644 index 000000000..b08b15945 --- /dev/null +++ b/src/Annotations/AnnotationChartTwoAxisLabel.h @@ -0,0 +1,62 @@ +#ifndef __ANNOTATION_CHART_TWO_AXIS_LABEL_H__ +#define __ANNOTATION_CHART_TWO_AXIS_LABEL_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "AnnotationPercentSizeText.h" + + + +namespace caret { + + class AnnotationChartTwoAxisLabel : public AnnotationPercentSizeText { + + public: + AnnotationChartTwoAxisLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); + + virtual ~AnnotationChartTwoAxisLabel(); + + AnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj); + + AnnotationChartTwoAxisLabel& operator=(const AnnotationChartTwoAxisLabel& obj); + +// void setAxisViewport(const int32_t axisViewport[4]); +// +// void getAxisViewport(int32_t axisViewportOut[4]) const; + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperAnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj); + + // ADD_NEW_MEMBERS_HERE + +// int32_t m_axisViewport[4] = { 0, 0, 0, 0 }; + }; + +#ifdef __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ + // +#endif // __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ + +} // namespace +#endif //__ANNOTATION_CHART_TWO_AXIS_LABEL_H__ diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx index 46a5d58f8..7128c88c0 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx @@ -130,6 +130,11 @@ AnnotationCoordinateSpaceEnum::initialize() "Tab", "T")); + enumData.push_back(AnnotationCoordinateSpaceEnum(VIEWPORT, + "VIEWPORT", + "Viewport", + "V")); + enumData.push_back(AnnotationCoordinateSpaceEnum(WINDOW, "WINDOW", "Window", @@ -311,6 +316,9 @@ AnnotationCoordinateSpaceEnum::toToolTip(Enum enumValue) case TAB: text = "New annotation is drawn at an XY coordinate in the tab"; break; + case VIEWPORT: + text = "New annotation is drawn at an XY coordinate in the viewport"; + break; case WINDOW: text = "New annotation is drawn at an XY coordinate in the window"; break; diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.h b/src/Annotations/AnnotationCoordinateSpaceEnum.h index 5f7e4b8d1..a1c72a377 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.h +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.h @@ -43,6 +43,8 @@ public: SURFACE, /** Annotation in tab space */ TAB, + /** Annotation in viewport space */ + VIEWPORT, /** Annotation in window space */ WINDOW }; diff --git a/src/Annotations/AnnotationFontAttributesInterface.h b/src/Annotations/AnnotationFontAttributesInterface.h index 3d5f96707..e804e84f1 100644 --- a/src/Annotations/AnnotationFontAttributesInterface.h +++ b/src/Annotations/AnnotationFontAttributesInterface.h @@ -35,7 +35,7 @@ namespace caret { AnnotationFontAttributesInterface() { } virtual ~AnnotationFontAttributesInterface() { } - + virtual AnnotationTextFontNameEnum::Enum getFont() const = 0; virtual void setFont(const AnnotationTextFontNameEnum::Enum font) = 0; diff --git a/src/Annotations/AnnotationGroup.cxx b/src/Annotations/AnnotationGroup.cxx index 75ddadb0a..dad98b6e5 100644 --- a/src/Annotations/AnnotationGroup.cxx +++ b/src/Annotations/AnnotationGroup.cxx @@ -104,6 +104,9 @@ SceneableInterface() CaretAssert((tabOrWindowIndex >= 0) && (tabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::WINDOW: CaretAssert((tabOrWindowIndex >= 0) && (tabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); @@ -270,6 +273,9 @@ AnnotationGroup::getName() const spaceName.append(" " + AString::number(getTabOrWindowIndex() + 1)); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertMessage(0, "Should never be viewport"); + break; case AnnotationCoordinateSpaceEnum::WINDOW: spaceName.append(" " + AString::number(getTabOrWindowIndex() + 1)); @@ -432,6 +438,8 @@ AnnotationGroup::validateAddedAnnotation(const Annotation* annotation) return false; } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (m_tabOrWindowIndex != annotation->getWindowIndex()) { CaretLogSevere("Attempting to add anntation with non-matching tab index: "); diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index a71f1660b..b18643443 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -319,6 +319,7 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; + bool viewportFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::PIXELS: @@ -333,6 +334,9 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp case AnnotationCoordinateSpaceEnum::TAB: tabWindowFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + viewportFlag = true; + break; case AnnotationCoordinateSpaceEnum::WINDOW: tabWindowFlag = true; break; @@ -684,6 +688,8 @@ AnnotationOneDimensionalShape::applySpatialModification(const AnnotationSpatialM case AnnotationCoordinateSpaceEnum::TAB: return applySpatialModificationTabOrWindowSpace(spatialModification); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: return applySpatialModificationTabOrWindowSpace(spatialModification); break; diff --git a/src/Annotations/AnnotationPercentSizeText.cxx b/src/Annotations/AnnotationPercentSizeText.cxx index f52dfe5be..62b860592 100644 --- a/src/Annotations/AnnotationPercentSizeText.cxx +++ b/src/Annotations/AnnotationPercentSizeText.cxx @@ -24,6 +24,8 @@ #undef __ANNOTATION_PERCENT_SIZE_TEXT_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" + using namespace caret; @@ -34,6 +36,60 @@ using namespace caret; * \ingroup Annotations */ +/** + * Constructor. + * + * @param attributeDefaultType + * Type for attribute defaults + * @param textFontSizeType + * Type of font sizing must be percentage height/width + */ +AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType) +: AnnotationText(attributeDefaultType, + textFontSizeType) +{ + switch (textFontSizeType) { + case AnnotationTextFontSizeTypeEnum::POINTS: + CaretAssertMessage(0, "POINTS font size type not allowed for AnnotationPercentSizeText"); + CaretLogSevere("POINTS font size type not allowed for AnnotationPercentSizeText"); + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: + break; + } +} + +/** + * Constructor for subclass. + * + * @param type + * Type of annotation. + * @param attributeDefaultType + * Type for attribute defaults + * @param textFontSizeType + * Type of font sizing must be percentage height/width + */ +AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationTypeEnum::Enum type, + const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType) +: AnnotationText(type, + attributeDefaultType, + textFontSizeType) +{ + switch (textFontSizeType) { + case AnnotationTextFontSizeTypeEnum::POINTS: + CaretAssertMessage(0, "POINTS font size type not allowed for AnnotationPercentSizeText"); + CaretLogSevere("POINTS font size type not allowed for AnnotationPercentSizeText"); + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: + break; + } +} + /** * Constructor. * diff --git a/src/Annotations/AnnotationPercentSizeText.h b/src/Annotations/AnnotationPercentSizeText.h index 9984efa03..983c60a61 100644 --- a/src/Annotations/AnnotationPercentSizeText.h +++ b/src/Annotations/AnnotationPercentSizeText.h @@ -33,7 +33,10 @@ namespace caret { public: AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); - virtual ~AnnotationPercentSizeText(); + AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType); + + virtual ~AnnotationPercentSizeText(); AnnotationPercentSizeText(const AnnotationPercentSizeText& obj); @@ -45,6 +48,11 @@ namespace caret { // ADD_NEW_METHODS_HERE + protected: + AnnotationPercentSizeText(const AnnotationTypeEnum::Enum type, + const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType); + private: void copyHelperAnnotationPercentSizeText(const AnnotationPercentSizeText& obj); diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index ba84295a8..132095598 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -1380,6 +1380,8 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, } } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: { const int windowIndex = oneDimAnn->getWindowIndex(); @@ -1863,6 +1865,8 @@ AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercent break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index fbb4dec35..afbd6a321 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -69,6 +69,27 @@ m_fontSizeType(fontSizeType) initializeAnnotationTextMembers(); } +/** + * Constructor for subclass. + * + * @param type + * Type of annotation. + * @param attributeDefaultType + * Type for attribute defaults + * @param fontSizeType + * Type of font sizing. + */ +AnnotationText::AnnotationText(const AnnotationTypeEnum::Enum type, + const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) +: AnnotationTwoDimensionalShape(type, + attributeDefaultType), +AnnotationFontAttributesInterface(), +m_fontSizeType(fontSizeType) +{ + initializeAnnotationTextMembers(); +} + /** * Destructor. */ @@ -173,23 +194,44 @@ AnnotationText::initializeAnnotationTextMembers() * scale while drawing the text (using glScale()), the * quality is poor. * + * @param drawingViewportWidth + * Width of the viewport that may be used to scale the font height. * @param drawingViewportHeight * Height of the viewport that may be used to scale the font height. * @return * Encoded name for font. */ AString -AnnotationText::getFontRenderingEncodedName(const float drawingViewportHeight) const +AnnotationText::getFontRenderingEncodedName(const float drawingViewportWidth, + const float drawingViewportHeight) const { AString fontSizeID = AnnotationTextFontPointSizeEnum::toName(m_fontPointSize); - if (m_fontPercentViewportSize > 0.0) { - if (drawingViewportHeight> 0.0) { - const int32_t fontSizeInt = getFontSizeForDrawing(drawingViewportHeight); - if (fontSizeInt > 0) { - fontSizeID = "SIZE" + AString::number(fontSizeInt); + switch (m_fontSizeType) { + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: + if (m_fontPercentViewportSize > 0.0) { + if (drawingViewportHeight > 0.0) { + const int32_t fontSizeInt = getFontSizeForDrawing(drawingViewportWidth, + drawingViewportHeight); + if (fontSizeInt > 0) { + fontSizeID = "SIZE" + AString::number(fontSizeInt); + } + } } - } + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + if (m_fontPercentViewportSize > 0.0) { + if (drawingViewportWidth > 0.0) { + const int32_t fontSizeInt = getFontSizeForDrawing(drawingViewportWidth, + drawingViewportHeight); + if (fontSizeInt > 0) { + fontSizeID = "SIZE" + AString::number(fontSizeInt); + } + } + } + break; + case AnnotationTextFontSizeTypeEnum::POINTS: + break; } AString encodedName; @@ -362,17 +404,23 @@ AnnotationText::setFont(const AnnotationTextFontNameEnum::Enum font) * "percent size" of the viewport height in a range from zero to * one where one equivalent to the viewport's height. * + * @param drawingViewportWidth + * Width of the viewport that may be used to scale the font height. * @param drawingViewportHeight * Height of the viewport that may be used to scale the font height. * @return * Size of the font. */ int32_t -AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportHeight) const +AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportWidth, + const int32_t drawingViewportHeight) const { float sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(AnnotationTextFontPointSizeEnum::SIZE14); switch (m_fontSizeType) { + case AnnotationTextFontSizeTypeEnum::POINTS: + sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(m_fontPointSize); + break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { /* @@ -382,8 +430,14 @@ AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportHeight) const sizeForDrawing = pixelSize; } break; - case AnnotationTextFontSizeTypeEnum::POINTS: - sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(m_fontPointSize); + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + { + /* + * May need pixel to points conversion if not 72 DPI + */ + const float pixelSize = drawingViewportWidth * (m_fontPercentViewportSize / 100.0); + sizeForDrawing = pixelSize; + } break; } diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index 6b3688ccf..339d01305 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -42,7 +42,8 @@ namespace caret { AnnotationText& operator=(const AnnotationText& obj); - AString getFontRenderingEncodedName(const float drawingViewportHeight) const; + AString getFontRenderingEncodedName(const float drawingViewportWidth, + const float drawingViewportHeight) const; AString getText() const; @@ -68,7 +69,8 @@ namespace caret { void setOrientation(const AnnotationTextOrientationEnum::Enum orientation); - int32_t getFontSizeForDrawing(const int32_t drawingViewportHeight) const; + int32_t getFontSizeForDrawing(const int32_t drawingViewportWidth, + const int32_t drawingViewportHeight) const; AnnotationTextFontSizeTypeEnum::Enum getFontSizeType() const; @@ -156,6 +158,10 @@ namespace caret { AnnotationText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); + AnnotationText(const AnnotationTypeEnum::Enum type, + const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); diff --git a/src/Annotations/AnnotationTextFontSizeTypeEnum.cxx b/src/Annotations/AnnotationTextFontSizeTypeEnum.cxx index 9c1b14c9a..7609791a0 100644 --- a/src/Annotations/AnnotationTextFontSizeTypeEnum.cxx +++ b/src/Annotations/AnnotationTextFontSizeTypeEnum.cxx @@ -31,9 +31,7 @@ using namespace caret; /** * \class caret::AnnotationTextFontSizeTypeEnum - * \brief - * - * + * \brief Enumerated type for font sizing * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -110,12 +108,15 @@ AnnotationTextFontSizeTypeEnum::initialize() enumData.push_back(AnnotationTextFontSizeTypeEnum(POINTS, "POINTS", - "")); + "Points")); enumData.push_back(AnnotationTextFontSizeTypeEnum(PERCENTAGE_OF_VIEWPORT_HEIGHT, "PERCENTAGE_OF_VIEWPORT_HEIGHT", - "")); + "Percentage of Viewport Height")); + enumData.push_back(AnnotationTextFontSizeTypeEnum(PERCENTAGE_OF_VIEWPORT_WIDTH, + "PERCENTAGE_OF_VIEWPORT_WIDTH", + "Percentage of Viewport Width")); } /** diff --git a/src/Annotations/AnnotationTextFontSizeTypeEnum.h b/src/Annotations/AnnotationTextFontSizeTypeEnum.h index e9cd63d38..1cfccf494 100644 --- a/src/Annotations/AnnotationTextFontSizeTypeEnum.h +++ b/src/Annotations/AnnotationTextFontSizeTypeEnum.h @@ -35,10 +35,12 @@ public: * Enumerated values. */ enum Enum { - /** */ + /** Sized in Points */ POINTS, - /** */ - PERCENTAGE_OF_VIEWPORT_HEIGHT + /** Sized as percentage of viewport height */ + PERCENTAGE_OF_VIEWPORT_HEIGHT, + /** Sized as percentage of viewport width */ + PERCENTAGE_OF_VIEWPORT_WIDTH }; diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 70d0a0a0f..7e891140a 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -332,6 +332,7 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; + bool viewportFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::PIXELS: @@ -346,6 +347,9 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp case AnnotationCoordinateSpaceEnum::TAB: tabWindowFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + viewportFlag = true; + break; case AnnotationCoordinateSpaceEnum::WINDOW: tabWindowFlag = true; break; @@ -363,6 +367,11 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp allowsSideResizingFlag = true; allowsRotationFlag = true; break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + allowsMovingFlag = true; + allowsCornerResizingFlag = true; + allowsSideResizingFlag = true; + break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; allowsCornerResizingFlag = true; @@ -390,7 +399,8 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool validFlag = false; - if ( ! pixelsFlag) { + if ( (! pixelsFlag) + && (! viewportFlag)) { switch (sizingHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: if (allowsSideResizingFlag) { @@ -484,6 +494,9 @@ AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace case AnnotationCoordinateSpaceEnum::TAB: badSpaceFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + badSpaceFlag = true; + break; case AnnotationCoordinateSpaceEnum::WINDOW: badSpaceFlag = true; break; @@ -1124,6 +1137,8 @@ AnnotationTwoDimensionalShape::applySpatialModification(const AnnotationSpatialM case AnnotationCoordinateSpaceEnum::TAB: return applySpatialModificationTabOrWindowSpace(spatialModification); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: return applySpatialModificationTabOrWindowSpace(spatialModification); break; diff --git a/src/Annotations/AnnotationTypeEnum.cxx b/src/Annotations/AnnotationTypeEnum.cxx index 8f800fc65..2477c3a26 100644 --- a/src/Annotations/AnnotationTypeEnum.cxx +++ b/src/Annotations/AnnotationTypeEnum.cxx @@ -110,10 +110,14 @@ AnnotationTypeEnum::initialize() "BOX", "Box")); + enumData.push_back(AnnotationTypeEnum(CHART_AXIS_LABEL, + "CHART_AXIS_LABEL", + "Chart Axis Label")); + enumData.push_back(AnnotationTypeEnum(COLOR_BAR, "COLOR_BAR", "Color Bar")); - + enumData.push_back(AnnotationTypeEnum(IMAGE, "IMAGE", "Image")); diff --git a/src/Annotations/AnnotationTypeEnum.h b/src/Annotations/AnnotationTypeEnum.h index a0650752a..f61d120a2 100644 --- a/src/Annotations/AnnotationTypeEnum.h +++ b/src/Annotations/AnnotationTypeEnum.h @@ -37,6 +37,8 @@ public: enum Enum { /** Box */ BOX, + /** Chart axis label */ + CHART_AXIS_LABEL, /** Colorbar */ COLOR_BAR, /** Image */ diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 324754d60..7d0d0a880 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -27,6 +27,7 @@ Annotation.h AnnotationAlignmentEnum.h AnnotationAttributesDefaultTypeEnum.h AnnotationBox.h +AnnotationChartTwoAxisLabel.h AnnotationColorBar.h AnnotationColorBarNumericText.h AnnotationColorBarPositionModeEnum.h @@ -69,6 +70,7 @@ Annotation.cxx AnnotationAlignmentEnum.cxx AnnotationAttributesDefaultTypeEnum.cxx AnnotationBox.cxx +AnnotationChartTwoAxisLabel.cxx AnnotationColorBar.cxx AnnotationColorBarNumericText.cxx AnnotationColorBarPositionModeEnum.cxx diff --git a/src/Brain/AnnotationArrangerExecutor.cxx b/src/Brain/AnnotationArrangerExecutor.cxx index ebe2f9d97..9decf8e41 100644 --- a/src/Brain/AnnotationArrangerExecutor.cxx +++ b/src/Brain/AnnotationArrangerExecutor.cxx @@ -625,6 +625,9 @@ AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& getTabViewport(annotation->getTabIndex(), annViewport); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::WINDOW: annViewport[0] = m_windowViewport[0]; annViewport[1] = m_windowViewport[1]; @@ -698,6 +701,7 @@ AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& viewportPixelOneXYZ[0], viewportPixelOneXYZ[1], viewportPixelOneXYZ[2], + annViewport[2], annViewport[3], bottomLeft, bottomRight, diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index a5750b361..c00414e27 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -941,11 +941,13 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: - displayedFlag = true; + displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: displayedFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: displayedFlag = true; break; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index bf0114707..4cda42f66 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -29,6 +29,7 @@ #undef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationBox.h" +#include "AnnotationChartTwoAxisLabel.h" #include "AnnotationColorBar.h" #include "AnnotationColorBarSection.h" #include "AnnotationColorBarNumericText.h" @@ -138,8 +139,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(cons /** * Get the window coordinate for display of the annotation. * + * @param annotation + * The annotation. * @param coordinate * The annotation coordinate whose window coordinate is computed. + * @param annotationCoordSpace + * The annotation coordinate space. * @param surfaceDisplayed * Surface that is displayed (may be NULL !) * @param windowXYZOut @@ -148,11 +153,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(cons * True if the window coordinate is valid, else false. */ bool -BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const AnnotationCoordinate* coordinate, - const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace, +BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const Annotation* annotation, + const AnnotationCoordinate* coordinate, const Surface* surfaceDisplayed, float windowXYZOut[3]) const { + const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace = annotation->getCoordinateSpace(); + float stereotaxicXYZ[3] = { 0.0, 0.0, 0.0 }; bool stereotaxicXYZValid = false; @@ -269,6 +276,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); windowXYZValid = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + { + int32_t annotationViewport[4]; + annotation->getViewportCoordinateSpaceViewport(annotationViewport); + windowXYZ[0] = annotationXYZ[0] + annotationViewport[0]; + windowXYZ[1] = annotationXYZ[1] + annotationViewport[1]; + windowXYZ[2] = annotationXYZ[2]; + windowXYZValid = true; + } + break; case AnnotationCoordinateSpaceEnum::WINDOW: viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); windowXYZValid = true; @@ -419,7 +436,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationTwoDimShapeBounds(const if (textFlag) { m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*textAnnotation, windowXYZ[0], windowXYZ[1], windowXYZ[2], - viewportHeight, + viewportWidth, viewportHeight, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut); boundsValid = true; @@ -494,9 +511,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic m_volumeSpacePlane = plane; m_volumeSpacePlaneValid = true; - std::vector colorBars; + std::vector dummyColorBars; + std::vector dummyAnnotationChartTwoAxisLabelsForDrawing; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, - colorBars, + dummyColorBars, + dummyAnnotationChartTwoAxisLabelsForDrawing, NULL, sliceThickness); } @@ -514,6 +533,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. + * @param annotationChartTwoAxisLabelsForDrawing + * Annotation chart two labels that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. */ @@ -521,6 +542,7 @@ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& annotationChartTwoAxisLabelsForDrawing, const Surface* surfaceDisplayed) { CaretAssert(inputs); @@ -531,6 +553,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const float sliceThickness = 0.0; drawAnnotationsInternal(drawingCoordinateSpace, colorBars, + annotationChartTwoAxisLabelsForDrawing, surfaceDisplayed, sliceThickness); @@ -546,16 +569,17 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, * Surface that is displayed. May be NULL in some instances. * @param colorbars * Colorbars that will be drawn. + * @param annotationChartTwoAxisLabelsForDrawing + * Annotation chart two labels that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param sliceThickness * Thickness of volume slice - * @param centerToEyeDistance - * Distance from center to eye using in gluLookAt(). */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& annotationChartTwoAxisLabelsForDrawing, const Surface* surfaceDisplayed, const float sliceThickness) { @@ -597,6 +621,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: switch (m_inputs->m_windowDrawingMode) { case Inputs::WINDOW_DRAWING_NO: @@ -675,7 +701,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat /* * Draw annotations from all files. - * NOTE: iFile == numAnnFiles, the annotation colorbars are drawn + * NOTE: iFile == numAnnFiles, the annotation colorbars + * and annotation chart labels are drawn */ const int32_t numAnnFiles = static_cast(allAnnotationFiles.size()); for (int32_t iFile = 0; iFile <= numAnnFiles; iFile++) { @@ -695,6 +722,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat break; case AnnotationCoordinateSpaceEnum::SURFACE: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + annotationsFromFile.insert(annotationsFromFile.end(), + annotationChartTwoAxisLabelsForDrawing.begin(), + annotationChartTwoAxisLabelsForDrawing.end()); + break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: { @@ -748,6 +780,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat colorBars.begin(), colorBars.end()); } + +// if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { +// annotationsFromFile.insert(annotationsFromFile.end(), +// annotationChartTwoAxisLabelsForDrawing.begin(), +// annotationChartTwoAxisLabelsForDrawing.end()); +// } } break; } @@ -1016,6 +1054,43 @@ BrainOpenGLAnnotationDrawingFixedPipeline::endOpenGLForDrawing(GLint savedShadeM glPopMatrix(); } +///** +// * Setup to drawn an annotation in viewport space. +// * +// * @param annotation +// * Annotation in viewport space. +// * @param transformationInfo +// * Transformation info that is saved. +// */ +//void +//BrainOpenGLAnnotationDrawingFixedPipeline::setupViewportSpaceDrawing(const Annotation* annotation, +// TransformationInfo& transformationInfo) +//{ +// CaretAssert(annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::VIEWPORT); +// +// transformationInfo.save(); +// +// GLdouble depthRange[2]; +// glGetDoublev(GL_DEPTH_RANGE, +// depthRange); +// +// GLint annotationViewport[4]; +// annotation->getViewportCoordinateSpaceViewport(annotationViewport); +// /* +// * All drawing is in window space +// */ +// glMatrixMode(GL_PROJECTION); +// glPushMatrix(); +// glLoadIdentity(); +// glOrtho(0.0, annotationViewport[2], +// 0.0, annotationViewport[3], +// depthRange[0], depthRange[1]); +// glMatrixMode(GL_MODELVIEW); +// glPushMatrix(); +// glLoadIdentity(); +//} + + /** * Get color used for identification when drawing an annotation. * @@ -1050,12 +1125,31 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota bool drawnFlag = false; + switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::PIXELS: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + switch (annotation->getType()) { case AnnotationTypeEnum::BOX: drawnFlag = drawBox(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + drawChartTwoAxisLabel(annotationFile, + dynamic_cast(annotation)); + break;; case AnnotationTypeEnum::COLOR_BAR: drawColorBar(annotationFile, dynamic_cast(annotation)); @@ -1109,8 +1203,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil CaretAssert(box->getType() == AnnotationTypeEnum::BOX); float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(box->getCoordinate(), - box->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(box, + box->getCoordinate(), surfaceDisplayed, windowXYZ)) { return false; @@ -1227,6 +1321,57 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil return drawnFlag; } +/** + * Draw an annotation chart two axis label + * + * @param annotationFile + * File containing the annotation. + * @param chartTwoAxisLabel + * Axis label to draw. + */ +void +BrainOpenGLAnnotationDrawingFixedPipeline::drawChartTwoAxisLabel(AnnotationFile* annotationFile, + AnnotationChartTwoAxisLabel* chartTwoAxisLabel) +{ + CaretAssert(chartTwoAxisLabel); + CaretAssert(chartTwoAxisLabel->getType() == AnnotationTypeEnum::CHART_AXIS_LABEL); + +// const GLint savedModelSpaceViewport[4] = { +// m_modelSpaceModelMatrix[0], +// m_modelSpaceModelMatrix[1], +// m_modelSpaceModelMatrix[2], +// m_modelSpaceModelMatrix[3] +// }; +// +// glPushAttrib(GL_VIEWPORT_BIT); + +// GLint viewportSave[4]; +// glGetIntegerv(GL_VIEWPORT, viewportSave); + +// int32_t labelViewport[4]; +// chartTwoAxisLabel->getAxisViewport(labelViewport); +// glViewport(labelViewport[0], labelViewport[1], labelViewport[2], labelViewport[3]); + +// m_modelSpaceViewport[0] = labelViewport[0]; +// m_modelSpaceViewport[1] = labelViewport[1]; +// m_modelSpaceViewport[2] = labelViewport[2]; +// m_modelSpaceViewport[3] = labelViewport[3]; + + drawText(annotationFile, + chartTwoAxisLabel, + NULL); + +// glPopAttrib(); + +// m_modelSpaceViewport[0] = savedModelSpaceViewport[0]; +// m_modelSpaceViewport[1] = savedModelSpaceViewport[1]; +// m_modelSpaceViewport[2] = savedModelSpaceViewport[2]; +// m_modelSpaceViewport[3] = savedModelSpaceViewport[3]; + +// glViewport(viewportSave[0], viewportSave[1], viewportSave[2], viewportSave[3]); +} + + /** * Draw an annotation box. * @@ -1243,8 +1388,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati CaretAssert(colorBar->getType() == AnnotationTypeEnum::COLOR_BAR); float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(colorBar->getCoordinate(), - colorBar->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(colorBar, + colorBar->getCoordinate(), NULL, windowXYZ)) { return; @@ -1829,8 +1974,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(oval->getCoordinate(), - oval->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(oval, + oval->getCoordinate(), surfaceDisplayed, windowXYZ)) { return false; @@ -2006,13 +2151,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX); float brainordinateXYZ[3]; - if (getAnnotationWindowCoordinate(&noOffsetCoord, - text->getCoordinateSpace(), + if (getAnnotationWindowCoordinate(text, + &noOffsetCoord, surfaceDisplayed, brainordinateXYZ)) { float windowXYZ[3]; - if (getAnnotationWindowCoordinate(coord, - text->getCoordinateSpace(), + if (getAnnotationWindowCoordinate(text, + coord, surfaceDisplayed, windowXYZ)) { @@ -2136,17 +2281,21 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi AnnotationText* text, const Surface* surfaceDisplayed) { + CaretAssert(text); + CaretAssert((text->getType() == AnnotationTypeEnum::TEXT) + || (text->getType() == AnnotationTypeEnum::CHART_AXIS_LABEL)); + DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); - if ( ! dpa->isDisplayTextAnnotations()) { - return false; + if (text->getType() == AnnotationTypeEnum::TEXT) { + if ( ! dpa->isDisplayTextAnnotations()) { + return false; + } } - CaretAssert(text); - CaretAssert(text->getType() == AnnotationTypeEnum::TEXT); float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(text->getCoordinate(), - text->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(text, + text->getCoordinate(), surfaceDisplayed, windowXYZ)) { return false; @@ -2194,7 +2343,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*text, windowXYZ[0], windowXYZ[1], windowXYZ[2], //textDrawingViewportHeight, - m_modelSpaceViewport[3], + m_modelSpaceViewport[2], m_modelSpaceViewport[3], bottomLeft, bottomRight, topRight, topLeft); std::vector coords; @@ -2377,8 +2526,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(image->getCoordinate(), - image->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(image, + image->getCoordinate(), surfaceDisplayed, windowXYZ)) { return false; @@ -2639,14 +2788,14 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi float lineHeadXYZ[3]; float lineTailXYZ[3]; - if ( ! getAnnotationWindowCoordinate(line->getStartCoordinate(), - line->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(line, + line->getStartCoordinate(), surfaceDisplayed, lineHeadXYZ)) { return false; } - if ( ! getAnnotationWindowCoordinate(line->getEndCoordinate(), - line->getCoordinateSpace(), + if ( ! getAnnotationWindowCoordinate(line, + line->getEndCoordinate(), surfaceDisplayed, lineTailXYZ)) { return false; @@ -3284,5 +3433,37 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setDepthTestingStatus(const bool newD return (savedStatus == GL_TRUE); } - - +/* ====================================================================================== */ + +///** +// * Save the transformation matrix (viewport, model view, projection) +// */ +//void +//BrainOpenGLAnnotationDrawingFixedPipeline::TransformationInfo::save() +//{ +// glGetIntegerv(GL_VIEWPORT, m_viewport); +// glGetDoublev(GL_MODELVIEW_MATRIX, m_modelViewMatrix); +// glGetDoublev(GL_PROJECTION_MATRIX, m_projectionMatrix); +// +//} +// +///** +// * Restore the transformation matrix (viewport, model view, projection) +// */ +//void +//BrainOpenGLAnnotationDrawingFixedPipeline::TransformationInfo::restore() +//{ +// CaretAssertMessage(0, "Trying to restore info that has not been saved"); +// if ( ! m_valid) { +// return; +// } +// +// GLboolean savedMatrixMode; +// glGetBooleanv(GL_MATRIX_MODE, &savedMatrixMode); +// glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]); +// glMatrixMode(GL_PROJECTION); +// glLoadMatrixd(m_projectionMatrix); +// glMatrixMode(GL_MODELVIEW); +// glLoadMatrixd(m_modelViewMatrix); +// glMatrixMode(savedMatrixMode); +//} diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index cd684d24b..753e8540d 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -35,6 +35,7 @@ namespace caret { class Annotation; class AnnotationBox; + class AnnotationChartTwoAxisLabel; class AnnotationColorBar; class AnnotationCoordinate; class AnnotationFile; @@ -116,6 +117,7 @@ namespace caret { void drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& annotationChartTwoAxisLabelsForDrawing, const Surface* surfaceDisplayed); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, @@ -165,17 +167,32 @@ namespace caret { float m_rgba[4]; }; + /** + * Used to save viewport, model view, projection + */ + class TransformationInfo { + public: + void save(); + void restore(); + + GLint m_viewport[4]; + GLdouble m_modelViewMatrix[16]; + GLdouble m_projectionMatrix[16]; + bool m_valid = false; + }; + BrainOpenGLAnnotationDrawingFixedPipeline(const BrainOpenGLAnnotationDrawingFixedPipeline&); BrainOpenGLAnnotationDrawingFixedPipeline& operator=(const BrainOpenGLAnnotationDrawingFixedPipeline&); void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& annotationChartTwoAxisLabelsForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); - bool getAnnotationWindowCoordinate(const AnnotationCoordinate* coordinate, - const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace, + bool getAnnotationWindowCoordinate(const Annotation* annotation, + const AnnotationCoordinate* coordinate, const Surface* surfaceDisplayed, float windowXYZOut[3]) const; @@ -197,12 +214,15 @@ namespace caret { Annotation* annotation, const Surface* surfaceDisplayed); + void drawColorBar(AnnotationFile* annotationFile, + AnnotationColorBar* colorBar); + bool drawBox(AnnotationFile* annotationFile, AnnotationBox* box, const Surface* surfaceDisplayed); - void drawColorBar(AnnotationFile* annotationFile, - AnnotationColorBar* colorBar); + void drawChartTwoAxisLabel(AnnotationFile* annotationFile, + AnnotationChartTwoAxisLabel* chartTwoAxisLabel); bool drawImage(AnnotationFile* annotationFile, AnnotationImage* image, @@ -307,6 +327,9 @@ namespace caret { void endOpenGLForDrawing(GLint savedShadeModel, GLboolean savedLightingEnabled); + void setupViewportSpaceDrawing(const Annotation* annotation, + TransformationInfo& transformationInfo); + void clipLineAtTextBox(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], diff --git a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx index c420657bc..b4f539076 100644 --- a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx @@ -180,13 +180,13 @@ BrainOpenGLChartDrawingFixedPipeline::drawCartesianChart(Brain* brain, Margins margins(marginSize); double width, height; - estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getLeftAxis(), width, height); + estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getLeftAxis(), width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getRightAxis(), width, height); + estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getRightAxis(), width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getTopAxis(), width, height); + estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getTopAxis(), width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpHeight, cartesianChart->getBottomAxis(), width, height); + estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getBottomAxis(), width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; @@ -658,6 +658,8 @@ BrainOpenGLChartDrawingFixedPipeline::drawChartAxisCartesian(const float vpX, * Text rendering. * @param viewportHeight * Height of viewport. + * @param viewportHeight + * Height of viewport. * @param axis * The axis. * @param widthOut @@ -667,6 +669,7 @@ BrainOpenGLChartDrawingFixedPipeline::drawChartAxisCartesian(const float vpX, */ void BrainOpenGLChartDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(BrainOpenGLTextRenderInterface* textRenderer, + const float viewportWidth, const float viewportHeight, ChartAxis* axis, double& widthOut, @@ -702,7 +705,7 @@ BrainOpenGLChartDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeig annotationText.setText(text); double textWidth = 0.0; double textHeight = 0.0; - textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); + textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); widthOut = std::max(widthOut, textWidth); heightOut = std::max(heightOut, textHeight); diff --git a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.h index 10dc85e84..6567b029b 100644 --- a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.h @@ -119,6 +119,7 @@ namespace caret { const float rgb[3]); void estimateCartesianChartAxisLegendsWidthHeight(BrainOpenGLTextRenderInterface* textRenderer, + const float viewportWidth, const float viewportHeight, ChartAxis* axis, double& widthOut, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 3075caccb..9719660d8 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -25,7 +25,10 @@ #include +#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationCoordinate.h" #include "AnnotationColorBar.h" +#include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" @@ -55,6 +58,7 @@ #include "PaletteColorMapping.h" #include "PaletteFile.h" #include "SessionManager.h" +#include "SelectionItemAnnotation.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" @@ -99,6 +103,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * Selected data type. * @param viewport * Viewport for the chart. + * @param annotationChartTwoAxisLabelsOut + * Output containing annotation chart axis labels that will be drawn + * by the Annotation OpenGL Drawing. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, @@ -106,8 +113,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4]) + const int32_t viewport[4], + std::vector& annotationChartTwoAxisLabelsOut) { + annotationChartTwoAxisLabelsOut.clear(); + m_annotationDrawingChartTwoAxisLabels.clear(); + CaretAssert(brain); CaretAssert(browserTabContent); CaretAssert(chartTwoModel); @@ -129,6 +140,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; + m_selectionItemAnnotation = m_brain->getSelectionManager()->getAnnotationIdentification(); m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); @@ -156,6 +168,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case AnnotationCoordinateSpaceEnum::TAB: useItFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } @@ -194,13 +208,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: - if ( ! m_selectionItemHistogram->isEnabledForSelection()) { + if ( (! m_selectionItemHistogram->isEnabledForSelection()) + && (! m_selectionItemAnnotation->isEnabledForSelection()) ){ drawHistogramFlag = false; } - if ( ! m_selectionItemLineSeries->isEnabledForSelection()) { + if ( (! m_selectionItemLineSeries->isEnabledForSelection()) + && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { drawLineSeriesFlag = false; } - if ( ! m_selectionItemMatrix->isEnabledForSelection()) { + if ( (! m_selectionItemMatrix->isEnabledForSelection()) + && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { drawMatrixFlag = false; } if (drawHistogramFlag @@ -257,6 +274,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, } restoreStateOfOpenGL(); + + annotationChartTwoAxisLabelsOut = m_annotationDrawingChartTwoAxisLabels; } /** @@ -391,13 +410,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, leftAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpHeight, rightAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, topAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpHeight, bottomAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; @@ -1073,6 +1092,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const C * * @param dataBounds * Bounds of data [minX, maxX, minY, maxY]. + * @param viewportWidth + * Widgth of viewport. * @param viewportHeight * Height of viewport. * @param cartesianAxis @@ -1084,6 +1105,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const C */ void BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], + const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, double& widthOut, @@ -1127,7 +1149,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH annotationText.setText(text); double textWidth = 0.0; double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); + m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); widthOut = std::max(widthOut, textWidth); heightOut = std::max(heightOut, textHeight); @@ -1149,7 +1171,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - const AString axisTitle = cartesianAxis->getAxisTitle(); + const AnnotationChartTwoAxisLabel* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); + const AString axisTitle = chartAxisLabel->getText(); if ( ! axisTitle.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setText(axisTitle); @@ -1172,7 +1195,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH double textWidth = 0.0; double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportHeight, textWidth, textHeight); + m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); /* * Note: Text on left and right is rotated but we need the width @@ -1561,7 +1584,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data drawPrimitivePrivate(ticksData.get()); } - const AString axisTitle = axis->getAxisTitle(); + const AString axisTitle = axis->getAnnotationAxisLabel()->getText(); if ( ! axisTitle.isEmpty()) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); @@ -1594,23 +1617,53 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data drawAxisTextVerticalFlag = true; break; } - if (drawAxisTextVerticalFlag) { - annotationText.setRotationAngle(-90.0); - annotationText.setText(axisTitle); - m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, - axisTextCenterY, - 0.0, - annotationText); - annotationText.setRotationAngle(0.0); - } - else { - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setText(axisTitle); - m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, - axisTextCenterY, - 0.0, - annotationText); + + if ((axisVpWidth > 0.0) + && (axisVpHeight > 0.0)) { +// const float labelPercentX = 100.0f * (axisTextCenterX / axisVpWidth); +// const float labelPercentY = 100.0f * (axisTextCenterY / axisVpHeight); + AnnotationChartTwoAxisLabel* chartLabel = axis->getAnnotationAxisLabel(); + chartLabel->setCustomTextColor(rgba); + chartLabel->setTextColor(CaretColorEnum::CUSTOM); + chartLabel->setTabIndex(m_tabIndex); + chartLabel->setViewportCoordinateSpaceViewport(axisViewport); +// chartLabel->setAxisViewport(axisViewport); + chartLabel->getCoordinate()->setXYZ(axisTextCenterX, + axisTextCenterY, + 0.0f); +// chartLabel->getCoordinate()->setXYZ(labelPercentX, +// labelPercentY, +// 0.0f); + + m_annotationDrawingChartTwoAxisLabels.push_back(chartLabel); } + +// /* +// * REMOVE THIS WHEN AXIS LABELS ARE DRAWN BY ANNOTATION CODE +// */ +// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, +// axisTextCenterY, +// 0.0, +// *axis->getAnnotationAxisLabel()); + + +// if (drawAxisTextVerticalFlag) { +// annotationText.setRotationAngle(-90.0); +// annotationText.setText(axisTitle); +// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, +// axisTextCenterY, +// 0.0, +// annotationText); +// annotationText.setRotationAngle(0.0); +// } +// else { +// annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); +// annotationText.setText(axisTitle); +// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, +// axisTextCenterY, +// 0.0, +// annotationText); +// } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index f56c3dd2d..12877842a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -36,6 +36,7 @@ namespace caret { class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class GraphicsPrimitive; + class SelectionItemAnnotation; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; @@ -52,7 +53,8 @@ namespace caret { ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4]) override; + const int32_t viewport[4], + std::vector& annotationChartTwoAxisLabelsOut) override; // ADD_NEW_METHODS_HERE @@ -133,6 +135,7 @@ namespace caret { float& axisMaximumOut); void estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], + const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, double& widthOut, @@ -162,6 +165,8 @@ namespace caret { CaretPreferences* m_preferences; + SelectionItemAnnotation* m_selectionItemAnnotation; + SelectionItemChartTwoHistogram* m_selectionItemHistogram; SelectionItemChartTwoLineSeries* m_selectionItemLineSeries; @@ -172,6 +177,8 @@ namespace caret { bool m_identificationModeFlag; + std::vector m_annotationDrawingChartTwoAxisLabels; + static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 076a04bbf..65c89db28 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -28,6 +28,7 @@ namespace caret { + class AnnotationChartTwoAxisLabel; class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; @@ -56,13 +57,17 @@ namespace caret { * Selected data type. * @param viewport * Viewport for the chart. + * @param annotationChartTwoAxisLabelsOut + * Output containing annotation chart axis labels that will be drawn + * by the Annotation OpenGL Drawing. */ virtual void drawChartOverlaySet(Brain* brain, BrowserTabContent* browserTabContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, - const int32_t viewport[4]) = 0; + const int32_t viewport[4], + std::vector& annotationChartTwoAxisLabelsOut) = 0; // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 6cbc76f7f..17f2ac826 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -275,6 +275,8 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, setTabViewport(viewportContent); + m_annotationChartTwoAxisLabelsForDrawing.clear(); + std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); setAnnotationColorBarsForDrawing(viewportContentsVector); @@ -356,6 +358,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex m_clippingPlaneGroup = NULL; + m_annotationChartTwoAxisLabelsForDrawing.clear(); m_brain->getSelectionManager()->reset(); this->modeProjectionData = &projectionOut; @@ -524,6 +527,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, setTabViewport(NULL); + m_annotationChartTwoAxisLabelsForDrawing.clear(); setAnnotationColorBarsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); @@ -797,8 +801,14 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, + m_annotationChartTwoAxisLabelsForDrawing, NULL); + m_annotationDrawing->drawAnnotations(&inputs, + AnnotationCoordinateSpaceEnum::VIEWPORT, + m_annotationColorBarsForDrawing, + m_annotationChartTwoAxisLabelsForDrawing, + NULL); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -866,9 +876,11 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, windowDrawingMode); + std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, + emptyAnnotationChartTwoAxisLabelsForDrawing, NULL); glPopMatrix(); @@ -973,6 +985,7 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, + m_annotationChartTwoAxisLabelsForDrawing, NULL); } } @@ -1810,14 +1823,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; + std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, + emptyAnnotationChartTwoAxisLabelsForDrawing, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, + emptyAnnotationChartTwoAxisLabelsForDrawing, NULL); } } @@ -1857,14 +1873,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; + std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, + emptyAnnotationChartTwoAxisLabelsForDrawing, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, + emptyAnnotationChartTwoAxisLabelsForDrawing, NULL); } @@ -5384,6 +5403,8 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, CaretAssert(browserTabContent); CaretAssert(chartModel); + + m_annotationChartTwoAxisLabelsForDrawing.clear(); BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, @@ -5391,7 +5412,8 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, chartModel, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, - viewport); + viewport, + m_annotationChartTwoAxisLabelsForDrawing); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index ff8df04b0..4906d99c6 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -42,6 +42,7 @@ namespace caret { + class AnnotationChartTwoAxisLabel; class AnnotationText; class BoundingBox; class Brain; @@ -621,6 +622,8 @@ namespace caret { std::vector m_annotationColorBarsForDrawing; + std::vector m_annotationChartTwoAxisLabelsForDrawing; + static bool s_staticInitialized; static const float s_gluLookAtCenterFromEyeOffsetDistance; diff --git a/src/Brain/BrainOpenGLTextRenderInterface.cxx b/src/Brain/BrainOpenGLTextRenderInterface.cxx index 72a3d6456..d9d88b42a 100644 --- a/src/Brain/BrainOpenGLTextRenderInterface.cxx +++ b/src/Brain/BrainOpenGLTextRenderInterface.cxx @@ -64,6 +64,8 @@ BrainOpenGLTextRenderInterface::~BrainOpenGLTextRenderInterface() * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Widgth of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -80,6 +82,7 @@ BrainOpenGLTextRenderInterface::getBoundsForTextAtViewportCoords(const Annotatio const float viewportX, const float viewportY, const float viewportZ, + const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], @@ -95,6 +98,7 @@ BrainOpenGLTextRenderInterface::getBoundsForTextAtViewportCoords(const Annotatio viewportX, viewportY, viewportZ, + viewportWidth, viewportHeight, bottomLeft, bottomRight, diff --git a/src/Brain/BrainOpenGLTextRenderInterface.h b/src/Brain/BrainOpenGLTextRenderInterface.h index 9da44305c..c8844cd8b 100644 --- a/src/Brain/BrainOpenGLTextRenderInterface.h +++ b/src/Brain/BrainOpenGLTextRenderInterface.h @@ -132,6 +132,8 @@ namespace caret { * * @param annotationText * Text for width and height estimation. + * @param viewportWidth + * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut @@ -140,6 +142,7 @@ namespace caret { * Estimated height of text. */ virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) = 0; @@ -158,6 +161,8 @@ namespace caret { * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -173,6 +178,7 @@ namespace caret { const double viewportX, const double viewportY, const double viewportZ, + const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], @@ -193,6 +199,8 @@ namespace caret { * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -208,6 +216,7 @@ namespace caret { const float viewportX, const float viewportY, const float viewportZ, + const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 7c1529bc4..7017e1080 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -25,6 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" +#include "AnnotationChartTwoAxisLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventManager.h" @@ -80,7 +81,7 @@ m_tabIndex(tabIndex) case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { m_chartAxisLeft->setEnabledByChart(true); - m_chartAxisLeft->setAxisTitle("Counts"); + m_chartAxisLeft->getAnnotationAxisLabel()->setText("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); float rangeMin = 0.0, rangeMax = 0.0; m_chartAxisLeft->getRange(rangeMin, rangeMax); @@ -88,14 +89,14 @@ m_tabIndex(tabIndex) m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); - m_chartAxisRight->setAxisTitle("Counts"); + m_chartAxisRight->getAnnotationAxisLabel()->setText("Counts"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); - m_chartAxisBottom->setAxisTitle("Data"); + m_chartAxisBottom->getAnnotationAxisLabel()->setText("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } break; diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index e1ae3b99b..147fb1c67 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -95,6 +95,8 @@ DisplayPropertiesAnnotation::updateForNewAnnotation(const Annotation* annotation break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: setDisplayWindowAnnotationsInSingleTabViews(annotation->getWindowIndex(), true); @@ -458,6 +460,9 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) } } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (numWindowStatus) { const int32_t windowIndex = ann->getWindowIndex(); diff --git a/src/Brain/DummyFontTextRenderer.cxx b/src/Brain/DummyFontTextRenderer.cxx index b960a756b..cc14ef7a8 100644 --- a/src/Brain/DummyFontTextRenderer.cxx +++ b/src/Brain/DummyFontTextRenderer.cxx @@ -149,6 +149,8 @@ DummyFontTextRenderer::drawTextAtModelCoords(const double /*modelX*/, * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -165,7 +167,7 @@ DummyFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& /* const double /*viewportX*/, const double /*viewportY*/, const double /*viewportZ*/, - const double /*viewportHeight*/, + const double /*viewportWidth*/, const double /*viewportHeight*/, double* /*bottomLeftOut[3]*/, double* /*bottomRightOut[3]*/, double* /*topRightOut[3]*/, @@ -191,6 +193,7 @@ DummyFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& /* */ void DummyFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& /*annotationText*/, + const double /*viewportWidth*/, const double /*viewportHeight*/, double& /*widthOut*/, double& /*heightOut*/) diff --git a/src/Brain/DummyFontTextRenderer.h b/src/Brain/DummyFontTextRenderer.h index 0649c326d..3dabcd5af 100644 --- a/src/Brain/DummyFontTextRenderer.h +++ b/src/Brain/DummyFontTextRenderer.h @@ -52,6 +52,7 @@ namespace caret { const AnnotationText& annotationText); virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut); @@ -60,6 +61,7 @@ namespace caret { const double viewportX, const double viewportY, const double viewportZ, + const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 24f80a1c8..6d9bc1a7b 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -179,7 +179,31 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, const bool creatingDefaultFontFlag) { #ifdef HAVE_FREETYPE - const AString fontName = annotationText.getFontRenderingEncodedName(m_viewportHeight); + int32_t viewportWidth = m_viewportWidth; + int32_t viewportHeight = m_viewportHeight; + + switch (annotationText.getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::PIXELS: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + { + int32_t vp[4]; + annotationText.getViewportCoordinateSpaceViewport(vp); + viewportWidth = vp[2]; + viewportHeight = vp[3]; + } + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + const AString fontName = annotationText.getFontRenderingEncodedName(viewportWidth, + viewportHeight); /* * Has the font already has been created? @@ -195,7 +219,8 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, * Create and save the font */ FontData* fontData = new FontData(annotationText, - m_viewportHeight); + viewportWidth, + viewportHeight); if (fontData->m_valid) { /* * Request font is valid. @@ -734,6 +759,8 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -750,6 +777,7 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann const double viewportX, const double viewportY, const double viewportZ, + const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], @@ -757,6 +785,7 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann double topLeftOut[3]) { setViewportHeight(); + m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; FTFont* font = getFont(annotationText, false); @@ -850,6 +879,7 @@ FtglFontTextRenderer::setViewportHeight() glGetIntegerv(GL_VIEWPORT, viewport); + m_viewportWidth = viewport[2]; m_viewportHeight = viewport[3]; } @@ -861,6 +891,8 @@ FtglFontTextRenderer::setViewportHeight() * * @param annotationText * Text for width and height estimation. + * @param viewportWidth + * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut @@ -870,11 +902,13 @@ FtglFontTextRenderer::setViewportHeight() */ void FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) { setViewportHeight(); + m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; @@ -889,11 +923,11 @@ FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotatio CaretAssert(textCopy); textCopy->setRotationAngle(0.0); getBoundsForTextAtViewportCoords(*textCopy, 0.0, 0.0, 0.0, - viewportHeight, bottomLeft, bottomRight, topRight, topLeft); + viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); } else { getBoundsForTextAtViewportCoords(annotationText, 0.0, 0.0, 0.0, - viewportHeight, bottomLeft, bottomRight, topRight, topLeft); + viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); } widthOut = MathFunctions::distance3D(bottomLeft, bottomRight); @@ -1028,10 +1062,13 @@ FtglFontTextRenderer::FontData::FontData() * * @param annotationText * Annotation Text that is to be drawn. + * @param viewportWidth + * Width of the viewport in which text is drawn. * @param viewportHeight * Height of the viewport in which text is drawn. */ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, + const int32_t viewportWidth, const int32_t viewportHeight) { m_valid = false; @@ -1082,7 +1119,7 @@ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, /* * Font size successful ? */ - const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportHeight); + const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportWidth, viewportHeight); if (m_font->FaceSize(fontSizePoints)) { m_valid = true; diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index f12ad2ae0..20f03d895 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -56,6 +56,7 @@ namespace caret { const AnnotationText& annotationText); virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut); @@ -65,6 +66,7 @@ namespace caret { const double viewportX, const double viewportY, const double viewportZ, + const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], @@ -119,6 +121,7 @@ namespace caret { FontData(); FontData(const AnnotationText& annotationText, + const int32_t viewportWidth, const int32_t viewportHeight); ~FontData(); @@ -316,6 +319,9 @@ namespace caret { /** Depth testing enabled status */ DepthTestEnum m_depthTestingStatus; + /** Width of the viewport */ + int32_t m_viewportWidth; + /** Height of the viewport */ int32_t m_viewportHeight; diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 2be44f399..95582ebbd 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -23,6 +23,7 @@ #include "ChartTwoCartesianAxis.h" #undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ +#include "AnnotationChartTwoAxisLabel.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" @@ -52,6 +53,22 @@ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum a SceneableInterface(), m_axisLocation(axisLocation) { + AnnotationTextFontSizeTypeEnum::Enum fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + } + m_annotationAxisLabel = std::unique_ptr(new AnnotationChartTwoAxisLabel(AnnotationAttributesDefaultTypeEnum::NORMAL, + fontSizeType)); + /* * Allowable range minimum and maximum * NOT SAVED TO SCENE @@ -81,12 +98,40 @@ m_axisLocation(axisLocation) &m_numericSubdivsionsMode); m_sceneAssistant->add("m_userNumberOfSubdivisions", &m_userNumberOfSubdivisions); - m_sceneAssistant->add("m_axisTitle", - &m_axisTitle); m_sceneAssistant->add("m_enabledByChart", &m_enabledByChart); m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); + m_sceneAssistant->add("m_annotationAxisLabel", + "AnnotationChartTwoAxisLabel", + m_annotationAxisLabel.get()); + + m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + //m_annotationAxisLabel->setBackgroundColor(CaretColorEnum::NONE); + m_annotationAxisLabel->setFontPercentViewportSize(40.0); + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + m_annotationAxisLabel->setRotationAngle(-90.0); + m_annotationAxisLabel->setFontPercentViewportSize(25.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + m_annotationAxisLabel->setRotationAngle(-90.0); + m_annotationAxisLabel->setFontPercentViewportSize(25.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + break; + } } /** @@ -136,6 +181,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx { CaretAssert(m_axisLocation == obj.m_axisLocation); + *m_annotationAxisLabel = *obj.m_annotationAxisLabel; m_displayedByUser = obj.m_displayedByUser; m_rangeMinimumValue = obj.m_rangeMinimumValue; m_rangeMaximumValue = obj.m_rangeMaximumValue; @@ -148,7 +194,6 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_userNumericFormat = obj.m_userNumericFormat; m_numericSubdivsionsMode = obj.m_numericSubdivsionsMode; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; - m_axisTitle = obj.m_axisTitle; m_enabledByChart = obj.m_enabledByChart; m_showTickmarks = obj.m_showTickmarks; limitUserScaleMinMaxToValidRange(); @@ -449,24 +494,21 @@ ChartTwoCartesianAxis::toString() const } /** - * @return Title for axis + * @return Annotation used for drawing axis label and tick mark numeric values */ -AString -ChartTwoCartesianAxis::getAxisTitle() const +const AnnotationChartTwoAxisLabel* +ChartTwoCartesianAxis::getAnnotationAxisLabel() const { - return m_axisTitle; + return m_annotationAxisLabel.get(); } /** - * Set title for axis - * - * @param axisTitle - * New value for axis title + * @return Annotation used for drawing axis label and tick mark numeric values */ -void -ChartTwoCartesianAxis::setAxisTitle(const AString& axisTitle) +AnnotationChartTwoAxisLabel* +ChartTwoCartesianAxis::getAnnotationAxisLabel() { - m_axisTitle = axisTitle; + return m_annotationAxisLabel.get(); } /** @@ -522,6 +564,10 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + const AString oldSceneAxisTitle = sceneClass->getStringValue("m_axisTitle"); + if ( ! oldSceneAxisTitle.isEmpty()) { + m_annotationAxisLabel->setText(oldSceneAxisTitle); + } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 8ab96fcf9..92af9605a 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -33,6 +33,7 @@ namespace caret { + class AnnotationChartTwoAxisLabel; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { @@ -105,9 +106,9 @@ namespace caret { std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; - AString getAxisTitle() const; + const AnnotationChartTwoAxisLabel* getAnnotationAxisLabel() const; - void setAxisTitle(const AString& axisTitle); + AnnotationChartTwoAxisLabel* getAnnotationAxisLabel(); // ADD_NEW_METHODS_HERE @@ -163,6 +164,9 @@ namespace caret { int32_t m_userDigitsRightOfDecimal = 1; + /** Annotation used for drawing axis label and tick mark numeric values*/ + std::unique_ptr m_annotationAxisLabel; + ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; ChartAxisUnitsEnum::Enum m_units = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; @@ -174,8 +178,6 @@ namespace caret { int32_t m_userNumberOfSubdivisions = 2; - AString m_axisTitle; - bool m_enabledByChart = false; bool m_showTickmarks = true; diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index 4af8b8ae6..c91da1e1d 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -244,6 +244,8 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) case AnnotationCoordinateSpaceEnum::TAB: annotationTabOrWindowIndex = annotation->getTabIndex(); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: annotationTabOrWindowIndex = annotation->getWindowIndex(); break; @@ -263,6 +265,9 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) case AnnotationCoordinateSpaceEnum::SURFACE: return group; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: if (annotationTabOrWindowIndex == group->getTabOrWindowIndex()) { @@ -285,6 +290,9 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) CaretAssert((annotationTabOrWindowIndex >= 0) && (annotationTabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::WINDOW: CaretAssert((annotationTabOrWindowIndex >= 0) && (annotationTabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); @@ -614,6 +622,9 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu break; case AnnotationCoordinateSpaceEnum::SURFACE: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + throw DataFileException("VIEWPORT coordinate space is not allowed for group while annotation file."); + break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: if ((tabOrWindowIndex < 0) @@ -671,6 +682,9 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu + ". Only one space group for each space is allowed."); } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (tabOrWindowIndex == group->getTabOrWindowIndex()) { throw DataFileException("There is more than one annotation space group with space " diff --git a/src/Files/AnnotationFileXmlFormatBase.h b/src/Files/AnnotationFileXmlFormatBase.h index a06c4241a..f10d1d9ec 100644 --- a/src/Files/AnnotationFileXmlFormatBase.h +++ b/src/Files/AnnotationFileXmlFormatBase.h @@ -148,6 +148,8 @@ namespace caret { static const QString ELEMENT_PERCENT_SIZE_TEXT; + static const QString ELEMENT_PERCENT_WIDTH_SIZE_TEXT; + static const QString ELEMENT_POINT_SIZE_TEXT; static const QString ELEMENT_TEXT_OBSOLETE; @@ -264,6 +266,8 @@ namespace caret { const QString AnnotationFileXmlFormatBase::ELEMENT_PERCENT_SIZE_TEXT = "percentSizeText"; + const QString AnnotationFileXmlFormatBase::ELEMENT_PERCENT_WIDTH_SIZE_TEXT = "percentWidthSizeText"; + const QString AnnotationFileXmlFormatBase::ELEMENT_POINT_SIZE_TEXT = "pointSizeText"; const QString AnnotationFileXmlFormatBase::ELEMENT_TEXT_OBSOLETE = "text"; diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index 85ed0ed65..99a5fd21b 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -252,6 +252,13 @@ AnnotationFileXmlReader::readVersionOne(AnnotationFile* annotationFile) annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } + else if (elementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { + CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH)); + readTwoDimensionalAnnotation(ELEMENT_PERCENT_WIDTH_SIZE_TEXT, + annotation); + annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); + } else if (elementName == ELEMENT_POINT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPointSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_POINT_SIZE_TEXT, @@ -692,6 +699,12 @@ AnnotationFileXmlReader::readGroup(AnnotationFile* annotationFile) annotation); annotations.push_back(annotation.releasePointer()); } + else if (elementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { + CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); + readTwoDimensionalAnnotation(ELEMENT_PERCENT_WIDTH_SIZE_TEXT, + annotation); + annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); + } else if (elementName == ELEMENT_POINT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPointSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_POINT_SIZE_TEXT, @@ -1001,7 +1014,8 @@ AnnotationFileXmlReader::readTextDataElement(AnnotationText *textAnnotation, } } - if (annotationTextElementName != ELEMENT_PERCENT_SIZE_TEXT) { + if ((annotationTextElementName != ELEMENT_PERCENT_SIZE_TEXT) + && (annotationTextElementName != ELEMENT_PERCENT_WIDTH_SIZE_TEXT)) { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_POINT_SIZE, @@ -1079,6 +1093,11 @@ AnnotationFileXmlReader::readTextDataElement(AnnotationText *textAnnotation, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE)); } + else if (annotationTextElementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { + textAnnotation->setFontPercentViewportSizeProtected(m_streamHelper->getRequiredAttributeFloatValue(attributes, + ELEMENT_TEXT_DATA, + ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE)); + } else { textAnnotation->setFontPercentViewportSizeProtected(m_streamHelper->getOptionalAttributeFloatValue(attributes, ELEMENT_TEXT_DATA, @@ -1095,6 +1114,12 @@ AnnotationFileXmlReader::readTextDataElement(AnnotationText *textAnnotation, */ textAnnotation->setFontPercentViewportSizeProtected(textAnnotation->getFontPercentViewportSizeProtected()); } + else if (annotationTextElementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { + /* + * Will cause warning or assertion failure if invalid value + */ + textAnnotation->setFontPercentViewportSizeProtected(textAnnotation->getFontPercentViewportSizeProtected()); + } else if (annotationTextElementName == ELEMENT_POINT_SIZE_TEXT) { } @@ -1104,6 +1129,8 @@ AnnotationFileXmlReader::readTextDataElement(AnnotationText *textAnnotation, + "\" expected " + ELEMENT_PERCENT_SIZE_TEXT + " or " + + ELEMENT_PERCENT_WIDTH_SIZE_TEXT + + " or " + ELEMENT_POINT_SIZE_TEXT); } diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index 48e8b1dfb..f73996948 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -255,6 +255,9 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) case AnnotationTypeEnum::BOX: writeBox(dynamic_cast(annotation)); break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + CaretAssertMessage(0, "Axis label is NEVER written to an annotation file"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); break; @@ -427,6 +430,9 @@ AnnotationFileXmlWriter::writeText(const AnnotationText* text) case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: annotationElementName = ELEMENT_PERCENT_SIZE_TEXT; break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + annotationElementName = ELEMENT_PERCENT_WIDTH_SIZE_TEXT; + break; case AnnotationTextFontSizeTypeEnum::POINTS: annotationElementName = ELEMENT_POINT_SIZE_TEXT; break; diff --git a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx index 991ddc0ce..fc8ef3dbd 100644 --- a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx +++ b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx @@ -137,6 +137,8 @@ AnnotationChangeCoordinateDialog::createCurrentCoordinateWidget() case AnnotationCoordinateSpaceEnum::TAB: spaceText += (AString::number(m_annotation->getTabIndex() + 1) + " "); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: spaceText += (AString::number(m_annotation->getWindowIndex() + 1) + " "); break; diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 80f2b8b02..ba4a8d0a3 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -488,6 +488,8 @@ AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, case AnnotationTypeEnum::BOX: allowBothColorsNoneFlag = false; break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index b1cf8f892..f5df30dd3 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -120,6 +120,9 @@ AnnotationCoordinateInformation::isCoordinateSpaceValid(const AnnotationCoordina case AnnotationCoordinateSpaceEnum::TAB: validSpaceFlag = (m_tabIndex >= 0); break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertMessage(0, "Should not create/move viewport annotations"); + break; case AnnotationCoordinateSpaceEnum::WINDOW: validSpaceFlag = (m_windowIndex >= 0); break; @@ -159,6 +162,8 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi switch (space) { case AnnotationCoordinateSpaceEnum::PIXELS: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: @@ -176,6 +181,7 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi switch (space) { case AnnotationCoordinateSpaceEnum::PIXELS: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: /* * Both coord info's must be in the SAME TAB @@ -199,6 +205,11 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi addItFlag = false; } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: +// if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { +// addItFlag = false; +// } + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { addItFlag = false; @@ -503,6 +514,9 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowIndex >= 0) { startCoordinate->setXYZ(coordInfoOne->m_windowXYZ); @@ -662,6 +676,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowIndex >= 0) { coordinate->setXYZ(coordInfoOne->m_windowXYZ); diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index c397fcf01..d14cd4e6a 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -93,6 +93,9 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + enableWindowSpaceFlag = false; + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -502,6 +505,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno case AnnotationCoordinateSpaceEnum::TAB: oldViewportHeight = m_coordInfo.m_tabHeight; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: oldViewportHeight = m_coordInfo.m_windowHeight; break; @@ -532,6 +538,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno case AnnotationCoordinateSpaceEnum::TAB: diffXyzValid = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: diffXyzValid = true; break; @@ -587,6 +596,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno newViewportHeight = m_coordInfo.m_tabHeight; } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: if (m_coordInfo.m_windowIndex >= 0) { const int32_t oldWindowIndex = redoAnnotation->getWindowIndex(); @@ -770,6 +782,9 @@ AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* vpWidth = m_coordInfo.m_tabWidth; vpHeight = m_coordInfo.m_tabHeight; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: vpWidth = m_coordInfo.m_windowWidth; vpHeight = m_coordInfo.m_windowHeight; @@ -837,6 +852,9 @@ AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Ann break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: dpa->setDisplayWindowAnnotationsInSingleTabViews(annotation->getWindowIndex(), true); diff --git a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx index 7c6ab537b..87f810172 100644 --- a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx @@ -141,6 +141,9 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati text.append(tabString); } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 905b7c8b1..3964edeb2 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -288,6 +288,9 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) case AnnotationCoordinateSpaceEnum::TAB: zMin = 0.0; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: zMin = 0.0; break; @@ -373,6 +376,9 @@ AnnotationCoordinateWidget::valueChanged() break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 220ba8abd..df3c153e4 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -190,6 +190,9 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, switch (annotationType) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + CaretAssertMessage(0, "Axis Labels do not get created !!!"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Colorbars do not get created !!!"); break; @@ -275,6 +278,9 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } @@ -867,6 +873,9 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() case AnnotationTypeEnum::BOX: useAverageFlag = true; break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + useAverageFlag = true; + break; case AnnotationTypeEnum::COLOR_BAR: useAverageFlag = true; break; @@ -945,6 +954,9 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() viewportHeight = viewport[3]; } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: { int viewport[4]; diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index ff65131e9..c4b6a16c7 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -308,6 +308,8 @@ AnnotationFontWidget::updateContent(std::vectordrawRect(1, 1, width - 2, height - 2); break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + CaretAssertMessage(0, "No pixmap for axis label as user does not create them like other annotations"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); break; @@ -501,6 +504,9 @@ AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpace break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertMessage(0, "Annotations in viewport space not supported."); + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } @@ -577,6 +583,9 @@ AnnotationInsertNewWidget::createSpacePixmap(const QWidget* widget, break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertMessage(0, "Annotations in viewport space not supported."); + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } diff --git a/src/GuiQt/AnnotationPasteDialog.cxx b/src/GuiQt/AnnotationPasteDialog.cxx index 6221c2bd7..faa9fe988 100644 --- a/src/GuiQt/AnnotationPasteDialog.cxx +++ b/src/GuiQt/AnnotationPasteDialog.cxx @@ -305,6 +305,8 @@ AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* o case AnnotationCoordinateSpaceEnum::TAB: tabFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: windowFlag = true; break; diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index 2146e30c3..c38c06575 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -119,6 +119,8 @@ AnnotationRotationWidget::getValidOneDimAnnotation(Annotation* annotation) case AnnotationCoordinateSpaceEnum::TAB: validSpaceFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: validSpaceFlag = true; break; @@ -184,6 +186,8 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) } } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: { const int windowIndex = oneDimAnn->getWindowIndex(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 31358a29e..1ee5085a7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -37,6 +37,7 @@ #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "CaretMappableDataFile.h" +#include "AnnotationChartTwoAxisLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" @@ -583,10 +584,10 @@ BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) WuQDataEntryDialog newNameDialog("Axis Title", m_axisNameToolButton); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Axis Name"); - lineEdit->setText(m_chartAxis->getAxisTitle()); + lineEdit->setText(m_chartAxis->getAnnotationAxisLabel()->getText()); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); - m_chartAxis->setAxisTitle(name); + m_chartAxis->getAnnotationAxisLabel()->setText(name); valueChanged(); } } diff --git a/src/GuiQt/QGLWidgetTextRenderer.cxx b/src/GuiQt/QGLWidgetTextRenderer.cxx index 731021289..1cc6a2959 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.cxx +++ b/src/GuiQt/QGLWidgetTextRenderer.cxx @@ -346,7 +346,7 @@ QGLWidgetTextRenderer::drawHorizontalTextAtWindowCoords(const double windowX, const AString text = annotationText.getText(); double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; - getBoundsForTextAtViewportCoords(annotationText, windowX, windowY, 0.0, viewport[3], bottomLeft, bottomRight, topRight, topLeft); + getBoundsForTextAtViewportCoords(annotationText, windowX, windowY, 0.0, viewport[2], viewport[3], bottomLeft, bottomRight, topRight, topLeft); double left = bottomLeft[0]; double right = bottomRight[0]; @@ -678,6 +678,8 @@ QGLWidgetTextRenderer::applyForegroundColoring(const AnnotationText& annotationT * * @param annotationText * Text for width and height estimation. + * @param viewportWidth + * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut @@ -687,6 +689,7 @@ QGLWidgetTextRenderer::applyForegroundColoring(const AnnotationText& annotationT */ void QGLWidgetTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) @@ -703,6 +706,7 @@ QGLWidgetTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotati 0.0, 0.0, 0.0, + viewportWidth, viewportHeight, bottomLeft, bottomRight, @@ -727,6 +731,8 @@ QGLWidgetTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotati * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. + * @param viewportWidth + * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut @@ -743,6 +749,7 @@ QGLWidgetTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& an const double viewportX, const double viewportY, const double viewportZ, + const double /*viewportWidth*/, const double /*viewportHeight*/, double bottomLeftOut[3], double bottomRightOut[3], @@ -942,6 +949,7 @@ QGLWidgetTextRenderer::setViewportHeight() glGetIntegerv(GL_VIEWPORT, viewport); + m_viewportWidth = viewport[2]; m_viewportHeight = viewport[3]; } @@ -958,7 +966,8 @@ QGLWidgetTextRenderer::findFont(const AnnotationText& annotationText, const bool creatingDefaultFontFlag) { - const AString fontName = annotationText.getFontRenderingEncodedName(m_viewportHeight); + const AString fontName = annotationText.getFontRenderingEncodedName(m_viewportWidth, + m_viewportHeight); /* * Has the font already has been created? @@ -974,6 +983,7 @@ QGLWidgetTextRenderer::findFont(const AnnotationText& annotationText, * Create and save the font */ FontData* fontData = new FontData(annotationText, + m_viewportWidth, m_viewportHeight); if (fontData->m_valid) { /* @@ -1057,6 +1067,7 @@ QGLWidgetTextRenderer::FontData::FontData() * Height of viewport. */ QGLWidgetTextRenderer::FontData::FontData(const AnnotationText& annotationText, + const int32_t viewportWidth, const int32_t viewportHeight) { m_valid = false; @@ -1094,7 +1105,8 @@ QGLWidgetTextRenderer::FontData::FontData(const AnnotationText& annotationText, m_font = new QFont(fontName); CaretAssert(m_font); - const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportHeight); + const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportWidth, + viewportHeight); m_font->setPointSize(fontSizePoints); m_font->setBold(annotationText.isBoldStyleEnabled()); diff --git a/src/GuiQt/QGLWidgetTextRenderer.h b/src/GuiQt/QGLWidgetTextRenderer.h index a4dfe22a3..574cb54c2 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.h +++ b/src/GuiQt/QGLWidgetTextRenderer.h @@ -59,6 +59,7 @@ namespace caret { const AnnotationText& annotationText); virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, + const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut); @@ -67,6 +68,7 @@ namespace caret { const double viewportX, const double viewportY, const double viewportZ, + const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], @@ -85,6 +87,7 @@ namespace caret { FontData(); FontData(const AnnotationText& annotationText, + const int32_t viewportWidth, const int32_t viewportHeight); ~FontData(); @@ -166,6 +169,9 @@ namespace caret { /** Height of the viewport */ int32_t m_viewportHeight; + /** Width of the viewport */ + int32_t m_viewportWidth; + // ADD_NEW_MEMBERS_HERE static const double s_textMarginSize; diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index d524d33a5..e3e601749 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -415,6 +415,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) changeCoordFlag = true; moveOnePixelFlag = true; break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: changeCoordFlag = true; moveOnePixelFlag = true; @@ -474,6 +476,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } @@ -699,6 +703,9 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) spaceHeight = viewport[3]; } break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssertToDoFatal(); + break; case AnnotationCoordinateSpaceEnum::WINDOW: { int viewport[4]; diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index fd845d8dd..8b6b1d72f 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -115,6 +115,8 @@ m_newAnnotationCreatedByContextMenu(NULL) break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } -- GitLab From ea0bc21576578ccbfe67cc015114365cc4cd0417 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 12:11:17 -0500 Subject: [PATCH 275/755] Fixed deselection of chart labels as annotations. --- src/Annotations/AnnotationRedoUndoCommand.cxx | 30 +++++++- .../AnnotationTwoDimensionalShape.cxx | 3 - src/Brain/AnnotationManager.cxx | 17 +++++ src/Brain/CMakeLists.txt | 2 + src/Brain/ChartTwoOverlaySet.cxx | 17 ++++- src/Brain/EventAnnotationChartLabelGet.cxx | 74 +++++++++++++++++++ src/Brain/EventAnnotationChartLabelGet.h | 65 ++++++++++++++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 6 +- src/Common/EventTypeEnum.h | 2 + src/GuiQt/AnnotationCoordinateSpaceWidget.cxx | 1 - src/GuiQt/AnnotationCoordinateWidget.cxx | 47 ++++++++---- 12 files changed, 240 insertions(+), 25 deletions(-) create mode 100644 src/Brain/EventAnnotationChartLabelGet.cxx create mode 100644 src/Brain/EventAnnotationChartLabelGet.h diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index 132095598..fc07e264c 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -25,6 +25,7 @@ #include +#include "AnnotationChartTwoAxisLabel.h" #include "AnnotationFontAttributesInterface.h" #include "AnnotationLine.h" #include "AnnotationPercentSizeText.h" @@ -1588,9 +1589,32 @@ AnnotationRedoUndoCommand::setModeTextCharacters(const AString& text, Annotation* annotation = *iter; CaretAssert(annotation); - if (annotation->getType() == AnnotationTypeEnum::TEXT) { - AnnotationText* redoAnnotation = dynamic_cast(annotation->clone()); - CaretAssert(redoAnnotation); + AnnotationText* redoAnnotation = NULL; + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::CHART_AXIS_LABEL: + redoAnnotation = dynamic_cast(annotation->clone()); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + redoAnnotation = dynamic_cast(annotation->clone()); + break; + } + + /* + * This method should only get call for text-type annotations. + */ + CaretAssert(redoAnnotation); + + if (redoAnnotation != NULL) { redoAnnotation->setText(text); Annotation* undoAnnotation = annotation->clone(); diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 7e891140a..1d2f2ce37 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -368,9 +368,6 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp allowsRotationFlag = true; break; case AnnotationTypeEnum::CHART_AXIS_LABEL: - allowsMovingFlag = true; - allowsCornerResizingFlag = true; - allowsSideResizingFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index c00414e27..0df0987fc 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -29,6 +29,7 @@ #include "Annotation.h" #include "AnnotationArrangerExecutor.h" +#include "AnnotationChartTwoAxisLabel.h" #include "AnnotationColorBar.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" @@ -41,6 +42,7 @@ #include "CaretLogger.h" #include "CaretUndoStack.h" #include "DisplayPropertiesAnnotation.h" +#include "EventAnnotationChartLabelGet.h" #include "EventAnnotationColorBarGet.h" #include "EventAnnotationGroupGetWithKey.h" #include "EventGetDisplayedDataFiles.h" @@ -202,6 +204,14 @@ AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) cb->setSelectedForEditing(windowIndex, false); } + + EventAnnotationChartLabelGet chartLabelEvent; + EventManager::get()->sendEvent(chartLabelEvent.getPointer()); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + for (auto label : chartLabels) { + label->setSelectedForEditing(windowIndex, + false); + } } ///** @@ -483,6 +493,13 @@ AnnotationManager::getAllAnnotations() const allAnnotations.push_back(*iter); } + EventAnnotationChartLabelGet chartLabelEvent; + EventManager::get()->sendEvent(chartLabelEvent.getPointer()); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + allAnnotations.insert(allAnnotations.end(), + chartLabels.begin(), + chartLabels.end()); + return allAnnotations; } diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index fd4e1447a..44b816401 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -99,6 +99,7 @@ DisplayPropertyDataBoolean.h DisplayPropertyDataEnum.h DisplayPropertyDataFloat.h DummyFontTextRenderer.h +EventAnnotationChartLabelGet.h EventAnnotationColorBarGet.h EventBrainReset.h EventBrainStructureGetAll.h @@ -244,6 +245,7 @@ DisplayPropertiesVolume.cxx DisplayPropertyDataBoolean.cxx DisplayPropertyDataFloat.cxx DummyFontTextRenderer.cxx +EventAnnotationChartLabelGet.cxx EventAnnotationColorBarGet.cxx EventBrainReset.cxx EventBrainStructureGetAll.cxx diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 7017e1080..77a432cf9 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -28,6 +28,7 @@ #include "AnnotationChartTwoAxisLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" +#include "EventAnnotationChartLabelGet.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" @@ -126,6 +127,8 @@ m_tabIndex(tabIndex) m_chartDataType, i); } + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } @@ -478,7 +481,19 @@ ChartTwoOverlaySet::toString() const void ChartTwoOverlaySet::receiveEvent(Event* event) { - if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { + if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { + /* + * The events intended for overlays are received here so that + * only DISPLAYED overlays are updated. + */ + EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); + CaretAssert(chartLabelEvent); + + chartLabelEvent->addAnnotationChartLabel(m_chartAxisBottom->getAnnotationAxisLabel()); + chartLabelEvent->addAnnotationChartLabel(m_chartAxisLeft->getAnnotationAxisLabel()); + chartLabelEvent->addAnnotationChartLabel(m_chartAxisRight->getAnnotationAxisLabel()); + } + else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. diff --git a/src/Brain/EventAnnotationChartLabelGet.cxx b/src/Brain/EventAnnotationChartLabelGet.cxx new file mode 100644 index 000000000..7e0a15147 --- /dev/null +++ b/src/Brain/EventAnnotationChartLabelGet.cxx @@ -0,0 +1,74 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ +#include "EventAnnotationChartLabelGet.h" +#undef __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventAnnotationChartLabelGet + * \brief Event to get annotation chart labels + * \ingroup Brain + */ + +/** + * Constructor. + */ +EventAnnotationChartLabelGet::EventAnnotationChartLabelGet() +: Event(EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) +{ + +} + +/** + * Destructor. + */ +EventAnnotationChartLabelGet::~EventAnnotationChartLabelGet() +{ +} + +/** + * Add a chart label. + * + * @param annotationChartLabel + */ +void +EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationChartTwoAxisLabel* annotationChartLabel) +{ + m_annotationChartLabels.push_back(annotationChartLabel); +} + +/** + * @return The annotation chart labels. + */ +std::vector +EventAnnotationChartLabelGet::getAnnotationChartLabels() +{ + return m_annotationChartLabels; +} + diff --git a/src/Brain/EventAnnotationChartLabelGet.h b/src/Brain/EventAnnotationChartLabelGet.h new file mode 100644 index 000000000..0c6c6cd3e --- /dev/null +++ b/src/Brain/EventAnnotationChartLabelGet.h @@ -0,0 +1,65 @@ +#ifndef __EVENT_ANNOTATION_CHART_LABEL_GET_H__ +#define __EVENT_ANNOTATION_CHART_LABEL_GET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class AnnotationChartTwoAxisLabel; + + class EventAnnotationChartLabelGet : public Event { + + public: + EventAnnotationChartLabelGet(); + + virtual ~EventAnnotationChartLabelGet(); + + void addAnnotationChartLabel(AnnotationChartTwoAxisLabel* annotationChartLabel); + + std::vector getAnnotationChartLabels(); + + // ADD_NEW_METHODS_HERE + + private: + EventAnnotationChartLabelGet(const EventAnnotationChartLabelGet&); + + EventAnnotationChartLabelGet& operator=(const EventAnnotationChartLabelGet&); + + std::vector m_annotationChartLabels; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ + // +#endif // __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ + +} // namespace +#endif //__EVENT_ANNOTATION_CHART_LABEL_GET_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 6fd3d54dd..4a8b50cf8 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -469,6 +469,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) break; case EventTypeEnum::EVENT_ALERT_USER: case EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE: + case EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET: case EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET: case EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE: case EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 07e8f08aa..9b217657c 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -73,7 +73,11 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE, "EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE", "Event to add or remove an annotation from a file")); - + + enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_CHART_LABEL_GET, + "EVENT_ANNOTATION_CHART_LABEL_GET", + "Event to get annotation chart labels")); + enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_COLOR_BAR_GET, "EVENT_ANNOTATION_COLOR_BAR_GET", "Event to get annotation color bars from tab(s)")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 3b7f45f5e..faa7060c3 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -42,6 +42,8 @@ public: EVENT_ALERT_USER, /** Add annotation to or remove from a file */ EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE, + /** Get annnotation chart labels */ + EVENT_ANNOTATION_CHART_LABEL_GET, /** Get color bars from tab(s) */ EVENT_ANNOTATION_COLOR_BAR_GET, /** Annotation create new of a particular type */ diff --git a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx index 87f810172..f9e4afe8c 100644 --- a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx @@ -142,7 +142,6 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 3964edeb2..db8a6fa04 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -265,18 +265,26 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) bool surfaceFlag = false; if (coordinate != NULL) { - double xyMin = 0.0; - double xyMax = 100.0; + float xyz[3]; + coordinate->getXYZ(xyz); + + bool viewportSpaceFlag = false; + double xMin = 0.0; + double xMax = 100.0; + double yMin = 0.0; + double yMax = 100.0; double zMin = -100.0; double zMax = 100.0; double xyzStep = 0.1; QString suffix("%"); switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - xyMax = 10000.0; - xyMin = -xyMax; - zMin = xyMin; - zMax = xyMax; + xMax = 10000.0; + xMin = -xMax; + yMax = 10000.0; + yMin = -yMax; + zMin = xMin; + zMax = xMax; xyzStep = 1.0; suffix.clear(); break; @@ -289,27 +297,30 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) zMin = 0.0; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + xMin = xyz[0]; + xMax = xyz[0]; + yMin = xyz[1]; + yMax = xyz[1]; + zMin = xyz[2]; + zMax = xyz[2]; + viewportSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: zMin = 0.0; break; } - float xyz[3]; - coordinate->getXYZ(xyz); - m_xCoordSpinBox->blockSignals(true); - m_xCoordSpinBox->setRange(xyMin, - xyMax); + m_xCoordSpinBox->setRange(xMin, + xMax); m_xCoordSpinBox->setSingleStep(xyzStep); m_xCoordSpinBox->setSuffix(suffix); m_xCoordSpinBox->setValue(xyz[0]); m_xCoordSpinBox->blockSignals(false); m_yCoordSpinBox->blockSignals(true); - m_yCoordSpinBox->setRange(xyMin, - xyMax); + m_yCoordSpinBox->setRange(yMin, + yMax); m_yCoordSpinBox->setSingleStep(xyzStep); m_yCoordSpinBox->setSuffix(suffix); m_yCoordSpinBox->setValue(xyz[1]); @@ -346,7 +357,12 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_surfaceOffsetLengthSpinBox->blockSignals(false); } - setEnabled(true); + if (viewportSpaceFlag) { + setEnabled(false); + } + else { + setEnabled(true); + } } else { setEnabled(false); @@ -377,7 +393,6 @@ AnnotationCoordinateWidget::valueChanged() case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; -- GitLab From 48c88a0029a04425d7bb9b820ab5a61baf84f845 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 12:51:14 -0500 Subject: [PATCH 276/755] Renamed AnnotationChartTwoAxisLabel to AnnotationGraphicsLabel. --- src/Annotations/Annotation.cxx | 22 +++++----- ...sLabel.cxx => AnnotationGraphicsLabel.cxx} | 30 ++++++------- ...oAxisLabel.h => AnnotationGraphicsLabel.h} | 22 +++++----- src/Annotations/AnnotationRedoUndoCommand.cxx | 6 +-- .../AnnotationTwoDimensionalShape.cxx | 2 +- src/Annotations/AnnotationTypeEnum.cxx | 8 ++-- src/Annotations/AnnotationTypeEnum.h | 4 +- src/Annotations/CMakeLists.txt | 4 +- src/Brain/AnnotationManager.cxx | 6 +-- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 44 +++++++++---------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 10 ++--- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 18 ++++---- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 4 +- .../BrainOpenGLChartTwoDrawingInterface.h | 6 +-- src/Brain/BrainOpenGLFixedPipeline.cxx | 32 +++++++------- src/Brain/BrainOpenGLFixedPipeline.h | 4 +- src/Brain/ChartTwoOverlaySet.cxx | 2 +- src/Brain/EventAnnotationChartLabelGet.cxx | 4 +- src/Brain/EventAnnotationChartLabelGet.h | 8 ++-- src/Charting/ChartTwoCartesianAxis.cxx | 10 ++--- src/Charting/ChartTwoCartesianAxis.h | 8 ++-- src/Files/AnnotationFileXmlWriter.cxx | 2 +- src/GuiQt/AnnotationColorWidget.cxx | 2 +- .../AnnotationCoordinateSelectionWidget.cxx | 2 +- src/GuiQt/AnnotationCreateDialog.cxx | 4 +- src/GuiQt/AnnotationInsertNewWidget.cxx | 2 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 2 +- 27 files changed, 134 insertions(+), 134 deletions(-) rename src/Annotations/{AnnotationChartTwoAxisLabel.cxx => AnnotationGraphicsLabel.cxx} (73%) rename src/Annotations/{AnnotationChartTwoAxisLabel.h => AnnotationGraphicsLabel.h} (65%) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 7a103954e..7f306cd4e 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -24,7 +24,7 @@ #undef __ANNOTATION_DECLARE__ #include "AnnotationBox.h" -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" @@ -174,11 +174,11 @@ Annotation::clone() const myClone = new AnnotationBox(*box); } break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: { - const AnnotationChartTwoAxisLabel* axisLabel = dynamic_cast(this); + const AnnotationGraphicsLabel* axisLabel = dynamic_cast(this); CaretAssert(axisLabel); - myClone = new AnnotationChartTwoAxisLabel(*axisLabel); + myClone = new AnnotationGraphicsLabel(*axisLabel); } break; case AnnotationTypeEnum::COLOR_BAR: @@ -346,8 +346,8 @@ Annotation::newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, case AnnotationTypeEnum::BOX: annotation = new AnnotationBox(attributeDefaultType); break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: - annotation = new AnnotationChartTwoAxisLabel(attributeDefaultType, + case AnnotationTypeEnum::GRAPHICS_LABEL: + annotation = new AnnotationGraphicsLabel(attributeDefaultType, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); break; case AnnotationTypeEnum::COLOR_BAR: @@ -418,7 +418,7 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: m_colorBackground = CaretColorEnum::BLACK; break; case AnnotationTypeEnum::COLOR_BAR: @@ -472,7 +472,7 @@ Annotation::initializeAnnotationMembers() m_colorBackground = defaultColor; } break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: break; @@ -519,7 +519,7 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: disallowLineColorNoneFlag = true; @@ -609,7 +609,7 @@ Annotation::getTextForPasteMenuItems(AString& pasteMenuItemText, switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: break; @@ -1225,7 +1225,7 @@ Annotation::textAnnotationResetName() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: break; diff --git a/src/Annotations/AnnotationChartTwoAxisLabel.cxx b/src/Annotations/AnnotationGraphicsLabel.cxx similarity index 73% rename from src/Annotations/AnnotationChartTwoAxisLabel.cxx rename to src/Annotations/AnnotationGraphicsLabel.cxx index 65824695c..1d399a65e 100644 --- a/src/Annotations/AnnotationChartTwoAxisLabel.cxx +++ b/src/Annotations/AnnotationGraphicsLabel.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ -#include "AnnotationChartTwoAxisLabel.h" -#undef __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ +#define __ANNOTATION_GRAPHICS_LABEL_DECLARE__ +#include "AnnotationGraphicsLabel.h" +#undef __ANNOTATION_GRAPHICS_LABEL_DECLARE__ #include "AnnotationCoordinate.h" #include "CaretAssert.h" @@ -31,7 +31,7 @@ using namespace caret; /** - * \class caret::AnnotationChartTwoAxisLabel + * \class caret::AnnotationGraphicsLabel * \brief Contains text for a chart two axis label * \ingroup Annotations */ @@ -44,9 +44,9 @@ using namespace caret; * @param fontSizeType * Type of font sizing (percent width or height) */ -AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, +AnnotationGraphicsLabel::AnnotationGraphicsLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) -: AnnotationPercentSizeText(AnnotationTypeEnum::CHART_AXIS_LABEL, +: AnnotationPercentSizeText(AnnotationTypeEnum::GRAPHICS_LABEL, attributeDefaultType, fontSizeType) { @@ -59,7 +59,7 @@ AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationAttribu /** * Destructor. */ -AnnotationChartTwoAxisLabel::~AnnotationChartTwoAxisLabel() +AnnotationGraphicsLabel::~AnnotationGraphicsLabel() { } @@ -68,10 +68,10 @@ AnnotationChartTwoAxisLabel::~AnnotationChartTwoAxisLabel() * @param obj * Object that is copied. */ -AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj) +AnnotationGraphicsLabel::AnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj) : AnnotationPercentSizeText(obj) { - this->copyHelperAnnotationChartTwoAxisLabel(obj); + this->copyHelperAnnotationGraphicsLabel(obj); } /** @@ -81,12 +81,12 @@ AnnotationChartTwoAxisLabel::AnnotationChartTwoAxisLabel(const AnnotationChartTw * @return * Reference to this object. */ -AnnotationChartTwoAxisLabel& -AnnotationChartTwoAxisLabel::operator=(const AnnotationChartTwoAxisLabel& obj) +AnnotationGraphicsLabel& +AnnotationGraphicsLabel::operator=(const AnnotationGraphicsLabel& obj) { if (this != &obj) { AnnotationPercentSizeText::operator=(obj); - this->copyHelperAnnotationChartTwoAxisLabel(obj); + this->copyHelperAnnotationGraphicsLabel(obj); } return *this; } @@ -97,7 +97,7 @@ AnnotationChartTwoAxisLabel::operator=(const AnnotationChartTwoAxisLabel& obj) * Object that is copied. */ void -AnnotationChartTwoAxisLabel::copyHelperAnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj) +AnnotationGraphicsLabel::copyHelperAnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj) { // m_axisViewport[0] = obj.m_axisViewport[0]; // m_axisViewport[1] = obj.m_axisViewport[1]; @@ -112,7 +112,7 @@ AnnotationChartTwoAxisLabel::copyHelperAnnotationChartTwoAxisLabel(const Annotat // * Values for viewport. // */ //void -//AnnotationChartTwoAxisLabel::setAxisViewport(const int32_t axisViewport[4]) +//AnnotationGraphicsLabel::setAxisViewport(const int32_t axisViewport[4]) //{ // m_axisViewport[0] = axisViewport[0]; // m_axisViewport[1] = axisViewport[1]; @@ -127,7 +127,7 @@ AnnotationChartTwoAxisLabel::copyHelperAnnotationChartTwoAxisLabel(const Annotat // * Output with the axis viewport. // */ //void -//AnnotationChartTwoAxisLabel::getAxisViewport(int32_t axisViewportOut[4]) const +//AnnotationGraphicsLabel::getAxisViewport(int32_t axisViewportOut[4]) const //{ // axisViewportOut[0] = m_axisViewport[0]; // axisViewportOut[1] = m_axisViewport[1]; diff --git a/src/Annotations/AnnotationChartTwoAxisLabel.h b/src/Annotations/AnnotationGraphicsLabel.h similarity index 65% rename from src/Annotations/AnnotationChartTwoAxisLabel.h rename to src/Annotations/AnnotationGraphicsLabel.h index b08b15945..b9a315f0e 100644 --- a/src/Annotations/AnnotationChartTwoAxisLabel.h +++ b/src/Annotations/AnnotationGraphicsLabel.h @@ -1,5 +1,5 @@ -#ifndef __ANNOTATION_CHART_TWO_AXIS_LABEL_H__ -#define __ANNOTATION_CHART_TWO_AXIS_LABEL_H__ +#ifndef __ANNOTATION_GRAPHICS_LABEL_H__ +#define __ANNOTATION_GRAPHICS_LABEL_H__ /*LICENSE_START*/ /* @@ -28,17 +28,17 @@ namespace caret { - class AnnotationChartTwoAxisLabel : public AnnotationPercentSizeText { + class AnnotationGraphicsLabel : public AnnotationPercentSizeText { public: - AnnotationChartTwoAxisLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, + AnnotationGraphicsLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); - virtual ~AnnotationChartTwoAxisLabel(); + virtual ~AnnotationGraphicsLabel(); - AnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj); + AnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj); - AnnotationChartTwoAxisLabel& operator=(const AnnotationChartTwoAxisLabel& obj); + AnnotationGraphicsLabel& operator=(const AnnotationGraphicsLabel& obj); // void setAxisViewport(const int32_t axisViewport[4]); // @@ -47,16 +47,16 @@ namespace caret { // ADD_NEW_METHODS_HERE private: - void copyHelperAnnotationChartTwoAxisLabel(const AnnotationChartTwoAxisLabel& obj); + void copyHelperAnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj); // ADD_NEW_MEMBERS_HERE // int32_t m_axisViewport[4] = { 0, 0, 0, 0 }; }; -#ifdef __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ +#ifdef __ANNOTATION_GRAPHICS_LABEL_DECLARE__ // -#endif // __ANNOTATION_CHART_TWO_AXIS_LABEL_DECLARE__ +#endif // __ANNOTATION_GRAPHICS_LABEL_DECLARE__ } // namespace -#endif //__ANNOTATION_CHART_TWO_AXIS_LABEL_H__ +#endif //__ANNOTATION_GRAPHICS_LABEL_H__ diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index fc07e264c..c81641dc5 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -25,7 +25,7 @@ #include -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "AnnotationFontAttributesInterface.h" #include "AnnotationLine.h" #include "AnnotationPercentSizeText.h" @@ -1593,8 +1593,8 @@ AnnotationRedoUndoCommand::setModeTextCharacters(const AString& text, switch (annotation->getType()) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: - redoAnnotation = dynamic_cast(annotation->clone()); + case AnnotationTypeEnum::GRAPHICS_LABEL: + redoAnnotation = dynamic_cast(annotation->clone()); break; case AnnotationTypeEnum::COLOR_BAR: break; diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 1d2f2ce37..bc021faae 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -367,7 +367,7 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp allowsSideResizingFlag = true; allowsRotationFlag = true; break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; diff --git a/src/Annotations/AnnotationTypeEnum.cxx b/src/Annotations/AnnotationTypeEnum.cxx index 2477c3a26..d69843259 100644 --- a/src/Annotations/AnnotationTypeEnum.cxx +++ b/src/Annotations/AnnotationTypeEnum.cxx @@ -110,14 +110,14 @@ AnnotationTypeEnum::initialize() "BOX", "Box")); - enumData.push_back(AnnotationTypeEnum(CHART_AXIS_LABEL, - "CHART_AXIS_LABEL", - "Chart Axis Label")); - enumData.push_back(AnnotationTypeEnum(COLOR_BAR, "COLOR_BAR", "Color Bar")); + enumData.push_back(AnnotationTypeEnum(GRAPHICS_LABEL, + "GRAPHICS_LABEL", + "Graphics Text Label")); + enumData.push_back(AnnotationTypeEnum(IMAGE, "IMAGE", "Image")); diff --git a/src/Annotations/AnnotationTypeEnum.h b/src/Annotations/AnnotationTypeEnum.h index f61d120a2..456260cf5 100644 --- a/src/Annotations/AnnotationTypeEnum.h +++ b/src/Annotations/AnnotationTypeEnum.h @@ -37,10 +37,10 @@ public: enum Enum { /** Box */ BOX, - /** Chart axis label */ - CHART_AXIS_LABEL, /** Colorbar */ COLOR_BAR, + /** Text label in graphics region */ + GRAPHICS_LABEL, /** Image */ IMAGE, /** Line */ diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 7d0d0a880..97795bc48 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -27,7 +27,7 @@ Annotation.h AnnotationAlignmentEnum.h AnnotationAttributesDefaultTypeEnum.h AnnotationBox.h -AnnotationChartTwoAxisLabel.h +AnnotationGraphicsLabel.h AnnotationColorBar.h AnnotationColorBarNumericText.h AnnotationColorBarPositionModeEnum.h @@ -70,7 +70,7 @@ Annotation.cxx AnnotationAlignmentEnum.cxx AnnotationAttributesDefaultTypeEnum.cxx AnnotationBox.cxx -AnnotationChartTwoAxisLabel.cxx +AnnotationGraphicsLabel.cxx AnnotationColorBar.cxx AnnotationColorBarNumericText.cxx AnnotationColorBarPositionModeEnum.cxx diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 0df0987fc..875b31232 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -29,7 +29,7 @@ #include "Annotation.h" #include "AnnotationArrangerExecutor.h" -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" @@ -207,7 +207,7 @@ AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); - std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); for (auto label : chartLabels) { label->setSelectedForEditing(windowIndex, false); @@ -495,7 +495,7 @@ AnnotationManager::getAllAnnotations() const EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); - std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); allAnnotations.insert(allAnnotations.end(), chartLabels.begin(), chartLabels.end()); diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 4cda42f66..c8f610114 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -29,7 +29,7 @@ #undef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationBox.h" -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationColorBarSection.h" #include "AnnotationColorBarNumericText.h" @@ -512,10 +512,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic m_volumeSpacePlaneValid = true; std::vector dummyColorBars; - std::vector dummyAnnotationChartTwoAxisLabelsForDrawing; + std::vector dummyAnnotationGraphicsLabelsForDrawing; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, dummyColorBars, - dummyAnnotationChartTwoAxisLabelsForDrawing, + dummyAnnotationGraphicsLabelsForDrawing, NULL, sliceThickness); } @@ -533,7 +533,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. - * @param annotationChartTwoAxisLabelsForDrawing + * @param annotationChartGraphicsLabelsForDrawing * Annotation chart two labels that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. @@ -542,7 +542,7 @@ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartTwoAxisLabelsForDrawing, + std::vector& annotationChartGraphicsLabelsForDrawing, const Surface* surfaceDisplayed) { CaretAssert(inputs); @@ -553,7 +553,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const float sliceThickness = 0.0; drawAnnotationsInternal(drawingCoordinateSpace, colorBars, - annotationChartTwoAxisLabelsForDrawing, + annotationChartGraphicsLabelsForDrawing, surfaceDisplayed, sliceThickness); @@ -569,7 +569,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, * Surface that is displayed. May be NULL in some instances. * @param colorbars * Colorbars that will be drawn. - * @param annotationChartTwoAxisLabelsForDrawing + * @param annotationChartGraphicsLabelsForDrawing * Annotation chart two labels that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. @@ -579,7 +579,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartTwoAxisLabelsForDrawing, + std::vector& annotationChartGraphicsLabelsForDrawing, const Surface* surfaceDisplayed, const float sliceThickness) { @@ -724,8 +724,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat break; case AnnotationCoordinateSpaceEnum::VIEWPORT: annotationsFromFile.insert(annotationsFromFile.end(), - annotationChartTwoAxisLabelsForDrawing.begin(), - annotationChartTwoAxisLabelsForDrawing.end()); + annotationChartGraphicsLabelsForDrawing.begin(), + annotationChartGraphicsLabelsForDrawing.end()); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: @@ -783,8 +783,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat // if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { // annotationsFromFile.insert(annotationsFromFile.end(), -// annotationChartTwoAxisLabelsForDrawing.begin(), -// annotationChartTwoAxisLabelsForDrawing.end()); +// annotationChartGraphicsLabelsForDrawing.begin(), +// annotationChartGraphicsLabelsForDrawing.end()); // } } break; @@ -1146,9 +1146,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota dynamic_cast(annotation), surfaceDisplayed); break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: - drawChartTwoAxisLabel(annotationFile, - dynamic_cast(annotation)); + case AnnotationTypeEnum::GRAPHICS_LABEL: + drawChartGraphicsLabel(annotationFile, + dynamic_cast(annotation)); break;; case AnnotationTypeEnum::COLOR_BAR: drawColorBar(annotationFile, @@ -1326,15 +1326,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * * @param annotationFile * File containing the annotation. - * @param chartTwoAxisLabel + * @param chartGraphicsLabel * Axis label to draw. */ void -BrainOpenGLAnnotationDrawingFixedPipeline::drawChartTwoAxisLabel(AnnotationFile* annotationFile, - AnnotationChartTwoAxisLabel* chartTwoAxisLabel) +BrainOpenGLAnnotationDrawingFixedPipeline::drawChartGraphicsLabel(AnnotationFile* annotationFile, + AnnotationGraphicsLabel* chartGraphicsLabel) { - CaretAssert(chartTwoAxisLabel); - CaretAssert(chartTwoAxisLabel->getType() == AnnotationTypeEnum::CHART_AXIS_LABEL); + CaretAssert(chartGraphicsLabel); + CaretAssert(chartGraphicsLabel->getType() == AnnotationTypeEnum::GRAPHICS_LABEL); // const GLint savedModelSpaceViewport[4] = { // m_modelSpaceModelMatrix[0], @@ -1358,7 +1358,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawChartTwoAxisLabel(AnnotationFile* // m_modelSpaceViewport[3] = labelViewport[3]; drawText(annotationFile, - chartTwoAxisLabel, + chartGraphicsLabel, NULL); // glPopAttrib(); @@ -2283,7 +2283,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi { CaretAssert(text); CaretAssert((text->getType() == AnnotationTypeEnum::TEXT) - || (text->getType() == AnnotationTypeEnum::CHART_AXIS_LABEL)); + || (text->getType() == AnnotationTypeEnum::GRAPHICS_LABEL)); DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); if (text->getType() == AnnotationTypeEnum::TEXT) { diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 753e8540d..58f23e4fc 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -35,7 +35,7 @@ namespace caret { class Annotation; class AnnotationBox; - class AnnotationChartTwoAxisLabel; + class AnnotationGraphicsLabel; class AnnotationColorBar; class AnnotationCoordinate; class AnnotationFile; @@ -117,7 +117,7 @@ namespace caret { void drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartTwoAxisLabelsForDrawing, + std::vector& annotationChartGraphicsLabelsForDrawing, const Surface* surfaceDisplayed); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, @@ -187,7 +187,7 @@ namespace caret { void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartTwoAxisLabelsForDrawing, + std::vector& annotationChartGraphicsLabelsForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); @@ -221,8 +221,8 @@ namespace caret { AnnotationBox* box, const Surface* surfaceDisplayed); - void drawChartTwoAxisLabel(AnnotationFile* annotationFile, - AnnotationChartTwoAxisLabel* chartTwoAxisLabel); + void drawChartGraphicsLabel(AnnotationFile* annotationFile, + AnnotationGraphicsLabel* chartGraphicsLabel); bool drawImage(AnnotationFile* annotationFile, AnnotationImage* image, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 9719660d8..3a326c4c2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -25,7 +25,7 @@ #include -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "AnnotationCoordinate.h" #include "AnnotationColorBar.h" #include "AnnotationPercentSizeText.h" @@ -103,7 +103,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * Selected data type. * @param viewport * Viewport for the chart. - * @param annotationChartTwoAxisLabelsOut + * @param annotationChartGraphicsLabelsOut * Output containing annotation chart axis labels that will be drawn * by the Annotation OpenGL Drawing. */ @@ -114,10 +114,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartTwoAxisLabelsOut) + std::vector& annotationChartGraphicsLabelsOut) { - annotationChartTwoAxisLabelsOut.clear(); - m_annotationDrawingChartTwoAxisLabels.clear(); + annotationChartGraphicsLabelsOut.clear(); + m_annotationDrawingChartGraphicsLabels.clear(); CaretAssert(brain); CaretAssert(browserTabContent); @@ -275,7 +275,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); - annotationChartTwoAxisLabelsOut = m_annotationDrawingChartTwoAxisLabels; + annotationChartGraphicsLabelsOut = m_annotationDrawingChartGraphicsLabels; } /** @@ -1171,7 +1171,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - const AnnotationChartTwoAxisLabel* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); + const AnnotationGraphicsLabel* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); const AString axisTitle = chartAxisLabel->getText(); if ( ! axisTitle.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); @@ -1622,7 +1622,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data && (axisVpHeight > 0.0)) { // const float labelPercentX = 100.0f * (axisTextCenterX / axisVpWidth); // const float labelPercentY = 100.0f * (axisTextCenterY / axisVpHeight); - AnnotationChartTwoAxisLabel* chartLabel = axis->getAnnotationAxisLabel(); + AnnotationGraphicsLabel* chartLabel = axis->getAnnotationAxisLabel(); chartLabel->setCustomTextColor(rgba); chartLabel->setTextColor(CaretColorEnum::CUSTOM); chartLabel->setTabIndex(m_tabIndex); @@ -1635,7 +1635,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data // labelPercentY, // 0.0f); - m_annotationDrawingChartTwoAxisLabels.push_back(chartLabel); + m_annotationDrawingChartGraphicsLabels.push_back(chartLabel); } // /* diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 12877842a..d52c33135 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -54,7 +54,7 @@ namespace caret { BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartTwoAxisLabelsOut) override; + std::vector& annotationChartGraphicsLabelsOut) override; // ADD_NEW_METHODS_HERE @@ -177,7 +177,7 @@ namespace caret { bool m_identificationModeFlag; - std::vector m_annotationDrawingChartTwoAxisLabels; + std::vector m_annotationDrawingChartGraphicsLabels; static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 65c89db28..8d96cf5c1 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -28,7 +28,7 @@ namespace caret { - class AnnotationChartTwoAxisLabel; + class AnnotationGraphicsLabel; class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; @@ -57,7 +57,7 @@ namespace caret { * Selected data type. * @param viewport * Viewport for the chart. - * @param annotationChartTwoAxisLabelsOut + * @param annotationChartGraphicsLabelsOut * Output containing annotation chart axis labels that will be drawn * by the Annotation OpenGL Drawing. */ @@ -67,7 +67,7 @@ namespace caret { BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartTwoAxisLabelsOut) = 0; + std::vector& annotationChartGraphicsLabelsOut) = 0; // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 17f2ac826..2ae486533 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -275,7 +275,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, setTabViewport(viewportContent); - m_annotationChartTwoAxisLabelsForDrawing.clear(); + m_annotationChartGraphicsLabelsForDrawing.clear(); std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); @@ -358,7 +358,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex m_clippingPlaneGroup = NULL; - m_annotationChartTwoAxisLabelsForDrawing.clear(); + m_annotationChartGraphicsLabelsForDrawing.clear(); m_brain->getSelectionManager()->reset(); this->modeProjectionData = &projectionOut; @@ -527,7 +527,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, setTabViewport(NULL); - m_annotationChartTwoAxisLabelsForDrawing.clear(); + m_annotationChartGraphicsLabelsForDrawing.clear(); setAnnotationColorBarsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); @@ -801,13 +801,13 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - m_annotationChartTwoAxisLabelsForDrawing, + m_annotationChartGraphicsLabelsForDrawing, NULL); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::VIEWPORT, m_annotationColorBarsForDrawing, - m_annotationChartTwoAxisLabelsForDrawing, + m_annotationChartGraphicsLabelsForDrawing, NULL); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -876,11 +876,11 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, windowDrawingMode); - std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; + std::vector emptyAnnotationGraphicsLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, - emptyAnnotationChartTwoAxisLabelsForDrawing, + emptyAnnotationGraphicsLabelsForDrawing, NULL); glPopMatrix(); @@ -985,7 +985,7 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - m_annotationChartTwoAxisLabelsForDrawing, + m_annotationChartGraphicsLabelsForDrawing, NULL); } } @@ -1823,17 +1823,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; - std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; + std::vector emptyAnnotationGraphicsLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, - emptyAnnotationChartTwoAxisLabelsForDrawing, + emptyAnnotationGraphicsLabelsForDrawing, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, - emptyAnnotationChartTwoAxisLabelsForDrawing, + emptyAnnotationGraphicsLabelsForDrawing, NULL); } } @@ -1873,17 +1873,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; - std::vector emptyAnnotationChartTwoAxisLabelsForDrawing; + std::vector emptyAnnotationGraphicsLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, - emptyAnnotationChartTwoAxisLabelsForDrawing, + emptyAnnotationGraphicsLabelsForDrawing, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, - emptyAnnotationChartTwoAxisLabelsForDrawing, + emptyAnnotationGraphicsLabelsForDrawing, NULL); } @@ -5404,7 +5404,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, CaretAssert(browserTabContent); CaretAssert(chartModel); - m_annotationChartTwoAxisLabelsForDrawing.clear(); + m_annotationChartGraphicsLabelsForDrawing.clear(); BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, @@ -5413,7 +5413,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, - m_annotationChartTwoAxisLabelsForDrawing); + m_annotationChartGraphicsLabelsForDrawing); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 4906d99c6..21e368bd7 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -42,7 +42,7 @@ namespace caret { - class AnnotationChartTwoAxisLabel; + class AnnotationGraphicsLabel; class AnnotationText; class BoundingBox; class Brain; @@ -622,7 +622,7 @@ namespace caret { std::vector m_annotationColorBarsForDrawing; - std::vector m_annotationChartTwoAxisLabelsForDrawing; + std::vector m_annotationChartGraphicsLabelsForDrawing; static bool s_staticInitialized; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 77a432cf9..0933e61ce 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -25,7 +25,7 @@ #include "CaretAssert.h" #include "CaretMappableDataFile.h" -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventAnnotationChartLabelGet.h" diff --git a/src/Brain/EventAnnotationChartLabelGet.cxx b/src/Brain/EventAnnotationChartLabelGet.cxx index 7e0a15147..fd1d29d14 100644 --- a/src/Brain/EventAnnotationChartLabelGet.cxx +++ b/src/Brain/EventAnnotationChartLabelGet.cxx @@ -58,7 +58,7 @@ EventAnnotationChartLabelGet::~EventAnnotationChartLabelGet() * @param annotationChartLabel */ void -EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationChartTwoAxisLabel* annotationChartLabel) +EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationGraphicsLabel* annotationChartLabel) { m_annotationChartLabels.push_back(annotationChartLabel); } @@ -66,7 +66,7 @@ EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationChartTwoAxisLabe /** * @return The annotation chart labels. */ -std::vector +std::vector EventAnnotationChartLabelGet::getAnnotationChartLabels() { return m_annotationChartLabels; diff --git a/src/Brain/EventAnnotationChartLabelGet.h b/src/Brain/EventAnnotationChartLabelGet.h index 0c6c6cd3e..cd2bb1959 100644 --- a/src/Brain/EventAnnotationChartLabelGet.h +++ b/src/Brain/EventAnnotationChartLabelGet.h @@ -31,7 +31,7 @@ namespace caret { - class AnnotationChartTwoAxisLabel; + class AnnotationGraphicsLabel; class EventAnnotationChartLabelGet : public Event { @@ -40,9 +40,9 @@ namespace caret { virtual ~EventAnnotationChartLabelGet(); - void addAnnotationChartLabel(AnnotationChartTwoAxisLabel* annotationChartLabel); + void addAnnotationChartLabel(AnnotationGraphicsLabel* annotationChartLabel); - std::vector getAnnotationChartLabels(); + std::vector getAnnotationChartLabels(); // ADD_NEW_METHODS_HERE @@ -51,7 +51,7 @@ namespace caret { EventAnnotationChartLabelGet& operator=(const EventAnnotationChartLabelGet&); - std::vector m_annotationChartLabels; + std::vector m_annotationChartLabels; // ADD_NEW_MEMBERS_HERE diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 95582ebbd..94cc6e288 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -23,7 +23,7 @@ #include "ChartTwoCartesianAxis.h" #undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" @@ -66,7 +66,7 @@ m_axisLocation(axisLocation) case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: break; } - m_annotationAxisLabel = std::unique_ptr(new AnnotationChartTwoAxisLabel(AnnotationAttributesDefaultTypeEnum::NORMAL, + m_annotationAxisLabel = std::unique_ptr(new AnnotationGraphicsLabel(AnnotationAttributesDefaultTypeEnum::NORMAL, fontSizeType)); /* @@ -103,7 +103,7 @@ m_axisLocation(axisLocation) m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); m_sceneAssistant->add("m_annotationAxisLabel", - "AnnotationChartTwoAxisLabel", + "AnnotationGraphicsLabel", m_annotationAxisLabel.get()); m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); @@ -496,7 +496,7 @@ ChartTwoCartesianAxis::toString() const /** * @return Annotation used for drawing axis label and tick mark numeric values */ -const AnnotationChartTwoAxisLabel* +const AnnotationGraphicsLabel* ChartTwoCartesianAxis::getAnnotationAxisLabel() const { return m_annotationAxisLabel.get(); @@ -505,7 +505,7 @@ ChartTwoCartesianAxis::getAnnotationAxisLabel() const /** * @return Annotation used for drawing axis label and tick mark numeric values */ -AnnotationChartTwoAxisLabel* +AnnotationGraphicsLabel* ChartTwoCartesianAxis::getAnnotationAxisLabel() { return m_annotationAxisLabel.get(); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 92af9605a..85a91d77e 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -33,7 +33,7 @@ namespace caret { - class AnnotationChartTwoAxisLabel; + class AnnotationGraphicsLabel; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { @@ -106,9 +106,9 @@ namespace caret { std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; - const AnnotationChartTwoAxisLabel* getAnnotationAxisLabel() const; + const AnnotationGraphicsLabel* getAnnotationAxisLabel() const; - AnnotationChartTwoAxisLabel* getAnnotationAxisLabel(); + AnnotationGraphicsLabel* getAnnotationAxisLabel(); // ADD_NEW_METHODS_HERE @@ -165,7 +165,7 @@ namespace caret { int32_t m_userDigitsRightOfDecimal = 1; /** Annotation used for drawing axis label and tick mark numeric values*/ - std::unique_ptr m_annotationAxisLabel; + std::unique_ptr m_annotationAxisLabel; ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index f73996948..04d8ed89a 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -255,7 +255,7 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) case AnnotationTypeEnum::BOX: writeBox(dynamic_cast(annotation)); break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: CaretAssertMessage(0, "Axis label is NEVER written to an annotation file"); break; case AnnotationTypeEnum::COLOR_BAR: diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index ba4a8d0a3..1f5f7af0f 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -488,7 +488,7 @@ AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, case AnnotationTypeEnum::BOX: allowBothColorsNoneFlag = false; break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: break; case AnnotationTypeEnum::COLOR_BAR: break; diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index d14cd4e6a..6e9a82b8f 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -93,7 +93,7 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: enableWindowSpaceFlag = false; break; case AnnotationTypeEnum::COLOR_BAR: diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index df3c153e4..03176b612 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -190,7 +190,7 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, switch (annotationType) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: CaretAssertMessage(0, "Axis Labels do not get created !!!"); break; case AnnotationTypeEnum::COLOR_BAR: @@ -873,7 +873,7 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() case AnnotationTypeEnum::BOX: useAverageFlag = true; break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: useAverageFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index 5d155ce7d..fe51e654c 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -411,7 +411,7 @@ AnnotationInsertNewWidget::createShapePixmap(const QWidget* widget, case AnnotationTypeEnum::BOX: painter->drawRect(1, 1, width - 2, height - 2); break; - case AnnotationTypeEnum::CHART_AXIS_LABEL: + case AnnotationTypeEnum::GRAPHICS_LABEL: CaretAssertMessage(0, "No pixmap for axis label as user does not create them like other annotations"); break; case AnnotationTypeEnum::COLOR_BAR: diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 1ee5085a7..86ceb1109 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -37,7 +37,7 @@ #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "CaretMappableDataFile.h" -#include "AnnotationChartTwoAxisLabel.h" +#include "AnnotationGraphicsLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" -- GitLab From b8c5a54db6acb5cd1544ff1d88582f94603afd92 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 14:33:42 -0500 Subject: [PATCH 277/755] Removed PIXEL space from annotations as it was not used and is pretty much replaced with the newer VIEWPORT space. --- .../AnnotationCoordinateSpaceEnum.cxx | 8 -------- .../AnnotationCoordinateSpaceEnum.h | 2 -- src/Annotations/AnnotationGroup.cxx | 12 ++---------- .../AnnotationOneDimensionalShape.cxx | 10 ++-------- src/Annotations/AnnotationRedoUndoCommand.cxx | 4 ---- .../AnnotationTwoDimensionalShape.cxx | 12 +----------- src/Brain/AnnotationArrangerExecutor.cxx | 3 --- src/Brain/AnnotationManager.cxx | 2 -- ...ainOpenGLAnnotationDrawingFixedPipeline.cxx | 16 ---------------- ...BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 2 -- src/Brain/DisplayPropertiesAnnotation.cxx | 5 ----- src/Brain/FtglFontTextRenderer.cxx | 2 -- src/Files/AnnotationFile.cxx | 14 -------------- src/Files/AnnotationFileXmlReader.cxx | 2 +- src/GuiQt/AnnotationChangeCoordinateDialog.cxx | 2 -- src/GuiQt/AnnotationCoordinateInformation.cxx | 13 ------------- .../AnnotationCoordinateSelectionWidget.cxx | 17 +---------------- src/GuiQt/AnnotationCoordinateSpaceWidget.cxx | 2 -- src/GuiQt/AnnotationCoordinateWidget.cxx | 4 ---- src/GuiQt/AnnotationCreateDialog.cxx | 4 ---- src/GuiQt/AnnotationFontWidget.cxx | 2 -- src/GuiQt/AnnotationInsertNewWidget.cxx | 6 ------ src/GuiQt/AnnotationPasteDialog.cxx | 2 -- src/GuiQt/AnnotationRotationWidget.cxx | 4 ---- src/GuiQt/UserInputModeAnnotations.cxx | 18 ++---------------- .../UserInputModeAnnotationsContextMenu.cxx | 2 -- 26 files changed, 9 insertions(+), 161 deletions(-) diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx index 7128c88c0..43e72a8a8 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx @@ -110,11 +110,6 @@ AnnotationCoordinateSpaceEnum::initialize() } initializedFlag = true; - enumData.push_back(AnnotationCoordinateSpaceEnum(PIXELS, - "PIXELS", - "Pixels", - "P")); - enumData.push_back(AnnotationCoordinateSpaceEnum(STEREOTAXIC, "STEREOTAXIC", "Stereotaxic", @@ -304,9 +299,6 @@ AnnotationCoordinateSpaceEnum::toToolTip(Enum enumValue) AString text; switch (enumValue) { - case PIXELS: - text = "New annotation is drawn at an XY pixel coordinate"; - break; case STEREOTAXIC: text = "New annotation is drawn at a surface/volume XYZ coordinate"; break; diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.h b/src/Annotations/AnnotationCoordinateSpaceEnum.h index a1c72a377..e8d2d45f6 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.h +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.h @@ -35,8 +35,6 @@ public: * Enumerated values. */ enum Enum { - /** Annotation in pixels (origin is bottom, left corner). */ - PIXELS, /** Annotation in stereotaxic (3D) space */ STEREOTAXIC, /** Annotation on surface node */ diff --git a/src/Annotations/AnnotationGroup.cxx b/src/Annotations/AnnotationGroup.cxx index dad98b6e5..82a9b143f 100644 --- a/src/Annotations/AnnotationGroup.cxx +++ b/src/Annotations/AnnotationGroup.cxx @@ -70,7 +70,7 @@ SceneableInterface() CaretAssert(annotationFile); CaretAssert(groupType != AnnotationGroupTypeEnum::INVALID); CaretAssert(uniqueKey > 0); - CaretAssert(coordinateSpace != AnnotationCoordinateSpaceEnum::PIXELS); + CaretAssert(coordinateSpace != AnnotationCoordinateSpaceEnum::VIEWPORT); initializeInstance(); @@ -93,9 +93,6 @@ SceneableInterface() m_tabOrWindowIndex = tabOrWindowIndex; switch (m_coordinateSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -182,7 +179,7 @@ void AnnotationGroup::initializeInstance() { m_groupKey.reset(); - m_coordinateSpace = AnnotationCoordinateSpaceEnum::PIXELS; + m_coordinateSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; m_name = ""; m_tabOrWindowIndex = -1; @@ -262,9 +259,6 @@ AnnotationGroup::getName() const AString spaceName = AnnotationCoordinateSpaceEnum::toGuiName(m_coordinateSpace); switch (m_coordinateSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssertMessage(0, "Should never be pixels"); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -425,8 +419,6 @@ AnnotationGroup::validateAddedAnnotation(const Annotation* annotation) } switch (space) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index b18643443..41f2ce996 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -315,16 +315,12 @@ AnnotationOneDimensionalShape::setRotationAngle(const float viewportWidth, bool AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { - bool pixelsFlag = false; bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; bool viewportFlag = false; switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - pixelsFlag = true; - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereotaxicFlag = true; break; @@ -344,7 +340,7 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool validFlag = false; - if ( ! pixelsFlag) { +// if ( ! pixelsFlag) { switch (sizingHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; @@ -379,7 +375,7 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp } break; } - } +// } return validFlag; } @@ -677,8 +673,6 @@ AnnotationOneDimensionalShape::applySpatialModification(const AnnotationSpatialM } switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationStereotaxicSpace(spatialModification); break; diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index c81641dc5..da4c91f81 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -1363,8 +1363,6 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValid = false; switch (oneDimAnn->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -1879,8 +1877,6 @@ AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercent float percentSize = newFontPercentSize; switch (redoAnnotation->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: percentSize *= surfaceSpaceRowCount; break; diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index bc021faae..44de59cd9 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -328,16 +328,12 @@ AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const An bool AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { - bool pixelsFlag = false; bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; bool viewportFlag = false; switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - pixelsFlag = true; - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereotaxicFlag = true; break; @@ -396,8 +392,7 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool validFlag = false; - if ( (! pixelsFlag) - && (! viewportFlag)) { + if (! viewportFlag) { switch (sizingHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: if (allowsSideResizingFlag) { @@ -479,9 +474,6 @@ AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace bool surfaceSpaceFlag = false; switch (coordinateSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - badSpaceFlag = true; - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereoSpaceFlag = true; break; @@ -1121,8 +1113,6 @@ AnnotationTwoDimensionalShape::applySpatialModification(const AnnotationSpatialM const AnnotationCoordinateSpaceEnum::Enum space = getCoordinateSpace(); switch (space) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationSurfaceOrStereotaxicSpace(spatialModification, space); diff --git a/src/Brain/AnnotationArrangerExecutor.cxx b/src/Brain/AnnotationArrangerExecutor.cxx index 9decf8e41..c230a6e56 100644 --- a/src/Brain/AnnotationArrangerExecutor.cxx +++ b/src/Brain/AnnotationArrangerExecutor.cxx @@ -612,9 +612,6 @@ AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& */ int32_t annViewport[4] = { 0, 0, 0, 0 }; switch (annotation->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: CaretAssert(0); break; diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 875b31232..4c746c712 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -952,8 +952,6 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ bool displayedFlag = false; switch (ann->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: displayedFlag = true; break; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index c8f610114..533995416 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -197,12 +197,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A } } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - windowXYZ[0] = annotationXYZ[0]; - windowXYZ[1] = annotationXYZ[1]; - windowXYZ[2] = annotationXYZ[2]; - windowXYZValid = true; - break; case AnnotationCoordinateSpaceEnum::SURFACE: if (surfaceDisplayed != NULL) { StructureEnum::Enum annotationStructure = StructureEnum::INVALID; @@ -613,10 +607,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssertMessage(0, "Never draw annotations in pixel space."); - return; - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: @@ -718,8 +708,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: @@ -1128,8 +1116,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: @@ -3398,8 +3384,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotat case AnnotationCoordinateSpaceEnum::STEREOTAXIC: depthTestFlag = true; break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: depthTestFlag = true; break; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 3a326c4c2..6472098b1 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -159,8 +159,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, for (auto cb : colorBars) { bool useItFlag = false; switch (cb->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index 147fb1c67..22d8debda 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -87,8 +87,6 @@ DisplayPropertiesAnnotation::updateForNewAnnotation(const Annotation* annotation CaretAssert(annotation); switch (annotation->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -416,9 +414,6 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) annIter++) { Annotation* ann = *annIter; switch (ann->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (stereoAnnDisplay != NULL) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 6d9bc1a7b..51762320e 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -185,8 +185,6 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, switch (annotationText.getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index c91da1e1d..744f96754 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -235,8 +235,6 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) const AnnotationCoordinateSpaceEnum::Enum annotationSpace = annotation->getCoordinateSpace(); int32_t annotationTabOrWindowIndex = -1; switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -258,9 +256,6 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) if (group->getGroupType() == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == annotationSpace) { switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: return group; @@ -280,9 +275,6 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) } switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: break; @@ -615,9 +607,6 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu } switch (coordinateSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - throw DataFileException("PIXELS coordinate space is not allowed for group while annotation file."); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -664,9 +653,6 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu if (groupType == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == coordinateSpace) { switch (coordinateSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: throw DataFileException("There is more than one annotation space group with space " diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index 99a5fd21b..fd6da346c 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -619,7 +619,7 @@ AnnotationFileXmlReader::readGroup(AnnotationFile* annotationFile) /* * Coordinate space */ - AnnotationCoordinateSpaceEnum::Enum coordSpace = AnnotationCoordinateSpaceEnum::PIXELS; + AnnotationCoordinateSpaceEnum::Enum coordSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_GROUP, diff --git a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx index fc8ef3dbd..cdd5af657 100644 --- a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx +++ b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx @@ -117,8 +117,6 @@ AnnotationChangeCoordinateDialog::createCurrentCoordinateWidget() switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: { useXyzFlag = false; diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index f5df30dd3..eca4ea133 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -108,9 +108,6 @@ AnnotationCoordinateInformation::isCoordinateSpaceValid(const AnnotationCoordina bool validSpaceFlag = false; switch (space) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssertMessage(0, "Space should never be pixels"); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: validSpaceFlag = m_modelXYZValid; break; @@ -160,8 +157,6 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi const AnnotationCoordinateSpaceEnum::Enum space = *spaceIter; switch (space) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: @@ -180,8 +175,6 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi addItFlag = coordInfoTwo->isCoordinateSpaceValid(space); switch (space) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: /* * Both coord info's must be in the SAME TAB @@ -450,9 +443,6 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: if (coordInfoOne->m_surfaceNodeValid) { const float surfaceOffsetLength = startCoordinate->getSurfaceOffsetLength(); @@ -607,9 +597,6 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: if (coordInfoOne->m_surfaceNodeValid) { coordinate->setSurfaceSpace(coordInfoOne->m_surfaceStructure, diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index 6e9a82b8f..a929ac849 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -353,7 +353,6 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) const AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::TAB; switch (space) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - case AnnotationCoordinateSpaceEnum::PIXELS: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: @@ -433,7 +432,7 @@ AnnotationCoordinateSpaceEnum::Enum AnnotationCoordinateSelectionWidget::getSelectedCoordinateSpace(bool& validOut) const { validOut = false; - AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::PIXELS; + AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::VIEWPORT; QAbstractButton* button = m_spaceButtonGroup->checkedButton(); if (button == NULL) { @@ -497,8 +496,6 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno case AnnotationCoordinateSpaceEnum::STEREOTAXIC: oldViewportHeight = m_coordInfo.m_tabHeight; break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: oldViewportHeight = m_coordInfo.m_tabHeight; break; @@ -530,9 +527,6 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno switch (oldSpace) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: @@ -563,9 +557,6 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno newViewportHeight = m_coordInfo.m_tabHeight; } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: if (m_coordInfo.m_surfaceNodeValid) { coordinate->setSurfaceSpace(m_coordInfo.m_surfaceStructure, @@ -771,9 +762,6 @@ AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* vpWidth = m_coordInfo.m_tabWidth; vpHeight = m_coordInfo.m_tabHeight; break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: vpWidth = m_coordInfo.m_tabWidth; vpHeight = m_coordInfo.m_tabHeight; @@ -843,9 +831,6 @@ AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Ann if (m_coordInfo.m_tabIndex >= 0) { } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssert(0); - break; case AnnotationCoordinateSpaceEnum::SURFACE: if (m_coordInfo.m_tabIndex >= 0) { } diff --git a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx index f9e4afe8c..869f5aef5 100644 --- a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx @@ -119,8 +119,6 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati switch (space) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index db8a6fa04..461befbfe 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -288,8 +288,6 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) xyzStep = 1.0; suffix.clear(); break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; @@ -385,8 +383,6 @@ AnnotationCoordinateWidget::valueChanged() switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 03176b612..d212c9d61 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -268,8 +268,6 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, */ bool adjustTextPctSizeFlag = false; switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: adjustTextPctSizeFlag = true; break; @@ -921,8 +919,6 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() float viewportWidth = 0.0; float viewportHeight = 0.0; switch (m_selectedSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: { diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index c4b6a16c7..a09008631 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -298,8 +298,6 @@ AnnotationFontWidget::updateContent(std::vector(annText); CaretAssert(ann); switch (ann->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: sizeValue /= surfaceMontageRowCount; break; diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index fe51e654c..12e04b17f 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -495,9 +495,6 @@ AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpace QActionGroup* actionGroup) { switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssertMessage(0, "Annotations in pixel space not supported."); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -574,9 +571,6 @@ AnnotationInsertNewWidget::createSpacePixmap(const QWidget* widget, * NOTE: ORIGIN is in TOP LEFT corner of pixmap. */ switch (annotationSpace) { - case AnnotationCoordinateSpaceEnum::PIXELS: - CaretAssertMessage(0, "Annotations in pixel space not supported."); - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationPasteDialog.cxx b/src/GuiQt/AnnotationPasteDialog.cxx index faa9fe988..6489eed40 100644 --- a/src/GuiQt/AnnotationPasteDialog.cxx +++ b/src/GuiQt/AnnotationPasteDialog.cxx @@ -296,8 +296,6 @@ AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* o bool windowFlag = false; switch (oneDimShape->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index c38c06575..896e03a1c 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -110,8 +110,6 @@ AnnotationRotationWidget::getValidOneDimAnnotation(Annotation* annotation) if (oneDimAnn != NULL) { bool validSpaceFlag = false; switch (oneDimAnn->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -168,8 +166,6 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValidFlag = false; switch (oneDimAnn->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index e3e601749..ddc192a50 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -94,7 +94,7 @@ m_annotationBeingDragged(NULL) m_annotationUnderMouseSizeHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; m_modeNewAnnotationFileSpaceAndType.grabNew(new NewAnnotationFileSpaceAndType(NULL, - AnnotationCoordinateSpaceEnum::PIXELS, + AnnotationCoordinateSpaceEnum::VIEWPORT, AnnotationTypeEnum::LINE)); m_newAnnotationCreatingWithMouseDrag.grabNew(NULL); @@ -407,8 +407,6 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) case AnnotationCoordinateSpaceEnum::STEREOTAXIC: changeCoordFlag = true; break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: @@ -469,8 +467,6 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) switch (selectedAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; @@ -589,7 +585,7 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) break; } - AnnotationCoordinateSpaceEnum::Enum draggingCoordinateSpace = AnnotationCoordinateSpaceEnum::PIXELS; + AnnotationCoordinateSpaceEnum::Enum draggingCoordinateSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); const int32_t numSelectedAnnotations = static_cast(selectedAnnotations.size()); @@ -651,16 +647,6 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) spaceHeight = montVP[3]; } break; - case AnnotationCoordinateSpaceEnum::PIXELS: - { - int viewport[4]; - vpContent->getWindowViewport(viewport); - spaceOriginX = viewport[0]; - spaceOriginY = viewport[1]; - spaceWidth = viewport[2]; - spaceHeight = viewport[3]; - } - break; case AnnotationCoordinateSpaceEnum::SURFACE: { /* diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 8b6b1d72f..41fbc02ac 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -105,8 +105,6 @@ m_newAnnotationCreatedByContextMenu(NULL) bool stereoOrSurfaceSpaceFlag = false; switch (ann->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::PIXELS: - break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereoOrSurfaceSpaceFlag = true; break; -- GitLab From 030909619894fd28326c5a11ca3c99513819a201 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 16:21:21 -0500 Subject: [PATCH 278/755] Updated annotation toolbar to disable editing of some attributes for an annotation graphics label. --- src/Annotations/AnnotationColorBar.cxx | 9 ++++++ src/Annotations/AnnotationColorBar.h | 2 ++ .../AnnotationFontAttributesInterface.h | 2 ++ src/Annotations/AnnotationGraphicsLabel.cxx | 20 +++++++++++++ src/Annotations/AnnotationGraphicsLabel.h | 4 +++ src/Annotations/AnnotationText.cxx | 9 ++++++ src/Annotations/AnnotationText.h | 2 ++ src/GuiQt/AnnotationColorWidget.cxx | 7 ++++- src/GuiQt/AnnotationFontWidget.cxx | 5 ++++ src/GuiQt/AnnotationTextAlignmentWidget.cxx | 30 ++++++++++++------- src/GuiQt/AnnotationTextAlignmentWidget.h | 2 +- src/GuiQt/AnnotationTextEditorWidget.cxx | 2 +- src/GuiQt/AnnotationTextOrientationWidget.cxx | 24 ++++++++++----- src/GuiQt/AnnotationTextOrientationWidget.h | 2 +- src/GuiQt/AnnotationWidthHeightWidget.cxx | 9 +++++- 15 files changed, 106 insertions(+), 23 deletions(-) diff --git a/src/Annotations/AnnotationColorBar.cxx b/src/Annotations/AnnotationColorBar.cxx index 34384c63b..12e5c36c6 100644 --- a/src/Annotations/AnnotationColorBar.cxx +++ b/src/Annotations/AnnotationColorBar.cxx @@ -226,6 +226,15 @@ AnnotationColorBar::setFontPercentViewportSize(const float fontPercentViewportHe } } +/** + * @return True if the font color is editable in the GUI. + */ +bool +AnnotationColorBar::isFontColorGuiEditable() const +{ + return true; +} + /** * Are font styles (Bold, Italic, Underline) supported? */ diff --git a/src/Annotations/AnnotationColorBar.h b/src/Annotations/AnnotationColorBar.h index addde99e2..58b9dd48d 100644 --- a/src/Annotations/AnnotationColorBar.h +++ b/src/Annotations/AnnotationColorBar.h @@ -74,6 +74,8 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]); + virtual bool isFontColorGuiEditable() const; + virtual bool isStylesSupported() const; virtual bool isBoldStyleEnabled() const; diff --git a/src/Annotations/AnnotationFontAttributesInterface.h b/src/Annotations/AnnotationFontAttributesInterface.h index e804e84f1..09097122f 100644 --- a/src/Annotations/AnnotationFontAttributesInterface.h +++ b/src/Annotations/AnnotationFontAttributesInterface.h @@ -60,6 +60,8 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]) = 0; + virtual bool isFontColorGuiEditable() const = 0; + virtual bool isStylesSupported() const = 0; virtual bool isBoldStyleEnabled() const = 0; diff --git a/src/Annotations/AnnotationGraphicsLabel.cxx b/src/Annotations/AnnotationGraphicsLabel.cxx index 1d399a65e..d994b8f03 100644 --- a/src/Annotations/AnnotationGraphicsLabel.cxx +++ b/src/Annotations/AnnotationGraphicsLabel.cxx @@ -91,6 +91,26 @@ AnnotationGraphicsLabel::operator=(const AnnotationGraphicsLabel& obj) return *this; } +/** + * @return Is this annotation deletable? This method may be overridden + * by annotations (such as colorbars) that cannot be deleted. + */ +bool +AnnotationGraphicsLabel::isDeletable() const +{ + return false; +} + +/** + * @return True if the font color is editable in the GUI. + */ +bool +AnnotationGraphicsLabel::isFontColorGuiEditable() const +{ + return false; +} + + /** * Helps with copying an object of this type. * @param obj diff --git a/src/Annotations/AnnotationGraphicsLabel.h b/src/Annotations/AnnotationGraphicsLabel.h index b9a315f0e..470baef66 100644 --- a/src/Annotations/AnnotationGraphicsLabel.h +++ b/src/Annotations/AnnotationGraphicsLabel.h @@ -40,6 +40,10 @@ namespace caret { AnnotationGraphicsLabel& operator=(const AnnotationGraphicsLabel& obj); + virtual bool isDeletable() const; + + virtual bool isFontColorGuiEditable() const; + // void setAxisViewport(const int32_t axisViewport[4]); // // void getAxisViewport(int32_t axisViewportOut[4]) const; diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index afbd6a321..437a17934 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -686,6 +686,15 @@ AnnotationText::setCustomTextColor(const uint8_t rgba[4]) } } +/** + * @return True if the font color is editable in the GUI. + */ +bool +AnnotationText::isFontColorGuiEditable() const +{ + return true; +} + /** * Are font styles (Bold, Italic, Underline) supported? */ diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index 339d01305..c4b5a45ab 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -90,6 +90,8 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]); + virtual bool isFontColorGuiEditable() const; + virtual bool isStylesSupported() const; virtual bool isBoldStyleEnabled() const; diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 1f5f7af0f..9f75e6300 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -224,7 +224,12 @@ AnnotationColorWidget::~AnnotationColorWidget() void AnnotationColorWidget::updateContent(std::vector& annotations) { - m_annotations = annotations; + m_annotations.clear(); + for (auto a : annotations) { + if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { + m_annotations.push_back(a); + } + } if ( ! m_annotations.empty()) { setEnabled(true); diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index a09008631..541f32397 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -498,6 +498,10 @@ AnnotationFontWidget::updateTextColorButton() bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { + if ( ! m_annotationsFontStyle[i]->isFontColorGuiEditable()) { + continue; + } + if (firstColorSupportFlag) { m_annotationsFontStyle[i]->getTextColorRGBA(rgba); firstColorSupportFlag = false; @@ -551,6 +555,7 @@ AnnotationFontWidget::updateTextColorButton() m_textColorAction->setIcon(QIcon(pm)); m_textColorMenu->setSelectedColor(colorEnum); + m_textColorToolButton->setEnabled(colorButtonValidFlag); if (colorButtonValidFlag) { } diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.cxx b/src/GuiQt/AnnotationTextAlignmentWidget.cxx index 32e7ce5cc..37d03a563 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.cxx +++ b/src/GuiQt/AnnotationTextAlignmentWidget.cxx @@ -159,10 +159,16 @@ AnnotationTextAlignmentWidget::~AnnotationTextAlignmentWidget() void AnnotationTextAlignmentWidget::updateContent(std::vector& annotationTexts) { +// m_annotations.clear(); +// m_annotations.insert(m_annotations.end(), +// annotationTexts.begin(), +// annotationTexts.end()); m_annotations.clear(); - m_annotations.insert(m_annotations.end(), - annotationTexts.begin(), - annotationTexts.end()); + for (auto a : annotationTexts) { + if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { + m_annotations.push_back(a); + } + } { /* @@ -174,8 +180,8 @@ AnnotationTextAlignmentWidget::updateContent(std::vector& annot * If multiple annotations are selected, the may have different alignments. */ std::set selectedAlignments; - for (std::vector::iterator iter = annotationTexts.begin(); - iter != annotationTexts.end(); + for (std::vector::iterator iter = m_annotations.begin(); + iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); @@ -230,8 +236,8 @@ AnnotationTextAlignmentWidget::updateContent(std::vector& annot * If multiple annotations are selected, the may have different alignments. */ std::set selectedAlignments; - for (std::vector::iterator iter = annotationTexts.begin(); - iter != annotationTexts.end(); + for (std::vector::iterator iter = m_annotations.begin(); + iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); @@ -277,7 +283,7 @@ AnnotationTextAlignmentWidget::updateContent(std::vector& annot m_verticalAlignActionGroup->blockSignals(false); } - setEnabled( ! annotationTexts.empty()); + setEnabled( ! m_annotations.empty()); } /** @@ -296,8 +302,10 @@ AnnotationTextAlignmentWidget::horizontalAlignmentActionSelected(QAction* action &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + std::vector annotations(m_annotations.begin(), + m_annotations.end()); undoCommand->setModeTextAlignmentHorizontal(actionAlign, - m_annotations); + annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, @@ -328,8 +336,10 @@ AnnotationTextAlignmentWidget::verticalAlignmentActionSelected(QAction* action) &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + std::vector annotations(m_annotations.begin(), + m_annotations.end()); undoCommand->setModeTextAlignmentVertical(actionAlign, - m_annotations); + annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.h b/src/GuiQt/AnnotationTextAlignmentWidget.h index 60d9377fb..71d618987 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.h +++ b/src/GuiQt/AnnotationTextAlignmentWidget.h @@ -76,7 +76,7 @@ namespace caret { QActionGroup* m_verticalAlignActionGroup; - std::vector m_annotations; + std::vector m_annotations; bool m_smallLayoutFlag; diff --git a/src/GuiQt/AnnotationTextEditorWidget.cxx b/src/GuiQt/AnnotationTextEditorWidget.cxx index aa8c00018..3c85969a0 100644 --- a/src/GuiQt/AnnotationTextEditorWidget.cxx +++ b/src/GuiQt/AnnotationTextEditorWidget.cxx @@ -122,9 +122,9 @@ AnnotationTextEditorWidget::updateContent(std::vector& annotati QString text; + m_annotationTextConnectTypeEnumComboBox->getComboBox()->setEnabled(false); if (m_annotationText != NULL) { setEnabled(true); - if (m_annotationText->isConnectToBrainordinateValid()) { m_annotationTextConnectTypeEnumComboBox->getComboBox()->setEnabled(true); } diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index 70012bdd3..0da7b5ea9 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -97,12 +97,18 @@ AnnotationTextOrientationWidget::~AnnotationTextOrientationWidget() * @param annotation. */ void -AnnotationTextOrientationWidget::updateContent(std::vector& annotationTexts) +AnnotationTextOrientationWidget::updateContent(std::vector& annotationTextsIn) { +// m_annotations.clear(); +// m_annotations.insert(m_annotations.end(), +// annotationTexts.begin(), +// annotationTexts.end()); m_annotations.clear(); - m_annotations.insert(m_annotations.end(), - annotationTexts.begin(), - annotationTexts.end()); + for (auto a : annotationTextsIn) { + if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { + m_annotations.push_back(a); + } + } { /* @@ -114,8 +120,8 @@ AnnotationTextOrientationWidget::updateContent(std::vector& ann * If multiple annotations are selected, the may have different orientation. */ std::set selectedOrientations; - for (std::vector::iterator iter = annotationTexts.begin(); - iter != annotationTexts.end(); + for (std::vector::iterator iter = m_annotations.begin(); + iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); @@ -161,7 +167,7 @@ AnnotationTextOrientationWidget::updateContent(std::vector& ann m_orientationActionGroup->blockSignals(false); } - setEnabled( ! annotationTexts.empty()); + setEnabled( ! m_annotations.empty()); } /** @@ -180,8 +186,10 @@ AnnotationTextOrientationWidget::orientationActionSelected(QAction* action) &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + std::vector annotations(m_annotations.begin(), + m_annotations.end()); undoCommand->setModeTextOrientation(actionOrientation, - m_annotations); + annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, diff --git a/src/GuiQt/AnnotationTextOrientationWidget.h b/src/GuiQt/AnnotationTextOrientationWidget.h index 8c674257c..12be1d04b 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.h +++ b/src/GuiQt/AnnotationTextOrientationWidget.h @@ -64,7 +64,7 @@ namespace caret { const int32_t m_browserWindowIndex; - std::vector m_annotations; + std::vector m_annotations; QActionGroup* m_orientationActionGroup; diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index ac8ad91b0..78a6e624c 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -119,7 +119,14 @@ AnnotationWidthHeightWidget::~AnnotationWidthHeightWidget() void AnnotationWidthHeightWidget::updateContent(std::vector& annotations2D) { - m_annotations2D = annotations2D; +// m_annotations2D = annotations2D; + m_annotations2D.clear(); + for (auto a : annotations2D) { + if ((a->getType() != AnnotationTypeEnum::COLOR_BAR) + && (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL)) { + m_annotations2D.push_back(a); + } + } if ( ! m_annotations2D.empty()) { float widthValue = 0.0; -- GitLab From 4499fafdc5ae5c88ed140c13b92e6b5e5cf0540c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 16:32:37 -0500 Subject: [PATCH 279/755] Annotations drawing was drawing background for text annotations but this code has been removed since the text renderer handles drawing the background color for text. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 533995416..f54ee3d52 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -2304,31 +2304,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi float savedFontPercentViewportHeight = -1.0; const bool modifiedStatus = text->isModified(); - const bool allowDifferentHeightModesFlag = false; - if (allowDifferentHeightModesFlag) { - switch (m_inputs->m_textHeightMode) { - case Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT: - break; - case Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT: - if (m_inputs->m_tabViewport[3] != m_modelSpaceViewport[3]) { - percentSizeText = dynamic_cast(text); - if (percentSizeText != NULL) { - savedFontPercentViewportHeight = percentSizeText->getFontPercentViewportSize(); - if (savedFontPercentViewportHeight > 0.0) { - CaretAssert(m_modelSpaceViewport[3]); - const float heightScaling = m_inputs->m_tabViewport[3] / m_modelSpaceViewport[3]; - percentSizeText->setFontPercentViewportSize(savedFontPercentViewportHeight - * heightScaling); - } - } - } - break; - } - } - m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*text, windowXYZ[0], windowXYZ[1], windowXYZ[2], - //textDrawingViewportHeight, m_modelSpaceViewport[2], m_modelSpaceViewport[3], bottomLeft, bottomRight, topRight, topLeft); @@ -2391,12 +2368,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi text->getLineWidth()); } - if (drawBackgroundFlag) { - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - backgroundRGBA); - } - if (drawTextFlag) { const bool debugFlag = false; if (debugFlag) { -- GitLab From cd6824d2a070fb17b8fcf3ef7bc4fced9ecf8483 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 6 Jun 2017 16:46:11 -0500 Subject: [PATCH 280/755] Cleanup some assertions that were added when viewport annotation coordinate space was implemented. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 2 +- src/GuiQt/AnnotationCoordinateInformation.cxx | 4 ++-- src/GuiQt/AnnotationCoordinateSelectionWidget.cxx | 10 +++++----- src/GuiQt/AnnotationCreateDialog.cxx | 4 ++-- src/GuiQt/UserInputModeAnnotations.cxx | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 26469fb30..e127219df 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -448,7 +448,7 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv } if ( ! useMipMapFlag) { - CaretAssertToDoFatal(); // image must be 2^N by 2^M + CaretAssert(0); // image must be 2^N by 2^M glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index eca4ea133..bfe23d248 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -505,7 +505,7 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowIndex >= 0) { @@ -664,7 +664,7 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowIndex >= 0) { diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index a929ac849..4fdaa19b8 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -503,7 +503,7 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno oldViewportHeight = m_coordInfo.m_tabHeight; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: oldViewportHeight = m_coordInfo.m_windowHeight; @@ -533,7 +533,7 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno diffXyzValid = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: diffXyzValid = true; @@ -588,7 +588,7 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (m_coordInfo.m_windowIndex >= 0) { @@ -771,7 +771,7 @@ AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* vpHeight = m_coordInfo.m_tabHeight; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: vpWidth = m_coordInfo.m_windowWidth; @@ -838,7 +838,7 @@ AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Ann case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: dpa->setDisplayWindowAnnotationsInSingleTabViews(annotation->getWindowIndex(), diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index d212c9d61..a03068899 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -277,7 +277,7 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; @@ -951,7 +951,7 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: { diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index ddc192a50..b8fc6e7a0 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -690,7 +690,7 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssertToDoFatal(); + CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: { -- GitLab From ff66d4b69eb09af87137eb271a8b93eddd47f879 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 7 Jun 2017 09:25:21 -0500 Subject: [PATCH 281/755] Corrections for annotation mode context (right-click) menu for use with graphics label annotations. --- src/Brain/AnnotationManager.cxx | 28 +++++++++++++++++++ src/Brain/AnnotationManager.h | 3 ++ .../UserInputModeAnnotationsContextMenu.cxx | 20 +++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 4c746c712..d0931e3ac 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -621,6 +621,34 @@ AnnotationManager::getAnnotationsSelectedForEditing(const int32_t windowIndex, } } } + +} + +/** + * Get the selected annotations for editing and the files that contain them. + * INCLUDES chart labels. + * + * @param windowIndex + * Index of window for annotation selection. + * @param annotationsAndFileOut + * A 'pair' containing a selected annotation and the file that contains the annotation. + */ +void +AnnotationManager::getAnnotationsSelectedForEditingIncludingLabels(const int32_t windowIndex, + std::vector >& annotationsAndFileOut) const +{ + getAnnotationsSelectedForEditing(windowIndex, + annotationsAndFileOut); + + EventAnnotationChartLabelGet chartLabelEvent; + EventManager::get()->sendEvent(chartLabelEvent.getPointer()); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + AnnotationFile* nullFile = NULL; + for (auto cl : chartLabels) { + if (cl->isSelectedForEditing(windowIndex)) { + annotationsAndFileOut.push_back(std::make_pair(cl, nullFile)); + } + } } /** diff --git a/src/Brain/AnnotationManager.h b/src/Brain/AnnotationManager.h index 33b4da759..7816e4048 100644 --- a/src/Brain/AnnotationManager.h +++ b/src/Brain/AnnotationManager.h @@ -103,6 +103,9 @@ namespace caret { void getAnnotationsSelectedForEditing(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const; + void getAnnotationsSelectedForEditingIncludingLabels(const int32_t windowIndex, + std::vector >& annotationsAndFileOut) const; + // std::vector getFilesContainingAnnotations(const std::vector annotations) const; bool isAnnotationOnClipboardValid() const; diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 41fbc02ac..6ec7c44b0 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -90,12 +90,14 @@ m_newAnnotationCreatedByContextMenu(NULL) const int32_t browserWindexIndex = m_mouseEvent.getBrowserWindowIndex(); std::vector > selectedAnnotations; AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); - annotationManager->getAnnotationsSelectedForEditing(browserWindexIndex, - selectedAnnotations); + annotationManager->getAnnotationsSelectedForEditingIncludingLabels(browserWindexIndex, + selectedAnnotations); m_annotationFile = NULL; m_annotation = NULL; + bool allSelectedAnnotationsDeletableFlag = true; + m_stereotaxicAndSurfaceAnnotations.clear(); for (std::vector >::iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); @@ -121,15 +123,23 @@ m_newAnnotationCreatedByContextMenu(NULL) if (stereoOrSurfaceSpaceFlag) { m_stereotaxicAndSurfaceAnnotations.push_back(ann); } + + if ( ! ann->isDeletable()) { + allSelectedAnnotationsDeletableFlag = false; + } } const bool haveStereotaxicAnnotationsFlag = ( ! m_stereotaxicAndSurfaceAnnotations.empty()); bool oneAnnotationSelectedFlag = false; + bool oneDeletableAnnotationSelectedFlag = false; if (selectedAnnotations.size() == 1) { CaretAssertVectorIndex(selectedAnnotations, 0); m_annotationFile = selectedAnnotations[0].second; m_annotation = selectedAnnotations[0].first; oneAnnotationSelectedFlag = true; + if (m_annotation->isDeletable()) { + oneDeletableAnnotationSelectedFlag = true; + } } m_textAnnotation = NULL; @@ -153,21 +163,21 @@ m_newAnnotationCreatedByContextMenu(NULL) */ QAction* cutAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::CUT), this, SLOT(cutAnnnotation())); - cutAction->setEnabled(oneAnnotationSelectedFlag); + cutAction->setEnabled(oneDeletableAnnotationSelectedFlag); /* * Copy */ QAction* copyAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::COPY), this, SLOT(copyAnnotationToAnnotationClipboard())); - copyAction->setEnabled(oneAnnotationSelectedFlag); + copyAction->setEnabled(oneDeletableAnnotationSelectedFlag); /* * Delete */ QAction* deleteAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::DELETER), this, SLOT(deleteAnnotations())); - deleteAction->setEnabled( ! selectedAnnotations.empty()); + deleteAction->setEnabled(allSelectedAnnotationsDeletableFlag); /* * Paste -- GitLab From f9972b76f21ca996b6ea04853c70e0c2a9193831 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 9 Jun 2017 17:02:01 -0500 Subject: [PATCH 282/755] Starting on line series charts. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 515 +++++++++++++++++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 18 + src/Brain/ChartTwoOverlay.cxx | 40 ++ src/Brain/ChartTwoOverlay.h | 4 + src/Brain/IdentificationTextGenerator.cxx | 16 +- src/Brain/ModelChart.cxx | 14 + src/Brain/SelectionItemChartTwoLineSeries.cxx | 45 +- src/Brain/SelectionItemChartTwoLineSeries.h | 12 + src/Charting/CMakeLists.txt | 9 +- src/Charting/ChartTwoData.cxx | 3 +- src/Charting/ChartTwoDataCartesian.cxx | 53 +- src/Charting/ChartTwoDataCartesian.h | 16 +- ...tory.cxx => ChartTwoLineSeriesHistory.cxx} | 120 ++-- ...nHistory.h => ChartTwoLineSeriesHistory.h} | 37 +- .../EventChartTwoLoadLineSeriesData.cxx | 80 +++ .../EventChartTwoLoadLineSeriesData.h | 69 +++ src/Charting/MapFileDataSelector.cxx | 375 +++++++++++++ src/Charting/MapFileDataSelector.h | 131 +++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/Files/CaretMappableDataFile.h | 4 + src/Files/ChartableTwoFileLineSeriesChart.cxx | 141 ++++- src/Files/ChartableTwoFileLineSeriesChart.h | 17 +- src/Files/CiftiFiberTrajectoryFile.cxx | 15 + src/Files/CiftiFiberTrajectoryFile.h | 4 +- src/Files/CiftiMappableDataFile.cxx | 61 ++- src/Files/CiftiMappableDataFile.h | 3 + src/Files/GiftiTypeFile.cxx | 14 + src/Files/GiftiTypeFile.h | 4 + src/Files/VolumeFile.cxx | 14 + src/Files/VolumeFile.h | 3 + src/Graphics/GraphicsEngineDataOpenGL.cxx | 19 + src/Graphics/GraphicsEngineDataOpenGL.h | 4 + src/Graphics/GraphicsPrimitiveV3f.cxx | 36 ++ src/Graphics/GraphicsPrimitiveV3f.h | 2 + .../ChartTwoOverlaySetViewController.cxx | 38 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 39 +- src/GuiQt/ChartTwoOverlayViewController.h | 4 + 39 files changed, 1870 insertions(+), 116 deletions(-) rename src/Charting/{ChartTwoDataCartesianHistory.cxx => ChartTwoLineSeriesHistory.cxx} (72%) rename src/Charting/{ChartTwoDataCartesianHistory.h => ChartTwoLineSeriesHistory.h} (75%) create mode 100644 src/Charting/EventChartTwoLoadLineSeriesData.cxx create mode 100644 src/Charting/EventChartTwoLoadLineSeriesData.h create mode 100644 src/Charting/MapFileDataSelector.cxx create mode 100644 src/Charting/MapFileDataSelector.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 6472098b1..0f5417ce6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -38,6 +38,8 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartTwoCartesianAxis.h" +#include "ChartTwoDataCartesian.h" +#include "ChartTwoLineSeriesHistory.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -253,12 +255,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (drawHistogramFlag) { - drawHistogramChart(); + drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + //drawHistogramChart(); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: if (drawLineSeriesFlag) { - + drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: @@ -623,6 +626,514 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() } } +/** + * Draw a histogram or line series chart. + * + * @param chartDataType + * Type of chart to draw. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType) +{ + bool drawHistogramFlag = false; + bool drawLineSeriesFlag = false; + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + CaretAssert(0); + return; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + drawHistogramFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + drawLineSeriesFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + CaretAssert(0); + return; + break; + } + + const int32_t vpX = m_viewport[0]; + const int32_t vpY = m_viewport[1]; + const int32_t vpWidth = m_viewport[2]; + const int32_t vpHeight = m_viewport[3]; + + int32_t chartGraphicsDrawingViewport[4] = { + vpX, + vpY, + vpWidth, + vpHeight + }; + + const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); + CaretAssert(numberOfOverlays > 0); + const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); + const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); + if (drawHistogramFlag) { + CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + } + else if (drawLineSeriesFlag) { + CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); + } + else { + CaretAssert(0); + } + + std::vector> histogramDrawingInfo; + std::vector lineSeriesChartsToDraw; + + /* + * Get the histogram drawing information and overall extent + */ + float xMin = std::numeric_limits::max(); + float xMax = -std::numeric_limits::max(); + float yMinLeft = std::numeric_limits::max(); + float yMaxLeft = -std::numeric_limits::max(); + float yMinRight = std::numeric_limits::max(); + float yMaxRight = -std::numeric_limits::max(); + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { + ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); + if ( ! chartOverlay->isEnabled()) { + continue; + } + + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + chartOverlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + if (mapFile == NULL) { + continue; + } + + ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + + if (drawHistogramFlag) { + ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + + if (histogramChart->isValid()) { + CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); + AString errorMessage; + histogramDrawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, + selectedIndex, + chartOverlay->getCartesianVerticalAxisLocation(), + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())))); + const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())); + CaretAssert(histogram); + float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; + histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); + if (histogramMaxX > histogramMinX) { + xMin = std::min(xMin, histogramMinX); + xMax = std::max(xMax, histogramMaxX); + + switch (chartOverlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yMinRight = std::min(yMinRight, 0.0f); + yMaxRight = std::max(yMaxRight, histogramMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + yMinLeft = std::min(yMinLeft, 0.0f); + yMaxLeft = std::max(yMaxLeft, histogramMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); + break; + } + } + } + } + + if (drawLineSeriesFlag) { + const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); + const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); + const int32_t numHistory = lineSeriesHistory->getHistoryCount(); + for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { + const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); + CaretAssert(data); + float boundsMinX = 0.0f; + float boundsMaxX = 0.0f; + float boundsMinY = 0.0f; + float boundsMaxY = 0.0f; + data->getBounds(boundsMinX, boundsMaxX, boundsMinY, boundsMaxY); + if (boundsMaxX > boundsMinX) { + xMin = std::min(xMin, boundsMinX); + xMax = std::max(xMax, boundsMaxX); + + switch (chartOverlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yMinRight = std::min(yMinRight, boundsMinY); + yMaxRight = std::max(yMaxRight, boundsMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + yMinLeft = std::min(yMinLeft, boundsMinY); + yMaxLeft = std::max(yMaxLeft, boundsMaxY); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); + break; + } + + lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, + data, + chartOverlay->getCartesianVerticalAxisLocation())); + } + } + } + } + + /* + * Bounds valid? + */ + if ((xMin < xMax) + && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { + /* + * Margin is region around the chart in which + * the axes legends, values, and ticks are drawn. + */ + const double marginSize = 10; + Margins margins(marginSize); + + ChartTwoCartesianAxis* leftAxis = NULL; + ChartTwoCartesianAxis* rightAxis = NULL; + ChartTwoCartesianAxis* bottomAxis = NULL; + ChartTwoCartesianAxis* topAxis = NULL; + + std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); + for (auto axis : displayedAxes) { + CaretAssert(axis); + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + bottomAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + leftAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + rightAxis = axis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + topAxis = axis; + break; + } + } + + const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; + const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; + double width = 0.0, height = 0.0; + + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); + margins.m_left = std::max(margins.m_left, width); + estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); + margins.m_right = std::max(margins.m_right, width); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); + margins.m_top = std::max(margins.m_top, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); + margins.m_bottom = std::max(margins.m_bottom, height); + + if (margins.m_left > marginSize) margins.m_left += 10; + if (margins.m_right > marginSize) margins.m_right += 10; + + /* + * Ensure that there is sufficient space for the axes data display. + */ + if ((vpWidth > (marginSize * 3)) + && (vpHeight > (marginSize * 3))) { + + float axisMinimumValue = 0.0; + float axisMaximumValue = 0.0; + + /* Draw legends and grids */ + if (drawChartAxisCartesian(boundsLeftBottomTop, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + leftAxis, + axisMinimumValue, + axisMaximumValue)) { + yMinLeft = axisMinimumValue; + yMaxLeft = axisMaximumValue; + } + + if (drawChartAxisCartesian(boundsRight, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + rightAxis, + axisMinimumValue, + axisMaximumValue)) { + yMinRight = axisMinimumValue; + yMaxRight = axisMaximumValue; + } + if (drawChartAxisCartesian(boundsLeftBottomTop, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + bottomAxis, + axisMinimumValue, + axisMaximumValue)) { + xMin = axisMinimumValue; + xMax = axisMaximumValue; + } + + drawChartAxisCartesian(boundsLeftBottomTop, + vpX, + vpY, + vpWidth, + vpHeight, + margins, + topAxis, + axisMinimumValue, + axisMaximumValue); + + drawChartGraphicsBoxAndSetViewport(vpX, + vpY, + vpWidth, + vpHeight, + margins, + chartGraphicsDrawingViewport); + } + + glViewport(chartGraphicsDrawingViewport[0], + chartGraphicsDrawingViewport[1], + chartGraphicsDrawingViewport[2], + chartGraphicsDrawingViewport[3]); + + + if (drawHistogramFlag) { + /* + * Draw the bars for all histogram and then draw the envelopes + * so the envelopes are not obscured by the bars + */ + for (auto& drawInfo : histogramDrawingInfo) { + if (drawInfo->m_histogramChart->isValid()) { + const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); + CaretAssert(cmdf); + const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); + const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); + const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); + + if (drawBarsFlag + || drawEnvelopeFlag) { + bool leftVerticalAxisFlag = true; + switch (drawInfo->m_verticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + leftVerticalAxisFlag = false; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (leftVerticalAxisFlag) { + glOrtho(xMin, xMax, + yMinLeft, yMaxLeft, + -10.0, 10.0); + } + else { + glOrtho(xMin, xMax, + yMinRight, yMaxRight, + -10.0, 10.0); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = false; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = + drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, + drawInfo->m_allMapsSelected); + if (histogramPrimitives != NULL) { + const float ENVELOPE_LINE_WIDTH = 1.0; + + if (m_identificationModeFlag) { + int32_t primitiveIndex = -1; + float primitiveDepth = 0.0; + + if (drawBarsFlag) { + /* + * Scale histogram bars in Y-axis so that identification + * will function when mouse is above a bar. This is helpful + * for identification of bars with a very small height. + */ + glPushMatrix(); + glScalef(1.0, 1000.0, 1.0); + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + histogramPrimitives->getBarsPrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + glPopMatrix(); + } + else if (drawEnvelopeFlag) { + /* + * Increase line width for identification + */ + glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + histogramPrimitives->getEnvelopePrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + } + + if (primitiveIndex >= 0) { + if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { + m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), + drawInfo->m_mapIndex, + primitiveIndex, + drawInfo->m_allMapsSelected); + } + } + } + else { + drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); + if (drawBarsFlag) { + drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); + } + if (drawEnvelopeFlag) { + glLineWidth(ENVELOPE_LINE_WIDTH); + m_fixedPipelineDrawing->enableLineAntiAliasing(); + drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); + m_fixedPipelineDrawing->disableLineAntiAliasing(); + } + } + } + } + } + } + } + if (drawLineSeriesFlag) { + for (const auto lineChart : lineSeriesChartsToDraw) { + bool leftVerticalAxisFlag = true; + switch (lineChart.m_verticalAxisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + leftVerticalAxisFlag = false; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + break; + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (leftVerticalAxisFlag) { + glOrtho(xMin, xMax, + yMinLeft, yMaxLeft, + -10.0, 10.0); + } + else { + glOrtho(xMin, xMax, + yMinRight, yMaxRight, + -10.0, 10.0); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + bool applyTransformationsFlag = false; + if (applyTransformationsFlag) { + glTranslatef(m_translation[0], + m_translation[1], + 0.0); + + const float chartWidth = chartGraphicsDrawingViewport[2]; + const float chartHeight = chartGraphicsDrawingViewport[3]; + const float halfWidth = chartWidth / 2.0; + const float halfHeight = chartHeight / 2.0; + glTranslatef(halfWidth, + halfHeight, + 0.0); + glScalef(m_zooming, + m_zooming, + 1.0); + glTranslatef(-halfWidth, + -halfHeight, + 0.0); + } + + const float LINE_SERIES_LINE_WIDTH = 1.0f; + if (m_identificationModeFlag) { + int32_t primitiveIndex = -1; + float primitiveDepth = 0.0; + + glLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); + GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + primitiveIndex, + primitiveDepth); + + if (primitiveIndex >= 0) { + if (m_selectionItemLineSeries->isOtherScreenDepthCloserToViewer(primitiveDepth)) { + m_selectionItemLineSeries->setLineSeriesChart(const_cast(lineChart.m_lineSeriesChart), + primitiveIndex); + } + } + } + else { + /* + * Note: do anti-aliasing here since it will mess up drawing when identifying + */ + m_fixedPipelineDrawing->enableLineAntiAliasing(); + glLineWidth(LINE_SERIES_LINE_WIDTH); + GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); + m_fixedPipelineDrawing->disableLineAntiAliasing(); + } + } + } + } +} + + /** * Draw a matrix chart. */ diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index d52c33135..559c6125e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -25,12 +25,14 @@ #include "BrainOpenGLChartTwoDrawingInterface.h" #include "CaretColorEnum.h" #include "ChartAxisLocationEnum.h" +#include "ChartTwoDataTypeEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" namespace caret { class CaretPreferences; class ChartTwoCartesianAxis; + class ChartTwoDataCartesian; class ChartTwoOverlaySet; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; @@ -74,6 +76,20 @@ namespace caret { ~HistogramChartDrawingInfo(); }; + class LineSeriesChartDrawingInfo { + public: + LineSeriesChartDrawingInfo(const ChartableTwoFileLineSeriesChart* lineSeriesChart, + const ChartTwoDataCartesian* chartTwoCartesianData, + const ChartAxisLocationEnum::Enum verticalAxisLocation) + : m_lineSeriesChart(lineSeriesChart), + m_chartTwoCartesianData(chartTwoCartesianData), + m_verticalAxisLocation(verticalAxisLocation) { } + + const ChartableTwoFileLineSeriesChart* m_lineSeriesChart; + const ChartTwoDataCartesian* m_chartTwoCartesianData; + const ChartAxisLocationEnum::Enum m_verticalAxisLocation; + }; + class Margins { public: Margins(const double defaultSize) { @@ -117,6 +133,8 @@ namespace caret { void drawHistogramChart(); + void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); + void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 95ea31950..a31dcadc4 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -31,6 +31,7 @@ #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" +#include "ChartTwoLineSeriesHistory.h" #include "ChartTwoOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventChartOverlayValidate.h" @@ -256,6 +257,45 @@ ChartTwoOverlay::setEnabled(const bool enabled) m_enabled = enabled; } +/** + * @return line-series loading enabled + */ +bool +ChartTwoOverlay::isLineSeriesLoadingEnabled() const +{ + CaretMappableDataFile* mapFile = NULL; + SelectedIndexType indexType = SelectedIndexType::INVALID; + int32_t mapIndex = -1; + getSelectionData(mapFile, + indexType, + mapIndex); + + const ChartableTwoFileLineSeriesChart* lineSeriesChart = mapFile->getChartingDelegate()->getLineSeriesCharting(); + const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); + return lineSeriesHistory->isLoadingEnabled(); +} + +/** + * Set line-series loading enabled + * + * @param lineSeriesLoadingEnabled + * New value for line-series loading enabled + */ +void +ChartTwoOverlay::setLineSeriesLoadingEnabled(const bool lineSeriesLoadingEnabled) +{ + CaretMappableDataFile* mapFile = NULL; + SelectedIndexType indexType = SelectedIndexType::INVALID; + int32_t mapIndex = -1; + getSelectionData(mapFile, + indexType, + mapIndex); + + ChartableTwoFileLineSeriesChart* lineSeriesChart = mapFile->getChartingDelegate()->getLineSeriesCharting(); + ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); + lineSeriesHistory->setLoadingEnabled(lineSeriesLoadingEnabled); +} + /** * Copy the data from the given overlay to this overlay. * @param overlay diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index f90eefb2f..e848d2a14 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -71,6 +71,10 @@ namespace caret { void setEnabled(const bool enabled); + bool isLineSeriesLoadingEnabled() const; + + void setLineSeriesLoadingEnabled(const bool lineSeriesLoadingEnabled); + void copyData(const ChartTwoOverlay* overlay); void swapData(ChartTwoOverlay* overlay); diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 441069c6e..33015ad64 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -856,7 +856,21 @@ IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(Identi const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const { if (idChartTwoLineSeries->isValid()) { - CaretAssertToDoWarning(); + ChartableTwoFileLineSeriesChart* fileLineSeriesChart = idChartTwoLineSeries->getFileLineSeriesChart(); + CaretAssert(fileLineSeriesChart); + CaretMappableDataFile* mapFile = fileLineSeriesChart->getCaretMappableDataFile(); + CaretAssert(mapFile); + + const int32_t primitiveIndex = idChartTwoLineSeries->getLineSegmentIndex(); + + AString boldText("Line Chart"); + idText.addLine(false, + boldText, + mapFile->getFileNameNoPath()); + + idText.addLine(true, + "Line Segment Index", + (AString::number(primitiveIndex))); } } diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 94167bd7d..56f3e2a9a 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -43,7 +43,9 @@ #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGetAll.h" +#include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" +#include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "ModelChart.h" @@ -583,6 +585,18 @@ ModelChart::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, chartData); } } + + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setSurfaceVertex(structure, + surfaceNumberOfNodes, + nodeIndex); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** diff --git a/src/Brain/SelectionItemChartTwoLineSeries.cxx b/src/Brain/SelectionItemChartTwoLineSeries.cxx index 9c79c1a73..1a352b14c 100644 --- a/src/Brain/SelectionItemChartTwoLineSeries.cxx +++ b/src/Brain/SelectionItemChartTwoLineSeries.cxx @@ -40,7 +40,8 @@ using namespace caret; SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LINE_SERIES) { - + m_fileLineSeriesChart = NULL; + m_lineSegmentIndex = -1; } /** @@ -78,6 +79,40 @@ SelectionItemChartTwoLineSeries::operator=(const SelectionItemChartTwoLineSeries return *this; } +/** + * @return The File line series chart. + */ +ChartableTwoFileLineSeriesChart* +SelectionItemChartTwoLineSeries::getFileLineSeriesChart() const +{ + return m_fileLineSeriesChart; +} + +/** + * @return The line segment index. + */ +int32_t +SelectionItemChartTwoLineSeries::getLineSegmentIndex() const +{ + return m_lineSegmentIndex; +} + +/** + * Set selection. + * + * @param fileLineSeriesChart + * The line series chart. + * @param lineSegmentIndex + * Index of the line segment. + */ +void +SelectionItemChartTwoLineSeries::setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, + const int32_t lineSegmentIndex) +{ + m_fileLineSeriesChart = fileLineSeriesChart; + m_lineSegmentIndex = lineSegmentIndex; +} + /** * Helps with copying an object of this type. * @param obj @@ -86,7 +121,8 @@ SelectionItemChartTwoLineSeries::operator=(const SelectionItemChartTwoLineSeries void SelectionItemChartTwoLineSeries::copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) { - + m_fileLineSeriesChart = obj.m_fileLineSeriesChart; + m_lineSegmentIndex = obj.m_lineSegmentIndex; } /** @@ -95,7 +131,8 @@ SelectionItemChartTwoLineSeries::copyHelperSelectionItemChartTwoLineSeries(const bool SelectionItemChartTwoLineSeries::isValid() const { - return false; + return ((m_fileLineSeriesChart != NULL) + && (m_lineSegmentIndex >= 0)); } /** @@ -104,5 +141,7 @@ SelectionItemChartTwoLineSeries::isValid() const void SelectionItemChartTwoLineSeries::reset() { + m_fileLineSeriesChart = NULL; + m_lineSegmentIndex = -1; } diff --git a/src/Brain/SelectionItemChartTwoLineSeries.h b/src/Brain/SelectionItemChartTwoLineSeries.h index cf3799e8d..f93a88246 100644 --- a/src/Brain/SelectionItemChartTwoLineSeries.h +++ b/src/Brain/SelectionItemChartTwoLineSeries.h @@ -28,6 +28,8 @@ namespace caret { + class ChartableTwoFileLineSeriesChart; + class SelectionItemChartTwoLineSeries : public SelectionItem { public: @@ -43,12 +45,22 @@ namespace caret { virtual void reset() override; + ChartableTwoFileLineSeriesChart* getFileLineSeriesChart() const; + + int32_t getLineSegmentIndex() const; + + void setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, + const int32_t lineSegmentIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj); + ChartableTwoFileLineSeriesChart* m_fileLineSeriesChart; + + int32_t m_lineSegmentIndex; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index ec85bed1b..7d486aa9a 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -43,7 +43,6 @@ ChartTwoCartesianAxis.h ChartTwoCompoundDataType.h ChartTwoData.h ChartTwoDataCartesian.h -ChartTwoDataCartesianHistory.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h @@ -52,6 +51,9 @@ ChartTwoMatrixDisplayProperties.h ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h ChartTwoNumericSubdivisionsModeEnum.h +ChartTwoLineSeriesHistory.h +EventChartTwoLoadLineSeriesData.h +MapFileDataSelector.h ChartTwoAxisScaleRangeModeEnum.cxx ChartAxis.cxx @@ -81,7 +83,6 @@ ChartTwoCartesianAxis.cxx ChartTwoCompoundDataType.cxx ChartTwoData.cxx ChartTwoDataCartesian.cxx -ChartTwoDataCartesianHistory.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx @@ -90,6 +91,9 @@ ChartTwoMatrixDisplayProperties.cxx ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx ChartTwoNumericSubdivisionsModeEnum.cxx +ChartTwoLineSeriesHistory.cxx +EventChartTwoLoadLineSeriesData.cxx +MapFileDataSelector.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) @@ -101,6 +105,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Common +${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Scenes ) diff --git a/src/Charting/ChartTwoData.cxx b/src/Charting/ChartTwoData.cxx index 3194b78c7..0c2042aa9 100644 --- a/src/Charting/ChartTwoData.cxx +++ b/src/Charting/ChartTwoData.cxx @@ -160,7 +160,8 @@ ChartTwoData::newChartTwoDataForChartTwoDataType(const ChartTwoDataTypeEnum::Enu case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: chartData = new ChartTwoDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + GraphicsPrimitive::PrimitiveType::LINES); break; } diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 3fb943631..ff24e815b 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -29,6 +29,7 @@ #include "CaretAssert.h" #include "ChartPoint.h" +#include "GraphicsPrimitiveV3f.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -51,13 +52,17 @@ using namespace caret; * Data units for X-axis. * @param dataAxisUnitsY * Data units for Y-axis. + * @param graphicsPrimitiveType + * Primitive type for graphics primitive drawing. */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum dataAxisUnitsX, - const ChartAxisUnitsEnum::Enum dataAxisUnitsY) + const ChartAxisUnitsEnum::Enum dataAxisUnitsX, + const ChartAxisUnitsEnum::Enum dataAxisUnitsY, + const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType) : ChartTwoData(chartDataType), m_dataAxisUnitsX(dataAxisUnitsX), -m_dataAxisUnitsY(dataAxisUnitsY) +m_dataAxisUnitsY(dataAxisUnitsY), +m_graphicsPrimitiveType(graphicsPrimitiveType) { initializeMembersChartTwoDataCartesian(); @@ -66,6 +71,7 @@ m_dataAxisUnitsY(dataAxisUnitsY) CaretAssert(0); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + CaretAssert(0); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; @@ -96,6 +102,8 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; + m_graphicsPrimitive = createGraphicsPrimitive(); + std::vector colorEnums; CaretColorEnum::getColorEnums(colorEnums); const int32_t numCaretColors = static_cast(colorEnums.size()); @@ -133,12 +141,30 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() &m_timeStepInSecondsAxisX); } +/** + * @return A new instance of the graphics primitive. + */ +std::unique_ptr +ChartTwoDataCartesian::createGraphicsPrimitive() +{ + float rgba[4]; + CaretColorEnum::toRGBAFloat(m_color, rgba); + + /* + * Note: LINES (line segments) are used so that individual segments can be identified. + * Cannot use line strip since it is identified as a single item. + */ + return std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(m_graphicsPrimitiveType, + rgba)); +} /** * Remove all points in the model. */ void ChartTwoDataCartesian::removeAllPoints() { + m_graphicsPrimitive = createGraphicsPrimitive(); + for (std::vector::const_iterator iter = m_points.begin(); iter != m_points.end(); iter++) { @@ -173,7 +199,8 @@ ChartTwoDataCartesian::clone() const ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataCartesian& obj) : ChartTwoData(obj), m_dataAxisUnitsX(obj.m_dataAxisUnitsX), -m_dataAxisUnitsY(obj.m_dataAxisUnitsY) +m_dataAxisUnitsY(obj.m_dataAxisUnitsY), +m_graphicsPrimitiveType(obj.m_graphicsPrimitiveType) { initializeMembersChartTwoDataCartesian(); this->copyHelperChartTwoDataCartesian(obj); @@ -217,12 +244,23 @@ ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesi m_points.push_back(new ChartPoint(*cp)); } + m_boundsValid = false; m_color = obj.m_color; m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; } +/** + * @return Graphics primitive for drawing cartesian data. + */ +GraphicsPrimitiveV3f* +ChartTwoDataCartesian::getGraphicsPrimitive() const +{ + return m_graphicsPrimitive.get(); +} + + /** * Add a point. * @@ -235,6 +273,7 @@ void ChartTwoDataCartesian::addPoint(const float x, const float y) { + m_graphicsPrimitive->addVertex(x, y); m_points.push_back(new ChartPoint(x, y)); m_boundsValid = false; } @@ -404,6 +443,12 @@ void ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) { m_color = color; + + if (m_graphicsPrimitive != NULL) { + float rgba[4]; + CaretColorEnum::toRGBAFloat(m_color, rgba); + m_graphicsPrimitive->replaceColoring(rgba); + } } /** diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index c891c9a53..5cc706025 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -24,19 +24,21 @@ #include "CaretColorEnum.h" #include "ChartAxisUnitsEnum.h" #include "ChartTwoData.h" - +#include "GraphicsPrimitive.h" namespace caret { class ChartPoint; + class GraphicsPrimitiveV3f; class ChartTwoDataCartesian : public ChartTwoData { public: ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum dataAxisUnitsX, - const ChartAxisUnitsEnum::Enum dataAxisUnitsY); + const ChartAxisUnitsEnum::Enum dataAxisUnitsX, + const ChartAxisUnitsEnum::Enum dataAxisUnitsY, + const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType); virtual ~ChartTwoDataCartesian(); @@ -54,6 +56,8 @@ namespace caret { float& yMinimumOut, float& yMaximumOut) const; + GraphicsPrimitiveV3f* getGraphicsPrimitive() const; + ChartAxisUnitsEnum::Enum getDataAxisUnitsX(); ChartAxisUnitsEnum::Enum getDataAxisUnitsY(); @@ -91,8 +95,12 @@ namespace caret { void removeAllPoints(); + std::unique_ptr createGraphicsPrimitive(); + std::vector m_points; + std::unique_ptr m_graphicsPrimitive; + mutable float m_bounds[6]; mutable bool m_boundsValid; @@ -101,6 +109,8 @@ namespace caret { ChartAxisUnitsEnum::Enum m_dataAxisUnitsY; + const GraphicsPrimitive::PrimitiveType m_graphicsPrimitiveType; + CaretColorEnum::Enum m_color; float m_timeStartInSecondsAxisX; diff --git a/src/Charting/ChartTwoDataCartesianHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx similarity index 72% rename from src/Charting/ChartTwoDataCartesianHistory.cxx rename to src/Charting/ChartTwoLineSeriesHistory.cxx index b8f3eb1a8..1c45fabcc 100644 --- a/src/Charting/ChartTwoDataCartesianHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ -#include "ChartTwoDataCartesianHistory.h" -#undef __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ +#define __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ +#include "ChartTwoLineSeriesHistory.h" +#undef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ #include "CaretAssert.h" #include "ChartTwoDataCartesian.h" @@ -34,15 +34,15 @@ using namespace caret; /** - * \class caret::ChartTwoDataCartesianHistory - * \brief Contains history of Cartesian Charts + * \class caret::ChartTwoLineSeriesHistory + * \brief Contains history of line series chart for a tab. * \ingroup Charting */ /** * Constructor. */ -ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory() +ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory() : CaretObjectTracksModification(), SceneableInterface() { @@ -52,7 +52,7 @@ SceneableInterface() /** * Destructor. */ -ChartTwoDataCartesianHistory::~ChartTwoDataCartesianHistory() +ChartTwoLineSeriesHistory::~ChartTwoLineSeriesHistory() { clearHistory(); delete m_sceneAssistant; @@ -63,12 +63,12 @@ ChartTwoDataCartesianHistory::~ChartTwoDataCartesianHistory() * @param obj * Object that is copied. */ -ChartTwoDataCartesianHistory::ChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj) +ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj) { initializeInstance(); - this->copyHelperChartTwoDataCartesianHistory(obj); + this->copyHelperChartTwoLineSeriesHistory(obj); } /** @@ -78,32 +78,52 @@ SceneableInterface(obj) * @return * Reference to this object. */ -ChartTwoDataCartesianHistory& -ChartTwoDataCartesianHistory::operator=(const ChartTwoDataCartesianHistory& obj) +ChartTwoLineSeriesHistory& +ChartTwoLineSeriesHistory::operator=(const ChartTwoLineSeriesHistory& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); - this->copyHelperChartTwoDataCartesianHistory(obj); + this->copyHelperChartTwoLineSeriesHistory(obj); } return *this; } +bool +ChartTwoLineSeriesHistory::isLoadingEnabled() const +{ + return m_loadingEnabled; +} + +/** + * Set loading line series charts enabled + * + * @param loadingEnabled + * New value for loading line series charts enabled + */ +void +ChartTwoLineSeriesHistory::setLoadingEnabled(const bool loadingEnabled) +{ + m_loadingEnabled = loadingEnabled; +} + /** * Initialize an instance of this class. */ void -ChartTwoDataCartesianHistory::initializeInstance() +ChartTwoLineSeriesHistory::initializeInstance() { const int32_t defaultHistoryCount = 5; + m_loadingEnabled = false; m_sceneAssistant = new SceneClassAssistant(); - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_displayCountInTab[i] = defaultHistoryCount; - } + m_displayCount = defaultHistoryCount; + m_sceneAssistant->add("m_loadingEnabled", + &m_loadingEnabled); m_sceneAssistant->add("m_defaultColor", &m_defaultColor); - m_sceneAssistant->addTabIndexedIntegerArray("m_displayCountInTab", m_displayCountInTab); + m_sceneAssistant->add("m_displayCount", + &m_displayCount); } @@ -113,8 +133,9 @@ ChartTwoDataCartesianHistory::initializeInstance() * Object that is copied. */ void -ChartTwoDataCartesianHistory::copyHelperChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj) -{ +ChartTwoLineSeriesHistory::copyHelperChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj) +{ m_loadingEnabled = obj.m_loadingEnabled; + clearHistory(); for (const auto item : m_chartHistory) { @@ -126,16 +147,14 @@ ChartTwoDataCartesianHistory::copyHelperChartTwoDataCartesianHistory(const Chart } m_defaultColor = obj.m_defaultColor; - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_displayCountInTab[i] = obj.m_displayCountInTab[i]; - } + m_displayCount = obj.m_displayCount; } /** * @return The default color. */ CaretColorEnum::Enum -ChartTwoDataCartesianHistory::getDefaultColor() const +ChartTwoLineSeriesHistory::getDefaultColor() const { return m_defaultColor; } @@ -146,42 +165,38 @@ ChartTwoDataCartesianHistory::getDefaultColor() const * @param defaultColor New value for default color. */ void -ChartTwoDataCartesianHistory::setDefaultColor(const CaretColorEnum::Enum defaultColor) +ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultColor) { if (defaultColor != m_defaultColor) { m_defaultColor = defaultColor; setModified(); } + + for (auto chartData : m_chartHistory) { + chartData->setColor(defaultColor); + } } /** - * @return Count of items for display in tab. - * - * @param tabIndex - * Index of tab. + * @return Count of items for display. */ int32_t -ChartTwoDataCartesianHistory::getDisplayCountInTab(const int32_t tabIndex) const +ChartTwoLineSeriesHistory::getDisplayCount() const { - CaretAssertArrayIndex(m_displayCountInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - return m_displayCountInTab[tabIndex]; + return m_displayCount; } /** - * Set count of items for display in tab. + * Set count of items for display. * - * @param tabIndex - * Index of tab. * @param count * New value for count. */ void -ChartTwoDataCartesianHistory::setDisplayCountInTab(const int32_t tabIndex, - const int count) +ChartTwoLineSeriesHistory::setDisplayCount(const int32_t count) { - CaretAssertArrayIndex(m_displayCountInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - if (count != m_displayCountInTab[tabIndex]) { - m_displayCountInTab[tabIndex] = count; + if (count != m_displayCount) { + m_displayCount = count; setModified(); } } @@ -189,7 +204,7 @@ ChartTwoDataCartesianHistory::setDisplayCountInTab(const int32_t tabIndex, /** * @return Count of items in history. */ -int32_t ChartTwoDataCartesianHistory::getHistoryCount() +int32_t ChartTwoLineSeriesHistory::getHistoryCount() const { return m_chartHistory.size(); } @@ -202,7 +217,7 @@ int32_t ChartTwoDataCartesianHistory::getHistoryCount() * Added to history. */ void -ChartTwoDataCartesianHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) +ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); historyItem->setColor(m_defaultColor); @@ -216,7 +231,7 @@ ChartTwoDataCartesianHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) * Index of the item. */ ChartTwoDataCartesian* -ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) +ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) { CaretAssertVectorIndex(m_chartHistory, index); return m_chartHistory[index]; @@ -229,7 +244,7 @@ ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) * Index of the item. */ const ChartTwoDataCartesian* -ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) const +ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) const { CaretAssertVectorIndex(m_chartHistory, index); return m_chartHistory[index]; @@ -239,7 +254,7 @@ ChartTwoDataCartesianHistory::getHistoryItem(const int32_t index) const * @return Clear the history. */ void -ChartTwoDataCartesianHistory::clearHistory() +ChartTwoLineSeriesHistory::clearHistory() { for (auto item : m_chartHistory) { delete item; @@ -253,16 +268,16 @@ ChartTwoDataCartesianHistory::clearHistory() * @return String describing this object's content. */ AString -ChartTwoDataCartesianHistory::toString() const +ChartTwoLineSeriesHistory::toString() const { - return "ChartTwoDataCartesianHistory"; + return "ChartTwoLineSeriesHistory"; } /** * @return Is this instance modified? */ bool -ChartTwoDataCartesianHistory::isModified() const +ChartTwoLineSeriesHistory::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; @@ -281,7 +296,7 @@ ChartTwoDataCartesianHistory::isModified() const * Clear modified status for this instance. */ void -ChartTwoDataCartesianHistory::clearModified() +ChartTwoLineSeriesHistory::clearModified() { for (const auto item : m_chartHistory) { item->clearModified(); @@ -300,11 +315,11 @@ ChartTwoDataCartesianHistory::clearModified() * Name of instance in the scene. */ SceneClass* -ChartTwoDataCartesianHistory::saveToScene(const SceneAttributes* sceneAttributes, +ChartTwoLineSeriesHistory::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, - "ChartTwoDataCartesianHistory", + "ChartTwoLineSeriesHistory", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -344,7 +359,7 @@ ChartTwoDataCartesianHistory::saveToScene(const SceneAttributes* sceneAttributes * sceneClass from which model specific information is obtained. */ void -ChartTwoDataCartesianHistory::restoreFromScene(const SceneAttributes* sceneAttributes, +ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { @@ -367,7 +382,8 @@ ChartTwoDataCartesianHistory::restoreFromScene(const SceneAttributes* sceneAttri const SceneClass* historyClass = chartHistoryMap->classValue(i); ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + GraphicsPrimitive::PrimitiveType::LINES); historyItem->restoreFromScene(sceneAttributes, historyClass); addHistoryItem(historyItem); diff --git a/src/Charting/ChartTwoDataCartesianHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h similarity index 75% rename from src/Charting/ChartTwoDataCartesianHistory.h rename to src/Charting/ChartTwoLineSeriesHistory.h index 83dfb863b..1a906e575 100644 --- a/src/Charting/ChartTwoDataCartesianHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -1,5 +1,5 @@ -#ifndef __CHART_TWO_DATA_CARTESIAN_HISTORY_H__ -#define __CHART_TWO_DATA_CARTESIAN_HISTORY_H__ +#ifndef __CHART_TWO_LINE_SERIES_HISTORY_H__ +#define __CHART_TWO_LINE_SERIES_HISTORY_H__ /*LICENSE_START*/ /* @@ -34,27 +34,30 @@ namespace caret { class ChartTwoDataCartesian; class SceneClassAssistant; - class ChartTwoDataCartesianHistory : public CaretObjectTracksModification, public SceneableInterface { + class ChartTwoLineSeriesHistory : public CaretObjectTracksModification, public SceneableInterface { public: - ChartTwoDataCartesianHistory(); + ChartTwoLineSeriesHistory(); - virtual ~ChartTwoDataCartesianHistory(); + virtual ~ChartTwoLineSeriesHistory(); - ChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj); + ChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj); - ChartTwoDataCartesianHistory& operator=(const ChartTwoDataCartesianHistory& obj); + ChartTwoLineSeriesHistory& operator=(const ChartTwoLineSeriesHistory& obj); + bool isLoadingEnabled() const; + + void setLoadingEnabled(const bool enabled); + CaretColorEnum::Enum getDefaultColor() const; void setDefaultColor(const CaretColorEnum::Enum defaultColor); - int32_t getDisplayCountInTab(const int32_t tabIndex) const; + int32_t getDisplayCount() const; - void setDisplayCountInTab(const int32_t tabIndex, - const int count); + void setDisplayCount(const int32_t count); - int32_t getHistoryCount(); + int32_t getHistoryCount() const; void addHistoryItem(ChartTwoDataCartesian* historyItem); @@ -92,25 +95,27 @@ namespace caret { // const SceneClass* sceneClass) = 0; private: - void copyHelperChartTwoDataCartesianHistory(const ChartTwoDataCartesianHistory& obj); + void copyHelperChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj); void initializeInstance(); + bool m_loadingEnabled = false; + SceneClassAssistant* m_sceneAssistant = NULL; std::deque m_chartHistory; CaretColorEnum::Enum m_defaultColor = CaretColorEnum::BLUE; - int32_t m_displayCountInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + int32_t m_displayCount; // ADD_NEW_MEMBERS_HERE }; -#ifdef __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ +#ifdef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ // -#endif // __CHART_TWO_DATA_CARTESIAN_HISTORY_DECLARE__ +#endif // __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ } // namespace -#endif //__CHART_TWO_DATA_CARTESIAN_HISTORY_H__ +#endif //__CHART_TWO_LINE_SERIES_HISTORY_H__ diff --git a/src/Charting/EventChartTwoLoadLineSeriesData.cxx b/src/Charting/EventChartTwoLoadLineSeriesData.cxx new file mode 100644 index 000000000..fbd2317f2 --- /dev/null +++ b/src/Charting/EventChartTwoLoadLineSeriesData.cxx @@ -0,0 +1,80 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ +#include "EventChartTwoLoadLineSeriesData.h" +#undef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventChartTwoLoadLineSeriesData + * \brief Event for loading chart two line series data + * \ingroup Charting + */ + +/** + * Constructor. + * + * @param validTabIndices + * Indices of valid tabs. + * @param mapFileDataSelector + * Map file data selector that provides data selection criteria. + */ +EventChartTwoLoadLineSeriesData::EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, + const MapFileDataSelector& mapFileDataSelector) +: Event(EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA), +m_validTabIndices(validTabIndices), +m_mapFileDataSelector(mapFileDataSelector) +{ + +} + +/** + * Destructor. + */ +EventChartTwoLoadLineSeriesData::~EventChartTwoLoadLineSeriesData() +{ +} + +/** + * @return The valid tab indices. + */ +std::vector +EventChartTwoLoadLineSeriesData::getValidTabIndices() const +{ + return m_validTabIndices; +} + +/** + * @return Map file data selector that provides data selection criteria. + */ +MapFileDataSelector +EventChartTwoLoadLineSeriesData::getMapFileDataSelector() const +{ + return m_mapFileDataSelector; +} + diff --git a/src/Charting/EventChartTwoLoadLineSeriesData.h b/src/Charting/EventChartTwoLoadLineSeriesData.h new file mode 100644 index 000000000..e31a209a7 --- /dev/null +++ b/src/Charting/EventChartTwoLoadLineSeriesData.h @@ -0,0 +1,69 @@ +#ifndef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ +#define __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" +#include "MapFileDataSelector.h" +#include "StructureEnum.h" + + +namespace caret { + + class EventChartTwoLoadLineSeriesData : public Event { + + public: + EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, + const MapFileDataSelector& mapFileDataSelector); +// EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, +// const MapFileDataSelector& mapFileDataSelector); + + virtual ~EventChartTwoLoadLineSeriesData(); + + MapFileDataSelector getMapFileDataSelector() const; + + std::vector getValidTabIndices() const; + + // ADD_NEW_METHODS_HERE + + private: + EventChartTwoLoadLineSeriesData(const EventChartTwoLoadLineSeriesData&); + + EventChartTwoLoadLineSeriesData& operator=(const EventChartTwoLoadLineSeriesData&); + + const std::vector m_validTabIndices; + + MapFileDataSelector m_mapFileDataSelector; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ + // +#endif // __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ + +} // namespace +#endif //__EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ diff --git a/src/Charting/MapFileDataSelector.cxx b/src/Charting/MapFileDataSelector.cxx new file mode 100644 index 000000000..9506ef0bf --- /dev/null +++ b/src/Charting/MapFileDataSelector.cxx @@ -0,0 +1,375 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __MAP_FILE_DATA_SELECTOR_DECLARE__ +#include "MapFileDataSelector.h" +#undef __MAP_FILE_DATA_SELECTOR_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassArray.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::MapFileDataSelector + * \brief Identifies data for selection in a map file + * \ingroup Charting + */ + +/** + * Constructor. + */ +MapFileDataSelector::MapFileDataSelector() +: CaretObject() +{ + reset(); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_surfaceNumberOfVertices", + &m_surfaceNumberOfVertices); + m_sceneAssistant->add("m_surfaceStructure", + &m_surfaceStructure); + m_sceneAssistant->add("m_surfaceVertexIndex", + &m_surfaceVertexIndex); + m_sceneAssistant->addArray("m_voxelXYZ", m_voxelXYZ, 3, 0.0f); +} + +/** + * Destructor. + */ +MapFileDataSelector::~MapFileDataSelector() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +MapFileDataSelector::MapFileDataSelector(const MapFileDataSelector& obj) +: CaretObject(obj) +{ + this->copyHelperMapFileDataSelector(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +MapFileDataSelector& +MapFileDataSelector::operator=(const MapFileDataSelector& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperMapFileDataSelector(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +MapFileDataSelector::copyHelperMapFileDataSelector(const MapFileDataSelector& obj) +{ + m_dataSelectionType = obj.m_dataSelectionType; + m_surfaceNumberOfVertices = obj.m_surfaceNumberOfVertices; + m_surfaceStructure = obj.m_surfaceStructure; + m_surfaceVertexAverageIndices = obj.m_surfaceVertexAverageIndices; + m_surfaceVertexIndex = obj.m_surfaceVertexIndex; + m_voxelXYZ[0] = obj.m_voxelXYZ[0]; + m_voxelXYZ[1] = obj.m_voxelXYZ[1]; + m_voxelXYZ[2] = obj.m_voxelXYZ[2]; +} + +/** + * @return The data selection type. + */ +MapFileDataSelector::DataSelectionType +MapFileDataSelector::getDataSelectionType() const +{ + return m_dataSelectionType; +} + +/** + * Get data for a surface vertex. + * + * @param surfaceStructure + * The surface structure. + * @param surfaceNumberOfVertices + * Number of vertices in the surface. + * @param surfaceVertexIndex + * Index of the vertex. + */ +void +MapFileDataSelector::getSurfaceVertex(StructureEnum::Enum& surfaceStructure, + int32_t& surfaceNumberOfVertices, + int32_t& surfaceVertexIndex) const +{ + surfaceStructure = m_surfaceStructure; + surfaceNumberOfVertices = m_surfaceNumberOfVertices; + surfaceVertexIndex = m_surfaceVertexIndex; +} + +/** + * Set data for a surface vertex. + * + * @param surfaceStructure + * The surface structure. + * @param surfaceNumberOfVertices + * Number of vertices in the surface. + * @param surfaceVertexIndex + * Index of the vertex. + */ +void +MapFileDataSelector::setSurfaceVertex(const StructureEnum::Enum& surfaceStructure, + const int32_t surfaceNumberOfVertices, + const int32_t surfaceVertexIndex) +{ + reset(); + m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; + m_surfaceStructure = surfaceStructure; + m_surfaceNumberOfVertices = surfaceNumberOfVertices; + m_surfaceVertexIndex = surfaceVertexIndex; +} + +/** + * Get data for a surface vertex average. + * + * @param surfaceStructure + * The surface structure. + * @param surfaceNumberOfVertices + * Number of vertices in the surface. + * @param surfaceVertexAverageIndices + * Indices of the vertex. + */ +void +MapFileDataSelector::getSurfaceVertexAverage(StructureEnum::Enum& surfaceStructure, + int32_t& surfaceNumberOfVertices, + std::vector& surfaceVertexAverageIndices) const +{ + surfaceStructure = m_surfaceStructure; + surfaceNumberOfVertices = m_surfaceNumberOfVertices; + surfaceVertexAverageIndices = m_surfaceVertexAverageIndices; +} + +/** + * Set data for a surface vertex average. + * + * @param surfaceStructure + * The surface structure. + * @param surfaceNumberOfVertices + * Number of vertices in the surface. + * @param surfaceVertexAverageIndices + * Indices of the vertex. + */ +void +MapFileDataSelector::setSurfaceVertexAverage(const StructureEnum::Enum& surfaceStructure, + const int32_t surfaceNumberOfVertices, + const std::vector& surfaceVertexAverageIndices) +{ + reset(); + m_dataSelectionType = DataSelectionType::SURFACE_VERTICES_AVERAGE; + m_surfaceStructure = surfaceStructure; + m_surfaceNumberOfVertices = surfaceNumberOfVertices; + m_surfaceVertexAverageIndices = surfaceVertexAverageIndices; +} + +/** + * Get the stereotaxic coordinate of the volume voxel. + * + * @param voxelXYZ + * The volume voxel XYZ. + */ +void +MapFileDataSelector::getVolumeVoxelXYZ(float voxelXYZ[3]) const +{ + voxelXYZ[0] = m_voxelXYZ[0]; + voxelXYZ[1] = m_voxelXYZ[1]; + voxelXYZ[2] = m_voxelXYZ[2]; +} + +/** + * Set the stereotaxic coordinate of the volume voxel. + * + * @param voxelXYZ + * The volume voxel XYZ. + */ +void +MapFileDataSelector::setVolumeVoxelXYZ(const float voxelXYZ[3]) +{ + reset(); + m_dataSelectionType = DataSelectionType::VOLUME_XYZ; + m_voxelXYZ[0] = voxelXYZ[0]; + m_voxelXYZ[1] = voxelXYZ[1]; + m_voxelXYZ[2] = voxelXYZ[2]; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +MapFileDataSelector::toString() const +{ + return "MapFileDataSelector"; +} + +/** + * Reset to an invalid state. + */ +void +MapFileDataSelector::reset() +{ + m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; + m_surfaceStructure = StructureEnum::INVALID; + m_surfaceNumberOfVertices = -1; + m_surfaceVertexIndex = -1; + m_surfaceVertexAverageIndices.clear(); + m_voxelXYZ[0] = 0.0f; + m_voxelXYZ[1] = 0.0f; + m_voxelXYZ[2] = 0.0f; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +MapFileDataSelector::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "MapFileDataSelector", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + AString dataSelectionTypeName; + switch (m_dataSelectionType) { + case DataSelectionType::INVALID: + dataSelectionTypeName = "INVALID"; + break; + case DataSelectionType::SURFACE_VERTEX: + dataSelectionTypeName = "SURFACE_VERTEX"; + break; + case DataSelectionType::SURFACE_VERTICES_AVERAGE: + dataSelectionTypeName = "SURFACE_VERTICES_AVERAGE"; + break; + case DataSelectionType::VOLUME_XYZ: + dataSelectionTypeName = "VOLUME_XYZ"; + break; + } + CaretAssert( ! dataSelectionTypeName.isEmpty()); + + sceneClass->addString("m_dataSelectionType", + dataSelectionTypeName); + + const int32_t numVertices = static_cast(m_surfaceVertexAverageIndices.size()); + if (numVertices > 0) { + sceneClass->addIntegerArray("m_surfaceVertexAverageIndices", + &m_surfaceVertexAverageIndices[0], + numVertices); + } + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +MapFileDataSelector::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + m_dataSelectionType = DataSelectionType::INVALID; + const AString dataSelectionTypeName = sceneClass->getStringValue("m_dataSelectionType", + "INVALID"); + if (dataSelectionTypeName == "INVALID") { + m_dataSelectionType = DataSelectionType::INVALID; + } + else if (dataSelectionTypeName == "SURFACE_VERTEX") { + m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; + } + else if (dataSelectionTypeName == "SURFACE_VERTICES_AVERAGE") { + m_dataSelectionType = DataSelectionType::SURFACE_VERTICES_AVERAGE; + } + else if (dataSelectionTypeName == "VOLUME_XYZ") { + m_dataSelectionType = DataSelectionType::VOLUME_XYZ; + } + else { + CaretAssertMessage(0, ("Invalid data selection type name \"" + + dataSelectionTypeName + + "\"")); + } + + const SceneClassArray* vertexArray = sceneClass->getClassArray("m_surfaceVertexAverageIndices"); + if (vertexArray != NULL) { + const int32_t numVertices = vertexArray->getNumberOfArrayElements(); + if (numVertices > 0) { + m_surfaceVertexAverageIndices.resize(numVertices); + sceneClass->getIntegerArrayValue("m_surfaceVertexAverageIndices", + &m_surfaceVertexAverageIndices[0], + numVertices); + } + } + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Charting/MapFileDataSelector.h b/src/Charting/MapFileDataSelector.h new file mode 100644 index 000000000..99c0867b7 --- /dev/null +++ b/src/Charting/MapFileDataSelector.h @@ -0,0 +1,131 @@ +#ifndef __MAP_FILE_DATA_SELECTOR_H__ +#define __MAP_FILE_DATA_SELECTOR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "SceneableInterface.h" +#include "StructureEnum.h" + +namespace caret { + class SceneClassAssistant; + + class MapFileDataSelector : public CaretObject, public SceneableInterface { + + public: + enum class DataSelectionType { + INVALID, + SURFACE_VERTEX, + SURFACE_VERTICES_AVERAGE, + VOLUME_XYZ + }; + + MapFileDataSelector(); + + virtual ~MapFileDataSelector(); + + MapFileDataSelector(const MapFileDataSelector& obj); + + MapFileDataSelector& operator=(const MapFileDataSelector& obj); + + DataSelectionType getDataSelectionType() const; + + std::vector getValidTabIndices() const; + + void getSurfaceVertex(StructureEnum::Enum& surfaceStructure, + int32_t& surfaceNumberOfVertices, + int32_t& surfaceVertexIndex) const; + + void setSurfaceVertex(const StructureEnum::Enum& surfaceStructure, + const int32_t surfaceNumberOfVertices, + const int32_t surfaceVertexIndex); + + void getSurfaceVertexAverage(StructureEnum::Enum& surfaceStructure, + int32_t& surfaceNumberOfVertices, + std::vector& surfaceVertexIndices) const; + + void setSurfaceVertexAverage(const StructureEnum::Enum& surfaceStructure, + const int32_t surfaceNumberOfVertices, + const std::vector& surfaceVertexIndices); + + void getVolumeVoxelXYZ(float xyz[3]) const; + + void setVolumeVoxelXYZ(const float xyz[3]); + + void reset(); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperMapFileDataSelector(const MapFileDataSelector& obj); + + std::unique_ptr m_sceneAssistant; + + DataSelectionType m_dataSelectionType = DataSelectionType::INVALID; + + int32_t m_surfaceNumberOfVertices = 0; + + StructureEnum::Enum m_surfaceStructure = StructureEnum::INVALID; + + std::vector m_surfaceVertexAverageIndices; + + int32_t m_surfaceVertexIndex = -1; + + float m_voxelXYZ[3]; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __MAP_FILE_DATA_SELECTOR_DECLARE__ + // +#endif // __MAP_FILE_DATA_SELECTOR_DECLARE__ + +} // namespace +#endif //__MAP_FILE_DATA_SELECTOR_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 4a8b50cf8..7219dc1c9 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -492,6 +492,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: + case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: case EventTypeEnum::EVENT_DATA_FILE_ADD: case EventTypeEnum::EVENT_DATA_FILE_DELETE: case EventTypeEnum::EVENT_DATA_FILE_READ: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 9b217657c..129b3b42d 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -185,6 +185,10 @@ EventTypeEnum::initialize() "EVENT_CHART_OVERLAY_VALIDATE", "Validate a chart overlay for validity (it exists)")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, + "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", + "Load line series data for chart two implementation")); + enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_ADD, "EVENT_DATA_FILE_ADD", "Add a data file to the Brain")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index faa7060c3..11acad2fc 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -92,6 +92,8 @@ public: EVENT_CHART_MATRIX_YOKING_VALIDATION, /** Validate that chart overlay is valid (it exists). */ EVENT_CHART_OVERLAY_VALIDATE, + /** Load chart two line series data */ + EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, /** Add a data file into the Brain*/ EVENT_DATA_FILE_ADD, /** Delete a data file from the brain */ diff --git a/src/Files/CaretMappableDataFile.h b/src/Files/CaretMappableDataFile.h index f0b33a974..9ed6bd9c8 100644 --- a/src/Files/CaretMappableDataFile.h +++ b/src/Files/CaretMappableDataFile.h @@ -39,6 +39,7 @@ namespace caret { class GiftiLabelTable; class Histogram; class LabelDrawingProperties; + class MapFileDataSelector; class PaletteColorMapping; class PaletteFile; @@ -472,6 +473,9 @@ namespace caret { const ChartableTwoFileDelegate* getChartingDelegate() const; + virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const = 0; + protected: CaretMappableDataFile(const CaretMappableDataFile&); diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index fae04533f..22dbbbeb8 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -24,8 +24,11 @@ #undef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ #include "CaretAssert.h" -#include "ChartTwoDataCartesianHistory.h" +#include "ChartTwoDataCartesian.h" +#include "ChartTwoLineSeriesHistory.h" #include "CiftiMappableDataFile.h" +#include "EventChartTwoLoadLineSeriesData.h" +#include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -126,9 +129,9 @@ m_lineSeriesContentType(lineSeriesContentType) } break; } - m_lineChartHistory = std::unique_ptr(new ChartTwoDataCartesianHistory()); + m_lineChartHistory = std::unique_ptr(new ChartTwoLineSeriesHistory()); m_sceneAssistant->add("m_lineChartHistory", - "ChartTwoDataCartesianHistory", + "ChartTwoLineSeriesHistory", m_lineChartHistory.get()); /* @@ -140,6 +143,11 @@ m_lineSeriesContentType(lineSeriesContentType) updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, xAxisNumberOfElements)); + + if (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA); + } } /** @@ -149,6 +157,129 @@ ChartableTwoFileLineSeriesChart::~ChartableTwoFileLineSeriesChart() { } +/** + * Receive an event. + * + * @param event + * An event for which this instance is listening. + */ +void +ChartableTwoFileLineSeriesChart::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA) { + const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent = dynamic_cast(event); + CaretAssert(lineSeriesDataEvent); + + if (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { + const std::vector tabIndicesForLoading = getTabIndicesForLoadingData(lineSeriesDataEvent->getValidTabIndices()); + if ( ! tabIndicesForLoading.empty()) { + + loadLineCharts(tabIndicesForLoading, + lineSeriesDataEvent); + } + } + + event->setEventProcessed(); + } + else { + ChartableTwoFileBaseChart::receiveEvent(event); + } +} + +/** + * @param tabIndicesForLoading + * Tab indices for loading data. + * @param lineSeriesDataEvent + * Event indicating data for loading. + */ +void +ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabIndicesForLoading, + const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent) +{ + const MapFileDataSelector mapFileDataSelector = lineSeriesDataEvent->getMapFileDataSelector(); + + bool loadDataFlag = false; + switch (m_lineSeriesContentType) { + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: + return; + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + loadDataFlag = true; + break; + } + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + break; + } + + if (loadDataFlag) { + std::vector data; + getCaretMappableDataFile()->getDataForSelector(mapFileDataSelector, + data); + if ( ! data.empty()) { + std::cout << "Loaded data for file " << getCaretMappableDataFile()->getFileNameNoPath() << std::endl; + + const ChartAxisUnitsEnum::Enum xUnits = getChartTwoCompoundDataType().getLineChartUnitsAxisX(); + CaretAssert(getChartTwoCompoundDataType().getLineChartNumberOfElementsAxisX() == static_cast(data.size())); + ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, + xUnits, + ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + GraphicsPrimitive::PrimitiveType::LINES); + + float x = 0.0f; + float xStep = 0.0f; + getCaretMappableDataFile()->getMapIntervalStartAndStep(x, xStep); + + /* + * Note: Start at index one since line segments are used + */ + const int32_t numData = static_cast(data.size()); + for (int32_t i = 1; i < numData; i++) { + CaretAssertVectorIndex(data, i - 1); + cartesianData->addPoint(x, data[i - 1]); + x += xStep; + CaretAssertVectorIndex(data, i); + cartesianData->addPoint(x, data[i]); + } +// for (float d : data) { +// cartesianData->addPoint(x, d); +// x += xStep; +// } + + m_lineChartHistory->addHistoryItem(cartesianData); + } + } +} + +/** + * Find tab indices for which user has loading of data enabled in the given valid tab indices. + * + * @param validTabIndices + * All tabs that are valid. + * @return + * Tab indices for which data should be loaded. + */ +std::vector +ChartableTwoFileLineSeriesChart::getTabIndicesForLoadingData(const std::vector& validTabIndices) const +{ + std::vector tabIndicesOut; + + if ( ! validTabIndices.empty()) { + if (m_lineChartHistory->isLoadingEnabled()) { + tabIndicesOut = validTabIndices; + } + } + + return tabIndicesOut; +} + + /** * @return Content type of the line series data. */ @@ -161,7 +292,7 @@ ChartableTwoFileLineSeriesChart::getLineSeriesContentType() const /** * @return History of line charts. */ -ChartTwoDataCartesianHistory* +ChartTwoLineSeriesHistory* ChartableTwoFileLineSeriesChart::getHistory() { return m_lineChartHistory.get(); @@ -170,7 +301,7 @@ ChartableTwoFileLineSeriesChart::getHistory() /** * @return History of line charts (const method) */ -const ChartTwoDataCartesianHistory* +const ChartTwoLineSeriesHistory* ChartableTwoFileLineSeriesChart::getHistory() const { return m_lineChartHistory.get(); diff --git a/src/Files/ChartableTwoFileLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h index 7666d2530..542fe6030 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -23,13 +23,15 @@ #include +#include "BrainConstants.h" #include "ChartableTwoFileBaseChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" namespace caret { - class ChartTwoDataCartesianHistory; + class ChartTwoLineSeriesHistory; + class EventChartTwoLoadLineSeriesData; class ChartableTwoFileLineSeriesChart : public ChartableTwoFileBaseChart { @@ -41,14 +43,16 @@ namespace caret { ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; - ChartTwoDataCartesianHistory* getHistory(); + ChartTwoLineSeriesHistory* getHistory(); - const ChartTwoDataCartesianHistory* getHistory() const; + const ChartTwoLineSeriesHistory* getHistory() const; virtual bool isValid() const override; virtual bool isEmpty() const override; + virtual void receiveEvent(Event* event) override; + // ADD_NEW_METHODS_HERE @@ -65,15 +69,20 @@ namespace caret { const SceneClass* sceneClass) override; private: + void loadLineCharts(const std::vector& tabIndicesForLoading, + const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent); + ChartableTwoFileLineSeriesChart(const ChartableTwoFileLineSeriesChart&); ChartableTwoFileLineSeriesChart& operator=(const ChartableTwoFileLineSeriesChart&); + std::vector getTabIndicesForLoadingData(const std::vector& validTabIndices) const; + std::unique_ptr m_sceneAssistant; ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; - std::unique_ptr m_lineChartHistory; + std::unique_ptr m_lineChartHistory; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/CiftiFiberTrajectoryFile.cxx b/src/Files/CiftiFiberTrajectoryFile.cxx index 423085f12..d822b8be0 100644 --- a/src/Files/CiftiFiberTrajectoryFile.cxx +++ b/src/Files/CiftiFiberTrajectoryFile.cxx @@ -1916,3 +1916,18 @@ const CiftiXML CiftiFiberTrajectoryFile::getCiftiXML() const } return CiftiXML(); } + +/** + * Get data from the file as requested in the given map file data selector. + * + * @param mapFileDataSelector + * Specifies selection of data. + * @param dataOut + * Output with data. Will be empty if data does not support the map file data selector. + */ +void +CiftiFiberTrajectoryFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, + std::vector& dataOut) const +{ + dataOut.clear(); +} diff --git a/src/Files/CiftiFiberTrajectoryFile.h b/src/Files/CiftiFiberTrajectoryFile.h index 91bd25557..84ba8359a 100644 --- a/src/Files/CiftiFiberTrajectoryFile.h +++ b/src/Files/CiftiFiberTrajectoryFile.h @@ -174,7 +174,9 @@ namespace caret { bool hasCiftiXML() const; const CiftiXML getCiftiXML() const; - + + virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const override; // ADD_NEW_METHODS_HERE private: diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index b752893ba..54c3445bc 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -55,6 +55,7 @@ #include "GraphicsPrimitiveV3fC4f.h" #include "GroupAndNameHierarchyModel.h" #include "Histogram.h" +#include "MapFileDataSelector.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" @@ -95,8 +96,8 @@ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFi m_containsSurfaceData = false; m_containsVolumeData = false; - m_mappingTimeStart = 0.0; - m_mappingTimeStep = 0.0; + m_mappingTimeStart = 0.0f; + m_mappingTimeStep = 1.0f; m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; m_dataReadingAccessMethod = DATA_ACCESS_METHOD_INVALID; @@ -464,8 +465,8 @@ CiftiMappableDataFile::clearPrivate() m_containsSurfaceData = false; m_containsVolumeData = false; - m_mappingTimeStart = 0.0; - m_mappingTimeStep = 0.0; + m_mappingTimeStart = 0.0f; + m_mappingTimeStep = 1.0f; m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; } @@ -1014,6 +1015,10 @@ CiftiMappableDataFile::initializeAfterReading(const AString& filename) m_mappingTimeStep = map.getStep(); } + if (m_mappingTimeStep <= 0.0) { + m_mappingTimeStep = 1.0f; + } + /* * May not have mappings to voxels */ @@ -6840,6 +6845,54 @@ CiftiMappableDataFile::helpMatrixFileLoadChartDataMatrixRGBA(int32_t& numberOfRo return false; } +/** + * Get data from the file as requested in the given map file data selector. + * + * @param mapFileDataSelector + * Specifies selection of data. + * @param dataOut + * Output with data. Will be empty if data does not support the map file data selector. + */ +void +CiftiMappableDataFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const +{ + dataOut.clear(); + + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + try { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfVertices = -1; + int32_t vertexIndex = -1; + mapFileDataSelector.getSurfaceVertex(structure, + numberOfVertices, + vertexIndex); + + if (getMappingSurfaceNumberOfNodes(structure) == numberOfVertices) { + if ( ! getSeriesDataForSurfaceNode(structure, + vertexIndex, + dataOut)) { + dataOut.clear(); + } + } + } + catch (const DataFileException& dfe) { + CaretLogWarning("Exeception: " + + dfe.whatString()); + dataOut.clear(); + } + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + break; + } + +} + ///* ========================================================================== */ diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 89e1c39ea..2b190c29f 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -467,6 +467,9 @@ namespace caret { */ static inline int32_t getCiftiFileRowColumnIndexBaseForGUI() { return CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI; } + virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const override; + private: CiftiMappableDataFile(const CiftiMappableDataFile&); diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index db2f28a71..2bff347fa 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -984,4 +984,18 @@ GiftiTypeFile::addToDataFileContentInformation(DataFileContentInformation& dataF getNumberOfNodes()); } +/** + * Get data from the file as requested in the given map file data selector. + * + * @param mapFileDataSelector + * Specifies selection of data. + * @param dataOut + * Output with data. Will be empty if data does not support the map file data selector. + */ +void +GiftiTypeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, + std::vector& dataOut) const +{ + dataOut.clear(); +} diff --git a/src/Files/GiftiTypeFile.h b/src/Files/GiftiTypeFile.h index 574563428..5b8bf9e79 100644 --- a/src/Files/GiftiTypeFile.h +++ b/src/Files/GiftiTypeFile.h @@ -165,6 +165,10 @@ namespace caret { virtual void updateScalarColoringForMap(const int32_t mapIndex, const PaletteFile* paletteFile); + + virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const override; + private: void copyHelperGiftiTypeFile(const GiftiTypeFile& gtf); diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 57ac9a5e8..9e7155462 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -2231,4 +2231,18 @@ VolumeFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) return chartData; } +/** + * Get data from the file as requested in the given map file data selector. + * + * @param mapFileDataSelector + * Specifies selection of data. + * @param dataOut + * Output with data. Will be empty if data does not support the map file data selector. + */ +void +VolumeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, + std::vector& dataOut) const +{ + dataOut.clear(); +} diff --git a/src/Files/VolumeFile.h b/src/Files/VolumeFile.h index 80ead28f9..3cd40edbe 100644 --- a/src/Files/VolumeFile.h +++ b/src/Files/VolumeFile.h @@ -362,6 +362,9 @@ namespace caret { virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const override; + }; } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index e127219df..3cac8ca3c 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -119,6 +119,16 @@ GraphicsEngineDataOpenGL::invalidateCoordinates() m_reloadCoordinatesFlag = true; } +/** + * Invalidate the colors after they have + * changed in the graphics primitive. + */ +void +GraphicsEngineDataOpenGL::invalidateColors() +{ + m_reloadColorsFlag = true; +} + /** * Get the OpenGL Buffer Usage Hint from the primitive. * @@ -304,6 +314,8 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) } break; } + + m_reloadColorsFlag = false; } /** @@ -811,6 +823,13 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, if (openglData->m_reloadCoordinatesFlag) { openglData->loadCoordinateBuffer(primitive); } + + /* + * Colors may get updated + */ + if (openglData->m_reloadColorsFlag) { + openglData->loadColorBuffer(primitive); + } } openglData->loadTextureImageDataBuffer(primitive); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index eb1d93a6a..9f08d1873 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -65,6 +65,8 @@ namespace caret { void invalidateCoordinates(); + void invalidateColors(); + // ADD_NEW_METHODS_HERE private: @@ -117,6 +119,8 @@ namespace caret { bool m_reloadCoordinatesFlag = false; + bool m_reloadColorsFlag = false; + GraphicsOpenGLBufferObject* m_normalVectorBufferObject = NULL; GLenum m_normalVectorDataType = GL_FLOAT; diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index 919f210a0..8c9e2bfbe 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -24,6 +24,9 @@ #undef __GRAPHICS_PRIMITIVE_V3F_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" +#include "GraphicsEngineDataOpenGL.h" + using namespace caret; @@ -233,3 +236,36 @@ GraphicsPrimitiveV3f::clone() const return obj; } +/** + * Replace the coloring in the primitive with float data. + * When primitive was constructed it must have used the + * constructor that accepts float data. + * + * @param rgba + * Replacement color RGBA components. + */ +void +GraphicsPrimitiveV3f::replaceColoring(const float rgba[4]) +{ + CaretAssert(m_colorType == ColorType::FLOAT_RGBA); + if (m_colorType == ColorType::FLOAT_RGBA) { + const int32_t numVertices = static_cast(m_floatRGBA.size() / 4); + for (int32_t i = 0; i < numVertices; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(m_floatRGBA, i4+3); + m_floatRGBA[i4] = rgba[0]; + m_floatRGBA[i4+1] = rgba[1]; + m_floatRGBA[i4+2] = rgba[2]; + m_floatRGBA[i4+3] = rgba[3]; + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateColors(); + } + } + } + else { + CaretLogSevere("Replacement coloring is wrong data type (Float)"); + } +} + + diff --git a/src/Graphics/GraphicsPrimitiveV3f.h b/src/Graphics/GraphicsPrimitiveV3f.h index f11925420..760a3a7d1 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.h +++ b/src/Graphics/GraphicsPrimitiveV3f.h @@ -58,6 +58,8 @@ namespace caret { virtual GraphicsPrimitive* clone() const; + void replaceColoring(const float rgba[4]); + // ADD_NEW_METHODS_HERE private: diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 35b45757a..72d7d70ed 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -99,19 +99,21 @@ m_browserWindowIndex(browserWindowIndex) if (orientation == Qt::Horizontal) { static const int COLUMN_ON = 0; - static const int COLUMN_SETTINGS_EDIT = 1; - static const int COLUMN_SETTINGS_COLOR_BAR = 2; - static const int COLUMN_SETTINGS_CONSTRUCTION = 3; - static const int COLUMN_HISTORY = 4; - static const int COLUMN_MATRIX_VIEW = 5; - static const int COLUMN_AXIS = 6; - static const int COLUMN_FILE = 7; - static const int COLUMN_YOKE = 8; - static const int COLUMN_MAP_INDEX = 9; - static const int COLUMN_ALL_MAPS = 10; - static const int COLUMN_MAP_NAME = 11; + static const int COLUMN_LOAD = 1; + static const int COLUMN_SETTINGS_EDIT = 2; + static const int COLUMN_SETTINGS_COLOR_BAR = 3; + static const int COLUMN_SETTINGS_CONSTRUCTION = 4; + static const int COLUMN_HISTORY = 5; + static const int COLUMN_MATRIX_VIEW = 6; + static const int COLUMN_AXIS = 7; + static const int COLUMN_FILE = 8; + static const int COLUMN_YOKE = 9; + static const int COLUMN_MAP_INDEX = 10; + static const int COLUMN_ALL_MAPS = 11; + static const int COLUMN_MAP_NAME = 12; gridLayout->setColumnStretch(COLUMN_ON, 0); + gridLayout->setColumnStretch(COLUMN_LOAD, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_COLOR_BAR, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); @@ -125,6 +127,7 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnStretch(COLUMN_MAP_NAME, 100); QLabel* onLabel = new QLabel("On"); + QLabel* loadLabel = new QLabel("Load"); QLabel* settingsLabel = new QLabel("Settings"); //QLabel* historyLabel = new QLabel("History"); QLabel* fileLabel = new QLabel("File"); @@ -135,6 +138,7 @@ m_browserWindowIndex(browserWindowIndex) int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); + gridLayout->addWidget(loadLabel, row, COLUMN_LOAD, Qt::AlignHCenter); gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 5, Qt::AlignHCenter); //gridLayout->addWidget(historyLabel, row, COLUMN_HISTORY, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); @@ -149,6 +153,7 @@ m_browserWindowIndex(browserWindowIndex) WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; glg->addWidget(covc->m_enabledCheckBox, row, COLUMN_ON, Qt::AlignHCenter); + glg->addWidget(covc->m_lineSeriesLoadingEnabledCheckBox, row, COLUMN_LOAD, Qt::AlignHCenter); glg->addWidget(covc->m_settingsToolButton, row, COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); @@ -173,8 +178,9 @@ m_browserWindowIndex(browserWindowIndex) static const int ROW_ONE_COLUMN_FILE_LABEL = 7; static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 8; - static const int ROW_TWO_COLUMN_YOKE = 0; - static const int ROW_TWO_COLUMN_ALL_MAPS = 3; + static const int ROW_TWO_COLUMN_LOAD = 0; + static const int ROW_TWO_COLUMN_YOKE = 2; + static const int ROW_TWO_COLUMN_ALL_MAPS = 4; static const int ROW_TWO_COLUMN_MAP_INDEX = 7; static const int ROW_TWO_COLUMN_MAP_NAME = 8; @@ -205,7 +211,7 @@ m_browserWindowIndex(browserWindowIndex) ChartTwoOverlayViewController* covc = m_chartOverlayViewControllers[i]; QLabel* fileLabel = new QLabel("File"); - glg->addWidget(covc->m_enabledCheckBox, row, ROW_ONE_COLUMN_ON, Qt::AlignHCenter); + glg->addWidget(covc->m_enabledCheckBox, row, ROW_ONE_COLUMN_ON, Qt::AlignLeft); glg->addWidget(covc->m_settingsToolButton, row, ROW_ONE_COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, ROW_ONE_COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); @@ -216,9 +222,9 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 2); row++; + glg->addWidget(covc->m_lineSeriesLoadingEnabledCheckBox, row, ROW_TWO_COLUMN_LOAD, Qt::AlignLeft); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); -// glg->addWidget(covc->m_historyToolButton, row, ROW_TWO_COLUMN_HISTORY, 1, 2, Qt::AlignHCenter); - glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 4, Qt::AlignRight); + glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 3, Qt::AlignRight); glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 34e18ab2b..970e29e16 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -100,12 +100,21 @@ m_chartOverlay(NULL) /* * Enabled Check Box */ - const QString checkboxText = ((orientation == Qt::Horizontal) ? " " : " "); - m_enabledCheckBox = new QCheckBox(checkboxText); + const QString enabledCheckboxText = ((orientation == Qt::Horizontal) ? " " : "On"); + m_enabledCheckBox = new QCheckBox(enabledCheckboxText); QObject::connect(m_enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); m_enabledCheckBox->setToolTip("Enables display of this layer"); + /* + * Line Series Enabled Check Box + */ + const QString loadingCheckboxText = ((orientation == Qt::Horizontal) ? " " : "Load"); + m_lineSeriesLoadingEnabledCheckBox = new QCheckBox(loadingCheckboxText); + QObject::connect(m_lineSeriesLoadingEnabledCheckBox, &QCheckBox::clicked, + this, &ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked); + m_lineSeriesLoadingEnabledCheckBox->setToolTip("Enabled loading of line charts for this overlay"); + /* * Settings Tool Button */ @@ -451,6 +460,22 @@ ChartTwoOverlayViewController::enabledCheckBoxClicked(bool checked) this->updateUserInterfaceAndGraphicsWindow(); } +/** + * Called when line-series loading enabled checkbox status is changed + * @parm checked + * Checked status + */ +void +ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked(bool checked) +{ + if (m_chartOverlay == NULL) { + return; + } + m_chartOverlay->setLineSeriesLoadingEnabled(checked); + + this->updateUserInterfaceAndGraphicsWindow(); +} + /** * Called when colorbar toolbutton is toggled. * @param status @@ -717,6 +742,16 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla m_enabledCheckBox->setChecked(m_chartOverlay->isEnabled()); } + /* + * Update lines series loading checkbox + */ + m_lineSeriesLoadingEnabledCheckBox->setEnabled(false); + m_lineSeriesLoadingEnabledCheckBox->setEnabled(false); + if ((validOverlayAndFileFlag) + && (m_chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES)) { + m_lineSeriesLoadingEnabledCheckBox->setEnabled(true); + m_lineSeriesLoadingEnabledCheckBox->setChecked(m_chartOverlay->isLineSeriesLoadingEnabled()); + } /* * Update yoking diff --git a/src/GuiQt/ChartTwoOverlayViewController.h b/src/GuiQt/ChartTwoOverlayViewController.h index f3c2fddab..ec44605f9 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.h +++ b/src/GuiQt/ChartTwoOverlayViewController.h @@ -76,6 +76,8 @@ namespace caret { void enabledCheckBoxClicked(bool); + void lineSeriesLoadingEnabledCheckBoxClicked(bool); + void colorBarActionTriggered(bool); void settingsActionTriggered(); @@ -149,6 +151,8 @@ namespace caret { QCheckBox* m_enabledCheckBox; + QCheckBox* m_lineSeriesLoadingEnabledCheckBox; + QToolButton* m_settingsToolButton; QAction* m_settingsAction; -- GitLab From d3ab680350f3c03063869a8d8c5fc159da44ee7f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Jun 2017 11:39:04 -0500 Subject: [PATCH 283/755] Updated cifti, metric, and volume files for loading chart two line series data. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1 + src/Brain/IdentificationTextGenerator.cxx | 80 +++++++++++++++- src/Brain/IdentificationTextGenerator.h | 4 + src/Brain/ModelChart.cxx | 24 ++++- src/Brain/SelectionItemChartTwoLineSeries.cxx | 19 +++- src/Brain/SelectionItemChartTwoLineSeries.h | 8 +- src/Charting/ChartTwoDataCartesian.cxx | 27 ++++++ src/Charting/ChartTwoDataCartesian.h | 7 ++ src/Files/ChartableTwoFileLineSeriesChart.cxx | 3 + src/Files/CiftiMappableDataFile.cxx | 65 ++++++++++++- src/Files/GiftiTypeFile.cxx | 2 +- src/Files/MetricFile.cxx | 96 +++++++++++++++++++ src/Files/MetricFile.h | 4 + src/Files/VolumeFile.cxx | 31 +++++- 14 files changed, 363 insertions(+), 8 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0f5417ce6..a88c9f70f 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1114,6 +1114,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if (primitiveIndex >= 0) { if (m_selectionItemLineSeries->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemLineSeries->setLineSeriesChart(const_cast(lineChart.m_lineSeriesChart), + const_cast(lineChart.m_chartTwoCartesianData), primitiveIndex); } } diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 33015ad64..4d7eef108 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -32,6 +32,7 @@ #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartModelDataSeries.h" +#include "ChartTwoDataCartesian.h" #include "ChartableMatrixInterface.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" @@ -48,6 +49,7 @@ #include "GiftiLabel.h" #include "Histogram.h" #include "ImageFile.h" +#include "MapFileDataSelector.h" #include "OverlaySet.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemChartDataSeries.h" @@ -856,10 +858,14 @@ IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(Identi const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const { if (idChartTwoLineSeries->isValid()) { - ChartableTwoFileLineSeriesChart* fileLineSeriesChart = idChartTwoLineSeries->getFileLineSeriesChart(); + const ChartableTwoFileLineSeriesChart* fileLineSeriesChart = idChartTwoLineSeries->getFileLineSeriesChart(); CaretAssert(fileLineSeriesChart); - CaretMappableDataFile* mapFile = fileLineSeriesChart->getCaretMappableDataFile(); + const CaretMappableDataFile* mapFile = fileLineSeriesChart->getCaretMappableDataFile(); CaretAssert(mapFile); + const ChartTwoDataCartesian* cartesianData = idChartTwoLineSeries->getChartTwoCartesianData(); + CaretAssert(cartesianData); + const MapFileDataSelector* mapFileDataSelector = cartesianData->getMapFileDataSelector(); + CaretAssert(mapFileDataSelector); const int32_t primitiveIndex = idChartTwoLineSeries->getLineSegmentIndex(); @@ -871,6 +877,9 @@ IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(Identi idText.addLine(true, "Line Segment Index", (AString::number(primitiveIndex))); + + generateMapFileSelectorText(idText, + mapFileDataSelector); } } @@ -1064,6 +1073,73 @@ IdentificationTextGenerator::generateChartDataSourceText(IdentificationStringBui } } +/** + * Generate text for a map file data selector. + * @param idText + * String builder for identification text. + * @param mapFileDataSelector + * The map file data selector. + */ +void +IdentificationTextGenerator::generateMapFileSelectorText(IdentificationStringBuilder& idText, + const MapFileDataSelector* mapFileDataSelector) const +{ + + switch (mapFileDataSelector->getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfVertices = 0; + int32_t vertexIndex = -1; + mapFileDataSelector->getSurfaceVertex(structure, + numberOfVertices, + vertexIndex); + + if ((structure != StructureEnum::INVALID) + && (vertexIndex >= 0)) { + idText.addLine(true, + "Structure", + StructureEnum::toGuiName(structure)); + idText.addLine(true, + "Vertex Index", + AString::number(vertexIndex)); + } + } + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t numberOfVertices = 0; + std::vector vertexIndices; + mapFileDataSelector->getSurfaceVertexAverage(structure, + numberOfVertices, + vertexIndices); + + const int32_t averageCount = static_cast(vertexIndices.size()); + if ((structure != StructureEnum::INVALID) + && (averageCount > 0)) { + idText.addLine(true, + "Structure", + StructureEnum::toGuiName(structure)); + idText.addLine(true, + "Vertex Average Count", + AString::number(averageCount)); + } + } + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + { + float voxelXYZ[3]; + mapFileDataSelector->getVolumeVoxelXYZ(voxelXYZ); + idText.addLine(true, + "Voxel XYZ", + AString::fromNumbers(voxelXYZ, 3, ",")); + } + break; + } +} /** * Generate identification text for a time series chart. diff --git a/src/Brain/IdentificationTextGenerator.h b/src/Brain/IdentificationTextGenerator.h index e38aab140..4fa605add 100644 --- a/src/Brain/IdentificationTextGenerator.h +++ b/src/Brain/IdentificationTextGenerator.h @@ -30,6 +30,7 @@ namespace caret { class BrowserTabContent; class CaretMappableDataFile; class ChartDataSource; + class MapFileDataSelector; class SelectionItemBorderSurface; class SelectionItemChartDataSeries; class SelectionItemChartFrequencySeries; @@ -116,6 +117,9 @@ namespace caret { void generateChartDataSourceText(IdentificationStringBuilder& idText, const AString& typeOfChartText, const ChartDataSource* chartDataSource) const; + + void generateMapFileSelectorText(IdentificationStringBuilder& idText, + const MapFileDataSelector* mapFileDataSelector) const; }; #ifdef __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 56f3e2a9a..b13df312d 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -205,7 +205,19 @@ ModelChart::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum struct addChartToChartModels(tabIndices, chartData); } - } + } + + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setSurfaceVertexAverage(structure, + surfaceNumberOfNodes, + nodeIndices); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** @@ -239,6 +251,16 @@ ModelChart::loadChartDataForVoxelAtCoordinate(const float xyz[3]) chartData); } } + + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setVolumeVoxelXYZ(xyz); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** diff --git a/src/Brain/SelectionItemChartTwoLineSeries.cxx b/src/Brain/SelectionItemChartTwoLineSeries.cxx index 1a352b14c..45b0f0d4d 100644 --- a/src/Brain/SelectionItemChartTwoLineSeries.cxx +++ b/src/Brain/SelectionItemChartTwoLineSeries.cxx @@ -41,6 +41,7 @@ SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LINE_SERIES) { m_fileLineSeriesChart = NULL; + m_chartTwoCartesianData = NULL; m_lineSegmentIndex = -1; } @@ -82,12 +83,21 @@ SelectionItemChartTwoLineSeries::operator=(const SelectionItemChartTwoLineSeries /** * @return The File line series chart. */ -ChartableTwoFileLineSeriesChart* +const ChartableTwoFileLineSeriesChart* SelectionItemChartTwoLineSeries::getFileLineSeriesChart() const { return m_fileLineSeriesChart; } +/** + * @return The cartesian data. + */ +const ChartTwoDataCartesian* +SelectionItemChartTwoLineSeries::getChartTwoCartesianData() const +{ + return m_chartTwoCartesianData; +} + /** * @return The line segment index. */ @@ -102,14 +112,18 @@ SelectionItemChartTwoLineSeries::getLineSegmentIndex() const * * @param fileLineSeriesChart * The line series chart. + * @param chartTwoCartesianData + * The cartesian data. * @param lineSegmentIndex * Index of the line segment. */ void SelectionItemChartTwoLineSeries::setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, + ChartTwoDataCartesian* chartTwoCartesianData, const int32_t lineSegmentIndex) { m_fileLineSeriesChart = fileLineSeriesChart; + m_chartTwoCartesianData = chartTwoCartesianData; m_lineSegmentIndex = lineSegmentIndex; } @@ -122,6 +136,7 @@ void SelectionItemChartTwoLineSeries::copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) { m_fileLineSeriesChart = obj.m_fileLineSeriesChart; + m_chartTwoCartesianData = obj.m_chartTwoCartesianData; m_lineSegmentIndex = obj.m_lineSegmentIndex; } @@ -132,6 +147,7 @@ bool SelectionItemChartTwoLineSeries::isValid() const { return ((m_fileLineSeriesChart != NULL) + && (m_chartTwoCartesianData != NULL) && (m_lineSegmentIndex >= 0)); } @@ -142,6 +158,7 @@ void SelectionItemChartTwoLineSeries::reset() { m_fileLineSeriesChart = NULL; + m_chartTwoCartesianData = NULL; m_lineSegmentIndex = -1; } diff --git a/src/Brain/SelectionItemChartTwoLineSeries.h b/src/Brain/SelectionItemChartTwoLineSeries.h index f93a88246..d479217e6 100644 --- a/src/Brain/SelectionItemChartTwoLineSeries.h +++ b/src/Brain/SelectionItemChartTwoLineSeries.h @@ -28,6 +28,7 @@ namespace caret { + class ChartTwoDataCartesian; class ChartableTwoFileLineSeriesChart; class SelectionItemChartTwoLineSeries : public SelectionItem { @@ -45,11 +46,14 @@ namespace caret { virtual void reset() override; - ChartableTwoFileLineSeriesChart* getFileLineSeriesChart() const; + const ChartableTwoFileLineSeriesChart* getFileLineSeriesChart() const; + + const ChartTwoDataCartesian* getChartTwoCartesianData() const; int32_t getLineSegmentIndex() const; void setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, + ChartTwoDataCartesian* chartTwoCartesianData, const int32_t lineSegmentIndex); // ADD_NEW_METHODS_HERE @@ -59,6 +63,8 @@ namespace caret { ChartableTwoFileLineSeriesChart* m_fileLineSeriesChart; + ChartTwoDataCartesian* m_chartTwoCartesianData; + int32_t m_lineSegmentIndex; // ADD_NEW_MEMBERS_HERE diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index ff24e815b..c11b45a44 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -30,6 +30,7 @@ #include "CaretAssert.h" #include "ChartPoint.h" #include "GraphicsPrimitiveV3f.h" +#include "MapFileDataSelector.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -97,6 +98,8 @@ ChartTwoDataCartesian::~ChartTwoDataCartesian() void ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() { + m_mapFileDataSelector = std::unique_ptr(new MapFileDataSelector()); + m_boundsValid = false; m_color = CaretColorEnum::RED; m_timeStartInSecondsAxisX = 0.0; @@ -139,6 +142,9 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() &m_timeStartInSecondsAxisX); m_sceneAssistant->add("m_timeStepInSecondsAxisX", &m_timeStepInSecondsAxisX); + m_sceneAssistant->add("m_mapFileDataSelector", + "MapFileDataSelector", + m_mapFileDataSelector.get()); } /** @@ -157,6 +163,25 @@ ChartTwoDataCartesian::createGraphicsPrimitive() return std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(m_graphicsPrimitiveType, rgba)); } + +/** + * @return The map file data selector that will indicate the source of data for this data. + */ +const MapFileDataSelector* +ChartTwoDataCartesian::getMapFileDataSelector() const +{ + return m_mapFileDataSelector.get(); +} + +/** + * @param + */ +void +ChartTwoDataCartesian::setMapFileDataSelector(const MapFileDataSelector& mapFileDataSelector) +{ + *m_mapFileDataSelector = mapFileDataSelector; +} + /** * Remove all points in the model. */ @@ -232,6 +257,8 @@ void ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj) { CaretAssert(0); + + *m_mapFileDataSelector = *obj.m_mapFileDataSelector; m_dataAxisUnitsX = obj.m_dataAxisUnitsX; m_dataAxisUnitsY = obj.m_dataAxisUnitsY; diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index 5cc706025..ff9b402f0 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -31,6 +31,7 @@ namespace caret { class ChartPoint; class GraphicsPrimitiveV3f; + class MapFileDataSelector; class ChartTwoDataCartesian : public ChartTwoData { @@ -58,6 +59,10 @@ namespace caret { GraphicsPrimitiveV3f* getGraphicsPrimitive() const; + const MapFileDataSelector* getMapFileDataSelector() const; + + void setMapFileDataSelector(const MapFileDataSelector& mapFileDataSelector); + ChartAxisUnitsEnum::Enum getDataAxisUnitsX(); ChartAxisUnitsEnum::Enum getDataAxisUnitsY(); @@ -97,6 +102,8 @@ namespace caret { std::unique_ptr createGraphicsPrimitive(); + std::unique_ptr m_mapFileDataSelector; + std::vector m_points; std::unique_ptr m_graphicsPrimitive; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 22dbbbeb8..4182395c2 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -218,6 +218,8 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabI break; } + std::cout << "Load data requested for file " << getCaretMappableDataFile()->getFileNameNoPath() << std::endl; + if (loadDataFlag) { std::vector data; getCaretMappableDataFile()->getDataForSelector(mapFileDataSelector, @@ -231,6 +233,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabI xUnits, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, GraphicsPrimitive::PrimitiveType::LINES); + cartesianData->setMapFileDataSelector(mapFileDataSelector); float x = 0.0f; float xStep = 0.0f; diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 54c3445bc..e800812f6 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -6886,11 +6886,74 @@ CiftiMappableDataFile::getDataForSelector(const MapFileDataSelector& mapFileData } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + { + try { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t surfaceNumberOfVertices = -1; + std::vector vertexIndices; + mapFileDataSelector.getSurfaceVertexAverage(structure, + surfaceNumberOfVertices, + vertexIndices); + + if (getMappingSurfaceNumberOfNodes(structure) == surfaceNumberOfVertices) { + const int32_t numberOfVertices = static_cast(vertexIndices.size()); + if (numberOfVertices > 0) { + std::vector dataSum; + int32_t dataSumSize = 0; + int32_t dataAverageCount = 0; + + std::vector data; + bool firstNodeFlag = true; + + for (int32_t i = 0; i < numberOfVertices; i++) { + if (getSeriesDataForSurfaceNode(structure, + vertexIndices[i], + data)) { + if (firstNodeFlag) { + firstNodeFlag = false; + + dataSumSize = static_cast(data.size()); + if (dataSumSize > 0) { + dataSum.resize(dataSumSize, + 0.0); + } + } + + CaretAssert(dataSumSize == static_cast(data.size())); + + for (int32_t j = 0; j < dataSumSize; j++) { + dataSum[j] += data[j]; + } + dataAverageCount++; + } + } + + if ((dataAverageCount > 0) + && (dataSumSize > 0)) { + dataOut.resize(dataSumSize); + for (int32_t k = 0; k < dataSumSize; k++) { + dataOut[k] = dataSum[k] / dataAverageCount; + } + } + } + } + } + catch (const DataFileException& dfe) { + CaretLogWarning("Exeception: " + + dfe.whatString()); + dataOut.clear(); + } + } break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + { + float xyz[3]; + mapFileDataSelector.getVolumeVoxelXYZ(xyz); + getSeriesDataForVoxelAtCoordinate(xyz, + dataOut); + } break; } - } diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index 2bff347fa..f5102c1da 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -993,7 +993,7 @@ GiftiTypeFile::addToDataFileContentInformation(DataFileContentInformation& dataF * Output with data. Will be empty if data does not support the map file data selector. */ void -GiftiTypeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, +GiftiTypeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); diff --git a/src/Files/MetricFile.cxx b/src/Files/MetricFile.cxx index 98b2409b2..f5c93d16b 100644 --- a/src/Files/MetricFile.cxx +++ b/src/Files/MetricFile.cxx @@ -25,6 +25,7 @@ #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "GiftiFile.h" +#include "MapFileDataSelector.h" #include "MathFunctions.h" #include "MetricFile.h" #include "NiftiEnums.h" @@ -617,6 +618,101 @@ MetricFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float * /*xyz[3]*/ return chartData; } +/** + * Get data from the file as requested in the given map file data selector. + * + * @param mapFileDataSelector + * Specifies selection of data. + * @param dataOut + * Output with data. Will be empty if data does not support the map file data selector. + */ +void +MetricFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const +{ + dataOut.clear(); + + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + try { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t surfaceNumberOfVertices = -1; + int32_t vertexIndex = -1; + mapFileDataSelector.getSurfaceVertex(structure, + surfaceNumberOfVertices, + vertexIndex); + + if ((structure == getStructure()) + && (surfaceNumberOfVertices == getNumberOfNodes())) { + const int32_t numMaps = getNumberOfMaps(); + + for (int64_t iMap = 0; iMap < numMaps; iMap++) { + dataOut.push_back(getValue(vertexIndex, + iMap)); + } + } + } + catch (const DataFileException& dfe) { + CaretLogWarning("Exeception: " + + dfe.whatString()); + dataOut.clear(); + } + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + { + try { + StructureEnum::Enum structure = StructureEnum::INVALID; + int32_t surfaceNumberOfVertices = -1; + std::vector vertexIndices; + mapFileDataSelector.getSurfaceVertexAverage(structure, + surfaceNumberOfVertices, + vertexIndices); + + if ((structure == getStructure()) + && (surfaceNumberOfVertices == getNumberOfNodes())) { + const int32_t numberOfVertexIndices = static_cast(vertexIndices.size()); + const int32_t numberOfMaps = getNumberOfMaps(); + + if ((numberOfVertexIndices > 0) + && (numberOfMaps > 0)) { + + std::vector dataSum(numberOfMaps, 0.0); + + for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { + CaretAssertVectorIndex(dataSum, iMap); + + for (int32_t iNode = 0; iNode < numberOfVertexIndices; iNode++) { + const int32_t nodeIndex = vertexIndices[iNode]; + dataSum[iMap] += getValue(nodeIndex, + iMap); + } + } + + dataOut.resize(numberOfMaps); + for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { + CaretAssertVectorIndex(dataSum, iMap); + + const float mapAverageValue = dataSum[iMap] / numberOfVertexIndices; + dataOut[iMap] = mapAverageValue; + } + } + } + } + catch (const DataFileException& dfe) { + CaretLogWarning("Exeception: " + + dfe.whatString()); + dataOut.clear(); + } + } + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + break; + } +} + + /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass diff --git a/src/Files/MetricFile.h b/src/Files/MetricFile.h index 8106ea2ba..f1ddb6e55 100644 --- a/src/Files/MetricFile.h +++ b/src/Files/MetricFile.h @@ -92,6 +92,10 @@ namespace caret { virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; + void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, + std::vector& dataOut) const; + + //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 9e7155462..f0aa60af0 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -36,6 +36,7 @@ #include "GroupAndNameHierarchyModel.h" #include "FastStatistics.h" #include "Histogram.h" +#include "MapFileDataSelector.h" #include "MultiDimIterator.h" #include "NiftiIO.h" #include "Palette.h" @@ -2240,9 +2241,37 @@ VolumeFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) * Output with data. Will be empty if data does not support the map file data selector. */ void -VolumeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, +VolumeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); + + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + { + if (isMappedWithPalette()) { + float xyz[3]; + mapFileDataSelector.getVolumeVoxelXYZ(xyz); + + int64_t ijk[3]; + enclosingVoxel(xyz, + ijk); + + if (indexValid(ijk)) { + const int32_t numMaps = getNumberOfMaps(); + for (int32_t iMap = 0; iMap < numMaps; iMap++) { + dataOut.push_back(getValue(ijk, iMap)); + } + } + } + } + break; + } } -- GitLab From a9c7b4655b348195672e0c48d651b4bd3b4454af Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Jun 2017 13:14:14 -0500 Subject: [PATCH 284/755] Removed storage of coordinates from ChartTwoDataCartesian since it contains a graphics primitive that contains coordinates. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 20 +-- src/Charting/ChartTwoDataCartesian.cxx | 167 ++---------------- src/Charting/ChartTwoDataCartesian.h | 17 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 4 - src/Files/MetricFile.h | 2 +- src/Graphics/GraphicsPrimitive.cxx | 81 ++++++++- src/Graphics/GraphicsPrimitive.h | 18 +- src/Graphics/GraphicsPrimitiveV3f.cxx | 11 +- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 11 +- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 7 +- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 11 +- 11 files changed, 128 insertions(+), 221 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index a88c9f70f..0ed52d3c3 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -758,26 +758,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); CaretAssert(data); - float boundsMinX = 0.0f; - float boundsMaxX = 0.0f; - float boundsMinY = 0.0f; - float boundsMaxY = 0.0f; - data->getBounds(boundsMinX, boundsMaxX, boundsMinY, boundsMaxY); - if (boundsMaxX > boundsMinX) { - xMin = std::min(xMin, boundsMinX); - xMax = std::max(xMax, boundsMaxX); + BoundingBox boundingBox; + if (data->getBounds(boundingBox)) { + xMin = std::min(xMin, boundingBox.getMinX()); + xMax = std::max(xMax, boundingBox.getMaxX()); switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - yMinRight = std::min(yMinRight, boundsMinY); - yMaxRight = std::max(yMaxRight, boundsMaxY); + yMinRight = std::min(yMinRight, boundingBox.getMinY()); + yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - yMinLeft = std::min(yMinLeft, boundsMinY); - yMaxLeft = std::max(yMaxLeft, boundsMaxY); + yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); + yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index c11b45a44..3fccb8e1c 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -27,6 +27,7 @@ #include +#include "BoundingBox.h" #include "CaretAssert.h" #include "ChartPoint.h" #include "GraphicsPrimitiveV3f.h" @@ -87,8 +88,6 @@ m_graphicsPrimitiveType(graphicsPrimitiveType) */ ChartTwoDataCartesian::~ChartTwoDataCartesian() { - removeAllPoints(); - delete m_sceneAssistant; } @@ -100,7 +99,6 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() { m_mapFileDataSelector = std::unique_ptr(new MapFileDataSelector()); - m_boundsValid = false; m_color = CaretColorEnum::RED; m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; @@ -182,24 +180,6 @@ ChartTwoDataCartesian::setMapFileDataSelector(const MapFileDataSelector& mapFile *m_mapFileDataSelector = mapFileDataSelector; } -/** - * Remove all points in the model. - */ -void -ChartTwoDataCartesian::removeAllPoints() -{ - m_graphicsPrimitive = createGraphicsPrimitive(); - - for (std::vector::const_iterator iter = m_points.begin(); - iter != m_points.end(); - iter++) { - delete *iter; - } - m_points.clear(); - - m_boundsValid = false; -} - /** * At times a copy of chart data will be needed BUT it must be * the proper subclass so copy constructor and assignment operator @@ -261,18 +241,9 @@ ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesi *m_mapFileDataSelector = *obj.m_mapFileDataSelector; m_dataAxisUnitsX = obj.m_dataAxisUnitsX; m_dataAxisUnitsY = obj.m_dataAxisUnitsY; - - removeAllPoints(); - - for (std::vector::const_iterator iter = obj.m_points.begin(); - iter != obj.m_points.end(); - iter++) { - const ChartPoint* cp = *iter; - m_points.push_back(new ChartPoint(*cp)); - } + m_graphicsPrimitive.reset(dynamic_cast(obj.m_graphicsPrimitive->clone())); - m_boundsValid = false; m_color = obj.m_color; m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; @@ -301,90 +272,20 @@ ChartTwoDataCartesian::addPoint(const float x, const float y) { m_graphicsPrimitive->addVertex(x, y); - m_points.push_back(new ChartPoint(x, y)); - m_boundsValid = false; -} - -/** - * @return Number of points. - */ -int32_t -ChartTwoDataCartesian::getNumberOfPoints() const -{ - return m_points.size(); } /** - * Get the point at the given index. + * Get a bounds box for the cartesian data. * - * @param pointIndex - * Index of point. + * @param boundingBoxOut + * Output bounding box. * @return - * Point at the given index. + * True if bounding box is valid, else false. */ -const ChartPoint* -ChartTwoDataCartesian::getPointAtIndex(const int32_t pointIndex) const +bool +ChartTwoDataCartesian::getBounds(BoundingBox& boundingBoxOut) const { - CaretAssertVectorIndex(m_points, pointIndex); - return m_points[pointIndex]; -} - -/** - * Get the bounds of all of the points. - * - * @param xMinimumOut - * Minimum X-coordinate of all points. - * @param xMaximumOut - * Maximum X-coordinate of all points. - * @param yMinimumOut - * Minimum Y-coordinate of all points. - * @param yMaximumOut - * Maximum Y-coordinate of all points. - */ -void -ChartTwoDataCartesian::getBounds(float& xMinimumOut, - float& xMaximumOut, - float& yMinimumOut, - float& yMaximumOut) const -{ - if (! m_boundsValid) { - float xMin = 0.0; - float xMax = 0.0; - float yMin = 0.0; - float yMax = 0.0; - float zMin = 0.0; - float zMax = 0.0; - const int32_t numPoints = getNumberOfPoints(); - if (numPoints > 0) { - xMin = std::numeric_limits::max(); - xMax = -std::numeric_limits::max(); - yMin = std::numeric_limits::max(); - yMax = -std::numeric_limits::max(); - for (int32_t i = 0; i < numPoints; i++) { - const float* xy = getPointAtIndex(i)->getXY(); - const float x = xy[0]; - const float y = xy[1]; - if (x < xMin) xMin = x; - if (x > xMax) xMax = x; - if (y < yMin) yMin = y; - if (y > yMax) yMax = y; - } - - m_boundsValid = true; - } - - m_bounds[0] = xMin; - m_bounds[1] = xMax; - m_bounds[2] = yMin; - m_bounds[3] = yMax; - m_bounds[4] = zMin; - m_bounds[5] = zMax; - } - - xMinimumOut = m_bounds[0]; - xMaximumOut = m_bounds[1]; - yMinimumOut = m_bounds[2]; - yMaximumOut = m_bounds[3]; + return m_graphicsPrimitive->getVertexBounds(boundingBoxOut); } /** @@ -500,25 +401,9 @@ ChartTwoDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttri m_sceneAssistant->saveMembers(sceneAttributes, chartDataCartesian); - - const int32_t numPoints2D = getNumberOfPoints(); - if (numPoints2D > 0) { - chartDataCartesian->addInteger("numberOfPoints2D", - numPoints2D); - - AString pointString; - pointString.reserve(numPoints2D * 2 * 10); - QTextStream textStream(&pointString, - QIODevice::WriteOnly); - - for (int32_t i = 0; i < numPoints2D; i++) { - const float* xy = m_points[i]->getXY(); - textStream << xy[0] << " " << xy[1] << " "; - } - - chartDataCartesian->addString("points2D", - pointString); - } + + sceneClass->addClass(m_mapFileDataSelector->saveToScene(sceneAttributes, + "m_mapFileDataSelector")); sceneClass->addClass(chartDataCartesian); } @@ -539,7 +424,7 @@ void ChartTwoDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { - removeAllPoints(); + m_graphicsPrimitive = createGraphicsPrimitive(); const SceneClass* chartDataCartesian = sceneClass->getClass("chartDataCartesian"); if (chartDataCartesian == NULL) { @@ -548,30 +433,6 @@ ChartTwoDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* scene m_sceneAssistant->restoreMembers(sceneAttributes, chartDataCartesian); - const int32_t numPoints2D = chartDataCartesian->getIntegerValue("numberOfPoints2D", - -1); - - if (numPoints2D > 0) { - AString pointString = chartDataCartesian->getStringValue("points2D", - ""); - if ( ! pointString.isEmpty()) { - float x, y; - QTextStream textStream(&pointString, - QIODevice::ReadOnly); - for (int32_t i = 0; i < numPoints2D; i++) { - if (textStream.atEnd()) { - sceneAttributes->addToErrorMessage("Tried to read " - + AString::number(numPoints2D) - + " but only got " - + AString::number(i)); - break; - } - - textStream >> x; - textStream >> y; - m_points.push_back(new ChartPoint(x, y)); - } - } - } + m_mapFileDataSelector->restoreFromScene(sceneAttributes, sceneClass->getClass("m_mapFileDataSelector")); } diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index ff9b402f0..d2f0aa328 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -48,14 +48,7 @@ namespace caret { void addPoint(const float x, const float y); - int32_t getNumberOfPoints() const; - - const ChartPoint* getPointAtIndex(const int32_t pointIndex) const; - - void getBounds(float& xMinimumOut, - float& xMaximumOut, - float& yMinimumOut, - float& yMaximumOut) const; + bool getBounds(BoundingBox& boundingBoxOut) const; GraphicsPrimitiveV3f* getGraphicsPrimitive() const; @@ -98,20 +91,12 @@ namespace caret { void initializeMembersChartTwoDataCartesian(); - void removeAllPoints(); - std::unique_ptr createGraphicsPrimitive(); std::unique_ptr m_mapFileDataSelector; - std::vector m_points; - std::unique_ptr m_graphicsPrimitive; - mutable float m_bounds[6]; - - mutable bool m_boundsValid; - ChartAxisUnitsEnum::Enum m_dataAxisUnitsX; ChartAxisUnitsEnum::Enum m_dataAxisUnitsY; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 4182395c2..daab74ae9 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -218,15 +218,11 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabI break; } - std::cout << "Load data requested for file " << getCaretMappableDataFile()->getFileNameNoPath() << std::endl; - if (loadDataFlag) { std::vector data; getCaretMappableDataFile()->getDataForSelector(mapFileDataSelector, data); if ( ! data.empty()) { - std::cout << "Loaded data for file " << getCaretMappableDataFile()->getFileNameNoPath() << std::endl; - const ChartAxisUnitsEnum::Enum xUnits = getChartTwoCompoundDataType().getLineChartUnitsAxisX(); CaretAssert(getChartTwoCompoundDataType().getLineChartNumberOfElementsAxisX() == static_cast(data.size())); ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, diff --git a/src/Files/MetricFile.h b/src/Files/MetricFile.h index f1ddb6e55..b22298dda 100644 --- a/src/Files/MetricFile.h +++ b/src/Files/MetricFile.h @@ -93,7 +93,7 @@ namespace caret { virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, - std::vector& dataOut) const; + std::vector& dataOut) const override; //override writeFile in order to check filename against type of file diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index d2ce8e283..0b366c80b 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -23,6 +23,7 @@ #include "GraphicsPrimitive.h" #undef __GRAPHICS_PRIMITIVE_DECLARE__ +#include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" @@ -68,7 +69,8 @@ GraphicsPrimitive::GraphicsPrimitive(const VertexType vertexType, m_normalVectorType(normalVectorType), m_colorType(colorType), m_textureType(textureType), - m_primitiveType(primitiveType) + m_primitiveType(primitiveType), + m_boundingBoxValid(false) { } @@ -92,8 +94,9 @@ GraphicsPrimitive::GraphicsPrimitive(const GraphicsPrimitive& obj) m_vertexType(obj.m_vertexType), m_normalVectorType(obj.m_normalVectorType), m_colorType(obj.m_colorType), -m_textureType(obj.m_textureType), -m_primitiveType(obj.m_primitiveType) + m_textureType(obj.m_textureType), + m_primitiveType(obj.m_primitiveType), + m_boundingBoxValid(false) { this->copyHelperGraphicsPrimitive(obj); } @@ -106,6 +109,7 @@ m_primitiveType(obj.m_primitiveType) void GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) { + m_boundingBoxValid = false; m_xyz = obj.m_xyz; m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; m_floatRGBA = obj.m_floatRGBA; @@ -165,6 +169,8 @@ GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) m_floatTextureSTR.reserve(numberOfVertices * 3); break; } + + m_boundingBoxValid = false; } /** @@ -568,6 +574,42 @@ GraphicsPrimitive::isAlternativeUnsignedByteRGBAValidProtected(const int32_t ide return false; } +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + */ +void +GraphicsPrimitive::addVertexProtected(const float xyz[3]) +{ + m_xyz.insert(m_xyz.end(), + xyz, xyz + 3); + m_boundingBoxValid = false; +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + */ +void +GraphicsPrimitive::addVertexProtected(const float x, + const float y, + const float z) +{ + m_xyz.push_back(x); + m_xyz.push_back(y); + m_xyz.push_back(z); + m_boundingBoxValid = false; +} + + /** * Replace the existing XYZ coordinates with the given * XYZ coordinates. The existing and new coordinates @@ -591,6 +633,39 @@ GraphicsPrimitive::replaceFloatXYZ(const std::vector& xyz) CaretLogWarning(msg); CaretAssertMessage(0, msg); } + + m_boundingBoxValid = false; +} + +/** + * Get a bounds box for the vertex coordinates. + * + * @param boundingBoxOut + * Output bounding box. + * @return + * True if bounding box is valid, else false. + */ +bool +GraphicsPrimitive::getVertexBounds(BoundingBox& boundingBoxOut) const +{ + if ( ! m_boundingBoxValid) { + if (m_boundingBox == NULL) { + m_boundingBox.reset(new BoundingBox()); + } + m_boundingBox->resetForUpdate(); + + const int32_t numberOfVertices = static_cast(m_xyz.size() / 3); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(m_xyz, i3 + 2); + m_boundingBox->update(&m_xyz[i3]); + } + + m_boundingBoxValid = true; + } + + boundingBoxOut = *m_boundingBox; + return m_boundingBoxValid; } diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index d968950d8..e58dc2f7d 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -26,12 +26,12 @@ #include #include "CaretObject.h" - #include "EventListenerInterface.h" namespace caret { + class BoundingBox; class GraphicsEngineDataOpenGL; class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; @@ -239,6 +239,8 @@ namespace caret { void replaceFloatXYZ(const std::vector& xyz); + bool getVertexBounds(BoundingBox& boundingBoxOut) const; + GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); @@ -273,6 +275,12 @@ namespace caret { const int32_t imageWidth, const int32_t imageHeight); + void addVertexProtected(const float xyz[3]); + + void addVertexProtected(const float x, + const float y, + const float z); + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; @@ -283,12 +291,12 @@ namespace caret { const PrimitiveType m_primitiveType; + mutable bool m_boundingBoxValid = false; + UsageType m_usageType = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; std::unique_ptr m_graphicsEngineDataForOpenGL; - std::vector m_xyz; - std::vector m_floatNormalVectorXYZ; std::vector m_floatRGBA; @@ -307,7 +315,11 @@ namespace caret { int32_t m_textureImageHeight = -1; + mutable std::unique_ptr m_boundingBox; + private: + std::vector m_xyz; + void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); friend class GraphicsEngineDataOpenGL; diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index 8c9e2bfbe..de19238a7 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -125,8 +125,7 @@ GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& void GraphicsPrimitiveV3f::addVertex(const float xyz[3]) { - m_xyz.insert(m_xyz.end(), - xyz, xyz + 3); + addVertexProtected(xyz); switch (m_colorType) { case GraphicsPrimitive::ColorType::NONE: @@ -158,9 +157,7 @@ GraphicsPrimitiveV3f::addVertex(const float x, const float y, const float z) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(z); + addVertexProtected(x, y, z); switch (m_colorType) { case GraphicsPrimitive::ColorType::NONE: CaretAssert(0); @@ -190,9 +187,7 @@ void GraphicsPrimitiveV3f::addVertex(const float x, const float y) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(0.0); + addVertexProtected(x, y, 0.0f); switch (m_colorType) { case GraphicsPrimitive::ColorType::NONE: CaretAssert(0); diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 1ccff81f3..d759e4d69 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -91,8 +91,7 @@ void GraphicsPrimitiveV3fC4f::addVertex(const float xyz[3], const float rgba[4]) { - m_xyz.insert(m_xyz.end(), - xyz, xyz + 3); + addVertexProtected(xyz); m_floatRGBA.insert(m_floatRGBA.end(), rgba, rgba + 4); } @@ -115,9 +114,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float z, const float rgba[4]) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(z); + addVertexProtected(x, y, z); m_floatRGBA.insert(m_floatRGBA.end(), rgba, rgba + 4); } @@ -137,9 +134,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float rgba[4]) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(0.0); + addVertexProtected(x, y, 0.0f); m_floatRGBA.insert(m_floatRGBA.end(), rgba, rgba + 4); } diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 017c83f3a..0558d59d3 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -91,8 +91,7 @@ void GraphicsPrimitiveV3fC4ub::addVertex(const float xyz[3], const uint8_t rgba[4]) { - m_xyz.insert(m_xyz.end(), - xyz, xyz + 3); + addVertexProtected(xyz); m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), rgba, rgba + 4); } @@ -115,9 +114,7 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, const float z, const uint8_t rgba[4]) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(z); + addVertexProtected(x, y, z); m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), rgba, rgba + 4); } diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 56e60489c..39da63b74 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -102,8 +102,7 @@ void GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], const float st[2]) { - m_xyz.insert(m_xyz.end(), - xyz, xyz + 3); + addVertexProtected(xyz); m_floatTextureSTR.push_back(st[0]); m_floatTextureSTR.push_back(st[1]); m_floatTextureSTR.push_back(0.0f); @@ -130,9 +129,7 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(z); + addVertexProtected(x, y, z); m_floatTextureSTR.push_back(s); m_floatTextureSTR.push_back(t); m_floatTextureSTR.push_back(0.0f); @@ -156,9 +153,7 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(0.0f); + addVertexProtected(x, y, 0.0f); m_floatTextureSTR.push_back(s); m_floatTextureSTR.push_back(t); m_floatTextureSTR.push_back(0.0f); -- GitLab From b757686a5719ede89b871ba9bfec64a59b2d9832 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Jun 2017 09:30:05 -0500 Subject: [PATCH 285/755] Implemented Chart Two Line Series History Dialog. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 743 +++++++++--------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 2 +- src/Brain/ChartTwoOverlay.cxx | 20 +- src/Brain/ChartTwoOverlay.h | 11 +- src/Brain/ChartTwoOverlaySet.cxx | 174 ++-- src/Brain/ChartTwoOverlaySet.h | 24 +- src/Charting/ChartTwoData.cxx | 39 +- src/Charting/ChartTwoData.h | 10 +- src/Charting/ChartTwoDataCartesian.cxx | 32 +- src/Charting/ChartTwoLineSeriesHistory.cxx | 71 +- src/Charting/ChartTwoLineSeriesHistory.h | 10 +- src/Charting/MapFileDataSelector.cxx | 25 +- src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 1 + src/GuiQt/CMakeLists.txt | 5 + src/GuiQt/CaretColorEnumComboBox.cxx | 9 + src/GuiQt/CaretColorEnumComboBox.h | 2 + src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 464 +++++++++++ src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 119 +++ src/GuiQt/ChartTwoOverlayViewController.cxx | 44 +- ...entChartTwoShowLineSeriesHistoryDialog.cxx | 92 +++ ...EventChartTwoShowLineSeriesHistoryDialog.h | 78 ++ src/GuiQt/GuiManager.cxx | 58 ++ src/GuiQt/GuiManager.h | 3 + 26 files changed, 1548 insertions(+), 495 deletions(-) create mode 100644 src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx create mode 100644 src/GuiQt/ChartTwoLineSeriesHistoryDialog.h create mode 100644 src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx create mode 100644 src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0ed52d3c3..0349eac61 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -256,7 +256,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (drawHistogramFlag) { drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); - //drawHistogramChart(); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: @@ -279,352 +278,352 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, annotationChartGraphicsLabelsOut = m_annotationDrawingChartGraphicsLabels; } -/** - * Draw histogram charts. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() -{ - const int32_t vpX = m_viewport[0]; - const int32_t vpY = m_viewport[1]; - const int32_t vpWidth = m_viewport[2]; - const int32_t vpHeight = m_viewport[3]; - - int32_t chartGraphicsDrawingViewport[4] = { - vpX, - vpY, - vpWidth, - vpHeight - }; - - const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); - CaretAssert(numberOfOverlays > 0); - const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); - const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); - CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); - - std::vector> drawingInfo; - - /* - * Get the histogram drawing information and overall extent - */ - float xMin = std::numeric_limits::max(); - float xMax = -std::numeric_limits::max(); - float yMinLeft = std::numeric_limits::max(); - float yMaxLeft = -std::numeric_limits::max(); - float yMinRight = std::numeric_limits::max(); - float yMaxRight = -std::numeric_limits::max(); - for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { - ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); - if ( ! chartOverlay->isEnabled()) { - continue; - } - - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; - int32_t selectedIndex = -1; - chartOverlay->getSelectionData(mapFile, - selectedIndexType, - selectedIndex); - if (mapFile == NULL) { - continue; - } - - ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); - ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); - - if (histogramChart->isValid()) { - CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); - AString errorMessage; - drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, - selectedIndex, - chartOverlay->getCartesianVerticalAxisLocation(), - (chartOverlay->isAllMapsSupported() - && chartOverlay->isAllMapsSelected())))); - const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, - (chartOverlay->isAllMapsSupported() - && chartOverlay->isAllMapsSelected())); - CaretAssert(histogram); - float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; - histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); - if (histogramMaxX > histogramMinX) { - xMin = std::min(xMin, histogramMinX); - xMax = std::max(xMax, histogramMaxX); - - switch (chartOverlay->getCartesianVerticalAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - yMinRight = std::min(yMinRight, 0.0f); - yMaxRight = std::max(yMaxRight, histogramMaxY); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - yMinLeft = std::min(yMinLeft, 0.0f); - yMaxLeft = std::max(yMaxLeft, histogramMaxY); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); - break; - } - } - } - } - - /* - * Bounds valid? - */ - if ((xMin < xMax) - && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { - /* - * Margin is region around the chart in which - * the axes legends, values, and ticks are drawn. - */ - const double marginSize = 10; - Margins margins(marginSize); - - ChartTwoCartesianAxis* leftAxis = NULL; - ChartTwoCartesianAxis* rightAxis = NULL; - ChartTwoCartesianAxis* bottomAxis = NULL; - ChartTwoCartesianAxis* topAxis = NULL; - - std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); - for (auto axis : displayedAxes) { - CaretAssert(axis); - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - bottomAxis = axis; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - leftAxis = axis; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - rightAxis = axis; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - topAxis = axis; - break; - } - } - - const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; - const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; - double width = 0.0, height = 0.0; - - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); - margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); - margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); - margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); - margins.m_bottom = std::max(margins.m_bottom, height); - - if (margins.m_left > marginSize) margins.m_left += 10; - if (margins.m_right > marginSize) margins.m_right += 10; - - /* - * Ensure that there is sufficient space for the axes data display. - */ - if ((vpWidth > (marginSize * 3)) - && (vpHeight > (marginSize * 3))) { - - float axisMinimumValue = 0.0; - float axisMaximumValue = 0.0; - - /* Draw legends and grids */ - if (drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - leftAxis, - axisMinimumValue, - axisMaximumValue)) { - yMinLeft = axisMinimumValue; - yMaxLeft = axisMaximumValue; - } - - if (drawChartAxisCartesian(boundsRight, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - rightAxis, - axisMinimumValue, - axisMaximumValue)) { - yMinRight = axisMinimumValue; - yMaxRight = axisMaximumValue; - } - if (drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - bottomAxis, - axisMinimumValue, - axisMaximumValue)) { - xMin = axisMinimumValue; - xMax = axisMaximumValue; - } - - drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, - margins, - topAxis, - axisMinimumValue, - axisMaximumValue); - - drawChartGraphicsBoxAndSetViewport(vpX, - vpY, - vpWidth, - vpHeight, - margins, - chartGraphicsDrawingViewport); - } - - glViewport(chartGraphicsDrawingViewport[0], - chartGraphicsDrawingViewport[1], - chartGraphicsDrawingViewport[2], - chartGraphicsDrawingViewport[3]); - - - /* - * Draw the bars for all histogram and then draw the envelopes - * so the envelopes are not obscured by the bars - */ - for (auto& drawInfo : drawingInfo) { - if (drawInfo->m_histogramChart->isValid()) { - const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); - CaretAssert(cmdf); - const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); - const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); - const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); - - if (drawBarsFlag - || drawEnvelopeFlag) { - bool leftVerticalAxisFlag = true; - switch (drawInfo->m_verticalAxisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - leftVerticalAxisFlag = false; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - break; - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (leftVerticalAxisFlag) { - glOrtho(xMin, xMax, - yMinLeft, yMaxLeft, - -10.0, 10.0); - } - else { - glOrtho(xMin, xMax, - yMinRight, yMaxRight, - -10.0, 10.0); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - bool applyTransformationsFlag = false; - if (applyTransformationsFlag) { - glTranslatef(m_translation[0], - m_translation[1], - 0.0); - - const float chartWidth = chartGraphicsDrawingViewport[2]; - const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; - glTranslatef(halfWidth, - halfHeight, - 0.0); - glScalef(m_zooming, - m_zooming, - 1.0); - glTranslatef(-halfWidth, - -halfHeight, - 0.0); - } - - ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = - drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, - drawInfo->m_allMapsSelected); - if (histogramPrimitives != NULL) { - const float ENVELOPE_LINE_WIDTH = 1.0; - - if (m_identificationModeFlag) { - int32_t primitiveIndex = -1; - float primitiveDepth = 0.0; - - if (drawBarsFlag) { - /* - * Scale histogram bars in Y-axis so that identification - * will function when mouse is above a bar. This is helpful - * for identification of bars with a very small height. - */ - glPushMatrix(); - glScalef(1.0, 1000.0, 1.0); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - histogramPrimitives->getBarsPrimitive(), - m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - primitiveIndex, - primitiveDepth); - glPopMatrix(); - } - else if (drawEnvelopeFlag) { - /* - * Increase line width for identification - */ - glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - histogramPrimitives->getEnvelopePrimitive(), - m_fixedPipelineDrawing->mouseX, - m_fixedPipelineDrawing->mouseY, - primitiveIndex, - primitiveDepth); - } - - if (primitiveIndex >= 0) { - if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { - m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), - drawInfo->m_mapIndex, - primitiveIndex, - drawInfo->m_allMapsSelected); - } - } - } - else { - drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); - if (drawBarsFlag) { - drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); - } - if (drawEnvelopeFlag) { - glLineWidth(ENVELOPE_LINE_WIDTH); - m_fixedPipelineDrawing->enableLineAntiAliasing(); - drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); - m_fixedPipelineDrawing->disableLineAntiAliasing(); - } - } - } - } - } - } - } -} +///** +// * Draw histogram charts. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() +//{ +// const int32_t vpX = m_viewport[0]; +// const int32_t vpY = m_viewport[1]; +// const int32_t vpWidth = m_viewport[2]; +// const int32_t vpHeight = m_viewport[3]; +// +// int32_t chartGraphicsDrawingViewport[4] = { +// vpX, +// vpY, +// vpWidth, +// vpHeight +// }; +// +// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); +// CaretAssert(numberOfOverlays > 0); +// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); +// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); +// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); +// +// std::vector> drawingInfo; +// +// /* +// * Get the histogram drawing information and overall extent +// */ +// float xMin = std::numeric_limits::max(); +// float xMax = -std::numeric_limits::max(); +// float yMinLeft = std::numeric_limits::max(); +// float yMaxLeft = -std::numeric_limits::max(); +// float yMinRight = std::numeric_limits::max(); +// float yMaxRight = -std::numeric_limits::max(); +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; +// int32_t selectedIndex = -1; +// chartOverlay->getSelectionData(mapFile, +// selectedIndexType, +// selectedIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// +// if (histogramChart->isValid()) { +// CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); +// AString errorMessage; +// drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, +// selectedIndex, +// chartOverlay->getCartesianVerticalAxisLocation(), +// (chartOverlay->isAllMapsSupported() +// && chartOverlay->isAllMapsSelected())))); +// const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, +// (chartOverlay->isAllMapsSupported() +// && chartOverlay->isAllMapsSelected())); +// CaretAssert(histogram); +// float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; +// histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); +// if (histogramMaxX > histogramMinX) { +// xMin = std::min(xMin, histogramMinX); +// xMax = std::max(xMax, histogramMaxX); +// +// switch (chartOverlay->getCartesianVerticalAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// yMinRight = std::min(yMinRight, 0.0f); +// yMaxRight = std::max(yMaxRight, histogramMaxY); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// yMinLeft = std::min(yMinLeft, 0.0f); +// yMaxLeft = std::max(yMaxLeft, histogramMaxY); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); +// break; +// } +// } +// } +// } +// +// /* +// * Bounds valid? +// */ +// if ((xMin < xMax) +// && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { +// /* +// * Margin is region around the chart in which +// * the axes legends, values, and ticks are drawn. +// */ +// const double marginSize = 10; +// Margins margins(marginSize); +// +// ChartTwoCartesianAxis* leftAxis = NULL; +// ChartTwoCartesianAxis* rightAxis = NULL; +// ChartTwoCartesianAxis* bottomAxis = NULL; +// ChartTwoCartesianAxis* topAxis = NULL; +// +// std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); +// for (auto axis : displayedAxes) { +// CaretAssert(axis); +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// bottomAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// leftAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// rightAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// topAxis = axis; +// break; +// } +// } +// +// const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; +// const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; +// double width = 0.0, height = 0.0; +// +// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); +// margins.m_left = std::max(margins.m_left, width); +// estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); +// margins.m_right = std::max(margins.m_right, width); +// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); +// margins.m_top = std::max(margins.m_top, height); +// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); +// margins.m_bottom = std::max(margins.m_bottom, height); +// +// if (margins.m_left > marginSize) margins.m_left += 10; +// if (margins.m_right > marginSize) margins.m_right += 10; +// +// /* +// * Ensure that there is sufficient space for the axes data display. +// */ +// if ((vpWidth > (marginSize * 3)) +// && (vpHeight > (marginSize * 3))) { +// +// float axisMinimumValue = 0.0; +// float axisMaximumValue = 0.0; +// +// /* Draw legends and grids */ +// if (drawChartAxisCartesian(boundsLeftBottomTop, +// vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// leftAxis, +// axisMinimumValue, +// axisMaximumValue)) { +// yMinLeft = axisMinimumValue; +// yMaxLeft = axisMaximumValue; +// } +// +// if (drawChartAxisCartesian(boundsRight, +// vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// rightAxis, +// axisMinimumValue, +// axisMaximumValue)) { +// yMinRight = axisMinimumValue; +// yMaxRight = axisMaximumValue; +// } +// if (drawChartAxisCartesian(boundsLeftBottomTop, +// vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// bottomAxis, +// axisMinimumValue, +// axisMaximumValue)) { +// xMin = axisMinimumValue; +// xMax = axisMaximumValue; +// } +// +// drawChartAxisCartesian(boundsLeftBottomTop, +// vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// topAxis, +// axisMinimumValue, +// axisMaximumValue); +// +// drawChartGraphicsBoxAndSetViewport(vpX, +// vpY, +// vpWidth, +// vpHeight, +// margins, +// chartGraphicsDrawingViewport); +// } +// +// glViewport(chartGraphicsDrawingViewport[0], +// chartGraphicsDrawingViewport[1], +// chartGraphicsDrawingViewport[2], +// chartGraphicsDrawingViewport[3]); +// +// +// /* +// * Draw the bars for all histogram and then draw the envelopes +// * so the envelopes are not obscured by the bars +// */ +// for (auto& drawInfo : drawingInfo) { +// if (drawInfo->m_histogramChart->isValid()) { +// const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); +// CaretAssert(cmdf); +// const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); +// const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); +// const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); +// +// if (drawBarsFlag +// || drawEnvelopeFlag) { +// bool leftVerticalAxisFlag = true; +// switch (drawInfo->m_verticalAxisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// leftVerticalAxisFlag = false; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// break; +// } +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// if (leftVerticalAxisFlag) { +// glOrtho(xMin, xMax, +// yMinLeft, yMaxLeft, +// -10.0, 10.0); +// } +// else { +// glOrtho(xMin, xMax, +// yMinRight, yMaxRight, +// -10.0, 10.0); +// } +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool applyTransformationsFlag = false; +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = chartGraphicsDrawingViewport[2]; +// const float chartHeight = chartGraphicsDrawingViewport[3]; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = +// drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, +// drawInfo->m_allMapsSelected); +// if (histogramPrimitives != NULL) { +// const float ENVELOPE_LINE_WIDTH = 1.0; +// +// if (m_identificationModeFlag) { +// int32_t primitiveIndex = -1; +// float primitiveDepth = 0.0; +// +// if (drawBarsFlag) { +// /* +// * Scale histogram bars in Y-axis so that identification +// * will function when mouse is above a bar. This is helpful +// * for identification of bars with a very small height. +// */ +// glPushMatrix(); +// glScalef(1.0, 1000.0, 1.0); +// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// histogramPrimitives->getBarsPrimitive(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// primitiveIndex, +// primitiveDepth); +// glPopMatrix(); +// } +// else if (drawEnvelopeFlag) { +// /* +// * Increase line width for identification +// */ +// glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); +// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// histogramPrimitives->getEnvelopePrimitive(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// primitiveIndex, +// primitiveDepth); +// } +// +// if (primitiveIndex >= 0) { +// if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { +// m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), +// drawInfo->m_mapIndex, +// primitiveIndex, +// drawInfo->m_allMapsSelected); +// } +// } +// } +// else { +// drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); +// if (drawBarsFlag) { +// drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); +// } +// if (drawEnvelopeFlag) { +// glLineWidth(ENVELOPE_LINE_WIDTH); +// m_fixedPipelineDrawing->enableLineAntiAliasing(); +// drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); +// m_fixedPipelineDrawing->disableLineAntiAliasing(); +// } +// } +// } +// } +// } +// } +// } +//} /** * Draw a histogram or line series chart. @@ -758,31 +757,33 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); CaretAssert(data); - BoundingBox boundingBox; - if (data->getBounds(boundingBox)) { - xMin = std::min(xMin, boundingBox.getMinX()); - xMax = std::max(xMax, boundingBox.getMaxX()); - - switch (chartOverlay->getCartesianVerticalAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - yMinRight = std::min(yMinRight, boundingBox.getMinY()); - yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); - yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); - break; + if (data->isSelected()) { + BoundingBox boundingBox; + if (data->getBounds(boundingBox)) { + xMin = std::min(xMin, boundingBox.getMinX()); + xMax = std::max(xMax, boundingBox.getMaxX()); + + switch (chartOverlay->getCartesianVerticalAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yMinRight = std::min(yMinRight, boundingBox.getMinY()); + yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); + yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); + break; + } + + lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, + data, + chartOverlay->getCartesianVerticalAxisLocation())); } - - lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, - data, - chartOverlay->getCartesianVerticalAxisLocation())); } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 559c6125e..a1542fd7c 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -131,7 +131,7 @@ namespace caret { const float cellHeight, const float zooming); - void drawHistogramChart(); + //void drawHistogramChart(); void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index a31dcadc4..d0aa1ae90 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -61,11 +61,13 @@ using namespace caret; * Index of this overlay. */ ChartTwoOverlay::ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, - const ChartTwoDataTypeEnum::Enum chartDataType, - const int32_t overlayIndex) + const ChartTwoDataTypeEnum::Enum chartDataType, + const int32_t tabIndex, + const int32_t overlayIndex) : CaretObject(), m_parentChartTwoOverlaySet(parentChartTwoOverlaySet), m_chartDataType(chartDataType), +m_tabIndex(tabIndex), m_overlayIndex(overlayIndex) { CaretAssert(m_parentChartTwoOverlaySet); @@ -237,6 +239,15 @@ ChartTwoOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& cha m_chartCompoundDataType = chartCompoundDataType; } +/** + * @return The tab index. + */ +int32_t +ChartTwoOverlay::getTabIndex() const +{ + return m_tabIndex; +} + /** * @return Enabled status for this surface overlay. */ @@ -337,8 +348,9 @@ void ChartTwoOverlay::swapData(ChartTwoOverlay* overlay) { std::unique_ptr swapOverlay = std::unique_ptr(new ChartTwoOverlay(m_parentChartTwoOverlaySet, - overlay->m_chartDataType, - overlay->m_overlayIndex)); + overlay->m_chartDataType, + overlay->m_tabIndex, + overlay->m_overlayIndex)); swapOverlay->copyData(overlay); overlay->copyData(this); diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index e848d2a14..35a238ded 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -50,8 +50,9 @@ namespace caret { }; ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, - const ChartTwoDataTypeEnum::Enum chartDataType, - const int32_t overlayIndex); + const ChartTwoDataTypeEnum::Enum chartDataType, + const int32_t tabIndex, + const int32_t overlayIndex); virtual ~ChartTwoOverlay(); @@ -61,7 +62,9 @@ namespace caret { void setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType); - AString getName() const; + int32_t getTabIndex() const; + + //AString getName() const; virtual AString toString() const; @@ -168,6 +171,8 @@ namespace caret { /** Enumerated Type of charts allowed in this overlay */ const ChartTwoDataTypeEnum::Enum m_chartDataType; + const int32_t m_tabIndex; + /** Index of this overlay (DO NOT COPY)*/ const int32_t m_overlayIndex; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 0933e61ce..3680fd7f6 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -102,8 +102,26 @@ m_tabIndex(tabIndex) } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { m_chartAxisLeft->setEnabledByChart(true); + m_chartAxisLeft->getAnnotationAxisLabel()->setText("Value"); + m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + float rangeMin = 0.0, rangeMax = 0.0; + m_chartAxisLeft->getRange(rangeMin, rangeMax); + rangeMin = 0.0; + m_chartAxisLeft->setRange(rangeMin, rangeMax); + + m_chartAxisRight->setEnabledByChart(false); + m_chartAxisRight->getAnnotationAxisLabel()->setText("Value"); + m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisRight->getRange(rangeMin, rangeMax); + rangeMin = 0.0; + m_chartAxisRight->setRange(rangeMin, rangeMax); + m_chartAxisBottom->setEnabledByChart(true); + m_chartAxisBottom->getAnnotationAxisLabel()->setText("Data"); + m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; @@ -124,8 +142,9 @@ m_tabIndex(tabIndex) for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays[i] = new ChartTwoOverlay(this, - m_chartDataType, - i); + m_chartDataType, + m_tabIndex, + i); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); @@ -173,6 +192,15 @@ ChartTwoOverlaySet::getPrimaryOverlay() return m_overlays[0]; } +/** + * @return Returns the top-most overlay regardless of its enabled status. + */ +const ChartTwoOverlay* +ChartTwoOverlaySet::getPrimaryOverlay() const +{ + return m_overlays[0]; +} + /** * Get the overlay at the specified index. * @param overlayNumber @@ -577,56 +605,70 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } } -/** - * @return The chart left-axis. - */ -ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisLeft() -{ - return m_chartAxisLeft.get(); -} - -/** - * @return The chart left-axis (const method) - */ -const ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisLeft() const -{ - return m_chartAxisLeft.get(); -} - -/** - * @return The chart right-axis. - */ -ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisRight() -{ - return m_chartAxisRight.get(); -} +///** +// * @return The chart left-axis. +// */ +//ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisLeft() +//{ +// return m_chartAxisLeft.get(); +//} +// +///** +// * @return The chart left-axis (const method) +// */ +//const ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisLeft() const +//{ +// return m_chartAxisLeft.get(); +//} +// +///** +// * @return The chart right-axis. +// */ +//ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisRight() +//{ +// return m_chartAxisRight.get(); +//} +// +///** +// * @return The chart right-axis (const method) +// */ +//const ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisRight() const +//{ +// return m_chartAxisRight.get(); +//} +// +///** +// * @return The chart bottom-axis. +// */ +//ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisBottom() +//{ +// return m_chartAxisBottom.get(); +//} +// +///** +// * @return The chart bottom-axis (const method) +// */ +//const ChartTwoCartesianAxis* +//ChartTwoOverlaySet::getChartAxisBottom() const +//{ +// return m_chartAxisBottom.get(); +//} /** - * @return The chart right-axis (const method) + * Get the displayed chart axes. */ -const ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisRight() const -{ - return m_chartAxisRight.get(); -} - -/** - * @return The chart bottom-axis. - */ -ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisBottom() -{ - return m_chartAxisBottom.get(); -} - std::vector ChartTwoOverlaySet::getDisplayedChartAxes() const { std::vector axes; + AString lineSeriesDataTypeName; + bool showAxesFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: @@ -635,6 +677,38 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const showAxesFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { + const ChartTwoOverlay* primaryOverlay = getPrimaryOverlay(); + if (primaryOverlay != NULL) { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType indexType; + int32_t mapIndex; + primaryOverlay->getSelectionData(mapFile, indexType, mapIndex); + if (mapFile != NULL) { + const NiftiTimeUnitsEnum::Enum units = mapFile->getMapIntervalUnits(); + switch (units) { + case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: + lineSeriesDataTypeName = "Hertz"; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: + lineSeriesDataTypeName = "milliseconds"; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: + lineSeriesDataTypeName = "parts per million"; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: + lineSeriesDataTypeName = "seconds"; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: + lineSeriesDataTypeName = "data"; + break; + case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: + lineSeriesDataTypeName = "microseconds"; + break; + } + } + } + } showAxesFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: @@ -680,6 +754,9 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const m_chartAxisRight->setEnabledByChart(showRightFlag); if (m_chartAxisBottom->isEnabledByChart()) { + if ( ! lineSeriesDataTypeName.isEmpty()) { + m_chartAxisBottom->getAnnotationAxisLabel()->setText(lineSeriesDataTypeName); + } axes.push_back(m_chartAxisBottom.get()); } if (m_chartAxisLeft->isEnabledByChart()) { @@ -693,15 +770,6 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const } -/** - * @return The chart bottom-axis (const method) - */ -const ChartTwoCartesianAxis* -ChartTwoOverlaySet::getChartAxisBottom() const -{ - return m_chartAxisBottom.get(); -} - /** * Save information specific to this type of model to the scene. * diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index dfb5ffcdc..b1820f70a 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -49,6 +49,8 @@ namespace caret { ChartTwoOverlay* getPrimaryOverlay(); + const ChartTwoOverlay* getPrimaryOverlay() const; + ChartTwoOverlay* getOverlay(const int32_t overlayNumber); const ChartTwoOverlay* getOverlay(const int32_t overlayNumber) const; @@ -61,17 +63,17 @@ namespace caret { ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); - ChartTwoCartesianAxis* getChartAxisLeft(); - - const ChartTwoCartesianAxis* getChartAxisLeft() const; - - ChartTwoCartesianAxis* getChartAxisRight(); - - const ChartTwoCartesianAxis* getChartAxisRight() const; - - ChartTwoCartesianAxis* getChartAxisBottom(); - - const ChartTwoCartesianAxis* getChartAxisBottom() const; +// ChartTwoCartesianAxis* getChartAxisLeft(); +// +// const ChartTwoCartesianAxis* getChartAxisLeft() const; +// +// ChartTwoCartesianAxis* getChartAxisRight(); +// +// const ChartTwoCartesianAxis* getChartAxisRight() const; +// +// ChartTwoCartesianAxis* getChartAxisBottom(); +// +// const ChartTwoCartesianAxis* getChartAxisBottom() const; std::vector getDisplayedChartAxes() const; diff --git a/src/Charting/ChartTwoData.cxx b/src/Charting/ChartTwoData.cxx index 0c2042aa9..980895134 100644 --- a/src/Charting/ChartTwoData.cxx +++ b/src/Charting/ChartTwoData.cxx @@ -70,17 +70,15 @@ void ChartTwoData::initializeMembersChartTwoData() { m_chartDataSource = new ChartDataSource(); - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectionStatus[i] = true; - } + m_selectionStatus = true; m_uniqueIdentifier = SystemUtilities::createUniqueID(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartDataSource", "ChartDataSource", m_chartDataSource); - m_sceneAssistant->addTabIndexedBooleanArray("m_selectionStatus", - m_selectionStatus); + m_sceneAssistant->add("m_selectionStatus", + &m_selectionStatus); m_sceneAssistant->add("m_uniqueIdentifier", &m_uniqueIdentifier); } @@ -129,9 +127,7 @@ ChartTwoData::copyHelperChartTwoData(const ChartTwoData& obj) CaretAssert(0); m_chartDataType = obj.m_chartDataType; *m_chartDataSource = *obj.m_chartDataSource; - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectionStatus[i] = obj.m_selectionStatus[i]; - } + m_selectionStatus = obj.m_selectionStatus; } /** @@ -250,15 +246,12 @@ ChartTwoData::getChartDataSource() } /** - * @return The selection status in the given tab - * @param tabIndex - * Index of the tab. + * @return The selection status */ bool -ChartTwoData::isSelected(const int32_t tabIndex) const +ChartTwoData::isSelected() const { - CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - return m_selectionStatus[tabIndex]; + return m_selectionStatus; } /** @@ -268,11 +261,9 @@ ChartTwoData::isSelected(const int32_t tabIndex) const * New selection status. */ void -ChartTwoData::setSelected(const int32_t tabIndex, - const bool selectionStatus) +ChartTwoData::setSelected(const bool selectionStatus) { - CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - m_selectionStatus[tabIndex] = selectionStatus; + m_selectionStatus = selectionStatus; /* * When selection status is true, @@ -291,13 +282,11 @@ ChartTwoData::setSelected(const int32_t tabIndex, * @param copyFrom * Chart data from which selection status is copied. */ -void -ChartTwoData::copySelectionStatusForAllTabs(const ChartTwoData* copyFrom) -{ - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_selectionStatus[i] = copyFrom->m_selectionStatus[i]; - } -} +//void +//ChartTwoData::copySelectionStatusForAllTabs(const ChartTwoData* copyFrom) +//{ +// m_selectionStatus = copyFrom->m_selectionStatus; +//} /** diff --git a/src/Charting/ChartTwoData.h b/src/Charting/ChartTwoData.h index b1f6623f7..5ca7ffc56 100644 --- a/src/Charting/ChartTwoData.h +++ b/src/Charting/ChartTwoData.h @@ -21,7 +21,6 @@ */ /*LICENSE_END*/ -#include "BrainConstants.h" #include "CaretObjectTracksModification.h" #include "ChartTwoDataTypeEnum.h" #include "SceneableInterface.h" @@ -56,10 +55,9 @@ namespace caret { ChartDataSource* getChartDataSource(); - bool isSelected(const int32_t tabIndex) const; + bool isSelected() const; - void setSelected(const int32_t tabIndex, - const bool selectionStatus); + void setSelected(const bool selectionStatus); void clearSelected(); @@ -67,7 +65,7 @@ namespace caret { void setUniqueIdentifier(const AString& uniqueIdentifier); - void copySelectionStatusForAllTabs(const ChartTwoData* copyFrom); + //void copySelectionStatusForAllTabs(const ChartTwoData* copyFrom); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -128,7 +126,7 @@ namespace caret { ChartDataSource* m_chartDataSource; - bool m_selectionStatus[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + bool m_selectionStatus; AString m_uniqueIdentifier; diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 3fccb8e1c..5bc404a91 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -34,6 +34,7 @@ #include "MapFileDataSelector.h" #include "SceneClass.h" #include "SceneClassAssistant.h" +#include "ScenePrimitiveArray.h" using namespace caret; @@ -402,8 +403,16 @@ ChartTwoDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttri m_sceneAssistant->saveMembers(sceneAttributes, chartDataCartesian); - sceneClass->addClass(m_mapFileDataSelector->saveToScene(sceneAttributes, - "m_mapFileDataSelector")); +// chartDataCartesian->addClass(m_mapFileDataSelector->saveToScene(sceneAttributes, +// "m_mapFileDataSelector")); + + const std::vector& xyz = m_graphicsPrimitive->getFloatXYZ(); + const int32_t numXYZ = static_cast(xyz.size()); + if (numXYZ > 0) { + chartDataCartesian->addFloatArray("xyz", + &xyz[0], + numXYZ); + } sceneClass->addClass(chartDataCartesian); } @@ -433,6 +442,23 @@ ChartTwoDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* scene m_sceneAssistant->restoreMembers(sceneAttributes, chartDataCartesian); - m_mapFileDataSelector->restoreFromScene(sceneAttributes, sceneClass->getClass("m_mapFileDataSelector")); +// m_mapFileDataSelector->restoreFromScene(sceneAttributes, chartDataCartesian->getClass("m_mapFileDataSelector")); + + const ScenePrimitiveArray* xyzArray = chartDataCartesian->getPrimitiveArray("xyz"); + if (xyzArray != NULL) { + const int32_t numElements = xyzArray->getNumberOfArrayElements(); + if (numElements > 0) { + std::vector data(numElements); + xyzArray->floatValues(&data[0], + numElements, + 0.0f); + const int32_t numXYZ = (numElements / 3); + for (int32_t i = 0; i < numXYZ; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(data, i3+2); + addPoint(data[i3], data[i3+1]); + } + } + } } diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 1c45fabcc..1f5697cf7 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -24,6 +24,7 @@ #undef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" #include "ChartTwoDataCartesian.h" #include "SceneAttributes.h" #include "SceneClass.h" @@ -106,12 +107,41 @@ ChartTwoLineSeriesHistory::setLoadingEnabled(const bool loadingEnabled) m_loadingEnabled = loadingEnabled; } +/** + * Generate the default color. + */ +CaretColorEnum::Enum +ChartTwoLineSeriesHistory::generateDefaultColor() +{ + CaretColorEnum::Enum color = CaretColorEnum::BLACK; + + bool validFlag = false; + color = CaretColorEnum::fromIntegerCode(s_defaultColorIndexGenerator, + &validFlag); + + if ( ! validFlag) { + s_defaultColorIndexGenerator = 0; + color = CaretColorEnum::fromIntegerCode(s_defaultColorIndexGenerator, + &validFlag); + if ( ! validFlag) { + color = CaretColorEnum::BLACK; + CaretLogWarning("Generation of default color failed"); + } + } + + ++s_defaultColorIndexGenerator; + + return color; +} + /** * Initialize an instance of this class. */ void ChartTwoLineSeriesHistory::initializeInstance() { + m_defaultColor = ChartTwoLineSeriesHistory::generateDefaultColor(); + const int32_t defaultHistoryCount = 5; m_loadingEnabled = false; @@ -172,9 +202,9 @@ ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultCol setModified(); } - for (auto chartData : m_chartHistory) { - chartData->setColor(defaultColor); - } +// for (auto chartData : m_chartHistory) { +// chartData->setColor(defaultColor); +// } } /** @@ -197,10 +227,29 @@ ChartTwoLineSeriesHistory::setDisplayCount(const int32_t count) { if (count != m_displayCount) { m_displayCount = count; + updateDisplayedHistoryItems(); setModified(); } } +/** + * Update the number of displayed history items. + */ +void ChartTwoLineSeriesHistory::updateDisplayedHistoryItems() +{ + int32_t itemsDisplayedCount = 0; + const int32_t numItems = getHistoryCount(); + for (int32_t i = 0; i < numItems; i++) { + ChartTwoDataCartesian* item = getHistoryItem(i); + if (item->isSelected()) { + itemsDisplayedCount++; + if (itemsDisplayedCount > m_displayCount) { + item->setSelected(false); + } + } + } +} + /** * @return Count of items in history. */ @@ -222,6 +271,7 @@ ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) CaretAssert(historyItem); historyItem->setColor(m_defaultColor); m_chartHistory.push_front(historyItem); + updateDisplayedHistoryItems(); } /** @@ -250,6 +300,14 @@ ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) const return m_chartHistory[index]; } +void +ChartTwoLineSeriesHistory::removeHistoryItem(const int32_t index) +{ + CaretAssertVectorIndex(m_chartHistory, index); + delete m_chartHistory[index]; + m_chartHistory.erase(m_chartHistory.begin() + index); +} + /** * @return Clear the history. */ @@ -386,7 +444,14 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut GraphicsPrimitive::PrimitiveType::LINES); historyItem->restoreFromScene(sceneAttributes, historyClass); + + /* + * Note: addHistoryItem() assigns the default color so + * need to update color + */ + const CaretColorEnum::Enum color = historyItem->getColor(); addHistoryItem(historyItem); + historyItem->setColor(color); } } diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 1a906e575..a135598f1 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -65,6 +65,8 @@ namespace caret { const ChartTwoDataCartesian* getHistoryItem(const int32_t index) const; + void removeHistoryItem(const int32_t index); + void clearHistory(); // ADD_NEW_METHODS_HERE @@ -98,6 +100,10 @@ namespace caret { void copyHelperChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj); void initializeInstance(); + + void updateDisplayedHistoryItems(); + + static CaretColorEnum::Enum generateDefaultColor(); bool m_loadingEnabled = false; @@ -109,12 +115,14 @@ namespace caret { int32_t m_displayCount; + static int32_t s_defaultColorIndexGenerator; + // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ - // + int32_t ChartTwoLineSeriesHistory::s_defaultColorIndexGenerator = 0; #endif // __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ } // namespace diff --git a/src/Charting/MapFileDataSelector.cxx b/src/Charting/MapFileDataSelector.cxx index 9506ef0bf..cbb708b98 100644 --- a/src/Charting/MapFileDataSelector.cxx +++ b/src/Charting/MapFileDataSelector.cxx @@ -239,7 +239,30 @@ MapFileDataSelector::setVolumeVoxelXYZ(const float voxelXYZ[3]) AString MapFileDataSelector::toString() const { - return "MapFileDataSelector"; + AString s; + + switch (m_dataSelectionType) { + case DataSelectionType::INVALID: + break; + case DataSelectionType::SURFACE_VERTEX: + s = ("Vertex " + + StructureEnum::toGuiName(m_surfaceStructure) + + " " + + AString::number(m_surfaceVertexIndex + 1)); + break; + case DataSelectionType::SURFACE_VERTICES_AVERAGE: + s = ("Vertex Average" + + StructureEnum::toGuiName(m_surfaceStructure) + + " count=" + + AString::number(m_surfaceVertexAverageIndices.size())); + break; + case DataSelectionType::VOLUME_XYZ: + s = ("Voxel " + + AString::fromNumbers(m_voxelXYZ, 3, ",")); + break; + } + + return s; } /** diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 7219dc1c9..9ff571d7a 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -493,6 +493,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: + case EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG: case EventTypeEnum::EVENT_DATA_FILE_ADD: case EventTypeEnum::EVENT_DATA_FILE_DELETE: case EventTypeEnum::EVENT_DATA_FILE_READ: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 129b3b42d..ec7057b12 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -189,6 +189,10 @@ EventTypeEnum::initialize() "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", "Load line series data for chart two implementation")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG, + "EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG", + "Show the Chart Two Line Series History Dialog")); + enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_ADD, "EVENT_DATA_FILE_ADD", "Add a data file to the Brain")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 11acad2fc..763c6d9a3 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -94,6 +94,8 @@ public: EVENT_CHART_OVERLAY_VALIDATE, /** Load chart two line series data */ EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, + /** Show the chart two line series history dialog */ + EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG, /** Add a data file into the Brain*/ EVENT_DATA_FILE_ADD, /** Delete a data file from the brain */ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 86ceb1109..ca3566717 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -331,6 +331,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 1102bcdd7..7b5d4afa4 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -99,6 +99,7 @@ ELSE() ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h + ChartTwoLineSeriesHistoryDialog.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h @@ -286,6 +287,7 @@ ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h +ChartTwoLineSeriesHistoryDialog.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h @@ -309,6 +311,7 @@ EventBrowserWindowContentGet.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h +EventChartTwoShowLineSeriesHistoryDialog.h EventGetOrSetUserInputModeProcessor.h EventGraphicsUpdateAllWindows.h EventGraphicsUpdateOneWindow.h @@ -497,6 +500,7 @@ ChartHistoryViewController.cxx ChartLinesSelectionViewController.cxx ChartMatrixParcelSelectionViewController.cxx ChartMatrixSeriesSelectionViewController.cxx +ChartTwoLineSeriesHistoryDialog.cxx ChartTwoOverlaySetViewController.cxx ChartTwoOverlayViewController.cxx ChartSelectionViewController.cxx @@ -519,6 +523,7 @@ EventBrowserWindowContentGet.cxx EventBrowserWindowCreateTabs.cxx EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx +EventChartTwoShowLineSeriesHistoryDialog.cxx EventGetOrSetUserInputModeProcessor.cxx EventGraphicsUpdateAllWindows.cxx EventGraphicsUpdateOneWindow.cxx diff --git a/src/GuiQt/CaretColorEnumComboBox.cxx b/src/GuiQt/CaretColorEnumComboBox.cxx index a690d14eb..e59e78dc2 100644 --- a/src/GuiQt/CaretColorEnumComboBox.cxx +++ b/src/GuiQt/CaretColorEnumComboBox.cxx @@ -183,6 +183,15 @@ CaretColorEnumComboBox::getWidget() return this->colorComboBox; } +/** + * @return The actual combo box encapsulated in this instance. + */ +QComboBox* +CaretColorEnumComboBox::getComboBox() +{ + return this->colorComboBox; +} + /** * @return The selected color. */ diff --git a/src/GuiQt/CaretColorEnumComboBox.h b/src/GuiQt/CaretColorEnumComboBox.h index 0c5dac456..4e991eeee 100644 --- a/src/GuiQt/CaretColorEnumComboBox.h +++ b/src/GuiQt/CaretColorEnumComboBox.h @@ -51,6 +51,8 @@ namespace caret { QWidget* getWidget(); + QComboBox* getComboBox(); + signals: void colorSelected(const CaretColorEnum::Enum); diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx new file mode 100644 index 000000000..491745de0 --- /dev/null +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -0,0 +1,464 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ +#include "ChartTwoLineSeriesHistoryDialog.h" +#undef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretColorEnumComboBox.h" +#include "CaretMappableDataFile.h" +#include "ChartTwoDataCartesian.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartTwoLineSeriesHistory.h" +#include "ChartTwoOverlay.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "MapFileDataSelector.h" +#include "WuQImageLabel.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoLineSeriesHistoryDialog + * \brief Dialog for controlling the display of line series chart data. + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent) +: WuQDialogNonModal("Line-Series History", + parent) +{ + const AString defaultColorToolTip("Color assigned to newly added line-series items"); + const AString displayMaximumToolTip("Maximum number of line-series items enabled for viewing\n" + "As new items are added, older items are disabled for viewing"); + + m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); + + m_filenameLabel = new QLabel(""); + + QLabel* defaultColorLabel = new QLabel("Default Color: "); + defaultColorLabel->setToolTip(defaultColorToolTip); + m_defaultColorComboBox = new CaretColorEnumComboBox(this); + m_defaultColorComboBox->getWidget()->setToolTip(defaultColorToolTip); + m_defaultColorComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + QObject::connect(m_defaultColorComboBox, &CaretColorEnumComboBox::colorSelected, + this, &ChartTwoLineSeriesHistoryDialog::defaultColorSelected); + + QToolButton* removeAllHistoryToolButton = new QToolButton(); + removeAllHistoryToolButton->setText("Remove All History..."); + QObject::connect(removeAllHistoryToolButton, &QToolButton::clicked, + this, &ChartTwoLineSeriesHistoryDialog::removeAllHistoryButtonClicked); + + QLabel* viewedMaximumLabel = new QLabel("Viewed Maximum: "); + viewedMaximumLabel->setToolTip(displayMaximumToolTip); + m_viewedMaximumCountSpinBox = new QSpinBox(); + m_viewedMaximumCountSpinBox->setToolTip(displayMaximumToolTip); + m_viewedMaximumCountSpinBox->setRange(1, 10000); + QObject::connect(m_viewedMaximumCountSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(viewedMaximumSpinBoxValueChanged(int))); + + m_removeHistoryItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_removeHistoryItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(removeHistoryItemSelected(int))); + + m_colorItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_colorItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(colorItemSelected(int))); + + m_tableWidget = new QTableWidget(); + m_tableWidget->setSelectionBehavior(QTableWidget::SelectItems); + m_tableWidget->setSelectionMode(QTableWidget::SingleSelection); + QObject::connect(m_tableWidget, &QTableWidget::cellChanged, + this, &ChartTwoLineSeriesHistoryDialog::tableWidgetCellChanged); + + QGridLayout* topLayout = new QGridLayout(); + topLayout->setColumnStretch(0, 0); + topLayout->setColumnStretch(1, 0); + topLayout->setColumnStretch(2, 0); + topLayout->setColumnStretch(3, 100); + topLayout->addWidget(defaultColorLabel, 0, 0); + topLayout->addWidget(m_defaultColorComboBox->getWidget(), 0, 1); + topLayout->addWidget(m_filenameLabel, 0, 2, 1, 2, Qt::AlignLeft); + topLayout->addWidget(viewedMaximumLabel, 1, 0); + topLayout->addWidget(m_viewedMaximumCountSpinBox, 1, 1); + topLayout->addWidget(removeAllHistoryToolButton, 1, 2); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addLayout(topLayout); + dialogLayout->addWidget(m_tableWidget); + + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); + + setApplyButtonText(""); +} + +/** + * Destructor. + */ +ChartTwoLineSeriesHistoryDialog::~ChartTwoLineSeriesHistoryDialog() +{ +} + +/** + * Update the dialog. + */ +void +ChartTwoLineSeriesHistoryDialog::updateDialog() +{ + updateDialogContent(m_chartOverlay); +} + +/** + * Update dialog if the given chart overlay is in the dialog. + * This may occur when the user changes the file in the chart overlay. + * + * @param chartOverlay + * Chart overlay for history display. + */ +void +ChartTwoLineSeriesHistoryDialog::updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay) +{ + if (m_chartOverlay == chartOverlay) { + updateDialogContent(m_chartOverlay); + } +} + +/** + * Update the content of the dialog. + * + * @param chartOverlay + * Chart overlay for history display. + */ +void +ChartTwoLineSeriesHistoryDialog::updateDialogContent(ChartTwoOverlay* chartOverlay) +{ + m_chartOverlay = chartOverlay; + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + + if (lineSeriesHistory != NULL) { + const CaretMappableDataFile* mapFile = getMapFile(); + if (mapFile != NULL) { + m_filenameLabel->setText("Filename: " + mapFile->getFileNameNoPath()); + m_filenameLabel->setToolTip(mapFile->getFileName()); + } + m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); + + m_viewedMaximumCountSpinBox->blockSignals(true); + m_viewedMaximumCountSpinBox->setValue(lineSeriesHistory->getDisplayCount()); + m_viewedMaximumCountSpinBox->blockSignals(false); + + loadHistoryIntoTableWidget(lineSeriesHistory); + } + else { + close(); + } +} + +/** + * @return Map file in the dialog. + */ +CaretMappableDataFile* +ChartTwoLineSeriesHistoryDialog::getMapFile() +{ + CaretMappableDataFile* mapFile = NULL; + if (m_chartOverlay != NULL) { + if (m_chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { + ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t mapIndex = -1; + m_chartOverlay->getSelectionData(mapFile, indexType, mapIndex); + } + } + + return mapFile; +} + +/** + * @return The line series history for the current chart overlay + */ +ChartTwoLineSeriesHistory* +ChartTwoLineSeriesHistoryDialog::getLineSeriesHistory() +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; + + CaretMappableDataFile* mapFile = getMapFile(); + if (mapFile != NULL) { + ChartableTwoFileLineSeriesChart* chartTwoLineSeries = mapFile->getChartingDelegate()->getLineSeriesCharting(); + lineSeriesHistory = chartTwoLineSeries->getHistory(); + } + + return lineSeriesHistory; +} + + +/** + * Load the line-series history into the table widget. + * + * @param lineSeriesHistory + * The line series history. + */ +void +ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory) +{ + CaretAssert(lineSeriesHistory); + + m_tableWidget->blockSignals(true); + + const int32_t preNumRows = m_tableWidget->rowCount(); + const int32_t numHistory = lineSeriesHistory->getHistoryCount(); + + /* + * Setup table dimensions + */ + m_tableWidget->setRowCount(numHistory); + m_tableWidget->setColumnCount(COLUMN_COUNT); + + /* + * May need to reduce color combo boxes + */ + m_colorComboBoxes.resize(preNumRows); + + /* + * If needed, add cells + */ + for (int32_t iRow = preNumRows; iRow < numHistory; iRow++) { + for (int32_t j = 0; j < COLUMN_COUNT; j++) { + if (j == COLUMN_VIEW) { + QTableWidgetItem* item = new QTableWidgetItem(""); + item->setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable + | Qt::ItemIsUserCheckable); + m_tableWidget->setItem(iRow, j, item); + } + else if (j == COLUMN_REMOVE) { + WuQImageLabel* removeHistoryLabel = new WuQImageLabel(m_removeAllHistoryIcon, + "Remove"); + QObject::connect(removeHistoryLabel, SIGNAL(clicked()), + m_removeHistoryItemSignalMapper, SLOT(map())); + m_removeHistoryItemSignalMapper->setMapping(removeHistoryLabel, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_REMOVE, + removeHistoryLabel); +// flags = (Qt::ItemIsEnabled); +// //| Qt::ItemIsSelectable); + } + else if (j == COLUMN_COLOR) { +// flags = (Qt::ItemIsEnabled +// | Qt::ItemIsSelectable); + CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); + QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), + m_colorItemSignalMapper, SLOT(map())); + m_colorItemSignalMapper->setMapping(caretColorComboBox, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_COLOR, + caretColorComboBox->getWidget()); + m_colorComboBoxes.push_back(caretColorComboBox); + } + else if (j == COLUMN_DESCRIPTION) { + QTableWidgetItem* item = new QTableWidgetItem(""); + item->setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + m_tableWidget->setItem(iRow, j, item); + } + else { + CaretAssert(0); + } + } + } + + /* + * Load cells + */ + for (int32_t iRow = 0; iRow < numHistory; iRow++) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iRow); + const MapFileDataSelector* mapFileDataSelector = data->getMapFileDataSelector(); + + m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(data->isSelected() + ? Qt::Checked + : Qt::Unchecked); + + CaretAssertVectorIndex(m_colorComboBoxes, iRow); + m_colorComboBoxes[iRow]->setSelectedColor(data->getColor()); + + QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); + item->setText(mapFileDataSelector->toString()); + } + + /* + * If table was empty, add column titles + * and adjust column widths + */ + if ((preNumRows == 0) + && (numHistory > 0)) { + m_tableWidget->setHorizontalHeaderItem(COLUMN_VIEW, + new QTableWidgetItem("View")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_REMOVE, + new QTableWidgetItem("Remove")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, + new QTableWidgetItem("Color")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_DESCRIPTION, + new QTableWidgetItem("Description")); + + m_tableWidget->resizeColumnToContents(COLUMN_VIEW); + m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); + m_tableWidget->resizeColumnToContents(COLUMN_COLOR); + m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, + 350); + + QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_tableWidget); + + WuQtUtilities::resizeWindow(this, + tableSize.width() + 30, + sizeHint().height()); + } + + m_tableWidget->blockSignals(false); +} + +/** + * Called when the content of a cell changes. + * Update corresponding item in the spec file. + * + * @param rowIndex + * The row of the cell that was clicked. + * @param columnIndex + * The columnof the cell that was clicked. + */ +void +ChartTwoLineSeriesHistoryDialog::tableWidgetCellChanged(int rowIndex, int columnIndex) +{ + QTableWidgetItem* item = m_tableWidget->item(rowIndex, columnIndex); + if (item != NULL) { + if (columnIndex == COLUMN_VIEW) { + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setSelected(WuQtUtilities::checkStateToBool(item->checkState())); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + } + } +} + +/** + * Remove a history item selected + * + * @param rowIndex + * Row index of item. + */ +void +ChartTwoLineSeriesHistoryDialog::removeHistoryItemSelected(int rowIndex) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->removeHistoryItem(rowIndex); + updateDialog(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Color item selected + * + * @param rowIndex + * Row index of item. + */ +void +ChartTwoLineSeriesHistoryDialog::colorItemSelected(int rowIndex) +{ + CaretAssertVectorIndex(m_colorComboBoxes, rowIndex); + CaretAssert(m_colorComboBoxes[rowIndex]); + + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setColor(m_colorComboBoxes[rowIndex]->getSelectedColor()); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + +/** + * Called when the "Remove All History" button is clicked. + */ +void +ChartTwoLineSeriesHistoryDialog::removeAllHistoryButtonClicked() +{ + if (WuQMessageBox::warningOkCancel(this, + ("Remove all line series history from the file " + + getMapFile()->getFileNameNoPath()))) { + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->clearHistory(); + updateDialog(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + +/** + * Called when the default color is changed. + * + * @param color + * New default color. + */ +void +ChartTwoLineSeriesHistoryDialog::defaultColorSelected(const CaretColorEnum::Enum color) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDefaultColor(color); + } +} + +/** + * Gets called when display last count is changed. + * + * @param num + * Number of history items to display. + */ +void +ChartTwoLineSeriesHistoryDialog::viewedMaximumSpinBoxValueChanged(int num) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDisplayCount(num); + updateDialog(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} \ No newline at end of file diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h new file mode 100644 index 000000000..faf69faba --- /dev/null +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h @@ -0,0 +1,119 @@ +#ifndef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ +#define __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretColorEnum.h" +#include "WuQDialogNonModal.h" + +class QLabel; +class QIcon; +class QSignalMapper; +class QSpinBox; +class QTableWidget; + +namespace caret { + + class CaretColorEnumComboBox; + class CaretMappableDataFile; + class ChartTwoLineSeriesHistory; + class ChartTwoOverlay; + + class ChartTwoLineSeriesHistoryDialog : public WuQDialogNonModal { + + Q_OBJECT + + public: + ChartTwoLineSeriesHistoryDialog(QWidget* parent); + + virtual ~ChartTwoLineSeriesHistoryDialog(); + + void updateDialogContent(ChartTwoOverlay* chartOverlay); + + virtual void updateDialog() override; + + void updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay); + + // ADD_NEW_METHODS_HERE + + private slots: + void tableWidgetCellChanged(int rowIndex, int columnIndex); + + void removeHistoryItemSelected(int rowIndex); + + void colorItemSelected(int rowIndex); + + void removeAllHistoryButtonClicked(); + + void defaultColorSelected(const CaretColorEnum::Enum color); + + void viewedMaximumSpinBoxValueChanged(int); + + private: + + ChartTwoLineSeriesHistoryDialog(const ChartTwoLineSeriesHistoryDialog&); + + ChartTwoLineSeriesHistoryDialog& operator=(const ChartTwoLineSeriesHistoryDialog&); + + void loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory); + + ChartTwoLineSeriesHistory* getLineSeriesHistory(); + + CaretMappableDataFile* getMapFile(); + + ChartTwoOverlay* m_chartOverlay = NULL; + + QTableWidget* m_tableWidget; + + QIcon* m_removeAllHistoryIcon; + + QSignalMapper* m_removeHistoryItemSignalMapper; + + QSignalMapper* m_colorItemSignalMapper; + + std::vector m_colorComboBoxes; + + QLabel* m_filenameLabel; + + CaretColorEnumComboBox* m_defaultColorComboBox; + + QSpinBox* m_viewedMaximumCountSpinBox; + + static const int32_t COLUMN_VIEW = 0; + static const int32_t COLUMN_REMOVE = 1; + static const int32_t COLUMN_COLOR = 2; + static const int32_t COLUMN_DESCRIPTION = 3; + static const int32_t COLUMN_COUNT = 4; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + // +#endif // __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + +} // namespace +#endif //__CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 970e29e16..f3c10f9d0 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -45,6 +45,7 @@ using namespace caret; #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" +#include "EventChartTwoShowLineSeriesHistoryDialog.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" @@ -306,6 +307,15 @@ ChartTwoOverlayViewController::updateOverlaySettingsEditor() selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } + + if (mapFile != NULL) { + if (m_chartOverlay->isHistorySupported()) { + EventChartTwoShowLineSeriesHistoryDialog lshd(EventChartTwoShowLineSeriesHistoryDialog::Mode::CHART_OVERLAY_CHANGED, + m_browserWindowIndex, + m_chartOverlay); + EventManager::get()->sendEvent(lshd.getPointer()); + } + } } /** @@ -593,18 +603,12 @@ ChartTwoOverlayViewController::historyActionTriggered(bool) selectedIndexType, selectedIndex); - std::cout << "History button clicked. Enabled=" - << qPrintable(AString::fromBool(m_chartOverlay->isHistorySupported())) << std::endl; - - CaretAssertToDoWarning(); -// if (mapFile != NULL) { -// EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, -// m_browserWindowIndex, -// m_chartOverlay, -// mapFile, -// mapIndex); -// EventManager::get()->sendEvent(pcme.getPointer()); -// } + if (mapFile != NULL) { + EventChartTwoShowLineSeriesHistoryDialog lshd(EventChartTwoShowLineSeriesHistoryDialog::Mode::SHOW_DIALOG, + m_browserWindowIndex, + m_chartOverlay); + EventManager::get()->sendEvent(lshd.getPointer()); + } } @@ -780,7 +784,21 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla /* * Update settings (wrench) button */ - m_settingsAction->setEnabled(validOverlayAndFileFlag); + bool enableSettingsActionFlag = validOverlayAndFileFlag; + switch (m_chartOverlay->getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + enableSettingsActionFlag = false; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + enableSettingsActionFlag = false; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + m_settingsAction->setEnabled(enableSettingsActionFlag); /* * Update color bar button diff --git a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx new file mode 100644 index 000000000..b16e211b3 --- /dev/null +++ b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx @@ -0,0 +1,92 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ +#include "EventChartTwoShowLineSeriesHistoryDialog.h" +#undef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventChartTwoShowLineSeriesHistoryDialog + * \brief Event to show the chart two line series history dialog + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param mode + * Mode for the dialog. + * @param browserWindowIndex + * Index of the browser window. + * @param chartOverlay + * The chart overlay. + */ +EventChartTwoShowLineSeriesHistoryDialog::EventChartTwoShowLineSeriesHistoryDialog(const Mode mode, + const int32_t browserWindowIndex, + ChartTwoOverlay* chartOverlay) +: Event(EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG), +m_mode(mode), +m_browserWindowIndex(browserWindowIndex), +m_chartOverlay(chartOverlay) +{ + +} + +/** + * Destructor. + */ +EventChartTwoShowLineSeriesHistoryDialog::~EventChartTwoShowLineSeriesHistoryDialog() +{ +} + +/** + * @return The mode. + */ +EventChartTwoShowLineSeriesHistoryDialog::Mode +EventChartTwoShowLineSeriesHistoryDialog::getMode() const +{ + return m_mode; +} + +/** + * Index of the browser window. + */ +int32_t +EventChartTwoShowLineSeriesHistoryDialog::getBrowserWindowIndex() const +{ + return m_browserWindowIndex; +} + +/** + * @return The chart overlay. + */ +ChartTwoOverlay* +EventChartTwoShowLineSeriesHistoryDialog::getChartOverlay() const +{ + return m_chartOverlay; +} diff --git a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h new file mode 100644 index 000000000..43f2fa8e3 --- /dev/null +++ b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h @@ -0,0 +1,78 @@ +#ifndef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ +#define __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class CaretMappableDataFile; + class ChartTwoOverlay; + + class EventChartTwoShowLineSeriesHistoryDialog : public Event { + + public: + enum class Mode { + CHART_OVERLAY_CHANGED, + SHOW_DIALOG + }; + EventChartTwoShowLineSeriesHistoryDialog(const Mode mode, + const int32_t browserWindowIndex, + ChartTwoOverlay* chartOverlay); + + virtual ~EventChartTwoShowLineSeriesHistoryDialog(); + + Mode getMode() const; + + int32_t getBrowserWindowIndex() const; + + ChartTwoOverlay* getChartOverlay() const; + + // ADD_NEW_METHODS_HERE + + private: + EventChartTwoShowLineSeriesHistoryDialog(const EventChartTwoShowLineSeriesHistoryDialog&); + + EventChartTwoShowLineSeriesHistoryDialog& operator=(const EventChartTwoShowLineSeriesHistoryDialog&); + + const Mode m_mode; + + const int32_t m_browserWindowIndex; + + ChartTwoOverlay* m_chartOverlay; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + // +#endif // __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ + +} // namespace +#endif //__EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 80f603155..8ee0f7672 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -46,6 +46,7 @@ #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartingDataManager.h" +#include "ChartTwoLineSeriesHistoryDialog.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiConnectivityMatrixDataFileManager.h" @@ -63,6 +64,7 @@ #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserWindowNew.h" +#include "EventChartTwoShowLineSeriesHistoryDialog.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" @@ -173,6 +175,7 @@ GuiManager::initializeGuiManager() this->connectomeDatabaseWebView = NULL; m_helpViewerDialog = NULL; m_paletteColorMappingEditor = NULL; + m_chartTwoLineSeriesHistoryDialog = NULL; this->sceneDialog = NULL; m_surfacePropertiesEditorDialog = NULL; m_tileTabsConfigurationDialog = NULL; @@ -286,6 +289,9 @@ GuiManager::initializeGuiManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ALERT_USER); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_NEW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW); @@ -1284,6 +1290,58 @@ GuiManager::receiveEvent(Event* event) EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); } + else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG) { + EventChartTwoShowLineSeriesHistoryDialog* historyDialogEvent = dynamic_cast(event); + CaretAssert(historyDialogEvent); + + const EventChartTwoShowLineSeriesHistoryDialog::Mode mode = historyDialogEvent->getMode(); + const int32_t browserWindowIndex = historyDialogEvent->getBrowserWindowIndex(); + ChartTwoOverlay* chartOverlay = historyDialogEvent->getChartOverlay(); + + CaretAssertVectorIndex(m_brainBrowserWindows, browserWindowIndex); + BrainBrowserWindow* browserWindow = m_brainBrowserWindows[browserWindowIndex]; + CaretAssert(browserWindow); + + switch (mode) { + case EventChartTwoShowLineSeriesHistoryDialog::Mode::CHART_OVERLAY_CHANGED: + if (m_chartTwoLineSeriesHistoryDialog != NULL) { + m_chartTwoLineSeriesHistoryDialog->updateIfThisChartOverlayIsInDialog(chartOverlay); + } + break; + case EventChartTwoShowLineSeriesHistoryDialog::Mode::SHOW_DIALOG: + { + bool placeInDefaultLocation = false; + if (m_chartTwoLineSeriesHistoryDialog == NULL) { + m_chartTwoLineSeriesHistoryDialog = new ChartTwoLineSeriesHistoryDialog(browserWindow); + addNonModalDialog(m_chartTwoLineSeriesHistoryDialog); + placeInDefaultLocation = true; + } + else if (m_chartTwoLineSeriesHistoryDialog->isHidden()) { + placeInDefaultLocation = true; + } + + m_chartTwoLineSeriesHistoryDialog->updateDialogContent(chartOverlay); + + m_chartTwoLineSeriesHistoryDialog->show(); + m_chartTwoLineSeriesHistoryDialog->raise(); + m_chartTwoLineSeriesHistoryDialog->activateWindow(); + if (placeInDefaultLocation) { + WuQtUtilities::moveWindowToSideOfParent(browserWindow, + m_chartTwoLineSeriesHistoryDialog); + } + + } + break; + } + + historyDialogEvent->setEventProcessed(); + } + else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) + || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW)) { + if (m_chartTwoLineSeriesHistoryDialog != NULL) { + m_chartTwoLineSeriesHistoryDialog->updateDialog(); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE) { EventMacDockMenuUpdate* macDockMenuEvent = dynamic_cast(event); CaretAssert(event); diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index f5e00e41a..2a79a8cc2 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -45,6 +45,7 @@ namespace caret { class BrainBrowserWindow; class BrowserTabContent; class BugReportDialog; + class ChartTwoLineSeriesHistoryDialog; class ClippingPlanesDialog; class CursorManager; class CustomViewDialog; @@ -248,6 +249,8 @@ namespace caret { /** Editor for palette color mapping editing */ PaletteColorMappingEditorDialog* m_paletteColorMappingEditor; + ChartTwoLineSeriesHistoryDialog* m_chartTwoLineSeriesHistoryDialog; + TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; ClippingPlanesDialog* m_clippingPlanesDialog; -- GitLab From d2e48c3e513e95f86720183b0c65336ad09f2524 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Jun 2017 10:15:02 -0500 Subject: [PATCH 286/755] Removed unused code and consolidated chart classes --- src/Brain/ModelChartTwo.cxx | 222 ------------ src/Brain/ModelChartTwo.h | 20 -- src/Charting/CMakeLists.txt | 2 - src/Charting/ChartTwoData.cxx | 322 ------------------ src/Charting/ChartTwoData.h | 141 -------- src/Charting/ChartTwoDataCartesian.cxx | 102 ++++-- src/Charting/ChartTwoDataCartesian.h | 31 +- src/Charting/ChartTwoLineSeriesHistory.cxx | 3 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 4 +- 9 files changed, 91 insertions(+), 756 deletions(-) delete mode 100644 src/Charting/ChartTwoData.cxx delete mode 100644 src/Charting/ChartTwoData.h diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index d6a4a3bf9..f8088db63 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -83,9 +83,6 @@ ModelChartTwo::ModelChartTwo(Brain* brain) "Line Series Chart Overlays")); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - //m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(m_brain); - //m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(m_brain, - // DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); } @@ -119,12 +116,6 @@ ModelChartTwo::~ModelChartTwo() removeAllCharts(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - //delete m_chartableMatrixFileSelectionModel[i]; - //m_chartableMatrixFileSelectionModel[i] = NULL; - - //delete m_chartableMatrixSeriesFileSelectionModel[i]; - //m_chartableMatrixSeriesFileSelectionModel[i] = NULL; - delete m_chartTwoMatrixDisplayProperties[i]; m_chartTwoMatrixDisplayProperties[i] = NULL; } @@ -157,81 +148,6 @@ ModelChartTwo::removeAllCharts() { } -/** - * Load chart data for an average of surface nodes. - * - * @param structure - * The surface structure - * @param surfaceNumberOfNodes - * Number of nodes in surface. - * @param nodeIndices - * Indices of node. - * @throws - * DataFileException if there is an error loading data. - */ -void -ModelChartTwo::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, - const int32_t surfaceNumberOfNodes, - const std::vector& nodeIndices) -{ - CaretAssertToDoWarning(); -// std::map > chartFileEnabledTabs; -// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); -// fileTabIter != chartFileEnabledTabs.end(); -// fileTabIter++) { -// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; -// const std::vector tabIndices = fileTabIter->second; -// -// CaretAssert(chartFile); -// ChartData* chartData = chartFile->loadAverageLineSeriesChartDataForSurfaceNodes(structure, -// nodeIndices); -// if (chartData != NULL) { -// ChartDataSource* dataSource = chartData->getChartDataSource(); -// dataSource->setSurfaceNodeAverage(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), -// StructureEnum::toName(structure), -// surfaceNumberOfNodes, nodeIndices); -// -// addChartToChartModels(tabIndices, -// chartData); -// } -// } -} - -/** - * Load chart data for voxel at the given coordinate. - * - * @param xyz - * Coordinate of voxel. - * @throws - * DataFileException if there is an error loading data. - */ -void -ModelChartTwo::loadChartDataForVoxelAtCoordinate(const float xyz[3]) -{ - CaretAssertToDoWarning(); -// std::map > chartFileEnabledTabs; -// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); -// fileTabIter != chartFileEnabledTabs.end(); -// fileTabIter++) { -// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; -// const std::vector tabIndices = fileTabIter->second; -// -// CaretAssert(chartFile); -// ChartData* chartData = chartFile->loadLineSeriesChartDataForVoxelAtCoordinate(xyz); -// if (chartData != NULL) { -// ChartDataSource* dataSource = chartData->getChartDataSource(); -// dataSource->setVolumeVoxel(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), -// xyz); -// -// addChartToChartModels(tabIndices, -// chartData); -// } -// } -} /** * Load chart data for CIFTI Map files yoked to the given yoking group. @@ -326,144 +242,6 @@ ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* cifti // } // } } - -///** -// * Get tabs and brainordinate chart files for loading chart data. -// * -// * @param chartBrainordinateFileEnabledTabsOut -// * Map with first being a chartable file and the second being -// * tabs for which that chartable file is enabled. -// */ -//void -//ModelChartTwo::getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const -//{ -// chartBrainordinateFileEnabledTabsOut.clear(); -// -// std::map > chartFileEnabledTabs; -// getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator iter = chartFileEnabledTabs.begin(); -// iter != chartFileEnabledTabs.end(); -// iter++) { -// ChartableLineSeriesBrainordinateInterface* brainChartFile = dynamic_cast(iter->first); -// if (brainChartFile != NULL) { -// chartBrainordinateFileEnabledTabsOut.insert(std::make_pair(brainChartFile, -// iter->second)); -// } -// } -//} - - -///** -// * Get tabs and row column chart files for loading chart data. -// * -// * @param chartRowColumnFilesEnabledTabsOut -// * Map with first being a chartable file and the second being -// * tabs for which that chartable file is enabled. -// */ -//void -//ModelChartTwo::getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const -//{ -// chartRowColumnFilesEnabledTabsOut.clear(); -// -// std::map > chartFileEnabledTabs; -// getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator iter = chartFileEnabledTabs.begin(); -// iter != chartFileEnabledTabs.end(); -// iter++) { -// ChartableLineSeriesRowColumnInterface* rowColChartFile = dynamic_cast(iter->first); -// if (rowColChartFile != NULL) { -// chartRowColumnFilesEnabledTabsOut.insert(std::make_pair(rowColChartFile, -// iter->second)); -// } -// } -//} - -///** -// * Get line series chart files for loading chart data. -// * -// * @param chartFileEnabledTabsOut -// * Map with first being a chartable file and the second being -// * tabs for which that chartable file is enabled. -// */ -//void -//ModelChartTwo::getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const -//{ -// chartFileEnabledTabsOut.clear(); -// -// EventBrowserTabGetAll allTabsEvent; -// EventManager::get()->sendEvent(allTabsEvent.getPointer()); -// std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); -// -// std::vector chartFiles; -// m_brain->getAllChartableLineSeriesDataFiles(chartFiles); -// -// for (std::vector::iterator iter = chartFiles.begin(); -// iter != chartFiles.end(); -// iter++) { -// ChartableLineSeriesInterface* cf = *iter; -// std::vector chartFileTabIndices; -// -// for (std::vector::iterator tabIter = validTabIndices.begin(); -// tabIter != validTabIndices.end(); -// tabIter++) { -// const int32_t tabIndex = *tabIter; -// if (cf->isLineSeriesChartingEnabled(tabIndex)) { -// chartFileTabIndices.push_back(tabIndex); -// } -// } -// -// if ( ! chartFileTabIndices.empty()) { -// chartFileEnabledTabsOut.insert(std::make_pair(cf, chartFileTabIndices)); -// } -// } -//} - -/** - * Load chart data for a surface node. - * - * @param structure - * The surface structure - * @param surfaceNumberOfNodes - * Number of nodes in surface. - * @param nodeIndex - * Index of node. - * @throws - * DataFileException if there is an error loading data. - */ -void -ModelChartTwo::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, - const int32_t surfaceNumberOfNodes, - const int32_t nodeIndex) -{ - CaretAssertToDoWarning(); - -// std::map > chartFileEnabledTabs; -// getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); -// fileTabIter != chartFileEnabledTabs.end(); -// fileTabIter++) { -// ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; -// const std::vector tabIndices = fileTabIter->second; -// -// CaretAssert(chartFile); -// ChartData* chartData = chartFile->loadLineSeriesChartDataForSurfaceNode(structure, -// nodeIndex); -// if (chartData != NULL) { -// ChartDataSource* dataSource = chartData->getChartDataSource(); -// dataSource->setSurfaceNode(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), -// StructureEnum::toName(structure), -// surfaceNumberOfNodes, -// nodeIndex); -// -// addChartToChartModels(tabIndices, -// chartData); -// } -// } -} - /** * Receive an event. * diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index e5df77055..ecb349933 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -62,16 +62,6 @@ namespace caret { virtual AString getNameForBrowserTab() const override; - void loadChartDataForSurfaceNode(const StructureEnum::Enum structure, - const int32_t surfaceNumberOfNodes, - const int32_t nodeIndex); - - void loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, - const int32_t surfaceNumberOfNodes, - const std::vector& nodeIndices); - - void loadChartDataForVoxelAtCoordinate(const float xyz[3]); - void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); @@ -133,12 +123,6 @@ namespace caret { void restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, const int32_t tabIndex); -// void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; -// -// void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; -// -// void getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const; - virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); @@ -161,10 +145,6 @@ namespace caret { ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - //CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - - //CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - std::unique_ptr m_sceneAssistant; }; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 7d486aa9a..ab7ac0dde 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -41,7 +41,6 @@ ChartingVersionEnum.h ChartTwoAxisScaleRangeModeEnum.h ChartTwoCartesianAxis.h ChartTwoCompoundDataType.h -ChartTwoData.h ChartTwoDataCartesian.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h @@ -81,7 +80,6 @@ ChartingVersionEnum.cxx ChartTwoCartesianAxis.cxx ChartTwoCompoundDataType.cxx -ChartTwoData.cxx ChartTwoDataCartesian.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx diff --git a/src/Charting/ChartTwoData.cxx b/src/Charting/ChartTwoData.cxx deleted file mode 100644 index 980895134..000000000 --- a/src/Charting/ChartTwoData.cxx +++ /dev/null @@ -1,322 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHART_TWO_DATA_DECLARE__ -#include "ChartTwoData.h" -#undef __CHART_TWO_DATA_DECLARE__ - -#include "CaretAssert.h" -#include "ChartTwoDataCartesian.h" -#include "ChartDataSource.h" -#include "SceneClass.h" -#include "SceneClassAssistant.h" -#include "SystemUtilities.h" - -using namespace caret; - - - -/** - * \class caret::ChartTwoData - * \brief Base class for chart data. - * \ingroup Charting - */ - -/** - * Constructor. - * - * @param chartDataType - * Type of chart data. - */ -ChartTwoData::ChartTwoData(const ChartTwoDataTypeEnum::Enum chartDataType) -: CaretObjectTracksModification(), -SceneableInterface(), -m_chartDataType(chartDataType) -{ - initializeMembersChartTwoData(); -} - -/** - * Destructor. - */ -ChartTwoData::~ChartTwoData() -{ - delete m_sceneAssistant; - delete m_chartDataSource; -} - -/** - * Initialize members of a new instance. - */ -void -ChartTwoData::initializeMembersChartTwoData() -{ - m_chartDataSource = new ChartDataSource(); - m_selectionStatus = true; - m_uniqueIdentifier = SystemUtilities::createUniqueID(); - - m_sceneAssistant = new SceneClassAssistant(); - m_sceneAssistant->add("m_chartDataSource", - "ChartDataSource", - m_chartDataSource); - m_sceneAssistant->add("m_selectionStatus", - &m_selectionStatus); - m_sceneAssistant->add("m_uniqueIdentifier", - &m_uniqueIdentifier); -} - - -/** - * Copy constructor. - * @param obj - * Object that is copied. - */ -ChartTwoData::ChartTwoData(const ChartTwoData& obj) -: CaretObjectTracksModification(obj), -SceneableInterface(obj), -m_chartDataType(obj.m_chartDataType) -{ - initializeMembersChartTwoData(); - - this->copyHelperChartTwoData(obj); -} - -/** - * Assignment operator. - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -ChartTwoData& -ChartTwoData::operator=(const ChartTwoData& obj) -{ - if (this != &obj) { - CaretObjectTracksModification::operator=(obj); - this->copyHelperChartTwoData(obj); - } - return *this; -} - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -ChartTwoData::copyHelperChartTwoData(const ChartTwoData& obj) -{ - CaretAssert(0); - m_chartDataType = obj.m_chartDataType; - *m_chartDataSource = *obj.m_chartDataSource; - m_selectionStatus = obj.m_selectionStatus; -} - -/** - * Create a new instance of a chart for the given data type. - * - * @param chartDataType - * Type of chart data. - * @return - * Pointer to new instance. - */ -ChartTwoData* -ChartTwoData::newChartTwoDataForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) -{ - ChartTwoData* chartData = NULL; - - switch (chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - CaretAssert(0); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - CaretAssert(0); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - CaretAssert(0); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - chartData = new ChartTwoDataCartesian(chartDataType, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - GraphicsPrimitive::PrimitiveType::LINES); - break; - } - - return chartData; -} - - -/** - * Save information specific to this type of model to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * saving the scene. - * - * @param instanceName - * Name of instance in the scene. - */ -SceneClass* -ChartTwoData::saveToScene(const SceneAttributes* sceneAttributes, - const AString& instanceName) -{ - SceneClass* sceneClass = new SceneClass(instanceName, - "ChartTwoData", - 1); - m_sceneAssistant->saveMembers(sceneAttributes, - sceneClass); - - saveSubClassDataToScene(sceneAttributes, - sceneClass); - - return sceneClass; -} - -/** - * Restore information specific to the type of model from the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass from which model specific information is obtained. - */ -void -ChartTwoData::restoreFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - if (sceneClass == NULL) { - return; - } - - m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); - restoreSubClassDataFromScene(sceneAttributes, - sceneClass); -} - - -/** - * @return The chart data type. - */ -ChartTwoDataTypeEnum::Enum -ChartTwoData::getChartTwoDataType() const -{ - return m_chartDataType; -} - -/** - * @return The source of the chart data (const method). - */ -const ChartDataSource* -ChartTwoData::getChartDataSource() const -{ - return m_chartDataSource; -} - -/** - * @return The source of the chart data. - */ -ChartDataSource* -ChartTwoData::getChartDataSource() -{ - return m_chartDataSource; -} - -/** - * @return The selection status - */ -bool -ChartTwoData::isSelected() const -{ - return m_selectionStatus; -} - -/** - * Set the selection status. - * - * @param selectionStatus - * New selection status. - */ -void -ChartTwoData::setSelected(const bool selectionStatus) -{ - m_selectionStatus = selectionStatus; - - /* - * When selection status is true, - * notify parent. - */ -// if (m_selectionStatus[tabIndex]) { -// if (m_parentChartModel != NULL) { -// m_parentChartModel->childChartTwoDataSelectionChanged(this); -// } -// } -} - -/** - * Copy the selection status for all tabs from the given chart data to me. - * - * @param copyFrom - * Chart data from which selection status is copied. - */ -//void -//ChartTwoData::copySelectionStatusForAllTabs(const ChartTwoData* copyFrom) -//{ -// m_selectionStatus = copyFrom->m_selectionStatus; -//} - - -/** - * @return The Unique Identifier (UUID). - */ -AString -ChartTwoData::getUniqueIdentifier() const -{ - return m_uniqueIdentifier; -} - -/** - * Set the unique identifier. - * - * @param uniqueIdentifier - * The new unique identifier. - */ -void -ChartTwoData::setUniqueIdentifier(const AString& uniqueIdentifier) -{ - m_uniqueIdentifier = uniqueIdentifier; -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -ChartTwoData::toString() const -{ - return "ChartTwoData"; -} - diff --git a/src/Charting/ChartTwoData.h b/src/Charting/ChartTwoData.h deleted file mode 100644 index 5ca7ffc56..000000000 --- a/src/Charting/ChartTwoData.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __CHART_TWO_DATA_H__ -#define __CHART_TWO_DATA_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include "CaretObjectTracksModification.h" -#include "ChartTwoDataTypeEnum.h" -#include "SceneableInterface.h" - - -namespace caret { - - class ChartDataSource; - class SceneClassAssistant; - - class ChartTwoData : public CaretObjectTracksModification, public SceneableInterface { - - public: - static ChartTwoData* newChartTwoDataForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType); - - virtual ~ChartTwoData(); - - /** - * At times a copy of chart data will be needed BUT it must be - * the proper subclass so copy constructor and assignment operator - * will function when this abstract, base class is used. Each - * subclass will override this method so that the returned class - * is of the proper type. - * - * @return Copy of this instance that is the actual subclass. - */ - virtual ChartTwoData* clone() const = 0; - - ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; - - const ChartDataSource* getChartDataSource() const; - - ChartDataSource* getChartDataSource(); - - bool isSelected() const; - - void setSelected(const bool selectionStatus); - - void clearSelected(); - - AString getUniqueIdentifier() const; - - void setUniqueIdentifier(const AString& uniqueIdentifier); - - //void copySelectionStatusForAllTabs(const ChartTwoData* copyFrom); - - virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, - const AString& instanceName); - - virtual void restoreFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - protected: - ChartTwoData(const ChartTwoDataTypeEnum::Enum chartDataType); - - ChartTwoData(const ChartTwoData& obj); - - ChartTwoData& operator=(const ChartTwoData& obj); - - /** - * Save subclass data to the scene. sceneClass - * will be valid and any scene data should be added to it. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass to which data members should be added. - */ - virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) = 0; - - /** - * Restore file data from the scene. The scene class - * will be valid and any scene data may be obtained from it. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass for the instance of a class that implements - * this interface. Will NEVER be NULL. - */ - virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) = 0; - - private: - void initializeMembersChartTwoData(); - - void copyHelperChartTwoData(const ChartTwoData& obj); - - SceneClassAssistant* m_sceneAssistant; - - ChartTwoDataTypeEnum::Enum m_chartDataType; - - ChartDataSource* m_chartDataSource; - - bool m_selectionStatus; - - AString m_uniqueIdentifier; - - // ADD_NEW_MEMBERS_HERE - }; - -#ifdef __CHART_TWO_DATA_DECLARE__ - // -#endif // __CHART_TWO_DATA_DECLARE__ - -} // namespace -#endif //__CHART_TWO_DATA_H__ diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 5bc404a91..978494f79 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -62,14 +62,14 @@ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum ch const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY, const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType) -: ChartTwoData(chartDataType), +: CaretObjectTracksModification(), m_dataAxisUnitsX(dataAxisUnitsX), m_dataAxisUnitsY(dataAxisUnitsY), m_graphicsPrimitiveType(graphicsPrimitiveType) { initializeMembersChartTwoDataCartesian(); - switch (getChartTwoDataType()) { + switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; @@ -100,6 +100,7 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() { m_mapFileDataSelector = std::unique_ptr(new MapFileDataSelector()); + m_selectionStatus = true; m_color = CaretColorEnum::RED; m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; @@ -131,6 +132,8 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_selectionStatus", + &m_selectionStatus); m_sceneAssistant->add("m_dataAxisUnitsX", &m_dataAxisUnitsX); m_sceneAssistant->add("m_dataAxisUnitsY", @@ -190,7 +193,7 @@ ChartTwoDataCartesian::setMapFileDataSelector(const MapFileDataSelector& mapFile * * @return Copy of this instance that is the actual subclass. */ -ChartTwoData* +ChartTwoDataCartesian* ChartTwoDataCartesian::clone() const { ChartTwoDataCartesian* cloneCopy = new ChartTwoDataCartesian(*this); @@ -203,7 +206,7 @@ ChartTwoDataCartesian::clone() const * Object that is copied. */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataCartesian& obj) -: ChartTwoData(obj), +: CaretObjectTracksModification(obj), m_dataAxisUnitsX(obj.m_dataAxisUnitsX), m_dataAxisUnitsY(obj.m_dataAxisUnitsY), m_graphicsPrimitiveType(obj.m_graphicsPrimitiveType) @@ -223,7 +226,7 @@ ChartTwoDataCartesian& ChartTwoDataCartesian::operator=(const ChartTwoDataCartesian& obj) { if (this != &obj) { - ChartTwoData::operator=(obj); + CaretObjectTracksModification::operator=(obj); this->copyHelperChartTwoDataCartesian(obj); } return *this; @@ -237,8 +240,7 @@ ChartTwoDataCartesian::operator=(const ChartTwoDataCartesian& obj) void ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj) { - CaretAssert(0); - + m_selectionStatus = obj.m_selectionStatus; *m_mapFileDataSelector = *obj.m_mapFileDataSelector; m_dataAxisUnitsX = obj.m_dataAxisUnitsX; m_dataAxisUnitsY = obj.m_dataAxisUnitsY; @@ -259,6 +261,37 @@ ChartTwoDataCartesian::getGraphicsPrimitive() const return m_graphicsPrimitive.get(); } +/** + * @return The selection status + */ +bool +ChartTwoDataCartesian::isSelected() const +{ + return m_selectionStatus; +} + +/** + * Set the selection status. + * + * @param selectionStatus + * New selection status. + */ +void +ChartTwoDataCartesian::setSelected(const bool selectionStatus) +{ + m_selectionStatus = selectionStatus; + + /* + * When selection status is true, + * notify parent. + */ + // if (m_selectionStatus[tabIndex]) { + // if (m_parentChartModel != NULL) { + // m_parentChartModel->childChartTwoDataSelectionChanged(this); + // } + // } +} + /** * Add a point. @@ -381,44 +414,42 @@ ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) } /** - * Save subclass data to the scene. + * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when - * restoring the scene. + * saving the scene. * - * @param sceneClass - * sceneClass to which data members should be added. Will always - * be valid (non-NULL). + * @param instanceName + * Name of instance in the scene. */ -void -ChartTwoDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) +SceneClass* +ChartTwoDataCartesian::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) { - SceneClass* chartDataCartesian = new SceneClass("chartDataCartesian", - "ChartTwoDataCartesian", - 1); - + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoDataCartesian", + 1); m_sceneAssistant->saveMembers(sceneAttributes, - chartDataCartesian); - + sceneClass); + // chartDataCartesian->addClass(m_mapFileDataSelector->saveToScene(sceneAttributes, // "m_mapFileDataSelector")); const std::vector& xyz = m_graphicsPrimitive->getFloatXYZ(); const int32_t numXYZ = static_cast(xyz.size()); if (numXYZ > 0) { - chartDataCartesian->addFloatArray("xyz", - &xyz[0], - numXYZ); + sceneClass->addFloatArray("xyz", + &xyz[0], + numXYZ); } - - sceneClass->addClass(chartDataCartesian); + + return sceneClass; } /** - * Restore file data from the scene. + * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types @@ -426,25 +457,22 @@ ChartTwoDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttri * restoring the scene. * * @param sceneClass - * sceneClass for the instance of a class that implements - * this interface. Will NEVER be NULL. + * sceneClass from which model specific information is obtained. */ void -ChartTwoDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) +ChartTwoDataCartesian::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) { - m_graphicsPrimitive = createGraphicsPrimitive(); - - const SceneClass* chartDataCartesian = sceneClass->getClass("chartDataCartesian"); - if (chartDataCartesian == NULL) { + if (sceneClass == NULL) { return; } + m_graphicsPrimitive = createGraphicsPrimitive(); - m_sceneAssistant->restoreMembers(sceneAttributes, chartDataCartesian); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); // m_mapFileDataSelector->restoreFromScene(sceneAttributes, chartDataCartesian->getClass("m_mapFileDataSelector")); - const ScenePrimitiveArray* xyzArray = chartDataCartesian->getPrimitiveArray("xyz"); + const ScenePrimitiveArray* xyzArray = sceneClass->getPrimitiveArray("xyz"); if (xyzArray != NULL) { const int32_t numElements = xyzArray->getNumberOfArrayElements(); if (numElements > 0) { diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index d2f0aa328..7c81b520b 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -22,9 +22,11 @@ /*LICENSE_END*/ #include "CaretColorEnum.h" +#include "CaretObjectTracksModification.h" #include "ChartAxisUnitsEnum.h" -#include "ChartTwoData.h" +#include "ChartTwoDataTypeEnum.h" #include "GraphicsPrimitive.h" +#include "SceneableInterface.h" namespace caret { @@ -32,8 +34,9 @@ namespace caret { class ChartPoint; class GraphicsPrimitiveV3f; class MapFileDataSelector; + class SceneClassAssistant; - class ChartTwoDataCartesian : public ChartTwoData { + class ChartTwoDataCartesian : public CaretObjectTracksModification, public SceneableInterface { public: ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, @@ -43,7 +46,11 @@ namespace caret { virtual ~ChartTwoDataCartesian(); - virtual ChartTwoData* clone() const; + virtual ChartTwoDataCartesian* clone() const; + + bool isSelected() const; + + void setSelected(const bool selectionStatus); void addPoint(const float x, const float y); @@ -74,12 +81,18 @@ namespace caret { // ADD_NEW_METHODS_HERE - protected: - virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); - virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass); +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass); private: @@ -103,6 +116,8 @@ namespace caret { const GraphicsPrimitive::PrimitiveType m_graphicsPrimitiveType; + bool m_selectionStatus; + CaretColorEnum::Enum m_color; float m_timeStartInSecondsAxisX; diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 1f5697cf7..498660d96 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -169,8 +169,7 @@ ChartTwoLineSeriesHistory::copyHelperChartTwoLineSeriesHistory(const ChartTwoLin clearHistory(); for (const auto item : m_chartHistory) { - ChartTwoData* chartData = item->clone(); - ChartTwoDataCartesian* cartData = dynamic_cast(chartData); + ChartTwoDataCartesian* cartData = item->clone(); CaretAssert(cartData); addHistoryItem(cartData); diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index daab74ae9..49b1af43d 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -322,9 +322,9 @@ ChartableTwoFileLineSeriesChart::isValid() const bool ChartableTwoFileLineSeriesChart::isEmpty() const { - CaretAssertToDoWarning(); // use history??? - return false; + return (m_lineChartHistory->getHistoryCount() <= 0); } + /** * Save subclass data to the scene. * -- GitLab From c27ccc1e3268078c1f4cf77b4cdaf7a4137707b3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 16 Jun 2017 10:54:27 -0500 Subject: [PATCH 287/755] Add a weak pointer for ChartTwoOverlay so that the Line Series History dialog can store the weak pointer and use it to verify the chart two overlay is valid when the dialog is updated. --- src/Brain/ChartTwoOverlay.cxx | 29 +++- src/Brain/ChartTwoOverlay.h | 8 + src/Brain/ChartTwoOverlaySet.cxx | 141 ++++++------------ src/Brain/ChartTwoOverlaySet.h | 20 +-- src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 58 +++++-- src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 6 +- 6 files changed, 132 insertions(+), 130 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index d0aa1ae90..4e730be0c 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -110,6 +110,31 @@ ChartTwoOverlay::~ChartTwoOverlay() EventManager::get()->removeAllEventsFromListener(this); } +/** + * @return Weak pointer to instance. + * This weak pointer stored by classes (such as those in the GUI) + * safely test if an instance is still valid and can be safely accessed. + */ +std::weak_ptr +ChartTwoOverlay::getWeakPointerToSelf() +{ + return m_weakPointerToSelf; +} + +/** + * Set the weak pointer for this instance. + * This is called by the parent ChartTwoOverlaySet. + * + * @param weakPointerToSelf + * Weak pointer to this instance. + */ +void +ChartTwoOverlay::setWeakPointerToSelf(std::weak_ptr weakPointerToSelf) +{ + m_weakPointerToSelf = weakPointerToSelf; + CaretAssert( ! m_weakPointerToSelf.expired()); + CaretAssert(m_weakPointerToSelf.lock().get() == this); +} /** * Receive an event. @@ -728,8 +753,6 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma if (selectedFileMapNamesOut != NULL) { for (int32_t i = 0; i < numMaps; i++) { selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); - // const AString namePrefix = "Column "; - // selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); } } } @@ -744,8 +767,6 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma if (selectedFileMapNamesOut != NULL) { for (int32_t i = 0; i < numMaps; i++) { selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); - // const AString namePrefix = "Row "; - // selectedFileMapNamesOut->push_back(namePrefix + QString::number(i)); } } } diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 35a238ded..e411e2c80 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -56,6 +56,8 @@ namespace caret { virtual ~ChartTwoOverlay(); + std::weak_ptr getWeakPointerToSelf(); + ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; ChartTwoCompoundDataType getChartTwoCompoundDataType() const; @@ -155,6 +157,8 @@ namespace caret { ChartTwoOverlay& operator=(const ChartTwoOverlay&); + void setWeakPointerToSelf(std::weak_ptr weakPointerToSelf); + void getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector* selectedFileMapNamesOut, @@ -206,8 +210,12 @@ namespace caret { /** Location of vertical cartesian axis*/ mutable ChartAxisLocationEnum::Enum m_cartesianVerticalAxisLocation; + /** A weak pointer to 'self' so that can be stored to safely test instance is valid and can be accessed */ + std::weak_ptr m_weakPointerToSelf; + // ADD_NEW_MEMBERS_HERE + friend class ChartTwoOverlaySet; }; #ifdef __CHART_TWO_OVERLAY_DECLARE__ diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 3680fd7f6..c81fe403a 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -141,10 +141,12 @@ m_tabIndex(tabIndex) &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - m_overlays[i] = new ChartTwoOverlay(this, - m_chartDataType, - m_tabIndex, - i); + m_overlays.push_back(std::make_shared(this, + m_chartDataType, + m_tabIndex, + i)); + CaretAssertVectorIndex(m_overlays, i); + m_overlays[i]->setWeakPointerToSelf(m_overlays[i]); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); @@ -158,9 +160,7 @@ m_tabIndex(tabIndex) ChartTwoOverlaySet::~ChartTwoOverlaySet() { EventManager::get()->removeAllEventsFromListener(this); - for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { - delete m_overlays[i]; - } + m_overlays.clear(); delete m_sceneAssistant; } @@ -189,7 +189,7 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) ChartTwoOverlay* ChartTwoOverlaySet::getPrimaryOverlay() { - return m_overlays[0]; + return m_overlays[0].get(); } /** @@ -198,11 +198,15 @@ ChartTwoOverlaySet::getPrimaryOverlay() const ChartTwoOverlay* ChartTwoOverlaySet::getPrimaryOverlay() const { - return m_overlays[0]; + return m_overlays[0].get(); } /** - * Get the overlay at the specified index. + * Get the overlay at the specified index. If caller needs + * to store the pointer there is a risk that the overlay + * may be destroyed. Consider using getOverlayWeakPointer() + * instead. + * * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. @@ -213,17 +217,39 @@ ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) const CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); - return m_overlays[overlayNumber]; + return m_overlays[overlayNumber].get(); } /** - * Get the overlay at the specified index. + * Get the overlay at the specified index. If caller needs + * to store the pointer there is a risk that the overlay + * may be destroyed. Consider using getOverlayWeakPointer() + * instead. + * * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. */ ChartTwoOverlay* ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) +{ + CaretAssertArrayIndex(m_overlays, + BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, + overlayNumber); + return m_overlays[overlayNumber].get(); +} + +/** + * Get the a "weak pointer" to the chart overlay at the given + * index. Caller can store this pointer and test to see + * if the chart overlay is still valid. + * + * @param overlayNumber + * Index of the overlay. + * @return Weak pointer to chart verlay at the given index. + */ +std::weak_ptr +ChartTwoOverlaySet::getOverlayWeakPointer(const int32_t overlayNumber) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, @@ -231,6 +257,7 @@ ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) return m_overlays[overlayNumber]; } + /** * Get a text description of the window's content. * @@ -313,36 +340,6 @@ ChartTwoOverlaySet::getNumberOfDisplayedOverlays() const return m_numberOfDisplayedOverlays; } -/** - * Sets the number of displayed overlays. - * @param numberOfDisplayedOverlays - * Number of overlays for display. - */ -void -ChartTwoOverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays) -{ - const int32_t oldNumberOfDisplayedOverlays = m_numberOfDisplayedOverlays; - m_numberOfDisplayedOverlays = numberOfDisplayedOverlays; - if (m_numberOfDisplayedOverlays < BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { - m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; - } - if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { - m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; - } - - /* - * If one overlay added (probably through GUI), - * shift all overlays down one position so that - * new overlay appears at the top - */ - const int32_t numberOfOverlaysAdded = m_numberOfDisplayedOverlays - oldNumberOfDisplayedOverlays; - if (numberOfOverlaysAdded == 1) { - for (int32_t i = (m_numberOfDisplayedOverlays - 1); i >= 0; i--) { - moveDisplayedOverlayDown(i); - } - } -} - /** * Insert an overlay below this overlay * @param overlayIndex @@ -398,7 +395,7 @@ ChartTwoOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) m_numberOfDisplayedOverlays--; for (int32_t i = overlayIndex; i < m_numberOfDisplayedOverlays; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i+1); - m_overlays[i]->copyData(m_overlays[i+1]); + m_overlays[i]->copyData(m_overlays[i+1].get()); } } } @@ -416,7 +413,7 @@ ChartTwoOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) { if (overlayIndex > 0) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); - m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1]); + m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1].get()); } } @@ -434,7 +431,7 @@ ChartTwoOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) const int32_t nextOverlayIndex = overlayIndex + 1; if (nextOverlayIndex < m_numberOfDisplayedOverlays) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, nextOverlayIndex); - m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex]); + m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex].get()); } } @@ -605,60 +602,6 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } } -///** -// * @return The chart left-axis. -// */ -//ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisLeft() -//{ -// return m_chartAxisLeft.get(); -//} -// -///** -// * @return The chart left-axis (const method) -// */ -//const ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisLeft() const -//{ -// return m_chartAxisLeft.get(); -//} -// -///** -// * @return The chart right-axis. -// */ -//ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisRight() -//{ -// return m_chartAxisRight.get(); -//} -// -///** -// * @return The chart right-axis (const method) -// */ -//const ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisRight() const -//{ -// return m_chartAxisRight.get(); -//} -// -///** -// * @return The chart bottom-axis. -// */ -//ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisBottom() -//{ -// return m_chartAxisBottom.get(); -//} -// -///** -// * @return The chart bottom-axis (const method) -// */ -//const ChartTwoCartesianAxis* -//ChartTwoOverlaySet::getChartAxisBottom() const -//{ -// return m_chartAxisBottom.get(); -//} - /** * Get the displayed chart axes. */ diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index b1820f70a..127728076 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -55,26 +55,14 @@ namespace caret { const ChartTwoOverlay* getOverlay(const int32_t overlayNumber) const; - void addDisplayedOverlay(); + std::weak_ptr getOverlayWeakPointer(const int32_t overlayNumber); - void setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays); + void addDisplayedOverlay(); int32_t getNumberOfDisplayedOverlays() const; ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); -// ChartTwoCartesianAxis* getChartAxisLeft(); -// -// const ChartTwoCartesianAxis* getChartAxisLeft() const; -// -// ChartTwoCartesianAxis* getChartAxisRight(); -// -// const ChartTwoCartesianAxis* getChartAxisRight() const; -// -// ChartTwoCartesianAxis* getChartAxisBottom(); -// -// const ChartTwoCartesianAxis* getChartAxisBottom() const; - std::vector getDisplayedChartAxes() const; void insertOverlayAbove(const int32_t overlayIndex); @@ -129,7 +117,9 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - ChartTwoOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; + //ChartTwoOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; + + std::vector> m_overlays; const ChartTwoDataTypeEnum::Enum m_chartDataType; diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 491745de0..9673980bf 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -134,6 +134,7 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent */ ChartTwoLineSeriesHistoryDialog::~ChartTwoLineSeriesHistoryDialog() { + std::cout << "CLOSING CHART LINE SERIES HISTORY" << std::endl; } /** @@ -142,9 +143,27 @@ ChartTwoLineSeriesHistoryDialog::~ChartTwoLineSeriesHistoryDialog() void ChartTwoLineSeriesHistoryDialog::updateDialog() { - updateDialogContent(m_chartOverlay); + updateDialogContentPrivate(); } +/** + * @return The chart overlay in this dialog (May be NULL !) + */ +ChartTwoOverlay* +ChartTwoLineSeriesHistoryDialog::getChartOverlay() +{ + ChartTwoOverlay* chartOverlay = NULL; + if (m_chartOverlayWeakPointer.expired()) { + m_chartOverlayWeakPointer.reset(); + } + else { + chartOverlay = m_chartOverlayWeakPointer.lock().get(); + } + + return chartOverlay; +} + + /** * Update dialog if the given chart overlay is in the dialog. * This may occur when the user changes the file in the chart overlay. @@ -155,9 +174,15 @@ ChartTwoLineSeriesHistoryDialog::updateDialog() void ChartTwoLineSeriesHistoryDialog::updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay) { - if (m_chartOverlay == chartOverlay) { - updateDialogContent(m_chartOverlay); + ChartTwoOverlay* currentChartOverlay = getChartOverlay(); + + if (currentChartOverlay != NULL) { + if (chartOverlay != currentChartOverlay) { + return; + } } + + updateDialogContentPrivate(); } /** @@ -169,7 +194,20 @@ ChartTwoLineSeriesHistoryDialog::updateIfThisChartOverlayIsInDialog(const ChartT void ChartTwoLineSeriesHistoryDialog::updateDialogContent(ChartTwoOverlay* chartOverlay) { - m_chartOverlay = chartOverlay; + CaretAssert(chartOverlay); + m_chartOverlayWeakPointer = chartOverlay->getWeakPointerToSelf(); + updateDialogContentPrivate(); +} + +void +ChartTwoLineSeriesHistoryDialog::updateDialogContentPrivate() +{ + ChartTwoOverlay* chartOverlay = getChartOverlay(); + if (chartOverlay == NULL) { + close(); + return; + } + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { @@ -191,6 +229,7 @@ ChartTwoLineSeriesHistoryDialog::updateDialogContent(ChartTwoOverlay* chartOverl } } + /** * @return Map file in the dialog. */ @@ -198,11 +237,12 @@ CaretMappableDataFile* ChartTwoLineSeriesHistoryDialog::getMapFile() { CaretMappableDataFile* mapFile = NULL; - if (m_chartOverlay != NULL) { - if (m_chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { + ChartTwoOverlay* chartOverlay = getChartOverlay(); + if (chartOverlay != NULL) { + if (chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t mapIndex = -1; - m_chartOverlay->getSelectionData(mapFile, indexType, mapIndex); + chartOverlay->getSelectionData(mapFile, indexType, mapIndex); } } @@ -275,12 +315,8 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi m_tableWidget->setCellWidget(iRow, COLUMN_REMOVE, removeHistoryLabel); -// flags = (Qt::ItemIsEnabled); -// //| Qt::ItemIsSelectable); } else if (j == COLUMN_COLOR) { -// flags = (Qt::ItemIsEnabled -// | Qt::ItemIsSelectable); CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), m_colorItemSignalMapper, SLOT(map())); diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h index faf69faba..f706e8da1 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h @@ -77,13 +77,17 @@ namespace caret { ChartTwoLineSeriesHistoryDialog& operator=(const ChartTwoLineSeriesHistoryDialog&); + void updateDialogContentPrivate(); + void loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory); + ChartTwoOverlay* getChartOverlay(); + ChartTwoLineSeriesHistory* getLineSeriesHistory(); CaretMappableDataFile* getMapFile(); - ChartTwoOverlay* m_chartOverlay = NULL; + std::weak_ptr m_chartOverlayWeakPointer; QTableWidget* m_tableWidget; -- GitLab From 76c29f12600aa9711fc7cb3379f782401e955f2d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 16 Jun 2017 10:55:31 -0500 Subject: [PATCH 288/755] Removed print statement. --- src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 9673980bf..620ec8774 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -134,7 +134,6 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent */ ChartTwoLineSeriesHistoryDialog::~ChartTwoLineSeriesHistoryDialog() { - std::cout << "CLOSING CHART LINE SERIES HISTORY" << std::endl; } /** -- GitLab From b37e024a6a869e71eea56dd5f2dfea817f5fb6e2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 16 Jun 2017 11:12:38 -0500 Subject: [PATCH 289/755] Update chart two line series drawing so that newer charts are drawn on top of older charts. --- src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0349eac61..a5f76bfe3 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -680,7 +680,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } std::vector> histogramDrawingInfo; - std::vector lineSeriesChartsToDraw; + std::deque lineSeriesChartsToDraw; /* * Get the histogram drawing information and overall extent @@ -780,7 +780,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch break; } - lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, + lineSeriesChartsToDraw.push_front(LineSeriesChartDrawingInfo(lineSeriesChart, data, chartOverlay->getCartesianVerticalAxisLocation())); } -- GitLab From cfdd1196b02c0bc4a6ab14ee5188f25b595a9f57 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Jun 2017 14:59:53 -0500 Subject: [PATCH 290/755] Fixed problems with chart axis title drawn in incorrect location when lock tab/window aspect was selected. Fixed problem with chart label annotation drawn in all tabs instead of just the correct tab. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 325 +++++++----------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 16 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 92 +++-- 3 files changed, 176 insertions(+), 257 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index f54ee3d52..3c7cf1a00 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -55,6 +55,7 @@ #include "EventBrowserTabGet.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fT3f.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" @@ -137,7 +138,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(cons } /** - * Get the window coordinate for display of the annotation. + * Get the drawing space coordinate for display of the annotation. * * @param annotation * The annotation. @@ -147,24 +148,24 @@ BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(cons * The annotation coordinate space. * @param surfaceDisplayed * Surface that is displayed (may be NULL !) - * @param windowXYZOut - * Output containing the window coordinate. + * @param xyzOut + * Output containing the drawing space coordinate. * @return - * True if the window coordinate is valid, else false. + * True if the drawing space coordinate is valid, else false. */ bool -BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const Annotation* annotation, - const AnnotationCoordinate* coordinate, - const Surface* surfaceDisplayed, - float windowXYZOut[3]) const +BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(const Annotation* annotation, + const AnnotationCoordinate* coordinate, + const Surface* surfaceDisplayed, + float xyzOut[3]) const { const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace = annotation->getCoordinateSpace(); float stereotaxicXYZ[3] = { 0.0, 0.0, 0.0 }; bool stereotaxicXYZValid = false; - float windowXYZ[3] = { 0.0, 0.0, 0.0 }; - bool windowXYZValid = false; + float drawingSpaceXYZ[3] = { 0.0, 0.0, 0.0 }; + bool drawingSpaceXYZValid = false; float annotationXYZ[3]; coordinate->getXYZ(annotationXYZ); @@ -267,22 +268,37 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A } break; case AnnotationCoordinateSpaceEnum::TAB: - viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); - windowXYZValid = true; + viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); + drawingSpaceXYZValid = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: { - int32_t annotationViewport[4]; - annotation->getViewportCoordinateSpaceViewport(annotationViewport); - windowXYZ[0] = annotationXYZ[0] + annotationViewport[0]; - windowXYZ[1] = annotationXYZ[1] + annotationViewport[1]; - windowXYZ[2] = annotationXYZ[2]; - windowXYZValid = true; + drawingSpaceXYZ[0] = annotationXYZ[0]; + drawingSpaceXYZ[1] = annotationXYZ[1]; + drawingSpaceXYZ[2] = annotationXYZ[2]; + drawingSpaceXYZValid = true; + + const bool drawCrossFlag = false; + if (drawCrossFlag) { + const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; + std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + redRGBA)); + crossShape->addVertex(drawingSpaceXYZ[0], + drawingSpaceXYZ[1] - 10); + crossShape->addVertex(drawingSpaceXYZ[0], + drawingSpaceXYZ[1] + 10); + crossShape->addVertex(drawingSpaceXYZ[0] - 10, + drawingSpaceXYZ[1]); + crossShape->addVertex(drawingSpaceXYZ[0] + 10, + drawingSpaceXYZ[1]); + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + crossShape.get()); + } } break; case AnnotationCoordinateSpaceEnum::WINDOW: - viewportToOpenGLWindowCoordinate(annotationXYZ, windowXYZ); - windowXYZValid = true; + viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); + drawingSpaceXYZValid = true; break; } @@ -292,22 +308,22 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationWindowCoordinate(const A * as all annotations are drawn in window coordinates. */ - if (convertModelToWindowCoordinate(stereotaxicXYZ, windowXYZ)) { + if (convertModelToWindowCoordinate(stereotaxicXYZ, drawingSpaceXYZ)) { stereotaxicXYZValid = false; - windowXYZValid = true; + drawingSpaceXYZValid = true; } else { - CaretLogSevere("Failed to convert model coordinates to window coordinates for annotation drawing."); + CaretLogSevere("Failed to convert model coordinates to drawing space coordinates for annotation drawing."); } } - if (windowXYZValid) { - windowXYZOut[0] = windowXYZ[0]; - windowXYZOut[1] = windowXYZ[1]; - windowXYZOut[2] = windowXYZ[2]; + if (drawingSpaceXYZValid) { + xyzOut[0] = drawingSpaceXYZ[0]; + xyzOut[1] = drawingSpaceXYZ[1]; + xyzOut[2] = drawingSpaceXYZ[2]; } - return windowXYZValid; + return drawingSpaceXYZValid; } @@ -506,10 +522,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic m_volumeSpacePlaneValid = true; std::vector dummyColorBars; - std::vector dummyAnnotationGraphicsLabelsForDrawing; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, dummyColorBars, - dummyAnnotationGraphicsLabelsForDrawing, + NULL, NULL, sliceThickness); } @@ -544,12 +559,44 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, m_volumeSpacePlaneValid = false; - const float sliceThickness = 0.0; - drawAnnotationsInternal(drawingCoordinateSpace, - colorBars, - annotationChartGraphicsLabelsForDrawing, - surfaceDisplayed, - sliceThickness); + const float sliceThickness = 0.0; + + if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { + GLint savedViewport[4]; + glGetIntegerv(GL_VIEWPORT, + savedViewport); + + std::vector emptyColorBars; + + for (auto graphicsLabel : annotationChartGraphicsLabelsForDrawing) { + CaretAssert(graphicsLabel); + + int32_t viewport[4]; + graphicsLabel->getViewportCoordinateSpaceViewport(viewport); + glViewport(viewport[0], + viewport[1], + viewport[2], + viewport[3]); + + drawAnnotationsInternal(drawingCoordinateSpace, + emptyColorBars, + graphicsLabel, + surfaceDisplayed, + sliceThickness); + } + + glViewport(savedViewport[0], + savedViewport[1], + savedViewport[2], + savedViewport[3]); + } + else { + drawAnnotationsInternal(drawingCoordinateSpace, + colorBars, + NULL, + surfaceDisplayed, + sliceThickness); + } m_inputs = NULL; } @@ -563,8 +610,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, * Surface that is displayed. May be NULL in some instances. * @param colorbars * Colorbars that will be drawn. - * @param annotationChartGraphicsLabelsForDrawing - * Annotation chart two labels that will be drawn. + * @param annotationGraphicsLabel + * Annotation graphics label that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param sliceThickness @@ -573,7 +620,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartGraphicsLabelsForDrawing, + AnnotationGraphicsLabel* annotationGraphicsLabel, const Surface* surfaceDisplayed, const float sliceThickness) { @@ -604,6 +651,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat bool drawAnnotationsFromFilesFlag = true; + bool haveDisplayGroupFlag = true; switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; @@ -612,8 +660,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(annotationGraphicsLabel); + haveDisplayGroupFlag = false; break; case AnnotationCoordinateSpaceEnum::WINDOW: + haveDisplayGroupFlag = false; switch (m_inputs->m_windowDrawingMode) { case Inputs::WINDOW_DRAWING_NO: drawAnnotationsFromFilesFlag = false; @@ -629,7 +680,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat * tab index is invalid so it must be ignored. */ DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_A; - if (drawingCoordinateSpace != AnnotationCoordinateSpaceEnum::WINDOW) { + if (haveDisplayGroupFlag) { displayGroup = dpa->getDisplayGroupForTab(m_inputs->m_tabIndex); } @@ -711,9 +762,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - annotationsFromFile.insert(annotationsFromFile.end(), - annotationChartGraphicsLabelsForDrawing.begin(), - annotationChartGraphicsLabelsForDrawing.end()); + annotationsFromFile.push_back(annotationGraphicsLabel); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: @@ -768,12 +817,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat colorBars.begin(), colorBars.end()); } - -// if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { -// annotationsFromFile.insert(annotationsFromFile.end(), -// annotationChartGraphicsLabelsForDrawing.begin(), -// annotationChartGraphicsLabelsForDrawing.end()); -// } } break; } @@ -1042,43 +1085,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::endOpenGLForDrawing(GLint savedShadeM glPopMatrix(); } -///** -// * Setup to drawn an annotation in viewport space. -// * -// * @param annotation -// * Annotation in viewport space. -// * @param transformationInfo -// * Transformation info that is saved. -// */ -//void -//BrainOpenGLAnnotationDrawingFixedPipeline::setupViewportSpaceDrawing(const Annotation* annotation, -// TransformationInfo& transformationInfo) -//{ -// CaretAssert(annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::VIEWPORT); -// -// transformationInfo.save(); -// -// GLdouble depthRange[2]; -// glGetDoublev(GL_DEPTH_RANGE, -// depthRange); -// -// GLint annotationViewport[4]; -// annotation->getViewportCoordinateSpaceViewport(annotationViewport); -// /* -// * All drawing is in window space -// */ -// glMatrixMode(GL_PROJECTION); -// glPushMatrix(); -// glLoadIdentity(); -// glOrtho(0.0, annotationViewport[2], -// 0.0, annotationViewport[3], -// depthRange[0], depthRange[1]); -// glMatrixMode(GL_MODELVIEW); -// glPushMatrix(); -// glLoadIdentity(); -//} - - /** * Get color used for identification when drawing an annotation. * @@ -1188,11 +1194,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil CaretAssert(box); CaretAssert(box->getType() == AnnotationTypeEnum::BOX); - float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(box, + float annXYZ[3]; + if ( ! getAnnotationDrawingSpaceCoordinate(box, box->getCoordinate(), surfaceDisplayed, - windowXYZ)) { + annXYZ)) { return false; } @@ -1200,7 +1206,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil float bottomRight[3]; float topRight[3]; float topLeft[3]; - if ( ! getAnnotationTwoDimShapeBounds(box, windowXYZ, + if ( ! getAnnotationTwoDimShapeBounds(box, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } @@ -1322,39 +1328,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawChartGraphicsLabel(AnnotationFile CaretAssert(chartGraphicsLabel); CaretAssert(chartGraphicsLabel->getType() == AnnotationTypeEnum::GRAPHICS_LABEL); -// const GLint savedModelSpaceViewport[4] = { -// m_modelSpaceModelMatrix[0], -// m_modelSpaceModelMatrix[1], -// m_modelSpaceModelMatrix[2], -// m_modelSpaceModelMatrix[3] -// }; -// -// glPushAttrib(GL_VIEWPORT_BIT); - -// GLint viewportSave[4]; -// glGetIntegerv(GL_VIEWPORT, viewportSave); - -// int32_t labelViewport[4]; -// chartTwoAxisLabel->getAxisViewport(labelViewport); -// glViewport(labelViewport[0], labelViewport[1], labelViewport[2], labelViewport[3]); - -// m_modelSpaceViewport[0] = labelViewport[0]; -// m_modelSpaceViewport[1] = labelViewport[1]; -// m_modelSpaceViewport[2] = labelViewport[2]; -// m_modelSpaceViewport[3] = labelViewport[3]; - drawText(annotationFile, chartGraphicsLabel, NULL); - -// glPopAttrib(); - -// m_modelSpaceViewport[0] = savedModelSpaceViewport[0]; -// m_modelSpaceViewport[1] = savedModelSpaceViewport[1]; -// m_modelSpaceViewport[2] = savedModelSpaceViewport[2]; -// m_modelSpaceViewport[3] = savedModelSpaceViewport[3]; - -// glViewport(viewportSave[0], viewportSave[1], viewportSave[2], viewportSave[3]); } @@ -1373,11 +1349,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati CaretAssert(colorBar); CaretAssert(colorBar->getType() == AnnotationTypeEnum::COLOR_BAR); - float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(colorBar, + float annXYZ[3]; + if ( ! getAnnotationDrawingSpaceCoordinate(colorBar, colorBar->getCoordinate(), NULL, - windowXYZ)) { + annXYZ)) { return; } @@ -1385,7 +1361,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati float bottomRight[3]; float topRight[3]; float topLeft[3]; - if ( ! getAnnotationTwoDimShapeBounds(colorBar, windowXYZ, + if ( ! getAnnotationTwoDimShapeBounds(colorBar, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return; } @@ -1958,12 +1934,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi CaretAssert(oval); CaretAssert(oval->getType() == AnnotationTypeEnum::OVAL); - float windowXYZ[3]; + float annXYZ[3]; - if ( ! getAnnotationWindowCoordinate(oval, + if ( ! getAnnotationDrawingSpaceCoordinate(oval, oval->getCoordinate(), surfaceDisplayed, - windowXYZ)) { + annXYZ)) { return false; } @@ -1971,7 +1947,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi float bottomRight[3]; float topRight[3]; float topLeft[3]; - if ( ! getAnnotationTwoDimShapeBounds(oval, windowXYZ, + if ( ! getAnnotationTwoDimShapeBounds(oval, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } @@ -2003,7 +1979,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi if (drawAnnotationFlag) { glPushMatrix(); - glTranslatef(windowXYZ[0], windowXYZ[1], windowXYZ[2]); + glTranslatef(annXYZ[0], annXYZ[1], annXYZ[2]); if (rotationAngle != 0.0) { glRotatef(-rotationAngle, 0.0, 0.0, 1.0); } @@ -2137,15 +2113,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX); float brainordinateXYZ[3]; - if (getAnnotationWindowCoordinate(text, + if (getAnnotationDrawingSpaceCoordinate(text, &noOffsetCoord, surfaceDisplayed, brainordinateXYZ)) { - float windowXYZ[3]; - if (getAnnotationWindowCoordinate(text, + float annXYZ[3]; + if (getAnnotationDrawingSpaceCoordinate(text, coord, surfaceDisplayed, - windowXYZ)) { + annXYZ)) { const bool clipAtBoxFlag = true; if (clipAtBoxFlag) { @@ -2154,10 +2130,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin topRight, topLeft, brainordinateXYZ, - windowXYZ); + annXYZ); } - createLineCoordinates(windowXYZ, + createLineCoordinates(annXYZ, brainordinateXYZ, text->getLineWidth(), false, @@ -2279,11 +2255,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi } - float windowXYZ[3]; - if ( ! getAnnotationWindowCoordinate(text, + float annXYZ[3]; + if ( ! getAnnotationDrawingSpaceCoordinate(text, text->getCoordinate(), surfaceDisplayed, - windowXYZ)) { + annXYZ)) { return false; } @@ -2305,7 +2281,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi const bool modifiedStatus = text->isModified(); m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*text, - windowXYZ[0], windowXYZ[1], windowXYZ[2], + annXYZ[0], annXYZ[1], annXYZ[2], m_modelSpaceViewport[2], m_modelSpaceViewport[3], bottomLeft, bottomRight, topRight, topLeft); @@ -2375,15 +2351,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi AString msg("Drawing Text: " + text->getText() + " DepthTest=" + AString::fromBool(depthTestFlag)); const float* xyz = text->getCoordinate()->getXYZ(); msg.appendWithNewLine(" Stereotaxic: " + AString::fromNumbers(xyz, 3, ",")); - msg.appendWithNewLine(" Window: " + AString::fromNumbers(windowXYZ, 3, ",")); + msg.appendWithNewLine(" Drawing Space: " + AString::fromNumbers(annXYZ, 3, ",")); std::cout << qPrintable(msg) << std::endl; } } if (depthTestFlag) { - m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(windowXYZ[0], - windowXYZ[1], - windowXYZ[2], + m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(annXYZ[0], + annXYZ[1], + annXYZ[2], *text); drawnFlag = true; } @@ -2398,7 +2374,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi float br[3]; float tr[3]; float tl[3]; - getAnnotationTwoDimShapeBounds(text, windowXYZ, bl, br, tr, tl); + getAnnotationTwoDimShapeBounds(text, annXYZ, bl, br, tr, tl); std::vector boxCoords; boxCoords.insert(boxCoords.end(), bl, bl + 3); @@ -2413,8 +2389,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi } } else { - m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(windowXYZ[0], - windowXYZ[1], + m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(annXYZ[0], + annXYZ[1], *text); drawnFlag = true; } @@ -2481,12 +2457,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF CaretLogWarning("Attempt to draw invalid image annotation."); } - float windowXYZ[3]; + float annXYZ[3]; - if ( ! getAnnotationWindowCoordinate(image, + if ( ! getAnnotationDrawingSpaceCoordinate(image, image->getCoordinate(), surfaceDisplayed, - windowXYZ)) { + annXYZ)) { return false; } @@ -2494,7 +2470,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF float bottomRight[3]; float topRight[3]; float topLeft[3]; - if ( ! getAnnotationTwoDimShapeBounds(image, windowXYZ, + if ( ! getAnnotationTwoDimShapeBounds(image, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } @@ -2543,7 +2519,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF AString msg("Drawing Image: DepthTest=" + AString::fromBool(depthTestFlag)); const float* xyz = image->getCoordinate()->getXYZ(); msg.appendWithNewLine(" Stereotaxic: " + AString::fromNumbers(xyz, 3, ",")); - msg.appendWithNewLine(" Window: " + AString::fromNumbers(windowXYZ, 3, ",")); + msg.appendWithNewLine(" Drawing Space: " + AString::fromNumbers(annXYZ, 3, ",")); std::cout << qPrintable(msg) << std::endl; } } @@ -2568,15 +2544,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF drawnFlag = true; } -// drawImageBytesWithTexture(image->getDrawWithOpenGLTextureInfo(), -// bottomLeft, -// bottomRight, -// topRight, -// topLeft, -// imageRgbaBytes, -// imageWidth, -// imageHeight); - if (drawForegroundFlag) { BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, foregroundRGBA, @@ -2745,13 +2712,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi float lineHeadXYZ[3]; float lineTailXYZ[3]; - if ( ! getAnnotationWindowCoordinate(line, + if ( ! getAnnotationDrawingSpaceCoordinate(line, line->getStartCoordinate(), surfaceDisplayed, lineHeadXYZ)) { return false; } - if ( ! getAnnotationWindowCoordinate(line, + if ( ! getAnnotationDrawingSpaceCoordinate(line, line->getEndCoordinate(), surfaceDisplayed, lineTailXYZ)) { @@ -3388,37 +3355,3 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setDepthTestingStatus(const bool newD return (savedStatus == GL_TRUE); } -/* ====================================================================================== */ - -///** -// * Save the transformation matrix (viewport, model view, projection) -// */ -//void -//BrainOpenGLAnnotationDrawingFixedPipeline::TransformationInfo::save() -//{ -// glGetIntegerv(GL_VIEWPORT, m_viewport); -// glGetDoublev(GL_MODELVIEW_MATRIX, m_modelViewMatrix); -// glGetDoublev(GL_PROJECTION_MATRIX, m_projectionMatrix); -// -//} -// -///** -// * Restore the transformation matrix (viewport, model view, projection) -// */ -//void -//BrainOpenGLAnnotationDrawingFixedPipeline::TransformationInfo::restore() -//{ -// CaretAssertMessage(0, "Trying to restore info that has not been saved"); -// if ( ! m_valid) { -// return; -// } -// -// GLboolean savedMatrixMode; -// glGetBooleanv(GL_MATRIX_MODE, &savedMatrixMode); -// glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]); -// glMatrixMode(GL_PROJECTION); -// glLoadMatrixd(m_projectionMatrix); -// glMatrixMode(GL_MODELVIEW); -// glLoadMatrixd(m_modelViewMatrix); -// glMatrixMode(savedMatrixMode); -//} diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 58f23e4fc..daed01df9 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -187,14 +187,14 @@ namespace caret { void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartGraphicsLabelsForDrawing, + AnnotationGraphicsLabel* annotationChartGraphicsLabelsForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); - bool getAnnotationWindowCoordinate(const Annotation* annotation, - const AnnotationCoordinate* coordinate, - const Surface* surfaceDisplayed, - float windowXYZOut[3]) const; + bool getAnnotationDrawingSpaceCoordinate(const Annotation* annotation, + const AnnotationCoordinate* coordinate, + const Surface* surfaceDisplayed, + float xyzOut[3]) const; bool getAnnotationTwoDimShapeBounds(const AnnotationTwoDimensionalShape* annotation2D, const float windowXYZ[3], @@ -327,9 +327,6 @@ namespace caret { void endOpenGLForDrawing(GLint savedShadeModel, GLboolean savedLightingEnabled); - void setupViewportSpaceDrawing(const Annotation* annotation, - TransformationInfo& transformationInfo); - void clipLineAtTextBox(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], @@ -363,9 +360,6 @@ namespace caret { /** OpenGL Viewport */ GLint m_modelSpaceViewport[4]; - /** Browser tab's viewport */ - //GLint m_tabViewport[4]; - /** volume space plane */ Plane m_volumeSpacePlane; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 2ae486533..ddc9c6d40 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -152,11 +152,6 @@ using namespace caret; -/* - * When true, - */ -static bool drawTabAnnotationsAfterTabContentFlag = true; - /** * Constructor. * @@ -300,16 +295,13 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, this->drawModelInternal(MODE_IDENTIFICATION, viewportContent); - if (drawTabAnnotationsAfterTabContentFlag) { - /* - * Clear depth buffer since tab and window - * annotations ALWAYS are on top of - * everything else. - */ - glClear(GL_DEPTH_BUFFER_BIT); - drawTabAnnotations(viewportContent); //, -// m_tabViewport); - } + /* + * Clear depth buffer since tab and window + * annotations ALWAYS are on top of + * everything else. + */ + glClear(GL_DEPTH_BUFFER_BIT); + drawTabAnnotations(viewportContent); //, int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); @@ -632,31 +624,28 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, } if ( ! viewportContents.empty()) { - if (drawTabAnnotationsAfterTabContentFlag) { + /* + * Clear depth buffer since tab and window + * annotations ALWAYS are on top of + * everything else. + */ + glClear(GL_DEPTH_BUFFER_BIT); + + for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { /* - * Clear depth buffer since tab and window - * annotations ALWAYS are on top of - * everything else. + * Viewport of window. */ - glClear(GL_DEPTH_BUFFER_BIT); + BrainOpenGLViewportContent* vpContent = viewportContents[i]; + setTabViewport(vpContent); - for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { - /* - * Viewport of window. - */ - BrainOpenGLViewportContent* vpContent = viewportContents[i]; - setTabViewport(vpContent); - - /* - * Update foreground and background colors for model - */ - updateForegroundAndBackgroundColors(vpContent); - - drawTabAnnotations(vpContent); - //m_tabViewport); - } - } - + /* + * Update foreground and background colors for model + */ + updateForegroundAndBackgroundColors(vpContent); + + drawTabAnnotations(vpContent); + //m_tabViewport); + } /* * Draw window viewport annotations @@ -798,17 +787,13 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont this->windowTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + std::vector emptyAnnotationChartGraphicsLabelsForDrawing; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - m_annotationChartGraphicsLabelsForDrawing, + emptyAnnotationChartGraphicsLabelsForDrawing, NULL); - m_annotationDrawing->drawAnnotations(&inputs, - AnnotationCoordinateSpaceEnum::VIEWPORT, - m_annotationColorBarsForDrawing, - m_annotationChartGraphicsLabelsForDrawing, - NULL); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -883,6 +868,20 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) emptyAnnotationGraphicsLabelsForDrawing, NULL); + + + + std::vector emptyColorBars; + m_annotationDrawing->drawAnnotations(&inputs, + AnnotationCoordinateSpaceEnum::VIEWPORT, + emptyColorBars, + m_annotationChartGraphicsLabelsForDrawing, + NULL); + m_annotationChartGraphicsLabelsForDrawing.clear(); + + + + glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -981,13 +980,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, this->windowTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); - if ( ! drawTabAnnotationsAfterTabContentFlag) { - m_annotationDrawing->drawAnnotations(&inputs, - AnnotationCoordinateSpaceEnum::TAB, - m_annotationColorBarsForDrawing, - m_annotationChartGraphicsLabelsForDrawing, - NULL); - } } } -- GitLab From 5511c1cf4b36e28e2cc63906c69bf8a53fe66d0e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Jun 2017 17:10:18 -0500 Subject: [PATCH 291/755] Replaced use of AnnotationGraphicsLabel with AnnotationPercentSizeText for chart two axis labels. --- src/Annotations/Annotation.cxx | 18 ++++++++++ src/Annotations/AnnotationText.cxx | 17 ++++++++++ src/Brain/AnnotationManager.cxx | 6 ++-- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 18 +++++----- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 4 +-- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 18 +++++----- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 +-- .../BrainOpenGLChartTwoDrawingInterface.h | 4 +-- src/Brain/BrainOpenGLFixedPipeline.cxx | 34 +++++++++---------- src/Brain/BrainOpenGLFixedPipeline.h | 4 +-- src/Brain/EventAnnotationChartLabelGet.cxx | 4 +-- src/Brain/EventAnnotationChartLabelGet.h | 8 ++--- src/Charting/ChartTwoCartesianAxis.cxx | 12 ++++--- src/Charting/ChartTwoCartesianAxis.h | 8 ++--- 14 files changed, 100 insertions(+), 60 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 7f306cd4e..2b2609c29 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -277,6 +277,24 @@ Annotation::replaceWithCopyOfAnnotation(const Annotation* annotation) bool Annotation::isDeletable() const { + switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + /* + * Viewport annotations are not in annotation files + * so not deletable + */ + return false; + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + return true; } diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index 437a17934..d0d56c2ce 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -692,6 +692,23 @@ AnnotationText::setCustomTextColor(const uint8_t rgba[4]) bool AnnotationText::isFontColorGuiEditable() const { + switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + /* + * Viewport annotations do not allow changing of font color + */ + return false; + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + return true; } diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index d0931e3ac..4ea527599 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -207,7 +207,7 @@ AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); - std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); for (auto label : chartLabels) { label->setSelectedForEditing(windowIndex, false); @@ -495,7 +495,7 @@ AnnotationManager::getAllAnnotations() const EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); - std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); allAnnotations.insert(allAnnotations.end(), chartLabels.begin(), chartLabels.end()); @@ -642,7 +642,7 @@ AnnotationManager::getAnnotationsSelectedForEditingIncludingLabels(const int32_t EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); - std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); + std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); AnnotationFile* nullFile = NULL; for (auto cl : chartLabels) { if (cl->isSelectedForEditing(windowIndex)) { diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 3c7cf1a00..e4e38f73d 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -542,8 +542,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. - * @param annotationChartGraphicsLabelsForDrawing - * Annotation chart two labels that will be drawn. + * @param viewportAnnotations + * Annotation for drawing in viewport space * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. */ @@ -551,7 +551,7 @@ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartGraphicsLabelsForDrawing, + std::vector& viewportAnnotations, const Surface* surfaceDisplayed) { CaretAssert(inputs); @@ -568,7 +568,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, std::vector emptyColorBars; - for (auto graphicsLabel : annotationChartGraphicsLabelsForDrawing) { + for (auto graphicsLabel : viewportAnnotations) { CaretAssert(graphicsLabel); int32_t viewport[4]; @@ -610,8 +610,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, * Surface that is displayed. May be NULL in some instances. * @param colorbars * Colorbars that will be drawn. - * @param annotationGraphicsLabel - * Annotation graphics label that will be drawn. + * @param viewportAnnotationForDrawing + * Viewport space label that will be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param sliceThickness @@ -620,7 +620,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - AnnotationGraphicsLabel* annotationGraphicsLabel, + Annotation* viewportAnnotationForDrawing, const Surface* surfaceDisplayed, const float sliceThickness) { @@ -660,7 +660,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssert(annotationGraphicsLabel); + CaretAssert(viewportAnnotationForDrawing); haveDisplayGroupFlag = false; break; case AnnotationCoordinateSpaceEnum::WINDOW: @@ -762,7 +762,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - annotationsFromFile.push_back(annotationGraphicsLabel); + annotationsFromFile.push_back(viewportAnnotationForDrawing); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index daed01df9..0f68617a1 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -117,7 +117,7 @@ namespace caret { void drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& annotationChartGraphicsLabelsForDrawing, + std::vector& viewportAnnotations, const Surface* surfaceDisplayed); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, @@ -187,7 +187,7 @@ namespace caret { void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - AnnotationGraphicsLabel* annotationChartGraphicsLabelsForDrawing, + Annotation* viewportAnnotationForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index a5f76bfe3..1ad40a182 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -105,9 +105,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * Selected data type. * @param viewport * Viewport for the chart. - * @param annotationChartGraphicsLabelsOut + * @param viewportSpaceAnnotationsOut * Output containing annotation chart axis labels that will be drawn - * by the Annotation OpenGL Drawing. + * by the Annotation OpenGL Drawing in viewport space. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, @@ -116,10 +116,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartGraphicsLabelsOut) + std::vector& viewportSpaceAnnotationsOut) { - annotationChartGraphicsLabelsOut.clear(); - m_annotationDrawingChartGraphicsLabels.clear(); + viewportSpaceAnnotationsOut.clear(); + m_viewportSpaceAnnotationsOut.clear(); CaretAssert(brain); CaretAssert(browserTabContent); @@ -275,7 +275,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, restoreStateOfOpenGL(); - annotationChartGraphicsLabelsOut = m_annotationDrawingChartGraphicsLabels; + viewportSpaceAnnotationsOut = m_viewportSpaceAnnotationsOut; } ///** @@ -1678,7 +1678,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - const AnnotationGraphicsLabel* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); + const AnnotationPercentSizeText* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); const AString axisTitle = chartAxisLabel->getText(); if ( ! axisTitle.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); @@ -2129,7 +2129,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data && (axisVpHeight > 0.0)) { // const float labelPercentX = 100.0f * (axisTextCenterX / axisVpWidth); // const float labelPercentY = 100.0f * (axisTextCenterY / axisVpHeight); - AnnotationGraphicsLabel* chartLabel = axis->getAnnotationAxisLabel(); + AnnotationPercentSizeText* chartLabel = axis->getAnnotationAxisLabel(); chartLabel->setCustomTextColor(rgba); chartLabel->setTextColor(CaretColorEnum::CUSTOM); chartLabel->setTabIndex(m_tabIndex); @@ -2142,7 +2142,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data // labelPercentY, // 0.0f); - m_annotationDrawingChartGraphicsLabels.push_back(chartLabel); + m_viewportSpaceAnnotationsOut.push_back(chartLabel); } // /* diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index a1542fd7c..cf4954715 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -30,6 +30,7 @@ namespace caret { + class Annotation; class CaretPreferences; class ChartTwoCartesianAxis; class ChartTwoDataCartesian; @@ -56,7 +57,7 @@ namespace caret { BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartGraphicsLabelsOut) override; + std::vector& viewportSpaceAnnotationsOut) override; // ADD_NEW_METHODS_HERE @@ -195,7 +196,7 @@ namespace caret { bool m_identificationModeFlag; - std::vector m_annotationDrawingChartGraphicsLabels; + std::vector m_viewportSpaceAnnotationsOut; static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 8d96cf5c1..2d2709c0b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -28,7 +28,7 @@ namespace caret { - class AnnotationGraphicsLabel; + class Annotation; class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; @@ -67,7 +67,7 @@ namespace caret { BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& annotationChartGraphicsLabelsOut) = 0; + std::vector& annotationChartGraphicsLabelsOut) = 0; // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index ddc9c6d40..53d9cba83 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -270,7 +270,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, setTabViewport(viewportContent); - m_annotationChartGraphicsLabelsForDrawing.clear(); + m_viewportSpaceAnnotations.clear(); std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); @@ -350,7 +350,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex m_clippingPlaneGroup = NULL; - m_annotationChartGraphicsLabelsForDrawing.clear(); + m_viewportSpaceAnnotations.clear(); m_brain->getSelectionManager()->reset(); this->modeProjectionData = &projectionOut; @@ -519,7 +519,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, setTabViewport(NULL); - m_annotationChartGraphicsLabelsForDrawing.clear(); + m_viewportSpaceAnnotations.clear(); setAnnotationColorBarsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); @@ -787,11 +787,11 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont this->windowTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); - std::vector emptyAnnotationChartGraphicsLabelsForDrawing; + std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - emptyAnnotationChartGraphicsLabelsForDrawing, + emptyViewportAnnotations, NULL); glPopMatrix(); @@ -861,11 +861,11 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, windowDrawingMode); - std::vector emptyAnnotationGraphicsLabelsForDrawing; + std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, - emptyAnnotationGraphicsLabelsForDrawing, + emptyViewportAnnotations, NULL); @@ -875,9 +875,9 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::VIEWPORT, emptyColorBars, - m_annotationChartGraphicsLabelsForDrawing, + m_viewportSpaceAnnotations, NULL); - m_annotationChartGraphicsLabelsForDrawing.clear(); + m_viewportSpaceAnnotations.clear(); @@ -1815,17 +1815,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; - std::vector emptyAnnotationGraphicsLabelsForDrawing; + std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, - emptyAnnotationGraphicsLabelsForDrawing, + emptyViewportAnnotations, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, - emptyAnnotationGraphicsLabelsForDrawing, + emptyViewportAnnotations, NULL); } } @@ -1865,17 +1865,17 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; - std::vector emptyAnnotationGraphicsLabelsForDrawing; + std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, - emptyAnnotationGraphicsLabelsForDrawing, + emptyViewportAnnotations, surface); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, - emptyAnnotationGraphicsLabelsForDrawing, + emptyViewportAnnotations, NULL); } @@ -5396,7 +5396,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, CaretAssert(browserTabContent); CaretAssert(chartModel); - m_annotationChartGraphicsLabelsForDrawing.clear(); + m_viewportSpaceAnnotations.clear(); BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, @@ -5405,7 +5405,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, - m_annotationChartGraphicsLabelsForDrawing); + m_viewportSpaceAnnotations); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 21e368bd7..95f2054b1 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -42,7 +42,7 @@ namespace caret { - class AnnotationGraphicsLabel; + class Annotation; class AnnotationText; class BoundingBox; class Brain; @@ -622,7 +622,7 @@ namespace caret { std::vector m_annotationColorBarsForDrawing; - std::vector m_annotationChartGraphicsLabelsForDrawing; + std::vector m_viewportSpaceAnnotations; static bool s_staticInitialized; diff --git a/src/Brain/EventAnnotationChartLabelGet.cxx b/src/Brain/EventAnnotationChartLabelGet.cxx index fd1d29d14..9ba0d4238 100644 --- a/src/Brain/EventAnnotationChartLabelGet.cxx +++ b/src/Brain/EventAnnotationChartLabelGet.cxx @@ -58,7 +58,7 @@ EventAnnotationChartLabelGet::~EventAnnotationChartLabelGet() * @param annotationChartLabel */ void -EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationGraphicsLabel* annotationChartLabel) +EventAnnotationChartLabelGet::addAnnotationChartLabel(Annotation* annotationChartLabel) { m_annotationChartLabels.push_back(annotationChartLabel); } @@ -66,7 +66,7 @@ EventAnnotationChartLabelGet::addAnnotationChartLabel(AnnotationGraphicsLabel* a /** * @return The annotation chart labels. */ -std::vector +std::vector EventAnnotationChartLabelGet::getAnnotationChartLabels() { return m_annotationChartLabels; diff --git a/src/Brain/EventAnnotationChartLabelGet.h b/src/Brain/EventAnnotationChartLabelGet.h index cd2bb1959..16bda9777 100644 --- a/src/Brain/EventAnnotationChartLabelGet.h +++ b/src/Brain/EventAnnotationChartLabelGet.h @@ -31,7 +31,7 @@ namespace caret { - class AnnotationGraphicsLabel; + class Annotation; class EventAnnotationChartLabelGet : public Event { @@ -40,9 +40,9 @@ namespace caret { virtual ~EventAnnotationChartLabelGet(); - void addAnnotationChartLabel(AnnotationGraphicsLabel* annotationChartLabel); + void addAnnotationChartLabel(Annotation* annotationChartLabel); - std::vector getAnnotationChartLabels(); + std::vector getAnnotationChartLabels(); // ADD_NEW_METHODS_HERE @@ -51,7 +51,7 @@ namespace caret { EventAnnotationChartLabelGet& operator=(const EventAnnotationChartLabelGet&); - std::vector m_annotationChartLabels; + std::vector m_annotationChartLabels; // ADD_NEW_MEMBERS_HERE diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 94cc6e288..3d3e2e2c5 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -66,8 +66,12 @@ m_axisLocation(axisLocation) case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: break; } - m_annotationAxisLabel = std::unique_ptr(new AnnotationGraphicsLabel(AnnotationAttributesDefaultTypeEnum::NORMAL, + m_annotationAxisLabel = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, fontSizeType)); + m_annotationAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); + m_annotationAxisLabel->setTextColor(CaretColorEnum::RED); + m_annotationAxisLabel->setLineColor(CaretColorEnum::NONE); + m_annotationAxisLabel->setBackgroundColor(CaretColorEnum::NONE); /* * Allowable range minimum and maximum @@ -103,7 +107,7 @@ m_axisLocation(axisLocation) m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); m_sceneAssistant->add("m_annotationAxisLabel", - "AnnotationGraphicsLabel", + "AnnotationPercentSizeText", m_annotationAxisLabel.get()); m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); @@ -496,7 +500,7 @@ ChartTwoCartesianAxis::toString() const /** * @return Annotation used for drawing axis label and tick mark numeric values */ -const AnnotationGraphicsLabel* +const AnnotationPercentSizeText* ChartTwoCartesianAxis::getAnnotationAxisLabel() const { return m_annotationAxisLabel.get(); @@ -505,7 +509,7 @@ ChartTwoCartesianAxis::getAnnotationAxisLabel() const /** * @return Annotation used for drawing axis label and tick mark numeric values */ -AnnotationGraphicsLabel* +AnnotationPercentSizeText* ChartTwoCartesianAxis::getAnnotationAxisLabel() { return m_annotationAxisLabel.get(); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 85a91d77e..035819d52 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -33,7 +33,7 @@ namespace caret { - class AnnotationGraphicsLabel; + class AnnotationPercentSizeText; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { @@ -106,9 +106,9 @@ namespace caret { std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; - const AnnotationGraphicsLabel* getAnnotationAxisLabel() const; + const AnnotationPercentSizeText* getAnnotationAxisLabel() const; - AnnotationGraphicsLabel* getAnnotationAxisLabel(); + AnnotationPercentSizeText* getAnnotationAxisLabel(); // ADD_NEW_METHODS_HERE @@ -165,7 +165,7 @@ namespace caret { int32_t m_userDigitsRightOfDecimal = 1; /** Annotation used for drawing axis label and tick mark numeric values*/ - std::unique_ptr m_annotationAxisLabel; + std::unique_ptr m_annotationAxisLabel; ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; -- GitLab From f74ce0db423ca60923249acbb58e0c4690063a7f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Jun 2017 08:50:23 -0500 Subject: [PATCH 292/755] Fixed crash if the user attempted to drag an annotation in viewport coordinate space. --- src/GuiQt/UserInputModeAnnotations.cxx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index b8fc6e7a0..9d25bf293 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -612,6 +612,23 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) } } + switch (draggingCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + /* + * No dragging in viewport space + */ + draggingValid = false; + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + if (draggingValid) { BrainOpenGLViewportContent* vpContent = mouseEvent.getViewportContent(); if (vpContent == NULL) { -- GitLab From 27bc892309201dc7dfa0e41298a13c623a63c763 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Jun 2017 09:13:37 -0500 Subject: [PATCH 293/755] Removed AnnotationGraphicsLabel and AnnotationPercentSizeText provides the needed functionality. --- src/Annotations/Annotation.cxx | 23 --- src/Annotations/AnnotationGraphicsLabel.cxx | 158 ------------------ src/Annotations/AnnotationGraphicsLabel.h | 66 -------- src/Annotations/AnnotationRedoUndoCommand.cxx | 4 - .../AnnotationTwoDimensionalShape.cxx | 2 - src/Annotations/AnnotationTypeEnum.cxx | 4 - src/Annotations/AnnotationTypeEnum.h | 2 - src/Annotations/CMakeLists.txt | 2 - src/Brain/AnnotationManager.cxx | 1 - ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 29 +--- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 4 - ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1 - src/Brain/ChartTwoOverlaySet.cxx | 2 +- src/Charting/ChartTwoCartesianAxis.cxx | 2 +- src/Files/AnnotationFileXmlWriter.cxx | 3 - src/GuiQt/AnnotationColorWidget.cxx | 6 +- .../AnnotationCoordinateSelectionWidget.cxx | 3 - src/GuiQt/AnnotationCreateDialog.cxx | 6 - src/GuiQt/AnnotationInsertNewWidget.cxx | 3 - src/GuiQt/AnnotationTextAlignmentWidget.cxx | 12 +- src/GuiQt/AnnotationTextOrientationWidget.cxx | 14 +- src/GuiQt/AnnotationWidthHeightWidget.cxx | 4 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 2 +- 23 files changed, 13 insertions(+), 340 deletions(-) delete mode 100644 src/Annotations/AnnotationGraphicsLabel.cxx delete mode 100644 src/Annotations/AnnotationGraphicsLabel.h diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 2b2609c29..ee4c99313 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -24,7 +24,6 @@ #undef __ANNOTATION_DECLARE__ #include "AnnotationBox.h" -#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" @@ -174,13 +173,6 @@ Annotation::clone() const myClone = new AnnotationBox(*box); } break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - { - const AnnotationGraphicsLabel* axisLabel = dynamic_cast(this); - CaretAssert(axisLabel); - myClone = new AnnotationGraphicsLabel(*axisLabel); - } - break; case AnnotationTypeEnum::COLOR_BAR: { const AnnotationColorBar* colorBar = dynamic_cast(this); @@ -364,10 +356,6 @@ Annotation::newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, case AnnotationTypeEnum::BOX: annotation = new AnnotationBox(attributeDefaultType); break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - annotation = new AnnotationGraphicsLabel(attributeDefaultType, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - break; case AnnotationTypeEnum::COLOR_BAR: annotation = new AnnotationColorBar(attributeDefaultType); break; @@ -436,9 +424,6 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - m_colorBackground = CaretColorEnum::BLACK; - break; case AnnotationTypeEnum::COLOR_BAR: m_colorBackground = CaretColorEnum::BLACK; break; @@ -490,8 +475,6 @@ Annotation::initializeAnnotationMembers() m_colorBackground = defaultColor; } break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -537,8 +520,6 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: disallowLineColorNoneFlag = true; break; @@ -627,8 +608,6 @@ Annotation::getTextForPasteMenuItems(AString& pasteMenuItemText, switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -1243,8 +1222,6 @@ Annotation::textAnnotationResetName() switch (m_type) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/Annotations/AnnotationGraphicsLabel.cxx b/src/Annotations/AnnotationGraphicsLabel.cxx deleted file mode 100644 index d994b8f03..000000000 --- a/src/Annotations/AnnotationGraphicsLabel.cxx +++ /dev/null @@ -1,158 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __ANNOTATION_GRAPHICS_LABEL_DECLARE__ -#include "AnnotationGraphicsLabel.h" -#undef __ANNOTATION_GRAPHICS_LABEL_DECLARE__ - -#include "AnnotationCoordinate.h" -#include "CaretAssert.h" - -using namespace caret; - - - -/** - * \class caret::AnnotationGraphicsLabel - * \brief Contains text for a chart two axis label - * \ingroup Annotations - */ - -/** - * Constructor. - * - * @param attributeDefaultType - * Defaults for new instances. - * @param fontSizeType - * Type of font sizing (percent width or height) - */ -AnnotationGraphicsLabel::AnnotationGraphicsLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, - const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) -: AnnotationPercentSizeText(AnnotationTypeEnum::GRAPHICS_LABEL, - attributeDefaultType, - fontSizeType) -{ - setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); - setTextColor(CaretColorEnum::RED); - setLineColor(CaretColorEnum::NONE); - setBackgroundColor(CaretColorEnum::NONE); -} - -/** - * Destructor. - */ -AnnotationGraphicsLabel::~AnnotationGraphicsLabel() -{ -} - -/** - * Copy constructor. - * @param obj - * Object that is copied. - */ -AnnotationGraphicsLabel::AnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj) -: AnnotationPercentSizeText(obj) -{ - this->copyHelperAnnotationGraphicsLabel(obj); -} - -/** - * Assignment operator. - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -AnnotationGraphicsLabel& -AnnotationGraphicsLabel::operator=(const AnnotationGraphicsLabel& obj) -{ - if (this != &obj) { - AnnotationPercentSizeText::operator=(obj); - this->copyHelperAnnotationGraphicsLabel(obj); - } - return *this; -} - -/** - * @return Is this annotation deletable? This method may be overridden - * by annotations (such as colorbars) that cannot be deleted. - */ -bool -AnnotationGraphicsLabel::isDeletable() const -{ - return false; -} - -/** - * @return True if the font color is editable in the GUI. - */ -bool -AnnotationGraphicsLabel::isFontColorGuiEditable() const -{ - return false; -} - - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -AnnotationGraphicsLabel::copyHelperAnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj) -{ -// m_axisViewport[0] = obj.m_axisViewport[0]; -// m_axisViewport[1] = obj.m_axisViewport[1]; -// m_axisViewport[2] = obj.m_axisViewport[2]; -// m_axisViewport[3] = obj.m_axisViewport[3]; -} - -///** -// * Set the viewport in which the axis data is drawn. -// * -// * @param axisViewport -// * Values for viewport. -// */ -//void -//AnnotationGraphicsLabel::setAxisViewport(const int32_t axisViewport[4]) -//{ -// m_axisViewport[0] = axisViewport[0]; -// m_axisViewport[1] = axisViewport[1]; -// m_axisViewport[2] = axisViewport[2]; -// m_axisViewport[3] = axisViewport[3]; -//} -// -///* -// * Get the viewport in which the axis is drawn. -// * -// * @param axisViewportOut -// * Output with the axis viewport. -// */ -//void -//AnnotationGraphicsLabel::getAxisViewport(int32_t axisViewportOut[4]) const -//{ -// axisViewportOut[0] = m_axisViewport[0]; -// axisViewportOut[1] = m_axisViewport[1]; -// axisViewportOut[2] = m_axisViewport[2]; -// axisViewportOut[3] = m_axisViewport[3]; -//} -// - diff --git a/src/Annotations/AnnotationGraphicsLabel.h b/src/Annotations/AnnotationGraphicsLabel.h deleted file mode 100644 index 470baef66..000000000 --- a/src/Annotations/AnnotationGraphicsLabel.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ANNOTATION_GRAPHICS_LABEL_H__ -#define __ANNOTATION_GRAPHICS_LABEL_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include "AnnotationPercentSizeText.h" - - - -namespace caret { - - class AnnotationGraphicsLabel : public AnnotationPercentSizeText { - - public: - AnnotationGraphicsLabel(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, - const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); - - virtual ~AnnotationGraphicsLabel(); - - AnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj); - - AnnotationGraphicsLabel& operator=(const AnnotationGraphicsLabel& obj); - - virtual bool isDeletable() const; - - virtual bool isFontColorGuiEditable() const; - -// void setAxisViewport(const int32_t axisViewport[4]); -// -// void getAxisViewport(int32_t axisViewportOut[4]) const; - - // ADD_NEW_METHODS_HERE - - private: - void copyHelperAnnotationGraphicsLabel(const AnnotationGraphicsLabel& obj); - - // ADD_NEW_MEMBERS_HERE - -// int32_t m_axisViewport[4] = { 0, 0, 0, 0 }; - }; - -#ifdef __ANNOTATION_GRAPHICS_LABEL_DECLARE__ - // -#endif // __ANNOTATION_GRAPHICS_LABEL_DECLARE__ - -} // namespace -#endif //__ANNOTATION_GRAPHICS_LABEL_H__ diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index da4c91f81..9064b61ca 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -25,7 +25,6 @@ #include -#include "AnnotationGraphicsLabel.h" #include "AnnotationFontAttributesInterface.h" #include "AnnotationLine.h" #include "AnnotationPercentSizeText.h" @@ -1591,9 +1590,6 @@ AnnotationRedoUndoCommand::setModeTextCharacters(const AString& text, switch (annotation->getType()) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - redoAnnotation = dynamic_cast(annotation->clone()); - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 44de59cd9..4ed200be9 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -363,8 +363,6 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp allowsSideResizingFlag = true; allowsRotationFlag = true; break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; allowsCornerResizingFlag = true; diff --git a/src/Annotations/AnnotationTypeEnum.cxx b/src/Annotations/AnnotationTypeEnum.cxx index d69843259..1f316d521 100644 --- a/src/Annotations/AnnotationTypeEnum.cxx +++ b/src/Annotations/AnnotationTypeEnum.cxx @@ -114,10 +114,6 @@ AnnotationTypeEnum::initialize() "COLOR_BAR", "Color Bar")); - enumData.push_back(AnnotationTypeEnum(GRAPHICS_LABEL, - "GRAPHICS_LABEL", - "Graphics Text Label")); - enumData.push_back(AnnotationTypeEnum(IMAGE, "IMAGE", "Image")); diff --git a/src/Annotations/AnnotationTypeEnum.h b/src/Annotations/AnnotationTypeEnum.h index 456260cf5..a0650752a 100644 --- a/src/Annotations/AnnotationTypeEnum.h +++ b/src/Annotations/AnnotationTypeEnum.h @@ -39,8 +39,6 @@ public: BOX, /** Colorbar */ COLOR_BAR, - /** Text label in graphics region */ - GRAPHICS_LABEL, /** Image */ IMAGE, /** Line */ diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 97795bc48..324754d60 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -27,7 +27,6 @@ Annotation.h AnnotationAlignmentEnum.h AnnotationAttributesDefaultTypeEnum.h AnnotationBox.h -AnnotationGraphicsLabel.h AnnotationColorBar.h AnnotationColorBarNumericText.h AnnotationColorBarPositionModeEnum.h @@ -70,7 +69,6 @@ Annotation.cxx AnnotationAlignmentEnum.cxx AnnotationAttributesDefaultTypeEnum.cxx AnnotationBox.cxx -AnnotationGraphicsLabel.cxx AnnotationColorBar.cxx AnnotationColorBarNumericText.cxx AnnotationColorBarPositionModeEnum.cxx diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 4ea527599..727337620 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -29,7 +29,6 @@ #include "Annotation.h" #include "AnnotationArrangerExecutor.h" -#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index e4e38f73d..2c11d4792 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -29,7 +29,6 @@ #undef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationBox.h" -#include "AnnotationGraphicsLabel.h" #include "AnnotationColorBar.h" #include "AnnotationColorBarSection.h" #include "AnnotationColorBarNumericText.h" @@ -1138,10 +1137,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota dynamic_cast(annotation), surfaceDisplayed); break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - drawChartGraphicsLabel(annotationFile, - dynamic_cast(annotation)); - break;; case AnnotationTypeEnum::COLOR_BAR: drawColorBar(annotationFile, dynamic_cast(annotation)); @@ -1313,27 +1308,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil return drawnFlag; } -/** - * Draw an annotation chart two axis label - * - * @param annotationFile - * File containing the annotation. - * @param chartGraphicsLabel - * Axis label to draw. - */ -void -BrainOpenGLAnnotationDrawingFixedPipeline::drawChartGraphicsLabel(AnnotationFile* annotationFile, - AnnotationGraphicsLabel* chartGraphicsLabel) -{ - CaretAssert(chartGraphicsLabel); - CaretAssert(chartGraphicsLabel->getType() == AnnotationTypeEnum::GRAPHICS_LABEL); - - drawText(annotationFile, - chartGraphicsLabel, - NULL); -} - - /** * Draw an annotation box. * @@ -2244,8 +2218,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi const Surface* surfaceDisplayed) { CaretAssert(text); - CaretAssert((text->getType() == AnnotationTypeEnum::TEXT) - || (text->getType() == AnnotationTypeEnum::GRAPHICS_LABEL)); + CaretAssert(text->getType() == AnnotationTypeEnum::TEXT); DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); if (text->getType() == AnnotationTypeEnum::TEXT) { diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 0f68617a1..5552d2f89 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -35,7 +35,6 @@ namespace caret { class Annotation; class AnnotationBox; - class AnnotationGraphicsLabel; class AnnotationColorBar; class AnnotationCoordinate; class AnnotationFile; @@ -221,9 +220,6 @@ namespace caret { AnnotationBox* box, const Surface* surfaceDisplayed); - void drawChartGraphicsLabel(AnnotationFile* annotationFile, - AnnotationGraphicsLabel* chartGraphicsLabel); - bool drawImage(AnnotationFile* annotationFile, AnnotationImage* image, const Surface* surfaceDisplayed); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 1ad40a182..d66c677d9 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -25,7 +25,6 @@ #include -#include "AnnotationGraphicsLabel.h" #include "AnnotationCoordinate.h" #include "AnnotationColorBar.h" #include "AnnotationPercentSizeText.h" diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index c81fe403a..a5c3cd0ef 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -23,9 +23,9 @@ #include "ChartTwoOverlaySet.h" #undef __CHART_TWO_OVERLAY_SET_DECLARE__ +#include "AnnotationPercentSizeText.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" -#include "AnnotationGraphicsLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventAnnotationChartLabelGet.h" diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 3d3e2e2c5..1d879f01f 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -23,7 +23,7 @@ #include "ChartTwoCartesianAxis.h" #undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ -#include "AnnotationGraphicsLabel.h" +#include "AnnotationPercentSizeText.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index 04d8ed89a..946147e02 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -255,9 +255,6 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) case AnnotationTypeEnum::BOX: writeBox(dynamic_cast(annotation)); break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - CaretAssertMessage(0, "Axis label is NEVER written to an annotation file"); - break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); break; diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 9f75e6300..4881f1411 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -226,9 +226,7 @@ AnnotationColorWidget::updateContent(std::vector& annotations) { m_annotations.clear(); for (auto a : annotations) { - if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { - m_annotations.push_back(a); - } + m_annotations.push_back(a); } if ( ! m_annotations.empty()) { @@ -493,8 +491,6 @@ AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, case AnnotationTypeEnum::BOX: allowBothColorsNoneFlag = false; break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index 4fdaa19b8..f3ee2d4b8 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -93,9 +93,6 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - enableWindowSpaceFlag = false; - break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index a03068899..95c486ad7 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -190,9 +190,6 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, switch (annotationType) { case AnnotationTypeEnum::BOX: break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - CaretAssertMessage(0, "Axis Labels do not get created !!!"); - break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Colorbars do not get created !!!"); break; @@ -871,9 +868,6 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() case AnnotationTypeEnum::BOX: useAverageFlag = true; break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - useAverageFlag = true; - break; case AnnotationTypeEnum::COLOR_BAR: useAverageFlag = true; break; diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index 12e04b17f..250854a2b 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -411,9 +411,6 @@ AnnotationInsertNewWidget::createShapePixmap(const QWidget* widget, case AnnotationTypeEnum::BOX: painter->drawRect(1, 1, width - 2, height - 2); break; - case AnnotationTypeEnum::GRAPHICS_LABEL: - CaretAssertMessage(0, "No pixmap for axis label as user does not create them like other annotations"); - break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); break; diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.cxx b/src/GuiQt/AnnotationTextAlignmentWidget.cxx index 37d03a563..f9fd727a3 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.cxx +++ b/src/GuiQt/AnnotationTextAlignmentWidget.cxx @@ -159,16 +159,10 @@ AnnotationTextAlignmentWidget::~AnnotationTextAlignmentWidget() void AnnotationTextAlignmentWidget::updateContent(std::vector& annotationTexts) { -// m_annotations.clear(); -// m_annotations.insert(m_annotations.end(), -// annotationTexts.begin(), -// annotationTexts.end()); m_annotations.clear(); - for (auto a : annotationTexts) { - if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { - m_annotations.push_back(a); - } - } + m_annotations.insert(m_annotations.end(), + annotationTexts.begin(), + annotationTexts.end()); { /* diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index 0da7b5ea9..92601646e 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -94,21 +94,15 @@ AnnotationTextOrientationWidget::~AnnotationTextOrientationWidget() /** * Update with the given annotation. * - * @param annotation. + * @param annotationTextsIn. */ void AnnotationTextOrientationWidget::updateContent(std::vector& annotationTextsIn) { -// m_annotations.clear(); -// m_annotations.insert(m_annotations.end(), -// annotationTexts.begin(), -// annotationTexts.end()); m_annotations.clear(); - for (auto a : annotationTextsIn) { - if (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL) { - m_annotations.push_back(a); - } - } + m_annotations.insert(m_annotations.end(), + annotationTextsIn.begin(), + annotationTextsIn.end()); { /* diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index 78a6e624c..98aff29d6 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -119,11 +119,9 @@ AnnotationWidthHeightWidget::~AnnotationWidthHeightWidget() void AnnotationWidthHeightWidget::updateContent(std::vector& annotations2D) { -// m_annotations2D = annotations2D; m_annotations2D.clear(); for (auto a : annotations2D) { - if ((a->getType() != AnnotationTypeEnum::COLOR_BAR) - && (a->getType() != AnnotationTypeEnum::GRAPHICS_LABEL)) { + if (a->getType() != AnnotationTypeEnum::COLOR_BAR) { m_annotations2D.push_back(a); } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index ca3566717..537891d67 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -32,12 +32,12 @@ #include "BrainBrowserWindowToolBarChartTwoAxes.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ +#include "AnnotationPercentSizeText.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "CaretMappableDataFile.h" -#include "AnnotationGraphicsLabel.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" -- GitLab From 7bf7aacb94e8cdd6fd5b25b80ee5c7a47b281401 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Jun 2017 10:36:02 -0500 Subject: [PATCH 294/755] When a scene is displayed that contains charting version one line-series type charts, attempt to convert these charts to charting version two. --- src/Brain/ModelChartTwo.cxx | 208 ++++++++++++++++++++++++++++++- src/Brain/ModelChartTwo.h | 2 + src/Charting/ChartDataSource.cxx | 131 +++++++++++++++++++ src/Charting/ChartDataSource.h | 4 + 4 files changed, 344 insertions(+), 1 deletion(-) diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index f8088db63..773da0998 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -20,6 +20,7 @@ #include #include +#include #include "AnnotationColorBar.h" #include "Brain.h" @@ -30,11 +31,20 @@ #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFileAndMapSelectionModel.h" +#include "ChartData.h" +#include "ChartDataCartesian.h" +#include "ChartDataSource.h" #include "ChartableTwoFileDelegate.h" #include "ChartableMatrixParcelInterface.h" #include "ChartableMatrixSeriesInterface.h" #include "ChartMatrixDisplayProperties.h" +#include "ChartModelDataSeries.h" +#include "ChartModelFrequencySeries.h" +#include "ChartModelTimeSeries.h" +#include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartTwoLineSeriesHistory.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" @@ -47,8 +57,10 @@ #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventCaretMappableDataFilesGet.h" +#include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" +#include "MapFileDataSelector.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "OverlaySet.h" @@ -521,6 +533,8 @@ ModelChartTwo::restoreSceneFromChartOneModel(ModelChart* modelChartOne) EventManager::get()->sendEvent(allTabsEvent.getPointer()); std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); + bool haveLineSeriesModelsFlag = true; + for (auto tabIndex : validTabIndices) { switch (modelChartOne->getSelectedChartOneDataType(tabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: @@ -528,7 +542,9 @@ ModelChartTwo::restoreSceneFromChartOneModel(ModelChart* modelChartOne) case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: - setSelectedChartTwoDataType(tabIndex, ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); + setSelectedChartTwoDataType(tabIndex, + ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); + haveLineSeriesModelsFlag = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: setSelectedChartTwoDataType(tabIndex, @@ -544,6 +560,196 @@ ModelChartTwo::restoreSceneFromChartOneModel(ModelChart* modelChartOne) break; } } + + if (haveLineSeriesModelsFlag) { + restoreLineSeriesChartFromChartOneModel(modelChartOne); + } +} + +/** + * Attempt to restore line series data from a chart version one scene. + * + * @param modelChartOne + * The chart one model. + */ +void +ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne) +{ + CaretAssert(modelChartOne); + + std::set dataSources; + + int32_t maxDisplayCount = 0; + + std::vector validTabIndices; + std::map dataFileNamesAndColors; + + /* + * Loop through all tabs to find those containing line-series style charts + */ + for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { + ChartModelCartesian* cartesianModel = NULL; + switch (modelChartOne->getSelectedChartOneDataType(iTab)) { + case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: + cartesianModel = modelChartOne->getSelectedDataSeriesChartModel(iTab); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: + cartesianModel = modelChartOne->getSelectedFrequencySeriesChartModel(iTab); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: + cartesianModel = modelChartOne->getSelectedTimeSeriesChartModel(iTab); + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: + break; + case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: + break; + } + + if (cartesianModel != NULL) { + validTabIndices.push_back(iTab); + + maxDisplayCount = std::max(maxDisplayCount, + cartesianModel->getMaximumNumberOfChartDatasToDisplay()); + + /* + * Examine all lines in the tab + */ + const int32_t numChartLines = cartesianModel->getNumberOfChartData(); + for (int32_t i = (numChartLines - 1); i >= 0; i--) { + const ChartData* chartData = cartesianModel->getChartDataAtIndex(i); + if (chartData != NULL) { + const ChartDataSource* chartDataSource = chartData->getChartDataSource(); + if (chartData->isSelected(iTab)) { + ChartDataSource dataSourceCopy(*chartDataSource); + dataSources.insert(dataSourceCopy); + const ChartDataCartesian* cartesianData = dynamic_cast(chartData); + CaretColorEnum::Enum color = CaretColorEnum::RED; + if (cartesianData != NULL) { + color = cartesianData->getColor(); + } + dataFileNamesAndColors.insert(std::make_pair(chartDataSource->getChartableFileName(), + color)); + } + } + } + } + } + + std::vector allDataFiles; + EventCaretMappableDataFilesGet eventGetMapDataFiles; + EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); + eventGetMapDataFiles.getAllFiles(allDataFiles); + + //std::set chartTypeSet; + + /* + * Find the data files and setup for loading of + * lines series data. + */ + for (const auto filenameAndColor : dataFileNamesAndColors) { + const AString filename = filenameAndColor.first; + CaretColorEnum::Enum color = filenameAndColor.second; + CaretMappableDataFile* mapFileFullPath = NULL; + CaretMappableDataFile* mapFileNoPath = NULL; + for (auto mapFile : allDataFiles) { + if (filename == mapFile->getFileName()) { + mapFileFullPath = mapFile; + } + if (mapFile->getFileName().endsWith(filename)) { + mapFileNoPath = mapFile; + } + } + + ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; + if (mapFileFullPath != NULL) { + lineSeriesHistory = mapFileFullPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); + } + else if (mapFileNoPath != NULL) { + lineSeriesHistory = mapFileNoPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); + } + else { + CaretLogWarning("Unable to find data file with name: " + + filename); + } + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setLoadingEnabled(true); + if (maxDisplayCount <= 0) { + maxDisplayCount = 1; + } + lineSeriesHistory->setDisplayCount(maxDisplayCount); + lineSeriesHistory->setDefaultColor(color); + } + } + + std::cout << "Restoring " << dataSources.size() << " chart lines" << std::endl; + + /* + * Send events to load line charts for the brainordinates + * found in the older charts + */ + for (const auto& ds : dataSources) { + MapFileDataSelector mapFileDataSelector; + switch (ds.getDataSourceMode()) { + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: + { + int32_t surfaceNumberOfVertices = -1; + int32_t vertexIndex = -1; + AString structureName; + ds.getSurfaceNode(structureName, surfaceNumberOfVertices, vertexIndex); + bool validFlag = false; + const StructureEnum::Enum structure = StructureEnum::fromName(structureName, + &validFlag); + if (validFlag) { + mapFileDataSelector.setSurfaceVertex(structure, + surfaceNumberOfVertices, + vertexIndex); + } + else { + CaretLogWarning("Unrecogized structure name :" + + structureName); + } + } + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: + { + int32_t surfaceNumberOfVertices = -1; + AString structureName; + std::vector vertices; + ds.getSurfaceNodeAverage(structureName, surfaceNumberOfVertices, vertices); + bool validFlag = false; + const StructureEnum::Enum structure = StructureEnum::fromName(structureName, + &validFlag); + if (validFlag) { + mapFileDataSelector.setSurfaceVertexAverage(structure, + surfaceNumberOfVertices, + vertices); + } + else { + CaretLogWarning("Unrecogized structure name :" + + structureName); + } + } + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: + { + float xyz[3]; + ds.getVolumeVoxel(xyz); + mapFileDataSelector.setVolumeVoxelXYZ(xyz); + } + break; + } + + if (mapFileDataSelector.getDataSelectionType() != MapFileDataSelector::DataSelectionType::INVALID) { + EventChartTwoLoadLineSeriesData loadLineDataEvent(validTabIndices, + mapFileDataSelector); + EventManager::get()->sendEvent(loadLineDataEvent.getPointer()); + } + } } /** diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index ecb349933..c1076eacd 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -123,6 +123,8 @@ namespace caret { void restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, const int32_t tabIndex); + void restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne); + virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); diff --git a/src/Charting/ChartDataSource.cxx b/src/Charting/ChartDataSource.cxx index a399e6a6f..c2f7014c8 100644 --- a/src/Charting/ChartDataSource.cxx +++ b/src/Charting/ChartDataSource.cxx @@ -120,6 +120,137 @@ ChartDataSource::operator=(const ChartDataSource& obj) return *this; } +/** + * Equality operator. + * + * @param rhs + * Other item for comparison. + */ +bool +ChartDataSource::operator==(const ChartDataSource& rhs) const +{ + if (this == &rhs) { + return true; + } + + if (m_chartableFileName != rhs.m_chartableFileName) { + return false; + } + + switch (m_dataSourceMode) { + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: + if (m_fileRowIndex == rhs.m_fileRowIndex) { + return true; + } + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: + if ((m_surfaceStructureName == rhs.m_surfaceStructureName) + && (m_surfaceNumberOfNodes == rhs.m_surfaceNumberOfNodes) + && (m_nodeIndex == rhs.m_nodeIndex)) { + return true; + } + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: + if ((m_surfaceStructureName == rhs.m_surfaceStructureName) + && (m_surfaceNumberOfNodes == rhs.m_surfaceNumberOfNodes) + && (m_nodeIndicesAverage == rhs.m_nodeIndicesAverage)) { + return true; + } + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: + if ((m_voxelXYZ[0] == rhs.m_voxelXYZ[0]) + && (m_voxelXYZ[1] == rhs.m_voxelXYZ[1]) + && (m_voxelXYZ[2] == rhs.m_voxelXYZ[2])) { + return true; + } + break; + } + + return false; +} + +/** + * Equality operator. + * + * @param rhs + * Other item for comparison. + */ +bool +ChartDataSource::operator<(const ChartDataSource& rhs) const +{ + if (this == &rhs) { + return false; + } + + if (m_chartableFileName != rhs.m_chartableFileName) { + return false; + } + + switch (m_dataSourceMode) { + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: + return (m_fileRowIndex < rhs.m_fileRowIndex); + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: + if (m_surfaceStructureName < rhs.m_surfaceStructureName) { + return true; + } + if (m_surfaceNumberOfNodes < rhs.m_surfaceNumberOfNodes) { + return true; + } + if (m_nodeIndex < rhs.m_nodeIndex) { + return true; + } + break; + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: + if (m_surfaceStructureName < rhs.m_surfaceStructureName) { + return true; + } + if (m_surfaceNumberOfNodes < rhs.m_surfaceNumberOfNodes) { + return true; + } + if (m_nodeIndicesAverage.size() < rhs.m_nodeIndicesAverage.size()) { + return true; + } + else if (m_nodeIndicesAverage.size() > rhs.m_nodeIndicesAverage.size()) { + return false; + } + else if (m_nodeIndicesAverage.size() == rhs.m_nodeIndicesAverage.size()) { + std::vector copyMe = m_nodeIndicesAverage; + std::sort(copyMe.begin(), copyMe.end()); + std::vector copyRhs = rhs.m_nodeIndicesAverage; + std::sort(copyRhs.begin(), copyRhs.end()); + + const int32_t numItems = static_cast(copyMe.size()); + for (int32_t i = 0; i < numItems; i++) { + CaretAssertVectorIndex(copyMe, i); + CaretAssertVectorIndex(copyRhs, i); + if (copyMe[i] < copyRhs[i]) { + return true; + } + else if (copyMe[i] > copyRhs[i]) { + return false; + } + } + } + case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: + if (m_voxelXYZ[0] < rhs.m_voxelXYZ[0]) { + return true; + } + if (m_voxelXYZ[1] < rhs.m_voxelXYZ[1]) { + return true; + } + if (m_voxelXYZ[2] < rhs.m_voxelXYZ[2]) { + return true; + } + break; + } + + return false; +} + /** * Copy the given data source to me. * diff --git a/src/Charting/ChartDataSource.h b/src/Charting/ChartDataSource.h index 8370d2c62..dc8cdbc42 100644 --- a/src/Charting/ChartDataSource.h +++ b/src/Charting/ChartDataSource.h @@ -41,6 +41,10 @@ namespace caret { ChartDataSource& operator=(const ChartDataSource&); + bool operator==(const ChartDataSource&) const; + + bool operator<(const ChartDataSource&) const; + void copy(const ChartDataSource* copyFrom); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, -- GitLab From 284521efe5dfd923a6db27bd8fc0b84e066b37c2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Jun 2017 10:44:33 -0500 Subject: [PATCH 295/755] Enabled vertical axis location button in chart overlay toolbox for line-series charts. --- src/Brain/ChartTwoOverlay.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 4e730be0c..fbc762424 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -1023,6 +1023,7 @@ ChartTwoOverlay::isCartesianVerticalAxisLocationSupported() const return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; -- GitLab From 402f5aa3d27a63cbb6f1632df18749cd61aa0dc8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Jun 2017 16:54:24 -0500 Subject: [PATCH 296/755] Added loading of line charts from row in a CIFTI scalar data series file's matrix. --- src/Brain/ChartingDataManager.cxx | 26 +++ src/Brain/IdentificationTextGenerator.cxx | 95 ++++----- src/Brain/ModelChart.cxx | 117 ----------- src/Brain/ModelChartTwo.cxx | 123 +++++++++--- src/Brain/ModelChartTwo.h | 10 + src/Charting/MapFileDataSelector.cxx | 184 +++++++++++++++--- src/Charting/MapFileDataSelector.h | 33 ++++ src/Files/ChartableTwoFileLineSeriesChart.cxx | 44 ++++- src/Files/CiftiMappableDataFile.cxx | 71 +++++++ src/Files/MetricFile.cxx | 4 + src/Files/VolumeFile.cxx | 4 + src/GuiQt/GuiManager.cxx | 2 + 12 files changed, 480 insertions(+), 233 deletions(-) diff --git a/src/Brain/ChartingDataManager.cxx b/src/Brain/ChartingDataManager.cxx index 5deae2eb3..9ce6d2ee7 100644 --- a/src/Brain/ChartingDataManager.cxx +++ b/src/Brain/ChartingDataManager.cxx @@ -28,6 +28,7 @@ #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "ModelChart.h" +#include "ModelChartTwo.h" #include "SurfaceFile.h" using namespace caret; @@ -104,6 +105,13 @@ ChartingDataManager::loadAverageChartForSurfaceNodes(const SurfaceFile* surfaceF surfaceFile->getNumberOfNodes(), nodeIndices); } + + ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); + if (modelChartTwo != NULL) { + modelChartTwo->loadAverageChartDataForSurfaceNodes(surfaceFile->getStructure(), + surfaceFile->getNumberOfNodes(), + nodeIndices); + } } /** @@ -126,6 +134,13 @@ ChartingDataManager::loadChartForSurfaceNode(const SurfaceFile* surfaceFile, surfaceFile->getNumberOfNodes(), nodeIndex); } + + ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); + if (modelChartTwo != NULL) { + modelChartTwo->loadChartDataForSurfaceNode(surfaceFile->getStructure(), + surfaceFile->getNumberOfNodes(), + nodeIndex); + } } /** @@ -147,6 +162,12 @@ ChartingDataManager::loadChartForCiftiMappableFileRow(CiftiMappableDataFile* cif modelChart->loadChartDataForCiftiMappableFileRow(ciftiMapFile, rowIndex); } + + ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); + if (modelChartTwo != NULL) { + modelChartTwo->loadChartDataForCiftiMappableFileRow(ciftiMapFile, + rowIndex); + } } @@ -163,6 +184,11 @@ ChartingDataManager::loadChartForVoxelAtCoordinate(const float xyz[3]) const if (modelChart != NULL) { modelChart->loadChartDataForVoxelAtCoordinate(xyz); } + + ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); + if (modelChartTwo != NULL) { + modelChartTwo->loadChartDataForVoxelAtCoordinate(xyz); + } } /** diff --git a/src/Brain/IdentificationTextGenerator.cxx b/src/Brain/IdentificationTextGenerator.cxx index 4d7eef108..90925718d 100644 --- a/src/Brain/IdentificationTextGenerator.cxx +++ b/src/Brain/IdentificationTextGenerator.cxx @@ -403,14 +403,6 @@ IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStri getMapIndicesOfFileUsedInOverlays(ciftiFile, mapIndices); } -// /* -// * Limit dense scalar and data series to maps selected in the overlay. -// */ -// if ((ciftiFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR) -// || (ciftiFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES)) { -// getMapIndicesOfFileUsedInOverlays(ciftiFile, -// mapIndices); -// } AString textValue; int64_t voxelIJK[3]; @@ -475,26 +467,6 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr const BrainStructure* brainStructure = surface->getBrainStructure(); CaretAssert(brainStructure); -// std::vector allCiftiMappableDataFiles; -// brain->getAllCiftiMappableDataFiles(allCiftiMappableDataFiles); -// for (std::vector::iterator ciftiMapIter = allCiftiMappableDataFiles.begin(); -// ciftiMapIter != allCiftiMappableDataFiles.end(); -// ciftiMapIter++) { -// const CiftiMappableDataFile* cmdf = *ciftiMapIter; -// if (cmdf->isEmpty() == false) { -// const int numMaps = cmdf->getNumberOfMaps(); -// for (int32_t iMap = 0; iMap < numMaps; iMap++) { -// AString textValue; -// if (cmdf->getMapSurfaceNodeValue(iMap, surface->getStructure(), nodeNumber, surface->getNumberOfNodes(), textValue)) { -// AString boldText = (DataFileTypeEnum::toOverlayTypeName(cmdf->getDataFileType()) -// + " " -// + cmdf->getFileNameNoPath()); -// idText.addLine(true, boldText, textValue); -// } -// } -// } -// } - std::vector allCiftiMappableDataFiles; brain->getAllCiftiMappableDataFiles(allCiftiMappableDataFiles); for (std::vector::iterator ciftiMapIter = allCiftiMappableDataFiles.begin(); @@ -593,37 +565,6 @@ IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStr boldText, textValue); } - -// const CiftiMappableConnectivityMatrixDataFile* connCifti = dynamic_cast(cmdf); -// if (cmdf->isEmpty() == false) { -// const int numMaps = cmdf->getNumberOfMaps(); -// if (numMaps > 0) { -// if (connCifti != NULL) { -// AString textValue; -// const int32_t mapIndex = 0; -// if (cmdf->getMapSurfaceNodeValue(mapIndex, surface->getStructure(), nodeNumber, surface->getNumberOfNodes(), textValue)) { -// AString boldText = (DataFileTypeEnum::toOverlayTypeName(cmdf->getDataFileType()) -// + " " -// + cmdf->getFileNameNoPath()); -// idText.addLine(true, boldText, textValue); -// } -// } -// else { -// AString boldText = (DataFileTypeEnum::toOverlayTypeName(cmdf->getDataFileType()) -// + " " -// + cmdf->getFileNameNoPath()); -// std::vector nodeData; -// if (cmdf->getSeriesDataForSurfaceNode(surface->getStructure(), -// nodeNumber, -// nodeData)) { -// for (int32_t iMap = 0; iMap < numMaps; iMap++) { -// AString textValue = AString::number(nodeData[iMap]); -// idText.addLine(true, boldText, textValue); -// } -// } -// } -// } -// } } @@ -716,7 +657,6 @@ IdentificationTextGenerator::generateChartDataSeriesIdentificationText(Identific const SelectionItemChartDataSeries* idChartDataSeries) const { if (idChartDataSeries->isValid()) { - //const ChartModelDataSeries* chartModelDataSeries = idChartDataSeries->getChartModelDataSeries(); const ChartDataCartesian* chartDataCartesian = idChartDataSeries->getChartDataCartesian(); const ChartDataSource* chartDataSource = chartDataCartesian->getChartDataSource(); @@ -1088,6 +1028,40 @@ IdentificationTextGenerator::generateMapFileSelectorText(IdentificationStringBui switch (mapFileDataSelector->getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t columnIndex = -1; + mapFileDataSelector->getColumnIndex(mapFile, + mapFileName, + columnIndex); + + idText.addLine(true, + "Column File", + mapFileName); + idText.addLine(true, + "Column Index", + AString::number(columnIndex)); + } + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t rowIndex = -1; + mapFileDataSelector->getRowIndex(mapFile, + mapFileName, + rowIndex); + + idText.addLine(true, + "Row File", + mapFileName); + idText.addLine(true, + "Row Index", + AString::number(rowIndex)); + } + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: { StructureEnum::Enum structure = StructureEnum::INVALID; @@ -1153,7 +1127,6 @@ IdentificationTextGenerator::generateChartTimeSeriesIdentificationText(Identific const SelectionItemChartTimeSeries* idChartTimeSeries) const { if (idChartTimeSeries->isValid()) { - //const ChartModelDataSeries* chartModelDataSeries = idChartDataSeries->getChartModelDataSeries(); const ChartDataCartesian* chartDataCartesian = idChartTimeSeries->getChartDataCartesian(); const ChartDataSource* chartDataSource = chartDataCartesian->getChartDataSource(); diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index b13df312d..5489c35db 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -45,7 +45,6 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" -#include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "ModelChart.h" @@ -206,18 +205,6 @@ ModelChart::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum struct chartData); } } - - std::vector tabIndices; - EventBrowserTabIndicesGetAll tabIndicesEvent; - EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); - - MapFileDataSelector mapFileDataSelector; - mapFileDataSelector.setSurfaceVertexAverage(structure, - surfaceNumberOfNodes, - nodeIndices); - EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), - mapFileDataSelector); - EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** @@ -251,16 +238,6 @@ ModelChart::loadChartDataForVoxelAtCoordinate(const float xyz[3]) chartData); } } - - std::vector tabIndices; - EventBrowserTabIndicesGetAll tabIndicesEvent; - EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); - - MapFileDataSelector mapFileDataSelector; - mapFileDataSelector.setVolumeVoxelXYZ(xyz); - EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), - mapFileDataSelector); - EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** @@ -353,22 +330,6 @@ ModelChart::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMap } } } - -// if (ciftiMapFile != NULL) { -// ChartableLineSeriesRowColumnInterface* chartableLineFile = dynamic_cast(ciftiMapFile); -// if (chartableLineFile != NULL) { -// ChartData* chartData = chartableLineFile->loadLineSeriesChartDataForRow(rowIndex); -// if (chartData != NULL) { -// } -// } -// else { -// CaretLogSevere("Loading row charts from file type " -// + DataFileTypeEnum::toGuiName(ciftiMapFile->getDataFileType()) -// + " name " -// + ciftiMapFile->getFileName() -// + " is not supported."); -// } -// } } /** @@ -454,36 +415,6 @@ ModelChart::addChartToChartModels(const std::vector& tabIndices, void ModelChart::getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const { -// chartFileEnabledTabsOut.clear(); -// -// EventBrowserTabGetAll allTabsEvent; -// EventManager::get()->sendEvent(allTabsEvent.getPointer()); -// std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); -// -// std::vector chartFiles; -// m_brain->getAllChartableBrainordinateDataFilesWithChartingEnabled(chartFiles); -// -// for (std::vector::iterator iter = chartFiles.begin(); -// iter != chartFiles.end(); -// iter++) { -// ChartableLineSeriesBrainordinateInterface* cf = *iter; -// std::vector chartFileTabIndices; -// -// for (std::vector::iterator tabIter = validTabIndices.begin(); -// tabIter != validTabIndices.end(); -// tabIter++) { -// const int32_t tabIndex = *tabIter; -// if (cf->isLineSeriesChartingEnabled(tabIndex)) { -// chartFileTabIndices.push_back(tabIndex); -// } -// } -// -// if ( ! chartFileTabIndices.empty()) { -// chartFileEnabledTabsOut.insert(std::make_pair(cf, chartFileTabIndices)); -// } -// } - - chartBrainordinateFileEnabledTabsOut.clear(); std::map > chartFileEnabledTabs; @@ -607,18 +538,6 @@ ModelChart::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, chartData); } } - - std::vector tabIndices; - EventBrowserTabIndicesGetAll tabIndicesEvent; - EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); - - MapFileDataSelector mapFileDataSelector; - mapFileDataSelector.setSurfaceVertex(structure, - surfaceNumberOfNodes, - nodeIndex); - EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), - mapFileDataSelector); - EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** @@ -1571,42 +1490,6 @@ ModelChart::getValidChartOneDataTypes(std::vector& v } } } - - -// std::vector allBrainordinateChartableFiles; -// m_brain->getAllChartableBrainordinateDataFiles(allBrainordinateChartableFiles); -// -// for (std::vector::iterator fileIter = allBrainordinateChartableFiles.begin(); -// fileIter != allBrainordinateChartableFiles.end(); -// fileIter++) { -// ChartableLineSeriesBrainordinateInterface* chartFile = *fileIter; -// -// std::vector chartDataTypes; -// chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); -// -// for (std::vector::iterator typeIter = chartDataTypes.begin(); -// typeIter != chartDataTypes.end(); -// typeIter++) { -// const ChartOneDataTypeEnum::Enum cdt = *typeIter; -// switch (cdt) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// haveDataSeries = true; -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// haveFrequencySeries = true; -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// haveTimeSeries = true; -// break; -// } -// } -// } std::vector allMatrixChartableFiles; m_brain->getAllChartableMatrixDataFiles(allMatrixChartableFiles); diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 773da0998..a3b73ef85 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -56,6 +56,7 @@ #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" +#include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" @@ -160,6 +161,87 @@ ModelChartTwo::removeAllCharts() { } +/** + * Load chart data for a surface node. + * + * @param structure + * The surface structure + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param nodeIndex + * Index of node. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const int32_t nodeIndex) +{ + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setSurfaceVertex(structure, + surfaceNumberOfNodes, + nodeIndex); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); +} + +/** + * Load chart data for an average of surface nodes. + * + * @param structure + * The surface structure + * @param surfaceNumberOfNodes + * Number of nodes in surface. + * @param nodeIndices + * Indices of node. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const std::vector& nodeIndices) +{ + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setSurfaceVertexAverage(structure, + surfaceNumberOfNodes, + nodeIndices); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); +} + +/** + * Load chart data for voxel at the given coordinate. + * + * @param xyz + * Coordinate of voxel. + * @throws + * DataFileException if there is an error loading data. + */ +void +ModelChartTwo::loadChartDataForVoxelAtCoordinate(const float xyz[3]) +{ + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setVolumeVoxelXYZ(xyz); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); +} /** * Load chart data for CIFTI Map files yoked to the given yoking group. @@ -229,30 +311,19 @@ void ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex) { -// CaretAssert(ciftiMapFile); -// -// std::map > chartFileEnabledTabs; -// getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); -// fileTabIter != chartFileEnabledTabs.end(); -// fileTabIter++) { -// ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; -// if (ciftiMapFile == dynamic_cast(chartFile)) { -// const std::vector tabIndices = fileTabIter->second; -// -// CaretAssert(chartFile); -// ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(rowIndex); -// if (chartData != NULL) { -// ChartDataSource* dataSource = chartData->getChartDataSource(); -// dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), -// rowIndex); -// -// addChartToChartModels(tabIndices, -// chartData); -// } -// } -// } + CaretAssert(ciftiMapFile); + + std::vector tabIndices; + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + + MapFileDataSelector mapFileDataSelector; + mapFileDataSelector.setRowIndex(ciftiMapFile, + ciftiMapFile->getFileName(), + rowIndex); + EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), + mapFileDataSelector); + EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** * Receive an event. @@ -641,8 +712,6 @@ ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); - //std::set chartTypeSet; - /* * Find the data files and setup for loading of * lines series data. @@ -682,8 +751,6 @@ ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne } } - std::cout << "Restoring " << dataSources.size() << " chart lines" << std::endl; - /* * Send events to load line charts for the brainordinates * found in the older charts diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index c1076eacd..ac86bb992 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -62,6 +62,16 @@ namespace caret { virtual AString getNameForBrowserTab() const override; + void loadChartDataForSurfaceNode(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const int32_t nodeIndex); + + void loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, + const int32_t surfaceNumberOfNodes, + const std::vector& nodeIndices); + + void loadChartDataForVoxelAtCoordinate(const float xyz[3]); + void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); diff --git a/src/Charting/MapFileDataSelector.cxx b/src/Charting/MapFileDataSelector.cxx index cbb708b98..5f035c32f 100644 --- a/src/Charting/MapFileDataSelector.cxx +++ b/src/Charting/MapFileDataSelector.cxx @@ -54,6 +54,14 @@ MapFileDataSelector::MapFileDataSelector() m_sceneAssistant->add("m_surfaceVertexIndex", &m_surfaceVertexIndex); m_sceneAssistant->addArray("m_voxelXYZ", m_voxelXYZ, 3, 0.0f); + m_sceneAssistant->add("m_columnIndex", + &m_columnIndex); + m_sceneAssistant->add("m_columnMapFileName", + &m_columnMapFileName); + m_sceneAssistant->add("m_rowIndex", + &m_rowIndex); + m_sceneAssistant->add("m_rowMapFileName", + &m_rowMapFileName); } /** @@ -107,6 +115,12 @@ MapFileDataSelector::copyHelperMapFileDataSelector(const MapFileDataSelector& ob m_voxelXYZ[0] = obj.m_voxelXYZ[0]; m_voxelXYZ[1] = obj.m_voxelXYZ[1]; m_voxelXYZ[2] = obj.m_voxelXYZ[2]; + m_columnIndex = obj.m_columnIndex; + m_columnMapFile = obj.m_columnMapFile; + m_columnMapFileName = obj.m_columnMapFileName; + m_rowIndex = obj.m_rowIndex; + m_rowMapFile = obj.m_rowMapFile; + m_rowMapFileName = obj.m_rowMapFileName; } /** @@ -118,6 +132,41 @@ MapFileDataSelector::getDataSelectionType() const return m_dataSelectionType; } +/** + * @return Name of the data selection type. + * + * @param dataSelectionType + * The data selection type. + */ +AString +MapFileDataSelector::getDataSelectionTypeName(const DataSelectionType dataSelectionType) +{ + AString dataSelectionTypeName; + switch (dataSelectionType) { + case DataSelectionType::INVALID: + dataSelectionTypeName = "INVALID"; + break; + case DataSelectionType::COLUMN_DATA: + dataSelectionTypeName = "COLUMN_DATA"; + break; + case DataSelectionType::ROW_DATA: + dataSelectionTypeName = "ROW_DATA"; + break; + case DataSelectionType::SURFACE_VERTEX: + dataSelectionTypeName = "SURFACE_VERTEX"; + break; + case DataSelectionType::SURFACE_VERTICES_AVERAGE: + dataSelectionTypeName = "SURFACE_VERTICES_AVERAGE"; + break; + case DataSelectionType::VOLUME_XYZ: + dataSelectionTypeName = "VOLUME_XYZ"; + break; + } + CaretAssert( ! dataSelectionTypeName.isEmpty()); + + return dataSelectionTypeName; +} + /** * Get data for a surface vertex. * @@ -232,6 +281,90 @@ MapFileDataSelector::setVolumeVoxelXYZ(const float voxelXYZ[3]) m_voxelXYZ[2] = voxelXYZ[2]; } +/** + * Get the column index. + * + * @param columnMapFile + * Data file for column loading. Could be an invalid pointer or NULL !!! + * @param columnMapFileName + * Name of column map file. + * @param columnIndex + * The column index. + */ +void +MapFileDataSelector::getColumnIndex(CaretMappableDataFile* &columnMapFile, + AString& columnMapFileName, + int32_t &columnIndex) const +{ + columnMapFile = m_columnMapFile; + columnMapFileName = m_columnMapFileName; + columnIndex = m_columnIndex; +} + +/** + * Set the column index. + * + * @param columnMapFile + * Data file for column loading. + * @param columnMapFileName + * Name of column map file. + * @param columnIndex + * The column index. + */ +void +MapFileDataSelector::setColumnIndex(CaretMappableDataFile* columnMapFile, + const AString& columnMapFileName, + const int32_t columnIndex) +{ + reset(); + m_dataSelectionType = DataSelectionType::COLUMN_DATA; + m_columnMapFile = columnMapFile; + m_columnMapFileName = columnMapFileName; + m_columnIndex = columnIndex; +} + +/** + * Get the row index. + * + * @param rowMapFile + * Data file for row loading. Could be an invalid pointer or NULL !!! + * @param rowMapFileName + * Name of row map file. + * @param rowIndex + * The row index. + */ +void +MapFileDataSelector::getRowIndex(CaretMappableDataFile* &rowMapFile, + AString& rowMapFileName, + int32_t &rowIndex) const +{ + rowIndex = m_rowIndex; + rowMapFile = m_rowMapFile; + rowMapFileName = m_rowMapFileName; +} + +/** + * Set the row index. + * + * @param rowMapFile + * Data file for row loading. + * @param rowMapFileName + * Name of row map file. + * @param rowIndex + * The row index. + */ +void +MapFileDataSelector::setRowIndex(CaretMappableDataFile* rowMapFile, + const AString& rowMapFileName, + const int32_t rowIndex) +{ + reset(); + m_dataSelectionType = DataSelectionType::ROW_DATA; + m_rowMapFile = rowMapFile; + m_rowMapFileName = rowMapFileName; + m_rowIndex = rowIndex; +} + /** * Get a description of this object's content. * @return String describing this object's content. @@ -244,6 +377,14 @@ MapFileDataSelector::toString() const switch (m_dataSelectionType) { case DataSelectionType::INVALID: break; + case DataSelectionType::COLUMN_DATA: + s = ("Column " + + AString::number(m_columnIndex)); + break; + case DataSelectionType::ROW_DATA: + s = ("Row " + + AString::number(m_rowIndex)); + break; case DataSelectionType::SURFACE_VERTEX: s = ("Vertex " + StructureEnum::toGuiName(m_surfaceStructure) @@ -271,7 +412,7 @@ MapFileDataSelector::toString() const void MapFileDataSelector::reset() { - m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; + m_dataSelectionType = DataSelectionType::INVALID; m_surfaceStructure = StructureEnum::INVALID; m_surfaceNumberOfVertices = -1; m_surfaceVertexIndex = -1; @@ -279,6 +420,12 @@ MapFileDataSelector::reset() m_voxelXYZ[0] = 0.0f; m_voxelXYZ[1] = 0.0f; m_voxelXYZ[2] = 0.0f; + m_columnIndex = -1; + m_columnMapFile = NULL; + m_columnMapFileName = ""; + m_rowIndex = -1; + m_rowMapFile = NULL; + m_rowMapFileName = ""; } /** @@ -302,25 +449,8 @@ MapFileDataSelector::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - AString dataSelectionTypeName; - switch (m_dataSelectionType) { - case DataSelectionType::INVALID: - dataSelectionTypeName = "INVALID"; - break; - case DataSelectionType::SURFACE_VERTEX: - dataSelectionTypeName = "SURFACE_VERTEX"; - break; - case DataSelectionType::SURFACE_VERTICES_AVERAGE: - dataSelectionTypeName = "SURFACE_VERTICES_AVERAGE"; - break; - case DataSelectionType::VOLUME_XYZ: - dataSelectionTypeName = "VOLUME_XYZ"; - break; - } - CaretAssert( ! dataSelectionTypeName.isEmpty()); - sceneClass->addString("m_dataSelectionType", - dataSelectionTypeName); + getDataSelectionTypeName(m_dataSelectionType)); const int32_t numVertices = static_cast(m_surfaceVertexAverageIndices.size()); if (numVertices > 0) { @@ -355,22 +485,30 @@ MapFileDataSelector::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + reset(); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_dataSelectionType = DataSelectionType::INVALID; const AString dataSelectionTypeName = sceneClass->getStringValue("m_dataSelectionType", "INVALID"); - if (dataSelectionTypeName == "INVALID") { + if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::INVALID)) { m_dataSelectionType = DataSelectionType::INVALID; } - else if (dataSelectionTypeName == "SURFACE_VERTEX") { + else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::COLUMN_DATA)) { + m_dataSelectionType = DataSelectionType::COLUMN_DATA; + } + else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::ROW_DATA)) { + m_dataSelectionType = DataSelectionType::ROW_DATA; + } + else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::SURFACE_VERTEX)) { m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; } - else if (dataSelectionTypeName == "SURFACE_VERTICES_AVERAGE") { + else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::SURFACE_VERTICES_AVERAGE)) { m_dataSelectionType = DataSelectionType::SURFACE_VERTICES_AVERAGE; } - else if (dataSelectionTypeName == "VOLUME_XYZ") { + else if (dataSelectionTypeName ==getDataSelectionTypeName(DataSelectionType::VOLUME_XYZ)) { m_dataSelectionType = DataSelectionType::VOLUME_XYZ; } else { diff --git a/src/Charting/MapFileDataSelector.h b/src/Charting/MapFileDataSelector.h index 99c0867b7..c6ac3e95d 100644 --- a/src/Charting/MapFileDataSelector.h +++ b/src/Charting/MapFileDataSelector.h @@ -31,6 +31,7 @@ #include "StructureEnum.h" namespace caret { + class CaretMappableDataFile; class SceneClassAssistant; class MapFileDataSelector : public CaretObject, public SceneableInterface { @@ -38,6 +39,8 @@ namespace caret { public: enum class DataSelectionType { INVALID, + COLUMN_DATA, + ROW_DATA, SURFACE_VERTEX, SURFACE_VERTICES_AVERAGE, VOLUME_XYZ @@ -53,6 +56,8 @@ namespace caret { DataSelectionType getDataSelectionType() const; + static AString getDataSelectionTypeName(const DataSelectionType dataSelectionType); + std::vector getValidTabIndices() const; void getSurfaceVertex(StructureEnum::Enum& surfaceStructure, @@ -75,6 +80,22 @@ namespace caret { void setVolumeVoxelXYZ(const float xyz[3]); + void getColumnIndex(CaretMappableDataFile* &columnMapFile, + AString& columnMapFileName, + int32_t &columnIndex) const; + + void setColumnIndex(CaretMappableDataFile* columnMapFile, + const AString& columnMapFileName, + const int32_t columnIndex); + + void getRowIndex(CaretMappableDataFile* &rowMapFile, + AString& rowMapFileName, + int32_t &rowIndex) const; + + void setRowIndex(CaretMappableDataFile* rowMapFile, + const AString& rowMapFileName, + const int32_t rowIndex); + void reset(); // ADD_NEW_METHODS_HERE @@ -119,6 +140,18 @@ namespace caret { float m_voxelXYZ[3]; + int32_t m_columnIndex = -1; + + int32_t m_rowIndex = -1; + + CaretMappableDataFile* m_rowMapFile; + + CaretMappableDataFile* m_columnMapFile; + + AString m_rowMapFileName; + + AString m_columnMapFileName; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 49b1af43d..1c74b2ea0 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -207,14 +207,54 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabI switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + loadDataFlag = true; + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + loadDataFlag = true; + break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: loadDataFlag = true; break; } break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + switch (mapFileDataSelector.getDataSelectionType()) { + case MapFileDataSelector::DataSelectionType::INVALID: + break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t columnIndex = -1; + mapFileDataSelector.getColumnIndex(mapFile, mapFileName, columnIndex); + if (mapFile == getCaretMappableDataFile()) { + loadDataFlag = true; + } + } + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t rowIndex = -1; + mapFileDataSelector.getRowIndex(mapFile, mapFileName, rowIndex); + if (mapFile == getCaretMappableDataFile()) { + loadDataFlag = true; + } + } + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: + break; + case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: + break; + case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: + break; + } break; } @@ -246,10 +286,6 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabI CaretAssertVectorIndex(data, i); cartesianData->addPoint(x, data[i]); } -// for (float d : data) { -// cartesianData->addPoint(x, d); -// x += xStep; -// } m_lineChartHistory->addHistoryItem(cartesianData); } diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index e800812f6..80b2ac368 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -40,6 +40,7 @@ #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" #include "CiftiParcelSeriesFile.h" +#include "CiftiScalarDataSeriesFile.h" #include "CaretTemporaryFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" @@ -6862,6 +6863,76 @@ CiftiMappableDataFile::getDataForSelector(const MapFileDataSelector& mapFileData switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + { + const bool loadColumnDataFlag = false; + if (loadColumnDataFlag) { + const DataFileTypeEnum::Enum dataFileType = getDataFileType(); + if (dataFileType == DataFileTypeEnum::UNKNOWN) { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t columnIndex = -1; + mapFileDataSelector.getColumnIndex(mapFile, + mapFileName, + columnIndex); + bool loadDataFlag = false; + if (mapFile != NULL) { + if (mapFile == dynamic_cast(this)) { + loadDataFlag = true; + } + } + else if (mapFileName.endsWith(getFileNameNoPath())) { + loadDataFlag = true; + } + if (loadDataFlag) { + if ((columnIndex >= 0) + && (columnIndex < m_ciftiFile->getNumberOfColumns())) { + const int32_t numberOfElementsInColumn = m_ciftiFile->getNumberOfRows(); + if (numberOfElementsInColumn > 0) { + dataOut.resize(numberOfElementsInColumn); + m_ciftiFile->getColumn(&dataOut[0], + columnIndex); + } + } + } + } + } + } + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + { + const DataFileTypeEnum::Enum dataFileType = getDataFileType(); + if (dataFileType == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + CaretMappableDataFile* mapFile = NULL; + AString mapFileName; + int32_t rowIndex = -1; + mapFileDataSelector.getRowIndex(mapFile, + mapFileName, + rowIndex); + + bool loadDataFlag = false; + if (mapFile != NULL) { + if (mapFile == dynamic_cast(this)) { + loadDataFlag = true; + } + } + else if (mapFileName.endsWith(getFileNameNoPath())) { + loadDataFlag = true; + } + if (loadDataFlag) { + if ((rowIndex >= 0) + && (rowIndex < m_ciftiFile->getNumberOfRows())) { + const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); + if (numberOfElementsInRow > 0) { + dataOut.resize(numberOfElementsInRow); + m_ciftiFile->getRow(&dataOut[0], + rowIndex); + } + } + } + } + } + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: try { StructureEnum::Enum structure = StructureEnum::INVALID; diff --git a/src/Files/MetricFile.cxx b/src/Files/MetricFile.cxx index f5c93d16b..c7892b114 100644 --- a/src/Files/MetricFile.cxx +++ b/src/Files/MetricFile.cxx @@ -635,6 +635,10 @@ MetricFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: try { StructureEnum::Enum structure = StructureEnum::INVALID; diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index f0aa60af0..44cd890b9 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -2249,6 +2249,10 @@ VolumeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; + case MapFileDataSelector::DataSelectionType::COLUMN_DATA: + break; + case MapFileDataSelector::DataSelectionType::ROW_DATA: + break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 8ee0f7672..a6bf2c2ca 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -2951,6 +2951,8 @@ GuiManager::processIdentification(const int32_t tabIndex, } updateGraphicsFlag = true; foundChartOverlayFlag = true; + chartingDataManager->loadChartForCiftiMappableFileRow(matrixChart->getCiftiMappableDataFile(), + rowIndex); } } } -- GitLab From 48258e47713e32cdd96312e24c4cb98c25048b77 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Jun 2017 09:53:30 -0500 Subject: [PATCH 297/755] Added line width to line-series data chart lines. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 7 ++- src/Charting/ChartTwoDataCartesian.cxx | 25 +++++++++++ src/Charting/ChartTwoDataCartesian.h | 6 +++ src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- ...BrowserWindowToolBarChartTwoAttributes.cxx | 2 + src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 44 +++++++++++++++++++ src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 12 ++++- 7 files changed, 93 insertions(+), 5 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index d66c677d9..45773a167 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1117,10 +1117,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } else { /* - * Note: do anti-aliasing here since it will mess up drawing when identifying + * Note: Anti-aliasing is only enabled when drawing the line. + * Anti-aliasing cannot be enabled during identification since + * identification encodes information in the colors (anti-aliasing + * will alter the colors during drawing). */ m_fixedPipelineDrawing->enableLineAntiAliasing(); - glLineWidth(LINE_SERIES_LINE_WIDTH); + glLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 978494f79..d9d5fbf64 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -102,6 +102,7 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() m_selectionStatus = true; m_color = CaretColorEnum::RED; + m_lineWidth = 1.0; m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; @@ -140,6 +141,8 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() &m_dataAxisUnitsY); m_sceneAssistant->add("m_color", &m_color); + m_sceneAssistant->add("m_lineWidth", + &m_lineWidth); m_sceneAssistant->add("m_timeStartInSecondsAxisX", &m_timeStartInSecondsAxisX); m_sceneAssistant->add("m_timeStepInSecondsAxisX", @@ -248,6 +251,7 @@ ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesi m_graphicsPrimitive.reset(dynamic_cast(obj.m_graphicsPrimitive->clone())); m_color = obj.m_color; + m_lineWidth = obj.m_lineWidth; m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; } @@ -413,6 +417,27 @@ ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) } } +/** + * @return The line width. + */ +float +ChartTwoDataCartesian::getLineWidth() const +{ + return m_lineWidth; +} + +/** + * Set line width. + * + * @param lineWidth + * New value for line width. + */ +void +ChartTwoDataCartesian::setLineWidth(const float lineWidth) +{ + m_lineWidth = lineWidth; +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index 7c81b520b..9a1d16d04 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -71,6 +71,10 @@ namespace caret { void setColor(const CaretColorEnum::Enum color); + float getLineWidth() const; + + void setLineWidth(const float lineWidth); + float getTimeStartInSecondsAxisX() const; void setTimeStartInSecondsAxisX(const float timeStart); @@ -120,6 +124,8 @@ namespace caret { CaretColorEnum::Enum m_color; + float m_lineWidth; + float m_timeStartInSecondsAxisX; float m_timeStepInSecondsAxisX; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 09cbbe401..cf88caf82 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1476,7 +1476,7 @@ BrainBrowserWindowToolBar::updateToolBar() break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: showChartTwoAxesWidget = true; - showChartTwoAttributesWidget = true; + //showChartTwoAttributesWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: showChartTwoOrientationWidget = true; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 3a6e69b4d..4c59c12a3 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -105,6 +105,8 @@ BrainBrowserWindowToolBarChartTwoAttributes::updateContent(BrowserTabContent* br case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + m_stackedWidget->setCurrentWidget(m_cartesianChartAttributesWidget); + m_cartesianChartAttributesWidget->updateContent(); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: m_stackedWidget->setCurrentWidget(m_matrixChartTwoAttributesWidget); diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 620ec8774..24cc59e80 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -24,6 +24,7 @@ #undef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ #include +#include #include #include #include @@ -101,6 +102,10 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent QObject::connect(m_colorItemSignalMapper, SIGNAL(mapped(int)), this, SLOT(colorItemSelected(int))); + m_lineWidthItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_lineWidthItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(lineWidthItemSelected(int))); + m_tableWidget = new QTableWidget(); m_tableWidget->setSelectionBehavior(QTableWidget::SelectItems); m_tableWidget->setSelectionMode(QTableWidget::SingleSelection); @@ -325,6 +330,18 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi caretColorComboBox->getWidget()); m_colorComboBoxes.push_back(caretColorComboBox); } + else if (j == COLUMN_LINE_WIDTH) { + QDoubleSpinBox* lineWidthSpinBox = new QDoubleSpinBox(); + lineWidthSpinBox->setRange(1.0, 10.0); + lineWidthSpinBox->setSingleStep(1.0); + QObject::connect(lineWidthSpinBox, SIGNAL(valueChanged(double)), + m_lineWidthItemSignalMapper, SLOT(map())); + m_lineWidthItemSignalMapper->setMapping(lineWidthSpinBox, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_LINE_WIDTH, + lineWidthSpinBox); + m_lineWidthSpinBoxes.push_back(lineWidthSpinBox); + } else if (j == COLUMN_DESCRIPTION) { QTableWidgetItem* item = new QTableWidgetItem(""); item->setFlags(Qt::ItemIsEnabled @@ -351,6 +368,8 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi CaretAssertVectorIndex(m_colorComboBoxes, iRow); m_colorComboBoxes[iRow]->setSelectedColor(data->getColor()); + m_lineWidthSpinBoxes[iRow]->setValue(data->getLineWidth()); + QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); item->setText(mapFileDataSelector->toString()); } @@ -367,12 +386,15 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi new QTableWidgetItem("Remove")); m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, new QTableWidgetItem("Color")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_LINE_WIDTH, + new QTableWidgetItem("Line Width")); m_tableWidget->setHorizontalHeaderItem(COLUMN_DESCRIPTION, new QTableWidgetItem("Description")); m_tableWidget->resizeColumnToContents(COLUMN_VIEW); m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); m_tableWidget->resizeColumnToContents(COLUMN_COLOR); + m_tableWidget->resizeColumnToContents(COLUMN_LINE_WIDTH); m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, 350); @@ -450,6 +472,28 @@ ChartTwoLineSeriesHistoryDialog::colorItemSelected(int rowIndex) } } +/** + * line width item selected + * + * @param rowIndex + * Row index of item. + */ +void +ChartTwoLineSeriesHistoryDialog::lineWidthItemSelected(int rowIndex) +{ + CaretAssertVectorIndex(m_lineWidthSpinBoxes, rowIndex); + CaretAssert(m_lineWidthSpinBoxes[rowIndex]); + + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setLineWidth(m_lineWidthSpinBoxes[rowIndex]->value()); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + /** * Called when the "Remove All History" button is clicked. */ diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h index f706e8da1..2631fd21f 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h @@ -28,6 +28,7 @@ #include "CaretColorEnum.h" #include "WuQDialogNonModal.h" +class QDoubleSpinBox; class QLabel; class QIcon; class QSignalMapper; @@ -65,6 +66,8 @@ namespace caret { void colorItemSelected(int rowIndex); + void lineWidthItemSelected(int rowIndex); + void removeAllHistoryButtonClicked(); void defaultColorSelected(const CaretColorEnum::Enum color); @@ -97,8 +100,12 @@ namespace caret { QSignalMapper* m_colorItemSignalMapper; + QSignalMapper* m_lineWidthItemSignalMapper; + std::vector m_colorComboBoxes; + std::vector m_lineWidthSpinBoxes; + QLabel* m_filenameLabel; CaretColorEnumComboBox* m_defaultColorComboBox; @@ -108,8 +115,9 @@ namespace caret { static const int32_t COLUMN_VIEW = 0; static const int32_t COLUMN_REMOVE = 1; static const int32_t COLUMN_COLOR = 2; - static const int32_t COLUMN_DESCRIPTION = 3; - static const int32_t COLUMN_COUNT = 4; + static const int32_t COLUMN_LINE_WIDTH = 3; + static const int32_t COLUMN_DESCRIPTION = 4; + static const int32_t COLUMN_COUNT = 5; // ADD_NEW_MEMBERS_HERE -- GitLab From d5ecdb518e9265704d5507a7339977565ec6f05c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Jun 2017 15:08:19 -0500 Subject: [PATCH 298/755] Added yoking of chart matrix display properties and chart line axes. --- src/Brain/ChartTwoOverlaySet.cxx | 56 +++++++ src/Brain/ModelChartTwo.cxx | 41 +++++ src/Charting/CMakeLists.txt | 2 + .../EventChartTwoAttributesChanged.cxx | 141 +++++++++++++++++ src/Charting/EventChartTwoAttributesChanged.h | 93 +++++++++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 5 + src/Common/EventTypeEnum.h | 2 + ...BrowserWindowToolBarChartTwoAttributes.cxx | 145 +++++++++++------- ...inBrowserWindowToolBarChartTwoAttributes.h | 16 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 16 ++ 11 files changed, 455 insertions(+), 63 deletions(-) create mode 100644 src/Charting/EventChartTwoAttributesChanged.cxx create mode 100644 src/Charting/EventChartTwoAttributesChanged.h diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index a5c3cd0ef..ca0f9ae33 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -24,11 +24,14 @@ #undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "AnnotationPercentSizeText.h" +#include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "EventAnnotationChartLabelGet.h" +#include "EventBrowserTabGet.h" +#include "EventChartTwoAttributesChanged.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" @@ -149,6 +152,7 @@ m_tabIndex(tabIndex) m_overlays[i]->setWeakPointerToSelf(m_overlays[i]); } + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); @@ -518,6 +522,58 @@ ChartTwoOverlaySet::receiveEvent(Event* event) chartLabelEvent->addAnnotationChartLabel(m_chartAxisLeft->getAnnotationAxisLabel()); chartLabelEvent->addAnnotationChartLabel(m_chartAxisRight->getAnnotationAxisLabel()); } + else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { + EventChartTwoAttributesChanged* attributeEvent = dynamic_cast(event); + CaretAssert(attributeEvent); + + switch (attributeEvent->getMode()) { + case EventChartTwoAttributesChanged::Mode::INVALID: + break; + case EventChartTwoAttributesChanged::Mode::CARTESIAN_AXIS: + { + YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartTwoCartesianAxis* cartesianAxis = NULL; + attributeEvent->getCartesianAxisChanged(yokingGroup, + chartTwoDataType, + cartesianAxis); + + /* + * Only tabs in the windows are valid + */ + EventBrowserTabGet tabEvent(m_tabIndex); + EventManager::get()->sendEvent(tabEvent.getPointer()); + const BrowserTabContent* btc = tabEvent.getBrowserTab(); + if (btc != NULL) { + const YokingGroupEnum::Enum tabYoking = btc->getYokingGroup(); + + if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) + && (yokingGroup == tabYoking) + && (m_chartDataType == chartTwoDataType)) { + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + *m_chartAxisBottom = *cartesianAxis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + *m_chartAxisLeft = *cartesianAxis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + *m_chartAxisRight = *cartesianAxis; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + } + } + } + break; + case EventChartTwoAttributesChanged::Mode::MATRIX_PROPERTIES: + break; + } + + attributeEvent->setEventProcessed(); + } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { /* * The events intended for overlays are received here so that diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index a3b73ef85..19eb7316a 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -58,6 +58,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" +#include "EventChartTwoAttributesChanged.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" @@ -114,6 +115,8 @@ ModelChartTwo::ModelChartTwo(Brain* brain) "ChartTwoOverlaySetArray", m_lineSeriesChartOverlaySetArray.get()); + EventManager::get()->addEventListener(this, + EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } @@ -406,6 +409,44 @@ ModelChartTwo::receiveEvent(Event* event) nodeChartID->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { + EventChartTwoAttributesChanged* attributeEvent = dynamic_cast(event); + CaretAssert(attributeEvent); + + switch (attributeEvent->getMode()) { + case EventChartTwoAttributesChanged::Mode::INVALID: + break; + case EventChartTwoAttributesChanged::Mode::CARTESIAN_AXIS: + break; + case EventChartTwoAttributesChanged::Mode::MATRIX_PROPERTIES: + { + YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + ChartTwoMatrixDisplayProperties *matrixDisplayProperties = NULL; + attributeEvent->getMatrixPropertiesChanged(yokingGroup, + matrixDisplayProperties); + + + if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) + && (matrixDisplayProperties != NULL)) { + + EventBrowserTabGetAll allTabsEvent; + EventManager::get()->sendEvent(allTabsEvent.getPointer()); + std::vector allTabContent = allTabsEvent.getAllBrowserTabs(); + + for (auto btc : allTabContent) { + CaretAssert(btc); + if (btc->getYokingGroup() == yokingGroup) { + const int32_t tabIndex = btc->getTabNumber(); + *m_chartTwoMatrixDisplayProperties[tabIndex] = *matrixDisplayProperties; + } + } + } + } + break; + } + + attributeEvent->setEventProcessed(); + } } /** diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index ab7ac0dde..902c0f75d 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -51,6 +51,7 @@ ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h ChartTwoNumericSubdivisionsModeEnum.h ChartTwoLineSeriesHistory.h +EventChartTwoAttributesChanged.h EventChartTwoLoadLineSeriesData.h MapFileDataSelector.h @@ -90,6 +91,7 @@ ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx ChartTwoNumericSubdivisionsModeEnum.cxx ChartTwoLineSeriesHistory.cxx +EventChartTwoAttributesChanged.cxx EventChartTwoLoadLineSeriesData.cxx MapFileDataSelector.cxx ) diff --git a/src/Charting/EventChartTwoAttributesChanged.cxx b/src/Charting/EventChartTwoAttributesChanged.cxx new file mode 100644 index 000000000..462b042f8 --- /dev/null +++ b/src/Charting/EventChartTwoAttributesChanged.cxx @@ -0,0 +1,141 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ +#include "EventChartTwoAttributesChanged.h" +#undef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventChartTwoAttributesChanged + * \brief Event for change in chart two attributes + * \ingroup Charting + */ + +/** + * Constructor. + */ +EventChartTwoAttributesChanged::EventChartTwoAttributesChanged() +: Event(EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) +{ + +} + +/** + * Destructor. + */ +EventChartTwoAttributesChanged::~EventChartTwoAttributesChanged() +{ +} + +/** + * @return The mode. + */ +EventChartTwoAttributesChanged::Mode +EventChartTwoAttributesChanged::getMode() const +{ + return m_mode; +} + +/** + * Set for a change in a cartesian axis. + * + * @param yokingGroup + * Selected yoking group. + * @param chartTwoDataType + * Type of chart. + * @param cartesianAxis + * Cartesian axis that is changed. + */ +void +EventChartTwoAttributesChanged::setCartesianAxisChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const ChartTwoCartesianAxis* cartesianAxis) +{ + m_mode = Mode::CARTESIAN_AXIS; + m_yokingGroup = yokingGroup; + m_chartTwoDataType = chartTwoDataType; + m_cartesianAxis = const_cast(cartesianAxis); +} + +/** + * Get for a change in a cartesian axis. + * + * @param yokingGroupOut + * Selected yoking group. + * @param chartTwoDataTypeOut + * Type of chart. + * @param cartesianAxisOut + * Cartesian axis that is changed. + */ +void +EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + ChartTwoCartesianAxis* &cartesianAxisOut) +{ + CaretAssert(m_mode == Mode::CARTESIAN_AXIS); + yokingGroupOut = m_yokingGroup; + chartTwoDataTypeOut = m_chartTwoDataType; + cartesianAxisOut = m_cartesianAxis; +} + + +/** + * Set for a change in matrix properties. + * + * @param yokingGroup + * Selected yoking group. + * @param matrixDisplayProperties + * The matrix properties. + */ +void +EventChartTwoAttributesChanged::setMatrixPropertiesChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoMatrixDisplayProperties* matrixDisplayProperties) +{ + m_mode = Mode::MATRIX_PROPERTIES; + m_yokingGroup = yokingGroup; + m_matrixDisplayProperties = const_cast(matrixDisplayProperties); +} + +/** + * Get for a change in matrix properties. + * + * @param yokingGroupOut + * Selected yoking group. + * @param matrixDisplayPropertiesOut + * The matrix properties. + */ +void +EventChartTwoAttributesChanged::getMatrixPropertiesChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoMatrixDisplayProperties* &matrixDisplayPropertiesOut) +{ + CaretAssert(m_mode == Mode::MATRIX_PROPERTIES); + yokingGroupOut = m_yokingGroup; + matrixDisplayPropertiesOut = m_matrixDisplayProperties; +} + + diff --git a/src/Charting/EventChartTwoAttributesChanged.h b/src/Charting/EventChartTwoAttributesChanged.h new file mode 100644 index 000000000..929f3a5df --- /dev/null +++ b/src/Charting/EventChartTwoAttributesChanged.h @@ -0,0 +1,93 @@ +#ifndef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ +#define __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "ChartTwoDataTypeEnum.h" +#include "Event.h" +#include "YokingGroupEnum.h" + + +namespace caret { + + class ChartTwoCartesianAxis; + class ChartTwoMatrixDisplayProperties; + class EventChartTwoAttributesChanged : public Event { + + public: + enum class Mode { + INVALID, + CARTESIAN_AXIS, + MATRIX_PROPERTIES + }; + + EventChartTwoAttributesChanged(); + + Mode getMode() const; + + void setCartesianAxisChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const ChartTwoCartesianAxis* cartesianAxis); + + void getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + ChartTwoCartesianAxis* &cartesianAxisOut); + + void setMatrixPropertiesChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoMatrixDisplayProperties* matrixDisplayProperties); + + void getMatrixPropertiesChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoMatrixDisplayProperties* &matrixDisplayPropertiesOut); + + virtual ~EventChartTwoAttributesChanged(); + + + // ADD_NEW_METHODS_HERE + + private: + EventChartTwoAttributesChanged(const EventChartTwoAttributesChanged&); + + EventChartTwoAttributesChanged& operator=(const EventChartTwoAttributesChanged&); + + Mode m_mode = Mode::INVALID; + + YokingGroupEnum::Enum m_yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + + ChartTwoDataTypeEnum::Enum m_chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + + ChartTwoCartesianAxis* m_cartesianAxis = NULL; + + ChartTwoMatrixDisplayProperties* m_matrixDisplayProperties = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ + // +#endif // __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ + +} // namespace +#endif //__EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 9ff571d7a..741e3614a 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -492,6 +492,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: + case EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED: case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: case EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG: case EventTypeEnum::EVENT_DATA_FILE_ADD: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index ec7057b12..eaffa390d 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -181,10 +181,15 @@ EventTypeEnum::initialize() enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, "EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME", "Delete an OpenGL Texture Name for an OpenGL Context")); + enumData.push_back(EventTypeEnum(EVENT_CHART_OVERLAY_VALIDATE, "EVENT_CHART_OVERLAY_VALIDATE", "Validate a chart overlay for validity (it exists)")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_ATTRIBUTES_CHANGED, + "EVENT_CHART_TWO_ATTRIBUTES_CHANGED", + "GUI notification of the change in chart two atttributes")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", "Load line series data for chart two implementation")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 763c6d9a3..8ac2e575e 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -92,6 +92,8 @@ public: EVENT_CHART_MATRIX_YOKING_VALIDATION, /** Validate that chart overlay is valid (it exists). */ EVENT_CHART_OVERLAY_VALIDATE, + /** GUI notification of the change in chart two atttributes */ + EVENT_CHART_TWO_ATTRIBUTES_CHANGED, /** Load chart two line series data */ EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, /** Show the chart two line series history dialog */ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 4c59c12a3..69d8509f9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -39,8 +39,10 @@ #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartTwoMatrixDisplayProperties.h" +#include "EventChartTwoAttributesChanged.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" +#include "EventUserInterfaceUpdate.h" #include "ModelChartTwo.h" #include "WuQFactory.h" #include "WuQWidgetObjectGroup.h" @@ -351,7 +353,7 @@ EventListenerInterface() 1.0, 1, this, - SLOT(cellWidthPercentageSpinBoxValueChanged(double))); + SLOT(valueChanged())); m_cellWidthPercentageSpinBox->setKeyboardTracking(true); m_cellWidthPercentageSpinBox->setSuffix("%"); @@ -361,7 +363,7 @@ EventListenerInterface() 1.0, 1, this, - SLOT(cellHeightPercentageSpinBoxValueChanged(double))); + SLOT(valueChanged())); m_cellHeightPercentageSpinBox->setKeyboardTracking(true); m_cellHeightPercentageSpinBox->setSuffix("%"); @@ -370,11 +372,11 @@ EventListenerInterface() m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), - this, SLOT(highlightSelectionCheckBoxClicked(bool))); + this, SLOT(valueChanged())); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), - this, SLOT(displayGridLinesCheckBoxClicked(bool))); + this, SLOT(valueChanged())); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthPercentageSpinBox); @@ -448,67 +450,98 @@ MatrixChartTwoAttributesWidget::updateContent() } /** - * Called when the cell width spin box value is changed. - * - * @param value - * New value for cell width. + * Gets called when user changes value of a user-interface component. */ void -MatrixChartTwoAttributesWidget::cellWidthPercentageSpinBoxValueChanged(double value) +MatrixChartTwoAttributesWidget::valueChanged() { ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { - matrixDisplayProperties->setCellPercentageZoomWidth(value); - m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); - } -} + matrixDisplayProperties->setCellPercentageZoomWidth(m_cellWidthPercentageSpinBox->value()); + matrixDisplayProperties->setCellPercentageZoomHeight(m_cellHeightPercentageSpinBox->value()); + matrixDisplayProperties->setSelectedRowColumnHighlighted(m_highlightSelectionCheckBox->isChecked()); + matrixDisplayProperties->setGridLinesDisplayed(m_displayGridLinesCheckBox->isChecked()); -/** - * Called when the cell height spin box value is changed. - * - * @param value - * New value for cell height. - */ -void -MatrixChartTwoAttributesWidget::cellHeightPercentageSpinBoxValueChanged(double value) -{ - ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); - if (matrixDisplayProperties != NULL) { - matrixDisplayProperties->setCellPercentageZoomHeight(value); - m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + const BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); + CaretAssert(tabContent); + + const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); + if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { + const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); + CaretAssert(modelChartTwo); + EventChartTwoAttributesChanged attributesEvent; + attributesEvent.setMatrixPropertiesChanged(yokingGroup, + matrixDisplayProperties); + EventManager::get()->sendEvent(attributesEvent.getPointer()); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); + } } } -/** - * Called when the show selection check box is checked. - * - * @param checked - * New checked status. - */ -void -MatrixChartTwoAttributesWidget::highlightSelectionCheckBoxClicked(bool checked) -{ - ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); - if (matrixDisplayProperties != NULL) { - matrixDisplayProperties->setSelectedRowColumnHighlighted(checked); - m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); - } -} -/** - * Called when the display grid lines check box is checked. - * - * @param checked - * New checked status. - */ -void -MatrixChartTwoAttributesWidget::displayGridLinesCheckBoxClicked(bool checked) -{ - ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); - if (matrixDisplayProperties != NULL) { - matrixDisplayProperties->setGridLinesDisplayed(checked); - m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); - } -} +///** +// * Called when the cell width spin box value is changed. +// * +// * @param value +// * New value for cell width. +// */ +//void +//MatrixChartTwoAttributesWidget::cellWidthPercentageSpinBoxValueChanged(double value) +//{ +// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); +// if (matrixDisplayProperties != NULL) { +// matrixDisplayProperties->setCellPercentageZoomWidth(value); +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// } +//} +// +///** +// * Called when the cell height spin box value is changed. +// * +// * @param value +// * New value for cell height. +// */ +//void +//MatrixChartTwoAttributesWidget::cellHeightPercentageSpinBoxValueChanged(double value) +//{ +// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); +// if (matrixDisplayProperties != NULL) { +// matrixDisplayProperties->setCellPercentageZoomHeight(value); +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// } +//} +// +///** +// * Called when the show selection check box is checked. +// * +// * @param checked +// * New checked status. +// */ +//void +//MatrixChartTwoAttributesWidget::highlightSelectionCheckBoxClicked(bool checked) +//{ +// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); +// if (matrixDisplayProperties != NULL) { +// matrixDisplayProperties->setSelectedRowColumnHighlighted(checked); +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// } +//} +// +///** +// * Called when the display grid lines check box is checked. +// * +// * @param checked +// * New checked status. +// */ +//void +//MatrixChartTwoAttributesWidget::displayGridLinesCheckBoxClicked(bool checked) +//{ +// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); +// if (matrixDisplayProperties != NULL) { +// matrixDisplayProperties->setGridLinesDisplayed(checked); +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// } +//} diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h index d72aed964..a45d655da 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h @@ -113,13 +113,15 @@ namespace caret { virtual void updateContent(); private slots: - void cellWidthPercentageSpinBoxValueChanged(double value); - - void cellHeightPercentageSpinBoxValueChanged(double value); - - void highlightSelectionCheckBoxClicked(bool checked); - - void displayGridLinesCheckBoxClicked(bool checked); + void valueChanged(); + +// void cellWidthPercentageSpinBoxValueChanged(double value); +// +// void cellHeightPercentageSpinBoxValueChanged(double value); +// +// void highlightSelectionCheckBoxClicked(bool checked); +// +// void displayGridLinesCheckBoxClicked(bool checked); private: BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 537891d67..24d3cb3b8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -42,6 +42,7 @@ #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" +#include "EventChartTwoAttributesChanged.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "ModelChartTwo.h" @@ -466,6 +467,21 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); + + const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); + CaretAssert(tabContent); + + const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); + if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { + const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); + CaretAssert(modelChartTwo); + const int32_t tabIndex = tabContent->getTabNumber(); + EventChartTwoAttributesChanged attributesEvent; + attributesEvent.setCartesianAxisChanged(yokingGroup, + modelChartTwo->getSelectedChartTwoDataType(tabIndex), + m_chartAxis); + EventManager::get()->sendEvent(attributesEvent.getPointer()); + } } updateGraphics(); -- GitLab From 1e2e677e9ca9f35d6a88a9aa1d8e2c1ad9680e42 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Jun 2017 16:22:15 -0500 Subject: [PATCH 299/755] Move ChartTwoMatrixDisplayProperties out of ModelChartTwo and into BrowserTabContent so that yoking, cloning, new tabs work correctly. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 14 +- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 3 + src/Brain/BrowserTabContent.cxx | 28 ++++ src/Brain/BrowserTabContent.h | 8 ++ src/Brain/ModelChartTwo.cxx | 121 +----------------- src/Brain/ModelChartTwo.h | 7 - ...BrowserWindowToolBarChartTwoAttributes.cxx | 31 +++-- 7 files changed, 71 insertions(+), 141 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 45773a167..d73e41612 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -128,12 +128,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = fixedPipelineDrawing->getTextRenderer(); + m_browserTabContent = browserTabContent; m_translation[0] = 0.0; m_translation[1] = 0.0; m_translation[2] = 0.0; - browserTabContent->getTranslation(m_translation); - m_tabIndex = browserTabContent->getTabNumber(); - m_zooming = browserTabContent->getScaling(); + m_browserTabContent->getTranslation(m_translation); + m_tabIndex = m_browserTabContent->getTabNumber(); + m_zooming = m_browserTabContent->getScaling(); m_chartOverlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabIndex); m_selectionItemDataType = selectionItemDataType; m_viewport[0] = viewport[0]; @@ -153,7 +154,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, * viewport so chart is above color bars. */ std::vector colorBars; - browserTabContent->getAnnotationColorBars(colorBars); + m_browserTabContent->getAnnotationColorBars(colorBars); if ( ! colorBars.empty()) { int heightOfAllColorBars = 0; @@ -1184,7 +1185,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() /* * Set the width and neight of each matrix cell. */ - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); // //m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; @@ -1336,7 +1337,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT else { drawPrimitivePrivate(matrixPrimitive); - const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); +// const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index cf4954715..2d494cc5f 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -31,6 +31,7 @@ namespace caret { class Annotation; + class BrowserTabContent; class CaretPreferences; class ChartTwoCartesianAxis; class ChartTwoDataCartesian; @@ -164,6 +165,8 @@ namespace caret { Brain* m_brain; + BrowserTabContent* m_browserTabContent; + ModelChartTwo* m_chartTwoModel; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 0b25e281d..bd587d303 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -40,6 +40,7 @@ #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartModelDataSeries.h" +#include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateDataSeriesFile.h" @@ -129,6 +130,7 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_viewingTransformation = new ViewingTransformations(); m_volumeSliceViewingTransformation = new ViewingTransformationsVolume(); m_chartTwoMatrixViewingTranformation = new ViewingTransformations(); + m_chartTwoMatrixDisplayProperties = new ChartTwoMatrixDisplayProperties(); m_wholeBrainSurfaceSettings = new WholeBrainSurfaceSettings(); @@ -177,6 +179,10 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) "ViewingTransformations", m_chartTwoMatrixViewingTranformation); + m_sceneClassAssistant->add("m_chartTwoMatrixDisplayProperties", + "ChartTwoMatrixDisplayProperties", + m_chartTwoMatrixDisplayProperties); + m_sceneClassAssistant->add("m_volumeSliceSettings", "VolumeSliceSettings", m_volumeSliceSettings); @@ -228,6 +234,7 @@ BrowserTabContent::~BrowserTabContent() delete m_viewingTransformation; delete m_volumeSliceViewingTransformation; delete m_chartTwoMatrixViewingTranformation; + delete m_chartTwoMatrixDisplayProperties; delete m_obliqueVolumeRotationMatrix; delete m_surfaceModelSelector; @@ -283,6 +290,7 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) *m_viewingTransformation = *tabToClone->m_viewingTransformation; *m_volumeSliceViewingTransformation = *tabToClone->m_volumeSliceViewingTransformation; *m_chartTwoMatrixViewingTranformation = *tabToClone->m_chartTwoMatrixViewingTranformation; + *m_chartTwoMatrixDisplayProperties = *tabToClone->m_chartTwoMatrixDisplayProperties; *m_volumeSliceSettings = *tabToClone->m_volumeSliceSettings; *m_wholeBrainSurfaceSettings = *tabToClone->m_wholeBrainSurfaceSettings; @@ -948,6 +956,24 @@ BrowserTabContent::getChartTwoOverlaySet() const // return NULL; } +/** + * @return Chart two matrix display properties. + */ +ChartTwoMatrixDisplayProperties* +BrowserTabContent::getChartTwoMatrixDisplayProperties() +{ + return m_chartTwoMatrixDisplayProperties; +} + +/** + * @return Chart two matrix display properties (const method) + */ +const ChartTwoMatrixDisplayProperties* +BrowserTabContent::getChartTwoMatrixDisplayProperties() const +{ + return m_chartTwoMatrixDisplayProperties; +} + /** * Get the tab number for this content. * @@ -4252,6 +4278,7 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; *m_chartTwoMatrixViewingTranformation = *btc->m_chartTwoMatrixViewingTranformation; + *m_chartTwoMatrixDisplayProperties = *btc->m_chartTwoMatrixDisplayProperties; *m_volumeSliceSettings = *btc->m_volumeSliceSettings; *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; @@ -4303,6 +4330,7 @@ BrowserTabContent::updateYokedBrowserTabs() *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; *btc->m_chartTwoMatrixViewingTranformation = *m_chartTwoMatrixViewingTranformation; + *btc->m_chartTwoMatrixDisplayProperties = *m_chartTwoMatrixDisplayProperties; *btc->m_volumeSliceSettings = *m_volumeSliceSettings; *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 989f90e93..2722636a7 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -43,6 +43,7 @@ namespace caret { class BrainOpenGLViewportContent; class CaretDataFile; class CaretMappableDataFile; + class ChartTwoMatrixDisplayProperties; class ChartTwoOverlaySet; class ClippingPlaneGroup; class Matrix4x4; @@ -285,6 +286,10 @@ namespace caret { void setTransformationsFromModelTransform(const ModelTransform& modelTransform); + ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(); + + const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties() const; + VolumeSliceViewPlaneEnum::Enum getSliceViewPlane() const; void setSliceViewPlane(VolumeSliceViewPlaneEnum::Enum sliceAxisMode); @@ -503,6 +508,9 @@ namespace caret { /** Transformation for matrix chart two viewing */ ViewingTransformations* m_chartTwoMatrixViewingTranformation; + /** Display properties for chart two matrix */ + ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties; + /** Volume slice settings for volume slices */ VolumeSliceSettings* m_volumeSliceSettings; diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 19eb7316a..1d9d28c4d 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -45,7 +45,6 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartTwoLineSeriesHistory.h" -#include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoOverlaySetArray.h" @@ -58,7 +57,6 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" -#include "EventChartTwoAttributesChanged.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" @@ -95,10 +93,6 @@ ModelChartTwo::ModelChartTwo(Brain* brain) "Matrix Chart Overlays")); m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, "Line Series Chart Overlays")); - - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_chartTwoMatrixDisplayProperties[i] = new ChartTwoMatrixDisplayProperties(); - } initializeCharts(); @@ -115,8 +109,6 @@ ModelChartTwo::ModelChartTwo(Brain* brain) "ChartTwoOverlaySetArray", m_lineSeriesChartOverlaySetArray.get()); - EventManager::get()->addEventListener(this, - EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } @@ -129,12 +121,7 @@ ModelChartTwo::~ModelChartTwo() delete m_overlaySetArray; EventManager::get()->removeAllEventsFromListener(this); - removeAllCharts(); - - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - delete m_chartTwoMatrixDisplayProperties[i]; - m_chartTwoMatrixDisplayProperties[i] = NULL; - } + removeAllCharts(); } void @@ -409,44 +396,6 @@ ModelChartTwo::receiveEvent(Event* event) nodeChartID->setEventProcessed(); } - else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { - EventChartTwoAttributesChanged* attributeEvent = dynamic_cast(event); - CaretAssert(attributeEvent); - - switch (attributeEvent->getMode()) { - case EventChartTwoAttributesChanged::Mode::INVALID: - break; - case EventChartTwoAttributesChanged::Mode::CARTESIAN_AXIS: - break; - case EventChartTwoAttributesChanged::Mode::MATRIX_PROPERTIES: - { - YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; - ChartTwoMatrixDisplayProperties *matrixDisplayProperties = NULL; - attributeEvent->getMatrixPropertiesChanged(yokingGroup, - matrixDisplayProperties); - - - if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) - && (matrixDisplayProperties != NULL)) { - - EventBrowserTabGetAll allTabsEvent; - EventManager::get()->sendEvent(allTabsEvent.getPointer()); - std::vector allTabContent = allTabsEvent.getAllBrowserTabs(); - - for (auto btc : allTabContent) { - CaretAssert(btc); - if (btc->getYokingGroup() == yokingGroup) { - const int32_t tabIndex = btc->getTabNumber(); - *m_chartTwoMatrixDisplayProperties[tabIndex] = *matrixDisplayProperties; - } - } - } - } - break; - } - - attributeEvent->setEventProcessed(); - } } /** @@ -531,19 +480,6 @@ void ModelChartTwo::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { - std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); - - /* - * Save matrix properties. - */ - SceneObjectMapIntegerKey* matrixPropsMap = new SceneObjectMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP", - SceneObjectDataTypeEnum::SCENE_CLASS); - - for (int32_t tabIndex : tabIndices) { - matrixPropsMap->addClass(tabIndex, m_chartTwoMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, - "m_chartTwoMatrixDisplayProperties")); - } - sceneClass->addChild(matrixPropsMap); } /** @@ -606,19 +542,7 @@ ModelChartTwo::restoreModelSpecificInformationFromScene(const SceneAttributes* s void ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) -{ /* - * Restore matrix chart series models from scene. - */ - const SceneObjectMapIntegerKey* matrixPropsMap = sceneClass->getMapIntegerKey("m_chartTwoMatrixDisplayPropertiesMAP"); - if (matrixPropsMap != NULL) { - const std::vector tabIndices = matrixPropsMap->getKeys(); - for (const int32_t tabIndex : tabIndices) { - const SceneClass* sceneClass = matrixPropsMap->classValue(tabIndex); - m_chartTwoMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, - sceneClass); - } - } - +{ /* * Restore the chart models */ @@ -953,11 +877,11 @@ ModelChartTwo::restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, CaretAssert(chartOneMatrixDisplayProperties); - ChartTwoMatrixDisplayProperties* chartTwoMatrixDisplayProperties = getChartTwoMatrixDisplayProperties(tabIndex); - CaretAssert(chartTwoMatrixDisplayProperties); - chartTwoMatrixDisplayProperties->resetPropertiesToDefault(); - chartTwoMatrixDisplayProperties->setGridLinesDisplayed(chartOneMatrixDisplayProperties->isGridLinesDisplayed()); - chartTwoMatrixDisplayProperties->setSelectedRowColumnHighlighted(chartOneMatrixDisplayProperties->isSelectedRowColumnHighlighted()); +// ChartTwoMatrixDisplayProperties* chartTwoMatrixDisplayProperties = getChartTwoMatrixDisplayProperties(tabIndex); +// CaretAssert(chartTwoMatrixDisplayProperties); +// chartTwoMatrixDisplayProperties->resetPropertiesToDefault(); +// chartTwoMatrixDisplayProperties->setGridLinesDisplayed(chartOneMatrixDisplayProperties->isGridLinesDisplayed()); +// chartTwoMatrixDisplayProperties->setSelectedRowColumnHighlighted(chartOneMatrixDisplayProperties->isSelectedRowColumnHighlighted()); AnnotationColorBar* chartOneColorBar = chartOneMatrixDisplayProperties->getColorBar(); EventBrowserTabGet getTabEvent(tabIndex); @@ -1117,7 +1041,6 @@ ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, destinationTabIndex); m_matrixChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, destinationTabIndex); - *m_chartTwoMatrixDisplayProperties[destinationTabIndex] = *m_chartTwoMatrixDisplayProperties[sourceTabIndex]; } @@ -1238,36 +1161,6 @@ ModelChartTwo::updateChartOverlaySets(const int32_t tabIndex) } } -/** - * @return The chart matrix display properties for the given tab. - * - * @param tabIndex - * The tab index. - */ -ChartTwoMatrixDisplayProperties* -ModelChartTwo::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) -{ - CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - return m_chartTwoMatrixDisplayProperties[tabIndex]; -} - -/** - * @return The chart matrix display properties for the given tab. - * - * @param tabIndex - * The tab index. - */ -const ChartTwoMatrixDisplayProperties* -ModelChartTwo::getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const -{ - CaretAssertArrayIndex(m_chartTwoMatrixDisplayProperties, - BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, - tabIndex); - return m_chartTwoMatrixDisplayProperties[tabIndex]; -} - /** * Get the chart overlay set for this model. * diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index ac86bb992..9bf7fa66e 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -40,7 +40,6 @@ namespace caret { class CaretDataFileSelectionModel; - class ChartTwoMatrixDisplayProperties; class ChartTwoOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; @@ -82,10 +81,6 @@ namespace caret { virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; - ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex); - - const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(const int32_t tabIndex) const; - virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) override; virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const override; @@ -155,8 +150,6 @@ namespace caret { /** Chart Overlay sets for XX data type */ std::unique_ptr m_matrixChartOverlaySetArray; - ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; - std::unique_ptr m_sceneAssistant; }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 69d8509f9..474d18f6d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -187,8 +187,7 @@ BrainBrowserWindowToolBarChartTwoAttributes::getChartableTwoMatrixDisplayPropert BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { - ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); - matrixDisplayProperties = modelChartTwo->getChartTwoMatrixDisplayProperties(browserTabContent->getTabNumber()); + matrixDisplayProperties = browserTabContent->getChartTwoMatrixDisplayProperties(); // // if (modelChart != NULL) { // const int32_t tabIndex = browserTabContent->getTabNumber(); @@ -462,20 +461,24 @@ MatrixChartTwoAttributesWidget::valueChanged() matrixDisplayProperties->setSelectedRowColumnHighlighted(m_highlightSelectionCheckBox->isChecked()); matrixDisplayProperties->setGridLinesDisplayed(m_displayGridLinesCheckBox->isChecked()); - const BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); + BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); CaretAssert(tabContent); - const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); - if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { - const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); - CaretAssert(modelChartTwo); - EventChartTwoAttributesChanged attributesEvent; - attributesEvent.setMatrixPropertiesChanged(yokingGroup, - matrixDisplayProperties); - EventManager::get()->sendEvent(attributesEvent.getPointer()); - m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); - EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); - } + tabContent->updateYokedBrowserTabs(); + m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); + +// const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); +// if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { +// const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); +// CaretAssert(modelChartTwo); +// EventChartTwoAttributesChanged attributesEvent; +// attributesEvent.setMatrixPropertiesChanged(yokingGroup, +// matrixDisplayProperties); +// EventManager::get()->sendEvent(attributesEvent.getPointer()); +// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); +// EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); +// } } } -- GitLab From 8b067866d0496ced8c976bd569790599e78733ed Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Jun 2017 12:08:32 -0500 Subject: [PATCH 300/755] When tab yoking is changed to a yoking group that is active in a tab, update the chart two axes to the yoking group's values. --- src/Brain/BrowserTabContent.cxx | 13 +++ src/Brain/ChartTwoOverlaySet.cxx | 19 ++++- src/Brain/ChartTwoOverlaySet.h | 2 + src/Brain/ChartTwoOverlaySetArray.cxx | 22 ++++++ src/Brain/ChartTwoOverlaySetArray.h | 5 +- src/Brain/ModelChartTwo.cxx | 20 +++++ src/Brain/ModelChartTwo.h | 3 + src/Charting/ChartTwoCartesianAxis.cxx | 6 ++ src/Charting/ChartTwoCartesianAxis.h | 4 +- .../EventChartTwoAttributesChanged.cxx | 35 -------- src/Charting/EventChartTwoAttributesChanged.h | 15 +--- ...BrowserWindowToolBarChartTwoAttributes.cxx | 79 +------------------ ...inBrowserWindowToolBarChartTwoAttributes.h | 8 -- 13 files changed, 93 insertions(+), 138 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index bd587d303..f14c94878 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -4260,6 +4260,8 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) return; } + int32_t copyFromTabIndex = -1; + /* * Find another browser tab using the same yoking as 'me' and copy * yoked data from the other browser tab. @@ -4270,6 +4272,7 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) BrowserTabContent* btc = *iter; if (btc != this) { if (btc->getYokingGroup() == m_yokingGroup) { + copyFromTabIndex = btc->getTabNumber(); /* * If anything is added, also need to update updateYokedBrowserTabs() */ @@ -4287,6 +4290,16 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) } } } + + if (copyFromTabIndex >= 0) { + /* + * Maybe NULL when restoring scenes + */ + if (m_chartTwoModel != NULL) { + m_chartTwoModel->copyChartTwoCartesianAxes(copyFromTabIndex, + m_tabNumber); + } + } } /** diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index ca0f9ae33..2944fbb77 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -187,6 +187,23 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } +/** + * Copy the cartesian axes from the given overlay set to this overlay set. + * + * @param overlaySet + * Overlay from which axes are copied. + */ +void +ChartTwoOverlaySet::copyCartesianAxes(const ChartTwoOverlaySet* overlaySet) +{ + CaretAssert(m_chartDataType == overlaySet->m_chartDataType); + + *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; + *m_chartAxisRight = *overlaySet->m_chartAxisRight; + *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; +} + + /** * @return Returns the top-most overlay regardless of its enabled status. */ @@ -568,8 +585,6 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } } break; - case EventChartTwoAttributesChanged::Mode::MATRIX_PROPERTIES: - break; } attributeEvent->setEventProcessed(); diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 127728076..5909f619e 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -47,6 +47,8 @@ namespace caret { void copyOverlaySet(const ChartTwoOverlaySet* overlaySet); + void copyCartesianAxes(const ChartTwoOverlaySet* overlaySet); + ChartTwoOverlay* getPrimaryOverlay(); const ChartTwoOverlay* getPrimaryOverlay() const; diff --git a/src/Brain/ChartTwoOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx index 7fbe0a804..ab3ef802d 100644 --- a/src/Brain/ChartTwoOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -177,6 +177,28 @@ ChartTwoOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, destinationChartOverlaySet->copyOverlaySet(sourceChartOverlaySet); } +/** + * Copy the chart overlay set cartesian axes from the source tab index to the + * destination tab index. + * + * @param sourceTabIndex + * Source from which tab content is copied. + * @param destinationTabIndex + * Destination to which tab content is copied. + */ +void +ChartTwoOverlaySetArray::copyChartOverlaySetCartesianAxes(const int32_t sourceTabIndex, + const int32_t destinationTabIndex) +{ + CaretAssertVectorIndex(m_chartOverlaySets, sourceTabIndex); + CaretAssertVectorIndex(m_chartOverlaySets, destinationTabIndex); + + const ChartTwoOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; + ChartTwoOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; + + destinationChartOverlaySet->copyCartesianAxes(sourceChartOverlaySet); +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Brain/ChartTwoOverlaySetArray.h b/src/Brain/ChartTwoOverlaySetArray.h index 8dddcc65a..0edbe6e19 100644 --- a/src/Brain/ChartTwoOverlaySetArray.h +++ b/src/Brain/ChartTwoOverlaySetArray.h @@ -45,7 +45,10 @@ namespace caret { void initializeOverlaySelections(); void copyChartOverlaySet(const int32_t sourceTabIndex, - const int32_t destinationTabIndex); + const int32_t destinationTabIndex); + + void copyChartOverlaySetCartesianAxes(const int32_t sourceTabIndex, + const int32_t destinationTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 1d9d28c4d..150f5494b 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -1043,6 +1043,26 @@ ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, destinationTabIndex); } +/** + * Copy cartesian axes from one tab to another. + * + * @param sourceTabIndex + * Source from which tab content is copied. + * @param destinationTabIndex + * Destination to which tab content is copied. + */ +void +ModelChartTwo::copyChartTwoCartesianAxes(const int32_t sourceTabIndex, + const int32_t destinationTabIndex) +{ + CaretAssertArrayIndex(m_histogramChartOverlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); + CaretAssertArrayIndex(m_lineSeriesChartOverlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); + + m_histogramChartOverlaySetArray->copyChartOverlaySetCartesianAxes(sourceTabIndex, + destinationTabIndex); + m_lineSeriesChartOverlaySetArray->copyChartOverlaySetCartesianAxes(sourceTabIndex, + destinationTabIndex); +} /** * Set the type of chart selected in the given tab. diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index 9bf7fa66e..11a2c4bcd 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -104,6 +104,9 @@ namespace caret { void restoreSceneFromChartOneModel(ModelChart* modelChartOne); + void copyChartTwoCartesianAxes(const int32_t sourceTabIndex, + const int32_t destinationTabIndex); + protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 1d879f01f..9088883b2 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -623,6 +623,9 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], break; } + m_rangeMinimumValue = 0.0; + m_rangeMaximumValue = 0.0; + if (maxValue > minValue) { double scaleStep = 0.0; double scaleMin = 0.0; @@ -640,6 +643,9 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], stepValueOut = scaleStep; digitsRightOfDecimalOut = digitsRightOfDecimal; + m_rangeMinimumValue = minimumOut; + m_rangeMaximumValue = maximumOut; + return true; } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 035819d52..a65f6cfb3 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -151,10 +151,10 @@ namespace caret { const ChartAxisLocationEnum::Enum m_axisLocation; /** Allowable range minimum NOT SAVED TO SCENE */ - float m_rangeMinimumValue = 0.0; + mutable float m_rangeMinimumValue = 0.0; /** Allowable range maximum NOT SAVED TO SCENE */ - float m_rangeMaximumValue = 1.0; + mutable float m_rangeMaximumValue = 1.0; mutable float m_userScaleMinimumValue = -100.0; diff --git a/src/Charting/EventChartTwoAttributesChanged.cxx b/src/Charting/EventChartTwoAttributesChanged.cxx index 462b042f8..325021a5e 100644 --- a/src/Charting/EventChartTwoAttributesChanged.cxx +++ b/src/Charting/EventChartTwoAttributesChanged.cxx @@ -104,38 +104,3 @@ EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &y } -/** - * Set for a change in matrix properties. - * - * @param yokingGroup - * Selected yoking group. - * @param matrixDisplayProperties - * The matrix properties. - */ -void -EventChartTwoAttributesChanged::setMatrixPropertiesChanged(const YokingGroupEnum::Enum yokingGroup, - const ChartTwoMatrixDisplayProperties* matrixDisplayProperties) -{ - m_mode = Mode::MATRIX_PROPERTIES; - m_yokingGroup = yokingGroup; - m_matrixDisplayProperties = const_cast(matrixDisplayProperties); -} - -/** - * Get for a change in matrix properties. - * - * @param yokingGroupOut - * Selected yoking group. - * @param matrixDisplayPropertiesOut - * The matrix properties. - */ -void -EventChartTwoAttributesChanged::getMatrixPropertiesChanged(YokingGroupEnum::Enum &yokingGroupOut, - ChartTwoMatrixDisplayProperties* &matrixDisplayPropertiesOut) -{ - CaretAssert(m_mode == Mode::MATRIX_PROPERTIES); - yokingGroupOut = m_yokingGroup; - matrixDisplayPropertiesOut = m_matrixDisplayProperties; -} - - diff --git a/src/Charting/EventChartTwoAttributesChanged.h b/src/Charting/EventChartTwoAttributesChanged.h index 929f3a5df..799e8426f 100644 --- a/src/Charting/EventChartTwoAttributesChanged.h +++ b/src/Charting/EventChartTwoAttributesChanged.h @@ -33,18 +33,18 @@ namespace caret { class ChartTwoCartesianAxis; - class ChartTwoMatrixDisplayProperties; class EventChartTwoAttributesChanged : public Event { public: enum class Mode { INVALID, - CARTESIAN_AXIS, - MATRIX_PROPERTIES + CARTESIAN_AXIS }; EventChartTwoAttributesChanged(); + ~EventChartTwoAttributesChanged(); + Mode getMode() const; void setCartesianAxisChanged(const YokingGroupEnum::Enum yokingGroup, @@ -55,13 +55,6 @@ namespace caret { ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoCartesianAxis* &cartesianAxisOut); - void setMatrixPropertiesChanged(const YokingGroupEnum::Enum yokingGroup, - const ChartTwoMatrixDisplayProperties* matrixDisplayProperties); - - void getMatrixPropertiesChanged(YokingGroupEnum::Enum &yokingGroupOut, - ChartTwoMatrixDisplayProperties* &matrixDisplayPropertiesOut); - - virtual ~EventChartTwoAttributesChanged(); // ADD_NEW_METHODS_HERE @@ -79,8 +72,6 @@ namespace caret { ChartTwoCartesianAxis* m_cartesianAxis = NULL; - ChartTwoMatrixDisplayProperties* m_matrixDisplayProperties = NULL; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 474d18f6d..86315f03f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -417,7 +417,7 @@ MatrixChartTwoAttributesWidget::~MatrixChartTwoAttributesWidget() * The event. */ void -MatrixChartTwoAttributesWidget::receiveEvent(Event* event) +MatrixChartTwoAttributesWidget::receiveEvent(Event* /*event*/) { } @@ -467,84 +467,7 @@ MatrixChartTwoAttributesWidget::valueChanged() tabContent->updateYokedBrowserTabs(); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); - -// const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); -// if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { -// const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); -// CaretAssert(modelChartTwo); -// EventChartTwoAttributesChanged attributesEvent; -// attributesEvent.setMatrixPropertiesChanged(yokingGroup, -// matrixDisplayProperties); -// EventManager::get()->sendEvent(attributesEvent.getPointer()); -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); -// } } } -///** -// * Called when the cell width spin box value is changed. -// * -// * @param value -// * New value for cell width. -// */ -//void -//MatrixChartTwoAttributesWidget::cellWidthPercentageSpinBoxValueChanged(double value) -//{ -// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); -// if (matrixDisplayProperties != NULL) { -// matrixDisplayProperties->setCellPercentageZoomWidth(value); -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// } -//} -// -///** -// * Called when the cell height spin box value is changed. -// * -// * @param value -// * New value for cell height. -// */ -//void -//MatrixChartTwoAttributesWidget::cellHeightPercentageSpinBoxValueChanged(double value) -//{ -// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); -// if (matrixDisplayProperties != NULL) { -// matrixDisplayProperties->setCellPercentageZoomHeight(value); -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// } -//} -// -///** -// * Called when the show selection check box is checked. -// * -// * @param checked -// * New checked status. -// */ -//void -//MatrixChartTwoAttributesWidget::highlightSelectionCheckBoxClicked(bool checked) -//{ -// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); -// if (matrixDisplayProperties != NULL) { -// matrixDisplayProperties->setSelectedRowColumnHighlighted(checked); -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// } -//} -// -///** -// * Called when the display grid lines check box is checked. -// * -// * @param checked -// * New checked status. -// */ -//void -//MatrixChartTwoAttributesWidget::displayGridLinesCheckBoxClicked(bool checked) -//{ -// ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); -// if (matrixDisplayProperties != NULL) { -// matrixDisplayProperties->setGridLinesDisplayed(checked); -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// } -//} - - diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h index a45d655da..3855496a6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h @@ -115,14 +115,6 @@ namespace caret { private slots: void valueChanged(); -// void cellWidthPercentageSpinBoxValueChanged(double value); -// -// void cellHeightPercentageSpinBoxValueChanged(double value); -// -// void highlightSelectionCheckBoxClicked(bool checked); -// -// void displayGridLinesCheckBoxClicked(bool checked); - private: BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; -- GitLab From 9e1c748c82a4d3e7d397d0c1658dacfd8b01c4c0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Jun 2017 12:34:14 -0500 Subject: [PATCH 301/755] When tab yoking is changed to a yoking group that is active in a tab, update the chart two axes to the yoking group's values. --- src/Brain/ChartTwoOverlay.cxx | 1 - src/Brain/ChartTwoOverlaySetArray.cxx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index fbc762424..ac8b84d25 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -190,7 +190,6 @@ ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) if (mapFile->hasMapAttributes()) { switch (indexType) { case SelectedIndexType::INVALID: - descriptionOut.addLine("Invalid selection type (none of map, row, column)"); break; case SelectedIndexType::COLUMN: descriptionOut.addLine("Column " diff --git a/src/Brain/ChartTwoOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx index ab3ef802d..70914f8e3 100644 --- a/src/Brain/ChartTwoOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -196,7 +196,7 @@ ChartTwoOverlaySetArray::copyChartOverlaySetCartesianAxes(const int32_t sourceTa const ChartTwoOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; ChartTwoOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; - destinationChartOverlaySet->copyCartesianAxes(sourceChartOverlaySet); + destinationChartOverlaySet->copyCartesianAxes(sourceChartOverlaySet); } /** -- GitLab From 6137c9febd985fe3171d90051df06c7bb98b2f2d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Jun 2017 12:57:00 -0500 Subject: [PATCH 302/755] Fixed memory leak that occurred in CiftiParcelReorderingModel when restoring a scene. --- src/Files/CiftiParcelReorderingModel.cxx | 12 +++++++++++- src/Files/CiftiParcelReorderingModel.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Files/CiftiParcelReorderingModel.cxx b/src/Files/CiftiParcelReorderingModel.cxx index 15023347a..e904e4d5e 100644 --- a/src/Files/CiftiParcelReorderingModel.cxx +++ b/src/Files/CiftiParcelReorderingModel.cxx @@ -82,6 +82,15 @@ CiftiParcelReorderingModel::~CiftiParcelReorderingModel() { delete m_sceneAssistant; + clearCiftiParcelReordering(); +} + +/** + * Clear all parcel reordering. + */ +void +CiftiParcelReorderingModel::clearCiftiParcelReordering() +{ for (std::vector::iterator iter = m_parcelReordering.begin(); iter != m_parcelReordering.end(); iter++) { @@ -90,6 +99,7 @@ CiftiParcelReorderingModel::~CiftiParcelReorderingModel() m_parcelReordering.clear(); } + /** * Copy constructor. * @param obj @@ -515,7 +525,7 @@ CiftiParcelReorderingModel::restoreFromScene(const SceneAttributes* sceneAttribu sceneClass); m_selectedParcelLabelFile = NULL; - m_parcelReordering.clear(); + clearCiftiParcelReordering(); const AString parcelLabelFileName = sceneClass->getPathNameValue("m_selectedParcelLabelFile"); if ( ! parcelLabelFileName.isEmpty()) { diff --git a/src/Files/CiftiParcelReorderingModel.h b/src/Files/CiftiParcelReorderingModel.h index 7b6ffaa9d..198e90b13 100644 --- a/src/Files/CiftiParcelReorderingModel.h +++ b/src/Files/CiftiParcelReorderingModel.h @@ -97,6 +97,8 @@ namespace caret { std::vector getParcelLabelFiles() const; + void clearCiftiParcelReordering(); + mutable std::map m_parcelLabelFileCompatibilityStatus; const CiftiMappableDataFile* m_parentCiftiMappableDataFile; -- GitLab From dfdbfaac3fd09a1b7d004809b14ffd27f7f12006 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Jun 2017 16:50:41 -0500 Subject: [PATCH 303/755] Finished merging with master and needed a few fixes. Also, cleaned out some commented out code. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 127 +-------- src/Brain/BrainOpenGLFixedPipeline.h | 2 - src/Files/CaretMappableDataFile.cxx | 365 ++++--------------------- src/Files/CiftiMappableDataFile.cxx | 97 ------- src/Files/CiftiMappableDataFile.h | 11 - src/GuiQt/SceneDialog.cxx | 125 +-------- src/GuiQt/SceneDialog.h | 2 - 7 files changed, 55 insertions(+), 674 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 53d9cba83..79e498d07 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -815,16 +815,13 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) * User may want window annotations only when in tile tabs view. */ BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WindowDrawingMode windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO; -// bool drawWindowAnnotationsFlag = false; if (m_tileTabsActiveFlag) { -// drawWindowAnnotationsFlag = true; windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_YES; } else { const DisplayPropertiesAnnotation* dpa = m_brain->getDisplayPropertiesAnnotation(); if (dpa->isDisplayWindowAnnotationsInSingleTabViews(m_windowIndex)) { windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_YES; -// drawWindowAnnotationsFlag = true; } } @@ -914,8 +911,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, this->mode = mode; -// drawBackgroundImage(viewportContent); - if (this->browserTabContent != NULL) { m_clippingPlaneGroup = const_cast(this->browserTabContent->getClippingPlaneGroup()); CaretAssert(m_clippingPlaneGroup); @@ -1339,16 +1334,6 @@ BrainOpenGLFixedPipeline::applyViewingTransformations(const Model* model, translation[1], translation[2]); -// if (rightCortexFlatFlag) { -// /* -// * When drawing right flat, the translation is "left translation" -// * so need to flip sign of X-offset. -// */ -// float rightFlatOffsetX, rightFlatOffsetY; -// browserTabContent->getRightCortexFlatMapOffset(rightFlatOffsetX, rightFlatOffsetY); -// glTranslatef(-rightFlatOffsetX, rightFlatOffsetY, 0.0); -// } - glMultMatrixd(rotationMatrixElements); /* @@ -1771,8 +1756,6 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, const DisplayPropertiesBorders* dpb = m_brain->getDisplayPropertiesBorders(); const float borderAboveSurfaceOffset = dpb->getAboveSurfaceOffset(); if (borderAboveSurfaceOffset != 0.0) { -// const float factor = borderAboveSurfaceOffset * 1.0 + 1.0; -// const float units = borderAboveSurfaceOffset * 1.0 + 1.0; const float factor = borderAboveSurfaceOffset;// + 0.5; const float units = 1.0;// + 0.5; glEnable(GL_POLYGON_OFFSET_FILL); @@ -5231,60 +5214,6 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte glPopMatrix(); } } -// /* -// * Draw surfaces last so that opacity works. -// */ -// const int32_t numberOfBrainStructures = brain->getNumberOfBrainStructures(); -// for (int32_t i = 0; i < numberOfBrainStructures; i++) { -// BrainStructure* brainStructure = brain->getBrainStructure(i); -// const StructureEnum::Enum structure = brainStructure->getStructure(); -// Surface* surface = wholeBrainModel->getSelectedSurface(structure, -// tabNumberIndex); -// if (surface != NULL) { -// float dx = 0.0; -// float dy = 0.0; -// float dz = 0.0; -// -// bool drawIt = false; -// switch (structure) { -// case StructureEnum::CORTEX_LEFT: -// drawIt = browserTabContent->isWholeBrainLeftEnabled(); -// dx = -browserTabContent->getWholeBrainLeftRightSeparation(); -// if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) -// && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { -// dx -= surface->getBoundingBox()->getMaxX(); -// } -// break; -// case StructureEnum::CORTEX_RIGHT: -// drawIt = browserTabContent->isWholeBrainRightEnabled(); -// dx = browserTabContent->getWholeBrainLeftRightSeparation(); -// if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) -// && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { -// dx -= surface->getBoundingBox()->getMinX(); -// } -// break; -// case StructureEnum::CEREBELLUM: -// drawIt = browserTabContent->isWholeBrainCerebellumEnabled(); -// dz = browserTabContent->getWholeBrainCerebellumSeparation(); -// break; -// default: -// CaretLogWarning("programmer-issure: Surface type not left/right/cerebellum"); -// break; -// } -// -// const float* nodeColoringRGBA = this->surfaceNodeColoring->colorSurfaceNodes(wholeBrainModel, -// surface, -// this->windowTabIndex); -// -// if (drawIt) { -// glPushMatrix(); -// glTranslatef(dx, dy, dz); -// this->drawSurface(surface, -// nodeColoringRGBA); -// glPopMatrix(); -// } -// } -// } } /** @@ -5492,7 +5421,6 @@ BrainOpenGLFixedPipeline::setOrthographicProjectionForWithBoundingBox(const int3 if (windowVerticalSize != 0.0) { modelHalfHeight = windowVerticalSize / 2.0; -// const float yDiff = boundingBox->getDifferenceY(); if ((windowHorizontalSize > 0.0) && (viewport[2] > 0.0)) { /* @@ -5647,60 +5575,7 @@ BrainOpenGLFixedPipeline::checkForOpenGLError(const Model* model, BrainOpenGL::testForOpenGLError(msgIn, model, this->m_windowIndex, - this->windowTabIndex); - -// GLenum errorCode = glGetError(); -// if (errorCode != GL_NO_ERROR) { -// AString msg; -// if (msgIn.isEmpty() == false) { -// msg += (msgIn + "\n"); -// } -// msg += ("OpenGL Error: " + AString((char*)gluErrorString(errorCode)) + "\n"); -// msg += ("OpenGL Version: " + AString((char*)glGetString(GL_VERSION)) + "\n"); -// msg += ("OpenGL Vendor: " + AString((char*)glGetString(GL_VENDOR)) + "\n"); -// if (model != NULL) { -// msg += ("While drawing brain model " + model->getNameForGUI(true) + "\n"); -// } -// msg += ("In tab number " + AString::number(this->windowTabIndex) + "\n"); -// -// GLint maxNameStackDepth, maxModelStackDepth, maxProjStackDepth; -// glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, -// &maxProjStackDepth); -// glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, -// &maxModelStackDepth); -// glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, -// &maxNameStackDepth); -// -// GLint nameStackDepth, modelStackDepth, projStackDepth; -// glGetIntegerv(GL_PROJECTION_STACK_DEPTH, -// &projStackDepth); -// glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, -// &modelStackDepth); -// glGetIntegerv(GL_NAME_STACK_DEPTH, -// &nameStackDepth); -// -// msg += ("Projection Matrix Stack Depth " -// + AString::number(projStackDepth) -// + " Max Depth " -// + AString::number(maxProjStackDepth) -// + "\n"); -// msg += ("Model Matrix Stack Depth " -// + AString::number(modelStackDepth) -// + " Max Depth " -// + AString::number(maxModelStackDepth) -// + "\n"); -// msg += ("Name Matrix Stack Depth " -// + AString::number(nameStackDepth) -// + " Max Depth " -// + AString::number(maxNameStackDepth) -// + "\n"); -// SystemBacktrace myBacktrace; -// SystemUtilities::getBackTrace(myBacktrace); -// msg += ("Backtrace:\n" -// + myBacktrace.toSymbolString() -// + "\n"); -// CaretLogSevere(msg); -// } + this->windowTabIndex); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 95f2054b1..96b13074e 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -461,8 +461,6 @@ namespace caret { void drawWindowAnnotations(const int windowViewport[4]); -// void drawTabAnnotations(BrainOpenGLViewportContent* tabContent, -// const int32_t tabViewport[4]); void drawTabAnnotations(BrainOpenGLViewportContent* tabContent); void drawBackgroundImage(BrainOpenGLViewportContent* vpContent); diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 626b2b40a..1d5f06f35 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -909,6 +909,19 @@ CaretMappableDataFile::isModified() const return false; } +/** + * Clear the modified status of this file. + */ +void +CaretMappableDataFile::clearModified() +{ + CaretDataFile::clearModified(); + + if (m_chartingDelegate != NULL) { + m_chartingDelegate->clearModified(); + } +} + /** * Create cartesian chart data from the given data. * @@ -1080,6 +1093,43 @@ CaretMappableDataFile::getLabelDrawingProperties() const return m_labelDrawingProperties.get(); } +/** + * @return The charting delegate for this file. Pointer + * will never be NULL, even if file does not support charting. + */ +ChartableTwoFileDelegate* +CaretMappableDataFile::getChartingDelegate() +{ + if (m_chartingDelegate == NULL) { + m_chartingDelegate = std::unique_ptr(new ChartableTwoFileDelegate(this)); + } + return m_chartingDelegate.get(); +} + +/* + * @return The charting delegate for this file. Pointer + * will never be NULL, even if file does not support charting. + */ +const ChartableTwoFileDelegate* +CaretMappableDataFile::getChartingDelegate() const +{ + if (m_chartingDelegate == NULL) { + CaretMappableDataFile* thisFile = const_cast(this); + m_chartingDelegate = std::unique_ptr(new ChartableTwoFileDelegate(thisFile)); + } + return m_chartingDelegate.get(); +} + +/** + * Update the charting delegate after changes + * are made to the data file. + */ +void +CaretMappableDataFile::updateChartingDelegate() +{ + getChartingDelegate()->updateAfterFileChanged(); +} + /** * @return The palette normalization mode for the file. * The default is NORMALIZATION_SELECTED_MAP_DATA. @@ -1142,318 +1192,3 @@ const CiftiXML CaretMappableDataFile::getCiftiXML() const return CiftiXML(); } -///** -// * @return The CaretMappableDataFile that implements this interface. -// */ -//CaretMappableDataFile* -//CaretMappableDataFile::getAsCaretMappableDataFile() -//{ -// return this; -//} -// -///** -// * @return The CaretMappableDataFile that implements this interface. -// */ -//const CaretMappableDataFile* -//CaretMappableDataFile::getAsCaretMappableDataFile() const -//{ -// return this; -//} -// -// -///** -// * Does this file support any type of charting? -// */ -//bool -//CaretMappableDataFile::isChartingSupported() const -//{ -// std::vector chartCompoundDataTypes; -// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); -// -// return ( ! chartCompoundDataTypes.empty()); -//} -// -///** -// * Test for support of the given chart data type. -// * -// * @param chartDataType -// * Type of chart data. -// * @return -// * True if the chart data type is supported, else false. -// */ -//bool -//CaretMappableDataFile::isChartingSupportedForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const -//{ -// std::vector chartDataTypes; -// getSupportedChartDataTypes(chartDataTypes); -// -// if (std::find(chartDataTypes.begin(), -// chartDataTypes.end(), -// chartDataType) != chartDataTypes.end()) { -// return true; -// } -// -// return false; -//} -// -///** -// * Test for support of the given chart compound data type. -// * -// * @param chartCompoundDataType -// * Type of chart compound data. -// * @return -// * True if the chart compound data type is supported, else false. -// */ -//bool -//CaretMappableDataFile::isChartingSupportedForChartCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const -//{ -// std::vector chartCompoundDataTypes; -// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); -// -// for (auto& ccdt : chartCompoundDataTypes) { -// if (ccdt == chartCompoundDataType) { -// return true; -// } -// } -// -// return false; -//} -// -///** -// * Get chart data types supported by this file. -// * -// * @param chartDataTypesOut -// * Output containing all chart data types supported by this data file. -// */ -//void -//CaretMappableDataFile::getSupportedChartDataTypes(std::vector& chartDataTypesOut) const -//{ -// chartDataTypesOut.clear(); -// -// std::vector chartCompoundDataTypes; -// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); -// -// for (auto& ccdt : chartCompoundDataTypes) { -// chartDataTypesOut.push_back(ccdt.getChartDataType()); -// } -//} -// -///** -// * Get chart data types supported by this file. -// * -// * @param chartDataTypesOut -// * Output containing all chart data types supported by this data file. -// */ -//void -//CaretMappableDataFile::getSupportedChartCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const -//{ -// chartCompoundDataTypesOut.clear(); -// -// bool hasHistogramFlag = false; -// bool hasBrainordinateLineSeriesFlag = false; -// bool hasNoMapsLineSeriesFlag = false; -// bool hasMatrixFlag = false; -// -// switch (getDataFileType()) { -// case DataFileTypeEnum::CONNECTIVITY_DENSE: -// hasHistogramFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: -// hasHistogramFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: -// hasHistogramFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL: -// hasHistogramFlag = true; -// hasMatrixFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: -// hasHistogramFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: -// //hasMatrixFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// hasMatrixFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// break; -// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: -// hasHistogramFlag = true; -// hasNoMapsLineSeriesFlag = true; -// hasMatrixFlag = true; -// break; -// case DataFileTypeEnum::ANNOTATION: -// break; -// case DataFileTypeEnum::BORDER: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: -// break; -// case DataFileTypeEnum::FOCI: -// break; -// case DataFileTypeEnum::IMAGE: -// break; -// case DataFileTypeEnum::LABEL: -// break; -// case DataFileTypeEnum::METRIC: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// break; -// case DataFileTypeEnum::PALETTE: -// break; -// case DataFileTypeEnum::RGBA: -// break; -// case DataFileTypeEnum::SCENE: -// break; -// case DataFileTypeEnum::SPECIFICATION: -// break; -// case DataFileTypeEnum::SURFACE: -// break; -// case DataFileTypeEnum::UNKNOWN: -// break; -// case DataFileTypeEnum::VOLUME: -// hasHistogramFlag = true; -// hasBrainordinateLineSeriesFlag = true; -// break; -// } -// -// if (hasHistogramFlag) { -// if (getNumberOfMaps() > 0) { -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); -// } -// } -// -// if (hasBrainordinateLineSeriesFlag) { -// if (getNumberOfMaps() > 1) { -// const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// const int32_t numMaps = getNumberOfMaps(); -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numMaps)); -// } -// } -// -// if (hasNoMapsLineSeriesFlag) { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// //const int32_t numRows = dims[1]; -// -// if (numCols > 1) { -// const NiftiTimeUnitsEnum::Enum mapUnits = getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numCols)); -// } -// } -// -// if (hasMatrixFlag) { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// const int32_t numRows = dims[1]; -// -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, -// numCols)); -// } -//} -// -///** -// * Get the chart compound data type supported by this file that uses the given -// * chart data type. -// * -// * @param chartDataType -// * The chart data type. -// * @param chartCompoundDataTypeOut -// * Output with the chart compound data type. -// * @return -// * True if there is output chart compound data type is valid. -// * False if output chart compound data type is invalid OR if chartDataType is invalid. -// */ -//bool -//CaretMappableDataFile::getChartCompoundDataTypeForChartDataType(const ChartTwoDataTypeEnum::Enum chartDataType, -// ChartTwoCompoundDataType& chartCompoundDataTypeOut) const -//{ -// std::vector chartCompoundDataTypes; -// getSupportedChartCompoundDataTypes(chartCompoundDataTypes); -// for (auto& cdt : chartCompoundDataTypes) { -// if (cdt.getChartDataType() == chartDataType) { -// chartCompoundDataTypeOut = cdt; -// return true; -// } -// } -// -// /* default constructor is invalid data type */ -// chartCompoundDataTypeOut = ChartTwoCompoundDataType(); -// return false; -//} -// -///** -// * @return Charting history if this file charts to lines. -// */ -//ChartTwoDataCartesianHistory* -//CaretMappableDataFile::getLineSeriesChartingHistory() -//{ -// return m_lineChartHistory.get(); -//} diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 80b2ac368..4c126722a 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1121,43 +1121,6 @@ CiftiMappableDataFile::writeFile(const AString& ciftiMapFileName) clearModified(); } -///** -// * @return The string name of the CIFTI index type. -// * @param ciftiIndexType -// */ -//AString -//CiftiMappableDataFile::ciftiIndexTypeToName(const IndicesMapToDataType ciftiIndexType) -//{ -// AString name = "Invalid"; -// -// switch (ciftiIndexType) { -// case CIFTI_INDEX_TYPE_BRAIN_MODELS: -// name = "CIFTI_INDEX_TYPE_BRAIN_MODELS"; -// break; -// case CIFTI_INDEX_TYPE_FIBERS: -// name = "CIFTI_INDEX_TYPE_FIBERS"; -// break; -// case CIFTI_INDEX_TYPE_INVALID: -// name = "CIFTI_INDEX_TYPE_INVALID"; -// break; -// case CIFTI_INDEX_TYPE_LABELS: -// name = "CIFTI_INDEX_TYPE_LABELS"; -// break; -// case CIFTI_INDEX_TYPE_PARCELS: -// name = "CIFTI_INDEX_TYPE_PARCELS"; -// break; -// case CIFTI_INDEX_TYPE_SCALARS: -// name = "CIFTI_INDEX_TYPE_SCALARS"; -// break; -// case CIFTI_INDEX_TYPE_TIME_POINTS: -// name = "CIFTI_INDEX_TYPE_TIME_POINTS"; -// break; -// } -// -// return name; -//} -// -// /** * @return Is the data mappable to a surface? */ @@ -4244,11 +4207,6 @@ CiftiMappableDataFile::getMapSurfaceNodeValue(const int32_t mapIndex, std::vector mapData; getMapData(mapIndex, mapData); - -// if (parcelIndex < static_cast(mapData.size())) { -// textValueOut += (" " -// + AString::number(mapData[parcelIndex])); -// } } } @@ -4710,24 +4668,6 @@ CiftiMappableDataFile::getSurfaceNodeIdentificationForMaps(const std::vector mapData; -// getMapData(mapIndex, mapData); -// -// if (parcelMapIndex < static_cast(mapData.size())) { -// textValueOut += (" " -// + AString::number(mapData[parcelMapIndex])); -// } } if (parcelMapIndex >= 0) { @@ -5381,14 +5313,7 @@ CiftiMappableDataFile::getMapVolumeVoxelValues(const std::vector mapInd textValueOut += (getMapName(*mapIter) + " "); } -// const AString networkName = getMapName(mapIndex); -// -// textValueOut = ("Area: " -// + areaName -// + ", Network: " -// + networkName); return true; - } else { switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { @@ -5717,23 +5642,6 @@ CiftiMappableDataFile::getVolumeVoxelIdentificationForMaps(const std::vector& data 0); } } -// else { -// const AString msg("NULL palette for coloring scalar data."); -// CaretAssertMessage(0, msg); -// CaretLogSevere(msg); -// } m_rgbaValid = true; } diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index 2b190c29f..eb0655f9a 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -531,15 +531,6 @@ namespace caret { const std::vector& rowIndicesIn, std::vector& rgbaOut) const; -// bool helpLoadChartDataMatrixRGBA(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// std::vector& rgbaOut) const; -// -// bool helpLoadChartDataMatrixRGBAWithRowIndicese(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// const std::vector& rowIndices, -// std::vector& rgbaOut) const; - private: class MapContent : public CaretObjectTracksModification { @@ -790,8 +781,6 @@ namespace caret { friend class ChartableTwoFileDelegate; friend class ChartableTwoFileMatrixChart; -// std::vector m_ciftiDimensions; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index d72824c8d..e34c04847 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -207,19 +207,6 @@ SceneDialog::closeEvent(QCloseEvent* event) return; } -// const SceneFile* sceneFile = getSelectedSceneFile(); -// -// if ((numberOfModifiedSceneFiles == 1) -// && sceneFile->isModified()) { -// const bool successFlag = warnIfSceneFileIsModified(ModifiedWarningType::CLOSE_DIALOG_BUTTON); -// if (successFlag) { -// return; -// } -// event->ignore(); -// WuQDialogNonModal::closeEvent(event); -// return; -// } - const AString msg("There are modified scene file(s). You can save modified scene files using File Menu->Save/Manage Files " "or by selecting them on the Scene Dialog and using the Save/Save As buttons.

" "Continue closing this Scene Dialog?"); @@ -1015,17 +1002,7 @@ SceneDialog::zipSceneFileButtonClicked() } SceneFile* sceneFile = getSelectedSceneFile(); -// if (sceneFile == NULL) { -// WuQMessageBox::errorOk(m_zipSceneFilePushButton, -// "No Scene File is selected."); -// return; -// } -// if (sceneFile->isModified()) { -// WuQMessageBox::errorOk(m_zipSceneFilePushButton, -// "Selected Scene File is modified and must be saved prior to zipping."); -// return; -// } - + ZipSceneFileDialog zipDialog(sceneFile, this); zipDialog.exec(); @@ -1439,7 +1416,6 @@ SceneDialog::testScenesPushButtonClicked() } } - //showWaitCursor(); ProgressReportingDialog progressDialog("Test All Scenes", "Starting...", m_testScenesPushButton); @@ -1683,89 +1659,6 @@ SceneDialog::replaceSceneButtonClicked() } } -///** -// * Add an image to the scene. -// * -// * @param scene -// * Scene to which image is added. -// */ -//void -//SceneDialog::addImageToScene(Scene* scene) -//{ -// AString errorMessage; -// -// CaretAssert(scene); -// -// uint8_t backgroundColor[3] = { 0, 0, 0 }; -// bool backgroundColorValid = false; -// -// /* -// * Capture an image of each window -// */ -// std::vector imageFiles; -// std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); -// for (std::vector::iterator iter = windows.begin(); -// iter != windows.end(); -// iter++) { -// BrainBrowserWindow* bbw = *iter; -// const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); -// -// EventImageCapture imageCaptureEvent(browserWindowIndex); -// EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); -// -// if (imageCaptureEvent.getEventProcessCount() > 0) { -// if (imageCaptureEvent.isError()) { -// errorMessage.appendWithNewLine(imageCaptureEvent.getErrorMessage()); -// } -// else { -// imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); -// if ( ! backgroundColorValid) { -// imageCaptureEvent.getBackgroundColor(backgroundColor); -// backgroundColorValid = true; -// } -// } -// } -// } -// -// /* -// * Assemble images of each window into a single image -// * and add it to the scene. Use one image per row -// * since the images are limited in horizontal space -// * when shown in the listing of scenes. -// */ -// if ( ! imageFiles.empty()) { -// try { -// const int32_t numImagesPerRow = 1; -// ImageFile compositeImageFile; -// compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, -// numImagesPerRow, -// backgroundColor); -// -// compositeImageFile.resizeToMaximumWidth(512); -// -// QByteArray byteArray; -// compositeImageFile.getImageInByteArray(byteArray, -// SceneDialog::PREFERRED_IMAGE_FORMAT); -// -// scene->getSceneInfo()->setImageBytes(byteArray, -// SceneDialog::PREFERRED_IMAGE_FORMAT); -// } -// catch (const DataFileException& dfe) { -// WuQMessageBox::errorOk(m_addNewScenePushButton, -// dfe.whatString()); -// } -// } -// -// /* -// * Free memory from the image files. -// */ -// for (std::vector::iterator iter = imageFiles.begin(); -// iter != imageFiles.end(); -// iter++) { -// delete *iter; -// } -//} - /** * Check to see if there are modified files. If there are * allow the user to continue or cancel creation of the scene. @@ -1806,10 +1699,6 @@ SceneDialog::checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, AString dialogMessage; AString modifiedFilesMessage; -// GuiManager::TestModifiedMode testMode = GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW; -// if (creatingSceneFlag) { -// testMode = GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD; -// } const bool haveModifiedFilesFlag = GuiManager::get()->testForModifiedFiles(testMode, dialogMessage, modifiedFilesMessage); @@ -2565,12 +2454,13 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, return false; } + bool debugLoggingFlag = true; std::vector allSceneObjects; - if (m_checkForUnrestoredItemsCheckBox->isChecked()) { + if (debugLoggingFlag) { allSceneObjects = scene->getDescendants(); } - SceneClass::setDebugLoggingEnabled(m_checkForUnrestoredItemsCheckBox->isChecked()); + SceneClass::setDebugLoggingEnabled(debugLoggingFlag); /* * Show the wait cursor @@ -2953,13 +2843,6 @@ SceneClassInfoWidget::updateContent(Scene* scene, else { m_previewImageLabel->setText("No preview
image"); } - -// const int32_t maxHeight = 150; -// const int32_t maxSizeHintHeight = std::max(m_leftSideWidget->sizeHint().height(), -// m_rightSideWidget->sizeHint().height()); -// const int32_t fixedHeight = std::min(maxSizeHintHeight, -// maxHeight); -// setFixedHeight(fixedHeight); } } diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index 8bd5692d1..c6ae36204 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -224,8 +224,6 @@ namespace caret { QPushButton* m_createSceneOptionsPushButton; - QCheckBox* m_checkForUnrestoredItemsCheckBox; - QScrollArea* m_sceneSelectionScrollArea; QWidget* m_sceneSelectionWidget; -- GitLab From 9b711df5cf4f193dabcb375feca11dc117439e9f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Jun 2017 11:20:50 -0500 Subject: [PATCH 304/755] Code for restoring an older format of annotations was updated to ignore the newer 'viewport' coordinate space. --- src/Brain/DisplayPropertiesAnnotation.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index 22d8debda..a1d407147 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -456,7 +456,10 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssert(0); + /* + * Ignore annotations in viewport space. These are usually text annotations + * in the graphics region such as chart labels. + */ break; case AnnotationCoordinateSpaceEnum::WINDOW: if (numWindowStatus) { -- GitLab From ae9530b984ec84275f2ce48ad976a1fc3610c9f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Jun 2017 13:09:01 -0500 Subject: [PATCH 305/755] Scene Dialog updates: When Test All Scenes is run, generate the 'after' image, even if there was an error as the image is still useful. Add the 'Replace All Scene's button to the group of 'Testing' buttons. --- src/GuiQt/SceneDialog.cxx | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index e34c04847..e86daa17e 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1130,7 +1130,7 @@ SceneDialog::replaceAllScenesPushButtonClicked() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { - WuQMessageBox::errorOk(m_testScenesPushButton, "No scene file is loaded."); + WuQMessageBox::errorOk(m_replaceAllScenesPushButton, "No scene file is loaded."); return; } @@ -1444,7 +1444,7 @@ SceneDialog::testScenesPushButtonClicked() if (origScene != NULL) { progressDialog.setValue(i+1); progressDialog.setLabelText("Testing: " + origScene->getName() - + "\n\nPressing Cancel will cease testing after the current scene is loaded."); + + "\n\nPressing the Cancel button will stop testing after the next scene finishes loading."); progressDialog.repaint(); progressDialog.show(); QApplication::processEvents(); @@ -1454,30 +1454,28 @@ SceneDialog::testScenesPushButtonClicked() } AString errorMessage; - const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, - origScene, - false, - errorMessage); - if (successFlag) { - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - - QImage image; - AString imageErrorMessage; - const bool validImage = SceneCreateReplaceDialog::createSceneImage(image, - imageErrorMessage); - if (validImage) { - newImages.push_back(image.scaledToWidth(IMAGE_DISPLAY_WIDTH)); - } - else { - newImages.push_back(QImage()); - } + displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + /* + * Always generate an image, even if the scene fails and failure may + * be a very minor error. + */ + QImage image; + AString imageErrorMessage; + const bool validImage = SceneCreateReplaceDialog::createSceneImage(image, + imageErrorMessage); + if (validImage) { + newImages.push_back(image.scaledToWidth(IMAGE_DISPLAY_WIDTH)); } else { newImages.push_back(QImage()); + errorMessage.appendWithNewLine("Generate image error: " + imageErrorMessage); } - - sceneNames.push_back(origScene->getName()); const QImage* imageFromScene = getQImageFromSceneInfo(origScene->getSceneInfo()); if (imageFromScene != NULL) { @@ -1489,7 +1487,6 @@ SceneDialog::testScenesPushButtonClicked() } sceneErrors.push_back(errorMessage); - } } @@ -1875,7 +1872,7 @@ SceneDialog::createScenesWidget() createGroupLayout->addWidget(m_addNewScenePushButton); createGroupLayout->addWidget(m_insertNewScenePushButton); createGroupLayout->addWidget(m_replaceScenePushButton); - if (m_createSceneOptionsPushButton) { + if (m_createSceneOptionsPushButton != NULL) { createGroupLayout->addWidget(m_createSceneOptionsPushButton); } @@ -1887,6 +1884,9 @@ SceneDialog::createScenesWidget() testGroupBox->setSizePolicy(testGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* testGroupLayout = new QVBoxLayout(testGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(testGroupLayout, 2, 2); + if (m_replaceAllScenesPushButton != NULL) { + testGroupLayout->addWidget(m_replaceAllScenesPushButton); + } testGroupLayout->addWidget(m_testScenesPushButton); /* -- GitLab From 257249dcd161ab9b6ff482247c52e47fbfcfae75 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Jun 2017 14:14:30 -0500 Subject: [PATCH 306/755] If compiled in DEBUG mode, log any scene members that fail to restore. These instance include a failure to restore a scene member or obsolete members. --- src/GuiQt/SceneDialog.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index e86daa17e..a9bd074fe 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2489,10 +2489,12 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, guiManagerClass); guiManagerClass->setRestored(true); +#ifndef NDEBUG if ( ! allSceneObjects.empty()) { SceneObject::logObjectsFailedRestore(scene->getName(), allSceneObjects); } +#endif // NDEBUG SceneClass::setDebugLoggingEnabled(false); -- GitLab From 90c1af9b71cbbd992ee9d85acbb3ae025f8d37e3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Jun 2017 14:23:00 -0500 Subject: [PATCH 307/755] Removed unused SceneCreateOptionsDialog as the options are on the Create New Scene dialog. --- src/GuiQt/CMakeLists.txt | 3 - src/GuiQt/SceneCreateOptionsDialog.cxx | 136 ------------------------- src/GuiQt/SceneCreateOptionsDialog.h | 94 ----------------- src/GuiQt/SceneDialog.cxx | 43 -------- src/GuiQt/SceneDialog.h | 4 - 5 files changed, 280 deletions(-) delete mode 100644 src/GuiQt/SceneCreateOptionsDialog.cxx delete mode 100644 src/GuiQt/SceneCreateOptionsDialog.h diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 7b5d4afa4..b35f91ff4 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -155,7 +155,6 @@ ELSE() ProgressReportingFromEvent.h ProgressReportingWithSlots.h RegionOfInterestCreateFromBorderDialog.h - SceneCreateOptionsDialog.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h @@ -372,7 +371,6 @@ ProgressReportingFromEvent.h ProgressReportingWithSlots.h QGLWidgetTextRenderer.h RegionOfInterestCreateFromBorderDialog.h -SceneCreateOptionsDialog.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h @@ -584,7 +582,6 @@ ProgressReportingFromEvent.cxx ProgressReportingWithSlots.cxx QGLWidgetTextRenderer.cxx RegionOfInterestCreateFromBorderDialog.cxx -SceneCreateOptionsDialog.cxx SceneCreateReplaceDialog.cxx SceneDialog.cxx ScenePreviewDialog.cxx diff --git a/src/GuiQt/SceneCreateOptionsDialog.cxx b/src/GuiQt/SceneCreateOptionsDialog.cxx deleted file mode 100644 index 7e0f07def..000000000 --- a/src/GuiQt/SceneCreateOptionsDialog.cxx +++ /dev/null @@ -1,136 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ -#include "SceneCreateOptionsDialog.h" -#undef __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ - -#include -#include -#include -#include -#include - -#include "CaretAssert.h" -#include "WuQDataEntryDialog.h" - -using namespace caret; - - - -/** - * \class caret::SceneCreateOptionsDialog - * \brief Dialog for setting create scene options - * \ingroup GuiQt - */ - -/** - * Constructor. - * - * @param options - * Options displayed in dialog. - * @param parent - * Optional parent for dialog. - */ -SceneCreateOptionsDialog::SceneCreateOptionsDialog(const Options& options, - QWidget* parent) -: WuQDialogModal("Create Scene Options", - parent) -{ - CaretAssertMessage(0, "This dialog was copied from the show scene options and needs to be implemented with the show scene options"); - - /* - * Use colors contained in the scene for background and foreground - */ - const QString colorTip("Override foreground/background colors from preferences with those in scene"); - - m_useSceneColorsCheckBox = new QCheckBox("Use background and foreground colors from scene"); - m_useSceneColorsCheckBox->setToolTip(colorTip); - m_useSceneColorsCheckBox->setChecked(options.isUseSceneColorsSelected()); - - m_useSceneColorsToolButton = new QToolButton(); - m_useSceneColorsToolButton->setText("Info..."); - QObject::connect(m_useSceneColorsToolButton, &QToolButton::clicked, - this, &SceneCreateOptionsDialog::useSceneColorsInfoButtonClicked); - - QHBoxLayout* useSceneColorsLayout = new QHBoxLayout(); - useSceneColorsLayout->addWidget(m_useSceneColorsCheckBox); - useSceneColorsLayout->addWidget(m_useSceneColorsToolButton); - useSceneColorsLayout->addStretch(); - - QWidget* dialogWidget = new QWidget; - QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); - dialogLayout->addLayout(useSceneColorsLayout); - - - dialogWidget->setSizePolicy(QSizePolicy::Fixed, - QSizePolicy::Fixed); - setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); -} - -/** - * Destructor. - */ -SceneCreateOptionsDialog::~SceneCreateOptionsDialog() -{ -} - -/** - * @return Status of options in dialog. - */ -SceneCreateOptionsDialog::Options -SceneCreateOptionsDialog::getOptions() const -{ - return Options(m_useSceneColorsCheckBox->isChecked()); -} - -void -SceneCreateOptionsDialog::useSceneColorsInfoButtonClicked() -{ - const QString infoText("Scenes created after 01 May 2016 contain the background and foreground from when the\n" - "scene was created. If this box is checked, background and foreground colors from the\n" - "scene will override the foreground and background colors in the Preferences Dialog.\n" - "The background and foreground colors will revert to those on the Preferences Dialog\n" - "when any of these events occur:\n" - " * This checkbox is unchecked\n" - " * A scene without background and foreground colors is loaded\n" - " * A Spec File and its data files are loaded\n" - " * File Menu->Close All Files is selected\n" - " * Any of the colors on the Preferences Dialog are changed\n" - " * The user quits wb_view"); - - WuQDataEntryDialog ded("Scene Colors Info", - m_useSceneColorsToolButton); - ded.hideCancelButton(); - QLabel* label = new QLabel(infoText); - ded.addWidget(label); - ded.exec(); -} - -/** - * Gets called if the user presses the OK button. - */ -void -SceneCreateOptionsDialog::okButtonClicked() -{ - WuQDialogModal::okButtonClicked(); -} - diff --git a/src/GuiQt/SceneCreateOptionsDialog.h b/src/GuiQt/SceneCreateOptionsDialog.h deleted file mode 100644 index 680420073..000000000 --- a/src/GuiQt/SceneCreateOptionsDialog.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef __SCENE_CREATE_OPTIONS_DIALOG_H__ -#define __SCENE_CREATE_OPTIONS_DIALOG_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "WuQDialogModal.h" - -class QCheckBox; -class QToolButton; - -namespace caret { - - class SceneCreateOptionsDialog : public WuQDialogModal { - - Q_OBJECT - - public: - /** - * Options for display in dialog - */ - class Options { - public: - /** - * Constructor - * - * @param useSceneColorsSelected - * Status of use scene colors - */ - Options(const bool useSceneColorsSelected) - : m_useSceneColorsSelected(useSceneColorsSelected) { } - - /** @return Status of use scene colors */ - bool isUseSceneColorsSelected() const { return m_useSceneColorsSelected; } - - private: - bool m_useSceneColorsSelected = false; - }; - - - SceneCreateOptionsDialog(const Options& options, - QWidget* parent = 0); - - virtual ~SceneCreateOptionsDialog(); - - Options getOptions() const; - - // ADD_NEW_METHODS_HERE - - protected: - virtual void okButtonClicked(); - - void useSceneColorsInfoButtonClicked(); - - private: - SceneCreateOptionsDialog(const SceneCreateOptionsDialog&); - - SceneCreateOptionsDialog& operator=(const SceneCreateOptionsDialog&); - - QCheckBox* m_useSceneColorsCheckBox; - - QToolButton* m_useSceneColorsToolButton; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ - // -#endif // __SCENE_CREATE_OPTIONS_DIALOG_DECLARE__ - -} // namespace -#endif //__SCENE_CREATE_OPTIONS_DIALOG_H__ diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index a9bd074fe..411a282af 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -72,7 +72,6 @@ #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" -#include "SceneCreateOptionsDialog.h" #include "SceneCreateReplaceDialog.h" #include "SceneFile.h" #include "SceneInfo.h" @@ -1834,21 +1833,6 @@ SceneDialog::createScenesWidget() QObject::connect(m_showSceneOptionsPushButton, &QPushButton::clicked, this, &SceneDialog::showSceneOptionsButtonClicked); - /* - * Create scene options button - */ - m_createSceneOptionsPushButton = NULL; - bool haveCreateOptionsFlag = false; - if (haveCreateOptionsFlag) { - m_createSceneOptionsPushButton = new QPushButton("Options..."); - m_createSceneOptionsPushButton->setToolTip("Display a dialog for create scene options"); - QObject::connect(m_createSceneOptionsPushButton, &QPushButton::clicked, - this, &SceneDialog::createSceneOptionsButtonClicked); - } - - /* - * Margins/spacing for button groups - */ /* * Group for show buttons */ @@ -1872,9 +1856,6 @@ SceneDialog::createScenesWidget() createGroupLayout->addWidget(m_addNewScenePushButton); createGroupLayout->addWidget(m_insertNewScenePushButton); createGroupLayout->addWidget(m_replaceScenePushButton); - if (m_createSceneOptionsPushButton != NULL) { - createGroupLayout->addWidget(m_createSceneOptionsPushButton); - } /* * Group for test buttons @@ -2242,30 +2223,6 @@ SceneDialog::showSceneOptionsButtonClicked() } } -/** - * Display the scene show options dialog - */ -void -SceneDialog::createSceneOptionsButtonClicked() -{ - Scene* scene = getSelectedScene(); - if (scene != NULL) { - SceneCreateOptionsDialog::Options options(s_useSceneForegroundBackgroundColorsFlag); - SceneCreateOptionsDialog optionsDialog(options, - m_createSceneOptionsPushButton); - if (optionsDialog.exec() == QDialog::Accepted) { - const SceneCreateOptionsDialog::Options optionsResult = optionsDialog.getOptions(); - s_useSceneForegroundBackgroundColorsFlag = optionsResult.isUseSceneColorsSelected(); - - if ( ! optionsResult.isUseSceneColorsSelected()) { - CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } - } - } -} - /** * Called when show image preview button is clicked. */ diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index c6ae36204..cbfebd899 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -104,8 +104,6 @@ namespace caret { void showImagePreviewButtonClicked(); - void createSceneOptionsButtonClicked(); - void showSceneOptionsButtonClicked(); void validateContentOfCreateSceneDialog(WuQDataEntryDialog*); @@ -222,8 +220,6 @@ namespace caret { QPushButton* m_showSceneOptionsPushButton; - QPushButton* m_createSceneOptionsPushButton; - QScrollArea* m_sceneSelectionScrollArea; QWidget* m_sceneSelectionWidget; -- GitLab From de6d24552b00596e7e7952e7ea61c5839d8c98fa Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Jun 2017 11:05:11 -0500 Subject: [PATCH 308/755] Moved chart axis titles from ChartOverlaySet to each chartable file. For display of chart axis titles, added selection of chart layer for source of title to chart axes toolbar. Also fixed crash in line chart history dialog when history was cleared and new data was loaded. --- src/Annotations/AnnotationText.cxx | 25 + src/Annotations/CMakeLists.txt | 2 + .../EventAnnotationChartLabelGet.cxx | 0 .../EventAnnotationChartLabelGet.h | 0 ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 707 +++--------------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 7 +- src/Brain/CMakeLists.txt | 2 - src/Brain/ChartTwoOverlay.cxx | 18 + src/Brain/ChartTwoOverlay.h | 4 +- src/Brain/ChartTwoOverlaySet.cxx | 121 ++- src/Brain/ChartTwoOverlaySet.h | 10 +- src/Charting/ChartTwoCartesianAxis.cxx | 112 +-- src/Charting/ChartTwoCartesianAxis.h | 8 +- src/Files/CaretMappableDataFile.cxx | 5 + src/Files/ChartableTwoFileBaseChart.cxx | 173 ++++- src/Files/ChartableTwoFileBaseChart.h | 17 + src/Files/ChartableTwoFileLineSeriesChart.cxx | 3 + src/Files/CiftiScalarDataSeriesFile.cxx | 6 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 384 ++++++---- .../BrainBrowserWindowToolBarChartTwoAxes.h | 16 +- src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 8 +- 21 files changed, 762 insertions(+), 866 deletions(-) rename src/{Brain => Annotations}/EventAnnotationChartLabelGet.cxx (100%) rename src/{Brain => Annotations}/EventAnnotationChartLabelGet.h (100%) diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index d0d56c2ce..9bd6b867e 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -174,6 +174,31 @@ AnnotationText::initializeAnnotationTextMembers() m_text = ""; m_sceneAssistant.grabNew(new SceneClassAssistant()); + m_sceneAssistant->add("m_alignmentHorizontal", + &m_alignmentHorizontal); + m_sceneAssistant->add("m_alignmentVertical", + &m_alignmentVertical); + m_sceneAssistant->add("m_font", + &m_font); + m_sceneAssistant->add("m_fontPointSize", + &m_fontPointSize); + m_sceneAssistant->add("m_orientation", + &m_orientation); + m_sceneAssistant->add("m_colorText", + &m_colorText); + m_sceneAssistant->addArray("m_customColorText", m_customColorText, 4, 1.0); + m_sceneAssistant->add("m_boldEnabled", + &m_boldEnabled); + m_sceneAssistant->add("m_italicEnabled", + &m_italicEnabled); + m_sceneAssistant->add("m_underlineEnabled", + &m_underlineEnabled); + m_sceneAssistant->add("m_connectToBrainordinate", + &m_connectToBrainordinate); + m_sceneAssistant->add("m_fontPercentViewportSize", + &m_fontPercentViewportSize); + m_sceneAssistant->add("m_text", + &m_text); } /** diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 324754d60..b2cbdc0c6 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -62,6 +62,7 @@ AnnotationTextOrientationEnum.h AnnotationTwoDimensionalShape.h AnnotationTypeEnum.h EventAnnotationAddToRemoveFromFile.h +EventAnnotationChartLabelGet.h EventAnnotationGroupGetWithKey.h EventAnnotationGrouping.h @@ -103,6 +104,7 @@ AnnotationTextOrientationEnum.cxx AnnotationTwoDimensionalShape.cxx AnnotationTypeEnum.cxx EventAnnotationAddToRemoveFromFile.cxx +EventAnnotationChartLabelGet.cxx EventAnnotationGroupGetWithKey.cxx EventAnnotationGrouping.cxx ) diff --git a/src/Brain/EventAnnotationChartLabelGet.cxx b/src/Annotations/EventAnnotationChartLabelGet.cxx similarity index 100% rename from src/Brain/EventAnnotationChartLabelGet.cxx rename to src/Annotations/EventAnnotationChartLabelGet.cxx diff --git a/src/Brain/EventAnnotationChartLabelGet.h b/src/Annotations/EventAnnotationChartLabelGet.h similarity index 100% rename from src/Brain/EventAnnotationChartLabelGet.h rename to src/Annotations/EventAnnotationChartLabelGet.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index d73e41612..ccc79c601 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -278,352 +278,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, viewportSpaceAnnotationsOut = m_viewportSpaceAnnotationsOut; } -///** -// * Draw histogram charts. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramChart() -//{ -// const int32_t vpX = m_viewport[0]; -// const int32_t vpY = m_viewport[1]; -// const int32_t vpWidth = m_viewport[2]; -// const int32_t vpHeight = m_viewport[3]; -// -// int32_t chartGraphicsDrawingViewport[4] = { -// vpX, -// vpY, -// vpWidth, -// vpHeight -// }; -// -// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); -// CaretAssert(numberOfOverlays > 0); -// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); -// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); -// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); -// -// std::vector> drawingInfo; -// -// /* -// * Get the histogram drawing information and overall extent -// */ -// float xMin = std::numeric_limits::max(); -// float xMax = -std::numeric_limits::max(); -// float yMinLeft = std::numeric_limits::max(); -// float yMaxLeft = -std::numeric_limits::max(); -// float yMinRight = std::numeric_limits::max(); -// float yMaxRight = -std::numeric_limits::max(); -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; -// int32_t selectedIndex = -1; -// chartOverlay->getSelectionData(mapFile, -// selectedIndexType, -// selectedIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// -// if (histogramChart->isValid()) { -// CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); -// AString errorMessage; -// drawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, -// selectedIndex, -// chartOverlay->getCartesianVerticalAxisLocation(), -// (chartOverlay->isAllMapsSupported() -// && chartOverlay->isAllMapsSelected())))); -// const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, -// (chartOverlay->isAllMapsSupported() -// && chartOverlay->isAllMapsSelected())); -// CaretAssert(histogram); -// float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; -// histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); -// if (histogramMaxX > histogramMinX) { -// xMin = std::min(xMin, histogramMinX); -// xMax = std::max(xMax, histogramMaxX); -// -// switch (chartOverlay->getCartesianVerticalAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// yMinRight = std::min(yMinRight, 0.0f); -// yMaxRight = std::max(yMaxRight, histogramMaxY); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// yMinLeft = std::min(yMinLeft, 0.0f); -// yMaxLeft = std::max(yMaxLeft, histogramMaxY); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); -// break; -// } -// } -// } -// } -// -// /* -// * Bounds valid? -// */ -// if ((xMin < xMax) -// && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { -// /* -// * Margin is region around the chart in which -// * the axes legends, values, and ticks are drawn. -// */ -// const double marginSize = 10; -// Margins margins(marginSize); -// -// ChartTwoCartesianAxis* leftAxis = NULL; -// ChartTwoCartesianAxis* rightAxis = NULL; -// ChartTwoCartesianAxis* bottomAxis = NULL; -// ChartTwoCartesianAxis* topAxis = NULL; -// -// std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); -// for (auto axis : displayedAxes) { -// CaretAssert(axis); -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// bottomAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// leftAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// rightAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// topAxis = axis; -// break; -// } -// } -// -// const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; -// const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; -// double width = 0.0, height = 0.0; -// -// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); -// margins.m_left = std::max(margins.m_left, width); -// estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); -// margins.m_right = std::max(margins.m_right, width); -// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); -// margins.m_top = std::max(margins.m_top, height); -// estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); -// margins.m_bottom = std::max(margins.m_bottom, height); -// -// if (margins.m_left > marginSize) margins.m_left += 10; -// if (margins.m_right > marginSize) margins.m_right += 10; -// -// /* -// * Ensure that there is sufficient space for the axes data display. -// */ -// if ((vpWidth > (marginSize * 3)) -// && (vpHeight > (marginSize * 3))) { -// -// float axisMinimumValue = 0.0; -// float axisMaximumValue = 0.0; -// -// /* Draw legends and grids */ -// if (drawChartAxisCartesian(boundsLeftBottomTop, -// vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// leftAxis, -// axisMinimumValue, -// axisMaximumValue)) { -// yMinLeft = axisMinimumValue; -// yMaxLeft = axisMaximumValue; -// } -// -// if (drawChartAxisCartesian(boundsRight, -// vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// rightAxis, -// axisMinimumValue, -// axisMaximumValue)) { -// yMinRight = axisMinimumValue; -// yMaxRight = axisMaximumValue; -// } -// if (drawChartAxisCartesian(boundsLeftBottomTop, -// vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// bottomAxis, -// axisMinimumValue, -// axisMaximumValue)) { -// xMin = axisMinimumValue; -// xMax = axisMaximumValue; -// } -// -// drawChartAxisCartesian(boundsLeftBottomTop, -// vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// topAxis, -// axisMinimumValue, -// axisMaximumValue); -// -// drawChartGraphicsBoxAndSetViewport(vpX, -// vpY, -// vpWidth, -// vpHeight, -// margins, -// chartGraphicsDrawingViewport); -// } -// -// glViewport(chartGraphicsDrawingViewport[0], -// chartGraphicsDrawingViewport[1], -// chartGraphicsDrawingViewport[2], -// chartGraphicsDrawingViewport[3]); -// -// -// /* -// * Draw the bars for all histogram and then draw the envelopes -// * so the envelopes are not obscured by the bars -// */ -// for (auto& drawInfo : drawingInfo) { -// if (drawInfo->m_histogramChart->isValid()) { -// const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); -// CaretAssert(cmdf); -// const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); -// const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); -// const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); -// -// if (drawBarsFlag -// || drawEnvelopeFlag) { -// bool leftVerticalAxisFlag = true; -// switch (drawInfo->m_verticalAxisLocation) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// leftVerticalAxisFlag = false; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// break; -// } -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// if (leftVerticalAxisFlag) { -// glOrtho(xMin, xMax, -// yMinLeft, yMaxLeft, -// -10.0, 10.0); -// } -// else { -// glOrtho(xMin, xMax, -// yMinRight, yMaxRight, -// -10.0, 10.0); -// } -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool applyTransformationsFlag = false; -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = chartGraphicsDrawingViewport[2]; -// const float chartHeight = chartGraphicsDrawingViewport[3]; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = -// drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, -// drawInfo->m_allMapsSelected); -// if (histogramPrimitives != NULL) { -// const float ENVELOPE_LINE_WIDTH = 1.0; -// -// if (m_identificationModeFlag) { -// int32_t primitiveIndex = -1; -// float primitiveDepth = 0.0; -// -// if (drawBarsFlag) { -// /* -// * Scale histogram bars in Y-axis so that identification -// * will function when mouse is above a bar. This is helpful -// * for identification of bars with a very small height. -// */ -// glPushMatrix(); -// glScalef(1.0, 1000.0, 1.0); -// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// histogramPrimitives->getBarsPrimitive(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// primitiveIndex, -// primitiveDepth); -// glPopMatrix(); -// } -// else if (drawEnvelopeFlag) { -// /* -// * Increase line width for identification -// */ -// glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); -// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// histogramPrimitives->getEnvelopePrimitive(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// primitiveIndex, -// primitiveDepth); -// } -// -// if (primitiveIndex >= 0) { -// if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { -// m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), -// drawInfo->m_mapIndex, -// primitiveIndex, -// drawInfo->m_allMapsSelected); -// } -// } -// } -// else { -// drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); -// if (drawBarsFlag) { -// drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); -// } -// if (drawEnvelopeFlag) { -// glLineWidth(ENVELOPE_LINE_WIDTH); -// m_fixedPipelineDrawing->enableLineAntiAliasing(); -// drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); -// m_fixedPipelineDrawing->disableLineAntiAliasing(); -// } -// } -// } -// } -// } -// } -// } -//} /** * Draw a histogram or line series chart. @@ -754,7 +408,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); const int32_t numHistory = lineSeriesHistory->getHistoryCount(); - for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { + for (int32_t iHistory = (numHistory - 1); iHistory >= 0; iHistory--) { + //for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); CaretAssert(data); if (data->isSelected()) { @@ -780,7 +435,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch break; } - lineSeriesChartsToDraw.push_front(LineSeriesChartDrawingInfo(lineSeriesChart, + lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, data, chartOverlay->getCartesianVerticalAxisLocation())); } @@ -806,7 +461,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch ChartTwoCartesianAxis* bottomAxis = NULL; ChartTwoCartesianAxis* topAxis = NULL; - std::vector displayedAxes = m_chartOverlaySet->getDisplayedChartAxes(); + std::vector displayedAxes; + AnnotationPercentSizeText* leftAxisLabel = NULL; + AnnotationPercentSizeText* rightAxisLabel = NULL; + AnnotationPercentSizeText* bottomAxisLabel = NULL; + m_chartOverlaySet->getDisplayedChartAxes(displayedAxes, + leftAxisLabel, + rightAxisLabel, + bottomAxisLabel); for (auto axis : displayedAxes) { CaretAssert(axis); switch (axis->getAxisLocation()) { @@ -829,13 +491,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, leftAxisLabel, width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, rightAxisLabel, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, NULL, width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, bottomAxisLabel, width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; @@ -858,6 +520,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch vpHeight, margins, leftAxis, + leftAxisLabel, axisMinimumValue, axisMaximumValue)) { yMinLeft = axisMinimumValue; @@ -871,6 +534,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch vpHeight, margins, rightAxis, + rightAxisLabel, axisMinimumValue, axisMaximumValue)) { yMinRight = axisMinimumValue; @@ -883,6 +547,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch vpHeight, margins, bottomAxis, + bottomAxisLabel, axisMinimumValue, axisMaximumValue)) { xMin = axisMinimumValue; @@ -896,6 +561,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch vpHeight, margins, topAxis, + NULL, axisMinimumValue, axisMaximumValue); @@ -1487,117 +1153,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() } -/** - * Process identification for line-series. - * - * @param lineSeriesChart - * The line-series chart. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart) -{ - // int32_t identifiedItemIndex; - // float depth = -1.0; - // - // if (m_chartModelDataSeriesBeingDrawnForIdentification != NULL) { - // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, - // m_fixedPipelineDrawing->mouseX, - // m_fixedPipelineDrawing->mouseY, - // identifiedItemIndex, - // depth); - // if (identifiedItemIndex >= 0) { - // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; - // const int32_t chartDataIndex = m_identificationIndices[idIndex]; - // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; - // - // SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); - // if (chartDataSeriesID->isOtherScreenDepthCloserToViewer(depth)) { - // ChartDataCartesian* chartDataCartesian = - // dynamic_cast(m_chartModelDataSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); - // CaretAssert(chartDataCartesian); - // chartDataSeriesID->setChart(m_chartModelDataSeriesBeingDrawnForIdentification, - // chartDataCartesian, - // chartLineIndex); - // - // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); - // const float lineXYZ[3] = { - // chartPoint->getX(), - // chartPoint->getY(), - // 0.0 - // }; - // - // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartDataSeriesID, - // lineXYZ); - // } - // } - // } - // else if (m_chartModelFrequencySeriesBeingDrawnForIdentification != NULL) { - // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, - // m_fixedPipelineDrawing->mouseX, - // m_fixedPipelineDrawing->mouseY, - // identifiedItemIndex, - // depth); - // if (identifiedItemIndex >= 0) { - // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; - // const int32_t chartDataIndex = m_identificationIndices[idIndex]; - // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; - // - // SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); - // if (chartFrequencySeriesID->isOtherScreenDepthCloserToViewer(depth)) { - // ChartDataCartesian* chartDataCartesian = - // dynamic_cast(m_chartModelFrequencySeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); - // CaretAssert(chartDataCartesian); - // chartFrequencySeriesID->setChart(m_chartModelFrequencySeriesBeingDrawnForIdentification, - // chartDataCartesian, - // chartLineIndex); - // - // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); - // const float lineXYZ[3] = { - // chartPoint->getX(), - // chartPoint->getY(), - // 0.0 - // }; - // - // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartFrequencySeriesID, - // lineXYZ); - // } - // } - // } - // else if (m_chartModelTimeSeriesBeingDrawnForIdentification != NULL) { - // m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, - // m_fixedPipelineDrawing->mouseX, - // m_fixedPipelineDrawing->mouseY, - // identifiedItemIndex, - // depth); - // if (identifiedItemIndex >= 0) { - // const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; - // const int32_t chartDataIndex = m_identificationIndices[idIndex]; - // const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; - // - // SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); - // if (chartTimeSeriesID->isOtherScreenDepthCloserToViewer(depth)) { - // ChartDataCartesian* chartDataCartesian = - // dynamic_cast(m_chartModelTimeSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); - // CaretAssert(chartDataCartesian); - // chartTimeSeriesID->setChart(m_chartModelTimeSeriesBeingDrawnForIdentification, - // chartDataCartesian, - // chartLineIndex); - // - // const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); - // const float lineXYZ[3] = { - // chartPoint->getX(), - // chartPoint->getY(), - // 0.0 - // }; - // - // m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartTimeSeriesID, - // lineXYZ); - // } - // } - // } - -} - /** * Estimate the size of the axis' text. * @@ -1609,6 +1164,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::processLineSeriesIdentification(const C * Height of viewport. * @param cartesianAxis * The axis. + * @param chartAxisLabel + * Label for the axis. * @param widthOut * Width of text out. * @param heightOut @@ -1619,6 +1176,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, + const AnnotationPercentSizeText* chartAxisLabel, double& widthOut, double& heightOut) { @@ -1682,51 +1240,53 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - const AnnotationPercentSizeText* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); - const AString axisTitle = chartAxisLabel->getText(); - if ( ! axisTitle.isEmpty()) { - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setText(axisTitle); - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - break; - } - - double textWidth = 0.0; - double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); - - /* - * Note: Text on left and right is rotated but we need the width - * and height after rotation so swap the width and height of the text - */ - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += textHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - std::swap(textWidth, textHeight); - widthOut += textWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - std::swap(textWidth, textHeight); - widthOut += textWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += textHeight; - break; + //const AnnotationPercentSizeText* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); + if (chartAxisLabel != NULL) { + const AString axisTitle = chartAxisLabel->getText(); + if ( ! axisTitle.isEmpty()) { + AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + annotationText.setText(axisTitle); + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + annotationText.setRotationAngle(-90.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + annotationText.setRotationAngle(-90.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); + break; + } + + double textWidth = 0.0; + double textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); + + /* + * Note: Text on left and right is rotated but we need the width + * and height after rotation so swap the width and height of the text + */ + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + heightOut += textHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + std::swap(textWidth, textHeight); + widthOut += textWidth; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + std::swap(textWidth, textHeight); + widthOut += textWidth; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + heightOut += textHeight; + break; + } } } } @@ -1825,6 +1385,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons * (and not cut off). * @param axis * Axis that is drawn. + * @param chartAxisLabel + * Axis label. * @param axisMinimumOut * Minimum value along the axis. * @param axisMaximumOut @@ -1840,6 +1402,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data const float vpHeight, const Margins& margins, ChartTwoCartesianAxis* axis, + AnnotationPercentSizeText* chartAxisLabel, float& axisMinimumOut, float& axisMaximumOut) { @@ -2095,86 +1658,56 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data drawPrimitivePrivate(ticksData.get()); } - const AString axisTitle = axis->getAnnotationAxisLabel()->getText(); - if ( ! axisTitle.isEmpty()) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - - bool drawAxisTextVerticalFlag = false; - float axisTextCenterX = axisVpWidth / 2.0; - float axisTextCenterY = axisVpHeight / 2.0; - const float textMarginOffset = 5.0; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisTextCenterX = (axisVpWidth / 2.0); - axisTextCenterY = textMarginOffset; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisTextCenterX = (axisVpWidth / 2.0); - axisTextCenterY = axisVpHeight - textMarginOffset; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisTextCenterX = textMarginOffset; - axisTextCenterY = (axisVpHeight / 2.0); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - drawAxisTextVerticalFlag = true; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisTextCenterX = axisVpWidth - textMarginOffset; - axisTextCenterY = (axisVpHeight / 2.0); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - drawAxisTextVerticalFlag = true; - break; - } - - if ((axisVpWidth > 0.0) - && (axisVpHeight > 0.0)) { -// const float labelPercentX = 100.0f * (axisTextCenterX / axisVpWidth); -// const float labelPercentY = 100.0f * (axisTextCenterY / axisVpHeight); - AnnotationPercentSizeText* chartLabel = axis->getAnnotationAxisLabel(); - chartLabel->setCustomTextColor(rgba); - chartLabel->setTextColor(CaretColorEnum::CUSTOM); - chartLabel->setTabIndex(m_tabIndex); - chartLabel->setViewportCoordinateSpaceViewport(axisViewport); -// chartLabel->setAxisViewport(axisViewport); - chartLabel->getCoordinate()->setXYZ(axisTextCenterX, - axisTextCenterY, - 0.0f); -// chartLabel->getCoordinate()->setXYZ(labelPercentX, -// labelPercentY, -// 0.0f); + if (chartAxisLabel != NULL) { + const AString axisTitle = chartAxisLabel->getText(); + if ( ! axisTitle.isEmpty()) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + + bool drawAxisTextVerticalFlag = false; + float axisTextCenterX = axisVpWidth / 2.0; + float axisTextCenterY = axisVpHeight / 2.0; + const float textMarginOffset = 5.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + axisTextCenterX = (axisVpWidth / 2.0); + axisTextCenterY = textMarginOffset; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + axisTextCenterX = (axisVpWidth / 2.0); + axisTextCenterY = axisVpHeight - textMarginOffset; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + axisTextCenterX = textMarginOffset; + axisTextCenterY = (axisVpHeight / 2.0); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + drawAxisTextVerticalFlag = true; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + axisTextCenterX = axisVpWidth - textMarginOffset; + axisTextCenterY = (axisVpHeight / 2.0); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + drawAxisTextVerticalFlag = true; + break; + } + + if ((axisVpWidth > 0.0) + && (axisVpHeight > 0.0)) { + //AnnotationPercentSizeText* chartLabel = axis->getAnnotationAxisLabel(); + chartAxisLabel->setCustomTextColor(rgba); + chartAxisLabel->setTextColor(CaretColorEnum::CUSTOM); + chartAxisLabel->setTabIndex(m_tabIndex); + chartAxisLabel->setViewportCoordinateSpaceViewport(axisViewport); + chartAxisLabel->getCoordinate()->setXYZ(axisTextCenterX, + axisTextCenterY, + 0.0f); + + m_viewportSpaceAnnotationsOut.push_back(chartAxisLabel); + } - m_viewportSpaceAnnotationsOut.push_back(chartLabel); } - -// /* -// * REMOVE THIS WHEN AXIS LABELS ARE DRAWN BY ANNOTATION CODE -// */ -// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, -// axisTextCenterY, -// 0.0, -// *axis->getAnnotationAxisLabel()); - - -// if (drawAxisTextVerticalFlag) { -// annotationText.setRotationAngle(-90.0); -// annotationText.setText(axisTitle); -// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, -// axisTextCenterY, -// 0.0, -// annotationText); -// annotationText.setRotationAngle(0.0); -// } -// else { -// annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); -// annotationText.setText(axisTitle); -// m_textRenderer->drawTextAtViewportCoords(axisTextCenterX, -// axisTextCenterY, -// 0.0, -// annotationText); -// } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 2d494cc5f..316a2580b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -31,6 +31,7 @@ namespace caret { class Annotation; + class AnnotationPercentSizeText; class BrowserTabContent; class CaretPreferences; class ChartTwoCartesianAxis; @@ -123,8 +124,6 @@ namespace caret { void saveStateOfOpenGL(); - void processLineSeriesIdentification(const ChartableTwoFileLineSeriesChart* lineSeriesChart); - void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, @@ -133,8 +132,6 @@ namespace caret { const float cellHeight, const float zooming); - //void drawHistogramChart(); - void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); void drawChartGraphicsBoxAndSetViewport(const float vpX, @@ -151,6 +148,7 @@ namespace caret { const float vpHeight, const Margins& margins, ChartTwoCartesianAxis* axis, + AnnotationPercentSizeText* chartAxisLabel, float& axisMinimumOut, float& axisMaximumOut); @@ -158,6 +156,7 @@ namespace caret { const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, + const AnnotationPercentSizeText* chartAxisLabel, double& widthOut, double& heightOut); diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 44b816401..fd4e1447a 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -99,7 +99,6 @@ DisplayPropertyDataBoolean.h DisplayPropertyDataEnum.h DisplayPropertyDataFloat.h DummyFontTextRenderer.h -EventAnnotationChartLabelGet.h EventAnnotationColorBarGet.h EventBrainReset.h EventBrainStructureGetAll.h @@ -245,7 +244,6 @@ DisplayPropertiesVolume.cxx DisplayPropertyDataBoolean.cxx DisplayPropertyDataFloat.cxx DummyFontTextRenderer.cxx -EventAnnotationChartLabelGet.cxx EventAnnotationColorBarGet.cxx EventBrainReset.cxx EventBrainStructureGetAll.cxx diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index ac8b84d25..f19a26e13 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -505,6 +505,24 @@ ChartTwoOverlay::getColorBar() const return m_colorBar.get(); } +/** + * @return The selected map file (NULL if not map file available) + */ +CaretMappableDataFile* +ChartTwoOverlay::getSelectedMapFile() const +{ + std::vector mapFiles; + CaretMappableDataFile* selectedMapFile = NULL; + SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + getSelectionData(mapFiles, + selectedMapFile, + selectedIndexType, + selectedIndex); + + return selectedMapFile; +} + /** * Return the selection information. This method is typically * called to update the user-interface. diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index e411e2c80..6eba54f0e 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -66,8 +66,6 @@ namespace caret { int32_t getTabIndex() const; - //AString getName() const; - virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; @@ -108,6 +106,8 @@ namespace caret { bool isCartesianVerticalAxisLocationSupported() const; + CaretMappableDataFile* getSelectedMapFile() const; + void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 2944fbb77..92ebfdaed 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -29,7 +29,9 @@ #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" -#include "EventAnnotationChartLabelGet.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" #include "EventBrowserTabGet.h" #include "EventChartTwoAttributesChanged.h" #include "EventManager.h" @@ -85,7 +87,6 @@ m_tabIndex(tabIndex) case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { m_chartAxisLeft->setEnabledByChart(true); - m_chartAxisLeft->getAnnotationAxisLabel()->setText("Counts"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); float rangeMin = 0.0, rangeMax = 0.0; m_chartAxisLeft->getRange(rangeMin, rangeMax); @@ -93,21 +94,18 @@ m_tabIndex(tabIndex) m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); - m_chartAxisRight->getAnnotationAxisLabel()->setText("Counts"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); - m_chartAxisBottom->getAnnotationAxisLabel()->setText("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { m_chartAxisLeft->setEnabledByChart(true); - m_chartAxisLeft->getAnnotationAxisLabel()->setText("Value"); m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); float rangeMin = 0.0, rangeMax = 0.0; m_chartAxisLeft->getRange(rangeMin, rangeMax); @@ -115,14 +113,12 @@ m_tabIndex(tabIndex) m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); - m_chartAxisRight->getAnnotationAxisLabel()->setText("Value"); m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); - m_chartAxisBottom->getAnnotationAxisLabel()->setText("Data"); m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } break; @@ -153,7 +149,6 @@ m_tabIndex(tabIndex) } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } @@ -527,19 +522,7 @@ ChartTwoOverlaySet::toString() const void ChartTwoOverlaySet::receiveEvent(Event* event) { - if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { - /* - * The events intended for overlays are received here so that - * only DISPLAYED overlays are updated. - */ - EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); - CaretAssert(chartLabelEvent); - - chartLabelEvent->addAnnotationChartLabel(m_chartAxisBottom->getAnnotationAxisLabel()); - chartLabelEvent->addAnnotationChartLabel(m_chartAxisLeft->getAnnotationAxisLabel()); - chartLabelEvent->addAnnotationChartLabel(m_chartAxisRight->getAnnotationAxisLabel()); - } - else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { + if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { EventChartTwoAttributesChanged* attributeEvent = dynamic_cast(event); CaretAssert(attributeEvent); @@ -675,11 +658,26 @@ ChartTwoOverlaySet::receiveEvent(Event* event) /** * Get the displayed chart axes. + * + * @param axesOut + * Output containing the displayed axes. + * @param leftAxisLabelOut + * Label for left axis (may be NULL if axis not displayed). + * @param rightAxisLabelOut + * Label for right axis (may be NULL if axis not displayed). + * @param bottomAxisLabelOut + * Label for bottom axis (may be NULL if axis not displayed). */ -std::vector -ChartTwoOverlaySet::getDisplayedChartAxes() const +void +ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut, + AnnotationPercentSizeText* &leftAxisLabelOut, + AnnotationPercentSizeText* &rightAxisLabelOut, + AnnotationPercentSizeText* &bottomAxisLabelOut) const { - std::vector axes; + axesOut.clear(); + leftAxisLabelOut = NULL; + rightAxisLabelOut = NULL; + bottomAxisLabelOut = NULL; AString lineSeriesDataTypeName; @@ -768,21 +766,80 @@ ChartTwoOverlaySet::getDisplayedChartAxes() const m_chartAxisRight->setEnabledByChart(showRightFlag); if (m_chartAxisBottom->isEnabledByChart()) { - if ( ! lineSeriesDataTypeName.isEmpty()) { - m_chartAxisBottom->getAnnotationAxisLabel()->setText(lineSeriesDataTypeName); - } - axes.push_back(m_chartAxisBottom.get()); + axesOut.push_back(m_chartAxisBottom.get()); + + bottomAxisLabelOut = getAxisLabel(m_chartAxisBottom.get()); } if (m_chartAxisLeft->isEnabledByChart()) { - axes.push_back(m_chartAxisLeft.get()); + axesOut.push_back(m_chartAxisLeft.get()); + + leftAxisLabelOut = getAxisLabel(m_chartAxisLeft.get()); } if (m_chartAxisRight->isEnabledByChart()) { - axes.push_back(m_chartAxisRight.get()); + axesOut.push_back(m_chartAxisRight.get()); + + rightAxisLabelOut = getAxisLabel(m_chartAxisRight.get()); } - - return axes; } +/** + * Get the annotation for the axis label. + * + * @param axis + * The cartesian axis. + * @return + * Pointer to annotation containing label or NULL if invalid. + */ +AnnotationPercentSizeText* +ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const +{ + AnnotationPercentSizeText* label = NULL; + + const int32_t overlayTitleIndex = axis->getTitleOverlayIndex(m_numberOfDisplayedOverlays); + const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); + CaretMappableDataFile* mapFile = chartOverlay->getSelectedMapFile(); + if (mapFile != NULL) { + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + label = mapFile->getChartingDelegate()->getHistogramCharting()->getBottomAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + label = mapFile->getChartingDelegate()->getHistogramCharting()->getLeftRightAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + label = mapFile->getChartingDelegate()->getHistogramCharting()->getLeftRightAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getBottomAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getLeftRightAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getLeftRightAxisTitle(); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + } + return label; +} /** * Save information specific to this type of model to the scene. diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 5909f619e..02c060a3a 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -30,6 +30,7 @@ namespace caret { + class AnnotationPercentSizeText; class CaretMappableDataFile; class ChartTwoCartesianAxis; class ChartTwoOverlay; @@ -65,7 +66,12 @@ namespace caret { ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); - std::vector getDisplayedChartAxes() const; + void getDisplayedChartAxes(std::vector& axesOut, + AnnotationPercentSizeText* &leftAxisLabelOut, + AnnotationPercentSizeText* &rightAxisLabelOut, + AnnotationPercentSizeText* &bottomAxisLabelOut) const; + + AnnotationPercentSizeText* getAxisLabel(const ChartTwoCartesianAxis* axis) const; void insertOverlayAbove(const int32_t overlayIndex); @@ -119,8 +125,6 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - //ChartTwoOverlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; - std::vector> m_overlays; const ChartTwoDataTypeEnum::Enum m_chartDataType; diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 9088883b2..7bc8f84d1 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -23,7 +23,6 @@ #include "ChartTwoCartesianAxis.h" #undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ -#include "AnnotationPercentSizeText.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" @@ -53,26 +52,6 @@ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum a SceneableInterface(), m_axisLocation(axisLocation) { - AnnotationTextFontSizeTypeEnum::Enum fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT; - switch (m_axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - fontSizeType = AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - break; - } - m_annotationAxisLabel = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, - fontSizeType)); - m_annotationAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); - m_annotationAxisLabel->setTextColor(CaretColorEnum::RED); - m_annotationAxisLabel->setLineColor(CaretColorEnum::NONE); - m_annotationAxisLabel->setBackgroundColor(CaretColorEnum::NONE); - /* * Allowable range minimum and maximum * NOT SAVED TO SCENE @@ -106,36 +85,8 @@ m_axisLocation(axisLocation) &m_enabledByChart); m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); - m_sceneAssistant->add("m_annotationAxisLabel", - "AnnotationPercentSizeText", - m_annotationAxisLabel.get()); - - m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - //m_annotationAxisLabel->setBackgroundColor(CaretColorEnum::NONE); - m_annotationAxisLabel->setFontPercentViewportSize(40.0); - switch (m_axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - m_annotationAxisLabel->setRotationAngle(-90.0); - m_annotationAxisLabel->setFontPercentViewportSize(25.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - m_annotationAxisLabel->setRotationAngle(-90.0); - m_annotationAxisLabel->setFontPercentViewportSize(25.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - m_annotationAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - m_annotationAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - break; - } + m_sceneAssistant->add("m_titleOverlayIndex", + &m_titleOverlayIndex); } /** @@ -185,21 +136,21 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx { CaretAssert(m_axisLocation == obj.m_axisLocation); - *m_annotationAxisLabel = *obj.m_annotationAxisLabel; - m_displayedByUser = obj.m_displayedByUser; - m_rangeMinimumValue = obj.m_rangeMinimumValue; - m_rangeMaximumValue = obj.m_rangeMaximumValue; - m_userScaleMinimumValue = obj.m_userScaleMinimumValue; - m_userScaleMaximumValue = obj.m_userScaleMaximumValue; - m_axisLabelsStepValue = obj.m_axisLabelsStepValue; - m_userDigitsRightOfDecimal = obj.m_userDigitsRightOfDecimal; - m_scaleRangeMode = obj.m_scaleRangeMode; - m_units = obj.m_units; + m_titleOverlayIndex = obj.m_titleOverlayIndex; + m_displayedByUser = obj.m_displayedByUser; + m_rangeMinimumValue = obj.m_rangeMinimumValue; + m_rangeMaximumValue = obj.m_rangeMaximumValue; + m_userScaleMinimumValue = obj.m_userScaleMinimumValue; + m_userScaleMaximumValue = obj.m_userScaleMaximumValue; + m_axisLabelsStepValue = obj.m_axisLabelsStepValue; + m_userDigitsRightOfDecimal = obj.m_userDigitsRightOfDecimal; + m_scaleRangeMode = obj.m_scaleRangeMode; + m_units = obj.m_units; m_userNumericFormat = obj.m_userNumericFormat; - m_numericSubdivsionsMode = obj.m_numericSubdivsionsMode; + m_numericSubdivsionsMode = obj.m_numericSubdivsionsMode; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; - m_enabledByChart = obj.m_enabledByChart; - m_showTickmarks = obj.m_showTickmarks; + m_enabledByChart = obj.m_enabledByChart; + m_showTickmarks = obj.m_showTickmarks; limitUserScaleMinMaxToValidRange(); } @@ -498,21 +449,34 @@ ChartTwoCartesianAxis::toString() const } /** - * @return Annotation used for drawing axis label and tick mark numeric values + * @return Index of overlay that supplies the title. + * + * @param maximumNumberOfOverlays + * Maximum number of allowable overlays. */ -const AnnotationPercentSizeText* -ChartTwoCartesianAxis::getAnnotationAxisLabel() const +int32_t +ChartTwoCartesianAxis::getTitleOverlayIndex(const int32_t maximumNumberOfOverlays) const { - return m_annotationAxisLabel.get(); + if (m_titleOverlayIndex < 0) { + m_titleOverlayIndex = 0; + } + else if (m_titleOverlayIndex >= maximumNumberOfOverlays) { + m_titleOverlayIndex = 0; + } + + return m_titleOverlayIndex; } /** - * @return Annotation used for drawing axis label and tick mark numeric values + * Set the index of the overlay that supplies the title. + * + * @param titleOverlayIndex + * New value for title overlay index. */ -AnnotationPercentSizeText* -ChartTwoCartesianAxis::getAnnotationAxisLabel() +void +ChartTwoCartesianAxis::setTitleOverlayIndex(const int32_t titleOverlayIndex) { - return m_annotationAxisLabel.get(); + m_titleOverlayIndex = titleOverlayIndex; } /** @@ -568,10 +532,6 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); - const AString oldSceneAxisTitle = sceneClass->getStringValue("m_axisTitle"); - if ( ! oldSceneAxisTitle.isEmpty()) { - m_annotationAxisLabel->setText(oldSceneAxisTitle); - } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index a65f6cfb3..697068834 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -33,7 +33,6 @@ namespace caret { - class AnnotationPercentSizeText; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { @@ -106,9 +105,9 @@ namespace caret { std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; - const AnnotationPercentSizeText* getAnnotationAxisLabel() const; + int32_t getTitleOverlayIndex(const int32_t maximumNumberOfOverlays) const; - AnnotationPercentSizeText* getAnnotationAxisLabel(); + void setTitleOverlayIndex(const int32_t titleOverlayIndex); // ADD_NEW_METHODS_HERE @@ -164,8 +163,7 @@ namespace caret { int32_t m_userDigitsRightOfDecimal = 1; - /** Annotation used for drawing axis label and tick mark numeric values*/ - std::unique_ptr m_annotationAxisLabel; + mutable int32_t m_titleOverlayIndex = 0; ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 1d5f06f35..8d7ff149b 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -330,6 +330,11 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute sceneClass->addClass(m_labelDrawingProperties->saveToScene(sceneAttributes, "m_labelDrawingProperties")); + + //m_chartingDelegate->updateAfterFileChanged(); + sceneClass->addClass(m_chartingDelegate->saveToScene(sceneAttributes, + "m_chartingDelegate")); + if (isMappedWithPalette()) { /* * 03 March 2017 diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 3b361aeed..55395a4d7 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -23,6 +23,7 @@ #include "ChartableTwoFileBaseChart.h" #undef __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ +#include "AnnotationPercentSizeText.h" #include "CaretAssert.h" #include "EventManager.h" #include "SceneClass.h" @@ -51,6 +52,8 @@ using namespace caret; #include "CaretMappableDataFile.h" #include "CiftiMappableDataFile.h" +#include "EventAnnotationChartLabelGet.h" +#include "SceneClassAssistant.h" /** * Constructor. @@ -72,16 +75,25 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) /* will be NULL if file is not a cifti mappable file */ m_parentCiftiMappableDataFile = dynamic_cast(m_parentCaretMappableDataFile); + m_bottomAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); + m_leftRightAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH)); + m_sceneAssistant = new SceneClassAssistant(); + m_sceneAssistant->add("m_bottomAxisTitle", + "AnnotationPercentSizeText", + m_bottomAxisTitle.get()); + m_sceneAssistant->add("m_leftRightAxisTitle", + "AnnotationPercentSizeText", + m_leftRightAxisTitle.get()); + + initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); -// EventManager::get()->addEventListener(this, EventTypeEnum::); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); } -//ChartableTwoFileBaseChart::ChartableTwoFileBaseChart() -//{ -// -//} - /** * Destructor. */ @@ -91,6 +103,100 @@ ChartableTwoFileBaseChart::~ChartableTwoFileBaseChart() delete m_sceneAssistant; } +/** + * Initialize an axis titlel + * + * @param titleAnnotation + * Annotation containing title. + * @param axisLocation + * Location of axis. + */ +void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* titleAnnotation, + const ChartAxisLocationEnum::Enum axisLocation) +{ + CaretAssert(titleAnnotation); + + titleAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); + titleAnnotation->setTextColor(CaretColorEnum::RED); + titleAnnotation->setLineColor(CaretColorEnum::NONE); + titleAnnotation->setBackgroundColor(CaretColorEnum::NONE); + + titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + titleAnnotation->setFontPercentViewportSize(40.0); + + AString title; + + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + titleAnnotation->setRotationAngle(-90.0); + titleAnnotation->setFontPercentViewportSize(25.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + titleAnnotation->setRotationAngle(-90.0); + titleAnnotation->setFontPercentViewportSize(25.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + break; + } + + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + switch (m_chartType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + title = "Data"; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + switch (m_compoundChartDataType.getLineChartUnitsAxisX()) { + case ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ: + title = "Hertz"; + break; + case ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE: + title = "Data"; + break; + case ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS: + title = "Seconds"; + break; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + switch (m_chartType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + title = "Counts"; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + title = "Value"; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + break; + } + + titleAnnotation->setText(title); +} + + /** * Get a description of this object's content. * @return String describing this object's content. @@ -110,12 +216,17 @@ ChartableTwoFileBaseChart::toString() const void ChartableTwoFileBaseChart::receiveEvent(Event* event) { -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } + if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { + /* + * The events intended for overlays are received here so that + * only DISPLAYED overlays are updated. + */ + EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); + CaretAssert(chartLabelEvent); + + chartLabelEvent->addAnnotationChartLabel(m_bottomAxisTitle.get()); + chartLabelEvent->addAnnotationChartLabel(m_leftRightAxisTitle.get()); + } } /** @@ -191,8 +302,46 @@ ChartableTwoFileBaseChart::updateChartTwoCompoundDataTypeAfterFileChanges(const CaretAssert(m_chartType == compoundChartDataType.getChartTwoDataType()); m_compoundChartDataType = compoundChartDataType; + + initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); +} + +/** + * @return Annotation for the bottom axis title. + */ +const AnnotationPercentSizeText* +ChartableTwoFileBaseChart::getBottomAxisTitle() const +{ + return m_bottomAxisTitle.get(); +} + +/** + * @return Annotation for the bottom axis title (const method) + */ +AnnotationPercentSizeText* +ChartableTwoFileBaseChart::getBottomAxisTitle() +{ + return m_bottomAxisTitle.get(); +} + +/** + * @return Annotation for the bottom axis title. + */ +const AnnotationPercentSizeText* +ChartableTwoFileBaseChart::getLeftRightAxisTitle() const +{ + return m_leftRightAxisTitle.get(); } +/** + * @return Annotation for the bottom axis title (const method) + */ +AnnotationPercentSizeText* +ChartableTwoFileBaseChart::getLeftRightAxisTitle() +{ + return m_leftRightAxisTitle.get(); +} /** * Save information specific to this type of model to the scene. diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index f4fd24ee4..85d2b97aa 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include "ChartAxisLocationEnum.h" #include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" #include "EventListenerInterface.h" @@ -28,6 +29,7 @@ namespace caret { + class AnnotationPercentSizeText; class CaretMappableDataFile; class CiftiMappableDataFile; class SceneClassAssistant; @@ -63,6 +65,14 @@ namespace caret { ChartTwoCompoundDataType getChartTwoCompoundDataType() const; + const AnnotationPercentSizeText* getBottomAxisTitle() const; + + AnnotationPercentSizeText* getBottomAxisTitle(); + + const AnnotationPercentSizeText* getLeftRightAxisTitle() const; + + AnnotationPercentSizeText* getLeftRightAxisTitle(); + // ADD_NEW_METHODS_HERE virtual AString toString() const override; @@ -96,6 +106,9 @@ namespace caret { ChartableTwoFileBaseChart& operator=(const ChartableTwoFileBaseChart&); + void initializeAxisTitle(AnnotationPercentSizeText* title, + const ChartAxisLocationEnum::Enum axisLocation); + const ChartTwoDataTypeEnum::Enum m_chartType; CaretMappableDataFile* m_parentCaretMappableDataFile; @@ -106,6 +119,10 @@ namespace caret { ChartTwoCompoundDataType m_compoundChartDataType; + std::unique_ptr m_bottomAxisTitle; + + std::unique_ptr m_leftRightAxisTitle; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 1c74b2ea0..32e810a91 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -379,6 +379,8 @@ ChartableTwoFileLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); + + std::cout << "Saved " << getCaretMappableDataFile()->getFileNameNoPath() << " loading is " << m_lineChartHistory->isLoadingEnabled() << std::endl; } /** @@ -399,5 +401,6 @@ ChartableTwoFileLineSeriesChart::restoreSubClassDataFromScene(const SceneAttribu { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + std::cout << "Restored " << getCaretMappableDataFile()->getFileNameNoPath() << " loading is " << m_lineChartHistory->isLoadingEnabled() << std::endl; } diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index e018950ef..ba245ab3b 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -594,6 +594,9 @@ void CiftiScalarDataSeriesFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { + CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, + sceneClass); + m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* @@ -632,6 +635,9 @@ void CiftiScalarDataSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { + CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, + sceneClass); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 24d3cb3b8..132166970 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,12 @@ #include "CaretDataFileSelectionModel.h" #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" +#include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" +#include "ChartableTwoFileBaseChart.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileHistogramChart.h" +#include "ChartableTwoFileLineSeriesChart.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventChartTwoAttributesChanged.h" @@ -70,7 +76,7 @@ using namespace caret; BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar) { - m_axisDisplayedByUserCheckBox = new QCheckBox("Axis"); + m_axisDisplayedByUserCheckBox = new QCheckBox("Show Axis"); m_axisDisplayedByUserCheckBox->setToolTip("Show/Hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); @@ -88,7 +94,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Controls for axis parameters */ m_axisNameToolButton = new QToolButton(); - m_axisNameToolButton->setText("Edit Title"); + m_axisNameToolButton->setText("Edit Title..."); QObject::connect(m_axisNameToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); @@ -116,6 +122,11 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); + QLabel* axisTitleFromOverlayLabel = new QLabel("Title From File In"); + m_axisTitleFromOverlayComboBox = new QComboBox(); + QObject::connect(m_axisTitleFromOverlayComboBox, static_cast(&QComboBox::activated), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); + m_userNumericFormatComboBox = new EnumComboBoxTemplate(this); m_userNumericFormatComboBox->setup(); QObject::connect(m_userNumericFormatComboBox, &EnumComboBoxTemplate::itemActivated, @@ -142,131 +153,100 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Group widgets for blocking signals */ m_widgetGroup = new WuQWidgetObjectGroup(this); + m_widgetGroup->add(m_axisComboBox); m_widgetGroup->add(m_axisDisplayedByUserCheckBox); m_widgetGroup->add(m_axisNameToolButton); m_widgetGroup->add(m_autoUserRangeComboBox->getWidget()); m_widgetGroup->add(m_userMinimumValueSpinBox); m_widgetGroup->add(m_userMaximumValueSpinBox); m_widgetGroup->add(m_showTickMarksCheckBox); + m_widgetGroup->add(m_axisTitleFromOverlayComboBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); m_widgetGroup->add(m_numericSubdivisionsModeComboBox->getWidget()); m_widgetGroup->add(m_userSubdivisionsSpinBox); /* - * Layouts + * Show widgets layout */ - QLayout* widgetsLayout = NULL; - - const int layoutStyle = 0; - if (layoutStyle == 0) { - QWidget* rangeWidget = new QWidget(); - { - QGridLayout* rangeLayout = new QGridLayout(rangeWidget); - WuQtUtilities::setLayoutSpacingAndMargins(rangeLayout, 3, 0); - int row = 0; - rangeLayout->addWidget(new QLabel("Range Mode"), row, 0); - m_autoUserRangeComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); - rangeLayout->addWidget(m_autoUserRangeComboBox->getWidget(), row, 1); - row++; - m_userMinimumValueSpinBox->setFixedWidth(90); - m_userMaximumValueSpinBox->setFixedWidth(90); - rangeLayout->addWidget(new QLabel("User Max"), row, 0); - rangeLayout->addWidget(m_userMaximumValueSpinBox, row, 1); - row++; - rangeLayout->addWidget(new QLabel("User Min"), row, 0); - rangeLayout->addWidget(m_userMinimumValueSpinBox, row, 1); - } - - QWidget* numericsWidget = new QWidget(); - { - QGridLayout* numericsLayout = new QGridLayout(numericsWidget); - WuQtUtilities::setLayoutSpacingAndMargins(numericsLayout, 3, 0); - int COLUMN_ONE = 0; - int COLUMN_TWO = 1; - int COLUMN_THREE = 2; - int row = 0; - numericsLayout->addWidget(new QLabel("Format"), row, COLUMN_ONE); - numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), row, COLUMN_TWO, 1, 2); - row++; - numericsLayout->addWidget(new QLabel("Decimals"), row, COLUMN_ONE); - numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, row, COLUMN_TWO, 1, 2); - row++; - numericsLayout->addWidget(new QLabel("Subdivisions"), row, COLUMN_ONE); - numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), row, COLUMN_TWO); - numericsLayout->addWidget(m_userSubdivisionsSpinBox, row, COLUMN_THREE); - } - - QHBoxLayout* axisLayout = new QHBoxLayout(); - WuQtUtilities::setLayoutSpacingAndMargins(axisLayout, 3, 0); - axisLayout->addWidget(new QLabel("Axis ")); - axisLayout->addWidget(m_axisComboBox->getWidget()); - axisLayout->addSpacing(5); - axisLayout->addStretch(); - m_axisDisplayedByUserCheckBox->setText("Show Axis"); - axisLayout->addWidget(m_axisDisplayedByUserCheckBox); - axisLayout->addSpacing(10); - axisLayout->addWidget(m_showTickMarksCheckBox); - axisLayout->addSpacing(5); - axisLayout->addStretch(); - axisLayout->addWidget(m_axisNameToolButton); - - QGridLayout* gridLayout = new QGridLayout(); - WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 3, 0); - gridLayout->addLayout(axisLayout, 0, 0, 1, 3); - gridLayout->addWidget(rangeWidget, 1, 0); //, Qt::AlignHCenter | Qt::AlignTop); - gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1); - gridLayout->addWidget(numericsWidget, 1, 2); - - widgetsLayout = gridLayout; - } - else { - const int COLUMN_ONE = 0; - const int COLUMN_TWO = 1; - const int COLUMN_THREE = 2; - const int COLUMN_FOUR = 3; - const int COLUMN_FIVE = 4; - const int COLUMN_SIX = 5; - - QGridLayout* layout = new QGridLayout(); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); - int leftRow = 0; - layout->addWidget(m_axisDisplayedByUserCheckBox, leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_axisComboBox->getWidget(), leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Range"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_autoUserRangeComboBox->getWidget(), leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Maximum"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_userMaximumValueSpinBox, leftRow, COLUMN_TWO); - leftRow++; - layout->addWidget(new QLabel("Minimum"), leftRow, COLUMN_ONE, Qt::AlignLeft); - layout->addWidget(m_userMinimumValueSpinBox, leftRow, COLUMN_TWO); - leftRow++; - - layout->setColumnMinimumWidth(COLUMN_THREE, 7); - - int rightRow = 0; - layout->addWidget(m_axisNameToolButton, rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_showTickMarksCheckBox, rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Format"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userNumericFormatComboBox->getWidget(), rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Decimals"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_userDigitsRightOfDecimalSpinBox, rightRow, COLUMN_FIVE, 1, 2); - rightRow++; - layout->addWidget(new QLabel("Subdivisions"), rightRow, COLUMN_FOUR, Qt::AlignLeft); - layout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), rightRow, COLUMN_FIVE, Qt::AlignHCenter); - layout->addWidget(m_userSubdivisionsSpinBox, rightRow, COLUMN_SIX, Qt::AlignRight); - rightRow++; - - widgetsLayout = layout; - } - + QWidget* showWidget = new QWidget(); + QGridLayout* showLayout = new QGridLayout(showWidget); + int32_t axisRow = 0; + showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); + axisRow++; + showLayout->addWidget(m_showTickMarksCheckBox, axisRow, 0); + axisRow++; + showWidget->setSizePolicy(showWidget->sizePolicy().horizontalPolicy(), + QSizePolicy::Fixed); + + /* + * Range widgets layout + */ + QWidget* rangeWidget = new QWidget(); + QGridLayout* rangeLayout = new QGridLayout(rangeWidget); + WuQtUtilities::setLayoutSpacingAndMargins(rangeLayout, 3, 0); + int rangeRow = 0; + rangeLayout->addWidget(new QLabel("Range Mode"), rangeRow, 0); + m_autoUserRangeComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + rangeLayout->addWidget(m_autoUserRangeComboBox->getWidget(), rangeRow, 1); + rangeRow++; + m_userMinimumValueSpinBox->setFixedWidth(90); + m_userMaximumValueSpinBox->setFixedWidth(90); + rangeLayout->addWidget(new QLabel("User Max"), rangeRow, 0); + rangeLayout->addWidget(m_userMaximumValueSpinBox, rangeRow, 1); + rangeRow++; + rangeLayout->addWidget(new QLabel("User Min"), rangeRow, 0); + rangeLayout->addWidget(m_userMinimumValueSpinBox, rangeRow, 1); + + /* + * Numerics widgets layout + */ + QWidget* numericsWidget = new QWidget(); + QGridLayout* numericsLayout = new QGridLayout(numericsWidget); + WuQtUtilities::setLayoutSpacingAndMargins(numericsLayout, 3, 0); + int COLUMN_ONE = 0; + int COLUMN_TWO = 1; + int COLUMN_THREE = 2; + int numericsRow = 0; + numericsLayout->addWidget(new QLabel("Format"), numericsRow, COLUMN_ONE); + numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), numericsRow, COLUMN_TWO, 1, 2); + numericsRow++; + numericsLayout->addWidget(new QLabel("Decimals"), numericsRow, COLUMN_ONE); + numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, numericsRow, COLUMN_TWO, 1, 2); + numericsRow++; + numericsLayout->addWidget(new QLabel("Subdivisions"), numericsRow, COLUMN_ONE); + numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), numericsRow, COLUMN_TWO); + numericsLayout->addWidget(m_userSubdivisionsSpinBox, numericsRow, COLUMN_THREE); + + /* + * Top layout + */ + QHBoxLayout* topLayout = new QHBoxLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(topLayout, 3, 0); + topLayout->addWidget(new QLabel("Edit Axis ")); + topLayout->addWidget(m_axisComboBox->getWidget()); + topLayout->addSpacing(10); + topLayout->addStretch(); + topLayout->addWidget(axisTitleFromOverlayLabel); + topLayout->addWidget(m_axisTitleFromOverlayComboBox); + topLayout->addSpacing(10); + topLayout->addWidget(m_axisNameToolButton); + + /* + * Grid layout containing layouts + */ + QGridLayout* gridLayout = new QGridLayout(); + WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 3, 0); + gridLayout->addLayout(topLayout, 0, 0, 1, 5); + gridLayout->addWidget(showWidget, 1, 0, Qt::AlignTop); + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1); + gridLayout->addWidget(rangeWidget, 1, 2); + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 3); + gridLayout->addWidget(numericsWidget, 1, 4); + QVBoxLayout* dialogLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); - dialogLayout->addLayout(widgetsLayout); + dialogLayout->addLayout(gridLayout); dialogLayout->addStretch(); EventManager::get()->addEventListener(this, @@ -313,14 +293,41 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT return; } - ChartTwoCartesianAxis* selectedAxis = NULL; + updateControls(browserTabContent); +} + +/** + * Get the selection data. + * + * @param browserTabContent + * The tab content. + * @param chartOverlaySetOut + * The chart overlay set (may be NULL) + * @param validAxesLocationsOut + * The valid axes locations. + * @param selectedAxisOut + * Output with selected axis (may be NULL) + * @param axisLabelOut + * Output with the axis text label. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::getSelectionData(BrowserTabContent* browserTabContent, + ChartTwoOverlaySet* &chartOverlaySetOut, + std::vector& validAxesLocationsOut, + ChartTwoCartesianAxis* &selectedAxisOut, + AnnotationPercentSizeText* &axisLabelOut) const +{ + chartOverlaySetOut = NULL; + validAxesLocationsOut.clear(); + selectedAxisOut = NULL; + axisLabelOut = NULL; + + if (browserTabContent == NULL) { + return; + } const ChartAxisLocationEnum::Enum lastSelectedAxis = getSelectedAxisLocation(); - - m_axisComboBox->blockSignals(true); - m_axisComboBox->getComboBox()->clear(); - ChartTwoOverlaySet* chartOverlaySet = NULL; if (browserTabContent != NULL) { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); const int32_t tabIndex = browserTabContent->getTabNumber(); @@ -329,29 +336,35 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + chartOverlaySetOut = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + chartOverlaySetOut = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } - if (chartOverlaySet != NULL) { + if (chartOverlaySetOut != NULL) { int32_t defaultAxisIndex = -1; - std::vector validAxesLocations; - std::vector axes = chartOverlaySet->getDisplayedChartAxes(); + std::vector axes; + AnnotationPercentSizeText* leftAxisLabel = NULL; + AnnotationPercentSizeText* rightAxisLabel = NULL; + AnnotationPercentSizeText* bottomAxisLabel = NULL; + chartOverlaySetOut->getDisplayedChartAxes(axes, + leftAxisLabel, + rightAxisLabel, + bottomAxisLabel); const int32_t numAxes = static_cast(axes.size()); for (int32_t i = 0; i < numAxes; i++) { const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); if (lastSelectedAxis == axisLocation) { defaultAxisIndex = i; } - validAxesLocations.push_back(axisLocation); + validAxesLocationsOut.push_back(axisLocation); } - CaretAssert(validAxesLocations.size() == axes.size()); + CaretAssert(validAxesLocationsOut.size() == axes.size()); if (defaultAxisIndex < 0) { /* @@ -371,22 +384,17 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT if (defaultAxisIndex < 0) { defaultAxisIndex = 0; } - CaretAssertVectorIndex(validAxesLocations, defaultAxisIndex); - const ChartAxisLocationEnum::Enum axisLocation = validAxesLocations[defaultAxisIndex]; - m_axisComboBox->setupWithItems(validAxesLocations); - m_axisComboBox->setSelectedItem(axisLocation); - CaretAssertVectorIndex(axes, defaultAxisIndex); - selectedAxis = axes[defaultAxisIndex]; + selectedAxisOut = axes[defaultAxisIndex]; + } + + if (selectedAxisOut != NULL) { + axisLabelOut = chartOverlaySetOut->getAxisLabel(selectedAxisOut); } } } } - m_axisComboBox->blockSignals(false); - - updateControls(selectedAxis); - setEnabled(selectedAxis != NULL); } /** @@ -414,22 +422,88 @@ BrainBrowserWindowToolBarChartTwoAxes::getSelectedAxisLocation() const } +void +BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browserTabContent) +{ + ChartTwoOverlaySet* chartOverlaySet = NULL; + std::vector validAxesLocations; + ChartTwoCartesianAxis* selectedAxis = NULL; + AnnotationPercentSizeText* axisLabel = NULL; + + getSelectionData(browserTabContent, + chartOverlaySet, + validAxesLocations, + selectedAxis, + axisLabel); + + m_widgetGroup->blockAllSignals(true); + + m_chartAxis = selectedAxis; + if ((chartOverlaySet != NULL) + && (m_chartAxis != NULL)) { + m_axisComboBox->setupWithItems(validAxesLocations); + m_axisComboBox->setSelectedItem(m_chartAxis->getAxisLocation()); + + m_axisDisplayedByUserCheckBox->setChecked(m_chartAxis->isDisplayedByUser()); + m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); + float rangeMin(0.0), rangeMax(0.0); + m_chartAxis->getRange(rangeMin, rangeMax); + m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); + m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); + m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); + m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); + m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); + const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); + m_userNumericFormatComboBox->setSelectedItem(numericFormat); + m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); + m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); + m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); + m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); + m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); + + const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); + int32_t selectedOverlayIndex = m_chartAxis->getTitleOverlayIndex(overlayCount); + const int32_t comboBoxCount = m_axisTitleFromOverlayComboBox->count(); + if (overlayCount < comboBoxCount) { + m_axisTitleFromOverlayComboBox->setMaxCount(overlayCount); + } + else if (overlayCount > comboBoxCount) { + for (int32_t j = comboBoxCount; j < overlayCount; j++) { + m_axisTitleFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); + } + } + + if ((selectedOverlayIndex >= 0) + && (selectedOverlayIndex < m_axisTitleFromOverlayComboBox->count())) { + m_axisTitleFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); + } + setEnabled(true); + } + else { + setEnabled(false); + } + + m_widgetGroup->blockAllSignals(false); +} /** * Update the content with the given axis. * + * @param chartOverlaySet + * Chart overlay set containing axis. * @param chartAxis * New chart axis content. */ void -BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* chartAxis) +BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartOverlaySet, + ChartTwoCartesianAxis* chartAxis) { m_chartAxis = chartAxis; - if (m_chartAxis != NULL) { + if ((chartOverlaySet != NULL) + && (m_chartAxis != NULL)) { m_widgetGroup->blockAllSignals(true); m_axisDisplayedByUserCheckBox->setChecked(chartAxis->isDisplayedByUser()); - //m_axisNameToolButton->setText(m_chartAxis->getLabelText()); m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); float rangeMin(0.0), rangeMax(0.0); m_chartAxis->getRange(rangeMin, rangeMax); @@ -446,6 +520,23 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoCartesianAxis* cha m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); + const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); + int32_t selectedOverlayIndex = m_chartAxis->getTitleOverlayIndex(overlayCount); + const int32_t comboBoxCount = m_axisTitleFromOverlayComboBox->count(); + if (overlayCount < comboBoxCount) { + m_axisTitleFromOverlayComboBox->setMaxCount(overlayCount); + } + else if (overlayCount > comboBoxCount) { + for (int32_t j = comboBoxCount; j < overlayCount; j++) { + m_axisTitleFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); + } + } + + if ((selectedOverlayIndex >= 0) + && (selectedOverlayIndex < m_axisTitleFromOverlayComboBox->count())) { + m_axisTitleFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); + } + m_widgetGroup->blockAllSignals(false); } } @@ -458,6 +549,7 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() { CaretAssert(m_chartAxis); if (m_chartAxis != NULL) { + m_chartAxis->setTitleOverlayIndex(m_axisTitleFromOverlayComboBox->currentIndex()); m_chartAxis->setDisplayedByUser(m_axisDisplayedByUserCheckBox->isChecked()); m_chartAxis->setScaleRangeMode(m_autoUserRangeComboBox->getSelectedItem()); m_chartAxis->setUserScaleMinimumValue(m_userMinimumValueSpinBox->value()); @@ -596,15 +688,25 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt(int) void BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) { - CaretAssert(m_chartAxis); - if (m_chartAxis != NULL) { + ChartTwoOverlaySet* chartOverlaySet = NULL; + std::vector validAxesLocations; + ChartTwoCartesianAxis* selectedAxis = NULL; + AnnotationPercentSizeText* axisLabel = NULL; + + getSelectionData(getTabContentFromSelectedTab(), + chartOverlaySet, + validAxesLocations, + selectedAxis, + axisLabel); + + if (axisLabel != NULL) { WuQDataEntryDialog newNameDialog("Axis Title", m_axisNameToolButton); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Axis Name"); - lineEdit->setText(m_chartAxis->getAnnotationAxisLabel()->getText()); + lineEdit->setText(axisLabel->getText()); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); - m_chartAxis->getAnnotationAxisLabel()->setText(name); + axisLabel->setText(name); valueChanged(); } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 665d5ffaa..85dadadce 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -26,6 +26,7 @@ #include "ChartAxisLocationEnum.h" class QCheckBox; +class QComboBox; class QDoubleSpinBox; class QLabel; class QSpinBox; @@ -33,8 +34,10 @@ class QToolButton; namespace caret { + class AnnotationPercentSizeText; class ChartTwoCartesianAxis; class ChartTwoCartesianAxisWidget; + class ChartTwoOverlaySet; class EnumComboBoxTemplate; class WuQWidgetObjectGroup; @@ -76,7 +79,16 @@ namespace caret { ChartAxisLocationEnum::Enum getSelectedAxisLocation() const; - void updateControls(ChartTwoCartesianAxis* chartAxis); + void getSelectionData(BrowserTabContent* browserTabContent, + ChartTwoOverlaySet* &chartOverlaySetOut, + std::vector& validAxesLocationsOut, + ChartTwoCartesianAxis* &selectedAxisOut, + AnnotationPercentSizeText* &axisLabelOut) const; + + void updateControls(ChartTwoOverlaySet* chartOverlaySet, + ChartTwoCartesianAxis* chartAxis); + + void updateControls(BrowserTabContent* browserTabContent); void updateGraphics(); @@ -88,6 +100,8 @@ namespace caret { QToolButton* m_axisNameToolButton; + QComboBox* m_axisTitleFromOverlayComboBox; + EnumComboBoxTemplate* m_autoUserRangeComboBox; QDoubleSpinBox* m_userMinimumValueSpinBox; diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 24cc59e80..b518b7f9e 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -295,8 +295,12 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi /* * May need to reduce color combo boxes + * Note that calling setRowCount() on the table widget + * will destroy the widgets that were added. */ - m_colorComboBoxes.resize(preNumRows); + const int32_t validWidgetCount = std::min(preNumRows, numHistory); + m_colorComboBoxes.resize(validWidgetCount); + m_lineWidthSpinBoxes.resize(validWidgetCount); /* * If needed, add cells @@ -354,6 +358,8 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi } } + CaretAssert(m_lineWidthSpinBoxes.size() == m_colorComboBoxes.size()); + /* * Load cells */ -- GitLab From cf2ae1557c64134360d2b00475500e243ac1c4bb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Jun 2017 11:59:58 -0500 Subject: [PATCH 309/755] Removed print statements added in last commit for debugging --- src/Files/ChartableTwoFileLineSeriesChart.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 32e810a91..1c74b2ea0 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -379,8 +379,6 @@ ChartableTwoFileLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - - std::cout << "Saved " << getCaretMappableDataFile()->getFileNameNoPath() << " loading is " << m_lineChartHistory->isLoadingEnabled() << std::endl; } /** @@ -401,6 +399,5 @@ ChartableTwoFileLineSeriesChart::restoreSubClassDataFromScene(const SceneAttribu { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); - std::cout << "Restored " << getCaretMappableDataFile()->getFileNameNoPath() << " loading is " << m_lineChartHistory->isLoadingEnabled() << std::endl; } -- GitLab From b4544b8d15767b9b3ee79818cfdac1b263e5b123 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Jun 2017 15:02:58 -0500 Subject: [PATCH 310/755] Fixed problems with incorrect line-series chart coloring including default color. --- src/Charting/ChartTwoLineSeriesHistory.cxx | 57 +++++++++++++++---- src/Charting/ChartTwoLineSeriesHistory.h | 2 + src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 51 ++++++++++------- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 498660d96..9763a288e 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -115,25 +115,56 @@ ChartTwoLineSeriesHistory::generateDefaultColor() { CaretColorEnum::Enum color = CaretColorEnum::BLACK; - bool validFlag = false; - color = CaretColorEnum::fromIntegerCode(s_defaultColorIndexGenerator, - &validFlag); + std::vector colors; + CaretColorEnum::getColorEnums(colors); - if ( ! validFlag) { + const int32_t numColors = static_cast(colors.size()); + CaretAssert(numColors > 0); + if (s_defaultColorIndexGenerator < 0) { + s_defaultColorIndexGenerator = 0; + } + else if (s_defaultColorIndexGenerator >= numColors) { s_defaultColorIndexGenerator = 0; - color = CaretColorEnum::fromIntegerCode(s_defaultColorIndexGenerator, - &validFlag); - if ( ! validFlag) { - color = CaretColorEnum::BLACK; - CaretLogWarning("Generation of default color failed"); - } } - + + CaretAssertVectorIndex(colors, s_defaultColorIndexGenerator); + color = colors[s_defaultColorIndexGenerator]; + + /* move to next color */ ++s_defaultColorIndexGenerator; return color; } +/** + * Validate the default color. + */ +void +ChartTwoLineSeriesHistory::validateDefaultColor() +{ + std::vector allEnums; + CaretColorEnum::getColorAndOptionalEnums(allEnums, (CaretColorEnum::ColorOptions::OPTION_INCLUDE_CUSTOM_COLOR + || CaretColorEnum::CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); + if (std::find(allEnums.begin(), + allEnums.end(), + m_defaultColor) == allEnums.end()) { + const AString msg("Default color enum is invalid. Integer value: " + AString::number((int)m_defaultColor)); + CaretLogSevere(msg); + m_defaultColor = CaretColorEnum::RED; + } + + if (m_defaultColor == CaretColorEnum::CUSTOM) { + const AString msg("Default color CUSTOM is not allowed"); + CaretLogSevere(msg); + m_defaultColor = CaretColorEnum::RED; + } + else if (m_defaultColor == CaretColorEnum::NONE) { + const AString msg("Default color NONE is not allowed"); + CaretLogSevere(msg); + m_defaultColor = CaretColorEnum::RED; + } +} + /** * Initialize an instance of this class. */ @@ -141,6 +172,7 @@ void ChartTwoLineSeriesHistory::initializeInstance() { m_defaultColor = ChartTwoLineSeriesHistory::generateDefaultColor(); + validateDefaultColor(); const int32_t defaultHistoryCount = 5; m_loadingEnabled = false; @@ -177,6 +209,7 @@ ChartTwoLineSeriesHistory::copyHelperChartTwoLineSeriesHistory(const ChartTwoLin m_defaultColor = obj.m_defaultColor; m_displayCount = obj.m_displayCount; + validateDefaultColor(); } /** @@ -198,6 +231,7 @@ ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultCol { if (defaultColor != m_defaultColor) { m_defaultColor = defaultColor; + validateDefaultColor(); setModified(); } @@ -427,6 +461,7 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + validateDefaultColor(); /* * Restore chart matrix properties diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index a135598f1..b7b563450 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -105,6 +105,8 @@ namespace caret { static CaretColorEnum::Enum generateDefaultColor(); + void validateDefaultColor(); + bool m_loadingEnabled = false; SceneClassAssistant* m_sceneAssistant = NULL; diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index b518b7f9e..7c63e1354 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -282,30 +283,29 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi { CaretAssert(lineSeriesHistory); - m_tableWidget->blockSignals(true); + /* + * NOTE: We never remove items from a table due to issues + * with widget ownership (and destruction) and the signal mappers. + * + * When new rows are needed, they are added. + * When there are two many rows, they are hidden. + */ + + const QSignalBlocker tableSignalBlocker(m_tableWidget); - const int32_t preNumRows = m_tableWidget->rowCount(); + const int32_t oldRowCount = m_tableWidget->rowCount(); const int32_t numHistory = lineSeriesHistory->getHistoryCount(); /* * Setup table dimensions */ - m_tableWidget->setRowCount(numHistory); + m_tableWidget->setRowCount(std::max(numHistory, oldRowCount)); m_tableWidget->setColumnCount(COLUMN_COUNT); - /* - * May need to reduce color combo boxes - * Note that calling setRowCount() on the table widget - * will destroy the widgets that were added. - */ - const int32_t validWidgetCount = std::min(preNumRows, numHistory); - m_colorComboBoxes.resize(validWidgetCount); - m_lineWidthSpinBoxes.resize(validWidgetCount); - /* * If needed, add cells */ - for (int32_t iRow = preNumRows; iRow < numHistory; iRow++) { + for (int32_t iRow = oldRowCount; iRow < numHistory; iRow++) { for (int32_t j = 0; j < COLUMN_COUNT; j++) { if (j == COLUMN_VIEW) { QTableWidgetItem* item = new QTableWidgetItem(""); @@ -360,31 +360,42 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi CaretAssert(m_lineWidthSpinBoxes.size() == m_colorComboBoxes.size()); + /* + * Hide rows not needed + */ + for (int32_t iRow = numHistory; iRow < oldRowCount; iRow++) { + m_tableWidget->setRowHidden(iRow, true); + } + /* * Load cells */ + CaretAssert(numHistory <= m_tableWidget->rowCount()); for (int32_t iRow = 0; iRow < numHistory; iRow++) { - ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iRow); - const MapFileDataSelector* mapFileDataSelector = data->getMapFileDataSelector(); + ChartTwoDataCartesian* historyData = lineSeriesHistory->getHistoryItem(iRow); + const MapFileDataSelector* mapFileDataSelector = historyData->getMapFileDataSelector(); - m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(data->isSelected() + m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(historyData->isSelected() ? Qt::Checked : Qt::Unchecked); CaretAssertVectorIndex(m_colorComboBoxes, iRow); - m_colorComboBoxes[iRow]->setSelectedColor(data->getColor()); + m_colorComboBoxes[iRow]->setSelectedColor(historyData->getColor()); - m_lineWidthSpinBoxes[iRow]->setValue(data->getLineWidth()); + CaretAssertVectorIndex(m_lineWidthSpinBoxes, iRow); + m_lineWidthSpinBoxes[iRow]->setValue(historyData->getLineWidth()); QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); item->setText(mapFileDataSelector->toString()); + + m_tableWidget->setRowHidden(iRow, false); } /* * If table was empty, add column titles * and adjust column widths */ - if ((preNumRows == 0) + if ((oldRowCount == 0) && (numHistory > 0)) { m_tableWidget->setHorizontalHeaderItem(COLUMN_VIEW, new QTableWidgetItem("View")); @@ -410,8 +421,6 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi tableSize.width() + 30, sizeHint().height()); } - - m_tableWidget->blockSignals(false); } /** -- GitLab From 9730c93bc4cd40d13782d976523846d1f52927b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Jun 2017 15:45:45 -0500 Subject: [PATCH 311/755] If there are modified scenes and the user requests the scene dialog to close, only warn the user about modified scene files if the scene dialog's close button was clicked. Do not warn user if closing of scene dialog was initiated from the Window Menu or the scenes button in the toolbar. --- src/GuiQt/SceneDialog.cxx | 40 ++++++++++++++++++++++----------------- src/GuiQt/SceneDialog.h | 2 ++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 411a282af..32386550d 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -186,13 +186,20 @@ SceneDialog::~SceneDialog() void SceneDialog::closeEvent(QCloseEvent* event) { + WuQDialogNonModal::closeEvent(event); +} + +/** + * Called when the close button is clicked. + */ +void +SceneDialog::closeButtonClicked() +{ + /* + * If there are any modified scene files, inform the user + */ Brain* brain = GuiManager::get()->getBrain(); const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); - if (numSceneFiles <= 0) { - WuQDialogNonModal::closeEvent(event); - return; - } - int32_t numberOfModifiedSceneFiles = 0; for (int32_t i = 0; i < numSceneFiles; i++) { const SceneFile* sceneFile = brain->getSceneFile(i); @@ -201,21 +208,20 @@ SceneDialog::closeEvent(QCloseEvent* event) } } - if (numberOfModifiedSceneFiles <= 0) { - WuQDialogNonModal::closeEvent(event); - return; - } + bool allowToCloseFlag = true; - const AString msg("There are modified scene file(s). You can save modified scene files using File Menu->Save/Manage Files " - "or by selecting them on the Scene Dialog and using the Save/Save As buttons.

" - "Continue closing this Scene Dialog?"); - if (WuQMessageBox::warningOkCancel(this, msg)) { - WuQDialogNonModal::closeEvent(event); - return; + if (numberOfModifiedSceneFiles > 0) { + const AString msg("There are modified scene file(s). You can save modified scene files using File Menu->Save/Manage Files " + "or by selecting them on the Scene Dialog and using the Save/Save As buttons.

" + "Continue closing this Scene Dialog?"); + if ( ! WuQMessageBox::warningOkCancel(this, msg)) { + allowToCloseFlag = false; + } } - event->ignore(); - WuQDialogNonModal::closeEvent(event); + if (allowToCloseFlag) { + WuQDialogNonModal::closeButtonClicked(); + } } /** diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index cbfebd899..13bac6f62 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -74,6 +74,8 @@ namespace caret { SceneDialog& operator=(const SceneDialog&); private slots: + virtual void closeButtonClicked(); + void sceneFileSelected(int); void newSceneFileButtonClicked(); -- GitLab From 2251efda0c360f7d8caa7a1b665a3c05b60ae9ea Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Jun 2017 16:56:10 -0500 Subject: [PATCH 312/755] Fixed compilation error on linux. --- src/Files/ChartableTwoFileBaseChart.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index 85d2b97aa..c1f6ee504 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include "ChartAxisLocationEnum.h" #include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" -- GitLab From b17a13cb12c74a67b733410a43a4010c88766bde Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 3 Jul 2017 09:46:48 -0500 Subject: [PATCH 313/755] Cleanup of new charting: Improvements to tooltip text and removed unused code. --- src/Files/ChartableTwoFileDelegate.cxx | 384 ------------------ src/Files/ChartableTwoFileDelegate.h | 48 --- src/Files/ChartableTwoFileLineSeriesChart.cxx | 10 +- src/Files/ChartableTwoFileLineSeriesChart.h | 3 +- src/Files/CiftiParcelScalarFile.cxx | 35 -- src/Files/CiftiParcelSeriesFile.cxx | 91 ----- src/Files/CiftiScalarDataSeriesFile.cxx | 5 - ...BrowserWindowToolBarChartTwoAttributes.cxx | 115 +----- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 9 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 10 +- 10 files changed, 22 insertions(+), 688 deletions(-) diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index 1085429a9..ce136f25d 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -48,16 +48,8 @@ using namespace caret; /** * Constructor. * - * @param type of matrix (if any) supported by implementing file. - * * @param caretMappableDataFile * Caret Mappable Data File this delegate charts. - * @param histogramChart - * Histogram charting for Caret Mappable Data File (NULL if histogram charting not supported). - * @param lineSeriesChart - * Line series charting for Caret Mappable Data File (NULL if line series charting not supported). - * @param matrixChart - * Matrix charting for Caret Mappable Data File (NULL if matrix charting not supported). */ ChartableTwoFileDelegate::ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile) : CaretObjectTracksModification(), @@ -316,26 +308,6 @@ ChartableTwoFileDelegate::getMatrixCharting() const return m_matrixCharting.get(); } -///** -// * @return The CiftiMappableDataFile that implements this interface. -// * NULL is returned if not a CiftiMappableDataFile. -// */ -//CiftiMappableDataFile* -//ChartableTwoFileDelegate::getAsCiftiMappableDataFile() -//{ -// return dynamic_cast(this); -//} -// -///** -// * @return The CiftiMappableDataFile that implements this interface. -// * NULL is returned if not a CiftiMappableDataFile. -// */ -//const CiftiMappableDataFile* -//ChartableTwoFileDelegate::getAsCiftiMappableDataFile() const -//{ -// return dynamic_cast(this); -//} - /** * Does this file support any type of charting? */ @@ -436,110 +408,6 @@ ChartableTwoFileDelegate::getSupportedChartTwoCompoundDataTypes(std::vectorgetMatrixContentType() != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartTwoCompoundDataType()); } - -// const CaretMappableDataFile* cmdf = getAsCaretMappableDataFile(); -// if (cmdf == NULL) { -// return; -// } -// -// switch (m_histogramContentType) { -// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: -// break; -// case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: -// if (cmdf->getNumberOfMaps() > 0) { -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForHistogram()); -// } -// break; -// } -// -// switch (m_lineSeriesContentType) { -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: -// if (cmdf->getNumberOfMaps() > 1) { -// const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// const int32_t numMaps = cmdf->getNumberOfMaps(); -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numMaps)); -// } -// break; -// case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: -// { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// const int32_t numRows = dims[1]; -// -// if ((numRows > 0) -// && (numCols > 1)) { -// const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); -// ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; -// switch (mapUnits) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// CaretAssert(0); -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// break; -// } -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, -// numCols)); -// } -// } break; -// } -// -// switch (m_matrixContentType) { -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: -// { -// const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(this); -// CaretAssert(ciftiMapFile); -// std::vector dims; -// ciftiMapFile->getMapDimensions(dims); -// CaretAssertVectorIndex(dims, 1); -// const int32_t numCols = dims[0]; -// const int32_t numRows = dims[1]; -// -// chartCompoundDataTypesOut.push_back(ChartTwoCompoundDataType::newInstanceForMatrix(numRows, -// numCols)); -// } break; -// } } /** @@ -653,255 +521,3 @@ ChartableTwoFileDelegate::restoreFromScene(const SceneAttributes* sceneAttribute } } - -///** -// * @return The content type for histograms. -// */ -//ChartTwoHistogramContentTypeEnum::Enum ChartableTwoFileDelegate::getHistogramContentType() const -//{ -// return m_histogramContentType; -//} -// -///** -// * @return The content type for line series. -// */ -//ChartTwoLineSeriesContentTypeEnum::Enum ChartableTwoFileDelegate::getLineSeriesContentType() const -//{ -// return m_lineSeriesContentType; -//} -// -///** -// * @return The content type for matrix. -// */ -//ChartTwoMatrixContentTypeEnum::Enum ChartableTwoFileDelegate::getMatrixContentType() const -//{ -// return m_matrixContentType; -//} -// -// -///** -// * Get the matrix dimensions. -// * -// * @param numberOfRowsOut -// * Number of rows in the matrix. -// * @param numberOfColumnsOut -// * Number of rows in the matrix. -// */ -//void -//ChartableTwoFileDelegate::getTwoMatrixDimensions(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut) const -//{ -// if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { -// numberOfRowsOut = 0; -// numberOfColumnsOut = 0; -// return; -// } -// -// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); -// CaretAssert(ciftiMapFile); -// CaretAssertToDoFatal(); -//// ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, -//// numberOfColumnsOut); -// // std::vector dims; -// // ciftiMapFile->getMapDimensions(dims); -// // CaretAssertVectorIndex(dims, 1); -// // numberOfRowsOut = dims[0]; -// // numberOfColumnsOut = dims[1]; -//} -// -///** -// * Get the matrix RGBA coloring for this matrix data creator. -// * -// * @param numberOfRowsOut -// * Number of rows in the coloring matrix. -// * @param numberOfColumnsOut -// * Number of rows in the coloring matrix. -// * @param rgbaOut -// * RGBA coloring output with number of elements -// * (numberOfRowsOut * numberOfColumnsOut * 4). -// * @return -// * True if data output data is valid, else false. -// */ -//bool -//ChartableTwoFileDelegate::getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// std::vector& rgbaOut) const -//{ -// const CaretMappableDataFile* mapFile = getAsCaretMappableDataFile(); -// CaretAssert(mapFile); -// -// bool useMapFileHelperFlag = false; -// bool useMatrixFileHelperFlag = false; -// -// std::vector parcelReorderedRowIndices; -// -// switch (mapFile->getDataFileType()) { -// case DataFileTypeEnum::CONNECTIVITY_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: -// break; -// case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL: -// { -// useMatrixFileHelperFlag = true; -// -// const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(mapFile); -// CaretAssert(parcelConnFile); -// if (parcelConnFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(mapFile); -// CaretAssert(parcelLabelFile); -// if (parcelLabelFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: -// { -// useMapFileHelperFlag = true; -// -// const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(mapFile); -// CaretAssert(parcelScalarFile); -// if (parcelScalarFile != NULL) { -// CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; -// int32_t parcelLabelFileMapIndex = -1; -// bool reorderingEnabledFlag = false; -// -// std::vector parcelLabelFiles; -// parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, -// parcelLabelReorderingFile, -// parcelLabelFileMapIndex, -// reorderingEnabledFlag); -// -// if (reorderingEnabledFlag) { -// const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, -// parcelLabelFileMapIndex); -// if (parcelReordering != NULL) { -// parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); -// } -// } -// } -// } -// break; -// case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: -// break; -// case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: -// useMatrixFileHelperFlag = true; -// break; -// case DataFileTypeEnum::ANNOTATION: -// break; -// case DataFileTypeEnum::BORDER: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: -// break; -// case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: -// break; -// case DataFileTypeEnum::FOCI: -// break; -// case DataFileTypeEnum::IMAGE: -// break; -// case DataFileTypeEnum::LABEL: -// break; -// case DataFileTypeEnum::METRIC: -// break; -// case DataFileTypeEnum::PALETTE: -// break; -// case DataFileTypeEnum::RGBA: -// break; -// case DataFileTypeEnum::SCENE: -// break; -// case DataFileTypeEnum::SPECIFICATION: -// break; -// case DataFileTypeEnum::SURFACE: -// break; -// case DataFileTypeEnum::UNKNOWN: -// break; -// case DataFileTypeEnum::VOLUME: -// break; -// } -// -// if (( ! useMapFileHelperFlag) -// && ( ! useMatrixFileHelperFlag)) { -// CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); -// return false; -// } -// -// const CiftiMappableDataFile* ciftiMapFile = getAsCiftiMappableDataFile(); -// CaretAssert(ciftiMapFile); -// -// -// bool validDataFlag = false; -// if (useMapFileHelperFlag) { -// CaretAssertToDoFatal(); -//// validDataFlag = ciftiMapFile->helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, -//// numberOfColumnsOut, -//// parcelReorderedRowIndices, -//// rgbaOut); -// } -// else if (useMatrixFileHelperFlag) { -// CaretAssertToDoFatal(); -//// validDataFlag = ciftiMapFile->helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, -//// numberOfColumnsOut, -//// parcelReorderedRowIndices, -//// rgbaOut); -// } -// switch (m_matrixContentType) { -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: -// break; -// case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: -// break; -// } -// -// return validDataFlag; -//} - diff --git a/src/Files/ChartableTwoFileDelegate.h b/src/Files/ChartableTwoFileDelegate.h index 428338afa..ab0947b8a 100644 --- a/src/Files/ChartableTwoFileDelegate.h +++ b/src/Files/ChartableTwoFileDelegate.h @@ -31,11 +31,9 @@ namespace caret { class CaretMappableDataFile; - //class ChartTwoDataCartesianHistory; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; - class CiftiMappableDataFile; class ChartableTwoFileDelegate : public CaretObjectTracksModification, public SceneableInterface { @@ -89,47 +87,6 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; - /* IMPLEMENT ABOVE NON-VIRTUAL METHODS USING THE VIRTUAL METHODS */ - - /* METHODS NO LONGER NEEDED ??? */ - -// CiftiMappableDataFile* getAsCiftiMappableDataFile(); -// -// const CiftiMappableDataFile* getAsCiftiMappableDataFile() const; -// -// -// ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; -// -// ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; -// -// ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; -// -// void getTwoMatrixDimensions(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut) const; -// -// bool getTwoMatrixDataRGBA(int32_t& numberOfRowsOut, -// int32_t& numberOfColumnsOut, -// std::vector& rgbaOut) const; - -// /** -// * @return Is line series charting enabled for this file in the given tab? -// */ -// virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const = 0; -// -// /** -// * Set charting enabled for this file in the given tab -// * -// * @param enabled -// * New status for charting enabled. -// */ -// virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, -// const bool enabled) = 0; - - /** - * @return Charting history if this file charts to lines. - */ - //virtual ChartTwoDataCartesianHistory* getLineSeriesChartingHistory() = 0; - // ADD_NEW_METHODS_HERE private: @@ -148,11 +105,6 @@ namespace caret { std::unique_ptr m_matrixCharting; -// const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; -// -// const ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; -// -// const ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 1c74b2ea0..d97a40e80 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -174,8 +174,7 @@ ChartableTwoFileLineSeriesChart::receiveEvent(Event* event) const std::vector tabIndicesForLoading = getTabIndicesForLoadingData(lineSeriesDataEvent->getValidTabIndices()); if ( ! tabIndicesForLoading.empty()) { - loadLineCharts(tabIndicesForLoading, - lineSeriesDataEvent); + loadLineCharts(lineSeriesDataEvent); } } @@ -187,14 +186,13 @@ ChartableTwoFileLineSeriesChart::receiveEvent(Event* event) } /** - * @param tabIndicesForLoading - * Tab indices for loading data. + * Load line-series charts. + * * @param lineSeriesDataEvent * Event indicating data for loading. */ void -ChartableTwoFileLineSeriesChart::loadLineCharts(const std::vector& tabIndicesForLoading, - const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent) +ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent) { const MapFileDataSelector mapFileDataSelector = lineSeriesDataEvent->getMapFileDataSelector(); diff --git a/src/Files/ChartableTwoFileLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h index 542fe6030..ce13d036f 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -69,8 +69,7 @@ namespace caret { const SceneClass* sceneClass) override; private: - void loadLineCharts(const std::vector& tabIndicesForLoading, - const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent); + void loadLineCharts(const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent); ChartableTwoFileLineSeriesChart(const ChartableTwoFileLineSeriesChart&); diff --git a/src/Files/CiftiParcelScalarFile.cxx b/src/Files/CiftiParcelScalarFile.cxx index 9ba5844ba..3c47df0ee 100644 --- a/src/Files/CiftiParcelScalarFile.cxx +++ b/src/Files/CiftiParcelScalarFile.cxx @@ -164,41 +164,6 @@ CiftiParcelScalarFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; - -// ChartDataCartesian* chartData = NULL; -// -// try { -// std::vector data; -// if (getSeriesDataForSurfaceNode(structure, -// nodeIndex, -// data)) { -// const int64_t numData = static_cast(data.size()); -// -// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); -// for (int64_t i = 0; i < numData; i++) { -// float xValue = i; -// chartData->addPoint(xValue, -// data[i]); -// } -// -// const AString description = (getFileNameNoPath() -// + " node " -// + AString::number(nodeIndex)); -// chartData->setDescription(description); -// } -// } -// catch (const DataFileException& dfe) { -// if (chartData != NULL) { -// delete chartData; -// chartData = NULL; -// } -// -// throw dfe; -// } -// -// return chartData; } /** diff --git a/src/Files/CiftiParcelSeriesFile.cxx b/src/Files/CiftiParcelSeriesFile.cxx index f8a09ae08..473b2fae8 100644 --- a/src/Files/CiftiParcelSeriesFile.cxx +++ b/src/Files/CiftiParcelSeriesFile.cxx @@ -140,97 +140,6 @@ CiftiParcelSeriesFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; - -// ChartDataCartesian* chartData = NULL; -// -// try { -// std::vector data; -// if (getSeriesDataForSurfaceNode(structure, -// nodeIndex, -// data)) { -// const int64_t numData = static_cast(data.size()); -// -// bool timeSeriesFlag = false; -// bool dataSeriesFlag = false; -// float convertTimeToSeconds = 1.0; -// switch (getMapIntervalUnits()) { -// case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: -// timeSeriesFlag = true; -// convertTimeToSeconds = 1000.0; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: -// convertTimeToSeconds = 1.0; -// timeSeriesFlag = true; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: -// dataSeriesFlag = true; -// break; -// case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: -// convertTimeToSeconds = 1000000.0; -// timeSeriesFlag = true; -// break; -// } -// -// if (dataSeriesFlag) { -// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); -// } -// else if (timeSeriesFlag) { -// chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, -// ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); -// } -// -// if (chartData != NULL) { -// float timeStart = 0.0; -// float timeStep = 1.0; -// if (timeSeriesFlag) { -// getMapIntervalStartAndStep(timeStart, -// timeStep); -// timeStart *= convertTimeToSeconds; -// timeStep *= convertTimeToSeconds; -// chartData->setTimeStartInSecondsAxisX(timeStart); -// chartData->setTimeStepInSecondsAxisX(timeStep); -// } -// -// for (int64_t i = 0; i < numData; i++) { -// float xValue = i; -// -// if (timeSeriesFlag) { -// xValue = timeStart + (i * timeStep); -// } -// -// chartData->addPoint(xValue, -// data[i]); -// } -// -// const AString description = (getFileNameNoPath() -// + " node " -// + AString::number(nodeIndex)); -// chartData->setDescription(description); -// } -// else { -// const AString msg = "New type of units for data series flag, needs updating for charting"; -// CaretAssertMessage(0, msg); -// throw DataFileException(msg); -// } -// } -// } -// catch (const DataFileException& dfe) { -// if (chartData != NULL) { -// delete chartData; -// chartData = NULL; -// } -// -// throw dfe; -// } -// -// return chartData; } /** diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index ba245ab3b..a68911a9a 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -309,11 +309,6 @@ CiftiScalarDataSeriesFile::getMatrixCellAttributes(const int32_t rowIndex, columnNameOut = (AString::number(time, 'f', 3) + " " + timeUnitsString); -// columnNameOut = (AString::number(time, 'f', 3) -// + " " -// + NiftiTimeUnitsEnum::toGuiName(getMapIntervalUnits()) -// + " Map Name: " -// + getMapName(columnIndex)); const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); std::vector rowData(numberOfElementsInRow); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 86315f03f..86fa695ab 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -117,65 +117,8 @@ BrainBrowserWindowToolBarChartTwoAttributes::updateContent(BrowserTabContent* br } } } - -// ChartModelCartesian* cartesianChart = getCartesianChart(); -// ChartTwoMatrixDisplayProperties* matrixProperties = getChartableMatrixDisplayProperties(); -// -// if (cartesianChart != NULL) { -// m_stackedWidget->setCurrentWidget(m_cartesianChartAttributesWidget); -// m_cartesianChartAttributesWidget->updateContent(); -// m_stackedWidget->setEnabled(true); -// } -// else if (matrixProperties) { -// m_stackedWidget->setCurrentWidget(m_matrixChartAttributesWidget); -// m_matrixChartAttributesWidget->updateContent(); -// m_stackedWidget->setEnabled(true); -// } -// else { -// m_stackedWidget->setEnabled(false); -// } } -///** -// * @return Cartesian chart in this widget. Returned value will -// * be NULL if the chart (or no chart) is not a Cartesian Chart. -// */ -//ChartModelCartesian* -//BrainBrowserWindowToolBarChartTwoAttributes::getCartesianChart() -//{ -// ChartModelCartesian* cartesianChart = NULL; -// -// BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); -// if (browserTabContent != NULL) { -// ModelChart* modelChart = browserTabContent->getDisplayedChartModel(); -// -// if (modelChart != NULL) { -// const int32_t tabIndex = browserTabContent->getTabNumber(); -// const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); -// -// switch (chartType) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); -// break; -// } -// } -// } -// -// return cartesianChart; -//} - /** * @return Matrix chart interface in this widget. Returned value will * be NULL if the chart (or no chart) is not a Matrix Chart. @@ -188,42 +131,6 @@ BrainBrowserWindowToolBarChartTwoAttributes::getChartableTwoMatrixDisplayPropert BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { matrixDisplayProperties = browserTabContent->getChartTwoMatrixDisplayProperties(); -// -// if (modelChart != NULL) { -// const int32_t tabIndex = browserTabContent->getTabNumber(); -// const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); -// -// switch (chartType) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// { -// ChartableMatrixInterface* matrixInterface = modelChart->getChartableMatrixParcelFileSelectionModel(tabIndex)->getSelectedFileOfType(); -// if (matrixInterface != NULL) { -// matrixDisplayProperties = matrixInterface->getChartTwoMatrixDisplayProperties(tabIndex); -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// { -// CaretDataFileSelectionModel* fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(tabIndex); -// CaretDataFile* caretFile = fileModel->getSelectedFile(); -// if (caretFile != NULL) { -// ChartableMatrixInterface* matrixInterface = dynamic_cast(caretFile); -// if (matrixInterface != NULL) { -// matrixDisplayProperties = matrixInterface->getChartTwoMatrixDisplayProperties(tabIndex); -// } -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// break; -// } -// } } return matrixDisplayProperties; @@ -294,12 +201,6 @@ CartesianChartTwoAttributesWidget::~CartesianChartTwoAttributesWidget() void CartesianChartTwoAttributesWidget::updateContent() { -// ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); -// if (chart != NULL) { -// m_cartesianLineWidthDoubleSpinBox->blockSignals(true); -// m_cartesianLineWidthDoubleSpinBox->setValue(chart->getLineWidth()); -// m_cartesianLineWidthDoubleSpinBox->blockSignals(false); -// } } /** @@ -309,14 +210,8 @@ CartesianChartTwoAttributesWidget::updateContent() * New value for line width. */ void -CartesianChartTwoAttributesWidget::cartesianLineWidthValueChanged(double value) +CartesianChartTwoAttributesWidget::cartesianLineWidthValueChanged(double /*value*/) { -// ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); -// if (chart != NULL) { -// chart->setLineWidth(value); -// -// m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); -// } } @@ -353,7 +248,8 @@ EventListenerInterface() 1, this, SLOT(valueChanged())); - m_cellWidthPercentageSpinBox->setKeyboardTracking(true); + m_cellWidthPercentageSpinBox->setToolTip("Percentage of tab width filled with matrix"); + m_cellWidthPercentageSpinBox->setKeyboardTracking(false); m_cellWidthPercentageSpinBox->setSuffix("%"); QLabel* cellHeightLabel = new QLabel("Cell Height"); @@ -363,19 +259,22 @@ EventListenerInterface() 1, this, SLOT(valueChanged())); - m_cellHeightPercentageSpinBox->setKeyboardTracking(true); + m_cellHeightPercentageSpinBox->setToolTip("Percentage of tab height filled with matrix"); + m_cellHeightPercentageSpinBox->setKeyboardTracking(false); m_cellHeightPercentageSpinBox->setSuffix("%"); WuQtUtilities::matchWidgetWidths(m_cellHeightPercentageSpinBox, m_cellWidthPercentageSpinBox); m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); + m_highlightSelectionCheckBox->setToolTip("Highlight selected row/column in the matrix"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); + m_displayGridLinesCheckBox->setToolTip("Outline cells in the matrix"); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthPercentageSpinBox); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 132166970..2d266f9cb 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -77,7 +77,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra : BrainBrowserWindowToolBarComponent(parentToolBar) { m_axisDisplayedByUserCheckBox = new QCheckBox("Show Axis"); - m_axisDisplayedByUserCheckBox->setToolTip("Show/Hide the axis"); + m_axisDisplayedByUserCheckBox->setToolTip("Show/hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); @@ -98,13 +98,13 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QObject::connect(m_axisNameToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); - m_axisNameToolButton->setToolTip("Edit name lable displayed in axis"); + m_axisNameToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); m_autoUserRangeComboBox->setup(); QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); - m_autoUserRangeComboBox->getWidget()->setToolTip("Choose auto or user axis scaling"); + m_autoUserRangeComboBox->getWidget()->setToolTip("Choose auto or user axis range scaling"); const double bigValue = 999999.0; m_userMinimumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); @@ -124,6 +124,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QLabel* axisTitleFromOverlayLabel = new QLabel("Title From File In"); m_axisTitleFromOverlayComboBox = new QComboBox(); + m_axisTitleFromOverlayComboBox->setToolTip("Title for axis is from file in selected layer"); QObject::connect(m_axisTitleFromOverlayComboBox, static_cast(&QComboBox::activated), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); @@ -469,7 +470,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser } else if (overlayCount > comboBoxCount) { for (int32_t j = comboBoxCount; j < overlayCount; j++) { - m_axisTitleFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); + m_axisTitleFromOverlayComboBox->addItem("Layer " + AString::number(j + 1)); } } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index f3c10f9d0..64bc19f70 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -105,7 +105,7 @@ m_chartOverlay(NULL) m_enabledCheckBox = new QCheckBox(enabledCheckboxText); QObject::connect(m_enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); - m_enabledCheckBox->setToolTip("Enables display of this layer"); + m_enabledCheckBox->setToolTip("Display line charts from the selected file"); /* * Line Series Enabled Check Box @@ -114,7 +114,7 @@ m_chartOverlay(NULL) m_lineSeriesLoadingEnabledCheckBox = new QCheckBox(loadingCheckboxText); QObject::connect(m_lineSeriesLoadingEnabledCheckBox, &QCheckBox::clicked, this, &ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked); - m_lineSeriesLoadingEnabledCheckBox->setToolTip("Enabled loading of line charts for this overlay"); + m_lineSeriesLoadingEnabledCheckBox->setToolTip("Enable loading of line charts for the selected file"); /* * Settings Tool Button @@ -175,7 +175,7 @@ m_chartOverlay(NULL) */ m_historyToolButton = new QToolButton(); m_historyAction = WuQtUtilities::createAction("H", - "Show history for line chart file", + "Show history of line charts loaded from selected file", this, this, SLOT(historyActionTriggered(bool))); @@ -187,7 +187,7 @@ m_chartOverlay(NULL) * Matrix triangular view mode button */ m_matrixTriangularViewModeAction = WuQtUtilities::createAction("M", - "Matrix triangular view", + "Select a triangular view of the matrix", this); m_matrixTriangularViewModeToolButton = new QToolButton(); QMenu* matrixTriangularViewModeMenu = createMatrixTriangularViewModeMenu(m_matrixTriangularViewModeToolButton); @@ -200,7 +200,7 @@ m_chartOverlay(NULL) * Axis location button */ m_axisLocationAction = WuQtUtilities::createAction("A", - "Vertical Axis Location", + "Select location of vertical axis for the selected file", this); m_axisLocationToolButton = new QToolButton(); QMenu* axisLocationMenu = createAxisLocationMenu(m_axisLocationToolButton); -- GitLab From bef97a3ee9e6e8cf59210884b2585726c32db049 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 3 Jul 2017 12:55:27 -0500 Subject: [PATCH 314/755] For charting two's axix units type, replaced usage of older ChartAxisUnitsEnum with new CaretUnitsTypeEnum. CaretUnitsTypeEnum supports all unit types in both NiftiTimeUnitsEnum and CiftiSeriesMap. Also corrected order of line-series history from scene and added ability to select rows in scalar data series files. --- src/Brain/ChartTwoOverlaySet.cxx | 12 +- src/Charting/ChartTwoCartesianAxis.cxx | 6 +- src/Charting/ChartTwoCartesianAxis.h | 8 +- src/Charting/ChartTwoCompoundDataType.cxx | 18 +- src/Charting/ChartTwoCompoundDataType.h | 10 +- src/Charting/ChartTwoDataCartesian.cxx | 12 +- src/Charting/ChartTwoDataCartesian.h | 14 +- src/Charting/ChartTwoLineSeriesHistory.cxx | 6 +- src/Common/CMakeLists.txt | 2 + src/Common/CaretUnitsTypeEnum.cxx | 389 ++++++++++++++++++ src/Common/CaretUnitsTypeEnum.h | 112 +++++ src/Files/ChartableTwoFileBaseChart.cxx | 17 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 30 +- src/Files/ChartableTwoFileMatrixChart.cxx | 1 + 14 files changed, 573 insertions(+), 64 deletions(-) create mode 100644 src/Common/CaretUnitsTypeEnum.cxx create mode 100644 src/Common/CaretUnitsTypeEnum.h diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 92ebfdaed..50baf48e0 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -87,39 +87,39 @@ m_tabIndex(tabIndex) case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { m_chartAxisLeft->setEnabledByChart(true); - m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); float rangeMin = 0.0, rangeMax = 0.0; m_chartAxisLeft->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); - m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); - m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { m_chartAxisLeft->setEnabledByChart(true); - m_chartAxisLeft->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); float rangeMin = 0.0, rangeMax = 0.0; m_chartAxisLeft->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); - m_chartAxisRight->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); m_chartAxisRight->getRange(rangeMin, rangeMax); rangeMin = 0.0; m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); - m_chartAxisBottom->setUnits(ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); + m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 7bc8f84d1..a7906dc2f 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -73,7 +73,7 @@ m_axisLocation(axisLocation) m_sceneAssistant->add("m_scaleRangeMode", &m_scaleRangeMode); - m_sceneAssistant->add("m_units", + m_sceneAssistant->add("m_units", &m_units); m_sceneAssistant->add("m_userNumericFormat", &m_userNumericFormat); @@ -399,7 +399,7 @@ ChartTwoCartesianAxis::setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::E /** * @return Axis units */ -ChartAxisUnitsEnum::Enum +CaretUnitsTypeEnum::Enum ChartTwoCartesianAxis::getUnits() const { return m_units; @@ -412,7 +412,7 @@ ChartTwoCartesianAxis::getUnits() const * New value for Axis units */ void -ChartTwoCartesianAxis::setUnits(const ChartAxisUnitsEnum::Enum units) +ChartTwoCartesianAxis::setUnits(const CaretUnitsTypeEnum::Enum units) { m_units = units; } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 697068834..2c455e879 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -25,7 +25,7 @@ #include "CaretObject.h" #include "ChartAxisLocationEnum.h" -#include "ChartAxisUnitsEnum.h" +#include "CaretUnitsTypeEnum.h" #include "ChartTwoAxisScaleRangeModeEnum.h" #include "ChartTwoNumericSubdivisionsModeEnum.h" #include "NumericFormatModeEnum.h" @@ -74,9 +74,9 @@ namespace caret { void setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode); - ChartAxisUnitsEnum::Enum getUnits() const; + CaretUnitsTypeEnum::Enum getUnits() const; - void setUnits(ChartAxisUnitsEnum::Enum units); + void setUnits(CaretUnitsTypeEnum::Enum units); NumericFormatModeEnum::Enum getUserNumericFormat() const; @@ -167,7 +167,7 @@ namespace caret { ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; - ChartAxisUnitsEnum::Enum m_units = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + CaretUnitsTypeEnum::Enum m_units = CaretUnitsTypeEnum::NONE; NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index a29935384..d3eea9535 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -58,7 +58,7 @@ using namespace caret; */ ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t histogramNumberOfBuckets, - const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX, const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns) @@ -101,7 +101,7 @@ ChartTwoCompoundDataType::newInstanceForHistogram(const int32_t histogramNumberO { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, histogramNumberOfBins, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + CaretUnitsTypeEnum::NONE, 0, 0, 0); @@ -116,7 +116,7 @@ ChartTwoCompoundDataType::newInstanceForHistogram(const int32_t histogramNumberO * Line chart x-axis number of elements. */ ChartTwoCompoundDataType -ChartTwoCompoundDataType::newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, +ChartTwoCompoundDataType::newInstanceForLineSeries(const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, @@ -141,7 +141,7 @@ ChartTwoCompoundDataType::newInstanceForMatrix(const int32_t matrixNumberOfRows, { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, 0, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + CaretUnitsTypeEnum::NONE, 0, matrixNumberOfRows, matrixNumberOfColumns); @@ -198,8 +198,8 @@ ChartTwoCompoundDataType::copyHelperChartTwoCompoundDataType(const ChartTwoCompo void ChartTwoCompoundDataType::initializeChartTwoCompoundDataType() { - m_chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; - m_lineChartUnitsAxisX = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + m_chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + m_lineChartUnitsAxisX = CaretUnitsTypeEnum::NONE; m_lineChartNumberOfElementsAxisX = 0; m_matrixNumberOfRows = 0; m_matrixNumberOfColumns = 0; @@ -207,7 +207,7 @@ ChartTwoCompoundDataType::initializeChartTwoCompoundDataType() m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartDataType", &m_chartDataType); - m_sceneAssistant->add("m_lineChartUnitsAxisX", + m_sceneAssistant->add("m_lineChartUnitsAxisX", &m_lineChartUnitsAxisX); m_sceneAssistant->add("m_lineChartNumberOfElementsAxisX", &m_lineChartNumberOfElementsAxisX); @@ -288,7 +288,7 @@ ChartTwoCompoundDataType::getHistogramNumberOfBuckets() const /** * @return Line chart X-axis units. */ -ChartAxisUnitsEnum::Enum +CaretUnitsTypeEnum::Enum ChartTwoCompoundDataType::getLineChartUnitsAxisX() const { return m_lineChartUnitsAxisX; @@ -343,7 +343,7 @@ ChartTwoCompoundDataType::toString() const case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: text.appendWithNewLine(indent + "x=units=" - + ChartAxisUnitsEnum::toName(m_lineChartUnitsAxisX)); + + CaretUnitsTypeEnum::toName(m_lineChartUnitsAxisX)); text.appendWithNewLine(indent + "x-elements=" + AString::number(m_lineChartNumberOfElementsAxisX)); diff --git a/src/Charting/ChartTwoCompoundDataType.h b/src/Charting/ChartTwoCompoundDataType.h index fa5586f87..5463afa7d 100644 --- a/src/Charting/ChartTwoCompoundDataType.h +++ b/src/Charting/ChartTwoCompoundDataType.h @@ -23,7 +23,7 @@ #include "CaretObject.h" -#include "ChartAxisUnitsEnum.h" +#include "CaretUnitsTypeEnum.h" #include "ChartTwoDataTypeEnum.h" #include "SceneableInterface.h" @@ -38,14 +38,14 @@ namespace caret { ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t histogramNumberOfBuckets, - const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX, const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns); static ChartTwoCompoundDataType newInstanceForHistogram(const int32_t histogramNumberOfBuckets); - static ChartTwoCompoundDataType newInstanceForLineSeries(const ChartAxisUnitsEnum::Enum lineChartUnitsAxisX, + static ChartTwoCompoundDataType newInstanceForLineSeries(const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX); static ChartTwoCompoundDataType newInstanceForMatrix(const int32_t matrixNumberOfRows, @@ -64,7 +64,7 @@ namespace caret { int32_t getHistogramNumberOfBuckets() const; - ChartAxisUnitsEnum::Enum getLineChartUnitsAxisX() const; + CaretUnitsTypeEnum::Enum getLineChartUnitsAxisX() const; int32_t getLineChartNumberOfElementsAxisX() const; @@ -108,7 +108,7 @@ namespace caret { int32_t m_histogramNumberOfBuckets; - ChartAxisUnitsEnum::Enum m_lineChartUnitsAxisX; + CaretUnitsTypeEnum::Enum m_lineChartUnitsAxisX; int32_t m_lineChartNumberOfElementsAxisX; diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index d9d5fbf64..214ec2242 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -59,8 +59,8 @@ using namespace caret; * Primitive type for graphics primitive drawing. */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum dataAxisUnitsX, - const ChartAxisUnitsEnum::Enum dataAxisUnitsY, + const CaretUnitsTypeEnum::Enum dataAxisUnitsX, + const CaretUnitsTypeEnum::Enum dataAxisUnitsY, const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType) : CaretObjectTracksModification(), m_dataAxisUnitsX(dataAxisUnitsX), @@ -135,9 +135,9 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() m_sceneAssistant->add("m_selectionStatus", &m_selectionStatus); - m_sceneAssistant->add("m_dataAxisUnitsX", + m_sceneAssistant->add("m_dataAxisUnitsX", &m_dataAxisUnitsX); - m_sceneAssistant->add("m_dataAxisUnitsY", + m_sceneAssistant->add("m_dataAxisUnitsY", &m_dataAxisUnitsY); m_sceneAssistant->add("m_color", &m_color); @@ -375,7 +375,7 @@ ChartTwoDataCartesian::setTimeStepInSecondsAxisX(const float timeStepInSecondsAx /** * @return Data units for X axis */ -ChartAxisUnitsEnum::Enum +CaretUnitsTypeEnum::Enum ChartTwoDataCartesian::getDataAxisUnitsX() { return m_dataAxisUnitsX; @@ -384,7 +384,7 @@ ChartTwoDataCartesian::getDataAxisUnitsX() /** * @return Data units for Y axis */ -ChartAxisUnitsEnum::Enum +CaretUnitsTypeEnum::Enum ChartTwoDataCartesian::getDataAxisUnitsY() { return m_dataAxisUnitsY; diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index 9a1d16d04..8460d3876 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -23,7 +23,7 @@ #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" -#include "ChartAxisUnitsEnum.h" +#include "CaretUnitsTypeEnum.h" #include "ChartTwoDataTypeEnum.h" #include "GraphicsPrimitive.h" #include "SceneableInterface.h" @@ -40,8 +40,8 @@ namespace caret { public: ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, - const ChartAxisUnitsEnum::Enum dataAxisUnitsX, - const ChartAxisUnitsEnum::Enum dataAxisUnitsY, + const CaretUnitsTypeEnum::Enum dataAxisUnitsX, + const CaretUnitsTypeEnum::Enum dataAxisUnitsY, const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType); virtual ~ChartTwoDataCartesian(); @@ -63,9 +63,9 @@ namespace caret { void setMapFileDataSelector(const MapFileDataSelector& mapFileDataSelector); - ChartAxisUnitsEnum::Enum getDataAxisUnitsX(); + CaretUnitsTypeEnum::Enum getDataAxisUnitsX(); - ChartAxisUnitsEnum::Enum getDataAxisUnitsY(); + CaretUnitsTypeEnum::Enum getDataAxisUnitsY(); CaretColorEnum::Enum getColor() const; @@ -114,9 +114,9 @@ namespace caret { std::unique_ptr m_graphicsPrimitive; - ChartAxisUnitsEnum::Enum m_dataAxisUnitsX; + CaretUnitsTypeEnum::Enum m_dataAxisUnitsX; - ChartAxisUnitsEnum::Enum m_dataAxisUnitsY; + CaretUnitsTypeEnum::Enum m_dataAxisUnitsY; const GraphicsPrimitive::PrimitiveType m_graphicsPrimitiveType; diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 9763a288e..f99c9fb2b 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -470,11 +470,11 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut if (chartHistoryMap != NULL) { const std::vector indices = chartHistoryMap->getKeys(); const int32_t numIndices = static_cast(indices.size()); - for (int32_t i = 0; i < numIndices; i++) { + for (int32_t i = (numIndices - 1); i >= 0; i--) { const SceneClass* historyClass = chartHistoryMap->classValue(i); ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + CaretUnitsTypeEnum::NONE, + CaretUnitsTypeEnum::NONE, GraphicsPrimitive::PrimitiveType::LINES); historyItem->restoreFromScene(sceneAttributes, historyClass); diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index b9b06d47a..dec3db174 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -80,6 +80,7 @@ CaretPreferences.h CaretTemporaryFile.h CaretUndoCommand.h CaretUndoStack.h +CaretUnitsTypeEnum.h CubicSpline.h DataCompressZLib.h DataFile.h @@ -179,6 +180,7 @@ CaretPreferences.cxx CaretTemporaryFile.cxx CaretUndoCommand.cxx CaretUndoStack.cxx +CaretUnitsTypeEnum.cxx CubicSpline.cxx DataCompressZLib.cxx DataFile.cxx diff --git a/src/Common/CaretUnitsTypeEnum.cxx b/src/Common/CaretUnitsTypeEnum.cxx new file mode 100644 index 000000000..c4e119642 --- /dev/null +++ b/src/Common/CaretUnitsTypeEnum.cxx @@ -0,0 +1,389 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __CARET_UNITS_TYPE_ENUM_DECLARE__ +#include "CaretUnitsTypeEnum.h" +#undef __CARET_UNITS_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::CaretUnitsTypeEnum + * \brief Units Type + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_caretUnitsTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void caretUnitsTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "CaretUnitsTypeEnum.h" + * + * Instatiate: + * m_caretUnitsTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_caretUnitsTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_caretUnitsTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(caretUnitsTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_caretUnitsTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const CaretUnitsTypeEnum::Enum VARIABLE = m_caretUnitsTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +CaretUnitsTypeEnum::CaretUnitsTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +CaretUnitsTypeEnum::~CaretUnitsTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +CaretUnitsTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(CaretUnitsTypeEnum(NONE, + "NONE", + "None")); + + enumData.push_back(CaretUnitsTypeEnum(HERTZ, + "HERTZ", + "Hertz")); + + enumData.push_back(CaretUnitsTypeEnum(METERS, + "METERS", + "Meters")); + + enumData.push_back(CaretUnitsTypeEnum(PARTS_PER_MILLION, + "PARTS_PER_MILLION", + "Parts Per Million")); + + enumData.push_back(CaretUnitsTypeEnum(RADIANS, + "RADIANS", + "Radians")); + + enumData.push_back(CaretUnitsTypeEnum(SECONDS, + "SECONDS", + "Seconds")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const CaretUnitsTypeEnum* +CaretUnitsTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const CaretUnitsTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +CaretUnitsTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const CaretUnitsTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +CaretUnitsTypeEnum::Enum +CaretUnitsTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const CaretUnitsTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type CaretUnitsTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +CaretUnitsTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const CaretUnitsTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +CaretUnitsTypeEnum::Enum +CaretUnitsTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const CaretUnitsTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type CaretUnitsTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +CaretUnitsTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const CaretUnitsTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +CaretUnitsTypeEnum::Enum +CaretUnitsTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const CaretUnitsTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type CaretUnitsTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +CaretUnitsTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +CaretUnitsTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(CaretUnitsTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +CaretUnitsTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(CaretUnitsTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/CaretUnitsTypeEnum.h b/src/Common/CaretUnitsTypeEnum.h new file mode 100644 index 000000000..7fee53530 --- /dev/null +++ b/src/Common/CaretUnitsTypeEnum.h @@ -0,0 +1,112 @@ +#ifndef __CARET_UNITS_TYPE_ENUM_H__ +#define __CARET_UNITS_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class CaretUnitsTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** none/unknown */ + NONE, + /** Hertz (frequency) */ + HERTZ, + /** Meters */ + METERS, + /** Parts per million */ + PARTS_PER_MILLION, + /** radians */ + RADIANS, + /** seconds */ + SECONDS + }; + + + ~CaretUnitsTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + CaretUnitsTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const CaretUnitsTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __CARET_UNITS_TYPE_ENUM_DECLARE__ +std::vector CaretUnitsTypeEnum::enumData; +bool CaretUnitsTypeEnum::initializedFlag = false; +int32_t CaretUnitsTypeEnum::integerCodeCounter = 0; +#endif // __CARET_UNITS_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__CARET_UNITS_TYPE_ENUM_H__ diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 55395a4d7..832b58e2d 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -160,15 +160,20 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t title = "Data"; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + title = CaretUnitsTypeEnum::toGuiName(m_compoundChartDataType.getLineChartUnitsAxisX()); switch (m_compoundChartDataType.getLineChartUnitsAxisX()) { - case ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ: - title = "Hertz"; - break; - case ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE: + case CaretUnitsTypeEnum::NONE: title = "Data"; break; - case ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS: - title = "Seconds"; + case CaretUnitsTypeEnum::HERTZ: + break; + case CaretUnitsTypeEnum::METERS: + break; + case CaretUnitsTypeEnum::PARTS_PER_MILLION: + break; + case CaretUnitsTypeEnum::RADIANS: + break; + case CaretUnitsTypeEnum::SECONDS: break; } break; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index d97a40e80..91ec86b27 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -56,7 +56,7 @@ m_lineSeriesContentType(lineSeriesContentType) { m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); - ChartAxisUnitsEnum::Enum xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + CaretUnitsTypeEnum::Enum xAxisUnits = CaretUnitsTypeEnum::NONE; int32_t xAxisNumberOfElements = 0; CaretMappableDataFile* cmdf = getCaretMappableDataFile(); @@ -68,22 +68,22 @@ m_lineSeriesContentType(lineSeriesContentType) case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: if (cmdf->getNumberOfMaps() > 1) { const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + xAxisUnits = CaretUnitsTypeEnum::NONE; switch (mapUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + xAxisUnits = CaretUnitsTypeEnum::HERTZ; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: - CaretAssert(0); + xAxisUnits = CaretUnitsTypeEnum::PARTS_PER_MILLION; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; @@ -104,22 +104,22 @@ m_lineSeriesContentType(lineSeriesContentType) if ((numRows > 0) && (numCols > 1)) { const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; + xAxisUnits = CaretUnitsTypeEnum::NONE; switch (mapUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ; + xAxisUnits = CaretUnitsTypeEnum::HERTZ; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: - CaretAssert(0); + xAxisUnits = CaretUnitsTypeEnum::PARTS_PER_MILLION; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - xAxisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS; + xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; @@ -261,11 +261,11 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie getCaretMappableDataFile()->getDataForSelector(mapFileDataSelector, data); if ( ! data.empty()) { - const ChartAxisUnitsEnum::Enum xUnits = getChartTwoCompoundDataType().getLineChartUnitsAxisX(); + const CaretUnitsTypeEnum::Enum xUnits = getChartTwoCompoundDataType().getLineChartUnitsAxisX(); CaretAssert(getChartTwoCompoundDataType().getLineChartNumberOfElementsAxisX() == static_cast(data.size())); ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, xUnits, - ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, + CaretUnitsTypeEnum::NONE, GraphicsPrimitive::PrimitiveType::LINES); cartesianData->setMapFileDataSelector(mapFileDataSelector); diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 032aed803..6a35d725d 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -186,6 +186,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) case MatrixDataFileType::SCALAR_DATA_SERIES: m_scalarDataSeriesFile = dynamic_cast(ciftiMapFile); CaretAssert(m_scalarDataSeriesFile); + m_hasRowSelectionFlag = true; break; } -- GitLab From f48e5433861e97da08ca6f4edac75a87c7b81c4f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Jul 2017 08:44:36 -0500 Subject: [PATCH 315/755] Additional cleanup of charting code that includes removing unused code and fixing a few 'narrowing' compilation warnings. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 8 +- src/Brain/BrainOpenGLPrimitiveDrawing.cxx | 6 +- src/Brain/ModelChart.cxx | 2 +- src/Brain/ModelChartTwo.cxx | 204 +----------------- src/Brain/ModelChartTwo.h | 15 -- src/Files/GiftiTypeFile.cxx | 2 +- src/Graphics/GraphicsEngineData.cxx | 2 +- src/GuiQt/AnnotationCoordinateInformation.cxx | 18 +- src/GuiQt/SceneDialog.cxx | 10 +- 9 files changed, 26 insertions(+), 241 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index ccc79c601..02830f537 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1027,10 +1027,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT uint8_t highlightRGBByte[3]; m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); const float highlightRGBA[4] = { - highlightRGBByte[0] / 255.0, - highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0, - 1.0 + highlightRGBByte[0] / 255.0f, + highlightRGBByte[1] / 255.0f, + highlightRGBByte[2] / 255.0f, + 1.0f }; std::vector selectedColumnIndices; diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx index 195225de4..6c4248e3b 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx @@ -1187,9 +1187,9 @@ BrainOpenGLPrimitiveDrawing::drawRectangleOutline(const float bottomLeft[3], const float height = MathFunctions::distance3D(bottomLeft, topLeft); const float center[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; float normalVector[3]; diff --git a/src/Brain/ModelChart.cxx b/src/Brain/ModelChart.cxx index 5489c35db..dfe24a5a5 100644 --- a/src/Brain/ModelChart.cxx +++ b/src/Brain/ModelChart.cxx @@ -1662,7 +1662,7 @@ ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const * Index of the tab. */ void -ModelChart::updateChartOverlaySets(const int32_t tabIndex) +ModelChart::updateChartOverlaySets(const int32_t /*tabIndex*/) { } diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 150f5494b..2dafb5eaf 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -233,62 +233,6 @@ ModelChartTwo::loadChartDataForVoxelAtCoordinate(const float xyz[3]) EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } -/** - * Load chart data for CIFTI Map files yoked to the given yoking group. - * - * @param mapYokingGroup - * The map yoking group. - * @param mapIndex - * The map index. - */ -void -ModelChartTwo::loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, - const int32_t mapIndex) -{ - if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - return; - } - - CaretAssertToDoWarning(); - -// std::map > chartFileEnabledTabs; -// getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); -// -// for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); -// fileTabIter != chartFileEnabledTabs.end(); -// fileTabIter++) { -// ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; -// CaretAssert(chartFile); -// CiftiScalarDataSeriesFile* csdsf = dynamic_cast(chartFile); -// if (csdsf != NULL) { -// -// std::vector matchedTabIndices; -// const std::vector tabIndices = fileTabIter->second; -// for (std::vector::const_iterator tabIter = tabIndices.begin(); -// tabIter != tabIndices.end(); -// tabIter++) { -// const int32_t tabIndex = *tabIter; -// if (csdsf->getMatrixRowColumnMapYokingGroup(tabIndex) == mapYokingGroup) { -// matchedTabIndices.push_back(tabIndex); -// } -// } -// -// if ( ! matchedTabIndices.empty()) { -// ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(mapIndex); -// if (chartData != NULL) { -// ChartDataSource* dataSource = chartData->getChartDataSource(); -// dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), -// mapIndex); -// -// addChartToChartModels(matchedTabIndices, -// chartData); -// } -// } -// } -// } -} - - /** * Load chart data from given file at the given row. * @@ -465,23 +409,6 @@ ModelChartTwo::initializeOverlays() m_overlaySetArray->initializeOverlaySelections(); } -/** - * Save version two charting information specific to this type of model to the scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * saving the scene. - * - * @param sceneClass - * SceneClass to which model specific information is added. - */ -void -ModelChartTwo::saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) -{ -} - /** * Save information specific to this type of model to the scene. * @@ -493,15 +420,12 @@ ModelChartTwo::saveVersionTwoModelSpecificInformationToScene(const SceneAttribut * @param sceneClass * SceneClass to which model specific information is added. */ -void +void ModelChartTwo::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass) + SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - - saveVersionTwoModelSpecificInformationToScene(sceneAttributes, - sceneClass); } /** @@ -523,31 +447,6 @@ ModelChartTwo::restoreModelSpecificInformationFromScene(const SceneAttributes* s m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); - - restoreVersionTwoModelSpecificInformationFromScene(sceneAttributes, - sceneClass); -} - -/** - * Restore information specific to the type of model from VERSION TWO scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass from which model specific information is obtained. - */ -void -ModelChartTwo::restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - /* - * Restore the chart models - */ - restoreVersionTwoChartModelsFromScene(sceneAttributes, - sceneClass); } /** @@ -914,105 +813,6 @@ ModelChartTwo::restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, } } -/** - * Restore the chart models from a VERSION TWO scene. - * - * @param sceneAttributes - * Attributes for the scene. Scenes may be of different types - * (full, generic, etc) and the attributes should be checked when - * restoring the scene. - * - * @param sceneClass - * sceneClass from which model specific information is obtained. - */ -void -ModelChartTwo::restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass) -{ - /* Probably nothing to do here */ -} - - -/** - * Get a text description of the window's content. - * - * @param tabIndex - * Index of the tab for content description. - * @param descriptionOut - * Description of the window's content. - */ -void -ModelChartTwo::getDescriptionOfContent(const int32_t tabIndex, - PlainTextStringBuilder& descriptionOut) const -{ -// ChartModel* chartModel = NULL; -// switch (getSelectedChartOneDataType(tabIndex)) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// { -// CaretDataFileSelectionModel* sm = m_chartableMatrixFileSelectionModel[tabIndex]; -// const CaretDataFile* caretFile = sm->getSelectedFile(); -// if (caretFile != NULL) { -// descriptionOut.addLine("Matrix (layer) chart for: " -// + caretFile->getFileNameNoPath()); -// return; -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// { -// CaretDataFileSelectionModel* sm = m_chartableMatrixSeriesFileSelectionModel[tabIndex]; -// const CaretDataFile* caretFile = sm->getSelectedFile(); -// if (caretFile != NULL) { -// descriptionOut.addLine("Matrix (series) chart for: " -// + caretFile->getFileNameNoPath()); -// return; -// } -// } -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// chartModel = const_cast(getSelectedDataSeriesChartModel(tabIndex)); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// chartModel = const_cast(getSelectedFrequencySeriesChartModel(tabIndex)); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// chartModel = const_cast(getSelectedTimeSeriesChartModel(tabIndex)); -// break; -// } -// -// const ChartModel* chartModelConst = chartModel; -// -// if (chartModel != NULL) { -// descriptionOut.addLine("Chart Type: " -// + ChartOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); -// -// descriptionOut.pushIndentation(); -// -// const std::vector cdVec = chartModelConst->getAllChartDatas(); -// for (std::vector::const_iterator iter = cdVec.begin(); -// iter != cdVec.end(); -// iter++) { -// const ChartData* cd = *iter; -// if (cd->isSelected(tabIndex)) { -// descriptionOut.addLine(cd->getChartDataSource()->getDescription()); -// } -// } -// -// if (chartModel->isAverageChartDisplaySupported()) { -// if (chartModel->isAverageChartDisplaySelected()) { -// descriptionOut.addLine("Average Chart Displayed"); -// } -// } -// -// descriptionOut.popIndentation(); -// } -// else { -// descriptionOut.addLine("No charts to display"); -// } -} - /** * Copy the tab content from the source tab index to the * destination tab index. diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index 11a2c4bcd..c8d18334d 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -74,9 +74,6 @@ namespace caret { void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); - void loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, - const int32_t mapIndex); - virtual OverlaySet* getOverlaySet(const int tabIndex) override; virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; @@ -94,9 +91,6 @@ namespace caret { void setSelectedChartTwoDataType(const int32_t tabIndex, const ChartTwoDataTypeEnum::Enum dataType); - virtual void getDescriptionOfContent(const int32_t tabIndex, - PlainTextStringBuilder& descriptionOut) const override; - virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) override; @@ -125,20 +119,11 @@ namespace caret { void updateChartOverlaySets(const int32_t tabIndex); - void restoreVersionTwoChartModelsFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - void restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, const int32_t tabIndex); void restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne); - virtual void saveVersionTwoModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, - SceneClass* sceneClass); - - void restoreVersionTwoModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, - const SceneClass* sceneClass); - /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; diff --git a/src/Files/GiftiTypeFile.cxx b/src/Files/GiftiTypeFile.cxx index f5102c1da..2bff347fa 100644 --- a/src/Files/GiftiTypeFile.cxx +++ b/src/Files/GiftiTypeFile.cxx @@ -993,7 +993,7 @@ GiftiTypeFile::addToDataFileContentInformation(DataFileContentInformation& dataF * Output with data. Will be empty if data does not support the map file data selector. */ void -GiftiTypeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, +GiftiTypeFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, std::vector& dataOut) const { dataOut.clear(); diff --git a/src/Graphics/GraphicsEngineData.cxx b/src/Graphics/GraphicsEngineData.cxx index 29be1ed24..b608d779c 100644 --- a/src/Graphics/GraphicsEngineData.cxx +++ b/src/Graphics/GraphicsEngineData.cxx @@ -70,7 +70,7 @@ GraphicsEngineData::toString() const * An event for which this instance is listening. */ void -GraphicsEngineData::receiveEvent(Event* event) +GraphicsEngineData::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index bfe23d248..2c3e1068a 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -587,9 +587,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_modelXYZValid) { float centerXYZ[3] = { - (coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0, - (coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0, - (coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0 + (coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, + (coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, + (coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -653,9 +653,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_tabIndex == coordInfoOne->m_tabIndex) { float centerXYZ[3] = { - (coordInfoOne->m_tabXYZ[0] + optionalCoordInfoTwo->m_tabXYZ[0]) / 2.0, - (coordInfoOne->m_tabXYZ[1] + optionalCoordInfoTwo->m_tabXYZ[1]) / 2.0, - (coordInfoOne->m_tabXYZ[2] + optionalCoordInfoTwo->m_tabXYZ[2]) / 2.0 + (coordInfoOne->m_tabXYZ[0] + optionalCoordInfoTwo->m_tabXYZ[0]) / 2.0f, + (coordInfoOne->m_tabXYZ[1] + optionalCoordInfoTwo->m_tabXYZ[1]) / 2.0f, + (coordInfoOne->m_tabXYZ[2] + optionalCoordInfoTwo->m_tabXYZ[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -677,9 +677,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_windowIndex == coordInfoOne->m_windowIndex) { float centerXYZ[3] = { - (coordInfoOne->m_windowXYZ[0] + optionalCoordInfoTwo->m_windowXYZ[0]) / 2.0, - (coordInfoOne->m_windowXYZ[1] + optionalCoordInfoTwo->m_windowXYZ[1]) / 2.0, - (coordInfoOne->m_windowXYZ[2] + optionalCoordInfoTwo->m_windowXYZ[2]) / 2.0 + (coordInfoOne->m_windowXYZ[0] + optionalCoordInfoTwo->m_windowXYZ[0]) / 2.0f, + (coordInfoOne->m_windowXYZ[1] + optionalCoordInfoTwo->m_windowXYZ[1]) / 2.0f, + (coordInfoOne->m_windowXYZ[2] + optionalCoordInfoTwo->m_windowXYZ[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithWindowCoordsFlag = true; diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 32386550d..9eeae4e2f 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1209,13 +1209,13 @@ SceneDialog::replaceAllScenesPushButtonClicked() * Display the scene */ AString errorMessage; - const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, - origScene, - false, - errorMessage); + displayScenePrivateWithErrorMessage(sceneFile, + origScene, + false, + errorMessage); sceneNames.push_back(origScene->getName()); - /* + /* * Assume scene loads correctly */ Scene* newScene = new Scene(SceneTypeEnum::SCENE_TYPE_FULL); -- GitLab From cd664814c886028e356f1b80067431fb48860173 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Jul 2017 09:13:37 -0500 Subject: [PATCH 316/755] When restoring line-series data from an older 'chart one' scene, find any files with line charts and add them to the chart overlays. --- src/Brain/ModelChartTwo.cxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 2dafb5eaf..539939fe9 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -576,6 +576,8 @@ ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); + std::vector overlayMapFiles; + /* * Find the data files and setup for loading of * lines series data. @@ -597,9 +599,11 @@ ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; if (mapFileFullPath != NULL) { lineSeriesHistory = mapFileFullPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); + overlayMapFiles.push_back(mapFileFullPath); } else if (mapFileNoPath != NULL) { lineSeriesHistory = mapFileNoPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); + overlayMapFiles.push_back(mapFileNoPath); } else { CaretLogWarning("Unable to find data file with name: " @@ -681,6 +685,18 @@ ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne EventManager::get()->sendEvent(loadLineDataEvent.getPointer()); } } + + /* + * Put line-series chart files into chart overlays + */ + const int32_t maxChartOverlays = 3; + const int32_t numChartOverlayMapFiles = std::min(maxChartOverlays, static_cast(overlayMapFiles.size())); + for (auto tabIndex : validTabIndices) { + for (int32_t i = 0; i < numChartOverlayMapFiles; i++) { + CaretAssertVectorIndex(overlayMapFiles, i); + getChartTwoOverlaySet(tabIndex)->getOverlay(i)->setSelectionData(overlayMapFiles[i], 0); + } + } } /** -- GitLab From 564944ed68eff1ada6e2df89017c9e0b6f5abe5b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 5 Jul 2017 16:03:31 -0500 Subject: [PATCH 317/755] Scene files had grown in size due to new charting and changes have been made to reduce the amount of new charting data in the scene file. --- src/Brain/Brain.cxx | 12 ++- src/Brain/CMakeLists.txt | 2 + src/Brain/ChartTwoOverlaySetArray.cxx | 10 +-- src/Brain/ChartTwoOverlaySetArray.h | 10 ++- src/Brain/EventModelGetAllDisplayed.cxx | 79 ++++++++++++++++++ src/Brain/EventModelGetAllDisplayed.h | 62 ++++++++++++++ src/Brain/ModelChartTwo.cxx | 82 +++++++++++++++++-- src/Brain/SessionManager.cxx | 15 ++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 6 +- src/Common/EventTypeEnum.h | 2 + src/Files/CaretMappableDataFile.cxx | 15 +++- src/Files/ChartableTwoFileDelegate.cxx | 4 + src/Files/ChartableTwoFileHistogramChart.cxx | 14 ++-- src/Files/ChartableTwoFileHistogramChart.h | 4 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 4 + src/Files/ChartableTwoFileMatrixChart.cxx | 4 + 17 files changed, 288 insertions(+), 38 deletions(-) create mode 100644 src/Brain/EventModelGetAllDisplayed.cxx create mode 100644 src/Brain/EventModelGetAllDisplayed.h diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 7ae7b0c9d..c878d5e0d 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -73,6 +73,7 @@ #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventModelGetAll.h" +#include "EventModelGetAllDisplayed.h" #include "EventPaletteGetByName.h" #include "EventProgressUpdate.h" #include "EventSpecFileReadDataFiles.h" @@ -6988,16 +6989,13 @@ Brain::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAnnotationFile->clearModified(); /* - * Save all models + * Save all DISPLAYED models */ std::vector modelClassVector; - EventModelGetAll getAllModels; + EventModelGetAllDisplayed getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); - std::vector allModels = getAllModels.getModels(); - for (std::vector::iterator iter = allModels.begin(); - iter != allModels.end(); - iter++) { - Model* mdc = *iter; + std::set allModels = getAllModels.getModels(); + for (auto mdc : allModels) { modelClassVector.push_back(mdc->saveToScene(sceneAttributes, "models")); } diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index fd4e1447a..3cd2d626b 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -117,6 +117,7 @@ EventIdentificationHighlightLocation.h EventModelAdd.h EventModelDelete.h EventModelGetAll.h +EventModelGetAllDisplayed.h EventModelSurfaceGet.h EventNodeDataFilesGet.h EventNodeIdentificationColorsGetFromCharts.h @@ -262,6 +263,7 @@ EventIdentificationHighlightLocation.cxx EventModelAdd.cxx EventModelDelete.cxx EventModelGetAll.cxx +EventModelGetAllDisplayed.cxx EventModelSurfaceGet.cxx EventNodeDataFilesGet.cxx EventNodeIdentificationColorsGetFromCharts.cxx diff --git a/src/Brain/ChartTwoOverlaySetArray.cxx b/src/Brain/ChartTwoOverlaySetArray.cxx index 70914f8e3..5d290159d 100644 --- a/src/Brain/ChartTwoOverlaySetArray.cxx +++ b/src/Brain/ChartTwoOverlaySetArray.cxx @@ -54,7 +54,6 @@ ChartTwoOverlaySetArray::ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enu const AString& name) : CaretObject(), EventListenerInterface(), -SceneableInterface(), m_name(name) { m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); @@ -202,6 +201,8 @@ ChartTwoOverlaySetArray::copyChartOverlaySetCartesianAxes(const int32_t sourceTa /** * Save information specific to this type of model to the scene. * + * @param tabIndices + * Tab indices that are valid. * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when @@ -211,15 +212,14 @@ ChartTwoOverlaySetArray::copyChartOverlaySetCartesianAxes(const int32_t sourceTa * Name of instance in the scene. */ SceneClass* -ChartTwoOverlaySetArray::saveToScene(const SceneAttributes* sceneAttributes, - const AString& instanceName) +ChartTwoOverlaySetArray::saveTabIndicesToScene(const std::vector& tabIndices, + const SceneAttributes* sceneAttributes, + const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoOverlaySetArray", 1); - std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); - /* * Save overlay sets for tabs */ diff --git a/src/Brain/ChartTwoOverlaySetArray.h b/src/Brain/ChartTwoOverlaySetArray.h index 0edbe6e19..03c54fd4d 100644 --- a/src/Brain/ChartTwoOverlaySetArray.h +++ b/src/Brain/ChartTwoOverlaySetArray.h @@ -25,12 +25,13 @@ #include "CaretObject.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" -#include "SceneableInterface.h" namespace caret { class ChartTwoOverlaySet; + class SceneAttributes; + class SceneClass; - class ChartTwoOverlaySetArray : public CaretObject, public EventListenerInterface, public SceneableInterface { + class ChartTwoOverlaySetArray : public CaretObject, public EventListenerInterface { public: ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, @@ -50,8 +51,9 @@ namespace caret { void copyChartOverlaySetCartesianAxes(const int32_t sourceTabIndex, const int32_t destinationTabIndex); - virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, - const AString& instanceName); + virtual SceneClass* saveTabIndicesToScene(const std::vector& tabIndices, + const SceneAttributes* sceneAttributes, + const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); diff --git a/src/Brain/EventModelGetAllDisplayed.cxx b/src/Brain/EventModelGetAllDisplayed.cxx new file mode 100644 index 000000000..cbf576374 --- /dev/null +++ b/src/Brain/EventModelGetAllDisplayed.cxx @@ -0,0 +1,79 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ +#include "EventModelGetAllDisplayed.h" +#undef __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventModelGetAllDisplayed + * \brief Event to get the displayed models. + * \ingroup Brain + */ + +/** + * Constructor. + */ +EventModelGetAllDisplayed::EventModelGetAllDisplayed() +: Event(EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED) +{ + +} + +/** + * Destructor. + */ +EventModelGetAllDisplayed::~EventModelGetAllDisplayed() +{ +} + +/** + * @return A set containing the displayed models. + */ +std::set +EventModelGetAllDisplayed::getModels() const +{ + return m_models; +} + +/** + * Add a model to the displayed models. + * This method may be called more than once with the same model. + * + * @param model + * The model. + */ +void +EventModelGetAllDisplayed::addModel(Model* model) +{ + if (model == NULL) { + return; + } + m_models.insert(model); +} + diff --git a/src/Brain/EventModelGetAllDisplayed.h b/src/Brain/EventModelGetAllDisplayed.h new file mode 100644 index 000000000..56267ec17 --- /dev/null +++ b/src/Brain/EventModelGetAllDisplayed.h @@ -0,0 +1,62 @@ +#ifndef __EVENT_MODEL_GET_ALL_DISPLAYED_H__ +#define __EVENT_MODEL_GET_ALL_DISPLAYED_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "Event.h" + + +namespace caret { + + class Model; + + class EventModelGetAllDisplayed : public Event { + + public: + EventModelGetAllDisplayed(); + + virtual ~EventModelGetAllDisplayed(); + + std::set getModels() const; + + void addModel(Model* model); + + // ADD_NEW_METHODS_HERE + + private: + EventModelGetAllDisplayed(const EventModelGetAllDisplayed&); + + EventModelGetAllDisplayed& operator=(const EventModelGetAllDisplayed&); + + std::set m_models; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ + // +#endif // __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ + +} // namespace +#endif //__EVENT_MODEL_GET_ALL_DISPLAYED_H__ diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 539939fe9..8a943cdcb 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -99,15 +99,15 @@ ModelChartTwo::ModelChartTwo(Brain* brain) m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", m_selectedChartTwoDataType); - m_sceneAssistant->add("m_histogramChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_histogramChartOverlaySetArray.get()); - m_sceneAssistant->add("m_matrixChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_matrixChartOverlaySetArray.get()); - m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", - "ChartTwoOverlaySetArray", - m_lineSeriesChartOverlaySetArray.get()); +// m_sceneAssistant->add("m_histogramChartOverlaySetArray", +// "ChartTwoOverlaySetArray", +// m_histogramChartOverlaySetArray.get()); +// m_sceneAssistant->add("m_matrixChartOverlaySetArray", +// "ChartTwoOverlaySetArray", +// m_matrixChartOverlaySetArray.get()); +// m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", +// "ChartTwoOverlaySetArray", +// m_lineSeriesChartOverlaySetArray.get()); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); @@ -424,8 +424,65 @@ void ModelChartTwo::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { + const std::vector validTabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); + + std::vector histogramChartTabIndices; + std::vector lineSeriesChartTabIndices; + std::vector matrixChartTabIndices; + for (auto tabIndex : validTabIndices) { + switch (m_selectedChartTwoDataType[tabIndex]) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + histogramChartTabIndices.push_back(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + lineSeriesChartTabIndices.push_back(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + matrixChartTabIndices.push_back(tabIndex); + break; + } + } + + if ( ! histogramChartTabIndices.empty()) { + SceneClass* histogramClass = m_histogramChartOverlaySetArray->saveTabIndicesToScene(histogramChartTabIndices, + sceneAttributes, + "m_histogramChartOverlaySetArray"); + if (histogramClass != NULL) { + sceneClass->addClass(histogramClass); + } + } + + if ( ! lineSeriesChartTabIndices.empty()) { + SceneClass* lineSeriesClass = m_lineSeriesChartOverlaySetArray->saveTabIndicesToScene(lineSeriesChartTabIndices, + sceneAttributes, + "m_lineSeriesChartOverlaySetArray"); + if (lineSeriesClass != NULL) { + sceneClass->addClass(lineSeriesClass); + } + } + + if ( ! matrixChartTabIndices.empty()) { + SceneClass* matrixClass = m_matrixChartOverlaySetArray->saveTabIndicesToScene(matrixChartTabIndices, + sceneAttributes, + "m_matrixChartOverlaySetArray"); + if (matrixClass != NULL) { + sceneClass->addClass(matrixClass); + } + } + m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); + // m_sceneAssistant->add("m_histogramChartOverlaySetArray", + // "ChartTwoOverlaySetArray", + // m_histogramChartOverlaySetArray.get()); + // m_sceneAssistant->add("m_matrixChartOverlaySetArray", + // "ChartTwoOverlaySetArray", + // m_matrixChartOverlaySetArray.get()); + // m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", + // "ChartTwoOverlaySetArray", + // m_lineSeriesChartOverlaySetArray.get()); } /** @@ -447,6 +504,13 @@ ModelChartTwo::restoreModelSpecificInformationFromScene(const SceneAttributes* s m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + + m_histogramChartOverlaySetArray->restoreFromScene(sceneAttributes, + sceneClass->getClass("m_histogramChartOverlaySetArray")); + m_lineSeriesChartOverlaySetArray->restoreFromScene(sceneAttributes, + sceneClass->getClass("m_lineSeriesChartOverlaySetArray")); + m_matrixChartOverlaySetArray->restoreFromScene(sceneAttributes, + sceneClass->getClass("m_matrixChartOverlaySetArray")); } /** diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 045ed9061..d8112b128 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -45,6 +45,7 @@ #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventModelGetAll.h" +#include "EventModelGetAllDisplayed.h" #include "EventProgressUpdate.h" #include "ImageCaptureSettings.h" #include "LogManager.h" @@ -86,6 +87,7 @@ SessionManager::SessionManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED); Brain* brain = new Brain(); m_brains.push_back(brain); @@ -390,6 +392,19 @@ SessionManager::receiveEvent(Event* event) getModelsEvent->addModels(m_models); } + else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED) { + EventModelGetAllDisplayed* getDisplayedModelsEvent = + dynamic_cast(event); + CaretAssert(getDisplayedModelsEvent); + + for (const auto tab : m_browserTabs) { + if (tab != NULL) { + getDisplayedModelsEvent->addModel(tab->getModelForDisplay()); + } + } + + getDisplayedModelsEvent->setEventProcessed(); + } } /** diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 741e3614a..1a45d7499 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -521,6 +521,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_MODEL_ADD: case EventTypeEnum::EVENT_MODEL_DELETE: case EventTypeEnum::EVENT_MODEL_GET_ALL: + case EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED: case EventTypeEnum::EVENT_MODEL_SURFACE_GET: case EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS: case EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index eaffa390d..6c519c67a 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -286,7 +286,11 @@ EventTypeEnum::initialize() "EVENT_MODEL_GET_ALL", "Get all models")); - enumData.push_back(EventTypeEnum(EVENT_MODEL_SURFACE_GET, + enumData.push_back(EventTypeEnum(EVENT_MODEL_GET_ALL_DISPLAYED, + "EVENT_MODEL_GET_ALL_DISPLAYED", + "Get all displayed models")); + + enumData.push_back(EventTypeEnum(EVENT_MODEL_SURFACE_GET, "EVENT_MODEL_SURFACE_GET", "Get a specific model surface")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 8ac2e575e..1c5af4f0d 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -150,6 +150,8 @@ public: EVENT_MODEL_DELETE, /** model - get all*/ EVENT_MODEL_GET_ALL, + /** model - get all displayed */ + EVENT_MODEL_GET_ALL_DISPLAYED, /** model surface - get */ EVENT_MODEL_SURFACE_GET, /** Get the color for a node's identification symbol from a chart that contains the node */ diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 8d7ff149b..126906ad7 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -263,7 +263,7 @@ CaretMappableDataFile::isPaletteColorMappingEqualForAllMaps() const void CaretMappableDataFile::invalidateHistogramChartColoring() { - m_chartingDelegate->getHistogramCharting()->invalidateAllColoring(); + getChartingDelegate()->getHistogramCharting()->invalidateAllColoring(); } // note: method is documented in header file @@ -332,8 +332,14 @@ CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttribute //m_chartingDelegate->updateAfterFileChanged(); - sceneClass->addClass(m_chartingDelegate->saveToScene(sceneAttributes, - "m_chartingDelegate")); + if (m_chartingDelegate) { + SceneClass* chartDelegateScene = m_chartingDelegate->saveToScene(sceneAttributes, + "m_chartingDelegate"); + if (chartDelegateScene != NULL) { + sceneClass->addClass(m_chartingDelegate->saveToScene(sceneAttributes, + "m_chartingDelegate")); + } + } if (isMappedWithPalette()) { /* @@ -422,6 +428,7 @@ CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttr const SceneClass* chartingDelegateClass = sceneClass->getClass("m_chartingDelegate"); m_chartingDelegate->updateAfterFileChanged(); if (chartingDelegateClass != NULL) { + CaretAssert(m_chartingDelegate); m_chartingDelegate->restoreFromScene(sceneAttributes, chartingDelegateClass); } @@ -922,7 +929,7 @@ CaretMappableDataFile::clearModified() { CaretDataFile::clearModified(); - if (m_chartingDelegate != NULL) { + if (m_chartingDelegate) { m_chartingDelegate->clearModified(); } } diff --git a/src/Files/ChartableTwoFileDelegate.cxx b/src/Files/ChartableTwoFileDelegate.cxx index ce136f25d..0a9776f65 100644 --- a/src/Files/ChartableTwoFileDelegate.cxx +++ b/src/Files/ChartableTwoFileDelegate.cxx @@ -455,6 +455,10 @@ SceneClass* ChartableTwoFileDelegate::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { + if ( ! isChartingTwoSupported()) { + return NULL; + } + SceneClass* sceneClass = new SceneClass(instanceName, "ChartableTwoFileDelegate", 1); diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 9c20819bf..89d2ccf04 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -120,7 +120,11 @@ ChartableTwoFileHistogramChart::isValid() const bool ChartableTwoFileHistogramChart::isEmpty() const { - return false; + if ( ! isValid()) { + return true; + } + + return m_mapHistogramPrimitives.empty(); } /** @@ -129,7 +133,7 @@ ChartableTwoFileHistogramChart::isEmpty() const void ChartableTwoFileHistogramChart::invalidateAllColoring() { - m_mapHistogramBarsPrimitive.clear(); + m_mapHistogramPrimitives.clear(); //std::cout << "Invalidating histograms..." << std::endl; } @@ -321,8 +325,8 @@ ChartableTwoFileHistogramChart::HistogramPrimitives* ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t mapIndex, const bool useDataFromAllMapsFlag) { - MapIndexPrimitiveContainer::iterator iter = m_mapHistogramBarsPrimitive.find(mapIndex); - if (iter != m_mapHistogramBarsPrimitive.end()) { + MapIndexPrimitiveContainer::iterator iter = m_mapHistogramPrimitives.find(mapIndex); + if (iter != m_mapHistogramPrimitives.end()) { HistogramPrimitives* histogramPrimitives = iter->second.get(); if (histogramPrimitives != NULL) { return histogramPrimitives; @@ -608,7 +612,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m barsPrimitive, envelopePrimitive); - m_mapHistogramBarsPrimitive.insert(std::make_pair(mapIndex, + m_mapHistogramPrimitives.insert(std::make_pair(mapIndex, std::unique_ptr(histogramPrimitives))); return histogramPrimitives; diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index 7e6ecbf8d..066ddd160 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -111,9 +111,7 @@ namespace caret { typedef std::map> MapIndexPrimitiveContainer; - MapIndexPrimitiveContainer m_mapHistogramBarsPrimitive; - - MapIndexPrimitiveContainer m_mapHistogramThresholdPrimitive; + MapIndexPrimitiveContainer m_mapHistogramPrimitives; // ADD_NEW_MEMBERS_HERE diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 91ec86b27..2ad846f75 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -356,6 +356,10 @@ ChartableTwoFileLineSeriesChart::isValid() const bool ChartableTwoFileLineSeriesChart::isEmpty() const { + if ( ! isValid()) { + return true; + } + return (m_lineChartHistory->getHistoryCount() <= 0); } diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 6a35d725d..38df3c679 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -325,6 +325,10 @@ ChartableTwoFileMatrixChart::isValid() const bool ChartableTwoFileMatrixChart::isEmpty() const { + if ( ! isValid()) { + return true; + } + int32_t numRows = 0; int32_t numCols = 0; getMatrixDimensions(numRows, -- GitLab From b6c491a20d84925bd794ca9ab85f329c317e6cff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 11 Jul 2017 15:43:45 -0500 Subject: [PATCH 318/755] Initial implementation of chart two axes whose text scales with the height of the window. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 10 + ...rainOpenGLAnnotationDrawingFixedPipeline.h | 1 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 534 ++++++++---------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 10 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 47 +- src/Files/ChartableTwoFileBaseChart.cxx | 19 +- src/Files/ChartableTwoFileBaseChart.h | 2 + 7 files changed, 300 insertions(+), 323 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 2c11d4792..4f0052900 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -521,8 +521,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic m_volumeSpacePlaneValid = true; std::vector dummyColorBars; + std::vector dummyViewportAnnotations; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, dummyColorBars, + dummyViewportAnnotations, NULL, NULL, sliceThickness); @@ -577,8 +579,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, viewport[2], viewport[3]); + std::vector emptyViewportAnnotations; drawAnnotationsInternal(drawingCoordinateSpace, emptyColorBars, + emptyViewportAnnotations, graphicsLabel, surfaceDisplayed, sliceThickness); @@ -592,6 +596,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, else { drawAnnotationsInternal(drawingCoordinateSpace, colorBars, + viewportAnnotations, NULL, surfaceDisplayed, sliceThickness); @@ -619,6 +624,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& viewportAnnotations, Annotation* viewportAnnotationForDrawing, const Surface* surfaceDisplayed, const float sliceThickness) @@ -819,6 +825,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat } break; } + + annotationsFromFile.insert(annotationsFromFile.end(), + viewportAnnotations.begin(), + viewportAnnotations.end()); } else { CaretAssertVectorIndex(allAnnotationFiles, iFile); diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 5552d2f89..27d4ced05 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -186,6 +186,7 @@ namespace caret { void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, + std::vector& viewportAnnotations, Annotation* viewportAnnotationForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 02830f537..07540bb56 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -307,16 +307,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch break; } - const int32_t vpX = m_viewport[0]; - const int32_t vpY = m_viewport[1]; - const int32_t vpWidth = m_viewport[2]; - const int32_t vpHeight = m_viewport[3]; + const int32_t tabViewportX = m_viewport[0]; + const int32_t tabViewportY = m_viewport[1]; + const int32_t tabViewportWidth = m_viewport[2]; + const int32_t tabViewportHeight = m_viewport[3]; int32_t chartGraphicsDrawingViewport[4] = { - vpX, - vpY, - vpWidth, - vpHeight + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight }; const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); @@ -409,7 +409,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); const int32_t numHistory = lineSeriesHistory->getHistoryCount(); for (int32_t iHistory = (numHistory - 1); iHistory >= 0; iHistory--) { - //for (int32_t iHistory = 0; iHistory < numHistory; iHistory++) { const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); CaretAssert(data); if (data->isSelected()) { @@ -491,13 +490,28 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, leftAxis, leftAxisLabel, width, height); + GLint vp[4]; + glGetIntegerv(GL_VIEWPORT, vp); + + glViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, tabViewportWidth, 0, tabViewportHeight, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, leftAxis, leftAxisLabel, width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsRight, vpWidth, vpHeight, rightAxis, rightAxisLabel, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsRight, tabViewportWidth, tabViewportHeight, rightAxis, rightAxisLabel, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, topAxis, NULL, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, vpWidth, vpHeight, bottomAxis, bottomAxisLabel, width, height); + estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, bottomAxis, bottomAxisLabel, width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; @@ -506,18 +520,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Ensure that there is sufficient space for the axes data display. */ - if ((vpWidth > (marginSize * 3)) - && (vpHeight > (marginSize * 3))) { + if ((tabViewportWidth > (marginSize * 3)) + && (tabViewportHeight > (marginSize * 3))) { float axisMinimumValue = 0.0; float axisMaximumValue = 0.0; /* Draw legends and grids */ if (drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, margins, leftAxis, leftAxisLabel, @@ -528,10 +542,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } if (drawChartAxisCartesian(boundsRight, - vpX, - vpY, - vpWidth, - vpHeight, + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, margins, rightAxis, rightAxisLabel, @@ -541,10 +555,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxRight = axisMaximumValue; } if (drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, margins, bottomAxis, bottomAxisLabel, @@ -555,20 +569,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } drawChartAxisCartesian(boundsLeftBottomTop, - vpX, - vpY, - vpWidth, - vpHeight, + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, margins, topAxis, NULL, axisMinimumValue, axisMaximumValue); - drawChartGraphicsBoxAndSetViewport(vpX, - vpY, - vpWidth, - vpHeight, + drawChartGraphicsBoxAndSetViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, margins, chartGraphicsDrawingViewport); } @@ -851,7 +865,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() /* * Set the width and neight of each matrix cell. */ - const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); // //m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); + const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); CaretAssert(matrixProperties); const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; @@ -982,7 +996,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); - //std::cout << "Matrix selection: " << primitiveIndex << std::endl; if (primitiveIndex >= 0) { int32_t numberOfRows = 0; int32_t numberOfColumns = 0; @@ -991,7 +1004,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const int32_t rowIndex = primitiveIndex / numberOfColumns; const int32_t colIndex = primitiveIndex % numberOfColumns; - //std::cout << " row=" << rowIndex << " col=" << colIndex << std::endl; if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), @@ -1004,7 +1016,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT drawPrimitivePrivate(matrixPrimitive); const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); -// const ChartTwoMatrixDisplayProperties* matrixProperties = m_chartTwoModel->getChartTwoMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { @@ -1057,10 +1068,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxX = rowIndex; // matrix is symmetric + maxX = rowIndex; /* matrix is symmetric */ break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minX = rowIndex + 1; // matrix is symmetric + minX = rowIndex + 1; /* matrix is symmetric */ break; } @@ -1090,10 +1101,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxY = columnIndex; // matrix is symmetric + maxY = columnIndex; /* matrix is symmetric */ break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minY = columnIndex + 1; // matrix is symmetric + minY = columnIndex + 1; /* matrix is symmetric */ break; } columnOutlineData4f->addVertex(minX, minY); @@ -1169,14 +1180,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() * @param widthOut * Width of text out. * @param heightOut - * Heigh of text out. + * Height of text out. */ void BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, - const AnnotationPercentSizeText* chartAxisLabel, + AnnotationPercentSizeText* chartAxisLabel, double& widthOut, double& heightOut) { @@ -1189,6 +1200,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH if ( ! cartesianAxis->isEnabledByChart()) { return; } + if ( ! cartesianAxis->isDisplayedByUser()) { + return; + } + + /* + * The percentage height from the label is also used + * by the axis numeric values. + */ + CaretAssert(chartAxisLabel); + chartAxisLabel->setTabIndex(m_tabIndex); + /* * The length of the axis does not matter here. * We are just estimating the width and height of the axes text labels. @@ -1199,32 +1221,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH std::vector scaleValueOffsetInPixels; std::vector scaleValuesText; cartesianAxis->getScaleValuesAndOffsets(dataBounds, - axisLength, - minimumValue, - maximumValue, - scaleValueOffsetInPixels, - scaleValuesText); - - if ( ! cartesianAxis->isDisplayedByUser()) { - return; - } + axisLength, + minimumValue, + maximumValue, + scaleValueOffsetInPixels, + scaleValuesText); + /* + * For sizing text for numeric values, copy the label annotation + * (so font size, style) are the same. We are only finding + * height and width of all numeric values. + */ + AnnotationPercentSizeText numericValueAnnotation(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + numericValueAnnotation = *chartAxisLabel; for (std::vector::iterator iter = scaleValuesText.begin(); iter != scaleValuesText.end(); iter++) { const AString text = *iter; if ( ! text.isEmpty()) { - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setText(text); + numericValueAnnotation.setText(text); double textWidth = 0.0; double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); + m_textRenderer->getTextWidthHeightInPixels(numericValueAnnotation, viewportWidth, viewportHeight, textWidth, textHeight); widthOut = std::max(widthOut, textWidth); heightOut = std::max(heightOut, textHeight); } } + /* + * Add space for the numeric value tick marks + */ switch (cartesianAxis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: @@ -1240,54 +1268,25 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - //const AnnotationPercentSizeText* chartAxisLabel = cartesianAxis->getAnnotationAxisLabel(); - if (chartAxisLabel != NULL) { - const AString axisTitle = chartAxisLabel->getText(); - if ( ! axisTitle.isEmpty()) { - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setText(axisTitle); - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - annotationText.setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); - break; - } - - double textWidth = 0.0; - double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(annotationText, viewportWidth, viewportHeight, textWidth, textHeight); - - /* - * Note: Text on left and right is rotated but we need the width - * and height after rotation so swap the width and height of the text - */ - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += textHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - std::swap(textWidth, textHeight); - widthOut += textWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - std::swap(textWidth, textHeight); - widthOut += textWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += textHeight; - break; - } - } + double labelWidth = 0.0; + double labelHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*chartAxisLabel, viewportWidth, viewportHeight, labelWidth, labelHeight); + + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + heightOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + /** Text is rotated 90 degrees so use HEIGHT */ + widthOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + /** Text is rotated 90 degrees so use HEIGHT */ + widthOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + heightOut += labelHeight; + break; } } @@ -1371,13 +1370,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons /** * Draw the chart axes grid/box * - * @param vpX + * @param tabViewportX * Viewport X for all chart content - * @param vpY + * @param tabViewportY * Viewport Y for all chart content - * @param vpWidth + * @param tabViewportWidth * Viewport width for all chart content - * @param vpHeight + * @param tabViewportHeight * Viewport height for all chart content * @param margins * Margin around graphics region. The margin corresponding to the @@ -1396,10 +1395,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons */ bool BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], - const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, + const float tabViewportX, + const float tabViewportY, + const float tabViewportWidth, + const float tabViewportHeight, const Margins& margins, ChartTwoCartesianAxis* axis, AnnotationPercentSizeText* chartAxisLabel, @@ -1420,49 +1419,43 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data float axisLength = 0.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisVpX = vpX + margins.m_left; - axisVpY = vpY; - axisVpWidth = vpWidth - (margins.m_left + margins.m_right); + axisVpX = tabViewportX + margins.m_left; + axisVpY = tabViewportY; + axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); axisVpHeight = margins.m_bottom; axisLength = axisVpWidth; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisVpX = vpX + margins.m_left; - axisVpY = vpY + vpHeight - margins.m_top; - axisVpWidth = vpWidth - (margins.m_left + margins.m_right); + axisVpX = tabViewportX + margins.m_left; + axisVpY = tabViewportY + tabViewportHeight - margins.m_top; + axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); axisVpHeight = margins.m_top; axisLength = axisVpWidth; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisVpX = vpX; - axisVpY = vpY + margins.m_bottom; - axisVpWidth = margins.m_left + 1; // so ticks go to box - axisVpHeight = vpHeight - (margins.m_bottom + margins.m_top); + axisVpX = tabViewportX; + axisVpY = tabViewportY + margins.m_bottom; + axisVpWidth = margins.m_left + 1; /* so ticks go to box */ + axisVpHeight = tabViewportHeight - (margins.m_bottom + margins.m_top); axisLength = axisVpHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisVpX = vpX + vpWidth - margins.m_right; - axisVpY = vpY + margins.m_bottom; + axisVpX = tabViewportX + tabViewportWidth - margins.m_right; + axisVpY = tabViewportY + margins.m_bottom; axisVpWidth = margins.m_right; - axisVpHeight = vpHeight - (margins.m_bottom + margins.m_top); + axisVpHeight = tabViewportHeight - (margins.m_bottom + margins.m_top); axisLength = axisVpHeight; break; } - const int32_t axisViewport[4] { - axisVpX, - axisVpY, - axisVpWidth, - axisVpHeight - }; std::vector scaleValueOffsetInPixels; std::vector scaleValuesText; const bool validAxisFlag = axis->getScaleValuesAndOffsets(dataBounds, - axisLength, - axisMinimumOut, - axisMaximumOut, - scaleValueOffsetInPixels, - scaleValuesText); + axisLength, + axisMinimumOut, + axisMaximumOut, + scaleValueOffsetInPixels, + scaleValuesText); if ( ! validAxisFlag) { return false; } @@ -1489,229 +1482,194 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data }; const int32_t numScaleValuesToDraw = static_cast(scaleValuesText.size()); - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + + /* + * For scale text, make a copy of the axis label so font properties match + */ + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + annotationText = *chartAxisLabel; annotationText.setCustomTextColor(rgba); annotationText.setTextColor(CaretColorEnum::CUSTOM); + annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + annotationText.setTabIndex(m_tabIndex); if (numScaleValuesToDraw > 0) { - float startX = 0.0; - float startY = 0.0; - float offsetMultiplierX = 0.0; - float offsetMultiplierY = 0.0; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - - float tickDeltaXY[2] = { 0.0, 0.0 }; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - startX = 0; - startY = axisVpHeight; - offsetMultiplierX = 1.0; - offsetMultiplierY = 0.0; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - tickDeltaXY[0] = 0.0; - tickDeltaXY[1] = -s_tickLength; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - startX = 0.0; - startY = 0.0; - offsetMultiplierX = 1.0; - offsetMultiplierY = 0.0; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - tickDeltaXY[0] = 0.0; - tickDeltaXY[1] = s_tickLength; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - startX = axisVpWidth; - startY = 0.0; - offsetMultiplierX = 0.0; - offsetMultiplierY = 1.0; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickDeltaXY[0] = -s_tickLength; - tickDeltaXY[1] = 0.0; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - startX = 0.0; - startY = 0.0; - offsetMultiplierX = 0.0; - offsetMultiplierY = 1.0; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickDeltaXY[0] = s_tickLength; - tickDeltaXY[1] = 0.0; - break; - } - - glViewport(axisViewport[0], - axisViewport[1], - axisViewport[2], - axisViewport[3]); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, axisVpWidth, 0, axisVpHeight, -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); - + const bool showTicksEnabledFlag = axis->isShowTickmarks(); + std::unique_ptr ticksData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); - const bool showTicksEnabledFlag = axis->isShowTickmarks(); + const int32_t firstTickIndex = 0; + const int32_t lastTickIndex = numScaleValuesToDraw - 1; - const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; - const int32_t firstIndex = 0; - const int32_t lastIndex = numScaleValuesToDraw - 1; for (int32_t i = 0; i < numScaleValuesToDraw; i++) { - float tickStartX = startX + scaleValueOffsetInPixels[i] * offsetMultiplierX; - float tickStartY = startY + scaleValueOffsetInPixels[i] * offsetMultiplierY; - float textOffsetX = 0.0; - float textOffsetY = 0.0; - bool showTickAtScaleValueFlag = showTicksEnabledFlag; + float tickStartX = 0.0; + float tickStartY = 0.0; + float tickEndX = 0.0; + float tickEndY = 0.0; + const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; + switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; + tickStartY = margins.m_bottom; + tickEndX = tickStartX; + tickEndY = tickStartY - s_tickLength; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - if (i == firstIndex) { + if (i == firstTickIndex) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - tickStartX += halfGridLineWidth; } - else if (i == lastIndex) { + else if (i == lastTickIndex) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - tickStartX -= halfGridLineWidth; } - textOffsetY = 2.0; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickStartX -= halfGridLineWidth; - if (i == firstIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - tickStartY += halfGridLineWidth; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; + tickStartY = tabViewportHeight - margins.m_top; + tickEndX = tickStartX; + tickEndY = tickStartY + s_tickLength; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + if (i == firstTickIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); } - else if (i == lastIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - tickStartY -= halfGridLineWidth; + else if (i == lastTickIndex) { + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); } - textOffsetX = 2.0; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + tickStartX = margins.m_left; + tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; + tickEndX = tickStartX - s_tickLength; + tickEndY = tickStartY; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - tickStartX += halfGridLineWidth; - if (i == firstIndex) { + if (i == firstTickIndex) { annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - tickStartY += halfGridLineWidth; } - else if (i == lastIndex) { + else if (i == lastTickIndex) { annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - tickStartY -= halfGridLineWidth; } - textOffsetX = -2.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - if (i == firstIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - tickStartX += halfGridLineWidth; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + tickStartX = tabViewportWidth - margins.m_right; + tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; + tickEndX = tickStartX + s_tickLength; + tickEndY = tickStartY; + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + if (i == firstTickIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); } - else if (i == lastIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - tickStartX -= halfGridLineWidth; + else if (i == lastTickIndex) { + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); } - textOffsetY = -2.0; + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); break; } - const float tickEndX = tickStartX + tickDeltaXY[0]; - const float tickEndY = tickStartY + tickDeltaXY[1]; - if ((i == firstIndex) - || (i == lastIndex)) { - showTickAtScaleValueFlag = false; + if (showTicksEnabledFlag) { + if ((i != firstTickIndex) + && (i != lastTickIndex)) { + ticksData->addVertex(tickStartX, tickStartY); + ticksData->addVertex(tickEndX, tickEndY); + } } - if (showTickAtScaleValueFlag) { - ticksData->addVertex(tickStartX, tickStartY); - ticksData->addVertex(tickEndX, tickEndY); + float textX = tickEndX; + float textY = tickEndY; + const float textOffset = 3.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + textY -= textOffset; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + textY += textOffset; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + textX -= textOffset; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + textX += textOffset; + break; } - - const float textX = tickEndX + textOffsetX; - const float textY = tickEndY + textOffsetY; annotationText.setText(scaleValuesText[i]); + m_textRenderer->drawTextAtViewportCoords(textX, textY, 0.0, annotationText); } - - if (ticksData->isValid()) { - glLineWidth(GRID_LINE_WIDTH); - drawPrimitivePrivate(ticksData.get()); - } + + glLineWidth(GRID_LINE_WIDTH); + drawPrimitivePrivate(ticksData.get()); + if (chartAxisLabel != NULL) { const AString axisTitle = chartAxisLabel->getText(); if ( ! axisTitle.isEmpty()) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - bool drawAxisTextVerticalFlag = false; - float axisTextCenterX = axisVpWidth / 2.0; - float axisTextCenterY = axisVpHeight / 2.0; + float labelTabX = axisVpWidth / 2.0; + float labelTabY = axisVpHeight / 2.0; const float textMarginOffset = 5.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisTextCenterX = (axisVpWidth / 2.0); - axisTextCenterY = textMarginOffset; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + labelTabX = (axisVpWidth / 2.0) + margins.m_left; + labelTabY = textMarginOffset; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + chartAxisLabel->setRotationAngle(0.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisTextCenterX = (axisVpWidth / 2.0); - axisTextCenterY = axisVpHeight - textMarginOffset; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + labelTabX = (axisVpWidth / 2.0) + margins.m_left; + labelTabY = tabViewportHeight - textMarginOffset; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setRotationAngle(0.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisTextCenterX = textMarginOffset; - axisTextCenterY = (axisVpHeight / 2.0); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - drawAxisTextVerticalFlag = true; + labelTabX = textMarginOffset; + labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setRotationAngle(-90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisTextCenterX = axisVpWidth - textMarginOffset; - axisTextCenterY = (axisVpHeight / 2.0); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - drawAxisTextVerticalFlag = true; + labelTabX = tabViewportWidth - textMarginOffset; + labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setRotationAngle(90.0); break; } if ((axisVpWidth > 0.0) && (axisVpHeight > 0.0)) { - //AnnotationPercentSizeText* chartLabel = axis->getAnnotationAxisLabel(); chartAxisLabel->setCustomTextColor(rgba); chartAxisLabel->setTextColor(CaretColorEnum::CUSTOM); chartAxisLabel->setTabIndex(m_tabIndex); - chartAxisLabel->setViewportCoordinateSpaceViewport(axisViewport); - chartAxisLabel->getCoordinate()->setXYZ(axisTextCenterX, - axisTextCenterY, - 0.0f); + chartAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; + const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; + chartAxisLabel->getCoordinate()->setXYZ(tabPercentageX, + tabPercentageY, + 0.0f); m_viewportSpaceAnnotationsOut.push_back(chartAxisLabel); } } } + + return true; } - return true; + return false; } /** diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 316a2580b..8fbdb1566 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -142,10 +142,10 @@ namespace caret { int32_t chartGraphicsDrawingViewportOut[4]); bool drawChartAxisCartesian(const float dataBounds[4], - const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, + const float tabViewportX, + const float tabViewportY, + const float tabViewportWidth, + const float tabViewportHeight, const Margins& margins, ChartTwoCartesianAxis* axis, AnnotationPercentSizeText* chartAxisLabel, @@ -156,7 +156,7 @@ namespace caret { const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, - const AnnotationPercentSizeText* chartAxisLabel, + AnnotationPercentSizeText* chartAxisLabel, double& widthOut, double& heightOut); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 79e498d07..0b93fc709 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -656,6 +656,8 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, drawWindowAnnotations(windowViewport); } + m_viewportSpaceAnnotations.clear(); + this->checkForOpenGLError(NULL, "At end of drawModels()"); m_brain = NULL; @@ -787,12 +789,13 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont this->windowTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); - std::vector emptyViewportAnnotations; + //std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - emptyViewportAnnotations, + m_viewportSpaceAnnotations, NULL); + //m_viewportSpaceAnnotations.clear(); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -868,13 +871,13 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) - std::vector emptyColorBars; - m_annotationDrawing->drawAnnotations(&inputs, - AnnotationCoordinateSpaceEnum::VIEWPORT, - emptyColorBars, - m_viewportSpaceAnnotations, - NULL); - m_viewportSpaceAnnotations.clear(); +// std::vector emptyColorBars; +// m_annotationDrawing->drawAnnotations(&inputs, +// AnnotationCoordinateSpaceEnum::VIEWPORT, +// emptyColorBars, +// m_viewportSpaceAnnotations, +// NULL); +// m_viewportSpaceAnnotations.clear(); @@ -963,18 +966,18 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, } - int viewport[4]; - viewportContent->getModelViewport(viewport); - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, - this->mode, - BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_tabViewport, - m_windowIndex, - this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); +// int viewport[4]; +// viewportContent->getModelViewport(viewport); +// glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); +// +// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, +// this->mode, +// BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, +// m_tabViewport, +// m_windowIndex, +// this->windowTabIndex, +// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, +// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); } } @@ -5325,7 +5328,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, CaretAssert(browserTabContent); CaretAssert(chartModel); - m_viewportSpaceAnnotations.clear(); + //m_viewportSpaceAnnotations.clear(); BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 832b58e2d..165fd89a6 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -78,7 +78,7 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) m_bottomAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); m_leftRightAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH)); + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_bottomAxisTitle", @@ -116,14 +116,15 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t { CaretAssert(titleAnnotation); - titleAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::VIEWPORT); + titleAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + titleAnnotation->setTabIndex(0); titleAnnotation->setTextColor(CaretColorEnum::RED); titleAnnotation->setLineColor(CaretColorEnum::NONE); titleAnnotation->setBackgroundColor(CaretColorEnum::NONE); titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - titleAnnotation->setFontPercentViewportSize(40.0); + titleAnnotation->setFontPercentViewportSize(s_defaultFontPercentViewportSize); AString title; @@ -136,13 +137,11 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); titleAnnotation->setRotationAngle(-90.0); - titleAnnotation->setFontPercentViewportSize(25.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - titleAnnotation->setRotationAngle(-90.0); - titleAnnotation->setFontPercentViewportSize(25.0); + titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + titleAnnotation->setRotationAngle(90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); @@ -365,7 +364,7 @@ ChartableTwoFileBaseChart::saveToScene(const SceneAttributes* sceneAttributes, { SceneClass* sceneClass = new SceneClass(instanceName, "ChartableTwoFileBaseChart", - 1); + 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -400,5 +399,9 @@ ChartableTwoFileBaseChart::restoreFromScene(const SceneAttributes* sceneAttribut restoreSubClassDataFromScene(sceneAttributes, sceneClass); + if (sceneClass->getVersionNumber() <= 1) { + m_bottomAxisTitle->setFontPercentViewportSize(s_defaultFontPercentViewportSize); + m_leftRightAxisTitle->setFontPercentViewportSize(s_defaultFontPercentViewportSize); + } } diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index c1f6ee504..204052b96 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -125,6 +125,8 @@ namespace caret { std::unique_ptr m_leftRightAxisTitle; + static float constexpr s_defaultFontPercentViewportSize = 5.0; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 815e1d5f1c07b309066812e0ddbecf4efcc9b430 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 11 Jul 2017 16:43:27 -0500 Subject: [PATCH 319/755] Revisions for drawing chart axes labels in tab coordinate space. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 77 +++++-------------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 3 +- 2 files changed, 20 insertions(+), 60 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 4f0052900..936468129 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -520,12 +520,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic m_volumeSpacePlane = plane; m_volumeSpacePlaneValid = true; - std::vector dummyColorBars; - std::vector dummyViewportAnnotations; + std::vector emptyColorBars; + std::vector emptyNotInFileAnnotations; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, - dummyColorBars, - dummyViewportAnnotations, - NULL, + emptyColorBars, + emptyNotInFileAnnotations, NULL, sliceThickness); } @@ -543,8 +542,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlic * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. - * @param viewportAnnotations - * Annotation for drawing in viewport space + * @param notInFileAnnotations + * Annotations that are not in a file but need to be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. */ @@ -552,7 +551,7 @@ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& viewportAnnotations, + std::vector& notInFileAnnotations, const Surface* surfaceDisplayed) { CaretAssert(inputs); @@ -562,45 +561,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const float sliceThickness = 0.0; - if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { - GLint savedViewport[4]; - glGetIntegerv(GL_VIEWPORT, - savedViewport); - - std::vector emptyColorBars; - - for (auto graphicsLabel : viewportAnnotations) { - CaretAssert(graphicsLabel); - - int32_t viewport[4]; - graphicsLabel->getViewportCoordinateSpaceViewport(viewport); - glViewport(viewport[0], - viewport[1], - viewport[2], - viewport[3]); - - std::vector emptyViewportAnnotations; - drawAnnotationsInternal(drawingCoordinateSpace, - emptyColorBars, - emptyViewportAnnotations, - graphicsLabel, - surfaceDisplayed, - sliceThickness); - } - - glViewport(savedViewport[0], - savedViewport[1], - savedViewport[2], - savedViewport[3]); - } - else { - drawAnnotationsInternal(drawingCoordinateSpace, - colorBars, - viewportAnnotations, - NULL, - surfaceDisplayed, - sliceThickness); - } + drawAnnotationsInternal(drawingCoordinateSpace, + colorBars, + notInFileAnnotations, + surfaceDisplayed, + sliceThickness); m_inputs = NULL; } @@ -610,12 +575,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, * * @param drawingCoordinateSpace * Coordinate space of annotation that are drawn. - * @param surfaceDisplayed - * Surface that is displayed. May be NULL in some instances. * @param colorbars * Colorbars that will be drawn. - * @param viewportAnnotationForDrawing - * Viewport space label that will be drawn. + * @param notInFileAnnotations + * Annotations that are not in a file but need to be drawn. + * @param surfaceDisplayed + * Surface that is displayed. May be NULL in some instances. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param sliceThickness @@ -624,8 +589,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& viewportAnnotations, - Annotation* viewportAnnotationForDrawing, + std::vector& notInFileAnnotations, const Surface* surfaceDisplayed, const float sliceThickness) { @@ -665,8 +629,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - CaretAssert(viewportAnnotationForDrawing); - haveDisplayGroupFlag = false; break; case AnnotationCoordinateSpaceEnum::WINDOW: haveDisplayGroupFlag = false; @@ -767,7 +729,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - annotationsFromFile.push_back(viewportAnnotationForDrawing); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: @@ -827,8 +788,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat } annotationsFromFile.insert(annotationsFromFile.end(), - viewportAnnotations.begin(), - viewportAnnotations.end()); + notInFileAnnotations.begin(), + notInFileAnnotations.end()); } else { CaretAssertVectorIndex(allAnnotationFiles, iFile); diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 27d4ced05..a37fd75bb 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -116,7 +116,7 @@ namespace caret { void drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, - std::vector& viewportAnnotations, + std::vector& notInFileAnnotations, const Surface* surfaceDisplayed); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, @@ -187,7 +187,6 @@ namespace caret { void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& viewportAnnotations, - Annotation* viewportAnnotationForDrawing, const Surface* surfaceDisplayed, const float sliceThickness); -- GitLab From e46174509f64a082c598ecc6c28d8376bb1f39b3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 12 Jul 2017 09:25:11 -0500 Subject: [PATCH 320/755] Removed excess space between axis label and numeric value on left/right sides of charts. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 47 +++++++----- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 6 +- src/Charting/ChartTwoCartesianAxis.cxx | 71 +++++++------------ src/Charting/ChartTwoCartesianAxis.h | 16 +++-- 4 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 07540bb56..f167d68df 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -486,8 +486,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } - const float boundsLeftBottomTop[4] = { xMin, xMax, yMinLeft, yMaxLeft }; - const float boundsRight[4] = { xMin, xMax, yMinRight, yMaxRight }; double width = 0.0, height = 0.0; GLint vp[4]; @@ -505,18 +503,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, leftAxis, leftAxisLabel, width, height); + estimateCartesianChartAxisLegendsWidthHeight(yMinLeft, yMaxLeft, tabViewportWidth, tabViewportHeight, leftAxis, leftAxisLabel, width, height); margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsRight, tabViewportWidth, tabViewportHeight, rightAxis, rightAxisLabel, width, height); + estimateCartesianChartAxisLegendsWidthHeight(yMinRight, yMaxRight, tabViewportWidth, tabViewportHeight, rightAxis, rightAxisLabel, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); + estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); margins.m_top = std::max(margins.m_top, height); - estimateCartesianChartAxisLegendsWidthHeight(boundsLeftBottomTop, tabViewportWidth, tabViewportHeight, bottomAxis, bottomAxisLabel, width, height); + estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, bottomAxis, bottomAxisLabel, width, height); margins.m_bottom = std::max(margins.m_bottom, height); - if (margins.m_left > marginSize) margins.m_left += 10; - if (margins.m_right > marginSize) margins.m_right += 10; - /* * Ensure that there is sufficient space for the axes data display. */ @@ -527,7 +522,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch float axisMaximumValue = 0.0; /* Draw legends and grids */ - if (drawChartAxisCartesian(boundsLeftBottomTop, + if (drawChartAxisCartesian(yMinLeft, + yMaxLeft, tabViewportX, tabViewportY, tabViewportWidth, @@ -541,7 +537,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxLeft = axisMaximumValue; } - if (drawChartAxisCartesian(boundsRight, + if (drawChartAxisCartesian(yMinRight, + yMaxRight, tabViewportX, tabViewportY, tabViewportWidth, @@ -554,7 +551,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMinRight = axisMinimumValue; yMaxRight = axisMaximumValue; } - if (drawChartAxisCartesian(boundsLeftBottomTop, + if (drawChartAxisCartesian(xMin, + xMax, tabViewportX, tabViewportY, tabViewportWidth, @@ -568,7 +566,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch xMax = axisMaximumValue; } - drawChartAxisCartesian(boundsLeftBottomTop, + drawChartAxisCartesian(xMin, + xMax, tabViewportX, tabViewportY, tabViewportWidth, @@ -1167,8 +1166,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() /** * Estimate the size of the axis' text. * - * @param dataBounds - * Bounds of data [minX, maxX, minY, maxY]. + * @param minimumDataValue + * Minimum data value + * @param maximumDataValue + * Maximum data value * @param viewportWidth * Widgth of viewport. * @param viewportHeight @@ -1183,7 +1184,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() * Height of text out. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], +BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, + const float maximumDataValue, const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, @@ -1220,7 +1222,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH float maximumValue = 0.0; std::vector scaleValueOffsetInPixels; std::vector scaleValuesText; - cartesianAxis->getScaleValuesAndOffsets(dataBounds, + cartesianAxis->getScaleValuesAndOffsets(minimumDataValue, + maximumDataValue, axisLength, minimumValue, maximumValue, @@ -1370,6 +1373,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons /** * Draw the chart axes grid/box * + * @param minimumDataValue + * Minimum data value + * @param maximumDataValue + * Maximum data value * @param tabViewportX * Viewport X for all chart content * @param tabViewportY @@ -1394,7 +1401,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons * True if the axis is valid and was drawn, else false. */ bool -BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float dataBounds[4], +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float minimumDataValue, + const float maximumDataValue, const float tabViewportX, const float tabViewportY, const float tabViewportWidth, @@ -1450,7 +1458,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float data std::vector scaleValueOffsetInPixels; std::vector scaleValuesText; - const bool validAxisFlag = axis->getScaleValuesAndOffsets(dataBounds, + const bool validAxisFlag = axis->getScaleValuesAndOffsets(minimumDataValue, + maximumDataValue, axisLength, axisMinimumOut, axisMaximumOut, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 8fbdb1566..9643121a5 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -141,7 +141,8 @@ namespace caret { const Margins& margins, int32_t chartGraphicsDrawingViewportOut[4]); - bool drawChartAxisCartesian(const float dataBounds[4], + bool drawChartAxisCartesian(const float minimumDataValue, + const float maximumDataValue, const float tabViewportX, const float tabViewportY, const float tabViewportWidth, @@ -152,7 +153,8 @@ namespace caret { float& axisMinimumOut, float& axisMaximumOut); - void estimateCartesianChartAxisLegendsWidthHeight(const float dataBounds[4], + void estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, + const float maximumDataValue, const float viewportWidth, const float viewportHeight, ChartTwoCartesianAxis* cartesianAxis, diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index a7906dc2f..0af8d1d2d 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -541,8 +541,10 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, /** * Given the bounds of the data, determine the auto range minimum and maximum values. * - * @param dataBounds - * Bounds of the data. + * @param minimumValue + * Minimum data value + * @param maximumValue + * Maximum data value * @param minimumOut * Output minimum value for autoranging. * @param maximumOut @@ -555,33 +557,15 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, * True if output values are valid, else false. */ bool -ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], +ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, + const float maximumValue, float& minimumOut, float& maximumOut, float& stepValueOut, int32_t& digitsRightOfDecimalOut) const { - float minValue = 1.0; - float maxValue = -1.0; - - switch (m_axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - minValue = dataBounds[0]; - maxValue = dataBounds[1]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - minValue = dataBounds[2]; - maxValue = dataBounds[3]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - minValue = dataBounds[2]; - maxValue = dataBounds[3]; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - minValue = dataBounds[0]; - maxValue = dataBounds[1]; - break; - } + float minValue = minimumValue; + float maxValue = maximumValue; m_rangeMinimumValue = 0.0; m_rangeMaximumValue = 0.0; @@ -615,8 +599,10 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], /** * Get the axis scale text values and their positions for drawing the scale. * - * @param dataBoundsIn - * Bounds of data [minX, maxX, minY, maxY]. + * @param minimumDataValue + * Minimum data value + * @param maximumDataValue + * Maximum data value * @param axisLengthInPixels * Length of axis in pixels. * @param minimumOut @@ -631,19 +617,16 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float dataBounds[4], * True if output data is valid, else false. */ bool -ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], +ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, + const float maximumDataValue, const float axisLengthInPixels, float& minimumOut, float& maximumOut, std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const { - float dataBounds[4] = { - dataBoundsIn[0], - dataBoundsIn[1], - dataBoundsIn[2], - dataBoundsIn[3], - }; + float minimumValue = minimumDataValue; + float maximumValue = maximumDataValue; minimumOut = 0.0; maximumOut = 0.0; @@ -665,26 +648,27 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - dataBounds[0] = m_userScaleMinimumValue; - dataBounds[1] = m_userScaleMaximumValue; + minimumValue = m_userScaleMinimumValue; + maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - dataBounds[2] = m_userScaleMinimumValue; - dataBounds[3] = m_userScaleMaximumValue; + minimumValue = m_userScaleMinimumValue; + maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - dataBounds[2] = m_userScaleMinimumValue; - dataBounds[3] = m_userScaleMaximumValue; + minimumValue = m_userScaleMinimumValue; + maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - dataBounds[0] = m_userScaleMinimumValue; - dataBounds[1] = m_userScaleMaximumValue; + minimumValue = m_userScaleMinimumValue; + maximumValue = m_userScaleMaximumValue; break; } break; } - if ( ! getAutoRangeMinimumAndMaximum(dataBounds, + if ( ! getAutoRangeMinimumAndMaximum(minimumValue, + maximumValue, labelsStart, labelsEnd, labelsStep, @@ -815,9 +799,6 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float dataBoundsIn[4], const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; labelNumericValues.push_back(labelValueForText); scaleValuesOffsetInPixelsOut.push_back(labelPixelsPosition); - -// const AString labelText = AString::number(labelValueForText, 'f', labelsDigitsRightOfDecimal); -// labelTextOut.push_back(labelText); } else { // std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 2c455e879..0a186b2ac 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -98,12 +98,13 @@ namespace caret { void setShowTickmarks(const bool showTickmarks); - bool getScaleValuesAndOffsets(const float dataBoundsIn[4], - const float axisLengthInPixels, - float& minimumOut, - float& maximumOut, - std::vector& scaleValuesOffsetInPixelsOut, - std::vector& scaleValuesOut) const; + bool getScaleValuesAndOffsets(const float minimumDataValue, + const float maximumDataValue, + const float axisLengthInPixels, + float& minimumOut, + float& maximumOut, + std::vector& scaleValuesOffsetInPixelsOut, + std::vector& scaleValuesOut) const; int32_t getTitleOverlayIndex(const int32_t maximumNumberOfOverlays) const; @@ -137,7 +138,8 @@ namespace caret { private: void copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); - bool getAutoRangeMinimumAndMaximum(const float dataBounds[4], + bool getAutoRangeMinimumAndMaximum(const float minimumValue, + const float maximumValue, float& minimumOut, float& maximumOut, float& stepValueOut, -- GitLab From 010da3c8026bf377ca507a80ef71bb8c9cec7638 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 14 Jul 2017 14:36:39 -0500 Subject: [PATCH 321/755] Changed the minimum font size for percentage size text from 10 pixels height to 1 pixel height. When the font height in pixels gets too small, an OpenGL warning is logged at the 'warning' level. It appears that the OpenGL errors may be caused by specific characters within a font and not necessarily the height of the font. In addition, the font errors were also found to be different on Mac and Linux. --- src/Annotations/AnnotationText.cxx | 19 +++++++++++-- src/Brain/FtglFontTextRenderer.cxx | 44 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index 9bd6b867e..719cfdc62 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -442,9 +442,19 @@ AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportWidth, { float sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(AnnotationTextFontPointSizeEnum::SIZE14); + /* + * Minimum pixel size for text that is sized as a percent of height (tab/window). + * Note that some characters in a font may cause an OpenGL error and this + * error may unique to the underlying OpenGL implementation. + */ + const float minimumPixelSizeForPercentageText = 1.0; + switch (m_fontSizeType) { case AnnotationTextFontSizeTypeEnum::POINTS: sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(m_fontPointSize); + if (sizeForDrawing < AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric()) { + sizeForDrawing = AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric(); + } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { @@ -453,6 +463,9 @@ AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportWidth, */ const float pixelSize = drawingViewportHeight * (m_fontPercentViewportSize / 100.0); sizeForDrawing = pixelSize; + if (sizeForDrawing < minimumPixelSizeForPercentageText) { + sizeForDrawing = minimumPixelSizeForPercentageText; + } } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: @@ -462,13 +475,13 @@ AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportWidth, */ const float pixelSize = drawingViewportWidth * (m_fontPercentViewportSize / 100.0); sizeForDrawing = pixelSize; + if (sizeForDrawing < minimumPixelSizeForPercentageText) { + sizeForDrawing = minimumPixelSizeForPercentageText; + } } break; } - if (sizeForDrawing < AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric()) { - sizeForDrawing = AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric(); - } const int32_t sizeInt = static_cast(MathFunctions::round(sizeForDrawing)); return sizeInt; diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 51762320e..fbc20c66a 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -791,6 +791,12 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann return; } + GLenum errorCode = glGetError(); + if (errorCode != GL_NO_ERROR) { + CaretLogWarning("OpenGL Error at begininng of FtglFontTextRenderer::getBoundsForTextAtViewportCoords(): " + + AString((char*)gluErrorString(errorCode))); + } + TextStringGroup textStringGroup(annotationText, font, viewportX, @@ -805,6 +811,44 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann topRightOut, topLeftOut, rotationPointXYZ); + + errorCode = glGetError(); + if (errorCode != GL_NO_ERROR) { + AString sizeMessage; + switch (annotationText.getFontSizeType()) { + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: + { + const float percentSize = annotationText.getFontPercentViewportSize(); + const float fontHeight = (percentSize / 100.0f) * viewportHeight; + sizeMessage = ("Percent of viewport height=" + + AString::number(percentSize, 'f', 2) + + "%, viewport height=" + AString::number(viewportHeight) + + " approximage font height=" + AString::number(fontHeight, 'f', 2)); + } + break; + case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: + { + const float percentSize = annotationText.getFontPercentViewportSize(); + const float fontHeight = (percentSize / 100.0f) * viewportWidth; + sizeMessage = ("Percent of viewport width=" + + AString::number(percentSize, 'f', 2) + + "%, viewport width=" + AString::number(viewportWidth) + + " approximage font height=" + AString::number(fontHeight, 'f', 2)); + } + break; + case AnnotationTextFontSizeTypeEnum::POINTS: + sizeMessage = ("Font Size=" + + AnnotationTextFontNameEnum::toGuiName(annotationText.getFont())); + break; + } + + CaretLogWarning("OpenGL error at end of FtglFontTextRenderer::getBoundsForTextAtViewportCoords(), " + "error may be caused by font size that is too small. Error may also occur with " + "particular characters in a font.\n" + " Rendering text: " + annotationText.getText() + "\n" + " " + sizeMessage + "\n" + " OpenGL Error=" + AString((char*)gluErrorString(errorCode))); + } } -- GitLab From 5d33928077a700d6a732a33b20ab519cf99b8935 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 18 Jul 2017 15:18:16 -0500 Subject: [PATCH 322/755] Initial implementation of new annotation CHART coordinate space that places annotations at chart data coordinates. --- src/Annotations/Annotation.cxx | 2 + src/Annotations/AnnotationCoordinate.cxx | 21 ++ src/Annotations/AnnotationCoordinate.h | 4 + .../AnnotationCoordinateSpaceEnum.cxx | 8 + .../AnnotationCoordinateSpaceEnum.h | 2 + src/Annotations/AnnotationGroup.cxx | 6 + .../AnnotationOneDimensionalShape.cxx | 139 +++++++++--- .../AnnotationOneDimensionalShape.h | 2 + src/Annotations/AnnotationRedoUndoCommand.cxx | 4 + .../AnnotationSpatialModification.cxx | 47 ++++ .../AnnotationSpatialModification.h | 27 +++ src/Annotations/AnnotationText.cxx | 2 + .../AnnotationTwoDimensionalShape.cxx | 202 ++++++++++++++++++ .../AnnotationTwoDimensionalShape.h | 4 +- src/Brain/AnnotationArrangerExecutor.cxx | 3 + src/Brain/AnnotationManager.cxx | 3 + ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 77 +++++-- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 119 ++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 6 +- .../BrainOpenGLChartTwoDrawingInterface.h | 4 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 84 +++++++- src/Brain/BrainOpenGLFixedPipeline.h | 4 +- src/Brain/BrainOpenGLViewportContent.cxx | 88 +++++++- src/Brain/BrainOpenGLViewportContent.h | 25 ++- src/Brain/DisplayPropertiesAnnotation.cxx | 5 + src/Brain/FtglFontTextRenderer.cxx | 2 + .../DisplayGroupAndTabItemInterface.cxx | 16 ++ src/Common/DisplayGroupAndTabItemInterface.h | 2 + src/Files/AnnotationFile.cxx | 7 + .../AnnotationChangeCoordinateDialog.cxx | 2 + src/GuiQt/AnnotationCoordinateInformation.cxx | 82 +++++++ src/GuiQt/AnnotationCoordinateInformation.h | 3 + .../AnnotationCoordinateSelectionWidget.cxx | 79 +++++++ src/GuiQt/AnnotationCoordinateSpaceWidget.cxx | 2 + src/GuiQt/AnnotationCoordinateWidget.cxx | 12 ++ src/GuiQt/AnnotationCreateDialog.cxx | 124 ++++++++++- src/GuiQt/AnnotationCreateDialog.h | 6 +- src/GuiQt/AnnotationFontWidget.cxx | 2 + src/GuiQt/AnnotationInsertNewWidget.cxx | 135 +++++++++++- src/GuiQt/AnnotationInsertNewWidget.h | 2 + src/GuiQt/AnnotationPasteDialog.cxx | 2 + src/GuiQt/AnnotationRotationWidget.cxx | 4 + .../AnnotationSelectionViewController.cxx | 1 + .../BrainBrowserWindowToolBarChartType.cxx | 92 -------- src/GuiQt/UserInputModeAnnotations.cxx | 44 ++++ .../UserInputModeAnnotationsContextMenu.cxx | 49 +++-- .../UserInputModeAnnotationsContextMenu.h | 2 +- 47 files changed, 1327 insertions(+), 231 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index ee4c99313..388123552 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -270,6 +270,8 @@ bool Annotation::isDeletable() const { switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Annotations/AnnotationCoordinate.cxx b/src/Annotations/AnnotationCoordinate.cxx index 036a29c04..2b5bd4b05 100644 --- a/src/Annotations/AnnotationCoordinate.cxx +++ b/src/Annotations/AnnotationCoordinate.cxx @@ -220,6 +220,27 @@ AnnotationCoordinate::setXYZ(const float x, } } +/** + * Add to the annotation's XYZ coordinate. + * + * @param dx + * Change in X-coordinate for the annotation. + * @param dy + * Change in Y-coordinate for the annotation. + * @param dz + * Change in Z-coordinate for the annotation. + */ +void +AnnotationCoordinate::addToXYZ(const float dx, + const float dy, + const float dz) +{ + setXYZ(m_xyz[0] + dx, + m_xyz[1] + dy, + m_xyz[2] + dz); +} + + /** * Set the window or tab XYZ from viewport X, Y. * diff --git a/src/Annotations/AnnotationCoordinate.h b/src/Annotations/AnnotationCoordinate.h index 7e8279f3e..1234146f7 100644 --- a/src/Annotations/AnnotationCoordinate.h +++ b/src/Annotations/AnnotationCoordinate.h @@ -53,6 +53,10 @@ namespace caret { const float y, const float z); + void addToXYZ(const float dx, + const float dy, + const float dz); + void setXYZFromViewportXYZ(const float viewportWidth, const float viewportHeight, const float viewportX, diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx index 43e72a8a8..0c767caae 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.cxx +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.cxx @@ -110,6 +110,11 @@ AnnotationCoordinateSpaceEnum::initialize() } initializedFlag = true; + enumData.push_back(AnnotationCoordinateSpaceEnum(CHART, + "CHART", + "Chart", + "Ch")); + enumData.push_back(AnnotationCoordinateSpaceEnum(STEREOTAXIC, "STEREOTAXIC", "Stereotaxic", @@ -299,6 +304,9 @@ AnnotationCoordinateSpaceEnum::toToolTip(Enum enumValue) AString text; switch (enumValue) { + case CHART: + text = "New annotation is drawn at a chart data XYZ coordinate"; + break; case STEREOTAXIC: text = "New annotation is drawn at a surface/volume XYZ coordinate"; break; diff --git a/src/Annotations/AnnotationCoordinateSpaceEnum.h b/src/Annotations/AnnotationCoordinateSpaceEnum.h index e8d2d45f6..3dc4a839f 100644 --- a/src/Annotations/AnnotationCoordinateSpaceEnum.h +++ b/src/Annotations/AnnotationCoordinateSpaceEnum.h @@ -35,6 +35,8 @@ public: * Enumerated values. */ enum Enum { + /** Chart space */ + CHART, /** Annotation in stereotaxic (3D) space */ STEREOTAXIC, /** Annotation on surface node */ diff --git a/src/Annotations/AnnotationGroup.cxx b/src/Annotations/AnnotationGroup.cxx index 82a9b143f..4f71c5bbf 100644 --- a/src/Annotations/AnnotationGroup.cxx +++ b/src/Annotations/AnnotationGroup.cxx @@ -93,6 +93,8 @@ SceneableInterface() m_tabOrWindowIndex = tabOrWindowIndex; switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -259,6 +261,8 @@ AnnotationGroup::getName() const AString spaceName = AnnotationCoordinateSpaceEnum::toGuiName(m_coordinateSpace); switch (m_coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -419,6 +423,8 @@ AnnotationGroup::validateAddedAnnotation(const Annotation* annotation) } switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index 41f2ce996..99da13564 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -315,12 +315,16 @@ AnnotationOneDimensionalShape::setRotationAngle(const float viewportWidth, bool AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { + bool chartFlag = false; bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; bool viewportFlag = false; switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + chartFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereotaxicFlag = true; break; @@ -340,42 +344,41 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp bool validFlag = false; -// if ( ! pixelsFlag) { - switch (sizingHandle) { - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: + switch (sizingHandle) { + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: + validFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: + validFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: + if (chartFlag + || tabWindowFlag) { validFlag = true; - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: + if (tabWindowFlag) { validFlag = true; - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: - if (tabWindowFlag) { - validFlag = true; - } - break; - case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: - if (tabWindowFlag) { - validFlag = true; - } - break; - } -// } + } + break; + } return validFlag; } @@ -602,6 +605,71 @@ AnnotationOneDimensionalShape::applySpatialModificationTabOrWindowSpace(const An return validFlag; } +/** + * Apply a spatial modification to an annotation in chart space. + * + * @param spatialModification + * Contains information about the spatial modification. + * @return + * True if the annotation was modified, else false. + */ +bool +AnnotationOneDimensionalShape::applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification) +{ + bool validFlag = false; + + switch (spatialModification.m_sizingHandleType) { + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: + if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { + m_endCoordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); + validFlag = true; + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: + if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { + m_startCoordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); + validFlag = true; + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: + if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid + && spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZValid) { + const float dx = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[0] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[0]; + const float dy = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[1] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[1]; + const float dz = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[2] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[2]; + + m_startCoordinate->addToXYZ(dx, dy, dz); + m_endCoordinate->addToXYZ(dx, dy, dz); + validFlag = true; + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: + break; + } + + if (validFlag) { + setModified(); + } + + return validFlag; +} + /** * Apply a spatial modification to an annotation in stereotaxic space. * @@ -673,6 +741,9 @@ AnnotationOneDimensionalShape::applySpatialModification(const AnnotationSpatialM } switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + return applySpatialModificationChartSpace(spatialModification); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationStereotaxicSpace(spatialModification); break; diff --git a/src/Annotations/AnnotationOneDimensionalShape.h b/src/Annotations/AnnotationOneDimensionalShape.h index b116506e5..e9f05f9dc 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.h +++ b/src/Annotations/AnnotationOneDimensionalShape.h @@ -86,6 +86,8 @@ namespace caret { void initializeMembersAnnotationOneDimensionalShape(); + bool applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification); + bool applySpatialModificationSurfaceSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationStereotaxicSpace(const AnnotationSpatialModification& spatialModification); diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index 9064b61ca..e9921c1ad 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -1362,6 +1362,8 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValid = false; switch (oneDimAnn->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -1873,6 +1875,8 @@ AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercent float percentSize = newFontPercentSize; switch (redoAnnotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: percentSize *= surfaceSpaceRowCount; break; diff --git a/src/Annotations/AnnotationSpatialModification.cxx b/src/Annotations/AnnotationSpatialModification.cxx index f4e3ebdcb..f78b65882 100644 --- a/src/Annotations/AnnotationSpatialModification.cxx +++ b/src/Annotations/AnnotationSpatialModification.cxx @@ -80,6 +80,10 @@ m_mouseDX(mouseDX), m_mouseDY(mouseDY), m_startOfDraggingFlag(startOfDraggingFlag) { + m_chartCoordAtMouseXY.m_chartXYZValid = false; + m_chartCoordAtPreviousMouseXY.m_chartXYZValid = false; + m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid = false; + m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid = false; } /** @@ -137,6 +141,49 @@ AnnotationSpatialModification::setStereotaxicCoordinateAtMouseXY(const float ste m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid = true; } +/** + * Set the chart coordinate at mouse X/Y + * + * @param chartX + * chart X-coordinate. + * @param chartY + * chart Y-coordinate. + * @param chartZ + * chart Z-coordinate. + */ +void +AnnotationSpatialModification::setChartCoordinateAtMouseXY(const float chartX, + const float chartY, + const float chartZ) +{ + m_chartCoordAtMouseXY.m_chartXYZ[0] = chartX; + m_chartCoordAtMouseXY.m_chartXYZ[1] = chartY; + m_chartCoordAtMouseXY.m_chartXYZ[2] = chartZ; + m_chartCoordAtMouseXY.m_chartXYZValid = true; +} + +/** + * Set the chart coordinate at previous mouse X/Y + * + * @param chartX + * chart X-coordinate. + * @param chartY + * chart Y-coordinate. + * @param chartZ + * chart Z-coordinate. + */ +void +AnnotationSpatialModification::setChartCoordinateAtPreviousMouseXY(const float chartX, + const float chartY, + const float chartZ) +{ + m_chartCoordAtPreviousMouseXY.m_chartXYZ[0] = chartX; + m_chartCoordAtPreviousMouseXY.m_chartXYZ[1] = chartY; + m_chartCoordAtPreviousMouseXY.m_chartXYZ[2] = chartZ; + m_chartCoordAtPreviousMouseXY.m_chartXYZValid = true; +} + + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Annotations/AnnotationSpatialModification.h b/src/Annotations/AnnotationSpatialModification.h index ea2a7d6b8..4699198f3 100644 --- a/src/Annotations/AnnotationSpatialModification.h +++ b/src/Annotations/AnnotationSpatialModification.h @@ -52,6 +52,14 @@ namespace caret { const float stereotaxicY, const float stereotaxicZ); + void setChartCoordinateAtMouseXY(const float chartX, + const float chartY, + const float chartZ); + + void setChartCoordinateAtPreviousMouseXY(const float chartX, + const float chartY, + const float chartZ); + virtual ~AnnotationSpatialModification(); @@ -77,6 +85,21 @@ namespace caret { bool m_surfaceNodeValid; }; + class ChartCoord { + public: + ChartCoord() { + m_chartXYZ[0] = 0.0; + m_chartXYZ[1] = 0.0; + m_chartXYZ[2] = 0.0; + + m_chartXYZValid = false; + } + + float m_chartXYZ[3]; + + bool m_chartXYZValid; + }; + class StereotaxicCoord { public: @@ -117,6 +140,10 @@ namespace caret { const bool m_startOfDraggingFlag; + ChartCoord m_chartCoordAtMouseXY; + + ChartCoord m_chartCoordAtPreviousMouseXY; + SurfaceCoord m_surfaceCoordinateAtMouseXY; StereotaxicCoord m_stereotaxicCoordinateAtMouseXY; diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index 719cfdc62..a99223838 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -731,6 +731,8 @@ bool AnnotationText::isFontColorGuiEditable() const { switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 4ed200be9..6891d080b 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -328,12 +328,16 @@ AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const An bool AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { + bool chartFlag = false; bool tabWindowFlag = false; bool stereotaxicFlag = false; bool surfaceFlag = false; bool viewportFlag = false; switch (getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + chartFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereotaxicFlag = true; break; @@ -452,6 +456,198 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp return validFlag; } +/** + * Apply a spatial modification to an annotation in chart space. + * + * @param spatialModification + * Contains information about the spatial modification. + * @return + * True if the annotation was modified, else false. + */ +bool +AnnotationTwoDimensionalShape::applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification) +{ + bool validFlag = false; + + const float rotationRadians = MathFunctions::toRadians(m_rotationAngle); + float dx = (spatialModification.m_mouseDX * std::cos(rotationRadians) + - spatialModification.m_mouseDY * std::sin(rotationRadians)); + float dy = (spatialModification.m_mouseDX * std::sin(rotationRadians) + + spatialModification.m_mouseDY * std::cos(rotationRadians)); + + + if (spatialModification.m_viewportWidth > 0) { + dx = (dx / spatialModification.m_viewportWidth) * 100.0; + } + else { + dx = 0.0; + } + if (spatialModification.m_viewportHeight > 0) { + dy = (dy / spatialModification.m_viewportHeight) * 100.0; + } + else { + dy = 0.0; + } + + bool validDxyFlag = false; + + switch (spatialModification.m_sizingHandleType) { + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: + dx = 0.0; + dy = -dy; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: + dx = -dx; + dy = -dy; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: + dy = -dy; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: + dx = -dx; + dy = 0.0; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: + dy = 0.0; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: + dx = 0.0; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: + dx = -dx; + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: + validDxyFlag = true; + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: + if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { + m_coordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); + validFlag = true; + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: + { + static float centerX = 0.0; + static float centerY = 0.0; + + /* + * Stereotaxic and surface rotations may be displayed in + * multiple locations if more that one surface is dislayed + * when surface montage is viewed and/or tile tabs is enabled. + * + * We don't have the window location of the annotation but + * we can estimate it as it is in the center of the annotation. + * Once we have approximated the center we can use the center + * as the rotation point and so that the rotation handle points + * to the mouse. During rotation, the center will not change + * so set its position when the user starts to drag the mouse. + */ + if (spatialModification.m_startOfDraggingFlag) { + const float height = ((m_height / 100.0) * spatialModification.m_viewportHeight); + const float halfHeight = height / 2.0; + + const float handleOffsetHeight = 15.0; + const float centerAngleRadians = MathFunctions::toRadians(m_rotationAngle - 90); + const float centerOffsetY = (halfHeight + handleOffsetHeight) * std::sin(centerAngleRadians); + const float centerOffsetX = -halfHeight * std::cos(centerAngleRadians); + centerX = spatialModification.m_mousePressX + centerOffsetX; + centerY = spatialModification.m_mousePressY + centerOffsetY; + } + + /* + * Rotation angle is a formed by the triangle + * (Mouse XY, Annotation XY, Positive X-axis). + */ + const float dy = (spatialModification.m_mouseY + - centerY); + const float dx = (spatialModification.m_mouseX + - centerX); + + const float angleRadians = std::atan2(dy, dx); + const float angleDegrees = MathFunctions::toDegrees(angleRadians); + m_rotationAngle = 90.0 - angleDegrees; + if (m_rotationAngle > 360.0) { + m_rotationAngle -= 360.0; + } + else if (m_rotationAngle < 0.0) { + m_rotationAngle += 360.0; + } + + validFlag = true; + } + break; + } + + if (validDxyFlag) { + if (isFixedAspectRatio()) { + switch (spatialModification.m_sizingHandleType) { + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: + if (std::fabs(dx) > std::fabs(dy)) { + /* + * For fixed aspect ratio, the width percentage is not a percentage + * of window width but of the window's height since the annotation + * is sized by its height (width = height / aspect). + * + * So when width is changed, need to set height. + */ + const float aspectRatio = getFixedAspectRatio(); + const float newHeight = MathFunctions::limitRange(getHeight() + dx * aspectRatio, 0.0f, 100.0f); + setHeight(newHeight); + validFlag = true; + } + else if (std::fabs(dx) < std::fabs(dy)) { + const float newHeight = MathFunctions::limitRange(getHeight() + dy, 0.0f, 100.0f); + setHeight(newHeight); + validFlag = true; + } + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: + break; + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: + case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: + break; + } + } + else { + if (dx != 0.0) { + m_width += dx; + m_width = MathFunctions::limitRange(m_width, 1.0f, 100.0f); + validFlag = true; + } + if (dy != 0.0) { + m_height += dy; + m_height = MathFunctions::limitRange(m_height, 1.0f, 100.0f); + validFlag = true; + } + } + } + + if (validFlag) { + setModified(); + } + + return validFlag; +} + /** * Apply a spatial modification to an annotation in surface * or stereotaxic space. @@ -472,6 +668,9 @@ AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace bool surfaceSpaceFlag = false; switch (coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + badSpaceFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereoSpaceFlag = true; break; @@ -1111,6 +1310,9 @@ AnnotationTwoDimensionalShape::applySpatialModification(const AnnotationSpatialM const AnnotationCoordinateSpaceEnum::Enum space = getCoordinateSpace(); switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: + return applySpatialModificationChartSpace(spatialModification); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationSurfaceOrStereotaxicSpace(spatialModification, space); diff --git a/src/Annotations/AnnotationTwoDimensionalShape.h b/src/Annotations/AnnotationTwoDimensionalShape.h index 5d93898f3..9bc0117d9 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.h +++ b/src/Annotations/AnnotationTwoDimensionalShape.h @@ -119,10 +119,10 @@ namespace caret { bool applySpatialModificationSurfaceOrStereotaxicSpace(const AnnotationSpatialModification& spatialModification, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace); -// bool applySpatialModificationStereotaxicSpace(const AnnotationSpatialModification& spatialModification); - bool applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification); + bool applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification); + bool rotationAngleTest(const float previousMouseXYZ[3], const float shapeXYZ[3], const float currentMouseXYZ[3]) const; diff --git a/src/Brain/AnnotationArrangerExecutor.cxx b/src/Brain/AnnotationArrangerExecutor.cxx index c230a6e56..210fc7ac0 100644 --- a/src/Brain/AnnotationArrangerExecutor.cxx +++ b/src/Brain/AnnotationArrangerExecutor.cxx @@ -612,6 +612,9 @@ AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& */ int32_t annViewport[4] = { 0, 0, 0, 0 }; switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + CaretAssert(0); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: CaretAssert(0); break; diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 727337620..45d428ffc 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -979,6 +979,9 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ bool displayedFlag = false; switch (ann->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + displayedFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: displayedFlag = true; break; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 936468129..90a54141b 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -160,8 +160,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c { const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace = annotation->getCoordinateSpace(); - float stereotaxicXYZ[3] = { 0.0, 0.0, 0.0 }; - bool stereotaxicXYZValid = false; + float modelXYZ[3] = { 0.0, 0.0, 0.0 }; + bool modelXYZValid = false; float drawingSpaceXYZ[3] = { 0.0, 0.0, 0.0 }; bool drawingSpaceXYZValid = false; @@ -170,30 +170,36 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c coordinate->getXYZ(annotationXYZ); switch (annotationCoordSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + modelXYZ[0] = annotationXYZ[0]; + modelXYZ[1] = annotationXYZ[1]; + modelXYZ[2] = annotationXYZ[2]; + modelXYZValid = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - stereotaxicXYZ[0] = annotationXYZ[0]; - stereotaxicXYZ[1] = annotationXYZ[1]; - stereotaxicXYZ[2] = annotationXYZ[2]; - stereotaxicXYZValid = true; + modelXYZ[0] = annotationXYZ[0]; + modelXYZ[1] = annotationXYZ[1]; + modelXYZ[2] = annotationXYZ[2]; + modelXYZValid = true; if (m_volumeSpacePlaneValid) { float xyzFloat[3] = { - stereotaxicXYZ[0], - stereotaxicXYZ[1], - stereotaxicXYZ[2] + modelXYZ[0], + modelXYZ[1], + modelXYZ[2] }; const float distToPlaneAbs = std::fabs(m_volumeSpacePlane.signedDistanceToPlane(xyzFloat)); const float halfSliceThickness = ((m_volumeSliceThickness > 0.0) ? (m_volumeSliceThickness / 2.0) : 1.0); if (distToPlaneAbs < halfSliceThickness) { //1.5) { - stereotaxicXYZValid = true; + modelXYZValid = true; float projectedPoint[3]; - m_volumeSpacePlane.projectPointToPlane(stereotaxicXYZ, projectedPoint); + m_volumeSpacePlane.projectPointToPlane(modelXYZ, projectedPoint); } else { - stereotaxicXYZValid = false; + modelXYZValid = false; } } break; @@ -219,9 +225,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c float nodeXYZ[3]; surfaceDisplayed->getCoordinate(annotationNodeIndex, nodeXYZ); - stereotaxicXYZ[0] = nodeXYZ[0]; - stereotaxicXYZ[1] = nodeXYZ[1]; - stereotaxicXYZ[2] = nodeXYZ[2]; + modelXYZ[0] = nodeXYZ[0]; + modelXYZ[1] = nodeXYZ[1]; + modelXYZ[2] = nodeXYZ[2]; @@ -258,10 +264,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c break; } - stereotaxicXYZ[0] += (offsetUnitVector[0] * annotationOffsetLength); - stereotaxicXYZ[1] += (offsetUnitVector[1] * annotationOffsetLength); - stereotaxicXYZ[2] += (offsetUnitVector[2] * annotationOffsetLength); - stereotaxicXYZValid = true; + modelXYZ[0] += (offsetUnitVector[0] * annotationOffsetLength); + modelXYZ[1] += (offsetUnitVector[1] * annotationOffsetLength); + modelXYZ[2] += (offsetUnitVector[2] * annotationOffsetLength); + modelXYZValid = true; } } } @@ -301,14 +307,14 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c break; } - if (stereotaxicXYZValid) { + if (modelXYZValid) { /* * Convert model space coordinates to window coordinates * as all annotations are drawn in window coordinates. */ - if (convertModelToWindowCoordinate(stereotaxicXYZ, drawingSpaceXYZ)) { - stereotaxicXYZValid = false; + if (convertModelToWindowCoordinate(modelXYZ, drawingSpaceXYZ)) { + modelXYZValid = false; drawingSpaceXYZValid = true; } else { @@ -622,6 +628,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat bool haveDisplayGroupFlag = true; switch (drawingCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -724,6 +732,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat annotationFile = m_dummyAnnotationFile; switch (drawingCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -1090,6 +1100,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota bool drawnFlag = false; switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -2354,6 +2366,27 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi topLeft, outlineWidth, text->getRotationAngle()); + + /* + * Cross can be used to show the text annotation's coordinate + * to assist with placement of the annotation + */ + const bool drawCrossFlag = false; + if (drawCrossFlag) { + const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; + std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + redRGBA)); + crossShape->addVertex(annXYZ[0], + annXYZ[1] - 10); + crossShape->addVertex(annXYZ[0], + annXYZ[1] + 10); + crossShape->addVertex(annXYZ[0] - 10, + annXYZ[1]); + crossShape->addVertex(annXYZ[0] + 10, + annXYZ[1]); + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + crossShape.get()); + } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index f167d68df..7d4713360 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -30,8 +30,10 @@ #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "Brain.h" +#include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" +#include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -94,8 +96,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * * @param brain * Brain. - * @param browserTabContent - * Content of the browser tab. + * @param viewportContent + * Content of the viewport * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing @@ -110,7 +112,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, - BrowserTabContent* browserTabContent, + BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, @@ -120,11 +122,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, viewportSpaceAnnotationsOut.clear(); m_viewportSpaceAnnotationsOut.clear(); + BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); + CaretAssert(browserTabContent); CaretAssert(brain); CaretAssert(browserTabContent); CaretAssert(chartTwoModel); CaretAssert(fixedPipelineDrawing); + m_brain = brain; + m_viewportContent = viewportContent; m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = fixedPipelineDrawing->getTextRenderer(); @@ -161,6 +167,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, for (auto cb : colorBars) { bool useItFlag = false; switch (cb->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -248,28 +256,47 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, topOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); - if (mapFile != NULL) { - const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); - switch (chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - if (drawHistogramFlag) { - drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); - } - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - if (drawLineSeriesFlag) { - drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); - } - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - if (drawMatrixFlag) { - drawMatrixChart(); - } - break; - } + if (mapFile != NULL) { + const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); + switch (chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + if (drawHistogramFlag) { + drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + if (drawLineSeriesFlag) { + drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + if (drawMatrixFlag) { + drawMatrixChart(); + } + break; } + + /* + * Draw annotations for the chart. + */ + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(m_fixedPipelineDrawing->m_brain, + m_fixedPipelineDrawing->mode, + BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_fixedPipelineDrawing->m_tabViewport, + m_fixedPipelineDrawing->m_windowIndex, + m_fixedPipelineDrawing->windowTabIndex, + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + std::vector emptyColorBars; + std::vector emptyViewportAnnotations; + m_fixedPipelineDrawing->m_annotationDrawing->drawAnnotations(&inputs, + AnnotationCoordinateSpaceEnum::STEREOTAXIC, + emptyColorBars, + emptyViewportAnnotations, + NULL); + } } } @@ -657,9 +684,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch 0.0); } + /* + * Save the transformation matrices and the viewport + * If there is more than one line chart, this code will be executed + * several times but since the top overlay is drawn last, the contents + * of the top overlay will be used. + */ + updateViewportContentForCharting(chartGraphicsDrawingViewport); + ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, drawInfo->m_allMapsSelected); + if (histogramPrimitives != NULL) { const float ENVELOPE_LINE_WIDTH = 1.0; @@ -808,6 +844,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); } + + /* + * Save the transformation matrices and the viewport + * If there is more than one line chart, this code will be executed + * several times but since the top overlay is drawn last, the contents + * of the top overlay will be used. + */ + updateViewportContentForCharting(chartGraphicsDrawingViewport); } } } @@ -911,6 +955,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() 0.0); } + /* + * Save the transformation matrices and the viewport + * If there is more than one line chart, this code will be executed + * several times but since the top overlay is drawn last, the contents + * of the top overlay will be used. + */ + updateViewportContentForCharting(m_viewport); + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -1681,6 +1733,25 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini return false; } +/** + * Update the viewport content with charting viewport and matrices. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::updateViewportContentForCharting(const int32_t viewport[4]) +{ + GLfloat modelviewArray[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, modelviewArray); + GLfloat projectionArray[16]; + glGetFloatv(GL_PROJECTION_MATRIX, projectionArray); + Matrix4x4 modelviewMatrix; + modelviewMatrix.setMatrixFromOpenGL(modelviewArray); + Matrix4x4 projectionMatrix; + projectionMatrix.setMatrixFromOpenGL(projectionArray); + m_viewportContent->setChartDataMatricesAndViewport(projectionMatrix, + modelviewMatrix, + viewport); +} + /** * Draw the graphics primitive. * diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 9643121a5..8fe40946f 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -54,7 +54,7 @@ namespace caret { virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, - BrowserTabContent* browserTabContent, + BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, @@ -164,8 +164,12 @@ namespace caret { void drawPrimitivePrivate(GraphicsPrimitive* primitive); + void updateViewportContentForCharting(const int32_t viewport[4]); + Brain* m_brain; + BrainOpenGLViewportContent* m_viewportContent; + BrowserTabContent* m_browserTabContent; ModelChartTwo* m_chartTwoModel; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 2d2709c0b..47d58a0c5 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -32,7 +32,7 @@ namespace caret { class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; - class BrowserTabContent; + class BrainOpenGLViewportContent; class ModelChartTwo; class BrainOpenGLChartTwoDrawingInterface { @@ -62,7 +62,7 @@ namespace caret { * by the Annotation OpenGL Drawing. */ virtual void drawChartOverlaySet(Brain* brain, - BrowserTabContent* browserTabContent, + BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 0b93fc709..0bf282c27 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -746,15 +746,81 @@ BrainOpenGLFixedPipeline::drawTabHighlighting(const float width, } } +/** + * Draw the chart coordinate space annotations. + * + * @param tabContent + * Viewport content + */ +void +BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(BrainOpenGLViewportContent* viewportContent) +{ + glPushAttrib(GL_VIEWPORT_BIT); + + Matrix4x4 projectionMatrix; + Matrix4x4 modelviewMatrix; + int viewport[4]; + if (viewportContent->getChartDataMatricesAndViewport(projectionMatrix, + modelviewMatrix, + viewport)) { + + glViewport(viewport[0], + viewport[1], + viewport[2], + viewport[3]); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + float projectionArray[16]; + projectionMatrix.getMatrixForOpenGL(projectionArray); + glLoadMatrixf(projectionArray); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + float modelviewArray[16]; + modelviewMatrix.getMatrixForOpenGL(modelviewArray); + glLoadMatrixf(modelviewArray); + + /* + * Draw annotations for this surface and maybe draw + * the model annotations. + */ + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, + this->mode, + BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, + m_tabViewport, + m_windowIndex, + this->windowTabIndex, + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, + BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); + std::vector emptyColorBars; + std::vector emptyViewportAnnotations; + m_annotationDrawing->drawAnnotations(&inputs, + AnnotationCoordinateSpaceEnum::CHART, + emptyColorBars, + emptyViewportAnnotations, + NULL); + + + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + + glPopAttrib(); +} + + /** * Draw the tab annotations. * - * @param windowViewport - * Viewport (x, y, w, h). + * @param tabContent + * Viewport content */ void BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabContent) -// const int tabViewport[4]) { if (tabContent->getBrowserTabContent() == NULL) { return; @@ -941,7 +1007,7 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, drawChartOneData(browserTabContent, modelChart, viewport); } else if (modelTwoChart != NULL) { - drawChartTwoData(browserTabContent, modelTwoChart, viewport); + drawChartTwoData(viewportContent, modelTwoChart, viewport); } else if (surfaceModel != NULL) { m_mirroredClippingEnabled = true; @@ -5312,15 +5378,15 @@ BrainOpenGLFixedPipeline::drawChartOneData(BrowserTabContent* browserTabContent, /** * Draw a chart two model. * - * @param browserTabContent - * Content of browser tab. + * @param viewportContent + * Content of the viewport * @param chartModel * The chart model. * @param viewport * The viewport (x, y, width, height) */ void -BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, +BrainOpenGLFixedPipeline::drawChartTwoData(BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartModel, const int32_t viewport[4]) { @@ -5332,12 +5398,14 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrowserTabContent* browserTabContent, BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, - browserTabContent, + viewportContent, chartModel, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, m_viewportSpaceAnnotations); + + drawChartCoordinateSpaceAnnotations(viewportContent); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 96b13074e..3aecd4706 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -187,7 +187,7 @@ namespace caret { ModelChart* chartData, const int32_t viewport[4]); - void drawChartTwoData(BrowserTabContent* browserTabContent, + void drawChartTwoData(BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartData, const int32_t viewport[4]); @@ -463,6 +463,8 @@ namespace caret { void drawTabAnnotations(BrainOpenGLViewportContent* tabContent); + void drawChartCoordinateSpaceAnnotations(BrainOpenGLViewportContent* viewportContent); + void drawBackgroundImage(BrainOpenGLViewportContent* vpContent); void drawImage(BrainOpenGLViewportContent* vpContent, diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 0d7255910..c03e212f3 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -92,6 +92,14 @@ m_browserTabContent(browserTabContent) m_modelY = modelViewport[1]; m_modelWidth = modelViewport[2]; m_modelHeight = modelViewport[3]; + + m_chartDataProjectionMatrix.identity(); + m_chartDataModelViewMatrix.identity(); + m_chartDataX = 0; + m_chartDataY = 0; + m_chartDataWidth = 0; + m_chartDataHeight = 0; + m_chartDataViewportValidFlag = false; } /** @@ -139,6 +147,13 @@ BrainOpenGLViewportContent::operator=(const BrainOpenGLViewportContent& obj) void BrainOpenGLViewportContent::initializeMembersBrainOpenGLViewportContent() { + m_chartDataProjectionMatrix.identity(); + m_chartDataModelViewMatrix.identity(); + m_chartDataX = 0; + m_chartDataY = 0; + m_chartDataWidth = 0; + m_chartDataHeight = 0; + m_chartDataViewportValidFlag = false; m_modelX = 0; m_modelY = 0; m_modelWidth = 0; @@ -161,6 +176,13 @@ BrainOpenGLViewportContent::initializeMembersBrainOpenGLViewportContent() void BrainOpenGLViewportContent::copyHelperBrainOpenGLViewportContent(const BrainOpenGLViewportContent& obj) { + m_chartDataProjectionMatrix = obj.m_chartDataProjectionMatrix; + m_chartDataModelViewMatrix = obj.m_chartDataModelViewMatrix; + m_chartDataX = obj.m_chartDataX; + m_chartDataY = obj.m_chartDataY; + m_chartDataWidth = obj.m_chartDataWidth; + m_chartDataHeight = obj.m_chartDataHeight; + m_chartDataViewportValidFlag = obj.m_chartDataViewportValidFlag; m_modelX = obj.m_modelX; m_modelY = obj.m_modelY; m_modelWidth = obj.m_modelWidth; @@ -281,6 +303,58 @@ BrainOpenGLViewportContent::isTabHighlighted() const return m_highlightTab; } +/** + * Get the data bounds and viewport for drawing the chart data. + * + * @param chartDataProjectionMatrixOut + * Output into which projection matrix for drawing chart data loaded. + * @param chartDataModelViewMatrixOut + * Output into which model viewing matrix for drawing chart data loaded. + * @param chartViewportOut + * Output into which viewport is loaded. + * (x, y, width, height) + * @return + * True if the chart data viewport is valid. + */ +bool +BrainOpenGLViewportContent::getChartDataMatricesAndViewport(Matrix4x4& chartDataProjectionMatrixOut, + Matrix4x4& chartDataModelViewMatrixOut, + int chartViewportOut[4]) const +{ + chartDataProjectionMatrixOut = m_chartDataProjectionMatrix; + chartDataModelViewMatrixOut = m_chartDataModelViewMatrix; + chartViewportOut[0] = m_chartDataX; + chartViewportOut[1] = m_chartDataY; + chartViewportOut[2] = m_chartDataWidth; + chartViewportOut[3] = m_chartDataHeight; + return m_chartDataViewportValidFlag; +} + +/** + * Set the viewport for drawing the chart data. + * + * @param chartDataProjectionMatrix + * Pojection matrix for drawing chart data. + * @param chartDataModelViewMatrix + * Viewing matrix for drawing chart data. + * @param chartDataViewport + * Viewport (x, y, width, height). + */ +void +BrainOpenGLViewportContent::setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, + const Matrix4x4& chartDataModelViewMatrix, + const int chartViewport[4]) +{ + m_chartDataProjectionMatrix = chartDataProjectionMatrix; + m_chartDataModelViewMatrix = chartDataModelViewMatrix; + m_chartDataX = chartViewport[0]; + m_chartDataY = chartViewport[1]; + m_chartDataWidth = chartViewport[2]; + m_chartDataHeight = chartViewport[3]; + m_chartDataViewportValidFlag = true; +} + + /** * Get the viewport for drawing the model (has been reduced * from tab viewport by applying the margin). @@ -373,7 +447,19 @@ BrainOpenGLViewportContent::toString() const const QString tabMsg = QString(" Tab x=%1 y=%2 w=%3 h=%4").arg(m_tabX).arg(m_tabY).arg(m_tabWidth).arg(m_tabHeight); const QString modelMsg = QString(" Model x=%1 y=%2 w=%3 h=%4").arg(m_modelX).arg(m_modelY).arg(m_modelWidth).arg(m_modelHeight); - AString msgOut(windowMsg); + AString msgOut; + if (m_chartDataViewportValidFlag) { + const QString chartProjectionMsg = QString(" Chart Projection=" + m_chartDataProjectionMatrix.toFormattedString(" ")); + const QString chartModelMsg = QString(" Chart Model View=" + m_chartDataModelViewMatrix.toFormattedString(" ")); + const QString chartViewportMsg = QString(" Chart x=%1 y=%2 w=%3 h=%4").arg(m_chartDataX).arg(m_chartDataY).arg(m_chartDataWidth).arg(m_chartDataHeight); + msgOut.appendWithNewLine(chartProjectionMsg); + msgOut.appendWithNewLine(chartModelMsg); + msgOut.appendWithNewLine(chartViewportMsg); + } + else { + msgOut.appendWithNewLine(" Chart Invalid."); + } + msgOut.appendWithNewLine(windowMsg); msgOut.appendWithNewLine(tabMsg); msgOut.appendWithNewLine(modelMsg); diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index 04a68cde2..504623e00 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -21,8 +21,8 @@ */ /*LICENSE_END*/ - #include "CaretObject.h" +#include "Matrix4x4.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" @@ -41,6 +41,14 @@ namespace caret { BrainOpenGLViewportContent& operator=(const BrainOpenGLViewportContent& obj); + bool getChartDataMatricesAndViewport(Matrix4x4& chartDataProjectionMatrixOut, + Matrix4x4& chartDataModelViewMatrixOut, + int chartViewportOut[4]) const; + + void setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, + const Matrix4x4& chartDataModelViewMatrix, + const int chartViewport[4]); + void getModelViewport(int modelViewportOut[4]) const; void getSurfaceMontageModelViewport(const int32_t montageX, @@ -147,6 +155,21 @@ namespace caret { /** Tab viewport's Height */ int m_tabHeight; + /** Chart data viewport's X-coordinate */ + int m_chartDataX; + /** Chart data viewport's Y-coordinate */ + int m_chartDataY; + /** Chart data viewport's Width */ + int m_chartDataWidth; + /** Chart data viewport's Height */ + int m_chartDataHeight; + /** Chart data viewport's validity */ + bool m_chartDataViewportValidFlag = false; + /** Chart data transformation matrix */ + Matrix4x4 m_chartDataModelViewMatrix; + /** Chart data transformation matrix */ + Matrix4x4 m_chartDataProjectionMatrix; + /** Model viewport's X-coordinate */ int m_modelX; /** Model viewport's Y-coordinate */ diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index a1d407147..fd7a5f1fa 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -87,6 +87,8 @@ DisplayPropertiesAnnotation::updateForNewAnnotation(const Annotation* annotation CaretAssert(annotation); switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -414,6 +416,9 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) annIter++) { Annotation* ann = *annIter; switch (ann->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + CaretAssertMessage(0, "This should never happen as CHART SPACE was never available in a version one scene"); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (stereoAnnDisplay != NULL) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index fbc20c66a..fd303e601 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -183,6 +183,8 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, int32_t viewportHeight = m_viewportHeight; switch (annotationText.getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/Common/DisplayGroupAndTabItemInterface.cxx b/src/Common/DisplayGroupAndTabItemInterface.cxx index 851663622..a0b4a047f 100644 --- a/src/Common/DisplayGroupAndTabItemInterface.cxx +++ b/src/Common/DisplayGroupAndTabItemInterface.cxx @@ -139,6 +139,22 @@ DisplayGroupAndTabItemInterface::setItemDisplaySelectedInAllGroups() } } +/** + * Set the display status to UNSELECTED for all groups (except TAB). + */ +void +DisplayGroupAndTabItemInterface::setItemDisplaySelectedInNoDisplayGroups() +{ + std::vector groupEnums; + DisplayGroupEnum::getAllEnumsExceptTab(groupEnums); + + for (auto group : groupEnums) { + setItemDisplaySelected(group, + 0, + TriStateSelectionStatusEnum::UNSELECTED); + } +} + /** * Set the display status to SELECTED for the given group (not TAB) and * UNSELECTED for all other groups (not TAB). diff --git a/src/Common/DisplayGroupAndTabItemInterface.h b/src/Common/DisplayGroupAndTabItemInterface.h index d0a17f64a..aab162aa4 100644 --- a/src/Common/DisplayGroupAndTabItemInterface.h +++ b/src/Common/DisplayGroupAndTabItemInterface.h @@ -158,6 +158,8 @@ namespace caret { virtual void setItemDisplaySelectedInAllGroups(); + virtual void setItemDisplaySelectedInNoDisplayGroups(); + virtual void setItemDisplaySelectedInOneGroup(const DisplayGroupEnum::Enum displayGroup); /** diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index 744f96754..e2257a707 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -235,6 +235,8 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) const AnnotationCoordinateSpaceEnum::Enum annotationSpace = annotation->getCoordinateSpace(); int32_t annotationTabOrWindowIndex = -1; switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -256,6 +258,7 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) if (group->getGroupType() == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == annotationSpace) { switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: return group; @@ -275,6 +278,7 @@ AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) } switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: break; @@ -607,6 +611,8 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu } switch (coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -653,6 +659,7 @@ AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnu if (groupType == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == coordinateSpace) { switch (coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: throw DataFileException("There is more than one annotation space group with space " diff --git a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx index cdd5af657..aa6f28b1e 100644 --- a/src/GuiQt/AnnotationChangeCoordinateDialog.cxx +++ b/src/GuiQt/AnnotationChangeCoordinateDialog.cxx @@ -115,6 +115,8 @@ AnnotationChangeCoordinateDialog::createCurrentCoordinateWidget() bool useXyzFlag = true; switch (m_annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index 2c3e1068a..c0e8ea79f 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -100,6 +100,10 @@ AnnotationCoordinateInformation::reset() { m_windowPixelXYZ[0] = 0.0; m_windowPixelXYZ[1] = 0.0; m_windowPixelXYZ[2] = 0.0; + m_chartXYZ[0] = 0.0; + m_chartXYZ[1] = 0.0; + m_chartXYZ[2] = 0.0; + m_chartXYZValid = false; } bool @@ -108,6 +112,9 @@ AnnotationCoordinateInformation::isCoordinateSpaceValid(const AnnotationCoordina bool validSpaceFlag = false; switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: + validSpaceFlag = m_chartXYZValid; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: validSpaceFlag = m_modelXYZValid; break; @@ -159,6 +166,7 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi switch (space) { case AnnotationCoordinateSpaceEnum::VIEWPORT: break; + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: @@ -175,6 +183,13 @@ AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordi addItFlag = coordInfoTwo->isCoordinateSpaceValid(space); switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: + /* + * Both coord info's must be in the SAME TAB + */ + if (coordInfoOne->m_tabIndex != coordInfoTwo->m_tabIndex) { + addItFlag = false; + } case AnnotationCoordinateSpaceEnum::STEREOTAXIC: /* * Both coord info's must be in the SAME TAB @@ -340,6 +355,37 @@ AnnotationCoordinateInformation::createCoordinateInformationFromXY(BrainOpenGLWi } } + if (tabContent != NULL) { + Matrix4x4 projectionMatrix; + Matrix4x4 modelviewMatrix; + int viewport[4]; + if (viewportContent->getChartDataMatricesAndViewport(projectionMatrix, + modelviewMatrix, + viewport)) { + if ((windowX >= viewport[0]) + && (windowX < (viewport[0] + viewport[2])) + && (windowY >= viewport[1]) + && (windowY < (viewport[1] + viewport[3]))) { + double projectionArray[16]; + projectionMatrix.getMatrixForOpenGL(projectionArray); + double modelviewArray[16]; + modelviewMatrix.getMatrixForOpenGL(modelviewArray); + + double chartX = 0.0; + double chartY = 0.0; + double chartZ = 0.0; + if (gluUnProject(windowX, windowY, 0.0, + modelviewArray, projectionArray, viewport, + &chartX, &chartY, &chartZ) == GL_TRUE) { + coordInfoOut.m_chartXYZ[0] = static_cast(chartX); + coordInfoOut.m_chartXYZ[1] = static_cast(chartY); + coordInfoOut.m_chartXYZ[2] = static_cast(chartZ); + coordInfoOut.m_chartXYZValid = true; + } + } + } + } + int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); coordInfoOut.m_windowPixelXYZ[0] = windowX - windowViewport[0]; @@ -427,6 +473,22 @@ AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(Annotati CaretAssert(endCoordinate); switch (coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + if (coordInfoOne->m_chartXYZValid) { + startCoordinate->setXYZ(coordInfoOne->m_chartXYZ); + annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); + + validCoordinateFlag = true; + + if (coordInfoTwo != NULL) { + if (coordInfoTwo->m_chartXYZValid) { + if (endCoordinate != NULL) { + endCoordinate->setXYZ(coordInfoTwo->m_chartXYZ); + } + } + } + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (coordInfoOne->m_modelXYZValid) { startCoordinate->setXYZ(coordInfoOne->m_modelXYZ); @@ -577,6 +639,26 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati AnnotationCoordinate* coordinate = annotation->getCoordinate(); switch (coordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + if (coordInfoOne->m_chartXYZValid) { + coordinate->setXYZ(coordInfoOne->m_chartXYZ); + annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); + + validCoordinateFlag = true; + + if (optionalCoordInfoTwo != NULL) { + if (optionalCoordInfoTwo->m_chartXYZValid) { + float centerXYZ[3] = { + (coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, + (coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, + (coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f + }; + coordinate->setXYZ(centerXYZ); + setWidthHeightWithTabCoordsFlag = true; + } + } + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (coordInfoOne->m_modelXYZValid) { coordinate->setXYZ(coordInfoOne->m_modelXYZ); diff --git a/src/GuiQt/AnnotationCoordinateInformation.h b/src/GuiQt/AnnotationCoordinateInformation.h index 669fe32ec..b951fa170 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.h +++ b/src/GuiQt/AnnotationCoordinateInformation.h @@ -92,6 +92,9 @@ namespace caret { AnnotationSurfaceOffsetVectorTypeEnum::Enum m_surfaceNodeVector; bool m_surfaceNodeValid; + + float m_chartXYZ[3]; + bool m_chartXYZValid; private: AnnotationCoordinateInformation(const AnnotationCoordinateInformation&); diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index f3ee2d4b8..589698e4f 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -83,6 +83,7 @@ m_annotationType(annotationType), m_coordInfo(coordInfo), m_optionalSecondCoordInfo(optionalSecondCoordInfo) { + bool enableChartSpaceFlag = false; bool enableModelSpaceFlag = false; bool enableSurfaceSpaceFlag = false; bool enableTabSpaceFlag = true; @@ -90,24 +91,29 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) switch (m_annotationType) { case AnnotationTypeEnum::BOX: + enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: + enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::LINE: + enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::OVAL: + enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::TEXT: + enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; @@ -169,6 +175,56 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) } } + if (enableChartSpaceFlag) { + if ( ! m_coordInfo.m_chartXYZValid) { + enableChartSpaceFlag = false; + } + if (m_optionalSecondCoordInfo != NULL) { + if ( ! m_optionalSecondCoordInfo->m_chartXYZValid) { + enableChartSpaceFlag = false; + } + /* + * Only allow chart space for two coordinates in the SAME tab. + * If tab space is not enabled, then the two chart coordinates are + * in different tabs. + */ + if ( ! enableTabSpaceFlag) { + enableChartSpaceFlag = false; + } + } + } + + if (enableChartSpaceFlag) { + QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::CHART); + m_spaceButtonGroup->addButton(rb, + AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::CHART)); + + const int rowNum = gridLayout->rowCount(); + gridLayout->addWidget(rb, + rowNum, COLUMN_RADIO_BUTTON); + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[0], 'f', 1)), + rowNum, COLUMN_COORD_X, + Qt::AlignRight); + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[1], 'f', 1)), + rowNum, COLUMN_COORD_Y, + Qt::AlignRight); + gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartXYZ[2], 'f', 1)), + rowNum, COLUMN_COORD_Z, + Qt::AlignRight); + + if (m_optionalSecondCoordInfo != NULL) { + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[0], 'f', 1)), + rowNum, COLUMN_COORD_TWO_X, + Qt::AlignRight); + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[1], 'f', 1)), + rowNum, COLUMN_COORD_TWO_Y, + Qt::AlignRight); + gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartXYZ[2], 'f', 1)), + rowNum, COLUMN_COORD_TWO_Z, + Qt::AlignRight); + } + } + if (enableModelSpaceFlag) { if ( ! m_coordInfo.m_modelXYZValid) { enableModelSpaceFlag = false; @@ -349,11 +405,15 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) */ const AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::TAB; switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; } setSizePolicy(QSizePolicy::Fixed, @@ -490,6 +550,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno float oldViewportHeight = 0.0; switch (oldSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + oldViewportHeight = m_coordInfo.m_tabHeight; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: oldViewportHeight = m_coordInfo.m_tabHeight; break; @@ -522,6 +585,9 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno otherCoordinate->getXYZ(otherXyz); switch (oldSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + diffXyzValid = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -547,6 +613,13 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno float newViewportHeight = 0.0; bool setOtherCoordinateFlag = false; switch (newSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + if (m_coordInfo.m_chartXYZValid) { + coordinate->setXYZ(m_coordInfo.m_chartXYZ); + redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); + newViewportHeight = m_coordInfo.m_tabHeight; + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (m_coordInfo.m_modelXYZValid) { coordinate->setXYZ(m_coordInfo.m_modelXYZ); @@ -755,6 +828,10 @@ AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* float vpWidth = 0.0; float vpHeight = 0.0; switch (imageAnn->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + vpWidth = m_coordInfo.m_tabWidth; + vpHeight = m_coordInfo.m_tabHeight; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: vpWidth = m_coordInfo.m_tabWidth; vpHeight = m_coordInfo.m_tabHeight; @@ -824,6 +901,8 @@ AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Ann CaretAssert(annotation); switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (m_coordInfo.m_tabIndex >= 0) { } diff --git a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx index 869f5aef5..9d801cede 100644 --- a/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx @@ -117,6 +117,8 @@ AnnotationCoordinateSpaceWidget::updateContent(std::vector annotati else { text = AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(space); switch (space) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 461befbfe..f5c94f3ec 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -278,6 +278,16 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) double xyzStep = 0.1; QString suffix("%"); switch (m_annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + xMax = 1000000.0; + xMin = -xMax; + yMax = 1000000.0; + yMin = -yMax; + zMin = xMin; + zMax = xMax; + xyzStep = 1.0; + suffix.clear(); + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: xMax = 10000.0; xMin = -xMax; @@ -381,6 +391,8 @@ AnnotationCoordinateWidget::valueChanged() && (coordinate != NULL)) { bool surfaceFlag = false; switch (m_annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 95c486ad7..486d81070 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -211,7 +211,8 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, needToLaunchDialogFlag = true; } else { - Annotation* newAnn = createAnnotation(newInfo, annotationSpace); + AString errorMessage; + Annotation* newAnn = createAnnotation(newInfo, annotationSpace, errorMessage); if (newAnn != NULL) { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(newAnn); @@ -220,8 +221,12 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, return newAnn; } + if ( ! errorMessage.isEmpty()) { + WuQMessageBox::errorOk(mouseEvent.getOpenGLWidget(), + errorMessage); + return NULL; + } - delete newAnn; needToLaunchDialogFlag = true; } } @@ -251,11 +256,18 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, * Information about the new annotation. * @param annotationSpace * Coordinate space for new annotaiton. + * @param errorMessageOut + * Output with error message. + * @return + * Pointer to new annotation or NULL if creating annotation failed. */ Annotation* AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, - const AnnotationCoordinateSpaceEnum::Enum annotationSpace) + const AnnotationCoordinateSpaceEnum::Enum annotationSpace, + AString& errorMessageOut) { + errorMessageOut.clear(); + Annotation* newAnnotation = NULL; if (newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) { newAnnotation = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::USER); @@ -265,6 +277,9 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, */ bool adjustTextPctSizeFlag = false; switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + adjustTextPctSizeFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: adjustTextPctSizeFlag = true; break; @@ -313,6 +328,49 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, if (newAnnotationInfo.m_coordTwoInfoValid) { coordTwo = &newAnnotationInfo.m_coordTwoInfo; } + else { + bool threeDimSpaceFlag = false; + switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + threeDimSpaceFlag = true; + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + threeDimSpaceFlag = true; + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + threeDimSpaceFlag = true; + break; + case AnnotationCoordinateSpaceEnum::TAB: + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + CaretAssert(0); + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + break; + } + if (threeDimSpaceFlag) { + switch (newAnnotationInfo.m_annotationType) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + delete newAnnotation; + newAnnotation = NULL; + errorMessageOut = ("A line annotation cannot be created from a mouse click in " + + AnnotationCoordinateSpaceEnum::toGuiName(annotationSpace) + + " coordinate space. Hold the mouse down, drag the mouse, and then release the mouse."); + return NULL; + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + } + } const bool validFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(newAnnotation, annotationSpace, &newAnnotationInfo.m_coordOneInfo, @@ -329,7 +387,8 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, finishAnnotationCreation(newAnnotationInfo.m_annotationFile, newAnnotation, - newAnnotationInfo.m_mouseEvent.getBrowserWindowIndex()); + newAnnotationInfo.m_mouseEvent.getBrowserWindowIndex(), + newAnnotationInfo.m_coordOneInfo.m_tabIndex); return newAnnotation; } @@ -649,11 +708,17 @@ AnnotationCreateDialog::okButtonClicked() CaretPointer annotation; annotation.grabNew(NULL); - annotation.grabNew(createAnnotation(m_newAnnotationInfo, space)); + annotation.grabNew(createAnnotation(m_newAnnotationInfo, space, errorMessage)); if (annotation == NULL) { - WuQMessageBox::errorOk(this, - "Failed to create annotation in space: " - + AnnotationCoordinateSpaceEnum::toGuiName(space)); + if (errorMessage.isEmpty()) { + WuQMessageBox::errorOk(this, + "Failed to create annotation in space: " + + AnnotationCoordinateSpaceEnum::toGuiName(space)); + } + else { + WuQMessageBox::errorOk(this, + errorMessage); + } return; } @@ -694,11 +759,14 @@ AnnotationCreateDialog::okButtonClicked() * Annotation that was created. * @param browserWindowIndex * Index of window in which annotation was created. + * @param tabIndex + * Index of tab in which annotation was created. */ void AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, Annotation* annotation, - const int32_t browswerWindowIndex) + const int32_t browswerWindowIndex, + const int32_t tabIndex) { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); @@ -721,6 +789,19 @@ AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, AnnotationManager::SELECTION_MODE_SINGLE, false, annotation); + + /* + * A new chart annotation is displayed only in the tab in which it was created + */ + if (annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::CHART) { + + //annotation->setItemDisplaySelectedInNoDisplayGroups(); + annotation->setItemDisplaySelectedInOneTab(tabIndex); + annotation->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, + tabIndex, + TriStateSelectionStatusEnum::SELECTED); + } + } ///** @@ -843,6 +924,30 @@ m_annotationFile(annotationFile) mouseEvent.getY(), m_coordOneInfo); + /* + * For one-dimensional annotations (line), we need a second coordinate + */ + bool addSecondCoordFlag = true; + switch (annotationType) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + addSecondCoordFlag = true; + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + + if (addSecondCoordFlag) { + + } + AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, NULL, m_validSpaces); @@ -913,6 +1018,7 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() float viewportWidth = 0.0; float viewportHeight = 0.0; switch (m_selectedSpace) { + case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: { diff --git a/src/GuiQt/AnnotationCreateDialog.h b/src/GuiQt/AnnotationCreateDialog.h index 76e1d26b7..e6d79952b 100644 --- a/src/GuiQt/AnnotationCreateDialog.h +++ b/src/GuiQt/AnnotationCreateDialog.h @@ -134,11 +134,13 @@ namespace caret { void invalidateImage(); static Annotation* createAnnotation(NewAnnotationInfo& newAnnotationInfo, - const AnnotationCoordinateSpaceEnum::Enum annotationSpace); + const AnnotationCoordinateSpaceEnum::Enum annotationSpace, + AString& errorMessageOut); static void finishAnnotationCreation(AnnotationFile* annotationFile, Annotation* annotation, - const int32_t browswerWindowIndex); + const int32_t browswerWindowIndex, + const int32_t tabIndex); const Mode m_mode; diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 541f32397..0234c2352 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -298,6 +298,8 @@ AnnotationFontWidget::updateContent(std::vector(annText); CaretAssert(ann); switch (ann->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: sizeValue /= surfaceMontageRowCount; break; diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index 250854a2b..2a60f4ee1 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,8 @@ #include "AnnotationMenuFileSelection.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretUndoStack.h" #include "DisplayPropertiesAnnotation.h" @@ -46,6 +49,7 @@ #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" +#include "Model.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -93,6 +97,8 @@ m_browserWindowIndex(browserWindowIndex) * Space buttons */ m_spaceActionGroup = new QActionGroup(this); + QToolButton* chartSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::CHART, + m_spaceActionGroup); QToolButton* tabSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::TAB, m_spaceActionGroup); QToolButton* stereotaxicSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::STEREOTAXIC, @@ -115,6 +121,7 @@ m_browserWindowIndex(browserWindowIndex) shapeOvalToolButton->setMaximumSize(mw, mh); shapeTextToolButton->setMaximumSize(mw, mh); + chartSpaceToolButton->setMaximumSize(mw, mh); tabSpaceToolButton->setMaximumSize(mw, mh); stereotaxicSpaceToolButton->setMaximumSize(mw, mh); surfaceSpaceToolButton->setMaximumSize(mw, mh); @@ -152,14 +159,16 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->addWidget(spaceLabel, 1, 2, Qt::AlignLeft); - gridLayout->addWidget(stereotaxicSpaceToolButton, + gridLayout->addWidget(chartSpaceToolButton, 1, 3); - gridLayout->addWidget(surfaceSpaceToolButton, + gridLayout->addWidget(stereotaxicSpaceToolButton, 1, 4); - gridLayout->addWidget(tabSpaceToolButton, + gridLayout->addWidget(surfaceSpaceToolButton, 1, 5); - gridLayout->addWidget(windowSpaceToolButton, + gridLayout->addWidget(tabSpaceToolButton, 1, 6); + gridLayout->addWidget(windowSpaceToolButton, + 1, 7); gridLayout->setRowMinimumHeight(2, 2); @@ -196,14 +205,16 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->addWidget(spaceLabel, 1, 2, Qt::AlignLeft); - gridLayout->addWidget(stereotaxicSpaceToolButton, + gridLayout->addWidget(chartSpaceToolButton, 1, 3); - gridLayout->addWidget(surfaceSpaceToolButton, + gridLayout->addWidget(stereotaxicSpaceToolButton, 1, 4); - gridLayout->addWidget(tabSpaceToolButton, + gridLayout->addWidget(surfaceSpaceToolButton, 1, 5); - gridLayout->addWidget(windowSpaceToolButton, + gridLayout->addWidget(tabSpaceToolButton, 1, 6); + gridLayout->addWidget(windowSpaceToolButton, + 1, 7); QSpacerItem* rowSpaceItem = new QSpacerItem(5, 5, QSizePolicy::Fixed, @@ -256,6 +267,7 @@ AnnotationInsertNewWidget::~AnnotationInsertNewWidget() void AnnotationInsertNewWidget::updateContent() { + enableDisableSpaceActions(); itemSelectedFromFileSelectionMenu(); } @@ -271,6 +283,109 @@ AnnotationInsertNewWidget::itemSelectedFromFileSelectionMenu() m_fileSelectionToolButtonAction->setText(m_fileSelectionMenu->getSelectedNameForToolButton()); } +/** + * Enable/disable space action based upon model in window. + */ +void +AnnotationInsertNewWidget::enableDisableSpaceActions() +{ + QSignalBlocker signalBlocker(m_spaceActionGroup); + + /* + * Window will be invalid when this widget is being created as part of window being created + */ + BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + if (window == NULL) { + return; + } + BrowserTabContent* tabContent = window->getBrowserTabContent(); + if (tabContent == NULL) { + return; + } + Model* model = tabContent->getModelForDisplay(); + if (model == NULL) { + return; + } + const ModelTypeEnum::Enum modelType = model->getModelType(); + + bool chartSpaceValidFlag = false; + bool surfaceSpaceValidFlag = false; + bool stereotaxicSpaceValidFlag = false; + + switch (modelType) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + chartSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + stereotaxicSpaceValidFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + stereotaxicSpaceValidFlag = true; + surfaceSpaceValidFlag = true; + break; + } + + QAction* selectedAction = m_spaceActionGroup->checkedAction(); + QAction* tabSpaceAction = NULL; + QListIterator actionsIterator(m_spaceActionGroup->actions()); + while (actionsIterator.hasNext()) { + QAction* action = actionsIterator.next(); + const int spaceInt = action->data().toInt(); + bool spaceValidFlag = false; + AnnotationCoordinateSpaceEnum::Enum annSpace = AnnotationCoordinateSpaceEnum::fromIntegerCode(spaceInt, + &spaceValidFlag); + CaretAssert(spaceValidFlag); + + bool enableSpaceFlag = false; + switch (annSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + enableSpaceFlag = chartSpaceValidFlag; + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + enableSpaceFlag = stereotaxicSpaceValidFlag; + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + enableSpaceFlag = surfaceSpaceValidFlag; + break; + case AnnotationCoordinateSpaceEnum::TAB: + tabSpaceAction = action; + enableSpaceFlag = true; + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + enableSpaceFlag = true; + break; + } + + action->setEnabled(enableSpaceFlag); + + if (action == selectedAction) { + if ( ! action->isEnabled()) { + selectedAction = NULL; + } + } + } + + if (selectedAction == NULL) { + CaretAssert(tabSpaceAction); + tabSpaceAction->setChecked(true); + } +} + + /** * @return Create a file selection/menu toolbutton. */ @@ -492,6 +607,8 @@ AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpace QActionGroup* actionGroup) { switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -568,6 +685,8 @@ AnnotationInsertNewWidget::createSpacePixmap(const QWidget* widget, * NOTE: ORIGIN is in TOP LEFT corner of pixmap. */ switch (annotationSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationInsertNewWidget.h b/src/GuiQt/AnnotationInsertNewWidget.h index e70989639..eb6f03e4c 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.h +++ b/src/GuiQt/AnnotationInsertNewWidget.h @@ -72,6 +72,8 @@ namespace caret { QToolButton* createFileSelectionToolButton(); + void enableDisableSpaceActions(); + const int32_t m_browserWindowIndex; QActionGroup* m_spaceActionGroup; diff --git a/src/GuiQt/AnnotationPasteDialog.cxx b/src/GuiQt/AnnotationPasteDialog.cxx index 6489eed40..7ada21c49 100644 --- a/src/GuiQt/AnnotationPasteDialog.cxx +++ b/src/GuiQt/AnnotationPasteDialog.cxx @@ -296,6 +296,8 @@ AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* o bool windowFlag = false; switch (oneDimShape->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index 896e03a1c..8190bc5a4 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -110,6 +110,8 @@ AnnotationRotationWidget::getValidOneDimAnnotation(Annotation* annotation) if (oneDimAnn != NULL) { bool validSpaceFlag = false; switch (oneDimAnn->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -166,6 +168,8 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValidFlag = false; switch (oneDimAnn->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: diff --git a/src/GuiQt/AnnotationSelectionViewController.cxx b/src/GuiQt/AnnotationSelectionViewController.cxx index 58505d27c..6334d6ce0 100644 --- a/src/GuiQt/AnnotationSelectionViewController.cxx +++ b/src/GuiQt/AnnotationSelectionViewController.cxx @@ -266,6 +266,7 @@ AnnotationSelectionViewController::displayGroupSelected(const DisplayGroupEnum:: dpa->setDisplayGroupForTab(browserTabIndex, displayGroup); updateAnnotationSelections(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx index 2b2ae2d97..b45ecc59b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx @@ -82,28 +82,8 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); radioButtonLayout->addStretch(); -// m_chartMatrixLayerTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER)); -// -// m_chartMatrixSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES)); -// -// m_chartDataSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES)); -// -// m_chartTimeSeriesTypeRadioButton = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES)); - - QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(chartTypeRadioButtonClicked(int))); -// m_chartTypeButtonGroup->addButton(m_chartMatrixLayerTypeRadioButton); -// m_chartTypeButtonGroup->addButton(m_chartMatrixSeriesTypeRadioButton); -// m_chartTypeButtonGroup->addButton(m_chartDataSeriesTypeRadioButton); -// m_chartTypeButtonGroup->addButton(m_chartTimeSeriesTypeRadioButton); - -// WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); -// layout->addWidget(m_chartDataSeriesTypeRadioButton); -// layout->addWidget(m_chartMatrixLayerTypeRadioButton); -// layout->addWidget(m_chartMatrixSeriesTypeRadioButton); -// layout->addWidget(m_chartTimeSeriesTypeRadioButton); -// layout->addStretch(); } /** @@ -126,24 +106,6 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) ChartOneDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; -// ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; -// -// if (m_chartDataSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; -// } -// else if (m_chartMatrixLayerTypeRadioButton->isChecked()) { -// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; -// } -// else if (m_chartTimeSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; -// } -// else if (m_chartMatrixSeriesTypeRadioButton->isChecked()) { -// chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; -// } -// else { -// CaretAssertMessage(0, "Has a new chart radio button been added?"); -// } - m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelChart* chartModel = btc->getDisplayedChartOneModel(); @@ -151,8 +113,6 @@ BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) chartModel->setSelectedChartOneDataType(tabIndex, chartDataType); - //updateContent(btc); - invalidateColoringAndUpdateGraphicsWindow(); m_parentToolBar->updateUserInterface(); } @@ -192,58 +152,6 @@ BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabC radioButton->setChecked(true); } } - -// bool dataSeriesValidFlag = false; -// bool matrixLayerValidFlag = false; -// bool matrixSeriesValidFlag = false; -// bool timeSeriesValidFlag = false; -// for (std::vector::iterator iter = validChartDataTypes.begin(); -// iter != validChartDataTypes.end(); -// iter++) { -// switch (*iter) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// matrixLayerValidFlag = true; -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// matrixSeriesValidFlag = true; -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// dataSeriesValidFlag = true; -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// CaretAssertToDoFatal(); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// timeSeriesValidFlag = true; -// break; -// } -// } -// -// m_chartDataSeriesTypeRadioButton->setEnabled(dataSeriesValidFlag); -// m_chartMatrixLayerTypeRadioButton->setEnabled(matrixLayerValidFlag); -// m_chartTimeSeriesTypeRadioButton->setEnabled(timeSeriesValidFlag); -// -// switch (chartType) { -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: -// m_chartMatrixLayerTypeRadioButton->setChecked(true); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: -// m_chartMatrixSeriesTypeRadioButton->setChecked(true); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: -// m_chartDataSeriesTypeRadioButton->setChecked(true); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: -// CaretAssertToDoFatal(); -// break; -// case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: -// m_chartTimeSeriesTypeRadioButton->setChecked(true); -// break; -// } } m_chartTypeButtonGroup->blockSignals(false); diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 9d25bf293..259d54ff7 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -404,6 +404,9 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) bool changeCoordFlag = false; bool moveOnePixelFlag = false; switch (selectedAnnotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + changeCoordFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: changeCoordFlag = true; break; @@ -465,6 +468,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) { bool surfaceFlag = false; switch (selectedAnnotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -613,6 +618,8 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) } switch (draggingCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: @@ -649,6 +656,24 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) float spaceHeight = 0.0; switch (draggingCoordinateSpace) { + case AnnotationCoordinateSpaceEnum::CHART: + { + /* + * Want viewport within montage that contains the surface + */ + Matrix4x4 projectionMatrix; + Matrix4x4 modelviewMatrix; + int32_t chartVP[4]; + if (vpContent->getChartDataMatricesAndViewport(projectionMatrix, + modelviewMatrix, + chartVP)) { + spaceOriginX = chartVP[0]; + spaceOriginY = chartVP[1]; + spaceWidth = chartVP[2]; + spaceHeight = chartVP[3]; + } + } + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: { /* @@ -753,7 +778,26 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) coordInfo.m_modelXYZ[2]); } + if (coordInfo.m_chartXYZValid) { + annSpatialMod.setChartCoordinateAtMouseXY(coordInfo.m_chartXYZ[0], + coordInfo.m_chartXYZ[1], + coordInfo.m_chartXYZ[2]); + } + if ((dx != 0.0) + || (dy != 0.0)) { + AnnotationCoordinateInformation previousMouseXYCoordInfo; + AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), + mouseEvent.getViewportContent(), + mouseEvent.getX() - dx, + mouseEvent.getY() - dy, + previousMouseXYCoordInfo); + if (previousMouseXYCoordInfo.m_chartXYZValid) { + annSpatialMod.setChartCoordinateAtPreviousMouseXY(previousMouseXYCoordInfo.m_chartXYZ[0], + previousMouseXYCoordInfo.m_chartXYZ[1], + previousMouseXYCoordInfo.m_chartXYZ[2]); + } + } std::vector annotationsBeforeMoveAndResize; std::vector annotationsAfterMoveAndResize; diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 6ec7c44b0..b49855225 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -98,20 +98,23 @@ m_newAnnotationCreatedByContextMenu(NULL) bool allSelectedAnnotationsDeletableFlag = true; - m_stereotaxicAndSurfaceAnnotations.clear(); + m_threeDimCoordAnnotations.clear(); for (std::vector >::iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); iter++) { Annotation* ann = iter->first; CaretAssert(ann); - bool stereoOrSurfaceSpaceFlag = false; + bool threeDimCoordFlag = false; switch (ann->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + threeDimCoordFlag = true; + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - stereoOrSurfaceSpaceFlag = true; + threeDimCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: - stereoOrSurfaceSpaceFlag = true; + threeDimCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; @@ -120,15 +123,15 @@ m_newAnnotationCreatedByContextMenu(NULL) case AnnotationCoordinateSpaceEnum::WINDOW: break; } - if (stereoOrSurfaceSpaceFlag) { - m_stereotaxicAndSurfaceAnnotations.push_back(ann); + if (threeDimCoordFlag) { + m_threeDimCoordAnnotations.push_back(ann); } if ( ! ann->isDeletable()) { allSelectedAnnotationsDeletableFlag = false; } } - const bool haveStereotaxicAnnotationsFlag = ( ! m_stereotaxicAndSurfaceAnnotations.empty()); + const bool haveThreeDimCoordAnnotationsFlag = ( ! m_threeDimCoordAnnotations.empty()); bool oneAnnotationSelectedFlag = false; bool oneDeletableAnnotationSelectedFlag = false; @@ -225,21 +228,21 @@ m_newAnnotationCreatedByContextMenu(NULL) /* * Turn on/off display in tabs */ - QAction* turnOffTabDisplayAction = addAction("Turn Off Stereotaxic/Surface Annotation Display in Other Tabs", + QAction* turnOffTabDisplayAction = addAction("Turn Off Chart/Stereotaxic/Surface Annotation Display in Other Tabs", this, SLOT(turnOffDisplayInOtherTabs())); - QAction* turnOnTabDisplayAction = addAction("Turn On Stereotaxic/Surface Annotation Display in All Tabs", + QAction* turnOnTabDisplayAction = addAction("Turn On Chart/Stereotaxic/Surface Annotation Display in All Tabs", this, SLOT(turnOnDisplayInAllTabs())); - turnOffTabDisplayAction->setEnabled(haveStereotaxicAnnotationsFlag); - turnOnTabDisplayAction->setEnabled(haveStereotaxicAnnotationsFlag); + turnOffTabDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); + turnOnTabDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); /* * Turn on/off display in groups */ - QAction* turnOnGroupDisplayAction = addAction("Turn On Stereotaxic/Surface Annotation Display in All Groups", + QAction* turnOnGroupDisplayAction = addAction("Turn On Chart/Stereotaxic/Surface Annotation Display in All Groups", this, SLOT(turnOnDisplayInAllGroups())); - turnOnGroupDisplayAction->setEnabled(haveStereotaxicAnnotationsFlag); + turnOnGroupDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); QMenu* turnOnInDisplayGroupMenu = createTurnOnInDisplayGroupMenu(); - turnOnInDisplayGroupMenu->setEnabled(haveStereotaxicAnnotationsFlag); + turnOnInDisplayGroupMenu->setEnabled(haveThreeDimCoordAnnotationsFlag); addMenu(turnOnInDisplayGroupMenu); /* @@ -389,8 +392,8 @@ UserInputModeAnnotationsContextMenu::setAnnotationText() void UserInputModeAnnotationsContextMenu::turnOffDisplayInOtherTabs() { - for (std::vector::iterator iter = m_stereotaxicAndSurfaceAnnotations.begin(); - iter != m_stereotaxicAndSurfaceAnnotations.end(); + for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); + iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInOneTab(m_browserTabContent->getTabNumber()); } @@ -405,8 +408,8 @@ UserInputModeAnnotationsContextMenu::turnOffDisplayInOtherTabs() void UserInputModeAnnotationsContextMenu::turnOnDisplayInAllTabs() { - for (std::vector::iterator iter = m_stereotaxicAndSurfaceAnnotations.begin(); - iter != m_stereotaxicAndSurfaceAnnotations.end(); + for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); + iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInAllTabs(); } @@ -421,8 +424,8 @@ UserInputModeAnnotationsContextMenu::turnOnDisplayInAllTabs() void UserInputModeAnnotationsContextMenu::turnOnDisplayInAllGroups() { - for (std::vector::iterator iter = m_stereotaxicAndSurfaceAnnotations.begin(); - iter != m_stereotaxicAndSurfaceAnnotations.end(); + for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); + iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInAllGroups(); } @@ -454,8 +457,8 @@ UserInputModeAnnotationsContextMenu::turnOnDisplayInGroup(QAction* action) return; } - for (std::vector::iterator iter = m_stereotaxicAndSurfaceAnnotations.begin(); - iter != m_stereotaxicAndSurfaceAnnotations.end(); + for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); + iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInOneGroup(displayGroup); } @@ -467,7 +470,7 @@ UserInputModeAnnotationsContextMenu::turnOnDisplayInGroup(QAction* action) QMenu* UserInputModeAnnotationsContextMenu::createTurnOnInDisplayGroupMenu() { - QMenu* menu = new QMenu("Turn On Stereotaxic/Surface Annotation Only in Group"); + QMenu* menu = new QMenu("Turn On Chart/Stereotaxic/Surface Annotation Only in Group"); QObject::connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(turnOnDisplayInGroup(QAction*))); diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.h b/src/GuiQt/UserInputModeAnnotationsContextMenu.h index 05257f7fb..33e6e663b 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.h +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.h @@ -107,7 +107,7 @@ namespace caret { AnnotationFile* m_annotationFile; - std::vector m_stereotaxicAndSurfaceAnnotations; + std::vector m_threeDimCoordAnnotations; Annotation* m_annotation; -- GitLab From 917c1c6091c87c1510fab5d5feb09481d3e49862 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 20 Jul 2017 15:47:09 -0500 Subject: [PATCH 323/755] Color Bar and Chart Label annotations have limited editing of properties in the annotation toolbar. For example the user cannot adjust the text orientation of a Color Bar or a Chart Label. A new strongly-type enum for identifying support of the properties was added to the Annotation class along with methods for testing and setting. Some methods named like "isPropertyNameSupported()" were removed from some of the annotation classes since the property supported enums provide the same functionality. Related updates where also made for grouping and deleting annotations. --- src/Annotations/Annotation.cxx | 303 ++++++++++++++---- src/Annotations/Annotation.h | 83 ++++- src/Annotations/AnnotationColorBar.cxx | 42 --- src/Annotations/AnnotationColorBar.h | 8 - .../AnnotationEditingSelectionInformation.cxx | 73 +++-- .../AnnotationFontAttributesInterface.h | 4 - src/Annotations/AnnotationImage.cxx | 24 -- src/Annotations/AnnotationImage.h | 4 - src/Annotations/AnnotationLine.cxx | 13 - src/Annotations/AnnotationLine.h | 3 - src/Annotations/AnnotationRedoUndoCommand.cxx | 87 +---- src/Annotations/AnnotationText.cxx | 69 ---- src/Annotations/AnnotationText.h | 6 - src/Brain/AnnotationManager.cxx | 52 +-- src/Brain/AnnotationManager.h | 2 - ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 33 +- src/Files/ChartableTwoFileBaseChart.cxx | 3 + src/GuiQt/AnnotationColorWidget.cxx | 226 +++++++------ src/GuiQt/AnnotationColorWidget.h | 12 +- src/GuiQt/AnnotationCoordinateWidget.cxx | 9 +- src/GuiQt/AnnotationDeleteWidget.cxx | 11 +- src/GuiQt/AnnotationFontWidget.cxx | 198 ++++++++---- src/GuiQt/AnnotationFontWidget.h | 20 +- src/GuiQt/AnnotationLineArrowTipsWidget.cxx | 85 +---- src/GuiQt/AnnotationRotationWidget.cxx | 163 ++++------ src/GuiQt/AnnotationRotationWidget.h | 2 - src/GuiQt/AnnotationTextAlignmentWidget.cxx | 15 +- src/GuiQt/AnnotationTextEditorWidget.cxx | 7 +- src/GuiQt/AnnotationTextOrientationWidget.cxx | 9 +- src/GuiQt/UserInputModeAnnotations.cxx | 32 +- .../UserInputModeAnnotationsContextMenu.cxx | 7 +- 31 files changed, 813 insertions(+), 792 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 388123552..5ded4474c 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -262,36 +262,6 @@ Annotation::replaceWithCopyOfAnnotation(const Annotation* annotation) *this = *annotation; } -/** - * @return Is this annotation deletable? This method may be overridden - * by annotations (such as colorbars) that cannot be deleted. - */ -bool -Annotation::isDeletable() const -{ - switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - /* - * Viewport annotations are not in annotation files - * so not deletable - */ - return false; - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - break; - } - - return true; -} - /** * @return Is this annotation requiring that it be kept in a fixed * aspect ratio? By default, this is false. This method may be @@ -569,6 +539,12 @@ Annotation::initializeAnnotationMembers() &m_colorLine); m_sceneAssistant->addArray("m_customColorLine", m_customColorLine, 4, 0.0); } + + initializeProperties(); + + if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { + initializePropertiesForViewportSpaceAnnotation(); + } } @@ -664,6 +640,8 @@ Annotation::setCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordin { if (m_coordinateSpace != coordinateSpace) { m_coordinateSpace = coordinateSpace; + CaretAssertMessage((m_coordinateSpace != AnnotationCoordinateSpaceEnum::VIEWPORT), + "Annotation coordinate space should never change to VIEWPORT space."); setModified(); } } @@ -793,31 +771,6 @@ Annotation::setLineWidth(const float lineWidth) } } -/** - * @return Is line width supported? - * Most annotations support a line width. - * Annotations that do not support a line width - * must override this method and return a value of false. - */ -bool -Annotation::isLineWidthSupported() const -{ - return true; -} - -/** - * @return Is background color supported? - * Most annotations support a background color. - * Annotations that do not support a background color - * must override this method and return a value of false. - */ -bool -Annotation::isBackgroundColorSupported() const -{ - return true; -} - - /** * @return The line color. */ @@ -1122,6 +1075,231 @@ Annotation::setCustomBackgroundColor(const uint8_t rgba[4]) } } +/** + * Initialize properties. + */ +void +Annotation::initializeProperties() +{ + /* + * Initialize all properties on/supported + */ + const int32_t propertyCount = static_cast::type>(Property::COUNT_FOR_BITSET); + CaretAssert(m_properties.size() >= propertyCount); + m_properties.set(); + + bool colorBarFlag = false; + bool fillColorFlag = true; + bool lineArrowsFlag = false; + bool textFlag = false; + switch (m_type) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::COLOR_BAR: + colorBarFlag = true; + break; + case AnnotationTypeEnum::IMAGE: + fillColorFlag = false; + break; + case AnnotationTypeEnum::LINE: + fillColorFlag = false; + lineArrowsFlag = true; + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + textFlag = true; + break; + } + + setProperty(Property::FILL_COLOR, fillColorFlag); + setProperty(Property::LINE_ARROWS, lineArrowsFlag); + setProperty(Property::TEXT_ALIGNMENT, textFlag); + setProperty(Property::TEXT_EDIT, textFlag); + setProperty(Property::TEXT_COLOR, textFlag); + setProperty(Property::TEXT_FONT_NAME, colorBarFlag | textFlag); + setProperty(Property::TEXT_FONT_SIZE, colorBarFlag | textFlag); + setProperty(Property::TEXT_FONT_STYLE, textFlag); + setProperty(Property::TEXT_ORIENTATION, textFlag); + + /* + * These are not valid properties + */ + resetProperty(Property::INVALID); + resetProperty(Property::COUNT_FOR_BITSET); + + if (colorBarFlag) { + resetProperty(Property::ARRANGE); + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETE); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::LINE_COLOR); + resetProperty(Property::LINE_THICKNESS); + resetProperty(Property::ROTATION); + resetProperty(Property::TEXT_COLOR); + resetProperty(Property::TEXT_EDIT); + } + +} + +/** + * Set the properties for a chart axis label. + * Chart axis labels are text annotations but have limited editing and other properties. + */ +void +Annotation::setPropertiesForChartAxisTitle() +{ + initializeProperties(); + + resetProperty(Property::ARRANGE); + resetProperty(Property::COORDINATE); + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETE); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::LINE_COLOR); + resetProperty(Property::LINE_THICKNESS); + resetProperty(Property::ROTATION); + resetProperty(Property::TEXT_ALIGNMENT); + resetProperty(Property::TEXT_COLOR); + resetProperty(Property::TEXT_ORIENTATION); +} + +/** + * Set the properties for an annotation in viewport coordinate space. + */ +void +Annotation::initializePropertiesForViewportSpaceAnnotation() +{ + initializeProperties(); + + resetProperty(Property::ARRANGE); + resetProperty(Property::COORDINATE); + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETE); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::ROTATION); +} + + +/** + * Test a property. + * + * @param property + * Property for testing. + * @return + * True if property is on, else false. + */ +bool +Annotation::testProperty(const Property property) const +{ + /* + * Text connect to brainordiante property is valid only + * for a a text annotation in surface space + + */ + if (property == Property::TEXT_CONNECT_TO_BRAINORDINATE) { + if (m_type == AnnotationTypeEnum::TEXT) { + if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::SURFACE) { + return true; + } + } + return false; + } + +// if (property == Property::TEXT_COLOR) { +// if (m_type == AnnotationTypeEnum::TEXT) { +// return false; +// } +// } + + const int32_t propertyIndex = static_cast::type>(property); + return m_properties.test(propertyIndex); + +} + +/** + * Test for any of the properties are set. + * + * @param propertyOne + * First property for testing. + * @param propertyTwo + * Two property for testing. + * @param propertyThree + * Three property for testing. + * @param propertyFour + * Four property for testing. + * @param propertyFive + * Five property for testing. + * @return + * True if property is on, else false. + */ +bool +Annotation::testPropertiesAny(const Property propertyOne, + const Property propertyTwo, + const Property propertyThree, + const Property propertyFour, + const Property propertyFive) const +{ + if (testProperty(propertyOne)) { + return true; + } + if (testProperty(propertyTwo)) { + return true; + } + if (propertyThree != Property::INVALID) { + if (testProperty(propertyThree)) { + return true; + } + } + if (propertyFour != Property::INVALID) { + if (testProperty(propertyFour)) { + return true; + } + } + if (propertyFive != Property::INVALID) { + if (testProperty(propertyFive)) { + return true; + } + } + + return false; +} + + +/** + * Set a property. + * + * @param property + * Property for testing. + * @param value + * New on/off status for property (optional argument defaults to true). + */ +void +Annotation::setProperty(const Property property, + const bool value) +{ + const int32_t propertyIndex = static_cast::type>(property); + m_properties.set(propertyIndex, + value); +} + +/** + * Reset (turn off) a property. + * + * @param property + * Property for testing. + */ +void +Annotation::resetProperty(const Property property) +{ + const int32_t propertyIndex = static_cast::type>(property); + m_properties.reset(propertyIndex); +} + + /** * @return The key to the annotation group that owns this annotation. */ @@ -1703,12 +1881,19 @@ TriStateSelectionStatusEnum::Enum Annotation::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { - return m_displayGroupAndTabItemHelper->getSelectedInWindow(m_windowIndex); + if (testProperty(Annotation::Property::DISPLAY_GROUP)) { + if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { + return m_displayGroupAndTabItemHelper->getSelectedInWindow(m_windowIndex); + } + + return m_displayGroupAndTabItemHelper->getSelected(displayGroup, + tabIndex); } - return m_displayGroupAndTabItemHelper->getSelected(displayGroup, - tabIndex); + /* + * Annotations that do not support a "display group" are always displayed + */ + return TriStateSelectionStatusEnum::SELECTED; } /** diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index ff90472a4..7a5487340 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -42,6 +42,56 @@ namespace caret { class Annotation : public CaretObjectTracksModification, public DisplayGroupAndTabItemInterface, public SceneableInterface { public: + /** + * Properties supported by an annotation + */ + enum class Property : int32_t { + /** Invalid (for internal use only) */ + INVALID, + /** Annotation can be arranged by user */ + ARRANGE, + /** Annotation can be moved by user */ + COORDINATE, + /** Annotation allows cut, copy, and paste by user*/ + COPY_CUT_PASTE, + /** Annotation may be deleted by user */ + DELETE, + /** Annotation display controlled by Display Group and Tab */ + DISPLAY_GROUP, + /** Annotation has fill (background) color */ + FILL_COLOR, + /** Annotation can be grouped by user */ + GROUP, + /** Annotation has arrows at its line endpoints */ + LINE_ARROWS, + /** Annotation has a line color */ + LINE_COLOR, + /** Annotation has line thickness */ + LINE_THICKNESS, + /** Annotation can be rotated by user */ + ROTATION, + /** Annotation is selectable */ + SELECT, + /** Annotation has alignment of text */ + TEXT_ALIGNMENT, + /** Annotation allows connection to brainordinate */ + TEXT_CONNECT_TO_BRAINORDINATE, + /** Annotation allows editing of its text by user */ + TEXT_EDIT, + /** Annotation has text color */ + TEXT_COLOR, + /** Annotation has font name */ + TEXT_FONT_NAME, + /** Annotation has font size*/ + TEXT_FONT_SIZE, + /** Annotation has font style */ + TEXT_FONT_STYLE, + /** Annotation has orientation of text */ + TEXT_ORIENTATION, + /** Count of properties MUST BE LAST */ + COUNT_FOR_BITSET + }; + Annotation(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); @@ -56,6 +106,21 @@ namespace caret { Annotation* clone() const; + bool testProperty(const Property property) const; + + bool testPropertiesAny(const Property propertyOne, + const Property propertyTwo, + const Property propertyThree = Property::INVALID, + const Property propertyFour = Property::INVALID, + const Property propertyFive = Property::INVALID) const; + + void setProperty(const Property property, + const bool value = true); + + void resetProperty(const Property property); + + void setPropertiesForChartAxisTitle(); + AnnotationGroupKey getAnnotationGroupKey() const; int32_t getUniqueKey() const; @@ -123,10 +188,6 @@ namespace caret { void setLineWidth(const float lineWidth); - virtual bool isLineWidthSupported() const; - - virtual bool isBackgroundColorSupported() const; - bool isSelectedForEditing(const int32_t windowIndex) const; static void setUserDefaultLineColor(const CaretColorEnum::Enum color); @@ -143,8 +204,6 @@ namespace caret { static void setUserDefaultLineWidth(const float lineWidth); - virtual bool isDeletable() const; - virtual bool isFixedAspectRatio() const; virtual float getFixedAspectRatio() const; @@ -248,6 +307,10 @@ namespace caret { void initializeAnnotationMembers(); + void initializeProperties(); + + void initializePropertiesForViewportSpaceAnnotation(); + // private - AnnotationManager handles selection and allowing // public access to this method could cause improper selection status void setSelectedForEditing(const int32_t windowIndex, @@ -307,11 +370,15 @@ namespace caret { * Selection (NOT DISPLAY) status in each window. * * Number of elements must be same as Constants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS - * An assertion will fail in the if number of elements differs. + * An assertion will fail in cxx file the if number of elements differs. */ mutable std::bitset<10> m_selectedForEditingInWindowFlag; - // defaults + /** + * Contains annotation properties. In the cxx file, an assertion will fail + * if the number of elements is insufficient. + */ + std::bitset<32> m_properties; static CaretColorEnum::Enum s_userDefaultColorLine; diff --git a/src/Annotations/AnnotationColorBar.cxx b/src/Annotations/AnnotationColorBar.cxx index 12e5c36c6..ff754ca1d 100644 --- a/src/Annotations/AnnotationColorBar.cxx +++ b/src/Annotations/AnnotationColorBar.cxx @@ -226,24 +226,6 @@ AnnotationColorBar::setFontPercentViewportSize(const float fontPercentViewportHe } } -/** - * @return True if the font color is editable in the GUI. - */ -bool -AnnotationColorBar::isFontColorGuiEditable() const -{ - return true; -} - -/** - * Are font styles (Bold, Italic, Underline) supported? - */ -bool -AnnotationColorBar::isStylesSupported() const -{ - return false; -} - /** * @return The foreground color. */ @@ -479,19 +461,6 @@ AnnotationColorBar::setOutlineStyleEnabled(const bool /*enabled*/) { } -/** - * @return Is foreground line width supported? - * Most annotations support a foreground line width. - * Annotations that do not support a foreground line width - * must override this method and return a value of false. - */ -bool -AnnotationColorBar::isLineWidthSupported() const -{ - return false; -} - - /** * @return The position mode for the colorbar annotation. */ @@ -547,17 +516,6 @@ AnnotationColorBar::setDisplayed(const bool displayed) } } -/** - * @return Is this annotation deletable? This method may be overridden - * by annotations (such as colorbars) that cannot be deleted. - */ -bool -AnnotationColorBar::isDeletable() const -{ - return false; -} - - /** * Save subclass data to the scene. * diff --git a/src/Annotations/AnnotationColorBar.h b/src/Annotations/AnnotationColorBar.h index 58b9dd48d..8caf992be 100644 --- a/src/Annotations/AnnotationColorBar.h +++ b/src/Annotations/AnnotationColorBar.h @@ -74,10 +74,6 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]); - virtual bool isFontColorGuiEditable() const; - - virtual bool isStylesSupported() const; - virtual bool isBoldStyleEnabled() const; virtual void setBoldStyleEnabled(const bool enabled); @@ -94,8 +90,6 @@ namespace caret { virtual void setOutlineStyleEnabled(const bool enabled); - virtual bool isLineWidthSupported() const; - bool isDisplayed() const; void setDisplayed(const bool displayed); @@ -129,8 +123,6 @@ namespace caret { void setShowTickMarksSelected(const bool selected); - virtual bool isDeletable() const; - // ADD_NEW_METHODS_HERE protected: diff --git a/src/Annotations/AnnotationEditingSelectionInformation.cxx b/src/Annotations/AnnotationEditingSelectionInformation.cxx index b35a0d1b0..ec71cd139 100644 --- a/src/Annotations/AnnotationEditingSelectionInformation.cxx +++ b/src/Annotations/AnnotationEditingSelectionInformation.cxx @@ -147,11 +147,18 @@ AnnotationEditingSelectionInformation::update(const std::vector& se m_annotations = selectedAnnotations; + bool allAnnotationsGroupableFlag = false; std::set groupKeysSet; - for (std::vector::iterator annIter = m_annotations.begin(); - annIter != m_annotations.end(); - annIter++) { - groupKeysSet.insert((*annIter)->getAnnotationGroupKey()); + if ( ! m_annotations.empty()) { + allAnnotationsGroupableFlag = true; + for (auto ann : m_annotations) { + if (ann->testProperty(Annotation::Property::GROUP)) { + groupKeysSet.insert(ann->getAnnotationGroupKey()); + } + else { + allAnnotationsGroupableFlag = false; + } + } } // std::set groupSet; @@ -163,38 +170,40 @@ AnnotationEditingSelectionInformation::update(const std::vector& se // groupSet.insert(annGroup); // } - m_annotationGroupKeys.insert(m_annotationGroupKeys.end(), - groupKeysSet.begin(), - groupKeysSet.end()); + if (allAnnotationsGroupableFlag) { + m_annotationGroupKeys.insert(m_annotationGroupKeys.end(), + groupKeysSet.begin(), + groupKeysSet.end()); + } const int32_t numGroups = static_cast(m_annotationGroupKeys.size()); /* * Are TWO or more annotations selected */ - if (m_annotations.size() > 1) { - if (numGroups == 1) { - CaretAssertVectorIndex(m_annotationGroupKeys, 0); - const AnnotationGroupKey& groupKey = m_annotationGroupKeys[0]; - - switch (groupKey.getGroupType()) { - case AnnotationGroupTypeEnum::INVALID: - break; - case AnnotationGroupTypeEnum::SPACE: - /* - * All annotations in a space group, allow creating a user group - */ - m_groupingValid = true; - break; - case AnnotationGroupTypeEnum::USER: - /* - * All annotations in a user group, allow ungrouping to a space group - */ - m_ungroupValid = true; - break; + if (m_annotations.size() > 1) { + if (numGroups == 1) { + CaretAssertVectorIndex(m_annotationGroupKeys, 0); + const AnnotationGroupKey& groupKey = m_annotationGroupKeys[0]; + + switch (groupKey.getGroupType()) { + case AnnotationGroupTypeEnum::INVALID: + break; + case AnnotationGroupTypeEnum::SPACE: + /* + * All annotations in a space group, allow creating a user group + */ + m_groupingValid = true; + break; + case AnnotationGroupTypeEnum::USER: + /* + * All annotations in a user group, allow ungrouping to a space group + */ + m_ungroupValid = true; + break; + } } } - } /* * Is ANY annotation selected @@ -276,6 +285,14 @@ AnnotationEditingSelectionInformation::getAnnotationsSelectedForEditing(std::vec annotationsOut = m_annotations; } +/** + * Is the given grouping mode valid? + * + * @param groupingMode + * The grouping mode. + * @return + * True if the grouping mode is valid, else false. + */ bool AnnotationEditingSelectionInformation::isGroupingModeValid(const AnnotationGroupingModeEnum::Enum groupingMode) const { diff --git a/src/Annotations/AnnotationFontAttributesInterface.h b/src/Annotations/AnnotationFontAttributesInterface.h index 09097122f..022fbf0b8 100644 --- a/src/Annotations/AnnotationFontAttributesInterface.h +++ b/src/Annotations/AnnotationFontAttributesInterface.h @@ -60,10 +60,6 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]) = 0; - virtual bool isFontColorGuiEditable() const = 0; - - virtual bool isStylesSupported() const = 0; - virtual bool isBoldStyleEnabled() const = 0; virtual void setBoldStyleEnabled(const bool enabled) = 0; diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index a4e6859cb..483530682 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -188,30 +188,6 @@ AnnotationImage::initializeMembersAnnotationImage() m_sceneAssistant = new SceneClassAssistant(); } -/** - * @return Is foreground line width supported? - * Most annotations support a foreground line width. - * Annotations that do not support a foreground line width - * must override this method and return a value of false. - */ -bool -AnnotationImage::isLineWidthSupported() const -{ - return true; -} - -/** - * @return Is background color supported? - * Most annotations support a background color. - * Annotations that do not support a background color - * must override this method and return a value of false. - */ -bool -AnnotationImage::isBackgroundColorSupported() const -{ - return false; -} - /** * @return Is this annotation requiring that it be kept in a fixed * aspect ratio? By default, this is false. This method may be diff --git a/src/Annotations/AnnotationImage.h b/src/Annotations/AnnotationImage.h index 56465f798..8d3078755 100644 --- a/src/Annotations/AnnotationImage.h +++ b/src/Annotations/AnnotationImage.h @@ -40,10 +40,6 @@ namespace caret { AnnotationImage& operator=(const AnnotationImage& obj); - virtual bool isLineWidthSupported() const; - - virtual bool isBackgroundColorSupported() const; - virtual bool isFixedAspectRatio() const; virtual float getFixedAspectRatio() const; diff --git a/src/Annotations/AnnotationLine.cxx b/src/Annotations/AnnotationLine.cxx index c9568f851..b6fa40d08 100644 --- a/src/Annotations/AnnotationLine.cxx +++ b/src/Annotations/AnnotationLine.cxx @@ -161,19 +161,6 @@ AnnotationLine::setDisplayEndArrow(const bool displayArrow) m_displayEndArrow = displayArrow; } -/** - * @return Is background color supported? - * Most annotations support a background color. - * Annotations that do not support a background color - * must override this method and return a value of false. - */ -bool -AnnotationLine::isBackgroundColorSupported() const -{ - return false; -} - - /** * Save subclass data to the scene. * diff --git a/src/Annotations/AnnotationLine.h b/src/Annotations/AnnotationLine.h index d0fb0b27d..e17e68e3b 100644 --- a/src/Annotations/AnnotationLine.h +++ b/src/Annotations/AnnotationLine.h @@ -46,9 +46,6 @@ namespace caret { void setDisplayEndArrow(const bool displayArrow); - virtual bool isBackgroundColorSupported() const; - - static void setUserDefaultDisplayStartArrow(const bool displayArrow); static void setUserDefaultDisplayEndArrow(const bool displayArrow); diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index e9921c1ad..b1de7a96c 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -219,8 +219,7 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, } break; case AnnotationRedoUndoCommandModeEnum::LINE_WIDTH_FOREGROUND: - if (annotation->isLineWidthSupported()) { - //annotation->setLineWidth(value.m_floatValue); + if (annotation->testProperty(Annotation::Property::LINE_THICKNESS)) { annotation->setLineWidth(annotationValue->getLineWidth()); } break; @@ -483,8 +482,6 @@ AnnotationRedoUndoCommand::redo(AString& errorMessageOut) EventManager::get()->sendEvent(groupEvent.getPointer()); - //m_annotationGroupMemento->setUndoAnnotationGroupKey(groupEvent.getGroupKeyToWhichAnnotationsWereMoved()); - if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; @@ -607,9 +604,6 @@ AnnotationRedoUndoCommand::undo(AString& errorMessageOut) EventManager::get()->sendEvent(groupEvent.getPointer()); - //m_annotationGroupMemento->setUndoAnnotationGroupKey(groupEvent.getGroupKeyToWhichAnnotationsWereMoved()); - - if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; @@ -710,8 +704,6 @@ AnnotationRedoUndoCommand::isValid() const } return false; - -// return m_annotationMementos.size(); } /** @@ -1409,37 +1401,10 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, const bool rotateAroundMiddleFlag = true; if (rotateAroundMiddleFlag) { -// const float midPointXYZ[3] = { -// (annOneX + annTwoX) / 2.0, -// (annOneY + annTwoY) / 2.0, -// 0.0 -// }; -// -// const float vpOneXYZ[3] = { annOneX, annOneY, 0.0 }; -// const float vpTwoXYZ[3] = { annTwoX, annTwoY, 0.0 }; -// const float length = MathFunctions::distance3D(vpOneXYZ, vpTwoXYZ); -// const float lengthMidToOne = MathFunctions::distance3D(midPointXYZ, vpOneXYZ); -// const float angleRadians = MathFunctions::toRadians(-newRotationAngle); -// const float dy = lengthMidToOne * std::sin(angleRadians); -// const float dx = lengthMidToOne * std::cos(angleRadians); -// annOneX = midPointXYZ[0] - dx; -// annOneY = midPointXYZ[1] - dy; -// -// annTwoX = midPointXYZ[0] + dx; -// annTwoY = midPointXYZ[1] + dy; -// -//// const float newVpOneXYZ[3] = { annOneX, annOneY, 0.0 }; -//// float vectorOneToMid[3] = { 0.0, 0.0, 0.0 }; -//// MathFunctions::subtractVectors(newVpOneXYZ, midPointXYZ, vectorOneToMid); -//// MathFunctions::normalizeVector(vectorOneToMid); -//// annTwoX = annOneX + vectorOneToMid[0] * length; -//// annTwoY = annOneY + vectorOneToMid[1] * length; AnnotationOneDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setRotationAngle(vpWidth, vpHeight, newRotationAngle); -// redoAnnotation->getStartCoordinate()->setXYZFromViewportXYZ(vpWidth, vpHeight, annOneX, annOneY); -// redoAnnotation->getEndCoordinate()->setXYZFromViewportXYZ(vpWidth, vpHeight, annTwoX, annTwoY); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, @@ -1467,29 +1432,6 @@ AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, m_annotationMementos.push_back(am); } } -// float xyzOne[3]; -// oneDimAnn->getStartCoordinate()->getXYZ(xyzOne); -// float xyzTwo[3]; -// oneDimAnn->getEndCoordinate()->getXYZ(xyzTwo); -// -//// const float dx = xyzTwo[0] - xyzOne[0]; -//// const float dy = xyzTwo[1] - xyzOne[1]; -// const float length = MathFunctions::distance3D(xyzOne, xyzTwo); -// const float angleRadians = MathFunctions::toRadians(-newRotationAngle); -// const float dy = length * std::sin(angleRadians); -// const float dx = length * std::cos(angleRadians); -// xyzTwo[0] = xyzOne[0] + dx; -// xyzTwo[1] = xyzOne[1] + dy; -// -// -// AnnotationOneDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); -// CaretAssert(redoAnnotation); -// redoAnnotation->getEndCoordinate()->setXYZ(xyzTwo); -// Annotation* undoAnnotation = annotation->clone(); -// AnnotationMemento* am = new AnnotationMemento(annotation, -// redoAnnotation, -// undoAnnotation); -// m_annotationMementos.push_back(am); } } @@ -1902,33 +1844,6 @@ AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercent } } -//void -//AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercentSize, -// const std::vector& annotations) -//{ -// m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_PERCENT_SIZE; -// setDescription("Text Font Percent Size"); -// -// for (std::vector::const_iterator iter = annotations.begin(); -// iter != annotations.end(); -// iter++) { -// Annotation* annotation = *iter; -// CaretAssert(annotation); -// -// if (annotation->getType() == AnnotationTypeEnum::TEXT) { -// AnnotationPercentSizeText* redoAnnotation = dynamic_cast(annotation->clone()); -// CaretAssert(redoAnnotation); -// redoAnnotation->setFontPercentViewportSize(newFontPercentSize); -// -// Annotation* undoAnnotation = annotation->clone(); -// AnnotationMemento* am = new AnnotationMemento(annotation, -// redoAnnotation, -// undoAnnotation); -// m_annotationMementos.push_back(am); -// } -// } -//} - /** * Set the mode to text font underline and create the undo/redo instances. * diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index a99223838..af16b8ca1 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -41,16 +41,6 @@ using namespace caret; * \ingroup Annotations */ -///** -// * Constructor for a text annotation. -// */ -//AnnotationText::AnnotationText() -//: AnnotationTwoDimensionalShape(AnnotationTypeEnum::TEXT), -//m_fontSizeType(AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT) -//{ -// initializeAnnotationTextMembers(); -//} - /** * Constructor for subclass. * @@ -273,15 +263,6 @@ AnnotationText::getFontRenderingEncodedName(const float drawingViewportWidth, if (m_italicEnabled) { encodedName.append("_I"); } - -// Underline and outline are not drawn by font rendering -// if (m_underlineEnabled) { -// encodedName.append("_U"); -// } -// -// if (m_outlineEnabled) { -// encodedName.append("_O"); -// } return encodedName; } @@ -724,43 +705,6 @@ AnnotationText::setCustomTextColor(const uint8_t rgba[4]) } } -/** - * @return True if the font color is editable in the GUI. - */ -bool -AnnotationText::isFontColorGuiEditable() const -{ - switch (getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - /* - * Viewport annotations do not allow changing of font color - */ - return false; - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - break; - } - - return true; -} - -/** - * Are font styles (Bold, Italic, Underline) supported? - */ -bool -AnnotationText::isStylesSupported() const -{ - return true; -} - /** * @return * Is bold enabled ? @@ -821,19 +765,6 @@ AnnotationText::isUnderlineStyleEnabled() const return m_underlineEnabled; } -/** - * @return Is foreground line width supported? - * Most annotations support a foreground line width. - * Annotations that do not support a foreground line width - * must override this method and return a value of false. - */ -bool -AnnotationText::isLineWidthSupported() const -{ - return true; -} - - /** * Set underline enabled. * diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index c4b5a45ab..77917bfac 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -90,10 +90,6 @@ namespace caret { virtual void setCustomTextColor(const uint8_t rgba[4]); - virtual bool isFontColorGuiEditable() const; - - virtual bool isStylesSupported() const; - virtual bool isBoldStyleEnabled() const; virtual void setBoldStyleEnabled(const bool enabled); @@ -112,8 +108,6 @@ namespace caret { bool isConnectToBrainordinateValid() const; - virtual bool isLineWidthSupported() const; - virtual bool applySpatialModification(const AnnotationSpatialModification& spatialModification); virtual void applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation); diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 45d428ffc..efbebf2d1 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -19,10 +19,6 @@ */ /*LICENSE_END*/ -//#include -//#include -//#include - #define __ANNOTATION_MANAGER_DECLARE__ #include "AnnotationManager.h" #undef __ANNOTATION_MANAGER_DECLARE__ @@ -213,51 +209,6 @@ AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) } } -///** -// * Get the files containing the given annotations. If a file is not found -// * for an annotation NULL is selected for the file. -// * -// * @param annotations -// * Annotations for which file is found. -// * @return -// * Files containing the annotations (NULL entry if file not found). The -// * size of this vector will ALWAYS be the same as the size of the -// * input vector. -// */ -//std::vector -//AnnotationManager::getFilesContainingAnnotations(const std::vector annotations) const -//{ -// CaretAssertMessage(0, "Use annotation's getAnnotationFile() method."); -//// std::vector allFiles; -//// m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(allFiles); -// -// std::vector filesOut; -// -//// for (std::vector::const_iterator annIter = annotations.begin(); -//// annIter != annotations.end(); -//// annIter++) { -//// Annotation* ann = *annIter; -//// -//// AnnotationFile* file = NULL; -//// for (std::vector::const_iterator fileIter = allFiles.begin(); -//// fileIter != allFiles.end(); -//// fileIter++) { -//// AnnotationFile* annFile = *fileIter; -//// if (annFile->containsAnnotation(ann)) { -//// file = annFile; -//// break; -//// } -//// } -//// -//// filesOut.push_back(file); -//// } -// -// -// CaretAssert(filesOut.size() == annotations.size()); -// return filesOut; -//} - - /** * Select the given annotation for editing using the given mode. * @@ -445,7 +396,7 @@ AnnotationManager::isAnnotationSelectedForEditingDeletable(const int32_t windowI iter != selectedAnnotations.end(); iter++) { const Annotation* ann = *iter; - if ( ! ann->isDeletable()) { + if ( ! ann->testProperty(Annotation::Property::DELETE)) { selectedAnnotationsDeletableFlag = false; break; } @@ -960,7 +911,6 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ const std::vector tabIndices = displayedFilesEvent->getTabIndices(); -// const DisplayPropertiesAnnotation* annProps = m_brain->getDisplayPropertiesAnnotation(); std::vector annotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); diff --git a/src/Brain/AnnotationManager.h b/src/Brain/AnnotationManager.h index 7816e4048..779aeba83 100644 --- a/src/Brain/AnnotationManager.h +++ b/src/Brain/AnnotationManager.h @@ -106,8 +106,6 @@ namespace caret { void getAnnotationsSelectedForEditingIncludingLabels(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const; -// std::vector getFilesContainingAnnotations(const std::vector annotations) const; - bool isAnnotationOnClipboardValid() const; AnnotationFile* getAnnotationFileOnClipboard() const; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 90a54141b..b4356daad 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -192,7 +192,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c const float halfSliceThickness = ((m_volumeSliceThickness > 0.0) ? (m_volumeSliceThickness / 2.0) : 1.0); - if (distToPlaneAbs < halfSliceThickness) { //1.5) { + if (distToPlaneAbs < halfSliceThickness) { modelXYZValid = true; float projectedPoint[3]; @@ -374,8 +374,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::convertModelToWindowCoordinate(const */ float nearValue = (1.0f + m_modelSpaceProjectionMatrix[14]) / m_modelSpaceProjectionMatrix[10]; float farValue = -(1.0f - m_modelSpaceProjectionMatrix[14]) / m_modelSpaceProjectionMatrix[10]; - //GLfloat bottom = (1.0f - m_modelSpaceProjectionMatrix[13]) / m_modelSpaceProjectionMatrix[5]; - //GLfloat top = -(1.0f + m_modelSpaceProjectionMatrix[13]) / m_modelSpaceProjectionMatrix[5]; float left = -(1.0f + m_modelSpaceProjectionMatrix[12]) / m_modelSpaceProjectionMatrix[0]; float right = (1.0f - m_modelSpaceProjectionMatrix[12]) / m_modelSpaceProjectionMatrix[0]; @@ -814,22 +812,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat CaretAssert(annotation); bool drawItFlag = false; - if (annotation->getType() == AnnotationTypeEnum::COLOR_BAR) { - AnnotationColorBar* colorBar = dynamic_cast(annotation); - CaretAssert(colorBar); - drawItFlag = colorBar->isDisplayed(); - } - else { - switch (annotation->getItemDisplaySelected(displayGroup, m_inputs->m_tabIndex)) { - case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: - CaretAssertMessage(0, "An annotation should never be partially selected"); - break; - case TriStateSelectionStatusEnum::SELECTED: - drawItFlag = true; - break; - case TriStateSelectionStatusEnum::UNSELECTED: - break; - } + switch (annotation->getItemDisplaySelected(displayGroup, m_inputs->m_tabIndex)) { + case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: + CaretAssertMessage(0, "An annotation should never be partially selected"); + break; + case TriStateSelectionStatusEnum::SELECTED: + drawItFlag = true; + break; + case TriStateSelectionStatusEnum::UNSELECTED: + break; } if ( ! drawItFlag) { @@ -1268,7 +1259,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil else { const float tempRGBA[4] = { 1.0, 1.0, 0.0, 1.0 }; BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - tempRGBA, //foregroundRGBA, + tempRGBA, outlineWidth); } drawnFlag = true; @@ -1824,7 +1815,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarText(const AnnotationColo AnnotationPercentSizeText annText(AnnotationAttributesDefaultTypeEnum::NORMAL); annText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annText.setFont(colorBar->getFont()); - annText.setFontPercentViewportSize(textPercentageHeight); //colorBar->getFontPercentViewportSize()); + annText.setFontPercentViewportSize(textPercentageHeight); annText.setTextColor(CaretColorEnum::CUSTOM); float rgba[4]; colorBar->getTextColorRGBA(rgba); diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 165fd89a6..829600987 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -91,6 +91,9 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + m_bottomAxisTitle->setPropertiesForChartAxisTitle(); + m_leftRightAxisTitle->setPropertiesForChartAxisTitle(); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); } diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 4881f1411..944b3d75f 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -76,15 +76,8 @@ m_browserWindowIndex(browserWindowIndex) QLabel* foreLineLabel = new QLabel("Line"); QLabel* foreLineColorLabel = new QLabel("Color"); - QLabel* lineWidthLabel = NULL; - switch (m_parentWidgetType) { - case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: - lineWidthLabel = new QLabel("Width"); - break; - case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: - CaretAssert(0); - break; - } + QLabel* lineLabel = new QLabel("Line"); + QLabel* lineWidthLabel = new QLabel("Width"); const QSize toolButtonSize(16, 16); @@ -112,10 +105,10 @@ m_browserWindowIndex(browserWindowIndex) /* * Widget/object group for background widgets */ - m_backgroundWidgetGroup = new WuQWidgetObjectGroup(this); - m_backgroundWidgetGroup->add(backFillLabel); - m_backgroundWidgetGroup->add(backFillColorLabel); - m_backgroundWidgetGroup->add(m_backgroundToolButton); + m_backgroundColorWidgetGroup = new WuQWidgetObjectGroup(this); + m_backgroundColorWidgetGroup->add(backFillLabel); + m_backgroundColorWidgetGroup->add(backFillColorLabel); + m_backgroundColorWidgetGroup->add(m_backgroundToolButton); /* * Line color menu @@ -137,29 +130,38 @@ m_browserWindowIndex(browserWindowIndex) m_lineToolButton->setIconSize(toolButtonSize); WuQtUtilities::setToolButtonStyleForQt5Mac(m_lineToolButton); + m_lineColorWidgetGroup = new WuQWidgetObjectGroup(this); + m_lineColorWidgetGroup->add(foreLineLabel); + m_lineColorWidgetGroup->add(foreLineColorLabel); + m_lineColorWidgetGroup->add(m_lineColorMenu); + m_lineColorWidgetGroup->add(m_lineToolButton); + /* * Line thickness */ float minimumLineWidth = 0.0; float maximumLineWidth = 1.0; - - m_lineThicknessSpinBox = NULL; - if (lineWidthLabel != NULL) { - BrainOpenGL::getMinMaxLineWidth(minimumLineWidth, - maximumLineWidth); - minimumLineWidth = std::max(minimumLineWidth, 1.0f); - m_lineThicknessSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minimumLineWidth, - maximumLineWidth, - 1.0, - 0, - this, - SLOT(lineThicknessSpinBoxValueChanged(double))); - WuQtUtilities::setWordWrappedToolTip(m_lineThicknessSpinBox, - "Adjust the line thickness"); - m_lineThicknessSpinBox->setFixedWidth(45); - } - + BrainOpenGL::getMinMaxLineWidth(minimumLineWidth, + maximumLineWidth); + minimumLineWidth = std::max(minimumLineWidth, 1.0f); + m_lineThicknessWidgetGroup = new WuQWidgetObjectGroup(this); + m_lineThicknessSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minimumLineWidth, + maximumLineWidth, + 1.0, + 0, + this, + SLOT(lineThicknessSpinBoxValueChanged(double))); + WuQtUtilities::setWordWrappedToolTip(m_lineThicknessSpinBox, + "Adjust the line thickness"); + m_lineThicknessSpinBox->setFixedWidth(45); + + m_lineThicknessWidgetGroup->add(lineLabel); + m_lineThicknessWidgetGroup->add(lineWidthLabel); + m_lineThicknessWidgetGroup->add(m_lineThicknessSpinBox); + /* + * Layout + */ QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); @@ -167,13 +169,15 @@ m_browserWindowIndex(browserWindowIndex) case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { CaretAssert(lineWidthLabel); - gridLayout->addWidget(foreLineLabel, + gridLayout->addWidget(lineLabel, 0, 0, - 1, 2, Qt::AlignHCenter); gridLayout->addWidget(lineWidthLabel, 1, 0, Qt::AlignHCenter); + gridLayout->addWidget(foreLineLabel, + 0, 1, + Qt::AlignHCenter); gridLayout->addWidget(foreLineColorLabel, 1, 1, Qt::AlignHCenter); @@ -224,17 +228,31 @@ AnnotationColorWidget::~AnnotationColorWidget() void AnnotationColorWidget::updateContent(std::vector& annotations) { - m_annotations.clear(); + m_lineColorAnnotations.clear(); + m_lineColorAnnotations.reserve(annotations.size()); + + m_lineThicknessAnnotations.clear(); + m_lineThicknessAnnotations.reserve(annotations.size()); + + m_backgroundColorAnnotations.clear(); + m_backgroundColorAnnotations.reserve(annotations.size()); + + bool haveAnnotationsFlag = false; for (auto a : annotations) { - m_annotations.push_back(a); + if (a->testProperty(Annotation::Property::FILL_COLOR)) { + m_backgroundColorAnnotations.push_back(a); + } + if (a->testProperty(Annotation::Property::LINE_COLOR)) { + m_lineColorAnnotations.push_back(a); + } + if (a->testProperty(Annotation::Property::LINE_THICKNESS)) { + m_lineThicknessAnnotations.push_back(a); + } + + haveAnnotationsFlag = true; } - if ( ! m_annotations.empty()) { - setEnabled(true); - } - else { - setEnabled(false); - } + setEnabled(haveAnnotationsFlag); updateBackgroundColorButton(); updateLineColorButton(); @@ -250,9 +268,9 @@ AnnotationColorWidget::updateContent(std::vector& annotations) void AnnotationColorWidget::backgroundColorSelected(const CaretColorEnum::Enum caretColor) { - if (! m_annotations.empty()) { + if (! m_backgroundColorAnnotations.empty()) { float rgba[4]; - m_annotations[0]->getCustomBackgroundColor(rgba); + m_backgroundColorAnnotations[0]->getCustomBackgroundColor(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; @@ -281,14 +299,14 @@ AnnotationColorWidget::backgroundColorSelected(const CaretColorEnum::Enum caretC if ( ! isBothColorsSetToNoneAllowed(this, caretColor, m_lineColorMenu->getSelectedColor(), - m_annotations)) { + m_backgroundColorAnnotations)) { return; } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeColorBackground(caretColor, rgba, - m_annotations); + m_backgroundColorAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; @@ -317,42 +335,40 @@ AnnotationColorWidget::updateBackgroundColorButton() CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; - const int32_t numAnnotations = static_cast(m_annotations.size()); + bool enableBackgroundFlag = false; + const int32_t numAnnotations = static_cast(m_backgroundColorAnnotations.size()); if (numAnnotations > 0) { bool firstColorSupportFlag = true; - bool enableBackgroundFlag = false; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { - if (m_annotations[0]->isBackgroundColorSupported()) { - if (firstColorSupportFlag) { - m_annotations[i]->getBackgroundColorRGBA(rgba); - firstColorSupportFlag = false; - enableBackgroundFlag = true; - } - else { - float colorRGBA[4]; - m_annotations[i]->getBackgroundColorRGBA(colorRGBA); - for (int32_t iColor = 0; iColor < 4; iColor++) { - if (rgba[iColor] != colorRGBA[iColor]) { - allSameColorFlag = false; - break; - } - } - - if ( ! allSameColorFlag) { + if (firstColorSupportFlag) { + m_backgroundColorAnnotations[i]->getBackgroundColorRGBA(rgba); + firstColorSupportFlag = false; + enableBackgroundFlag = true; + } + else { + float colorRGBA[4]; + m_backgroundColorAnnotations[i]->getBackgroundColorRGBA(colorRGBA); + for (int32_t iColor = 0; iColor < 4; iColor++) { + if (rgba[iColor] != colorRGBA[iColor]) { + allSameColorFlag = false; break; } } + + if ( ! allSameColorFlag) { + break; + } } } if (allSameColorFlag) { - colorEnum = m_annotations[0]->getBackgroundColor(); - m_annotations[0]->getBackgroundColorRGBA(rgba); + colorEnum = m_backgroundColorAnnotations[0]->getBackgroundColor(); + m_backgroundColorAnnotations[0]->getBackgroundColorRGBA(rgba); float customRGBA[4]; - m_annotations[0]->getCustomBackgroundColor(customRGBA); + m_backgroundColorAnnotations[0]->getCustomBackgroundColor(customRGBA); m_backgroundColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { @@ -367,12 +383,13 @@ AnnotationColorWidget::updateBackgroundColorButton() } - m_backgroundWidgetGroup->setEnabled(enableBackgroundFlag); - if ( ! enableBackgroundFlag) { - colorEnum = CaretColorEnum::NONE; - } } + m_backgroundColorWidgetGroup->setEnabled(enableBackgroundFlag); + if ( ! enableBackgroundFlag) { + colorEnum = CaretColorEnum::NONE; + } + QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(m_backgroundToolButton, 24, 24, colorEnum, @@ -396,21 +413,21 @@ AnnotationColorWidget::updateLineColorButton() CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; - const int32_t numAnnotations = static_cast(m_annotations.size()); + const int32_t numAnnotations = static_cast(m_lineColorAnnotations.size()); + bool enableLineFlag = false; if (numAnnotations > 0) { bool firstColorSupportFlag = true; - bool enableLineFlag = false; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { if (firstColorSupportFlag) { - m_annotations[i]->getLineColorRGBA(rgba); + m_lineColorAnnotations[i]->getLineColorRGBA(rgba); firstColorSupportFlag = false; enableLineFlag = true; } else { float colorRGBA[4]; - m_annotations[i]->getLineColorRGBA(colorRGBA); + m_lineColorAnnotations[i]->getLineColorRGBA(colorRGBA); for (int32_t iColor = 0; iColor < 4; iColor++) { if (rgba[iColor] != colorRGBA[iColor]) { allSameColorFlag = false; @@ -425,11 +442,11 @@ AnnotationColorWidget::updateLineColorButton() } if (allSameColorFlag) { - colorEnum = m_annotations[0]->getLineColor(); - m_annotations[0]->getLineColorRGBA(rgba); + colorEnum = m_lineColorAnnotations[0]->getLineColor(); + m_lineColorAnnotations[0]->getLineColorRGBA(rgba); float customRGBA[4]; - m_annotations[0]->getCustomLineColor(customRGBA); + m_lineColorAnnotations[0]->getCustomLineColor(customRGBA); m_lineColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { @@ -443,11 +460,12 @@ AnnotationColorWidget::updateLineColorButton() } } - - - if ( ! enableLineFlag) { - colorEnum = CaretColorEnum::NONE; - } + } + + m_lineColorWidgetGroup->setEnabled(enableLineFlag); + + if ( ! enableLineFlag) { + colorEnum = CaretColorEnum::NONE; } QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(m_lineToolButton, 24, 24, colorEnum, rgba, true); @@ -527,11 +545,11 @@ AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, void AnnotationColorWidget::lineColorSelected(const CaretColorEnum::Enum caretColor) { - if ( ! m_annotations.empty()) { - CaretAssertVectorIndex(m_annotations, 0); + if ( ! m_lineColorAnnotations.empty()) { + CaretAssertVectorIndex(m_lineColorAnnotations, 0); float rgba[4]; - m_annotations[0]->getCustomLineColor(rgba); + m_lineColorAnnotations[0]->getCustomLineColor(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; @@ -550,14 +568,14 @@ AnnotationColorWidget::lineColorSelected(const CaretColorEnum::Enum caretColor) if ( ! isBothColorsSetToNoneAllowed(this, caretColor, m_backgroundColorMenu->getSelectedColor(), - m_annotations)) { + m_lineColorAnnotations)) { return; } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeColorLine(caretColor, rgba, - m_annotations); + m_lineColorAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; @@ -595,12 +613,12 @@ void AnnotationColorWidget::setUserDefaultLineColor(const CaretColorEnum::Enum caretColor, const float customRGBA[4]) { - if ( ! m_annotations.empty()) { + if ( ! m_lineColorAnnotations.empty()) { bool allTextFlag = true; bool someTextFlag = false; - for (std::vector::iterator iter = m_annotations.begin(); - iter != m_annotations.end(); + for (std::vector::iterator iter = m_lineColorAnnotations.begin(); + iter != m_lineColorAnnotations.end(); iter++) { const Annotation* ann = *iter; if (ann->getType() == AnnotationTypeEnum::TEXT) { @@ -658,7 +676,7 @@ AnnotationColorWidget::lineThicknessSpinBoxValueChanged(double value) AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLineWidth(value, - m_annotations); + m_lineThicknessAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; @@ -688,22 +706,20 @@ AnnotationColorWidget::updateLineThicknessSpinBox() bool lineWidthValid = false; bool haveMultipleLineWidthValues = false; - const int32_t numAnnotations = static_cast(m_annotations.size()); + const int32_t numAnnotations = static_cast(m_lineThicknessAnnotations.size()); if (numAnnotations > 0) { for (int32_t i = 0; i < numAnnotations; i++) { - if (m_annotations[i]->isLineWidthSupported()) { - const float annLineWidth = m_annotations[i]->getLineWidth(); - if (lineWidthValid) { - if (annLineWidth != lineWidthValue) { - haveMultipleLineWidthValues = true; - } - lineWidthValue = std::min(lineWidthValue, - annLineWidth); - } - else { - lineWidthValue = annLineWidth; - lineWidthValid = true; + const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidth(); + if (lineWidthValid) { + if (annLineWidth != lineWidthValue) { + haveMultipleLineWidthValues = true; } + lineWidthValue = std::min(lineWidthValue, + annLineWidth); + } + else { + lineWidthValue = annLineWidth; + lineWidthValid = true; } } @@ -734,5 +750,7 @@ AnnotationColorWidget::updateLineThicknessSpinBox() m_lineThicknessSpinBox->setSuffix(""); } m_lineThicknessSpinBox->blockSignals(false); + + m_lineThicknessWidgetGroup->setEnabled(numAnnotations > 0); } diff --git a/src/GuiQt/AnnotationColorWidget.h b/src/GuiQt/AnnotationColorWidget.h index 0dc814e84..3d74c96e9 100644 --- a/src/GuiQt/AnnotationColorWidget.h +++ b/src/GuiQt/AnnotationColorWidget.h @@ -98,9 +98,17 @@ namespace caret { QDoubleSpinBox* m_lineThicknessSpinBox; - WuQWidgetObjectGroup* m_backgroundWidgetGroup; + WuQWidgetObjectGroup* m_backgroundColorWidgetGroup; - std::vector m_annotations; + WuQWidgetObjectGroup* m_lineColorWidgetGroup; + + WuQWidgetObjectGroup* m_lineThicknessWidgetGroup; + + std::vector m_lineColorAnnotations; + + std::vector m_lineThicknessAnnotations; + + std::vector m_backgroundColorAnnotations; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index f5c94f3ec..0b061e2d7 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -160,7 +160,7 @@ m_browserWindowIndex(browserWindowIndex) QToolButton* setCoordinateToolButton = NULL; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: - // disabled as change space cause grouping problems. setCoordinateToolButton = new QToolButton(); + /** disabled as change space cause grouping problems. setCoordinateToolButton = new QToolButton(); */ break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); @@ -256,7 +256,12 @@ AnnotationCoordinateWidget::getCoordinate() void AnnotationCoordinateWidget::updateContent(Annotation* annotation) { - m_annotation = annotation; + m_annotation = NULL; + if (annotation != NULL) { + if (annotation->testProperty(Annotation::Property::COORDINATE)) { + m_annotation = annotation; + } + } m_surfaceStructureComboBox->listOnlyValidStructures(); diff --git a/src/GuiQt/AnnotationDeleteWidget.cxx b/src/GuiQt/AnnotationDeleteWidget.cxx index 1f5f9f63c..9c6bf7245 100644 --- a/src/GuiQt/AnnotationDeleteWidget.cxx +++ b/src/GuiQt/AnnotationDeleteWidget.cxx @@ -149,9 +149,16 @@ AnnotationDeleteWidget::deleteActionTriggered() { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); - if ( ! selectedAnnotations.empty()) { + std::vector deleteAnnotations; + for (auto a : selectedAnnotations) { + if (a->testProperty(Annotation::Property::DELETE)) { + deleteAnnotations.push_back(a); + } + } + + if ( ! deleteAnnotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); - undoCommand->setModeDeleteAnnotations(selectedAnnotations); + undoCommand->setModeDeleteAnnotations(deleteAnnotations); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 0234c2352..fd7e40961 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -150,7 +150,7 @@ m_browserWindowIndex(browserWindowIndex) /* * Bold Font */ - m_boldFontAction = WuQtUtilities::createAction("B", //boldFontText.toStringWithHtmlBody(), + m_boldFontAction = WuQtUtilities::createAction("B", "Enable/disable bold styling", this, this, SLOT(fontBoldChanged())); m_boldFontAction->setCheckable(true); @@ -217,7 +217,6 @@ m_browserWindowIndex(browserWindowIndex) QHBoxLayout* stylesLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(stylesLayout, 0, 0); - //stylesLayout->addStretch(); stylesLayout->addWidget(boldFontToolButton); stylesLayout->addWidget(italicFontToolButton); stylesLayout->addWidget(underlineFontToolButton); @@ -267,32 +266,92 @@ AnnotationFontWidget::~AnnotationFontWidget() void AnnotationFontWidget::updateContent(std::vector& annotations) { - m_annotationsFontStyle = annotations; - m_annotations.clear(); + m_annotationsFontColor.clear(); + m_annotationsFontColor.reserve(annotations.size()); + m_annotationsFontName.clear(); + m_annotationsFontName.reserve(annotations.size()); + m_annotationsFontSize.clear(); + m_annotationsFontSize.reserve(annotations.size()); + m_annotationsFontStyle.clear(); + m_annotationsFontStyle.reserve(annotations.size()); + + for (auto a : annotations) { + Annotation* ann = dynamic_cast(a); + if (ann->testProperty(Annotation::Property::TEXT_FONT_NAME)) { + m_annotationsFontName.push_back(a); + } + if (ann->testProperty(Annotation::Property::TEXT_FONT_SIZE)) { + m_annotationsFontSize.push_back(a); + } + if (ann->testProperty(Annotation::Property::TEXT_FONT_STYLE)) { + m_annotationsFontStyle.push_back(a); + } + if (ann->testProperty(Annotation::Property::TEXT_COLOR)) { + m_annotationsFontColor.push_back(a); + } + } - if ( ! m_annotationsFontStyle.empty()) { - bool boldOnFlag = true; - bool italicOnFlag = true; - bool underlineOnFlag = true; - int32_t stylesEnabledCount = 0; - + updateFontNameControls(); + updateFontSizeControls(); + updateFontStyleControls(); + updateTextColorButton(); + + setEnabled((m_annotationsFontColor.size() + + m_annotationsFontName.size() + + m_annotationsFontSize.size() + + m_annotationsFontStyle.size()) > 0); +} + +/** + * Update the font name controls. + */ +void +AnnotationFontWidget::updateFontNameControls() +{ + if ( ! m_annotationsFontName.empty()) { AnnotationTextFontNameEnum::Enum fontName = AnnotationTextFontNameEnum::VERA; bool fontNameValid = true; + + const int32_t numAnn = static_cast(m_annotationsFontName.size()); + for (int32_t i = 0; i < numAnn; i++) { + CaretAssertVectorIndex(m_annotationsFontName, i); + AnnotationFontAttributesInterface* annText = m_annotationsFontName[i]; + CaretAssert(annText); + + if (i == 0) { + fontName = annText->getFont(); + } + else { + if (annText->getFont() != fontName) { + fontNameValid = false; + } + } + } + + m_fontNameComboBox->setSelectedItem(fontName); + + AnnotationText::setUserDefaultFont(fontName); + } +} + +/** + * Update the font size controls. + */ +void +AnnotationFontWidget::updateFontSizeControls() +{ + if ( ! m_annotationsFontSize.empty()) { float fontSizeValue = 5.0; bool haveMultipleFontSizeValues = false; const float surfaceMontageRowCount = getSurfaceMontageRowCount(); - const int32_t numAnn = static_cast(m_annotationsFontStyle.size()); + const int32_t numAnn = static_cast(m_annotationsFontSize.size()); for (int32_t i = 0; i < numAnn; i++) { - CaretAssertVectorIndex(m_annotationsFontStyle, i); - AnnotationFontAttributesInterface* annText = m_annotationsFontStyle[i]; + CaretAssertVectorIndex(m_annotationsFontSize, i); + AnnotationFontAttributesInterface* annText = m_annotationsFontSize[i]; CaretAssert(annText); - Annotation* annotation = dynamic_cast(annText); - CaretAssert(annotation); - m_annotations.push_back(annotation); - float sizeValue = annText->getFontPercentViewportSize(); Annotation* ann = dynamic_cast(annText); @@ -315,21 +374,45 @@ AnnotationFontWidget::updateContent(std::vectorgetFont(); fontSizeValue = sizeValue; } else { - if (annText->getFont() != fontName) { - fontNameValid = false; - } if (fontSizeValue != sizeValue) { haveMultipleFontSizeValues = true; fontSizeValue = std::min(fontSizeValue, sizeValue); } } + } + + updateFontSizeSpinBox(fontSizeValue, + haveMultipleFontSizeValues); + + AnnotationText::setUserDefaultFontPercentViewportSize(fontSizeValue); + } +} + +/** + * Update the font style controls. + */ +void +AnnotationFontWidget::updateFontStyleControls() +{ + if ( ! m_annotationsFontStyle.empty()) { + bool boldOnFlag = true; + bool italicOnFlag = true; + bool underlineOnFlag = true; + int32_t stylesEnabledCount = 0; + + const int32_t numAnn = static_cast(m_annotationsFontStyle.size()); + for (int32_t i = 0; i < numAnn; i++) { + CaretAssertVectorIndex(m_annotationsFontStyle, i); + AnnotationFontAttributesInterface* annText = m_annotationsFontStyle[i]; + CaretAssert(annText); - if (annText->isStylesSupported()) { + Annotation* annotation = dynamic_cast(annText); + CaretAssert(annotation); + if (annotation->testProperty(Annotation::Property::TEXT_FONT_STYLE)) { if ( ! annText->isBoldStyleEnabled()) { boldOnFlag = false; } @@ -344,11 +427,6 @@ AnnotationFontWidget::updateContent(std::vectorsetSelectedItem(fontName); - - updateFontSizeSpinBox(fontSizeValue, - haveMultipleFontSizeValues); - /* * Font styles are ON only if all selected * text annotations have the style enabled @@ -357,29 +435,22 @@ AnnotationFontWidget::updateContent(std::vectorsetEnabled(stylesEnabledFlag); m_boldFontAction->setChecked(boldOnFlag && stylesEnabledFlag); - + m_italicFontAction->setEnabled(stylesEnabledFlag); m_italicFontAction->setChecked(italicOnFlag && stylesEnabledFlag); m_underlineFontAction->setEnabled(stylesEnabledFlag); m_underlineFontAction->setChecked(underlineOnFlag && stylesEnabledFlag); - AnnotationText::setUserDefaultFont(fontName); - AnnotationText::setUserDefaultFontPercentViewportSize(fontSizeValue); if (stylesEnabledFlag) { AnnotationText::setUserDefaultBoldEnabled(boldOnFlag); AnnotationText::setUserDefaultItalicEnabled(italicOnFlag); AnnotationText::setUserDefaultUnderlineEnabled(underlineOnFlag); } } - - CaretAssert(m_annotations.size() == m_annotationsFontStyle.size()); - - updateTextColorButton(); - - setEnabled( ! m_annotations.empty()); } + /** * Update the font size spin box. * @@ -412,9 +483,9 @@ AnnotationFontWidget::updateFontSizeSpinBox(const float value, void AnnotationFontWidget::textColorSelected(const CaretColorEnum::Enum caretColor) { - if ( ! m_annotationsFontStyle.empty()) { + if ( ! m_annotationsFontColor.empty()) { float rgba[4]; - m_annotationsFontStyle[0]->getTextColorRGBA(rgba); + m_annotationsFontColor[0]->getTextColorRGBA(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; @@ -447,7 +518,7 @@ AnnotationFontWidget::textColorSelected(const CaretColorEnum::Enum caretColor) AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTextColor(caretColor, rgba, - m_annotations); + convertToAnnotations(m_annotationsFontColor)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, @@ -494,24 +565,20 @@ AnnotationFontWidget::updateTextColorButton() switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { - const int32_t numAnnotations = static_cast(m_annotationsFontStyle.size()); + const int32_t numAnnotations = static_cast(m_annotationsFontColor.size()); if (numAnnotations > 0) { bool firstColorSupportFlag = true; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { - if ( ! m_annotationsFontStyle[i]->isFontColorGuiEditable()) { - continue; - } - if (firstColorSupportFlag) { - m_annotationsFontStyle[i]->getTextColorRGBA(rgba); + m_annotationsFontColor[i]->getTextColorRGBA(rgba); firstColorSupportFlag = false; colorButtonValidFlag = true; } else { float colorRGBA[4]; - m_annotationsFontStyle[i]->getTextColorRGBA(colorRGBA); + m_annotationsFontColor[i]->getTextColorRGBA(colorRGBA); for (int32_t iColor = 0; iColor < 4; iColor++) { if (rgba[iColor] != colorRGBA[iColor]) { allSameColorFlag = false; @@ -526,11 +593,11 @@ AnnotationFontWidget::updateTextColorButton() } if (allSameColorFlag) { - colorEnum = m_annotationsFontStyle[0]->getTextColor(); - m_annotationsFontStyle[0]->getTextColorRGBA(rgba); + colorEnum = m_annotationsFontColor[0]->getTextColor(); + m_annotationsFontColor[0]->getTextColorRGBA(rgba); float customRGBA[4]; - m_annotationsFontStyle[0]->getCustomTextColor(customRGBA); + m_annotationsFontColor[0]->getCustomTextColor(customRGBA); m_textColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { @@ -571,7 +638,7 @@ AnnotationFontWidget::fontBoldChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontBold(m_boldFontAction->isChecked(), - m_annotations); + convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, @@ -599,7 +666,7 @@ AnnotationFontWidget::fontItalicChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontItalic(m_italicFontAction->isChecked(), - m_annotations); + convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, @@ -629,7 +696,7 @@ AnnotationFontWidget::fontNameChanged() AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontName(fontName, - m_annotations); + convertToAnnotations(m_annotationsFontName)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, @@ -661,7 +728,7 @@ AnnotationFontWidget::fontSizeChanged() AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontPercentSize(fontPercentSize, - m_annotations, + convertToAnnotations(m_annotationsFontSize), getSurfaceMontageRowCount()); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; @@ -717,7 +784,7 @@ AnnotationFontWidget::fontUnderlineChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontUnderline(m_underlineFontAction->isChecked(), - m_annotations); + convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, @@ -738,3 +805,26 @@ AnnotationFontWidget::fontUnderlineChanged() } } +/** + * Convert the font style interfade annotations to annotations + * + * @param fontInterfaces + * Input font interface annotations. + * @return + * Vector with input converted to Annotation class. + */ +std::vector +AnnotationFontWidget::convertToAnnotations(const std::vector& fontInterfaces) +{ + std::vector annotationsOut; + + for (auto f : fontInterfaces) { + Annotation* a = dynamic_cast(f); + CaretAssert(a); + annotationsOut.push_back(a); + } + + return annotationsOut; +} + + diff --git a/src/GuiQt/AnnotationFontWidget.h b/src/GuiQt/AnnotationFontWidget.h index 9a20de2bf..b65c3aea5 100644 --- a/src/GuiQt/AnnotationFontWidget.h +++ b/src/GuiQt/AnnotationFontWidget.h @@ -78,8 +78,16 @@ namespace caret { void updateTextColorButton(); + void updateFontNameControls(); + + void updateFontSizeControls(); + + void updateFontStyleControls(); + float getSurfaceMontageRowCount() const; + static std::vector convertToAnnotations(const std::vector& fontInterfaces); + const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const int32_t m_browserWindowIndex; @@ -100,12 +108,18 @@ namespace caret { QAction* m_underlineFontAction; - /** Contains annotations */ - std::vector m_annotations; + /** Contains annotations supporting font name */ + std::vector m_annotationsFontName; + + /** Contains annotations supporting font style */ + std::vector m_annotationsFontSize; - /** Contains annotations with type as font style */ + /** Contains annotations supporting font style */ std::vector m_annotationsFontStyle; + /** Contains annotations supporting font color */ + std::vector m_annotationsFontColor; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index 861a2f1e1..2d218a7be 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -60,7 +60,7 @@ m_browserWindowIndex(browserWindowIndex) { QLabel* label = new QLabel("Line"); - const QSize toolButtonSize(24, 24); //(18, 18); + const QSize toolButtonSize(24, 24); @@ -71,7 +71,6 @@ m_browserWindowIndex(browserWindowIndex) m_endArrowAction->setIcon(QIcon(createArrowPixmap(endArrowToolButton, ArrowType::DOWN))); QObject::connect(m_endArrowAction, &QAction::triggered, this, &AnnotationLineArrowTipsWidget::endArrowTipActionToggled); - //this, [=] { this->endArrowTipActionToggled(); }); endArrowToolButton->setDefaultAction(m_endArrowAction); WuQtUtilities::setToolButtonStyleForQt5Mac(endArrowToolButton); @@ -83,7 +82,6 @@ m_browserWindowIndex(browserWindowIndex) m_startArrowAction->setIcon(QIcon(createArrowPixmap(startArrowToolButton, ArrowType::UP))); QObject::connect(m_startArrowAction, &QAction::triggered, this, &AnnotationLineArrowTipsWidget::startArrowTipActionToggled); - //this, [=] { this->startArrowTipActionToggled(); }); startArrowToolButton->setDefaultAction(m_startArrowAction); WuQtUtilities::setToolButtonStyleForQt5Mac(startArrowToolButton); @@ -116,9 +114,12 @@ void AnnotationLineArrowTipsWidget::updateContent(std::vector& annotationLines) { m_annotations.clear(); - m_annotations.insert(m_annotations.end(), - annotationLines.begin(), - annotationLines.end()); + m_annotations.reserve(annotationLines.size()); + for (auto a : annotationLines) { + if (a->testProperty(Annotation::Property::LINE_ARROWS)) { + m_annotations.push_back(a); + } + } AnnotationLine* line = NULL; if ( ! annotationLines.empty()) { @@ -263,78 +264,6 @@ AnnotationLineArrowTipsWidget::createArrowPixmap(const QWidget* widget, painter->drawPolygon(triangle); return pixmap; - -// switch (annotationType) { -// case AnnotationTypeEnum::BOX: -// painter->drawRect(1, 1, width - 2, height - 2); -// break; -// case AnnotationTypeEnum::COLOR_BAR: -// CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); -// break; -// case AnnotationTypeEnum::IMAGE: -// { -// const int blueAsGray = qGray(25,25,255); -// QColor skyColor(blueAsGray, blueAsGray, blueAsGray); -// -// /* -// * Background (sky) -// */ -// painter->fillRect(pixmap.rect(), skyColor); -// -// const int greenAsGray = qGray(0, 255, 0); -// QColor terrainColor(greenAsGray, greenAsGray, greenAsGray); -// -// /* -// * Terrain -// */ -// painter->setBrush(terrainColor); -// painter->setPen(terrainColor); -// const int w14 = width * 0.25; -// const int h23 = height * 0.667; -// const int h34 = height * 0.75; -// QPolygon terrain; -// terrain.push_back(QPoint(1, height - 1)); -// terrain.push_back(QPoint(width - 1, height - 1)); -// terrain.push_back(QPoint(width - 1, h23)); -// terrain.push_back(QPoint(w14 * 3, h34)); -// terrain.push_back(QPoint(w14 * 2, h23)); -// terrain.push_back(QPoint(w14, h34)); -// terrain.push_back(QPoint(1, h23)); -// terrain.push_back(QPoint(1, height - 1)); -// painter->drawPolygon(terrain); -// -// const int yellowAsGray = qGray(255, 255, 0); -// QColor sunColor(yellowAsGray, yellowAsGray, yellowAsGray); -// -// /* -// * Sun -// */ -// painter->setBrush(sunColor); -// painter->setPen(sunColor); -// const int radius = width * 0.25; -// painter->drawEllipse(width * 0.33, height * 0.33, radius, radius); -// } -// break; -// case AnnotationTypeEnum::LINE: -// painter->drawLine(1, height - 1, width - 1, 1); -// break; -// case AnnotationTypeEnum::OVAL: -// painter->drawEllipse(1, 1, width - 1, height - 1); -// break; -// case AnnotationTypeEnum::TEXT: -// { -// QFont font = painter->font(); -// font.setPixelSize(20); -// painter->setFont(font); -// painter->drawText(pixmap.rect(), -// (Qt::AlignCenter), -// "A"); -// } -// break; -// } -// -// return pixmap; -// } diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index 8190bc5a4..de9a2363d 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -154,81 +154,83 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) for (int32_t i = 0; i < numAnns; i++) { CaretAssertVectorIndex(annotations, i); Annotation* ann = annotations[i]; - if (ann->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { - AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(ann); - AnnotationOneDimensionalShape* oneDimAnn = getValidOneDimAnnotation(ann); - - float angle = 0.0; - float angleValid = false; - if (twoDimAnn != NULL) { - angle = twoDimAnn->getRotationAngle(); - angleValid = true; - } - else if (oneDimAnn != NULL) { - int32_t viewport[4] = { 0, 0, 0, 0 }; - bool viewportValidFlag = false; - switch (oneDimAnn->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - { - const int tabIndex = oneDimAnn->getTabIndex(); - EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX, - tabIndex); - EventManager::get()->sendEvent(vpSizeEvent.getPointer()); - if (vpSizeEvent.isViewportSizeValid()) { - vpSizeEvent.getViewportSize(viewport); - viewportValidFlag = true; - } - } - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - { - const int windowIndex = oneDimAnn->getWindowIndex(); - EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_WINDOW_INDEX, - windowIndex); - EventManager::get()->sendEvent(vpSizeEvent.getPointer()); - if (vpSizeEvent.isViewportSizeValid()) { - vpSizeEvent.getViewportSize(viewport); - viewportValidFlag = true; - } - } - break; - } + if (ann->testProperty(Annotation::Property::ROTATION)) { + if (ann->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { + AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(ann); + AnnotationOneDimensionalShape* oneDimAnn = getValidOneDimAnnotation(ann); - if (viewportValidFlag) { - angle = oneDimAnn->getRotationAngle(viewport[2], viewport[3]); + float angle = 0.0; + float angleValid = false; + if (twoDimAnn != NULL) { + angle = twoDimAnn->getRotationAngle(); angleValid = true; } - } - - if (angleValid) { - if (angle < 0.0) { - angle += 360.0; - } - else if (angle > 360.0) { - angle -= 360.0; + else if (oneDimAnn != NULL) { + int32_t viewport[4] = { 0, 0, 0, 0 }; + bool viewportValidFlag = false; + switch (oneDimAnn->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + { + const int tabIndex = oneDimAnn->getTabIndex(); + EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX, + tabIndex); + EventManager::get()->sendEvent(vpSizeEvent.getPointer()); + if (vpSizeEvent.isViewportSizeValid()) { + vpSizeEvent.getViewportSize(viewport); + viewportValidFlag = true; + } + } + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + { + const int windowIndex = oneDimAnn->getWindowIndex(); + EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_WINDOW_INDEX, + windowIndex); + EventManager::get()->sendEvent(vpSizeEvent.getPointer()); + if (vpSizeEvent.isViewportSizeValid()) { + vpSizeEvent.getViewportSize(viewport); + viewportValidFlag = true; + } + } + break; + } + + if (viewportValidFlag) { + angle = oneDimAnn->getRotationAngle(viewport[2], viewport[3]); + angleValid = true; + } } - if (rotationAngleValid) { - if (rotationAngle != angle) { - haveMultipleRotationAnglesFlag = true; + if (angleValid) { + if (angle < 0.0) { + angle += 360.0; } - rotationAngle = std::min(rotationAngle, - angle); - } - else { - rotationAngle = angle; - rotationAngleValid = true; + else if (angle > 360.0) { + angle -= 360.0; + } + + if (rotationAngleValid) { + if (rotationAngle != angle) { + haveMultipleRotationAnglesFlag = true; + } + rotationAngle = std::min(rotationAngle, + angle); + } + else { + rotationAngle = angle; + rotationAngleValid = true; + } + + m_annotations.push_back(ann); } - - m_annotations.push_back(ann); } } } @@ -261,22 +263,6 @@ AnnotationRotationWidget::updateContent(std::vector& annotations) void AnnotationRotationWidget::rotationValueChanged(double value) { -// AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); -// std::vector annotations = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex); -// -// std::vector rotateAnnotations; -// const int32_t numAnns = static_cast(annotations.size()); -// for (int32_t i = 0; i < numAnns; i++) { -// CaretAssertVectorIndex(annotations, i); -// Annotation* ann = annotations[i]; -// AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(ann); -// AnnotationOneDimensionalShape* oneDimAnn = getValidOneDimAnnotation(ann); -// if ((oneDimAnn != NULL) -// || (twoDimAnn != NULL)) { -// rotateAnnotations.push_back(ann); -// } -// } - if ( ! m_annotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeRotationAngle(value, @@ -291,13 +277,4 @@ AnnotationRotationWidget::rotationValueChanged(double value) EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } - -// AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); -// AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); -// undoCommand->setModeRotationAngle(value, -// annMan->getAnnotationsSelectedForEditing()); -// annMan->applyCommand(undoCommand); -// -// EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); -// EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } diff --git a/src/GuiQt/AnnotationRotationWidget.h b/src/GuiQt/AnnotationRotationWidget.h index 696432104..6fb7419a6 100644 --- a/src/GuiQt/AnnotationRotationWidget.h +++ b/src/GuiQt/AnnotationRotationWidget.h @@ -45,8 +45,6 @@ namespace caret { // ADD_NEW_METHODS_HERE - -// void updateContent(std::vector& annotation2D); void updateContent(std::vector& annotations); diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.cxx b/src/GuiQt/AnnotationTextAlignmentWidget.cxx index f9fd727a3..8e5398dfc 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.cxx +++ b/src/GuiQt/AnnotationTextAlignmentWidget.cxx @@ -77,7 +77,7 @@ m_browserWindowIndex(browserWindowIndex) QToolButton* rightAlignToolButton = createHorizontalAlignmentToolButton(AnnotationTextAlignHorizontalEnum::RIGHT); m_horizontalAlignActionGroup = new QActionGroup(this); - m_horizontalAlignActionGroup->setExclusive(false); // not exclusive as may need to turn all off + m_horizontalAlignActionGroup->setExclusive(false); /** not exclusive as may need to turn all off */ m_horizontalAlignActionGroup->addAction(leftAlignToolButton->defaultAction()); m_horizontalAlignActionGroup->addAction(centerAlignToolButton->defaultAction()); m_horizontalAlignActionGroup->addAction(rightAlignToolButton->defaultAction()); @@ -90,7 +90,7 @@ m_browserWindowIndex(browserWindowIndex) QToolButton* bottomAlignToolButton = createVerticalAlignmentToolButton(AnnotationTextAlignVerticalEnum::BOTTOM); m_verticalAlignActionGroup = new QActionGroup(this); - m_verticalAlignActionGroup->setExclusive(false); // not exclusive as may need to turn all off + m_verticalAlignActionGroup->setExclusive(false); /** not exclusive as may need to turn all off */ m_verticalAlignActionGroup->addAction(topAlignToolButton->defaultAction()); m_verticalAlignActionGroup->addAction(middleAlignToolButton->defaultAction()); m_verticalAlignActionGroup->addAction(bottomAlignToolButton->defaultAction()); @@ -160,9 +160,12 @@ void AnnotationTextAlignmentWidget::updateContent(std::vector& annotationTexts) { m_annotations.clear(); - m_annotations.insert(m_annotations.end(), - annotationTexts.begin(), - annotationTexts.end()); + m_annotations.reserve(annotationTexts.size()); + for (auto a : annotationTexts) { + if (a->testProperty(Annotation::Property::TEXT_ORIENTATION)) { + m_annotations.push_back(a); + } + } { /* @@ -467,7 +470,7 @@ AnnotationTextAlignmentWidget::createHorizontalAlignmentPixmap(const QWidget* wi const qreal margin = width * 0.05; const qreal longLineLength = width - (margin * 2.0); const qreal shortLineLength = width / 2.0; - const qreal yStep = MathFunctions::round(height / (numLines + 1)); //6.0); + const qreal yStep = MathFunctions::round(height / (numLines + 1)); for (int32_t i = 1; i <= numLines; i++) { const qreal lineLength = (((i % 2) == 0) diff --git a/src/GuiQt/AnnotationTextEditorWidget.cxx b/src/GuiQt/AnnotationTextEditorWidget.cxx index 3c85969a0..4e80d4441 100644 --- a/src/GuiQt/AnnotationTextEditorWidget.cxx +++ b/src/GuiQt/AnnotationTextEditorWidget.cxx @@ -109,8 +109,11 @@ void AnnotationTextEditorWidget::updateContent(std::vector& annotationTexts) { m_annotationText = NULL; - if (annotationTexts.size() == 1) { - m_annotationText = annotationTexts[0]; + for (auto a : annotationTexts) { + if (a->testProperty(Annotation::Property::TEXT_EDIT)) { + m_annotationText = a; + break; + } } diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index 92601646e..3dbe7064a 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -100,9 +100,12 @@ void AnnotationTextOrientationWidget::updateContent(std::vector& annotationTextsIn) { m_annotations.clear(); - m_annotations.insert(m_annotations.end(), - annotationTextsIn.begin(), - annotationTextsIn.end()); + m_annotations.reserve(annotationTextsIn.size()); + for (auto a : annotationTextsIn) { + if (a->testProperty(Annotation::Property::TEXT_ORIENTATION)) { + m_annotations.push_back(a); + } + } { /* diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 259d54ff7..5363a3dbb 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -1380,7 +1380,7 @@ UserInputModeAnnotations::showContextMenu(const MouseEvent& mouseEvent, UserInputModeAnnotationsContextMenu contextMenu(this, mouseEvent, - NULL, //idManager, + NULL, tabContent, openGLWidget); if (contextMenu.actions().size() > 0) { @@ -1620,30 +1620,40 @@ UserInputModeAnnotations::getEnabledEditMenuItems(std::vector::const_iterator iter = allSelectedAnnotations.begin(); iter != allSelectedAnnotations.end(); iter++) { const Annotation* ann = *iter; - if (ann->getType() == AnnotationTypeEnum::COLOR_BAR) { - noColorBarsSelectedFlag = false; + if ( ! ann->testProperty(Annotation::Property::COPY_CUT_PASTE)) { + allAllowCopyCutPasteFlag = false; + } + if ( ! ann->testProperty(Annotation::Property::DELETE)) { + allAllowDeleteFlag = false; } } - if (noColorBarsSelectedFlag) { - const bool anySelectedFlag = ( ! allSelectedAnnotations.empty()); - const bool oneSelectedFlag = (allSelectedAnnotations.size() == 1); - + const bool anySelectedFlag = ( ! allSelectedAnnotations.empty()); + const bool oneSelectedFlag = (allSelectedAnnotations.size() == 1); + if (allAllowCopyCutPasteFlag) { if (oneSelectedFlag) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::COPY); enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::CUT); } - + } + + if (allAllowDeleteFlag) { if (anySelectedFlag) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::DELETER); } - - enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::SELECT_ALL); + } + + if (allAllowSelectFlag) { + if (anySelectedFlag) { + enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::SELECT_ALL); + } } if (annotationManager->isAnnotationOnClipboardValid()) { diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index b49855225..e493f487d 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -97,6 +97,9 @@ m_newAnnotationCreatedByContextMenu(NULL) m_annotation = NULL; bool allSelectedAnnotationsDeletableFlag = true; + if (selectedAnnotations.empty()) { + allSelectedAnnotationsDeletableFlag = false; + } m_threeDimCoordAnnotations.clear(); for (std::vector >::iterator iter = selectedAnnotations.begin(); @@ -127,7 +130,7 @@ m_newAnnotationCreatedByContextMenu(NULL) m_threeDimCoordAnnotations.push_back(ann); } - if ( ! ann->isDeletable()) { + if ( ! ann->testProperty(Annotation::Property::DELETE)) { allSelectedAnnotationsDeletableFlag = false; } } @@ -140,7 +143,7 @@ m_newAnnotationCreatedByContextMenu(NULL) m_annotationFile = selectedAnnotations[0].second; m_annotation = selectedAnnotations[0].first; oneAnnotationSelectedFlag = true; - if (m_annotation->isDeletable()) { + if (m_annotation->testProperty(Annotation::Property::DELETE)) { oneDeletableAnnotationSelectedFlag = true; } } -- GitLab From e8dff7f62f1337d7bedfe7e28c5174ffa09002b2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 21 Jul 2017 15:48:06 -0500 Subject: [PATCH 324/755] Change annotation line widths from "pixel thickness" to "percentage of viewport height thickness". That is, the thickness of a line is a function of the height specified by the user and the height of the viewport in which the line is drawn. However, the minimum and maximum thickness is dependent upon the implementation of OpenGL. On Mac, the maximum thickness is 10 pixels so lines will stop growing in thickness fairly quickly. --- src/Brain/BrainOpenGL.cxx | 2 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 59 +++++++++++++------ ...rainOpenGLAnnotationDrawingFixedPipeline.h | 36 +++-------- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 2 - src/Brain/BrainOpenGLFixedPipeline.cxx | 10 ---- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 2 - src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 2 - src/Brain/FtglFontTextRenderer.cxx | 48 +++++++++++++-- src/Brain/FtglFontTextRenderer.h | 20 +++++-- src/GuiQt/AnnotationColorWidget.cxx | 23 ++++---- 10 files changed, 118 insertions(+), 86 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 4fdbb2864..d2bf503f8 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -790,7 +790,7 @@ BrainOpenGL::initializeOpenGL() glGetFloatv(GL_POINT_SIZE_RANGE, sizes); s_minPointSize = sizes[0]; s_maxPointSize = sizes[1]; - glGetFloatv(GL_LINE_WIDTH_RANGE, sizes); + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, sizes); s_minLineWidth = sizes[0]; s_maxLineWidth = sizes[1]; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index b4356daad..f68d236a2 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -95,6 +95,8 @@ m_volumeSliceThickness(0.0) 0.7, 1.0); + BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, + m_lineWidthMaximum); } /** @@ -1186,7 +1188,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 }; - const float outlineWidth = box->getLineWidth(); + const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidth()); const bool depthTestFlag = isDrawnWithDepthTesting(box); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); @@ -1272,7 +1274,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil bottomRight, topRight, topLeft, - outlineWidth, + s_sizingHandleLineWidthInPixels, box->getRotationAngle()); } } @@ -1320,8 +1322,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 }; - const float outlineWidth = colorBar->getLineWidth(); - const bool depthTestFlag = isDrawnWithDepthTesting(colorBar); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); @@ -1458,7 +1458,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati bottomRight, topRight, topLeft, - outlineWidth, + s_sizingHandleLineWidthInPixels, colorBar->getRotationAngle()); } @@ -1903,7 +1903,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi const float majorAxis = ((oval->getWidth() / 100.0) * (m_modelSpaceViewport[2] / 2.0)); const float minorAxis = ((oval->getHeight() / 100.0) * (m_modelSpaceViewport[3] / 2.0)); const float rotationAngle = oval->getRotationAngle(); - const float outlineWidth = oval->getLineWidth(); + const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidth()); const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, @@ -1988,7 +1988,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi bottomRight, topRight, topLeft, - outlineWidth, + s_sizingHandleLineWidthInPixels, oval->getRotationAngle()); } } @@ -2083,7 +2083,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin createLineCoordinates(annXYZ, brainordinateXYZ, - text->getLineWidth(), + getLineWidthFromPercentageHeight(text->getLineWidth()), false, showArrowFlag, lineCoordinatesOut); @@ -2288,7 +2288,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi if ( ! connectLineCoordinates.empty()) { BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, textColorRGBA, - text->getLineWidth()); + getLineWidthFromPercentageHeight(text->getLineWidth())); } if (drawTextFlag) { @@ -2330,9 +2330,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi boxCoords.insert(boxCoords.end(), tl, tl + 3); if (boxCoords.size() == 12) { + const float lineWidthPixelsForDrawingNewTextAnnotation = 2.0f; BrainOpenGLPrimitiveDrawing::drawLineLoop(boxCoords, foregroundRGBA, - text->getLineWidth()); + lineWidthPixelsForDrawingNewTextAnnotation); } } else { @@ -2348,14 +2349,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi } if (text->isSelectedForEditing(m_inputs->m_windowIndex)) { - const float outlineWidth = 2.0; drawAnnotationTwoDimSizingHandles(annotationFile, text, bottomLeft, bottomRight, topRight, topLeft, - outlineWidth, + s_sizingHandleLineWidthInPixels, text->getRotationAngle()); /* @@ -2515,21 +2515,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (drawForegroundFlag) { BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, foregroundRGBA, - image->getLineWidth()); + getLineWidthFromPercentageHeight(image->getLineWidth())); } setDepthTestingStatus(depthTestFlag); } if (image->isSelectedForEditing(m_inputs->m_windowIndex)) { - const float outlineWidth = 2.0; drawAnnotationTwoDimSizingHandles(annotationFile, image, bottomLeft, bottomRight, topRight, topLeft, - outlineWidth, + s_sizingHandleLineWidthInPixels, image->getRotationAngle()); } } @@ -2692,7 +2691,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi lineTailXYZ)) { return false; } - const float lineWidth = line->getLineWidth(); + const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidth()); const float backgroundLineWidth = lineWidth + 4; const float selectionCenterXYZ[3] = { @@ -2707,7 +2706,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi std::vector coords; createLineCoordinates(lineHeadXYZ, lineTailXYZ, - line->getLineWidth(), + lineWidth, line->isDisplayStartArrow(), line->isDisplayEndArrow(), coords); @@ -2745,7 +2744,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi line, lineHeadXYZ, lineTailXYZ, - lineWidth); + s_sizingHandleLineWidthInPixels); } } @@ -3323,3 +3322,27 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setDepthTestingStatus(const bool newD return (savedStatus == GL_TRUE); } +/** + * Convert a percentage height to a line width in pixels + * + * @param percentageHeight + * Percentage of viewport height. + * @return + * Line width in pixels clamped to valid range + */ +float +BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthFromPercentageHeight(const float percentageHeight) const +{ + float widthPixels = (percentageHeight / 100.0f) * m_modelSpaceViewport[3]; + + if (widthPixels < m_lineWidthMinimum) { + widthPixels = m_lineWidthMinimum; + } + else if (widthPixels > m_lineWidthMaximum) { + widthPixels = m_lineWidthMaximum; + } + + return widthPixels; +} + + diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index a37fd75bb..e6b115c5c 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -54,25 +54,6 @@ namespace caret { public: class Inputs { public: - /** - * Viewport height used for setting text height - */ - enum TextHeightMode { - /** - * Use the viewport height from OpenGL drawing (last set by call to glViewport()). - * This is the viewport that is active when annotation drawing is executed and in - * which the model is drawn. - */ - TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, - /** - * Use the tab viewport height from the "Inputs". - * This mode is primarily used when drawing a surface montage and results in - * the same text height for a stereotaxic or surface annotation in both - * surface montage and single surface mode. - */ - TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT - }; - enum WindowDrawingMode { WINDOW_DRAWING_NO, WINDOW_DRAWING_YES @@ -81,31 +62,22 @@ namespace caret { Inputs(Brain* brain, const BrainOpenGLFixedPipeline::Mode drawingMode, const float centerToEyeDistance, - const int32_t tabViewport[4], const int32_t windowIndex, const int32_t tabIndex, - const TextHeightMode textHeightMode, const WindowDrawingMode windowDrawingMode) : m_brain(brain), m_drawingMode(drawingMode), m_centerToEyeDistance(centerToEyeDistance), m_windowIndex(windowIndex), m_tabIndex(tabIndex), - m_textHeightMode(textHeightMode), m_windowDrawingMode(windowDrawingMode) { - m_tabViewport[0] = tabViewport[0]; - m_tabViewport[1] = tabViewport[1]; - m_tabViewport[2] = tabViewport[2]; - m_tabViewport[3] = tabViewport[3]; } Brain* m_brain; const BrainOpenGLFixedPipeline::Mode m_drawingMode; const float m_centerToEyeDistance; - int32_t m_tabViewport[4]; const int32_t m_windowIndex; const int32_t m_tabIndex; - const TextHeightMode m_textHeightMode; const WindowDrawingMode m_windowDrawingMode; }; @@ -330,6 +302,8 @@ namespace caret { const float startXYZ[3], float endXYZ[3]) const; + float getLineWidthFromPercentageHeight(const float percentageHeight) const; + BrainOpenGLFixedPipeline* m_brainOpenGLFixedPipeline; Inputs* m_inputs; @@ -371,6 +345,12 @@ namespace caret { /** Used for rotation hanlde circle */ BrainOpenGLShapeRing* m_rotationHandleCircle; + float m_lineWidthMinimum = 1.0f; + + float m_lineWidthMaximum = 5.0f; + + static constexpr float s_sizingHandleLineWidthInPixels = 2.0f; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 7d4713360..12ef4872f 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -284,10 +284,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(m_fixedPipelineDrawing->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_fixedPipelineDrawing->m_tabViewport, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; std::vector emptyViewportAnnotations; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 0bf282c27..4887872e9 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -788,10 +788,8 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(BrainOpenGLViewpor BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_tabViewport, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; std::vector emptyViewportAnnotations; @@ -850,10 +848,8 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - tabViewport, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); //std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, @@ -921,10 +917,8 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - windowViewport, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, windowDrawingMode); std::vector emptyViewportAnnotations; @@ -1861,10 +1855,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_tabViewport, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; std::vector emptyViewportAnnotations; @@ -1911,10 +1903,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_tabViewport, m_windowIndex, this->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_TAB_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); std::vector emptyColorBars; std::vector emptyViewportAnnotations; diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 31b54fbeb..f9b09236f 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -850,10 +850,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewProjection(const Volume BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_fixedPipelineDrawing->m_tabViewport, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 80027a6ce..e58300a4e 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -867,10 +867,8 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewProjection(const VolumeSliceDr BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_fixedPipelineDrawing->m_tabViewport, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index fd303e601..eafb97132 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -130,6 +130,8 @@ FtglFontTextRenderer::FtglFontTextRenderer() true); #endif // HAVE_FREETYPE m_depthTestingStatus = DEPTH_TEST_NO; + BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, + m_lineWidthMaximum); } /** @@ -269,8 +271,28 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, #endif // HAVE_FREETYPE } - - +/** + * Convert a percentage height to a line width in pixels + * + * @param percentageHeight + * Percentage of viewport height. + * @return + * Line width in pixels clamped to valid range + */ +double +FtglFontTextRenderer::getLineWidthFromPercentageHeight(const double percentageHeight) const +{ + float widthPixels = (percentageHeight / 100.0) * m_viewportHeight; + + if (widthPixels < m_lineWidthMinimum) { + widthPixels = m_lineWidthMinimum; + } + else if (widthPixels > m_lineWidthMaximum) { + widthPixels = m_lineWidthMaximum; + } + + return widthPixels; +} /** * Draw the text piceces at their assigned viewport coordinates. @@ -732,12 +754,15 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth m_depthTestingStatus = depthTesting; + const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidth()); + TextStringGroup tsg(annotationText, font, viewportX, viewportY, viewportZ, - annotationText.getRotationAngle()); + annotationText.getRotationAngle(), + lineThicknessForViewportHeight); //tsg.print(); drawTextAtViewportCoordinatesInternal(annotationText, tsg); @@ -799,12 +824,15 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann + AString((char*)gluErrorString(errorCode))); } + double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidth()); + TextStringGroup textStringGroup(annotationText, font, viewportX, viewportY, viewportZ, - annotationText.getRotationAngle()); + annotationText.getRotationAngle(), + lineThicknessForViewportHeight); double rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, @@ -1673,19 +1701,23 @@ FtglFontTextRenderer::TextString::getTextBoundsInViewportCoordinates(double& vie * Z-coordinate in the viewport. * @param rotationAngle * Rotation angle for the text. + * @param lineThicknessForViewportHeight + * Line thickness adjusted for viewport height. */ FtglFontTextRenderer::TextStringGroup::TextStringGroup(const AnnotationText& annotationText, FTFont* font, const double viewportX, const double viewportY, const double viewportZ, - const double rotationAngle) + const double rotationAngle, + const double lineThicknessForViewportHeight) : m_annotationText(annotationText), m_font(font), m_viewportX(viewportX), m_viewportY(viewportY), m_viewportZ(viewportZ), m_rotationAngle(rotationAngle), +m_lineThicknessForViewportHeight(lineThicknessForViewportHeight), m_underlineThickness(0.0), m_outlineThickness(0.0), m_viewportBoundsMinX(0.0), @@ -1714,7 +1746,11 @@ m_viewportBoundsMaxY(0.0) */ if (annotationText.getLineColor() != CaretColorEnum::NONE) { if (annotationText.getOrientation() == AnnotationTextOrientationEnum::HORIZONTAL) { - m_outlineThickness = m_annotationText.getLineWidth(); + const double outlineThickness = m_annotationText.getLineWidth(); + if (outlineThickness > 0.0) { + m_outlineThickness = m_lineThicknessForViewportHeight; + } + //m_outlineThickness = m_annotationText.getLineWidth(); } } diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index 20f03d895..265338bbd 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -116,6 +116,9 @@ namespace caret { const float extraSpaceX, const float extraSpaceY); + double getLineWidthFromPercentageHeight(const double percentageHeight) const; + + class FontData { public: FontData(); @@ -224,11 +227,12 @@ namespace caret { class TextStringGroup { public: TextStringGroup(const AnnotationText& annotationText, - FTFont* font, - const double viewportX, - const double viewportY, - const double viewportZ, - const double rotationAngle); + FTFont* font, + const double viewportX, + const double viewportY, + const double viewportZ, + const double rotationAngle, + const double lineThicknessForViewportHeight); ~TextStringGroup(); @@ -255,6 +259,8 @@ namespace caret { const double m_rotationAngle; + const double m_lineThicknessForViewportHeight; + double m_underlineThickness; double m_outlineThickness; @@ -325,6 +331,10 @@ namespace caret { /** Height of the viewport */ int32_t m_viewportHeight; + float m_lineWidthMinimum = 1.0f; + + float m_lineWidthMaximum = 5.0f; + static const double s_textMarginSize; }; diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 944b3d75f..7ffec8365 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -139,21 +139,20 @@ m_browserWindowIndex(browserWindowIndex) /* * Line thickness */ - float minimumLineWidth = 0.0; - float maximumLineWidth = 1.0; - BrainOpenGL::getMinMaxLineWidth(minimumLineWidth, - maximumLineWidth); - minimumLineWidth = std::max(minimumLineWidth, 1.0f); + float minimumLineWidthPercentage = 0.1; + float maximumLineWidthPercentage = 100.0; + float lineWidthStep = 0.1; m_lineThicknessWidgetGroup = new WuQWidgetObjectGroup(this); - m_lineThicknessSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minimumLineWidth, - maximumLineWidth, - 1.0, - 0, + m_lineThicknessSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minimumLineWidthPercentage, + maximumLineWidthPercentage, + lineWidthStep, + 1, this, SLOT(lineThicknessSpinBoxValueChanged(double))); WuQtUtilities::setWordWrappedToolTip(m_lineThicknessSpinBox, "Adjust the line thickness"); - m_lineThicknessSpinBox->setFixedWidth(45); + //m_lineThicknessSpinBox->setFixedWidth(45); + m_lineThicknessSpinBox->setSuffix("%"); m_lineThicknessWidgetGroup->add(lineLabel); m_lineThicknessWidgetGroup->add(lineWidthLabel); @@ -744,10 +743,10 @@ AnnotationColorWidget::updateLineThicknessSpinBox() m_lineThicknessSpinBox->setValue(lineWidthValue); m_lineThicknessSpinBox->setEnabled(lineWidthValid); if (haveMultipleLineWidthValues) { - m_lineThicknessSpinBox->setSuffix("+"); + m_lineThicknessSpinBox->setSuffix("%+"); } else { - m_lineThicknessSpinBox->setSuffix(""); + m_lineThicknessSpinBox->setSuffix("%"); } m_lineThicknessSpinBox->blockSignals(false); -- GitLab From 5e4ee1c9ee2323a14204238becbdab4b5cd932c7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 24 Jul 2017 10:50:16 -0500 Subject: [PATCH 325/755] Fixed missing chart axis labels when charts were in tile tabs. Chart drawing code was incorrectly clearing the special annotations output for drawing by annotation code. Also performed a little code cleanup. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 33 +--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 148 ++++++------------ src/Brain/BrainOpenGLFixedPipeline.h | 3 +- 4 files changed, 64 insertions(+), 125 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 12ef4872f..ba41af9b4 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -30,7 +30,6 @@ #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "Brain.h" -#include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrainOpenGLViewportContent.h" @@ -106,9 +105,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * Selected data type. * @param viewport * Viewport for the chart. - * @param viewportSpaceAnnotationsOut - * Output containing annotation chart axis labels that will be drawn - * by the Annotation OpenGL Drawing in viewport space. + * @param annotationsOut + * Output containing annotations that will be drawing by annotation drawing code. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, @@ -117,10 +115,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& viewportSpaceAnnotationsOut) + std::vector& annotationsOut) { - viewportSpaceAnnotationsOut.clear(); - m_viewportSpaceAnnotationsOut.clear(); + annotationsOut.clear(); + m_annotationsForDrawingOutput.clear(); BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); CaretAssert(browserTabContent); @@ -277,30 +275,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, } break; } - - /* - * Draw annotations for the chart. - */ - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(m_fixedPipelineDrawing->m_brain, - m_fixedPipelineDrawing->mode, - BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, - m_fixedPipelineDrawing->m_windowIndex, - m_fixedPipelineDrawing->windowTabIndex, - BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); - std::vector emptyColorBars; - std::vector emptyViewportAnnotations; - m_fixedPipelineDrawing->m_annotationDrawing->drawAnnotations(&inputs, - AnnotationCoordinateSpaceEnum::STEREOTAXIC, - emptyColorBars, - emptyViewportAnnotations, - NULL); } } } restoreStateOfOpenGL(); - viewportSpaceAnnotationsOut = m_viewportSpaceAnnotationsOut; + annotationsOut = m_annotationsForDrawingOutput; } @@ -1719,7 +1700,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini tabPercentageY, 0.0f); - m_viewportSpaceAnnotationsOut.push_back(chartAxisLabel); + m_annotationsForDrawingOutput.push_back(chartAxisLabel); } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 8fe40946f..c9423175d 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -59,7 +59,7 @@ namespace caret { BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], - std::vector& viewportSpaceAnnotationsOut) override; + std::vector& annotationsOut) override; // ADD_NEW_METHODS_HERE @@ -204,7 +204,8 @@ namespace caret { bool m_identificationModeFlag; - std::vector m_viewportSpaceAnnotationsOut; + /** These annotations will be drawn by the annotation drawing code */ + std::vector m_annotationsForDrawingOutput; static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 4887872e9..b56110c79 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -270,7 +270,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, setTabViewport(viewportContent); - m_viewportSpaceAnnotations.clear(); + m_specialCaseGraphicsAnnotations.clear(); std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); @@ -301,7 +301,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, * everything else. */ glClear(GL_DEPTH_BUFFER_BIT); - drawTabAnnotations(viewportContent); //, + drawTabAnnotations(viewportContent); int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); @@ -350,7 +350,7 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex m_clippingPlaneGroup = NULL; - m_viewportSpaceAnnotations.clear(); + m_specialCaseGraphicsAnnotations.clear(); m_brain->getSelectionManager()->reset(); this->modeProjectionData = &projectionOut; @@ -472,26 +472,13 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vector tabIndices; -// for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { -// /* -// * Viewport of window. -// */ -// BrainOpenGLViewportContent* vpContent = viewportContents[i]; -// if (vpContent != NULL) { -// BrowserTabContent* tabContent = vpContent->getBrowserTabContent(); -// if (tabContent != NULL) { -// tabIndices.push_back(tabContent->getTabNumber()); -// } -// } -// } /* * When in tile tabs, a tab may have a color bar in window * space that appears in a different tab. So, we need to * get all color bars. Otherwise, the user will not be able * to select a color when it is displayed in a different tab. */ - EventAnnotationColorBarGet colorBarEvent; //tabIndices); + EventAnnotationColorBarGet colorBarEvent; EventManager::get()->sendEvent(colorBarEvent.getPointer()); m_annotationColorBarsForDrawing = colorBarEvent.getAnnotationColorBars(); } @@ -519,7 +506,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, setTabViewport(NULL); - m_viewportSpaceAnnotations.clear(); + m_specialCaseGraphicsAnnotations.clear(); setAnnotationColorBarsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); @@ -644,8 +631,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, updateForegroundAndBackgroundColors(vpContent); drawTabAnnotations(vpContent); - //m_tabViewport); - } + } /* * Draw window viewport annotations @@ -656,7 +642,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, drawWindowAnnotations(windowViewport); } - m_viewportSpaceAnnotations.clear(); + m_specialCaseGraphicsAnnotations.clear(); this->checkForOpenGLError(NULL, "At end of drawModels()"); @@ -851,13 +837,11 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabCont m_windowIndex, this->windowTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); - //std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, - m_viewportSpaceAnnotations, + m_specialCaseGraphicsAnnotations, NULL); - //m_viewportSpaceAnnotations.clear(); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -921,27 +905,12 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) this->windowTabIndex, windowDrawingMode); - std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, - emptyViewportAnnotations, + m_specialCaseGraphicsAnnotations, NULL); - - - - -// std::vector emptyColorBars; -// m_annotationDrawing->drawAnnotations(&inputs, -// AnnotationCoordinateSpaceEnum::VIEWPORT, -// emptyColorBars, -// m_viewportSpaceAnnotations, -// NULL); -// m_viewportSpaceAnnotations.clear(); - - - - + glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -1024,20 +993,6 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, else { CaretAssertMessage(0, "Unknown type of model for drawing"); } - - -// int viewport[4]; -// viewportContent->getModelViewport(viewport); -// glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); -// -// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, -// this->mode, -// BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, -// m_tabViewport, -// m_windowIndex, -// this->windowTabIndex, -// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::TEXT_HEIGHT_USE_OPENGL_VIEWPORT_HEIGHT, -// BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO); } } @@ -1346,12 +1301,12 @@ BrainOpenGLFixedPipeline::applyViewingTransformations(const Model* model, case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: - eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; //5.0; + eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; upY = 1.0; useGluLookAt = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: - eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; //5.0; + eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; upY = 1.0; useGluLookAt = true; break; @@ -1517,10 +1472,10 @@ BrainOpenGLFixedPipeline::getVolumeFitToWindowScalingAndTranslation(const Volume float temp; float scaleWindowX = (orthoExtentX / xExtent); - temp = (orthoExtentX / yExtent);//parasaggital y is screen x + temp = (orthoExtentX / yExtent);/* parasaggital y is screen x */ if (temp < scaleWindowX) scaleWindowX = temp; float scaleWindowY = (orthoExtentY / zExtent); - temp = (orthoExtentY / yExtent);//axial y is screen y + temp = (orthoExtentY / yExtent);/* axial y is screen y */ if (temp < scaleWindowY) scaleWindowY = temp; scalingOut = std::min(scaleWindowX, scaleWindowY); @@ -1819,8 +1774,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, const DisplayPropertiesBorders* dpb = m_brain->getDisplayPropertiesBorders(); const float borderAboveSurfaceOffset = dpb->getAboveSurfaceOffset(); if (borderAboveSurfaceOffset != 0.0) { - const float factor = borderAboveSurfaceOffset;// + 0.5; - const float units = 1.0;// + 0.5; + const float factor = borderAboveSurfaceOffset; + const float units = 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } @@ -3231,9 +3186,9 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) uint8_t idRGBA[4]; this->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::FOCUS_SURFACE, - i, // file index - j, // focus index - k);// projection index + i, /* file index */ + j, /* focus index */ + k);/* projection index */ idRGBA[3] = 255; if (drawAsSpheres) { this->drawSphereWithDiameter(idRGBA, @@ -3549,7 +3504,6 @@ BrainOpenGLFixedPipeline::setupVolumeDrawInfo(BrowserTabContent* browserTabConte statistics = const_cast(mapFile->getMapFastStatistics(mapIndex)); break; } - //CaretAssert(statistics); PaletteColorMapping* paletteColorMapping = mapFile->getMapPaletteColorMapping(mapIndex); Palette* palette = paletteFile->getPaletteByName(paletteColorMapping->getSelectedPaletteName()); @@ -4300,7 +4254,7 @@ BrainOpenGLFixedPipeline::drawAllFiberOrientations(const FiberOrientationDisplay { const int32_t indx = j % 3; switch (indx) { - case 0: // use RED + case 0: /* use RED */ glColor4f(BrainOpenGLFixedPipeline::COLOR_RED[0], BrainOpenGLFixedPipeline::COLOR_RED[1], BrainOpenGLFixedPipeline::COLOR_RED[2], @@ -4310,7 +4264,7 @@ BrainOpenGLFixedPipeline::drawAllFiberOrientations(const FiberOrientationDisplay fiberRGBA[2] = BrainOpenGLFixedPipeline::COLOR_RED[2]; fiberRGBA[3] = alpha; break; - case 1: // use BLUE + case 1: /* use BLUE */ glColor4f(BrainOpenGLFixedPipeline::COLOR_BLUE[0], BrainOpenGLFixedPipeline::COLOR_BLUE[1], BrainOpenGLFixedPipeline::COLOR_BLUE[2], @@ -4320,7 +4274,7 @@ BrainOpenGLFixedPipeline::drawAllFiberOrientations(const FiberOrientationDisplay fiberRGBA[2] = BrainOpenGLFixedPipeline::COLOR_BLUE[2]; fiberRGBA[3] = alpha; break; - case 2: // use GREEN + case 2: /* use GREEN */ glColor4f(BrainOpenGLFixedPipeline::COLOR_GREEN[0], BrainOpenGLFixedPipeline::COLOR_GREEN[1], BrainOpenGLFixedPipeline::COLOR_GREEN[2], @@ -4737,11 +4691,11 @@ BrainOpenGLFixedPipeline::drawEllipticalCone(const float rgba[4], double zero = 1.0e-3; if (std::abs(vz) < zero) { - ax = 57.2957795*std::acos( vx/z ); // rotation angle in x-y plane + ax = 57.2957795*std::acos( vx/z ); /* rotation angle in x-y plane */ if ( vx <= 0.0f ) ax = -ax; } else { - ax = 57.2957795*std::acos( vz/z ); // rotation angle + ax = 57.2957795*std::acos( vz/z ); /* rotation angle */ if ( vz <= 0.0f ) ax = -ax; } @@ -4758,11 +4712,11 @@ BrainOpenGLFixedPipeline::drawEllipticalCone(const float rgba[4], } if (std::abs(vz) < zero) { - glRotated(90.0, 0.0, 1.0, 0.0); // Rotate & align with x axis - glRotated(ax, -1.0, 0.0, 0.0); // Rotate to point 2 in x-y plane + glRotated(90.0, 0.0, 1.0, 0.0); /* Rotate & align with x axis */ + glRotated(ax, -1.0, 0.0, 0.0); /* Rotate to point 2 in x-y plane */ } else { - glRotated(ax, rx, ry, 0.0); // Rotate about rotation vector + glRotated(ax, rx, ry, 0.0); /* Rotate about rotation vector */ } glPushMatrix(); @@ -4822,11 +4776,11 @@ BrainOpenGLFixedPipeline::drawCylinder(const float rgba[4], double zero = 1.0e-3; if (std::abs(vz) < zero) { - ax = 57.2957795*std::acos( vx/z ); // rotation angle in x-y plane + ax = 57.2957795*std::acos( vx/z ); /* rotation angle in x-y plane */ if ( vx <= 0.0f ) ax = -ax; } else { - ax = 57.2957795*std::acos( vz/z ); // rotation angle + ax = 57.2957795*std::acos( vz/z ); /* rotation angle */ if ( vz <= 0.0f ) ax = -ax; } @@ -4843,11 +4797,11 @@ BrainOpenGLFixedPipeline::drawCylinder(const float rgba[4], } if (std::abs(vz) < zero) { - glRotated(90.0, 0.0, 1.0, 0.0); // Rotate & align with x axis - glRotated(ax, -1.0, 0.0, 0.0); // Rotate to point 2 in x-y plane + glRotated(90.0, 0.0, 1.0, 0.0); /* Rotate & align with x axis */ + glRotated(ax, -1.0, 0.0, 0.0); /* Rotate to point 2 in x-y plane */ } else { - glRotated(ax, rx, ry, 0.0); // Rotate about rotation vector + glRotated(ax, rx, ry, 0.0); /* Rotate about rotation vector */ } glPushMatrix(); @@ -5179,7 +5133,7 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; volumeSliceDrawing.draw(this, browserTabContent, - twoDimSliceDrawVolumeDrawInfo, //volumeDrawInfo, + twoDimSliceDrawVolumeDrawInfo, sliceDrawingType, sliceProjectionType, viewport); @@ -5384,8 +5338,7 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrainOpenGLViewportContent* viewportC CaretAssert(browserTabContent); CaretAssert(chartModel); - //m_viewportSpaceAnnotations.clear(); - + std::vector annotationFromChartDrawing; BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; chartDrawing.drawChartOverlaySet(m_brain, viewportContent, @@ -5393,7 +5346,11 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrainOpenGLViewportContent* viewportC this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, - m_viewportSpaceAnnotations); + annotationFromChartDrawing); + + m_specialCaseGraphicsAnnotations.insert(m_specialCaseGraphicsAnnotations.end(), + annotationFromChartDrawing.begin(), + annotationFromChartDrawing.end()); drawChartCoordinateSpaceAnnotations(viewportContent); } @@ -5478,7 +5435,6 @@ BrainOpenGLFixedPipeline::setOrthographicProjectionForWithBoundingBox(const int3 * See also BrowserTabContent::restoreFromScene() that tries to make * old scenes compatible with this new scaling. */ - //const float zDiff = boundingBox->getDifferenceZ(); if (windowVerticalSize != 0.0) { modelHalfHeight = windowVerticalSize / 2.0; @@ -5536,8 +5492,8 @@ BrainOpenGLFixedPipeline::setOrthographicProjectionWithHeight(const int32_t view this->orthographicLeft = -halfWindowHeight * aspectRatio; this->orthographicTop = halfWindowHeight; this->orthographicBottom = -halfWindowHeight; - this->orthographicNear = -1000.0; //-500.0; //-10000.0; - this->orthographicFar = 1000.0; //500.0; // 10000.0; + this->orthographicNear = -1000.0; + this->orthographicFar = 1000.0; switch (projectionType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: @@ -5588,12 +5544,12 @@ BrainOpenGLFixedPipeline::setOrthographicProjectionWithWidth(const int32_t viewp double width = viewport[2]; double height = viewport[3]; double aspectRatio = (width / height); - this->orthographicRight = halfWindowWidth; // halfWindowHeight * aspectRatio; - this->orthographicLeft = -halfWindowWidth; // -halfWindowHeight * aspectRatio; - this->orthographicTop = halfWindowWidth / aspectRatio; // halfWindowHeight; - this->orthographicBottom = -halfWindowWidth / aspectRatio; //-halfWindowHeight; - this->orthographicNear = -1000.0; //-500.0; //-10000.0; - this->orthographicFar = 1000.0; //500.0; // 10000.0; + this->orthographicRight = halfWindowWidth; + this->orthographicLeft = -halfWindowWidth; + this->orthographicTop = halfWindowWidth / aspectRatio; + this->orthographicBottom = -halfWindowWidth / aspectRatio; + this->orthographicNear = -1000.0; + this->orthographicFar = 1000.0; switch (projectionType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: @@ -5701,7 +5657,7 @@ BrainOpenGLFixedPipeline::getPixelDepthAndRGBA(const int32_t pixelX, #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - glPixelStorei(GL_PACK_ALIGNMENT, 4); // float is 4 bytes + glPixelStorei(GL_PACK_ALIGNMENT, 4); /* float is 4 bytes */ glReadPixels(pixelX, pixelY, 1, @@ -6514,7 +6470,7 @@ BrainOpenGLFixedPipeline::drawImage(BrainOpenGLViewportContent* vpContent, for (int32_t i = 0; i < numberOfPixels; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(imageBytesRGBA, i4 + 3); - uint8_t pixelAlpha = 255; //imageBytesRGBA[i4 + 3]; + uint8_t pixelAlpha = 255; if (testThresholdFlag) { if ((imageBytesRGBA[i4] < minimumThreshold) @@ -6623,8 +6579,8 @@ BrainOpenGLFixedPipeline::drawImage(BrainOpenGLViewportContent* vpContent, if (isSelectImageControlPoint) { this->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::IMAGE_CONTROL_POINT, - 0, // file index - icp); // index in file + 0, /* file index */ + icp); /* index in file */ rgba[3] = 255; } drawSphereWithDiameter(rgba, 10); @@ -6868,7 +6824,7 @@ BrainOpenGLFixedPipeline::getStateOfOpenGL() const -//============================================================================ +/* ============================================================================ */ /** * Constructor. */ diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 3aecd4706..44ca549b2 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -622,7 +622,8 @@ namespace caret { std::vector m_annotationColorBarsForDrawing; - std::vector m_viewportSpaceAnnotations; + /** Some graphics using annotations for some elements so user can select and edit them */ + std::vector m_specialCaseGraphicsAnnotations; static bool s_staticInitialized; -- GitLab From ef231f06b96a67da767b7a792cf9ef1b774d4111 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 24 Jul 2017 11:21:24 -0500 Subject: [PATCH 326/755] Fixed strange drawing behavior when chart axis labels was empty string (caused an invalid viewport). --- src/Brain/FtglFontTextRenderer.cxx | 37 ++++++++++-------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index eafb97132..aaaffe13d 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -395,7 +395,6 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText } const double underlineOffsetY = (textStringGroup.m_underlineThickness / 2.0); - //const double outlineOffsetY = (textStringGroup.m_outlineThickness / 2.0); double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3], rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, @@ -453,7 +452,7 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText drawUnderline(ts->m_stringGlyphsMinX, ts->m_stringGlyphsMaxX, underlineY, - z, //0.0, // Z + z, textStringGroup.m_underlineThickness, foregroundRgba); @@ -464,15 +463,13 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText glPushMatrix(); glTranslated(ts->m_viewportX - rotationPointXYZ[0], ts->m_viewportY - rotationPointXYZ[1], 0.0); -// const double outlineMinY = ts->m_stringGlyphsMinY + outlineOffsetY; -// const double outlineMaxY = ts->m_stringGlyphsMaxY - outlineOffsetY; uint8_t foregroundRgba[4]; annotationText.getLineColorRGBA(foregroundRgba); drawOutline(ts->m_stringGlyphsMinX, ts->m_stringGlyphsMaxX, ts->m_stringGlyphsMinY, ts->m_stringGlyphsMaxY, - z, //0.0, // Z + z, textStringGroup.m_outlineThickness, foregroundRgba); @@ -577,7 +574,6 @@ FtglFontTextRenderer::drawOutline(const double minX, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); -// const float halfThickness = outlineThickness / 2.0; float bottomLeft[3] = { minX, minY, z }; float bottomRight[3] = { maxX, minY, z }; float topRight[3] = { maxX, maxY, z }; @@ -590,18 +586,6 @@ FtglFontTextRenderer::drawOutline(const double minX, underlineCoords.insert(underlineCoords.end(), bottomRight, bottomRight + 3); underlineCoords.insert(underlineCoords.end(), topRight, topRight + 3); underlineCoords.insert(underlineCoords.end(), topLeft, topLeft + 3); -// underlineCoords.insert(underlineCoords.end(), minX); -// underlineCoords.insert(underlineCoords.end(), minY); -// underlineCoords.insert(underlineCoords.end(), z); -// underlineCoords.insert(underlineCoords.end(), maxX); -// underlineCoords.insert(underlineCoords.end(), minY); -// underlineCoords.insert(underlineCoords.end(), z); -// underlineCoords.insert(underlineCoords.end(), maxX); -// underlineCoords.insert(underlineCoords.end(), maxY); -// underlineCoords.insert(underlineCoords.end(), z); -// underlineCoords.insert(underlineCoords.end(), minX); -// underlineCoords.insert(underlineCoords.end(), maxY); -// underlineCoords.insert(underlineCoords.end(), z); BrainOpenGLPrimitiveDrawing::drawLineLoop(underlineCoords, foregroundRgba, @@ -763,7 +747,7 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth viewportZ, annotationText.getRotationAngle(), lineThicknessForViewportHeight); - //tsg.print(); + /* tsg.print(); */ drawTextAtViewportCoordinatesInternal(annotationText, tsg); } @@ -1418,10 +1402,6 @@ m_stringGlyphsMaxY(0.0) * and https://en.wikipedia.org/wiki/Serif */ advanceValue = font->Advance(theWideCharStr.c_str(), 1); -// const std::wstring nextWideCharStr = textString.mid(i + 1, 1).toStdWString(); -// const wchar_t nextWideChar = nextWideCharStr.at(0); -// advanceValue = font->Advance(theWideChar, -// nextWideChar); } TextCharacter* tc = new TextCharacter(theWideChar, @@ -1728,6 +1708,14 @@ m_viewportBoundsMaxY(0.0) #ifdef HAVE_FREETYPE CaretAssert(font); + if (annotationText.getText().isEmpty()) { + m_viewportBoundsMinX = m_viewportX; + m_viewportBoundsMaxX = m_viewportY; + m_viewportBoundsMinY = m_viewportX; + m_viewportBoundsMaxY = m_viewportY; + return; + } + /* * The underline for text is scaled with the size of the font * Underline is drawn anytime thickness is greater than zero @@ -1750,7 +1738,6 @@ m_viewportBoundsMaxY(0.0) if (outlineThickness > 0.0) { m_outlineThickness = m_lineThicknessForViewportHeight; } - //m_outlineThickness = m_annotationText.getLineWidth(); } } @@ -1957,7 +1944,7 @@ FtglFontTextRenderer::TextStringGroup::initializeTextPositions() const double offsetY1 = prevTextString->m_stringGlyphsMinY; const double offsetY2 = -(s_textMarginSize * 2.0); const double offsetY3 = -textString->m_stringGlyphsMaxY; - const double offsetY4 = 0.0; //-m_underlineThickness; + const double offsetY4 = 0.0; const double offsetY = (offsetY1 + offsetY2 + offsetY3 + offsetY4); y += offsetY; -- GitLab From 56ef1c2f9ae86e7f236cefa1037a7a57e3145a07 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 25 Jul 2017 10:27:56 -0500 Subject: [PATCH 327/755] Fixed bug that made all text annotations from blank when loaded from a scene. Problem was caused by saving to scene code added to AnnotationText for chart axis labels. Saving of text annotation attributes to a scene is now controlled by an annotation property (on for chart axis labels and off for all other text annotation types). --- src/Annotations/Annotation.cxx | 31 ++++---- src/Annotations/Annotation.h | 6 ++ src/Annotations/AnnotationBox.cxx | 4 + src/Annotations/AnnotationColorBar.cxx | 32 ++++---- src/Annotations/AnnotationImage.cxx | 2 + src/Annotations/AnnotationLine.cxx | 2 + .../AnnotationOneDimensionalShape.cxx | 8 ++ src/Annotations/AnnotationOval.cxx | 2 + src/Annotations/AnnotationText.cxx | 76 +++++++++++-------- src/Annotations/AnnotationText.h | 2 +- .../AnnotationTwoDimensionalShape.cxx | 2 +- src/Files/ChartableTwoFileBaseChart.cxx | 13 ++-- 12 files changed, 113 insertions(+), 67 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 5ded4474c..c31edeb4a 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -140,6 +140,8 @@ Annotation::copyHelperAnnotation(const Annotation& obj) m_customColorLine[2] = obj.m_customColorLine[2]; m_customColorLine[3] = obj.m_customColorLine[3]; + m_properties = obj.m_properties; + *m_displayGroupAndTabItemHelper = *obj.m_displayGroupAndTabItemHelper; /* @@ -515,6 +517,12 @@ Annotation::initializeAnnotationMembers() } } + initializeProperties(); + + if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { + initializePropertiesForViewportSpaceAnnotation(); + } + /* * Note: The 'const' members are not saved to the scene as they * are set by constructor. @@ -528,7 +536,7 @@ Annotation::initializeAnnotationMembers() m_sceneAssistant->add("m_displayGroupAndTabItemHelper", "DisplayGroupAndTabItemHelper", m_displayGroupAndTabItemHelper); - if (m_type == AnnotationTypeEnum::COLOR_BAR) { + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { m_sceneAssistant->add("m_coordinateSpace", &m_coordinateSpace); m_sceneAssistant->add("m_colorBackground", @@ -539,12 +547,6 @@ Annotation::initializeAnnotationMembers() &m_colorLine); m_sceneAssistant->addArray("m_customColorLine", m_customColorLine, 4, 0.0); } - - initializeProperties(); - - if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { - initializePropertiesForViewportSpaceAnnotation(); - } } @@ -1122,6 +1124,8 @@ Annotation::initializeProperties() setProperty(Property::TEXT_FONT_STYLE, textFlag); setProperty(Property::TEXT_ORIENTATION, textFlag); + resetProperty(Property::SCENE_CONTAINS_ATTRIBUTES); + /* * These are not valid properties */ @@ -1139,8 +1143,9 @@ Annotation::initializeProperties() resetProperty(Property::ROTATION); resetProperty(Property::TEXT_COLOR); resetProperty(Property::TEXT_EDIT); + + setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } - } /** @@ -1164,6 +1169,8 @@ Annotation::setPropertiesForChartAxisTitle() resetProperty(Property::TEXT_ALIGNMENT); resetProperty(Property::TEXT_COLOR); resetProperty(Property::TEXT_ORIENTATION); + + setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } /** @@ -1181,6 +1188,8 @@ Annotation::initializePropertiesForViewportSpaceAnnotation() resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::ROTATION); + + setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } @@ -1209,12 +1218,6 @@ Annotation::testProperty(const Property property) const return false; } -// if (property == Property::TEXT_COLOR) { -// if (m_type == AnnotationTypeEnum::TEXT) { -// return false; -// } -// } - const int32_t propertyIndex = static_cast::type>(property); return m_properties.test(propertyIndex); diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index 7a5487340..225d98f46 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -70,6 +70,12 @@ namespace caret { LINE_THICKNESS, /** Annotation can be rotated by user */ ROTATION, + /** + * Annotation's attributes are saved to and restored from scene. + * Typically used for special annotation that are saved to a scene + * and NOT saved in a file. + */ + SCENE_CONTAINS_ATTRIBUTES, /** Annotation is selectable */ SELECT, /** Annotation has alignment of text */ diff --git a/src/Annotations/AnnotationBox.cxx b/src/Annotations/AnnotationBox.cxx index 581e72181..aabc052a0 100644 --- a/src/Annotations/AnnotationBox.cxx +++ b/src/Annotations/AnnotationBox.cxx @@ -93,6 +93,10 @@ void AnnotationBox::initializeMembersAnnotationBox() { m_sceneAssistant.grabNew(new SceneClassAssistant()); + + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + + } } /** diff --git a/src/Annotations/AnnotationColorBar.cxx b/src/Annotations/AnnotationColorBar.cxx index ff754ca1d..1154148d3 100644 --- a/src/Annotations/AnnotationColorBar.cxx +++ b/src/Annotations/AnnotationColorBar.cxx @@ -54,21 +54,23 @@ AnnotationFontAttributesInterface() reset(); m_sceneAssistant.grabNew(new SceneClassAssistant()); - m_sceneAssistant->add("m_fontName", - &m_fontName); - m_sceneAssistant->add("m_fontPercentViewportHeight", - &m_fontPercentViewportHeight); - m_sceneAssistant->add("m_positionMode", - &m_positionMode); - m_sceneAssistant->add("m_displayedFlag", - &m_displayedFlag); - - m_sceneAssistant->add("m_showTickMarksSelected", - &m_showTickMarksSelected); - m_sceneAssistant->add("m_colorText", - &m_colorText); - m_sceneAssistant->addArray("m_customColorText", - m_customColorText, 4, 1.0); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + m_sceneAssistant->add("m_fontName", + &m_fontName); + m_sceneAssistant->add("m_fontPercentViewportHeight", + &m_fontPercentViewportHeight); + m_sceneAssistant->add("m_positionMode", + &m_positionMode); + m_sceneAssistant->add("m_displayedFlag", + &m_displayedFlag); + + m_sceneAssistant->add("m_showTickMarksSelected", + &m_showTickMarksSelected); + m_sceneAssistant->add("m_colorText", + &m_colorText); + m_sceneAssistant->addArray("m_customColorText", + m_customColorText, 4, 1.0); + } } /** diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index 483530682..11f967d75 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -186,6 +186,8 @@ AnnotationImage::initializeMembersAnnotationImage() m_imageHeight = 0; m_sceneAssistant = new SceneClassAssistant(); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + } } /** diff --git a/src/Annotations/AnnotationLine.cxx b/src/Annotations/AnnotationLine.cxx index b6fa40d08..f4557e234 100644 --- a/src/Annotations/AnnotationLine.cxx +++ b/src/Annotations/AnnotationLine.cxx @@ -117,6 +117,8 @@ AnnotationLine::initializeMembersAnnotationLine() m_sceneAssistant.grabNew(new SceneClassAssistant()); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + } } /** diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index 99da13564..f7bb1328d 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -116,6 +116,14 @@ AnnotationOneDimensionalShape::initializeMembersAnnotationOneDimensionalShape() m_endCoordinate.grabNew(new AnnotationCoordinate()); m_sceneAssistant.grabNew(new SceneClassAssistant()); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + m_sceneAssistant->add("m_startCoordinate", + "AnnotationCoordinate", + m_startCoordinate); + m_sceneAssistant->add("m_endCoordinate", + "AnnotationCoordinate", + m_endCoordinate); + } } /** diff --git a/src/Annotations/AnnotationOval.cxx b/src/Annotations/AnnotationOval.cxx index 490118ea7..f8c9212e5 100644 --- a/src/Annotations/AnnotationOval.cxx +++ b/src/Annotations/AnnotationOval.cxx @@ -104,6 +104,8 @@ void AnnotationOval::initializeMembersAnnotationOval() { m_sceneAssistant.grabNew(new SceneClassAssistant()); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + } } /** diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index af16b8ca1..59beaa572 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -163,32 +163,35 @@ AnnotationText::initializeAnnotationTextMembers() m_text = ""; - m_sceneAssistant.grabNew(new SceneClassAssistant()); - m_sceneAssistant->add("m_alignmentHorizontal", - &m_alignmentHorizontal); - m_sceneAssistant->add("m_alignmentVertical", - &m_alignmentVertical); - m_sceneAssistant->add("m_font", - &m_font); - m_sceneAssistant->add("m_fontPointSize", - &m_fontPointSize); - m_sceneAssistant->add("m_orientation", - &m_orientation); - m_sceneAssistant->add("m_colorText", - &m_colorText); - m_sceneAssistant->addArray("m_customColorText", m_customColorText, 4, 1.0); - m_sceneAssistant->add("m_boldEnabled", - &m_boldEnabled); - m_sceneAssistant->add("m_italicEnabled", - &m_italicEnabled); - m_sceneAssistant->add("m_underlineEnabled", - &m_underlineEnabled); - m_sceneAssistant->add("m_connectToBrainordinate", - &m_connectToBrainordinate); - m_sceneAssistant->add("m_fontPercentViewportSize", - &m_fontPercentViewportSize); - m_sceneAssistant->add("m_text", - &m_text); + /* + * Assists with attributes that may be saved to scene (controlled by annotation property). + */ + m_attributesAssistant.grabNew(new SceneClassAssistant()); + m_attributesAssistant->add("m_alignmentHorizontal", + &m_alignmentHorizontal); + m_attributesAssistant->add("m_alignmentVertical", + &m_alignmentVertical); + m_attributesAssistant->add("m_font", + &m_font); + m_attributesAssistant->add("m_fontPointSize", + &m_fontPointSize); + m_attributesAssistant->add("m_orientation", + &m_orientation); + m_attributesAssistant->add("m_colorText", + &m_colorText); + m_attributesAssistant->addArray("m_customColorText", m_customColorText, 4, 1.0); + m_attributesAssistant->add("m_boldEnabled", + &m_boldEnabled); + m_attributesAssistant->add("m_italicEnabled", + &m_italicEnabled); + m_attributesAssistant->add("m_underlineEnabled", + &m_underlineEnabled); + m_attributesAssistant->add("m_connectToBrainordinate", + &m_connectToBrainordinate); + m_attributesAssistant->add("m_fontPercentViewportSize", + &m_fontPercentViewportSize); + m_attributesAssistant->add("m_text", + &m_text); } /** @@ -946,8 +949,11 @@ AnnotationText::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); - m_sceneAssistant->saveMembers(sceneAttributes, - sceneClass); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + sceneClass->addBoolean("hasAttributesFlag", true); + m_attributesAssistant->saveMembers(sceneAttributes, + sceneClass); + } } /** @@ -968,8 +974,18 @@ AnnotationText::restoreSubClassDataFromScene(const SceneAttributes* sceneAttribu { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); - m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + /* + * This flag will tell us if the scene has attributes. + * If this test was not performed and attributes were not in scene + * members in the atttributes assistant would overwrite initialized + * values with invalid values. + */ + if (sceneClass->getBooleanValue("hasAttributesFlag")) { + m_attributesAssistant->restoreMembers(sceneAttributes, + sceneClass); + } + } } /** diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index 77917bfac..f284eeb2f 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -183,7 +183,7 @@ namespace caret { /* Not saved to scene since it is set by sub-class constructor. */ const AnnotationTextFontSizeTypeEnum::Enum m_fontSizeType; - CaretPointer m_sceneAssistant; + CaretPointer m_attributesAssistant; AString m_text; diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 6891d080b..a014b7415 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -135,7 +135,7 @@ AnnotationTwoDimensionalShape::initializeMembersAnnotationTwoDimensionalShape() m_sceneAssistant.grabNew(new SceneClassAssistant()); - if (getType() == AnnotationTypeEnum::COLOR_BAR) { + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { /* * Saves/restores color bar manual position and size mode. */ diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 829600987..11037fb2b 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -77,8 +77,13 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) m_bottomAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); + m_bottomAxisTitle->setPropertiesForChartAxisTitle(); m_leftRightAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); + m_leftRightAxisTitle->setPropertiesForChartAxisTitle(); + + initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_bottomAxisTitle", @@ -88,12 +93,6 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) "AnnotationPercentSizeText", m_leftRightAxisTitle.get()); - initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); - initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); - - m_bottomAxisTitle->setPropertiesForChartAxisTitle(); - m_leftRightAxisTitle->setPropertiesForChartAxisTitle(); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); } @@ -185,6 +184,7 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + { switch (m_chartType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -197,6 +197,7 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } + } break; } -- GitLab From 89f9182b83fae0baef521e34499c5ac055184788 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 25 Jul 2017 11:31:52 -0500 Subject: [PATCH 328/755] Changed "Axis Title" to "Axis Label". Added checkbox to turn label on/off. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 148 +++++++++--------- src/Brain/ChartTwoOverlaySet.cxx | 2 +- src/Charting/ChartTwoCartesianAxis.cxx | 38 ++++- src/Charting/ChartTwoCartesianAxis.h | 11 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 77 +++++---- .../BrainBrowserWindowToolBarChartTwoAxes.h | 8 +- 6 files changed, 167 insertions(+), 117 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index ba41af9b4..b6058a5a0 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1302,25 +1302,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH break; } - double labelWidth = 0.0; - double labelHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(*chartAxisLabel, viewportWidth, viewportHeight, labelWidth, labelHeight); - - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += labelHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += labelHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += labelHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += labelHeight; - break; + if (cartesianAxis->isShowLabel()) { + double labelWidth = 0.0; + double labelHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*chartAxisLabel, viewportWidth, viewportHeight, labelWidth, labelHeight); + + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + heightOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + /** Text is rotated 90 degrees so use HEIGHT */ + widthOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + /** Text is rotated 90 degrees so use HEIGHT */ + widthOut += labelHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + heightOut += labelHeight; + break; + } } } @@ -1648,61 +1650,63 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini drawPrimitivePrivate(ticksData.get()); - if (chartAxisLabel != NULL) { - const AString axisTitle = chartAxisLabel->getText(); - if ( ! axisTitle.isEmpty()) { - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - - float labelTabX = axisVpWidth / 2.0; - float labelTabY = axisVpHeight / 2.0; - const float textMarginOffset = 5.0; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - labelTabX = (axisVpWidth / 2.0) + margins.m_left; - labelTabY = textMarginOffset; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - chartAxisLabel->setRotationAngle(0.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - labelTabX = (axisVpWidth / 2.0) + margins.m_left; - labelTabY = tabViewportHeight - textMarginOffset; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setRotationAngle(0.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - labelTabX = textMarginOffset; - labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - labelTabX = tabViewportWidth - textMarginOffset; - labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setRotationAngle(90.0); - break; - } - - if ((axisVpWidth > 0.0) - && (axisVpHeight > 0.0)) { - chartAxisLabel->setCustomTextColor(rgba); - chartAxisLabel->setTextColor(CaretColorEnum::CUSTOM); - chartAxisLabel->setTabIndex(m_tabIndex); - chartAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; - const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; - chartAxisLabel->getCoordinate()->setXYZ(tabPercentageX, - tabPercentageY, - 0.0f); + if (axis->isShowLabel()) { + if (chartAxisLabel != NULL) { + const AString axisTitle = chartAxisLabel->getText(); + if ( ! axisTitle.isEmpty()) { + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + + float labelTabX = axisVpWidth / 2.0; + float labelTabY = axisVpHeight / 2.0; + const float textMarginOffset = 5.0; + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + labelTabX = (axisVpWidth / 2.0) + margins.m_left; + labelTabY = textMarginOffset; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + chartAxisLabel->setRotationAngle(0.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + labelTabX = (axisVpWidth / 2.0) + margins.m_left; + labelTabY = tabViewportHeight - textMarginOffset; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setRotationAngle(0.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + labelTabX = textMarginOffset; + labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setRotationAngle(-90.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + labelTabX = tabViewportWidth - textMarginOffset; + labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; + chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartAxisLabel->setRotationAngle(90.0); + break; + } + + if ((axisVpWidth > 0.0) + && (axisVpHeight > 0.0)) { + chartAxisLabel->setCustomTextColor(rgba); + chartAxisLabel->setTextColor(CaretColorEnum::CUSTOM); + chartAxisLabel->setTabIndex(m_tabIndex); + chartAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; + const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; + chartAxisLabel->getCoordinate()->setXYZ(tabPercentageX, + tabPercentageY, + 0.0f); + + m_annotationsForDrawingOutput.push_back(chartAxisLabel); + } - m_annotationsForDrawingOutput.push_back(chartAxisLabel); } - } } diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 50baf48e0..cf0d0a6e0 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -795,7 +795,7 @@ ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const { AnnotationPercentSizeText* label = NULL; - const int32_t overlayTitleIndex = axis->getTitleOverlayIndex(m_numberOfDisplayedOverlays); + const int32_t overlayTitleIndex = axis->getLabelOverlayIndex(m_numberOfDisplayedOverlays); const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); CaretMappableDataFile* mapFile = chartOverlay->getSelectedMapFile(); if (mapFile != NULL) { diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 0af8d1d2d..501cb49a2 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -59,6 +59,9 @@ m_axisLocation(axisLocation) m_rangeMinimumValue = -std::numeric_limits::max(); m_rangeMaximumValue = std::numeric_limits::max(); + m_showTickmarks = true; + m_showLabel = true; + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_displayedByUser", &m_displayedByUser); @@ -85,6 +88,8 @@ m_axisLocation(axisLocation) &m_enabledByChart); m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); + m_sceneAssistant->add("m_showLabel", + &m_showLabel); m_sceneAssistant->add("m_titleOverlayIndex", &m_titleOverlayIndex); } @@ -151,6 +156,7 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_enabledByChart = obj.m_enabledByChart; m_showTickmarks = obj.m_showTickmarks; + m_showLabel = obj.m_showLabel; limitUserScaleMinMaxToValidRange(); } @@ -375,6 +381,26 @@ ChartTwoCartesianAxis::setShowTickmarks(const bool showTickmarks) m_showTickmarks = showTickmarks; } +/** + * @return show axis label + */ +bool +ChartTwoCartesianAxis::isShowLabel() const +{ + return m_showLabel; +} + +/** + * Set show axis label + * @param showLabel + * New value for show axis label + */ +void +ChartTwoCartesianAxis::setShowLabel(const bool showLabel) +{ + m_showLabel = showLabel; +} + /** * @return Scale Range Mode */ @@ -449,13 +475,13 @@ ChartTwoCartesianAxis::toString() const } /** - * @return Index of overlay that supplies the title. + * @return Index of overlay that supplies the label. * * @param maximumNumberOfOverlays * Maximum number of allowable overlays. */ int32_t -ChartTwoCartesianAxis::getTitleOverlayIndex(const int32_t maximumNumberOfOverlays) const +ChartTwoCartesianAxis::getLabelOverlayIndex(const int32_t maximumNumberOfOverlays) const { if (m_titleOverlayIndex < 0) { m_titleOverlayIndex = 0; @@ -470,13 +496,13 @@ ChartTwoCartesianAxis::getTitleOverlayIndex(const int32_t maximumNumberOfOverlay /** * Set the index of the overlay that supplies the title. * - * @param titleOverlayIndex - * New value for title overlay index. + * @param labelOverlayIndex + * New value for label overlay index. */ void -ChartTwoCartesianAxis::setTitleOverlayIndex(const int32_t titleOverlayIndex) +ChartTwoCartesianAxis::setLabelOverlayIndex(const int32_t labelOverlayIndex) { - m_titleOverlayIndex = titleOverlayIndex; + m_titleOverlayIndex = labelOverlayIndex; } /** diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 0a186b2ac..278e59444 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -98,6 +98,10 @@ namespace caret { void setShowTickmarks(const bool showTickmarks); + bool isShowLabel() const; + + void setShowLabel(const bool showLabel); + bool getScaleValuesAndOffsets(const float minimumDataValue, const float maximumDataValue, const float axisLengthInPixels, @@ -106,9 +110,9 @@ namespace caret { std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; - int32_t getTitleOverlayIndex(const int32_t maximumNumberOfOverlays) const; + int32_t getLabelOverlayIndex(const int32_t maximumNumberOfOverlays) const; - void setTitleOverlayIndex(const int32_t titleOverlayIndex); + void setLabelOverlayIndex(const int32_t labelOverlayIndex); // ADD_NEW_METHODS_HERE @@ -182,6 +186,9 @@ namespace caret { bool m_showTickmarks = true; + /** show axis label*/ + bool m_showLabel; + /** user display the axis*/ bool m_displayedByUser = true; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 2d266f9cb..b40b4556b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -93,12 +93,12 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra /* * Controls for axis parameters */ - m_axisNameToolButton = new QToolButton(); - m_axisNameToolButton->setText("Edit Title..."); - QObject::connect(m_axisNameToolButton, &QToolButton::clicked, - this, &BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked); - WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisNameToolButton); - m_axisNameToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); + m_axisLabelToolButton = new QToolButton(); + m_axisLabelToolButton->setText("Edit Label..."); + QObject::connect(m_axisLabelToolButton, &QToolButton::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisLabelToolButton); + m_axisLabelToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); m_autoUserRangeComboBox->setup(); @@ -122,10 +122,15 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); - QLabel* axisTitleFromOverlayLabel = new QLabel("Title From File In"); - m_axisTitleFromOverlayComboBox = new QComboBox(); - m_axisTitleFromOverlayComboBox->setToolTip("Title for axis is from file in selected layer"); - QObject::connect(m_axisTitleFromOverlayComboBox, static_cast(&QComboBox::activated), + m_showLabelCheckBox = new QCheckBox("Show Label"); + QObject::connect(m_showLabelCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_showLabelCheckBox->setToolTip("Show label on axis"); + + QLabel* axisLabelFromOverlayLabel = new QLabel("Label From File In"); + m_axisLabelFromOverlayComboBox = new QComboBox(); + m_axisLabelFromOverlayComboBox->setToolTip("Label for axis is from file in selected layer"); + QObject::connect(m_axisLabelFromOverlayComboBox, static_cast(&QComboBox::activated), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userNumericFormatComboBox = new EnumComboBoxTemplate(this); @@ -156,12 +161,13 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_axisComboBox); m_widgetGroup->add(m_axisDisplayedByUserCheckBox); - m_widgetGroup->add(m_axisNameToolButton); + m_widgetGroup->add(m_axisLabelToolButton); m_widgetGroup->add(m_autoUserRangeComboBox->getWidget()); m_widgetGroup->add(m_userMinimumValueSpinBox); m_widgetGroup->add(m_userMaximumValueSpinBox); m_widgetGroup->add(m_showTickMarksCheckBox); - m_widgetGroup->add(m_axisTitleFromOverlayComboBox); + m_widgetGroup->add(m_showLabelCheckBox); + m_widgetGroup->add(m_axisLabelFromOverlayComboBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); m_widgetGroup->add(m_numericSubdivisionsModeComboBox->getWidget()); @@ -175,6 +181,8 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra int32_t axisRow = 0; showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); axisRow++; + showLayout->addWidget(m_showLabelCheckBox, axisRow, 0); + axisRow++; showLayout->addWidget(m_showTickMarksCheckBox, axisRow, 0); axisRow++; showWidget->setSizePolicy(showWidget->sizePolicy().horizontalPolicy(), @@ -228,10 +236,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra topLayout->addWidget(m_axisComboBox->getWidget()); topLayout->addSpacing(10); topLayout->addStretch(); - topLayout->addWidget(axisTitleFromOverlayLabel); - topLayout->addWidget(m_axisTitleFromOverlayComboBox); + topLayout->addWidget(axisLabelFromOverlayLabel); + topLayout->addWidget(m_axisLabelFromOverlayComboBox); topLayout->addSpacing(10); - topLayout->addWidget(m_axisNameToolButton); + topLayout->addWidget(m_axisLabelToolButton); /* * Grid layout containing layouts @@ -454,6 +462,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); + m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); @@ -463,20 +472,20 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); - int32_t selectedOverlayIndex = m_chartAxis->getTitleOverlayIndex(overlayCount); - const int32_t comboBoxCount = m_axisTitleFromOverlayComboBox->count(); + int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); + const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); if (overlayCount < comboBoxCount) { - m_axisTitleFromOverlayComboBox->setMaxCount(overlayCount); + m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); } else if (overlayCount > comboBoxCount) { for (int32_t j = comboBoxCount; j < overlayCount; j++) { - m_axisTitleFromOverlayComboBox->addItem("Layer " + AString::number(j + 1)); + m_axisLabelFromOverlayComboBox->addItem("Layer " + AString::number(j + 1)); } } if ((selectedOverlayIndex >= 0) - && (selectedOverlayIndex < m_axisTitleFromOverlayComboBox->count())) { - m_axisTitleFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); + && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { + m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); } setEnabled(true); } @@ -513,6 +522,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartO m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); + m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); @@ -522,20 +532,20 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartO m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); - int32_t selectedOverlayIndex = m_chartAxis->getTitleOverlayIndex(overlayCount); - const int32_t comboBoxCount = m_axisTitleFromOverlayComboBox->count(); + int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); + const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); if (overlayCount < comboBoxCount) { - m_axisTitleFromOverlayComboBox->setMaxCount(overlayCount); + m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); } else if (overlayCount > comboBoxCount) { for (int32_t j = comboBoxCount; j < overlayCount; j++) { - m_axisTitleFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); + m_axisLabelFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); } } if ((selectedOverlayIndex >= 0) - && (selectedOverlayIndex < m_axisTitleFromOverlayComboBox->count())) { - m_axisTitleFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); + && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { + m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); } m_widgetGroup->blockAllSignals(false); @@ -550,12 +560,13 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() { CaretAssert(m_chartAxis); if (m_chartAxis != NULL) { - m_chartAxis->setTitleOverlayIndex(m_axisTitleFromOverlayComboBox->currentIndex()); + m_chartAxis->setLabelOverlayIndex(m_axisLabelFromOverlayComboBox->currentIndex()); m_chartAxis->setDisplayedByUser(m_axisDisplayedByUserCheckBox->isChecked()); m_chartAxis->setScaleRangeMode(m_autoUserRangeComboBox->getSelectedItem()); m_chartAxis->setUserScaleMinimumValue(m_userMinimumValueSpinBox->value()); m_chartAxis->setUserScaleMaximumValue(m_userMaximumValueSpinBox->value()); m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); + m_chartAxis->setShowLabel(m_showLabelCheckBox->isChecked()); m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); @@ -684,10 +695,10 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt(int) } /** - * Called when name toolbutton is clicked to change axis name. + * Called when name toolbutton is clicked to change axis label. */ void -BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) +BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked(bool) { ChartTwoOverlaySet* chartOverlaySet = NULL; std::vector validAxesLocations; @@ -701,9 +712,9 @@ BrainBrowserWindowToolBarChartTwoAxes::axisNameToolButtonClicked(bool) axisLabel); if (axisLabel != NULL) { - WuQDataEntryDialog newNameDialog("Axis Title", - m_axisNameToolButton); - QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Axis Name"); + WuQDataEntryDialog newNameDialog("Axis Label", + m_axisLabelToolButton); + QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); lineEdit->setText(axisLabel->getText()); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 85dadadce..c5099b79a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -70,7 +70,7 @@ namespace caret { void axisMaximumValueChanged(double); - void axisNameToolButtonClicked(bool); + void axisLabelToolButtonClicked(bool); private: BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); @@ -98,9 +98,9 @@ namespace caret { EnumComboBoxTemplate* m_axisComboBox; - QToolButton* m_axisNameToolButton; + QToolButton* m_axisLabelToolButton; - QComboBox* m_axisTitleFromOverlayComboBox; + QComboBox* m_axisLabelFromOverlayComboBox; EnumComboBoxTemplate* m_autoUserRangeComboBox; @@ -110,6 +110,8 @@ namespace caret { QCheckBox* m_showTickMarksCheckBox; + QCheckBox* m_showLabelCheckBox; + EnumComboBoxTemplate* m_userNumericFormatComboBox; QSpinBox* m_userDigitsRightOfDecimalSpinBox; -- GitLab From f321a0788108371e8bde2de21c4dcd55d323f682 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 25 Jul 2017 12:29:28 -0500 Subject: [PATCH 329/755] Replace special case methods for setting annotations properties to a more generic one that accepts an enumerated type identifying the specialized usage. --- src/Annotations/Annotation.cxx | 84 ++++++++++++++----------- src/Annotations/Annotation.h | 11 +++- src/Files/ChartableTwoFileBaseChart.cxx | 6 +- 3 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index c31edeb4a..d778399a2 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -520,7 +520,7 @@ Annotation::initializeAnnotationMembers() initializeProperties(); if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::VIEWPORT) { - initializePropertiesForViewportSpaceAnnotation(); + setPropertiesForSpecializedUsage(PropertiesSpecializedUsage::VIEWPORT_ANNOTATION); } /* @@ -1149,50 +1149,62 @@ Annotation::initializeProperties() } /** - * Set the properties for a chart axis label. - * Chart axis labels are text annotations but have limited editing and other properties. + * Set the properties for specialized usage of annotations. This is typically used + * for annotations that are not stored in an annotation file but instead are a + * property of some entity (such as chart labels). + * + * @param specializedUsage + * The specialized usage. */ void -Annotation::setPropertiesForChartAxisTitle() +Annotation::setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage specializedUsage) { initializeProperties(); - - resetProperty(Property::ARRANGE); - resetProperty(Property::COORDINATE); - resetProperty(Property::COPY_CUT_PASTE); - resetProperty(Property::DELETE); - resetProperty(Property::DISPLAY_GROUP); - resetProperty(Property::GROUP); - resetProperty(Property::LINE_COLOR); - resetProperty(Property::LINE_THICKNESS); - resetProperty(Property::ROTATION); - resetProperty(Property::TEXT_ALIGNMENT); - resetProperty(Property::TEXT_COLOR); - resetProperty(Property::TEXT_ORIENTATION); - setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); -} - -/** - * Set the properties for an annotation in viewport coordinate space. - */ -void -Annotation::initializePropertiesForViewportSpaceAnnotation() -{ - initializeProperties(); + bool chartLabelTitleFlag = false; + bool viewportFlag = false; + switch (specializedUsage) { + case PropertiesSpecializedUsage::CHART_LABEL: + chartLabelTitleFlag = true; + break; + case PropertiesSpecializedUsage::CHART_TITLE: + chartLabelTitleFlag = true; + break; + case PropertiesSpecializedUsage::VIEWPORT_ANNOTATION: + viewportFlag = true; + break; + } - resetProperty(Property::ARRANGE); - resetProperty(Property::COORDINATE); - resetProperty(Property::COPY_CUT_PASTE); - resetProperty(Property::DELETE); - resetProperty(Property::DISPLAY_GROUP); - resetProperty(Property::GROUP); - resetProperty(Property::ROTATION); + if (chartLabelTitleFlag) { + resetProperty(Property::ARRANGE); + resetProperty(Property::COORDINATE); + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETE); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::LINE_COLOR); + resetProperty(Property::LINE_THICKNESS); + resetProperty(Property::ROTATION); + resetProperty(Property::TEXT_ALIGNMENT); + resetProperty(Property::TEXT_COLOR); + resetProperty(Property::TEXT_ORIENTATION); + + setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); + } - setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); + if (viewportFlag) { + resetProperty(Property::ARRANGE); + resetProperty(Property::COORDINATE); + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETE); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::ROTATION); + + setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); + } } - /** * Test a property. * diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index 225d98f46..f88679944 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -98,6 +98,13 @@ namespace caret { COUNT_FOR_BITSET }; + /** Identifies properities for specialized uses of annotations */ + enum class PropertiesSpecializedUsage { + CHART_LABEL, + CHART_TITLE, + VIEWPORT_ANNOTATION + }; + Annotation(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); @@ -125,7 +132,7 @@ namespace caret { void resetProperty(const Property property); - void setPropertiesForChartAxisTitle(); + void setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage specializedUsage); AnnotationGroupKey getAnnotationGroupKey() const; @@ -315,8 +322,6 @@ namespace caret { void initializeProperties(); - void initializePropertiesForViewportSpaceAnnotation(); - // private - AnnotationManager handles selection and allowing // public access to this method could cause improper selection status void setSelectedForEditing(const int32_t windowIndex, diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 11037fb2b..e850dbd9e 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -77,10 +77,12 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) m_bottomAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); - m_bottomAxisTitle->setPropertiesForChartAxisTitle(); + m_bottomAxisTitle->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); + m_leftRightAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); - m_leftRightAxisTitle->setPropertiesForChartAxisTitle(); + m_leftRightAxisTitle->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); + initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); -- GitLab From ee7ef8c1f6d66b84bb41ca8035c037ce4c9ac182 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 25 Jul 2017 15:27:25 -0500 Subject: [PATCH 330/755] When compiled debug, all items in a scene are monitored to verify if they are restored and scene items not restored are logged. A scene item (surface name without path) in SurfaceSelectionModel was being logged as not restored due to another scene item (surface name with path) having priority. Now the surface name with path is always restored to prevent the logged message. --- src/Brain/SurfaceSelectionModel.cxx | 44 +++++++++++++++++------------ src/GuiQt/SceneDialog.cxx | 15 ++++++---- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/Brain/SurfaceSelectionModel.cxx b/src/Brain/SurfaceSelectionModel.cxx index 5a49aa43f..57add87ca 100644 --- a/src/Brain/SurfaceSelectionModel.cxx +++ b/src/Brain/SurfaceSelectionModel.cxx @@ -428,38 +428,46 @@ SurfaceSelectionModel::restoreFromScene(const SceneAttributes* /*sceneAttributes * computers the full path may change the parts of the path nearest the * name of the file will match. */ - Surface* nameMatchSurface = NULL; - int32_t nameMatchLength = 0; + Surface* pathNameMatchSurface = NULL; + int32_t pathNameMatchLength = 0; if ( ! surfaceFileNameFullPath.isEmpty()) { for (auto surface : allSurfaces) { const AString name = surface->getFileName(); const int32_t numMatch = name.countMatchingCharactersFromEnd(surfaceFileNameFullPath); - if (numMatch > nameMatchLength) { - nameMatchLength = numMatch; - nameMatchSurface = surface; + if (numMatch > pathNameMatchLength) { + pathNameMatchLength = numMatch; + pathNameMatchSurface = surface; } } } - if (nameMatchSurface == NULL) { - /* - * Match name of file with NO path - */ - const AString& surfaceFileName = sceneClass->getStringValue("m_selectedSurface", - ""); - if ( ! surfaceFileName.isEmpty()) { - for (auto surface : allSurfaces) { - if (surface->getFileNameNoPath() == surfaceFileName) { - nameMatchSurface = surface; - break; - } + /* + * Match name of file with NO path + * Always restore this so that the object is marked as restored + * (within the 'get' method). Otherwise if compiled debug, this + * object will get logged as 'not restored'. + */ + Surface* nameMatchSurface = NULL; + const AString& surfaceFileName = sceneClass->getStringValue("m_selectedSurface", + ""); + if ( ! surfaceFileName.isEmpty()) { + for (auto surface : allSurfaces) { + if (surface->getFileNameNoPath() == surfaceFileName) { + nameMatchSurface = surface; + break; } } } - if (nameMatchSurface != NULL) { + if (pathNameMatchSurface != NULL) { + setSurface(pathNameMatchSurface); + } + else if (nameMatchSurface != NULL) { setSurface(nameMatchSurface); } + else { + setSurface(NULL); + } } diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 9eeae4e2f..a140c786e 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2417,13 +2417,20 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, return false; } - bool debugLoggingFlag = true; + /* + * When compiled in debug mode, log any SceneObject and + * subclasses that fail to restore + */ + bool logObjectFailedToRestoreFlag = true; +#ifdef NDEBUG + logObjectFailedToRestoreFlag = false; +#endif // NDEBUG std::vector allSceneObjects; - if (debugLoggingFlag) { + if (logObjectFailedToRestoreFlag) { allSceneObjects = scene->getDescendants(); } - SceneClass::setDebugLoggingEnabled(debugLoggingFlag); + SceneClass::setDebugLoggingEnabled(logObjectFailedToRestoreFlag); /* * Show the wait cursor @@ -2452,12 +2459,10 @@ SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, guiManagerClass); guiManagerClass->setRestored(true); -#ifndef NDEBUG if ( ! allSceneObjects.empty()) { SceneObject::logObjectsFailedRestore(scene->getName(), allSceneObjects); } -#endif // NDEBUG SceneClass::setDebugLoggingEnabled(false); -- GitLab From f3c62a84b6edf6bc19af713283b3b8a3e5967fbf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 26 Jul 2017 11:07:17 -0500 Subject: [PATCH 331/755] Added a title to charts. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 449 +++++++++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 13 + src/Brain/ChartTwoOverlaySet.cxx | 94 ++++ src/Brain/ChartTwoOverlaySet.h | 14 + src/Files/ChartableTwoFileBaseChart.cxx | 56 +-- src/Files/ChartableTwoFileBaseChart.h | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 48 +- src/GuiQt/BrainBrowserWindowToolBar.h | 10 +- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 149 ++++++ .../BrainBrowserWindowToolBarChartTwoTitle.h | 68 +++ src/GuiQt/CMakeLists.txt | 3 + 11 files changed, 817 insertions(+), 89 deletions(-) create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index b6058a5a0..62ece084b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -492,6 +492,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } + AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); + double width = 0.0, height = 0.0; GLint vp[4]; @@ -509,12 +511,23 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + bool allowTopAxisFlag = false; + + if (m_chartOverlaySet->isChartTitleDisplayed()) { + double titleHeight = 0.0; + estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); + margins.m_top = std::max(margins.m_top, titleHeight); + } + estimateCartesianChartAxisLegendsWidthHeight(yMinLeft, yMaxLeft, tabViewportWidth, tabViewportHeight, leftAxis, leftAxisLabel, width, height); margins.m_left = std::max(margins.m_left, width); estimateCartesianChartAxisLegendsWidthHeight(yMinRight, yMaxRight, tabViewportWidth, tabViewportHeight, rightAxis, rightAxisLabel, width, height); margins.m_right = std::max(margins.m_right, width); - estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); - margins.m_top = std::max(margins.m_top, height); + if (allowTopAxisFlag) { + CaretAssertMessage(0, "For top axis, will need to make space for chart title"); + estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); + margins.m_top = std::max(margins.m_top, height); + } estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, bottomAxis, bottomAxisLabel, width, height); margins.m_bottom = std::max(margins.m_bottom, height); @@ -572,23 +585,35 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch xMax = axisMaximumValue; } - drawChartAxisCartesian(xMin, - xMax, - tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - topAxis, - NULL, - axisMinimumValue, - axisMaximumValue); + if (allowTopAxisFlag) { + drawChartAxisCartesian(xMin, + xMax, + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + margins, + topAxis, + NULL, + axisMinimumValue, + axisMaximumValue); + } + + if (m_chartOverlaySet->isChartTitleDisplayed()) { + drawChartTitle(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + margins, + chartTitle); + } drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, margins, + true, /* draw the box */ chartGraphicsDrawingViewport); } @@ -837,16 +862,202 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } +///** +// * Draw a matrix chart. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() +//{ +// glViewport(m_viewport[0], +// m_viewport[1], +// m_viewport[2], +// m_viewport[3]); +// +// bool applyTransformationsFlag = true; +// float cellWidth = 1.0; +// float cellHeight = 1.0; +// +// /* +// * Setup width/height of area in which matrix is drawn with a +// * small margin along all of the edges +// */ +// float margin = 10.0; +// if ((m_viewport[2] < (margin * 3.0)) +// || (m_viewport[3] < (margin * 3.0))) { +// margin = 0.0; +// } +// const float graphicsWidth = m_viewport[2] - (margin * 2.0); +// const float graphicsHeight = m_viewport[3] - (margin * 2.0); +// +// /* +// * First overlay is ALWAYS ON and since all matrices must have +// * same number of rows/columns, use first matrix for rows/columns +// */ +// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); +// CaretAssert(numberOfOverlays > 0); +// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); +// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); +// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); +// const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); +// const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); +// if ((numberOfRows > 0) +// && (numberOfCols > 0)) { +// cellWidth = graphicsWidth / numberOfCols; +// cellHeight = graphicsHeight / numberOfRows; +// } +// else { +// return; +// } +// +// /* +// * Set the width and neight of each matrix cell. +// */ +// const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); +// CaretAssert(matrixProperties); +// const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; +// const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; +// if ((cellWidthZoom > 0.0) +// && (cellHeightZoom > 0.0)) { +// cellWidth *= cellWidthZoom; +// cellHeight *= cellHeightZoom; +// } +// +// /* +// * Set the coordinates for the area in which the matrix is drawn. +// */ +// const float xMin = -margin; +// const float xMax = graphicsWidth + margin; +// const float yMin = -margin; +// const float yMax = graphicsHeight + margin; +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// glOrtho(xMin, xMax, +// yMin, yMax, +// -1.0, 1.0); +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = cellWidth * numberOfCols; +// const float chartHeight = cellHeight * numberOfRows; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// /* +// * Save the transformation matrices and the viewport +// * If there is more than one line chart, this code will be executed +// * several times but since the top overlay is drawn last, the contents +// * of the top overlay will be used. +// */ +// updateViewportContentForCharting(m_viewport); +// +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; +// int32_t selectedIndex = -1; +// chartOverlay->getSelectionData(mapFile, +// selectedIndexType, +// selectedIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// const ChartableTwoFileMatrixChart* matrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); +// int32_t overlayRows = 0; +// int32_t overlayColumns = 0; +// matrixChart->getMatrixDimensions(overlayRows, +// overlayColumns); +// +// /* +// * All matrices must have same rows/columns +// */ +// if ((overlayRows == numberOfRows) +// && (overlayColumns == numberOfCols)) { +// drawMatrixChartContent(matrixChart, +// chartOverlay->getMatrixTriangularViewingMode(), +// cellWidth, +// cellHeight, +// m_zooming); +// } +// } +//} + /** * Draw a matrix chart. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() { - glViewport(m_viewport[0], - m_viewport[1], - m_viewport[2], - m_viewport[3]); + const int32_t tabViewportX = m_viewport[0]; + const int32_t tabViewportY = m_viewport[1]; + const int32_t tabViewportWidth = m_viewport[2]; + const int32_t tabViewportHeight = m_viewport[3]; + + int32_t chartGraphicsDrawingViewport[4] = { + tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight + }; + + Margins margins(3); + + AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); + if (m_chartOverlaySet->isChartTitleDisplayed()) { + double titleHeight = 0.0; + estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); + if (titleHeight > 0.0) { + margins.m_top = std::max(margins.m_top, titleHeight + 2); + } + } + + glViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight); + + if (m_chartOverlaySet->isChartTitleDisplayed()) { + drawChartTitle(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + margins, + chartTitle); + } + + drawChartGraphicsBoxAndSetViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + margins, + false, /* do not draw box */ + chartGraphicsDrawingViewport); + + glViewport(chartGraphicsDrawingViewport[0], + chartGraphicsDrawingViewport[1], + chartGraphicsDrawingViewport[2], + chartGraphicsDrawingViewport[3]); bool applyTransformationsFlag = true; float cellWidth = 1.0; @@ -861,11 +1072,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() || (m_viewport[3] < (margin * 3.0))) { margin = 0.0; } - const float graphicsWidth = m_viewport[2] - (margin * 2.0); - const float graphicsHeight = m_viewport[3] - (margin * 2.0); - + const float graphicsWidth = chartGraphicsDrawingViewport[2]; + const float graphicsHeight = chartGraphicsDrawingViewport[3]; + /* - * First overlay is ALWAYS ON and since all matrices must have + * First overlay is ALWAYS ON and since all matrices must have * same number of rows/columns, use first matrix for rows/columns */ const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); @@ -900,6 +1111,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() /* * Set the coordinates for the area in which the matrix is drawn. */ + margin = 0.0; const float xMin = -margin; const float xMax = graphicsWidth + margin; const float yMin = -margin; @@ -933,14 +1145,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() -halfHeight, 0.0); } - + /* * Save the transformation matrices and the viewport * If there is more than one line chart, this code will be executed * several times but since the top overlay is drawn last, the contents * of the top overlay will be used. */ - updateViewportContentForCharting(m_viewport); + updateViewportContentForCharting(chartGraphicsDrawingViewport); for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); @@ -971,15 +1183,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() && (overlayColumns == numberOfCols)) { drawMatrixChartContent(matrixChart, chartOverlay->getMatrixTriangularViewingMode(), - cellWidth, - cellHeight, - m_zooming); + cellWidth, + cellHeight, + m_zooming); } } } - /* - * Draw a matrix chart. + * Draw a matrix chart content. * * @param matrixChart * Matrix chart that is drawn. @@ -1194,6 +1405,43 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() } +/** + * Estimate the size of the chart title + * + * @param viewportWidth + * Widgth of viewport. + * @param viewportHeight + * Height of viewport. + * @param chartTitle + * Title for the chart. + * @param heightOut + * Height of text out. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::estimateChartTitleHeight(const float viewportWidth, + const float viewportHeight, + AnnotationPercentSizeText* chartTitle, + double& heightOut) +{ + CaretAssert(chartTitle); + + heightOut = 0; + + if (chartTitle->getText().trimmed().isEmpty()) { + return; + } + + /* + * The percentage height from the label is also used + * by the axis numeric values. + */ + chartTitle->setTabIndex(m_tabIndex); + + + double dummyWidth = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*chartTitle, viewportWidth, viewportHeight, dummyWidth, heightOut); +} + /** * Estimate the size of the axis' text. * @@ -1339,17 +1587,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH * Viewport height * @param marginSize * Margin around grid/box + * @param drawBoxFlag + * Controls drawing of box. * @param chartGraphicsDrawingViewportOut * Output containing viewport for drawing chart graphics within * the box/grid that is adjusted for the box's line thickness. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, - const Margins& margins, - int32_t chartGraphicsDrawingViewportOut[4]) + const float vpY, + const float vpWidth, + const float vpHeight, + const Margins& margins, + const bool drawBoxFlag, + int32_t chartGraphicsDrawingViewportOut[4]) { const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; @@ -1363,29 +1614,31 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons vpWidth, vpHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(vpX, (vpX + vpWidth), - vpY, (vpY + vpHeight), - -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - std::unique_ptr gridData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - gridData->reserveForNumberOfVertices(8); - gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); - gridData->addVertex(gridRight - halfGridLineWidth, gridTop); - gridData->addVertex(gridRight, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); - gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); - glLineWidth(GRID_LINE_WIDTH); - drawPrimitivePrivate(gridData.get()); + if (drawBoxFlag) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(vpX, (vpX + vpWidth), + vpY, (vpY + vpHeight), + -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + std::unique_ptr gridData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + gridData->reserveForNumberOfVertices(8); + gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); + gridData->addVertex(gridRight - halfGridLineWidth, gridTop); + gridData->addVertex(gridRight, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); + gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); + glLineWidth(GRID_LINE_WIDTH); + drawPrimitivePrivate(gridData.get()); + } /* * Region inside the grid's box @@ -1716,7 +1969,89 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini return false; } -/** +/** + * Draw the chart axes grid/box + * + * @param tabViewportX + * Viewport X for all chart content + * @param tabViewportY + * Viewport Y for all chart content + * @param tabViewportWidth + * Viewport width for all chart content + * @param tabViewportHeight + * Viewport height for all chart content + * @param margins + * Margin around graphics region. The margin corresponding to the + * axis may be changed so that all text in the axis is visible + * (and not cut off). + * @param chartTitle + * The chart title annotation. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartTitle(const float tabViewportX, + const float tabViewportY, + const float tabViewportWidth, + const float tabViewportHeight, + const Margins& margins, + AnnotationPercentSizeText* chartTitle) +{ + if (chartTitle == NULL) { + return; + } + + const AString text = chartTitle->getText().trimmed(); + if (text.isEmpty()) { + return; + } + + int32_t axisVpX = 0; + int32_t axisVpY = 0; + int32_t axisVpWidth = 0; + int32_t axisVpHeight = 0; + float axisLength = 0.0; + axisVpX = tabViewportX + margins.m_left; + axisVpY = tabViewportY + tabViewportHeight - margins.m_top; + axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); + axisVpHeight = margins.m_top; + axisLength = axisVpWidth; + + const float rgba[4] = { + m_fixedPipelineDrawing->m_foregroundColorFloat[0], + m_fixedPipelineDrawing->m_foregroundColorFloat[1], + m_fixedPipelineDrawing->m_foregroundColorFloat[2], + 1.0 + }; + + chartTitle->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartTitle->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + + float labelTabX = axisVpWidth / 2.0; + float labelTabY = axisVpHeight / 2.0; + const float textMarginOffset = 5.0; + labelTabX = (axisVpWidth / 2.0) + margins.m_left; + labelTabY = tabViewportHeight - textMarginOffset; + chartTitle->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + chartTitle->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + chartTitle->setRotationAngle(0.0); + + if ((axisVpWidth > 0.0) + && (axisVpHeight > 0.0)) { + chartTitle->setCustomTextColor(rgba); + chartTitle->setTextColor(CaretColorEnum::CUSTOM); + chartTitle->setTabIndex(m_tabIndex); + chartTitle->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; + const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; + chartTitle->getCoordinate()->setXYZ(tabPercentageX, + tabPercentageY, + 0.0f); + + m_annotationsForDrawingOutput.push_back(chartTitle); + } +} + + +/** * Update the viewport content with charting viewport and matrices. */ void diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index c9423175d..6d0a09e3b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -139,6 +139,7 @@ namespace caret { const float vpWidth, const float vpHeight, const Margins& margins, + const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]); bool drawChartAxisCartesian(const float minimumDataValue, @@ -153,6 +154,13 @@ namespace caret { float& axisMinimumOut, float& axisMaximumOut); + void drawChartTitle(const float tabViewportX, + const float tabViewportY, + const float tabViewportWidth, + const float tabViewportHeight, + const Margins& margins, + AnnotationPercentSizeText* chartTitle); + void estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, const float maximumDataValue, const float viewportWidth, @@ -162,6 +170,11 @@ namespace caret { double& widthOut, double& heightOut); + void estimateChartTitleHeight(const float viewportWidth, + const float viewportHeight, + AnnotationPercentSizeText* chartTitle, + double& heightOut); + void drawPrimitivePrivate(GraphicsPrimitive* primitive); void updateViewportContentForCharting(const int32_t viewport[4]); diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index cf0d0a6e0..c7c81acdb 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -32,6 +32,7 @@ #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" +#include "EventAnnotationChartLabelGet.h" #include "EventBrowserTabGet.h" #include "EventChartTwoAttributesChanged.h" #include "EventManager.h" @@ -126,6 +127,10 @@ m_tabIndex(tabIndex) break; } + m_chartTitle = createChartTitle(); + + m_chartTitleDisplayedFlag = true; + m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartAxisLeft", "ChartTwoCartesianAxis", @@ -136,6 +141,13 @@ m_tabIndex(tabIndex) m_sceneAssistant->add("m_chartAxisBottom", "ChartTwoCartesianAxis", m_chartAxisBottom.get()); + + m_sceneAssistant->add("m_chartTitle", + "AnnotationPercentSizeText", + m_chartTitle.get()); + m_sceneAssistant->add("m_chartTitleDisplayedFlag", + &m_chartTitleDisplayedFlag); + m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); @@ -148,6 +160,7 @@ m_tabIndex(tabIndex) m_overlays[i]->setWeakPointerToSelf(m_overlays[i]); } + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); @@ -178,6 +191,8 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; *m_chartAxisRight = *overlaySet->m_chartAxisRight; *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; + *m_chartTitle = *overlaySet->m_chartTitle; + m_chartTitleDisplayedFlag = overlaySet->m_chartTitleDisplayedFlag; m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } @@ -198,6 +213,31 @@ ChartTwoOverlaySet::copyCartesianAxes(const ChartTwoOverlaySet* overlaySet) *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; } +/** + * @return A new instance for the chart title. + */ +std::unique_ptr +ChartTwoOverlaySet::createChartTitle() +{ + std::unique_ptr title = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); + title->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); + + title->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + title->setTabIndex(0); + title->setTextColor(CaretColorEnum::RED); + title->setLineColor(CaretColorEnum::NONE); + title->setBackgroundColor(CaretColorEnum::NONE); + + title->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + title->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + title->setFontPercentViewportSize(5.0f); + + title->setText(""); + + return title; +} + /** * @return Returns the top-most overlay regardless of its enabled status. @@ -284,6 +324,9 @@ void ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Overlay Set"); + descriptionOut.pushIndentation(); + descriptionOut.addLine(" Title: " + (m_chartTitleDisplayedFlag ? m_chartTitle->getText() : "Disabled by user")); + descriptionOut.popIndentation(); const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { @@ -654,6 +697,16 @@ ChartTwoOverlaySet::receiveEvent(Event* event) selectMapEvent->setEventProcessed(); } } + else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { + /* + * The events intended for overlays are received here so that + * only DISPLAYED overlays are updated. + */ + EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); + CaretAssert(chartLabelEvent); + + chartLabelEvent->addAnnotationChartLabel(m_chartTitle.get()); + } } /** @@ -841,6 +894,44 @@ ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const return label; } +/** + * @return The chart title. + */ +AnnotationPercentSizeText* +ChartTwoOverlaySet::getChartTitle() +{ + return m_chartTitle.get(); +} + +/** + * @return The chart title. + */ +const AnnotationPercentSizeText* +ChartTwoOverlaySet::getChartTitle() const +{ + return m_chartTitle.get(); +} + +/** + * @return True if chart title displayed, else false. + */ +bool ChartTwoOverlaySet::isChartTitleDisplayed() const +{ + return m_chartTitleDisplayedFlag; +} + +/** + * Set chart title displayed + * + * @param status + * New status. + */ +void +ChartTwoOverlaySet::setChartTitleDislayed(const bool status) +{ + m_chartTitleDisplayedFlag = status; +} + /** * Save information specific to this type of model to the scene. * @@ -899,6 +990,9 @@ ChartTwoOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + m_chartTitle->setText(""); + m_chartTitleDisplayedFlag = false; + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 02c060a3a..04dabbcdd 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -73,6 +73,14 @@ namespace caret { AnnotationPercentSizeText* getAxisLabel(const ChartTwoCartesianAxis* axis) const; + AnnotationPercentSizeText* getChartTitle(); + + const AnnotationPercentSizeText* getChartTitle() const; + + bool isChartTitleDisplayed() const; + + void setChartTitleDislayed(const bool status); + void insertOverlayAbove(const int32_t overlayIndex); void insertOverlayBelow(const int32_t overlayIndex); @@ -123,6 +131,8 @@ namespace caret { void firstOverlaySelectionChanged(); + std::unique_ptr createChartTitle(); + SceneClassAssistant* m_sceneAssistant; std::vector> m_overlays; @@ -139,6 +149,10 @@ namespace caret { const int32_t m_tabIndex; + std::unique_ptr m_chartTitle; + + bool m_chartTitleDisplayedFlag = false; + int32_t m_numberOfDisplayedOverlays; bool m_inFirstOverlayChangedMethodFlag = false; diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index e850dbd9e..865aae2d6 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -84,8 +84,8 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) m_leftRightAxisTitle->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); - initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); - initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + initializeAxisLabel(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + initializeAxisLabel(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_bottomAxisTitle", @@ -108,48 +108,48 @@ ChartableTwoFileBaseChart::~ChartableTwoFileBaseChart() } /** - * Initialize an axis titlel + * Initialize an axis' label * - * @param titleAnnotation - * Annotation containing title. + * @param axisLabel + * Annotation containing label. * @param axisLocation * Location of axis. */ -void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* titleAnnotation, +void ChartableTwoFileBaseChart::initializeAxisLabel(AnnotationPercentSizeText* axisLabel, const ChartAxisLocationEnum::Enum axisLocation) { - CaretAssert(titleAnnotation); + CaretAssert(axisLabel); - titleAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - titleAnnotation->setTabIndex(0); - titleAnnotation->setTextColor(CaretColorEnum::RED); - titleAnnotation->setLineColor(CaretColorEnum::NONE); - titleAnnotation->setBackgroundColor(CaretColorEnum::NONE); + axisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + axisLabel->setTabIndex(0); + axisLabel->setTextColor(CaretColorEnum::RED); + axisLabel->setLineColor(CaretColorEnum::NONE); + axisLabel->setBackgroundColor(CaretColorEnum::NONE); - titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - titleAnnotation->setFontPercentViewportSize(s_defaultFontPercentViewportSize); + axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + axisLabel->setFontPercentViewportSize(s_defaultFontPercentViewportSize); AString title; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - titleAnnotation->setRotationAngle(-90.0); + axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + axisLabel->setRotationAngle(-90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - titleAnnotation->setRotationAngle(90.0); + axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + axisLabel->setRotationAngle(90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - titleAnnotation->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - titleAnnotation->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); break; } @@ -203,7 +203,7 @@ void ChartableTwoFileBaseChart::initializeAxisTitle(AnnotationPercentSizeText* t break; } - titleAnnotation->setText(title); + axisLabel->setText(title); } @@ -313,8 +313,8 @@ ChartableTwoFileBaseChart::updateChartTwoCompoundDataTypeAfterFileChanges(const m_compoundChartDataType = compoundChartDataType; - initializeAxisTitle(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); - initializeAxisTitle(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + initializeAxisLabel(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + initializeAxisLabel(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); } /** diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index 204052b96..36260a370 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -108,7 +108,7 @@ namespace caret { ChartableTwoFileBaseChart& operator=(const ChartableTwoFileBaseChart&); - void initializeAxisTitle(AnnotationPercentSizeText* title, + void initializeAxisLabel(AnnotationPercentSizeText* axisLabel, const ChartAxisLocationEnum::Enum axisLocation); const ChartTwoDataTypeEnum::Enum m_chartType; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index cf88caf82..fef737dca 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -58,6 +58,7 @@ #include "BrainBrowserWindowToolBarChartTwoAttributes.h" #include "BrainBrowserWindowToolBarChartTwoAxes.h" #include "BrainBrowserWindowToolBarChartTwoOrientation.h" +#include "BrainBrowserWindowToolBarChartTwoTitle.h" #include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" #include "BrainBrowserWindowToolBarClipping.h" @@ -338,6 +339,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->chartTwoOrientationWidget = createChartTwoOrientationWidget(); this->chartTwoAttributesWidget = createChartTwoAttributesWidget(); this->chartTwoAxesWidget = createChartTwoAxesWidget(); + this->chartTwoTitleWidget = createChartTwoTitleWidget(); this->chartTypeWidget = createChartTypeWidget(); this->chartTypeTwoWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); @@ -386,6 +388,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->toolbarWidgetLayout->addWidget(this->chartTwoAxesWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartTwoTitleWidget, 0, Qt::AlignLeft); + this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->modeWidget, 0, Qt::AlignLeft); @@ -1405,6 +1409,7 @@ BrainBrowserWindowToolBar::updateToolBar() bool showChartTwoOrientationWidget = false; bool showChartTwoAttributesWidget = false; bool showChartTwoAxesWidget = false; + bool showChartTwoTitleWidget = false; bool showModeWidget = true; bool showWindowWidget = true; @@ -1473,14 +1478,16 @@ BrainBrowserWindowToolBar::updateToolBar() break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: showChartTwoAxesWidget = true; + showChartTwoTitleWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: showChartTwoAxesWidget = true; - //showChartTwoAttributesWidget = true; + showChartTwoTitleWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: showChartTwoOrientationWidget = true; showChartTwoAttributesWidget = true; + showChartTwoTitleWidget = true; break; } @@ -1507,6 +1514,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartTwoOrientationWidget->setVisible(false); this->chartTwoAttributesWidget->setVisible(false); this->chartTwoAxesWidget->setVisible(false); + this->chartTwoTitleWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); this->volumePlaneWidget->setVisible(false); this->volumeMontageWidget->setVisible(false); @@ -1525,6 +1533,7 @@ BrainBrowserWindowToolBar::updateToolBar() this->chartTwoOrientationWidget->setVisible(showChartTwoOrientationWidget); this->chartTwoAttributesWidget->setVisible(showChartTwoAttributesWidget); this->chartTwoAxesWidget->setVisible(showChartTwoAxesWidget); + this->chartTwoTitleWidget->setVisible(showChartTwoTitleWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); @@ -1589,6 +1598,7 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab this->updateChartTwoOrientationWidget(browserTabContent); this->updateChartTwoAttributesWidget(browserTabContent); this->updateChartTwoAxesWidget(browserTabContent); + this->updateChartTwoTitleWidget(browserTabContent); this->updateVolumeMontageWidget(browserTabContent); this->updateVolumePlaneWidget(browserTabContent); this->updateModeWidget(browserTabContent); @@ -2732,12 +2742,46 @@ BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabCo m_chartTypeToolBarComponent->updateContent(browserTabContent); } +/** + * Create the chart two title widget. + * + * @return + * Widget containing the chart title. + */ +QWidget* +BrainBrowserWindowToolBar::createChartTwoTitleWidget() +{ + m_chartTwoTitleToolBarComponent = new BrainBrowserWindowToolBarChartTwoTitle(this); + QWidget* w = this->createToolWidget("Chart Title", + m_chartTwoTitleToolBarComponent, + WIDGET_PLACEMENT_LEFT, + WIDGET_PLACEMENT_TOP, + 100); + w->setVisible(false); + return w; +} +/** + * Update the chart title widget. + * + * @param browserTabContent + * The active tab content. + */ +void +BrainBrowserWindowToolBar::updateChartTwoTitleWidget(BrowserTabContent* browserTabContent) +{ + if (this->chartTwoTitleWidget->isHidden()) { + return; + } + + m_chartTwoTitleToolBarComponent->updateContent(browserTabContent); +} + /** * Create the chart type two widget. * * @return - * Widget containing the chart options. + * Widget containing the chart type. */ QWidget* BrainBrowserWindowToolBar::createChartTypeTwoWidget() diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 9eb79f650..d0bebf063 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -52,10 +52,11 @@ namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; + class BrainBrowserWindowToolBarChartTwoAttributes; class BrainBrowserWindowToolBarChartTwoAxes; class BrainBrowserWindowToolBarChartTwoOrientation; + class BrainBrowserWindowToolBarChartTwoTitle; class BrainBrowserWindowToolBarChartTwoType; - class BrainBrowserWindowToolBarChartTwoAttributes; class BrainBrowserWindowToolBarChartType; class BrainBrowserWindowToolBarClipping; class BrainBrowserWindowToolBarSlicePlane; @@ -148,6 +149,7 @@ namespace caret { QWidget* createChartTwoOrientationWidget(); QWidget* createChartTwoAttributesWidget(); QWidget* createChartTwoAxesWidget(); + QWidget* createChartTwoTitleWidget(); QWidget* createChartTypeWidget(); QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); @@ -169,6 +171,7 @@ namespace caret { void updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent); void updateChartTwoAxesWidget(BrowserTabContent* browserTabContent); void updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent); + void updateChartTwoTitleWidget(BrowserTabContent* browserTabContent); void updateChartTypeWidget(BrowserTabContent* browserTabContent); void updateChartTypeTwoWidget(BrowserTabContent* browserTabContent); void updateVolumeMontageWidget(BrowserTabContent* browserTabContent); @@ -199,6 +202,7 @@ namespace caret { QWidget* chartTwoOrientationWidget; QWidget* chartTwoAttributesWidget; QWidget* chartTwoAxesWidget; + QWidget* chartTwoTitleWidget; WuQWidgetObjectGroup* viewWidgetGroup; WuQWidgetObjectGroup* orientationWidgetGroup; @@ -373,6 +377,8 @@ namespace caret { BrainBrowserWindowToolBarChartTwoAxes* m_chartTwoAxesToolBarComponent; BrainBrowserWindowToolBarChartTwoOrientation* m_chartTwoOrientationToolBarComponent; BrainBrowserWindowToolBarChartTwoAttributes* m_chartTwoAttributesToolBarComponent; + BrainBrowserWindowToolBarChartTwoTitle* m_chartTwoTitleToolBarComponent; + BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; BrainBrowserWindowToolBarClipping* m_clippingToolBarComponent; @@ -409,6 +415,8 @@ namespace caret { friend class BrainBrowserWindowToolBarChartTwoAxes; friend class BrainBrowserWindowToolBarChartTwoOrientation; friend class BrainBrowserWindowToolBarChartTwoAttributes; + friend class BrainBrowserWindowToolBarChartTwoAttributes; + friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; friend class BrainBrowserWindowToolBarClipping; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx new file mode 100644 index 000000000..e1a2588a2 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -0,0 +1,149 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ +#include "BrainBrowserWindowToolBarChartTwoTitle.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ + +#include +#include +#include +#include + +#include "AnnotationPercentSizeText.h" +#include "BrainBrowserWindowToolBar.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "ChartTwoOverlaySet.h" +#include "ModelChartTwo.h" +#include "WuQDataEntryDialog.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarChartTwoTitle + * \brief Toolbar component for chart orientation. + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar) +: BrainBrowserWindowToolBarComponent(parentToolBar) +{ + m_showTitleCheckBox = new QCheckBox("Show Title"); + m_showTitleCheckBox->setToolTip("Show the title at the top of the chart"); + QObject::connect(m_showTitleCheckBox, &QCheckBox::toggled, + this, &BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxToggled); + + QAction* editTitleAction = new QAction("Edit Title..."); + editTitleAction->setToolTip("Edit the chart title in a dialog"); + QObject::connect(editTitleAction, &QAction::triggered, + this, &BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered); + + QToolButton* editTitleToolButton = new QToolButton; + WuQtUtilities::setToolButtonStyleForQt5Mac(editTitleToolButton); + editTitleToolButton->setDefaultAction(editTitleAction); + + QVBoxLayout* layout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); + layout->addWidget(m_showTitleCheckBox, 0, Qt::AlignHCenter); + layout->addWidget(editTitleToolButton, 0, Qt::AlignHCenter); + + setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarChartTwoTitle::~BrainBrowserWindowToolBarChartTwoTitle() +{ +} + +/** + * Update content of this tool bar component. + * + * @param browserTabContent + * Content of the browser tab. + */ +void +BrainBrowserWindowToolBarChartTwoTitle::updateContent(BrowserTabContent* browserTabContent) +{ + m_chartOverlaySet = NULL; + + if (browserTabContent != NULL) { + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); + if (modelChartTwo != NULL) { + const int32_t tabIndex = browserTabContent->getTabNumber(); + m_chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + } + } + + if (m_chartOverlaySet != NULL) { + setEnabled(true); + m_showTitleCheckBox->setChecked(m_chartOverlaySet->isChartTitleDisplayed()); + } + else { + setEnabled(false); + } +} + +/** + * Called when show title checkbox is toggled. + * + * @param checked + * Status of checkbox. + */ +void +BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxToggled(bool checked) +{ + if (m_chartOverlaySet != NULL) { + m_chartOverlaySet->setChartTitleDislayed(checked); + this->updateGraphicsWindow(); + this->updateOtherYokedWindows(); + } +} + +/** + * Called when edit title action is triggered. + */ +void +BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered() +{ + if (m_chartOverlaySet != NULL) { + WuQDataEntryDialog newNameDialog("Chart Title", + this); + QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Title"); + lineEdit->setText(m_chartOverlaySet->getChartTitle()->getText()); + if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { + const AString name = lineEdit->text().trimmed(); + m_chartOverlaySet->getChartTitle()->setText(name); + this->updateGraphicsWindow(); + this->updateOtherYokedWindows(); + } + } +} + diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h new file mode 100644 index 000000000..f0c9129cd --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h @@ -0,0 +1,68 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "BrainBrowserWindowToolBarComponent.h" + +class QCheckBox; + +namespace caret { + + class ChartTwoOverlaySet; + + class BrainBrowserWindowToolBarChartTwoTitle : public BrainBrowserWindowToolBarComponent { + Q_OBJECT + + public: + BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar); + + virtual ~BrainBrowserWindowToolBarChartTwoTitle(); + + virtual void updateContent(BrowserTabContent* browserTabContent); + + // ADD_NEW_METHODS_HERE + + private slots: + void editTitleActionTriggered(); + + void showTitleCheckBoxToggled(bool); + + private: + BrainBrowserWindowToolBarChartTwoTitle(const BrainBrowserWindowToolBarChartTwoTitle&); + + BrainBrowserWindowToolBarChartTwoTitle& operator=(const BrainBrowserWindowToolBarChartTwoTitle&); + + QCheckBox* m_showTitleCheckBox; + + ChartTwoOverlaySet* m_chartOverlaySet; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index b35f91ff4..96aa198e6 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -76,6 +76,7 @@ ELSE() BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoAxes.h BrainBrowserWindowToolBarChartTwoOrientation.h + BrainBrowserWindowToolBarChartTwoTitle.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -263,6 +264,7 @@ BrainBrowserWindowToolBarChartAxes.h BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoAxes.h BrainBrowserWindowToolBarChartTwoOrientation.h +BrainBrowserWindowToolBarChartTwoTitle.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h @@ -475,6 +477,7 @@ BrainBrowserWindowToolBarChartAxes.cxx BrainBrowserWindowToolBarChartTwoAttributes.cxx BrainBrowserWindowToolBarChartTwoAxes.cxx BrainBrowserWindowToolBarChartTwoOrientation.cxx +BrainBrowserWindowToolBarChartTwoTitle.cxx BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx -- GitLab From fe84a3c99e826fa705c50f99bfa959206578d6f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 26 Jul 2017 11:44:31 -0500 Subject: [PATCH 332/755] Added a title to charts. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 142 ------------------ 1 file changed, 142 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 62ece084b..4d5bd3b73 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -861,148 +861,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } - -///** -// * Draw a matrix chart. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() -//{ -// glViewport(m_viewport[0], -// m_viewport[1], -// m_viewport[2], -// m_viewport[3]); -// -// bool applyTransformationsFlag = true; -// float cellWidth = 1.0; -// float cellHeight = 1.0; -// -// /* -// * Setup width/height of area in which matrix is drawn with a -// * small margin along all of the edges -// */ -// float margin = 10.0; -// if ((m_viewport[2] < (margin * 3.0)) -// || (m_viewport[3] < (margin * 3.0))) { -// margin = 0.0; -// } -// const float graphicsWidth = m_viewport[2] - (margin * 2.0); -// const float graphicsHeight = m_viewport[3] - (margin * 2.0); -// -// /* -// * First overlay is ALWAYS ON and since all matrices must have -// * same number of rows/columns, use first matrix for rows/columns -// */ -// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); -// CaretAssert(numberOfOverlays > 0); -// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); -// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); -// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); -// const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); -// const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); -// if ((numberOfRows > 0) -// && (numberOfCols > 0)) { -// cellWidth = graphicsWidth / numberOfCols; -// cellHeight = graphicsHeight / numberOfRows; -// } -// else { -// return; -// } -// -// /* -// * Set the width and neight of each matrix cell. -// */ -// const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); -// CaretAssert(matrixProperties); -// const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; -// const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; -// if ((cellWidthZoom > 0.0) -// && (cellHeightZoom > 0.0)) { -// cellWidth *= cellWidthZoom; -// cellHeight *= cellHeightZoom; -// } -// -// /* -// * Set the coordinates for the area in which the matrix is drawn. -// */ -// const float xMin = -margin; -// const float xMax = graphicsWidth + margin; -// const float yMin = -margin; -// const float yMax = graphicsHeight + margin; -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// glOrtho(xMin, xMax, -// yMin, yMax, -// -1.0, 1.0); -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = cellWidth * numberOfCols; -// const float chartHeight = cellHeight * numberOfRows; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// /* -// * Save the transformation matrices and the viewport -// * If there is more than one line chart, this code will be executed -// * several times but since the top overlay is drawn last, the contents -// * of the top overlay will be used. -// */ -// updateViewportContentForCharting(m_viewport); -// -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; -// int32_t selectedIndex = -1; -// chartOverlay->getSelectionData(mapFile, -// selectedIndexType, -// selectedIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// const ChartableTwoFileMatrixChart* matrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); -// int32_t overlayRows = 0; -// int32_t overlayColumns = 0; -// matrixChart->getMatrixDimensions(overlayRows, -// overlayColumns); -// -// /* -// * All matrices must have same rows/columns -// */ -// if ((overlayRows == numberOfRows) -// && (overlayColumns == numberOfCols)) { -// drawMatrixChartContent(matrixChart, -// chartOverlay->getMatrixTriangularViewingMode(), -// cellWidth, -// cellHeight, -// m_zooming); -// } -// } -//} - /** * Draw a matrix chart. */ -- GitLab From 75c2dcba45371168bbcd5907811bf9758cf7ce0e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 26 Jul 2017 12:03:45 -0500 Subject: [PATCH 333/755] In the Features ToolBox --> Annotations page are checkboxes labeled "Display Annotations" and "Display Text Annotations". These checkboxes should have no effect on the display of chart titles, chart axis labels, and color bars and the necessary changes have been implemented. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index f68d236a2..ce4cd2f62 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -603,11 +603,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat return; } - const DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); - if ( ! dpa->isDisplayAnnotations()) { - return; - } - m_volumeSliceThickness = sliceThickness; setSelectionBoxColor(); @@ -650,6 +645,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat break; } + /* + * User may turn off display of all annotations. + * Color bars and other annotations not in a file are always + * drawn so continue processing. + */ + const DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); + if ( ! dpa->isDisplayAnnotations()) { + drawAnnotationsFromFilesFlag = false; + } + /* * Note: When window annotations are being drawn, the * tab index is invalid so it must be ignored. @@ -1805,11 +1810,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarText(const AnnotationColo const float textHeightInPixels, const float offsetFromTopInPixels) { - DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); - if ( ! dpa->isDisplayTextAnnotations()) { - return; - } - const float textPercentageHeight = (textHeightInPixels / m_modelSpaceViewport[3]) * 100.0; AnnotationPercentSizeText annText(AnnotationAttributesDefaultTypeEnum::NORMAL); @@ -2194,8 +2194,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi CaretAssert(text); CaretAssert(text->getType() == AnnotationTypeEnum::TEXT); + /* + * Annotations with "DISPLAY_GROUP" propery may be turned on/off by user. + */ DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); - if (text->getType() == AnnotationTypeEnum::TEXT) { + if (text->testProperty(Annotation::Property::DISPLAY_GROUP)) { if ( ! dpa->isDisplayTextAnnotations()) { return false; } -- GitLab From 9468f0dc47b44175a4679bfb868332d3cebbbd1b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 26 Jul 2017 15:17:15 -0500 Subject: [PATCH 334/755] Started on support, but not yet implementation, for converting older line widths specified in pixels to widths specified in percentages of window height. --- src/Annotations/Annotation.cxx | 72 +++++++++++++++---- src/Annotations/Annotation.h | 24 +++++-- src/Annotations/AnnotationRedoUndoCommand.cxx | 4 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 12 ++-- src/Brain/FtglFontTextRenderer.cxx | 6 +- src/Files/AnnotationFileXmlFormatBase.h | 8 ++- src/Files/AnnotationFileXmlReader.cxx | 15 +++- src/Files/AnnotationFileXmlWriter.cxx | 7 +- src/Files/XmlStreamReaderHelper.cxx | 36 ++++++++++ src/Files/XmlStreamReaderHelper.h | 5 ++ src/GuiQt/AnnotationColorWidget.cxx | 6 +- 11 files changed, 154 insertions(+), 41 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index d778399a2..fe1a5ef28 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -128,7 +128,8 @@ Annotation::copyHelperAnnotation(const Annotation& obj) m_viewportCoordinateSpaceViewport[1] = obj.m_viewportCoordinateSpaceViewport[1]; m_viewportCoordinateSpaceViewport[2] = obj.m_viewportCoordinateSpaceViewport[2]; m_viewportCoordinateSpaceViewport[3] = obj.m_viewportCoordinateSpaceViewport[3]; - m_lineWidth = obj.m_lineWidth; + m_lineWidthPixels = obj.m_lineWidthPixels; + m_lineWidthPercentage = obj.m_lineWidthPercentage; m_colorLine = obj.m_colorLine; m_colorBackground = obj.m_colorBackground; m_customColorBackground[0] = obj.m_customColorBackground[0]; @@ -302,7 +303,8 @@ Annotation::applyColoringFromOther(const Annotation* otherAnnotation) m_colorBackground = otherAnnotation->m_colorBackground; m_colorLine = otherAnnotation->m_colorLine; - m_lineWidth = otherAnnotation->m_lineWidth; + m_lineWidthPixels = otherAnnotation->m_lineWidthPixels; + m_lineWidthPercentage = otherAnnotation->m_lineWidthPercentage; for (int32_t i = 0; i < 4; i++) { m_customColorBackground[i] = otherAnnotation->m_customColorBackground[i]; @@ -390,7 +392,8 @@ Annotation::initializeAnnotationMembers() switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: - m_lineWidth = 3.0; + m_lineWidthPixels = 3.0; + m_lineWidthPercentage = 1.0; m_colorBackground = CaretColorEnum::NONE; m_colorLine = CaretColorEnum::WHITE; @@ -425,7 +428,8 @@ Annotation::initializeAnnotationMembers() break; case AnnotationAttributesDefaultTypeEnum::USER: { - m_lineWidth = s_userDefaultLineWidth; + m_lineWidthPixels = s_userDefaultLineWidthPixels; + m_lineWidthPercentage = s_userDefaultLineWidthPercentage; m_colorBackground = s_userDefaultColorBackground; m_colorLine = s_userDefaultColorLine; @@ -750,25 +754,49 @@ Annotation::toString() const } /** - * @return The line width. + * @return The line width in pixels. */ float -Annotation::getLineWidth() const +Annotation::getLineWidthPixelsObsolete() const { - return m_lineWidth; + return m_lineWidthPixels; } /** - * Set the line width. + * Set the line width in pixels. * * @param lineWidth * New value for line width. */ void -Annotation::setLineWidth(const float lineWidth) +Annotation::setLineWidthPixelsObsolete(const float lineWidth) { - if (lineWidth != m_lineWidth) { - m_lineWidth = lineWidth; + if (lineWidth != m_lineWidthPixels) { + m_lineWidthPixels = lineWidth; + setModified(); + } +} + +/** + * @return The line width percentage. + */ +float +Annotation::getLineWidthPercentage() const +{ + return m_lineWidthPercentage; +} + +/** + * Set the line width percentage. + * + * @param lineWidthPercentage + * New value for line width percentage. + */ +void +Annotation::setLineWidthPercentage(const float lineWidthPercentage) +{ + if (lineWidthPercentage != m_lineWidthPercentage) { + m_lineWidthPercentage = lineWidthPercentage; setModified(); } } @@ -2037,13 +2065,27 @@ Annotation::setUserDefaultCustomBackgroundColor(const float rgba[4]) } /** - * Set the default value for line width + * Set the default value for line width pixels * - * @param lineWidth + * @param lineWidthPixels + * Default for newly created annotations. + */ +void +Annotation::setUserDefaultLineWidthPixels(const float lineWidthPixels) +{ + s_userDefaultLineWidthPixels = lineWidthPixels; +} +static void setUserDefaultLineWidthPercentage(const float lineWidthPercentage); + +/** + * Set the default value for line width percentage + * + * @param lineWidthPercentage * Default for newly created annotations. */ void -Annotation::setUserDefaultLineWidth(const float lineWidth) +Annotation::setUserDefaultLineWidthPercentage(const float lineWidthPercentage) { - s_userDefaultLineWidth = lineWidth; + s_userDefaultLineWidthPercentage = lineWidthPercentage; } + diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index f88679944..a4f2c62fa 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -197,9 +197,13 @@ namespace caret { void setCustomBackgroundColor(const uint8_t rgba[4]); - float getLineWidth() const; + float getLineWidthPixelsObsolete() const; - void setLineWidth(const float lineWidth); + void setLineWidthPixelsObsolete(const float lineWidthPixels); + + float getLineWidthPercentage() const; + + void setLineWidthPercentage(const float lineWidthPercentage); bool isSelectedForEditing(const int32_t windowIndex) const; @@ -215,7 +219,9 @@ namespace caret { static void setUserDefaultCustomBackgroundColor(const float rgba[4]); - static void setUserDefaultLineWidth(const float lineWidth); + static void setUserDefaultLineWidthPixels(const float lineWidthPixels); + + static void setUserDefaultLineWidthPercentage(const float lineWidthPercentage); virtual bool isFixedAspectRatio() const; @@ -367,8 +373,10 @@ namespace caret { float m_customColorBackground[4]; - float m_lineWidth; + float m_lineWidthPixels; + float m_lineWidthPercentage = -1.0f; + AString m_name; int32_t m_uniqueKey; @@ -403,7 +411,9 @@ namespace caret { static float s_userDefaultCustomColorBackground[4]; - static float s_userDefaultLineWidth; + static float s_userDefaultLineWidthPixels; + + static float s_userDefaultLineWidthPercentage; // ADD_NEW_MEMBERS_HERE @@ -426,7 +436,9 @@ namespace caret { float Annotation::s_userDefaultCustomColorBackground[4] = { 0.0, 0.0, 0.0, 1.0 }; - float Annotation::s_userDefaultLineWidth = 3.0; + float Annotation::s_userDefaultLineWidthPixels = 3.0f; + + float Annotation::s_userDefaultLineWidthPercentage = 1.0f; #endif // __ANNOTATION_DECLARE__ } // namespace diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index b1de7a96c..97e7b95da 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -220,7 +220,7 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, break; case AnnotationRedoUndoCommandModeEnum::LINE_WIDTH_FOREGROUND: if (annotation->testProperty(Annotation::Property::LINE_THICKNESS)) { - annotation->setLineWidth(annotationValue->getLineWidth()); + annotation->setLineWidthPixelsObsolete(annotationValue->getLineWidthPixelsObsolete()); } break; case AnnotationRedoUndoCommandModeEnum::LOCATION_AND_SIZE: @@ -1039,7 +1039,7 @@ AnnotationRedoUndoCommand::setModeLineWidth(const float newLineWidth, CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); - redoAnnotation->setLineWidth(newLineWidth); + redoAnnotation->setLineWidthPixelsObsolete(newLineWidth); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index ce4cd2f62..6b1b23a0b 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1193,7 +1193,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 }; - const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidth()); + const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidthPixelsObsolete()); const bool depthTestFlag = isDrawnWithDepthTesting(box); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); @@ -1903,7 +1903,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi const float majorAxis = ((oval->getWidth() / 100.0) * (m_modelSpaceViewport[2] / 2.0)); const float minorAxis = ((oval->getHeight() / 100.0) * (m_modelSpaceViewport[3] / 2.0)); const float rotationAngle = oval->getRotationAngle(); - const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidth()); + const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidthPixelsObsolete()); const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, @@ -2083,7 +2083,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin createLineCoordinates(annXYZ, brainordinateXYZ, - getLineWidthFromPercentageHeight(text->getLineWidth()), + getLineWidthFromPercentageHeight(text->getLineWidthPixelsObsolete()), false, showArrowFlag, lineCoordinatesOut); @@ -2291,7 +2291,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi if ( ! connectLineCoordinates.empty()) { BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, textColorRGBA, - getLineWidthFromPercentageHeight(text->getLineWidth())); + getLineWidthFromPercentageHeight(text->getLineWidthPixelsObsolete())); } if (drawTextFlag) { @@ -2518,7 +2518,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (drawForegroundFlag) { BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, foregroundRGBA, - getLineWidthFromPercentageHeight(image->getLineWidth())); + getLineWidthFromPercentageHeight(image->getLineWidthPixelsObsolete())); } setDepthTestingStatus(depthTestFlag); @@ -2694,7 +2694,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi lineTailXYZ)) { return false; } - const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidth()); + const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPixelsObsolete()); const float backgroundLineWidth = lineWidth + 4; const float selectionCenterXYZ[3] = { diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index aaaffe13d..d2f01dc34 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -738,7 +738,7 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth m_depthTestingStatus = depthTesting; - const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidth()); + const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPixelsObsolete()); TextStringGroup tsg(annotationText, font, @@ -808,7 +808,7 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann + AString((char*)gluErrorString(errorCode))); } - double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidth()); + double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPixelsObsolete()); TextStringGroup textStringGroup(annotationText, font, @@ -1734,7 +1734,7 @@ m_viewportBoundsMaxY(0.0) */ if (annotationText.getLineColor() != CaretColorEnum::NONE) { if (annotationText.getOrientation() == AnnotationTextOrientationEnum::HORIZONTAL) { - const double outlineThickness = m_annotationText.getLineWidth(); + const double outlineThickness = m_annotationText.getLineWidthPixelsObsolete(); if (outlineThickness > 0.0) { m_outlineThickness = m_lineThicknessForViewportHeight; } diff --git a/src/Files/AnnotationFileXmlFormatBase.h b/src/Files/AnnotationFileXmlFormatBase.h index f10d1d9ec..66e58272b 100644 --- a/src/Files/AnnotationFileXmlFormatBase.h +++ b/src/Files/AnnotationFileXmlFormatBase.h @@ -74,7 +74,9 @@ namespace caret { static const QString ATTRIBUTE_FOREGROUND_CUSTOM_RGBA; - static const QString ATTRIBUTE_FOREGROUND_LINE_WIDTH; + static const QString ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS; + + static const QString ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE; static const QString ATTRIBUTE_GROUP_TYPE; @@ -192,7 +194,9 @@ namespace caret { const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_CUSTOM_RGBA = "foregroundCustomRGBA"; - const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_LINE_WIDTH = "foregroundLineWidth"; + const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS = "foregroundLineWidth"; + + const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE = "foregroundLineWidthPercentage"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_GROUP_TYPE = "groupType"; diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index fd6da346c..e2caf8905 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -541,9 +541,20 @@ AnnotationFileXmlReader::readAnnotationAttributes(Annotation* annotation, /* * Foreground line width */ - annotation->setLineWidth(m_streamHelper->getRequiredAttributeFloatValue(attributes, + annotation->setLineWidthPixelsObsolete(m_streamHelper->getRequiredAttributeFloatValue(attributes, annotationElementName, - ATTRIBUTE_FOREGROUND_LINE_WIDTH)); + ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS)); + + /* + * Line width percentage added on July 26, 2017. + * A "negative value" indicates it is missing and the percentage width + * may be set by graphics code that attempts to set the percentage using + * the obsolete pixel width and viewport height. + */ + annotation->setLineWidthPercentage(m_streamHelper->getOptionalAttributeIntValue(attributes, + annotationElementName, + ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE, + -1.0f)); /* * Tab Index */ diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index 946147e02..3b0edb917 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -488,8 +488,11 @@ AnnotationFileXmlWriter::getAnnotationPropertiesAsAttributes(const Annotation* a attributes.append(ATTRIBUTE_FOREGROUND_CUSTOM_RGBA, realArrayToString(rgba, 4)); - attributes.append(ATTRIBUTE_FOREGROUND_LINE_WIDTH, - QString::number(annotation->getLineWidth())); + attributes.append(ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS, + QString::number(annotation->getLineWidthPixelsObsolete())); + + attributes.append(ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE, + QString::number(annotation->getLineWidthPercentage())); attributes.append(ATTRIBUTE_TAB_INDEX, QString::number(annotation->getTabIndex())); diff --git a/src/Files/XmlStreamReaderHelper.cxx b/src/Files/XmlStreamReaderHelper.cxx index 92e25b0bb..34712bf96 100644 --- a/src/Files/XmlStreamReaderHelper.cxx +++ b/src/Files/XmlStreamReaderHelper.cxx @@ -241,6 +241,42 @@ XmlStreamReaderHelper::getRequiredAttributeBoolValue(const QXmlStreamAttributes& return value; } +/** + * Get the int value for the given attribute name from the + * given attributes. If the attribute is missing or if the + * attributes value is empty text, the defaultValue is + * returned. This method WILL NOT throw an exception. + * + * @param attributes + * The XML attributes. + * @param elementName + * Name of element containing the attributes. + * @param attributeName + * Name of the attribute. + * @param defaultValue + * Value that is returned if the attribute is missing. + * @return + * int value for the attribute. + * @throw + * DataFileException if attribute is missing or value is + * an empty string. + */ +int +XmlStreamReaderHelper::getOptionalAttributeIntValue(const QXmlStreamAttributes& attributes, + const QString& elementName, + const QString& attributeName, + const int defaultValue) +{ + const AString stringValue = getOptionalAttributeStringValue(attributes, + elementName, + attributeName, + AString::number(defaultValue)); + + const int value = stringValue.toInt(); + + return value; +} + /** * Get the int value for the given attribute name from the * given attributes. If the attribute name is not found or diff --git a/src/Files/XmlStreamReaderHelper.h b/src/Files/XmlStreamReaderHelper.h index 3b1e5f857..3876684eb 100644 --- a/src/Files/XmlStreamReaderHelper.h +++ b/src/Files/XmlStreamReaderHelper.h @@ -49,6 +49,11 @@ namespace caret { const QString& alternateAttributeNameOne = "", const QString& alternateAttributeNameTwo = ""); + int getOptionalAttributeIntValue(const QXmlStreamAttributes& attributes, + const QString& elementName, + const QString& attributeName, + const int defaultValue); + int getRequiredAttributeIntValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName); diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 7ffec8365..601d519a7 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -686,7 +686,7 @@ AnnotationColorWidget::lineThicknessSpinBoxValueChanged(double value) } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); - Annotation::setUserDefaultLineWidth(value); + Annotation::setUserDefaultLineWidthPixels(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } @@ -708,7 +708,7 @@ AnnotationColorWidget::updateLineThicknessSpinBox() const int32_t numAnnotations = static_cast(m_lineThicknessAnnotations.size()); if (numAnnotations > 0) { for (int32_t i = 0; i < numAnnotations; i++) { - const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidth(); + const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidthPixelsObsolete(); if (lineWidthValid) { if (annLineWidth != lineWidthValue) { haveMultipleLineWidthValues = true; @@ -725,7 +725,7 @@ AnnotationColorWidget::updateLineThicknessSpinBox() if (lineWidthValid) { switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: - Annotation::setUserDefaultLineWidth(lineWidthValue); + Annotation::setUserDefaultLineWidthPixels(lineWidthValue); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); -- GitLab From a3136fa848c6a203ab6d3ed15b946fac43758ad7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 26 Jul 2017 15:56:50 -0500 Subject: [PATCH 335/755] Removed limits on minimum and maximum values for annotation coordinates in the annotation toolbar. Limited the width of the annotation coordinate spin boxes. Otherwise, they will resize to the width of 14 (check Qt documentation to verify) and make the browser window very wide. --- src/Annotations/Annotation.cxx | 1 - src/GuiQt/AnnotationCoordinateWidget.cxx | 66 ++++++++++++++++-------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index fe1a5ef28..9c4ca8548 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -2075,7 +2075,6 @@ Annotation::setUserDefaultLineWidthPixels(const float lineWidthPixels) { s_userDefaultLineWidthPixels = lineWidthPixels; } -static void setUserDefaultLineWidthPercentage(const float lineWidthPercentage); /** * Set the default value for line width percentage diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 0b061e2d7..b1333ace1 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -143,6 +143,11 @@ m_browserWindowIndex(browserWindowIndex) " 0.0% => Toward's viewer\n" " 100.0% => Away from viewer\n"); + const float spinBoxMaximumWidth = 80.0f; + m_xCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); + m_yCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); + m_zCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); + m_surfaceOffsetVectorTypeComboBox = new EnumComboBoxTemplate(this); m_surfaceOffsetVectorTypeComboBox->setup(); QObject::connect(m_surfaceOffsetVectorTypeComboBox, SIGNAL(itemActivated()), @@ -274,42 +279,55 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) coordinate->getXYZ(xyz); bool viewportSpaceFlag = false; + const double percentageMinimum = 0.0; + const double percentageMaximum = 100.0; + const double zDepthMinimum = 0.0; + const double zDepthMaximum = 100.0; + const double coordinateMinimum = -std::numeric_limits::max(); + const double coordinateMaximum = std::numeric_limits::max(); double xMin = 0.0; - double xMax = 100.0; + double xMax = 0.0; double yMin = 0.0; - double yMax = 100.0; - double zMin = -100.0; - double zMax = 100.0; + double yMax = 0.0; + double zMin = 0.0; + double zMax = 0.0; double xyzStep = 0.1; - QString suffix("%"); + QString suffix; switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: - xMax = 1000000.0; - xMin = -xMax; - yMax = 1000000.0; - yMin = -yMax; - zMin = xMin; - zMax = xMax; + xMin = coordinateMinimum; + xMax = coordinateMaximum; + yMin = coordinateMinimum; + yMax = coordinateMaximum; + zMin = coordinateMinimum; + zMax = coordinateMaximum; xyzStep = 1.0; - suffix.clear(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - xMax = 10000.0; - xMin = -xMax; - yMax = 10000.0; - yMin = -yMax; - zMin = xMin; - zMax = xMax; + xMin = coordinateMinimum; + xMax = coordinateMaximum; + yMin = coordinateMinimum; + yMax = coordinateMaximum; + zMin = coordinateMinimum; + zMax = coordinateMaximum; xyzStep = 1.0; - suffix.clear(); break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: - zMin = 0.0; + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + zMin = zDepthMinimum; + zMax = zDepthMaximum; + suffix = "%"; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: + /* + * Cannot move + */ xMin = xyz[0]; xMax = xyz[0]; yMin = xyz[1]; @@ -319,7 +337,13 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) viewportSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: - zMin = 0.0; + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + zMin = zDepthMinimum; + zMax = zDepthMaximum; + suffix = "%"; break; } -- GitLab From eb26fcbdcafcc77baf101434b3eaee0b4479cf4d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 27 Jul 2017 12:30:10 -0500 Subject: [PATCH 336/755] Added a percentage width to annotations. For previously created annotations, the percentage width is invalid. When an older annotation with an invalid percentage width is drawn for the first time, the obsolete pixel width is converted to a percentage width using the height of the viewport in which the annotation is drawn. This new percentage width is then updated in the annotation which can have its file saved or scene saved (scene annotations). --- src/Annotations/Annotation.cxx | 44 ++++++++++----- src/Annotations/Annotation.h | 8 +-- src/Annotations/AnnotationRedoUndoCommand.cxx | 4 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 53 ++++++++++++++++--- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 2 + src/Files/AnnotationFileXmlReader.cxx | 2 +- src/GuiQt/AnnotationColorWidget.cxx | 9 ++-- 7 files changed, 91 insertions(+), 31 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 9c4ca8548..ae814df6d 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -428,7 +428,7 @@ Annotation::initializeAnnotationMembers() break; case AnnotationAttributesDefaultTypeEnum::USER: { - m_lineWidthPixels = s_userDefaultLineWidthPixels; + m_lineWidthPixels = s_userDefaultLineWidthPixelsObsolete; m_lineWidthPercentage = s_userDefaultLineWidthPercentage; m_colorBackground = s_userDefaultColorBackground; @@ -753,6 +753,36 @@ Annotation::toString() const return msg; } +/** + * Convert the annotation's obsolete line width that was in pixels to a percentage of viewport height. + * Prior to late July, 2017, a line was specified in pixels. + * + * First, the annotation's percentage width is examined. If it is valid (greater than zero), then + * no conversion is needed. Otherwise, use the viewport height to convert the pixel width to a + * percentage and set the annotation's percentage line width. + * + * Note that even though this method is 'const' it may cause the modification status to change + * to modified. + * + * @param viewportHeight + * The height of the viewport in pixels. + */ +void +Annotation::convertObsoleteLineWidthPixelsToPercentageWidth(const float viewportHeight) const +{ + if (m_lineWidthPercentage > 0.0f) { + return; + } + + float percentWidth = 1.0f; + if (viewportHeight > 0.0f) { + percentWidth = (m_lineWidthPixels / viewportHeight) * 100.0f; + } + + const_cast(this)->setLineWidthPercentage(percentWidth); +} + + /** * @return The line width in pixels. */ @@ -2064,18 +2094,6 @@ Annotation::setUserDefaultCustomBackgroundColor(const float rgba[4]) s_userDefaultCustomColorBackground[3] = rgba[3]; } -/** - * Set the default value for line width pixels - * - * @param lineWidthPixels - * Default for newly created annotations. - */ -void -Annotation::setUserDefaultLineWidthPixels(const float lineWidthPixels) -{ - s_userDefaultLineWidthPixels = lineWidthPixels; -} - /** * Set the default value for line width percentage * diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index a4f2c62fa..fcf72768d 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -197,6 +197,8 @@ namespace caret { void setCustomBackgroundColor(const uint8_t rgba[4]); + void convertObsoleteLineWidthPixelsToPercentageWidth(const float viewportHeight) const; + float getLineWidthPixelsObsolete() const; void setLineWidthPixelsObsolete(const float lineWidthPixels); @@ -219,8 +221,6 @@ namespace caret { static void setUserDefaultCustomBackgroundColor(const float rgba[4]); - static void setUserDefaultLineWidthPixels(const float lineWidthPixels); - static void setUserDefaultLineWidthPercentage(const float lineWidthPercentage); virtual bool isFixedAspectRatio() const; @@ -411,7 +411,7 @@ namespace caret { static float s_userDefaultCustomColorBackground[4]; - static float s_userDefaultLineWidthPixels; + static float s_userDefaultLineWidthPixelsObsolete; static float s_userDefaultLineWidthPercentage; @@ -436,7 +436,7 @@ namespace caret { float Annotation::s_userDefaultCustomColorBackground[4] = { 0.0, 0.0, 0.0, 1.0 }; - float Annotation::s_userDefaultLineWidthPixels = 3.0f; + float Annotation::s_userDefaultLineWidthPixelsObsolete = 3.0f; float Annotation::s_userDefaultLineWidthPercentage = 1.0f; #endif // __ANNOTATION_DECLARE__ diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index 97e7b95da..f63a2b902 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -220,7 +220,7 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, break; case AnnotationRedoUndoCommandModeEnum::LINE_WIDTH_FOREGROUND: if (annotation->testProperty(Annotation::Property::LINE_THICKNESS)) { - annotation->setLineWidthPixelsObsolete(annotationValue->getLineWidthPixelsObsolete()); + annotation->setLineWidthPercentage(annotationValue->getLineWidthPercentage()); } break; case AnnotationRedoUndoCommandModeEnum::LOCATION_AND_SIZE: @@ -1039,7 +1039,7 @@ AnnotationRedoUndoCommand::setModeLineWidth(const float newLineWidth, CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); - redoAnnotation->setLineWidthPixelsObsolete(newLineWidth); + redoAnnotation->setLineWidthPercentage(newLineWidth); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 6b1b23a0b..286da285e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1193,7 +1193,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 }; - const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidthPixelsObsolete()); + if (box->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(box); + } + const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidthPercentage()); const bool depthTestFlag = isDrawnWithDepthTesting(box); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); @@ -1903,7 +1906,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi const float majorAxis = ((oval->getWidth() / 100.0) * (m_modelSpaceViewport[2] / 2.0)); const float minorAxis = ((oval->getHeight() / 100.0) * (m_modelSpaceViewport[3] / 2.0)); const float rotationAngle = oval->getRotationAngle(); - const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidthPixelsObsolete()); + + if (oval->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(oval); + } + const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidthPercentage()); const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, @@ -2081,9 +2088,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin annXYZ); } + if (text->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(text); + } + const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); createLineCoordinates(annXYZ, brainordinateXYZ, - getLineWidthFromPercentageHeight(text->getLineWidthPixelsObsolete()), + lineWidth, false, showArrowFlag, lineCoordinatesOut); @@ -2289,9 +2300,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi connectLineCoordinates); if ( ! connectLineCoordinates.empty()) { + if (text->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(text); + } + const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, textColorRGBA, - getLineWidthFromPercentageHeight(text->getLineWidthPixelsObsolete())); + lineWidth); } if (drawTextFlag) { @@ -2516,9 +2531,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } if (drawForegroundFlag) { + if (image->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(image); + } + const float lineWidth = getLineWidthFromPercentageHeight(image->getLineWidthPercentage()); BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, foregroundRGBA, - getLineWidthFromPercentageHeight(image->getLineWidthPixelsObsolete())); + lineWidth); } setDepthTestingStatus(depthTestFlag); @@ -2694,7 +2713,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi lineTailXYZ)) { return false; } - const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPixelsObsolete()); + + if (line->getLineWidthPercentage() <= 0.0) { + convertObsoleteLineWidthPixelsToPercentageWidth(line); + } + const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPercentage()); const float backgroundLineWidth = lineWidth + 4; const float selectionCenterXYZ[3] = { @@ -3348,4 +3371,22 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthFromPercentageHeight(cons return widthPixels; } +/** + * Convert the annotation's obsolete line width that was in pixels to a percentage of viewport height. + * Prior to late July, 2017, a line was specified in pixels. + * + * First, the annotation's percentage width is examined. If it is valid (greater than zero), then + * no conversion is needed. Otherwise, use the viewport height to convert the pixel width to a + * percentage and set the annotation's percentage line width. + * + * @param annotation + * The annotation. + */ +void +BrainOpenGLAnnotationDrawingFixedPipeline::convertObsoleteLineWidthPixelsToPercentageWidth(const Annotation* annotation) const +{ + annotation->convertObsoleteLineWidthPixelsToPercentageWidth(m_modelSpaceViewport[3]); +} + + diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index e6b115c5c..d57ab76d9 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -302,6 +302,8 @@ namespace caret { const float startXYZ[3], float endXYZ[3]) const; + void convertObsoleteLineWidthPixelsToPercentageWidth(const Annotation* annotation) const; + float getLineWidthFromPercentageHeight(const float percentageHeight) const; BrainOpenGLFixedPipeline* m_brainOpenGLFixedPipeline; diff --git a/src/Files/AnnotationFileXmlReader.cxx b/src/Files/AnnotationFileXmlReader.cxx index e2caf8905..aab0fb224 100644 --- a/src/Files/AnnotationFileXmlReader.cxx +++ b/src/Files/AnnotationFileXmlReader.cxx @@ -551,7 +551,7 @@ AnnotationFileXmlReader::readAnnotationAttributes(Annotation* annotation, * may be set by graphics code that attempts to set the percentage using * the obsolete pixel width and viewport height. */ - annotation->setLineWidthPercentage(m_streamHelper->getOptionalAttributeIntValue(attributes, + annotation->setLineWidthPercentage(m_streamHelper->getOptionalAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE, -1.0f)); diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index 601d519a7..fc51bbf82 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -150,8 +150,7 @@ m_browserWindowIndex(browserWindowIndex) this, SLOT(lineThicknessSpinBoxValueChanged(double))); WuQtUtilities::setWordWrappedToolTip(m_lineThicknessSpinBox, - "Adjust the line thickness"); - //m_lineThicknessSpinBox->setFixedWidth(45); + "Adjust the line thickness as percentage of tab/window height"); m_lineThicknessSpinBox->setSuffix("%"); m_lineThicknessWidgetGroup->add(lineLabel); @@ -686,7 +685,7 @@ AnnotationColorWidget::lineThicknessSpinBoxValueChanged(double value) } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); - Annotation::setUserDefaultLineWidthPixels(value); + Annotation::setUserDefaultLineWidthPercentage(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } @@ -708,7 +707,7 @@ AnnotationColorWidget::updateLineThicknessSpinBox() const int32_t numAnnotations = static_cast(m_lineThicknessAnnotations.size()); if (numAnnotations > 0) { for (int32_t i = 0; i < numAnnotations; i++) { - const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidthPixelsObsolete(); + const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidthPercentage(); if (lineWidthValid) { if (annLineWidth != lineWidthValue) { haveMultipleLineWidthValues = true; @@ -725,7 +724,7 @@ AnnotationColorWidget::updateLineThicknessSpinBox() if (lineWidthValid) { switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: - Annotation::setUserDefaultLineWidthPixels(lineWidthValue); + Annotation::setUserDefaultLineWidthPercentage(lineWidthValue); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); -- GitLab From cd4d81826dd69bb282d417b7a2d6b92d6ea996f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 27 Jul 2017 15:03:49 -0500 Subject: [PATCH 337/755] Implemented percentage outline width for text rendering. For previously created text annotations, the percentage line width is invalid. When an older text annotation with an invalid percentage width is drawn for the first time, the obsolete pixel line width is converted to a percentage line width using the height of the viewport in which the text annotation is drawn. This new percentage line width is then updated in the text annotation which can have its file saved or scene saved (scene annotations). --- src/Annotations/Annotation.h | 9 +++++---- src/Brain/FtglFontTextRenderer.cxx | 26 +++++++++++++------------- src/Brain/FtglFontTextRenderer.h | 4 ---- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index fcf72768d..63b02f7bb 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -199,10 +199,6 @@ namespace caret { void convertObsoleteLineWidthPixelsToPercentageWidth(const float viewportHeight) const; - float getLineWidthPixelsObsolete() const; - - void setLineWidthPixelsObsolete(const float lineWidthPixels); - float getLineWidthPercentage() const; void setLineWidthPercentage(const float lineWidthPercentage); @@ -347,6 +343,10 @@ namespace caret { void clearDrawnInWindowStatusForAllWindows(); private: + float getLineWidthPixelsObsolete() const; + + void setLineWidthPixelsObsolete(const float lineWidthPixels); + void setAnnotationGroupKey(const AnnotationGroupKey& annotationGroupKey); void invalidateAnnotationGroupKey(); @@ -419,6 +419,7 @@ namespace caret { friend class AnnotationFile; friend class AnnotationFileXmlReader; + friend class AnnotationFileXmlWriter; friend class AnnotationGroup; friend class AnnotationManager; }; diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index d2f01dc34..a0403963f 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -453,7 +453,7 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText ts->m_stringGlyphsMaxX, underlineY, z, - textStringGroup.m_underlineThickness, + ts->m_underlineThickness, foregroundRgba); glPopMatrix(); @@ -470,7 +470,7 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText ts->m_stringGlyphsMinY, ts->m_stringGlyphsMaxY, z, - textStringGroup.m_outlineThickness, + ts->m_outlineThickness, foregroundRgba); glPopMatrix(); @@ -738,7 +738,10 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth m_depthTestingStatus = depthTesting; - const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPixelsObsolete()); + if (annotationText.getLineWidthPercentage() <= 0.0f) { + annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); + } + const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPercentage()); TextStringGroup tsg(annotationText, font, @@ -808,7 +811,10 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann + AString((char*)gluErrorString(errorCode))); } - double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPixelsObsolete()); + if (annotationText.getLineWidthPercentage() <= 0.0f) { + annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); + } + double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPercentage()); TextStringGroup textStringGroup(annotationText, font, @@ -1697,9 +1703,7 @@ m_viewportX(viewportX), m_viewportY(viewportY), m_viewportZ(viewportZ), m_rotationAngle(rotationAngle), -m_lineThicknessForViewportHeight(lineThicknessForViewportHeight), m_underlineThickness(0.0), -m_outlineThickness(0.0), m_viewportBoundsMinX(0.0), m_viewportBoundsMaxX(0.0), m_viewportBoundsMinY(0.0), @@ -1732,13 +1736,9 @@ m_viewportBoundsMaxY(0.0) * Outline is drawn anytime thickness is greater than zero * and is drawn using the foreground color */ + float outlineThickness = 0.0; if (annotationText.getLineColor() != CaretColorEnum::NONE) { - if (annotationText.getOrientation() == AnnotationTextOrientationEnum::HORIZONTAL) { - const double outlineThickness = m_annotationText.getLineWidthPixelsObsolete(); - if (outlineThickness > 0.0) { - m_outlineThickness = m_lineThicknessForViewportHeight; - } - } + outlineThickness = lineThicknessForViewportHeight; } /* @@ -1753,7 +1753,7 @@ m_viewportBoundsMaxY(0.0) TextString* ts = new TextString(textList.at(i), annotationText.getOrientation(), m_underlineThickness, - m_outlineThickness, + outlineThickness, font); m_textStrings.push_back(ts); } diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index 265338bbd..938670ddb 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -259,12 +259,8 @@ namespace caret { const double m_rotationAngle; - const double m_lineThicknessForViewportHeight; - double m_underlineThickness; - double m_outlineThickness; - /* * Bounds relative to origin of first character */ -- GitLab From 96be24a91938b53d8c25a2705e47560c6cdb9d08 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 27 Jul 2017 15:25:20 -0500 Subject: [PATCH 338/755] In Annotations Editing Mode, the Edit Menu --> Select All item was not enabled and has been fixed. --- src/GuiQt/UserInputModeAnnotations.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 5363a3dbb..28881437f 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -1651,9 +1651,7 @@ UserInputModeAnnotations::getEnabledEditMenuItems(std::vectorisAnnotationOnClipboardValid()) { -- GitLab From 370e31c50acc67a3ba7913cb31818d7ae8aeff42 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 09:58:32 -0500 Subject: [PATCH 339/755] Increase decimals for chart annotation space to 3. --- src/GuiQt/AnnotationCoordinateWidget.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index b1333ace1..775e9f9a5 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -293,6 +293,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) double zMax = 0.0; double xyzStep = 0.1; QString suffix; + int32_t digitsRightOfDecimal = 1; switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: xMin = coordinateMinimum; @@ -301,6 +302,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) yMax = coordinateMaximum; zMin = coordinateMinimum; zMax = coordinateMaximum; + digitsRightOfDecimal = 3; xyzStep = 1.0; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: @@ -354,6 +356,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_xCoordSpinBox->setSuffix(suffix); m_xCoordSpinBox->setValue(xyz[0]); m_xCoordSpinBox->blockSignals(false); + m_xCoordSpinBox->setDecimals(digitsRightOfDecimal); m_yCoordSpinBox->blockSignals(true); m_yCoordSpinBox->setRange(yMin, @@ -362,6 +365,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_yCoordSpinBox->setSuffix(suffix); m_yCoordSpinBox->setValue(xyz[1]); m_yCoordSpinBox->blockSignals(false); + m_yCoordSpinBox->setDecimals(digitsRightOfDecimal); m_zCoordSpinBox->blockSignals(true); m_zCoordSpinBox->setRange(zMin, @@ -370,6 +374,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_zCoordSpinBox->setSuffix(suffix); m_zCoordSpinBox->setValue(xyz[2]); m_zCoordSpinBox->blockSignals(false); + m_zCoordSpinBox->setDecimals(digitsRightOfDecimal); if (surfaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; -- GitLab From 860695dbe040eab235b3e4bf507433ae83e41130 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 11:04:03 -0500 Subject: [PATCH 340/755] Added CaretOpenGLWindowsFunctionsKludge.h that contains OpenGL function and constant definitions so that source will compile on windows. An enumerated type value 'DELETE' will not compile on windows and has been replaced with 'DELETION' in Annotation.h. --- src/Annotations/Annotation.cxx | 6 +- src/Annotations/Annotation.h | 4 +- src/Brain/AnnotationManager.cxx | 2 +- src/Graphics/CMakeLists.txt | 1 + src/Graphics/CaretOpenGLInclude.h | 1 + .../CaretOpenGLWindowsFunctionsKludge.h | 83 +++++++++++++++++++ src/GuiQt/AnnotationDeleteWidget.cxx | 2 +- src/GuiQt/UserInputModeAnnotations.cxx | 2 +- .../UserInputModeAnnotationsContextMenu.cxx | 4 +- 9 files changed, 95 insertions(+), 10 deletions(-) create mode 100755 src/Graphics/CaretOpenGLWindowsFunctionsKludge.h diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index ae814df6d..0377eb3ed 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -1193,7 +1193,7 @@ Annotation::initializeProperties() if (colorBarFlag) { resetProperty(Property::ARRANGE); resetProperty(Property::COPY_CUT_PASTE); - resetProperty(Property::DELETE); + resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); @@ -1237,7 +1237,7 @@ Annotation::setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage sp resetProperty(Property::ARRANGE); resetProperty(Property::COORDINATE); resetProperty(Property::COPY_CUT_PASTE); - resetProperty(Property::DELETE); + resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); @@ -1254,7 +1254,7 @@ Annotation::setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage sp resetProperty(Property::ARRANGE); resetProperty(Property::COORDINATE); resetProperty(Property::COPY_CUT_PASTE); - resetProperty(Property::DELETE); + resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::ROTATION); diff --git a/src/Annotations/Annotation.h b/src/Annotations/Annotation.h index 63b02f7bb..3693529b7 100644 --- a/src/Annotations/Annotation.h +++ b/src/Annotations/Annotation.h @@ -54,8 +54,8 @@ namespace caret { COORDINATE, /** Annotation allows cut, copy, and paste by user*/ COPY_CUT_PASTE, - /** Annotation may be deleted by user */ - DELETE, + /** Annotation may be deleted by user (note 'DELETE' will not compile on windows) */ + DELETION, /** Annotation display controlled by Display Group and Tab */ DISPLAY_GROUP, /** Annotation has fill (background) color */ diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index efbebf2d1..46549ac34 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -396,7 +396,7 @@ AnnotationManager::isAnnotationSelectedForEditingDeletable(const int32_t windowI iter != selectedAnnotations.end(); iter++) { const Annotation* ann = *iter; - if ( ! ann->testProperty(Annotation::Property::DELETE)) { + if ( ! ann->testProperty(Annotation::Property::DELETION)) { selectedAnnotationsDeletableFlag = false; break; } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index aad89faa0..062afeabd 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -33,6 +33,7 @@ ENDIF (OPENGL_FOUND) # ADD_LIBRARY(Graphics CaretOpenGLInclude.h +CaretOpenGLWindowsFunctionsKludge.h EventGraphicsOpenGLCreateBufferObject.h EventGraphicsOpenGLCreateTextureName.h EventGraphicsOpenGLDeleteBufferObject.h diff --git a/src/Graphics/CaretOpenGLInclude.h b/src/Graphics/CaretOpenGLInclude.h index d90329cdb..0355afb6a 100644 --- a/src/Graphics/CaretOpenGLInclude.h +++ b/src/Graphics/CaretOpenGLInclude.h @@ -29,6 +29,7 @@ #ifdef CARET_OS_WINDOWS #include +#include "CaretOpenGLWindowsFunctionsKludge.h" #endif #ifdef CARET_OS_MACOSX #include diff --git a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h new file mode 100755 index 000000000..9844e9793 --- /dev/null +++ b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h @@ -0,0 +1,83 @@ + +/** + * Created on July 28, 2017 by John Harwell + * This is a temporary kludge to fix errors on Windows. + * This file contains OpenGL definitions that are missing on windows. + */ +#ifndef __CARET_KLUDGE_h_ +#define __CARET_KLUDGE_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2017 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** https://github.com/KhronosGroup/OpenGL-Registry +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#include +#include + +/* Generated C header for: + * API: gl + * Profile: compatibility + * Versions considered: .* + * Versions emitted: 1\.[2-9]|[234]\.[0-9] + * Default extensions included: gl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E + +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GuiQt/AnnotationDeleteWidget.cxx b/src/GuiQt/AnnotationDeleteWidget.cxx index 9c6bf7245..a6dd38cd0 100644 --- a/src/GuiQt/AnnotationDeleteWidget.cxx +++ b/src/GuiQt/AnnotationDeleteWidget.cxx @@ -151,7 +151,7 @@ AnnotationDeleteWidget::deleteActionTriggered() std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); std::vector deleteAnnotations; for (auto a : selectedAnnotations) { - if (a->testProperty(Annotation::Property::DELETE)) { + if (a->testProperty(Annotation::Property::DELETION)) { deleteAnnotations.push_back(a); } } diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 28881437f..11bd49584 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -1630,7 +1630,7 @@ UserInputModeAnnotations::getEnabledEditMenuItems(std::vectortestProperty(Annotation::Property::COPY_CUT_PASTE)) { allAllowCopyCutPasteFlag = false; } - if ( ! ann->testProperty(Annotation::Property::DELETE)) { + if ( ! ann->testProperty(Annotation::Property::DELETION)) { allAllowDeleteFlag = false; } } diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index e493f487d..fcec0b043 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -130,7 +130,7 @@ m_newAnnotationCreatedByContextMenu(NULL) m_threeDimCoordAnnotations.push_back(ann); } - if ( ! ann->testProperty(Annotation::Property::DELETE)) { + if ( ! ann->testProperty(Annotation::Property::DELETION)) { allSelectedAnnotationsDeletableFlag = false; } } @@ -143,7 +143,7 @@ m_newAnnotationCreatedByContextMenu(NULL) m_annotationFile = selectedAnnotations[0].second; m_annotation = selectedAnnotations[0].first; oneAnnotationSelectedFlag = true; - if (m_annotation->testProperty(Annotation::Property::DELETE)) { + if (m_annotation->testProperty(Annotation::Property::DELETION)) { oneDeletableAnnotationSelectedFlag = true; } } -- GitLab From 0a3182f6c6514fa0fe0d3e0bfe6aae721ac56683 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 11:15:17 -0500 Subject: [PATCH 341/755] Added more definitions to Graphics/CaretOpenGLWindowsFunctionsKludge.h --- src/Graphics/CaretOpenGLWindowsFunctionsKludge.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h index 9844e9793..655adfc68 100755 --- a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h +++ b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h @@ -70,6 +70,11 @@ extern "C" { * Extensions removed: _nomatch_^ */ #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -- GitLab From a216f28f4ca0313e687516e2f07f678cb5b73faf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 11:23:55 -0500 Subject: [PATCH 342/755] Added more definitions to Graphics/CaretOpenGLWindowsFunctionsKludge.h. added glBufferData and glBindBuffer --- src/Graphics/CaretOpenGLWindowsFunctionsKludge.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h index 655adfc68..b850f7126 100755 --- a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h +++ b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h @@ -79,6 +79,8 @@ extern "C" { GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); #ifdef __cplusplus -- GitLab From 96837132e01d0c09fb7b9a4b962093bf273f8098 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 11:30:02 -0500 Subject: [PATCH 343/755] Added more definitions to Graphics/CaretOpenGLWindowsFunctionsKludge.h. Added typedef ptrdiff_t GLsizeiptr --- src/Graphics/CaretOpenGLWindowsFunctionsKludge.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h index b850f7126..41fe5577b 100755 --- a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h +++ b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h @@ -76,6 +76,8 @@ extern "C" { #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 +typedef ptrdiff_t GLsizeiptr; + GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -- GitLab From a046d5d6a1b2028fe9b9beb59f16da8e3b8eec3b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 28 Jul 2017 11:58:22 -0500 Subject: [PATCH 344/755] Updated Desktop/CMakeLists.txt to try to find OpenGL on windows. --- src/Desktop/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index f28af31be..618073524 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -34,6 +34,13 @@ IF (UNIX) IF (NOT APPLE) FIND_PACKAGE(OpenGL) ENDIF (NOT APPLE) +ELSE (UNIX) + FIND_PACKAGE(OpenGL) + #INCLUDE(${OPENGL_INCLUDE_DIR}) + + MESSAGE("OpenGL Include Dir: ${OPENGL_INCLUDE_DIR}") + MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") + MESSAGE("OpenGL Library path ${OPENGL_gl_LIBRARY}") ENDIF (UNIX) # -- GitLab From cf1faad575229c6519aee2b773f3e50b3d89e17e Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 7 Aug 2017 18:31:24 -0500 Subject: [PATCH 345/755] don't try to split gcc version into components since we don't need it - it can report only one component, breaking the build script --- src/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b5325a8f..32fb803e6 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -99,10 +99,7 @@ IF (NOT MSVC) if (CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) - list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) - list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) - message("gcc major minor version numbers are: " ${GCC_MAJOR},${GCC_MINOR}) + message("gcc version is: " ${GCC_VERSION}) if(${GCC_VERSION} VERSION_LESS "4.2") ADD_DEFINITIONS(-W -Wall) else() -- GitLab From 8f288f6869af24dac9c0b5bb31d2d73032880c93 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 7 Aug 2017 16:02:45 -0500 Subject: [PATCH 346/755] When only a volume file was loaded, the Chart Two model was selected for viewing in the browser window instead of the volume file. This was caused by the Chart Two model always being valid. This has been changed so that the Chart Two model is only valid if at least one data file is loaded that contains a valid chart two data type. In addition, if all files were removed, several Toolbar --> View mode buttons were still selectable and this has also been corrected. --- src/Brain/Brain.cxx | 49 ++++++++++++++++++++----- src/Brain/BrowserTabContent.cxx | 19 ++++------ src/GuiQt/BrainBrowserWindowToolBar.cxx | 8 ++++ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index c878d5e0d..28b08087e 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -38,6 +38,7 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartingDataManager.h" +#include "ChartableTwoFileDelegate.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiBrainordinateLabelFile.h" @@ -4718,13 +4719,43 @@ Brain::updateChartModel() } } - if (m_modelChartTwo == NULL) { - m_modelChartTwo = new ModelChartTwo(this); - EventModelAdd eventAddModel(m_modelChartTwo); - EventManager::get()->sendEvent(eventAddModel.getPointer()); - - if (m_isSpecFileBeingRead == false) { - m_modelChartTwo->initializeOverlays(); + /* + * For Chart Two, test for any files that report a valid charting data type + * and then update (add/remove charting two model) + */ + EventCaretMappableDataFilesGet allMapFilesEvent; + EventManager::get()->sendEvent(allMapFilesEvent.getPointer()); + std::vector allMapFiles; + allMapFilesEvent.getAllFiles(allMapFiles); + + bool haveChartableFileFlag = false; + for (auto mapFile : allMapFiles) { + CaretAssert(mapFile); + std::vector chartDataTypes; + mapFile->getChartingDelegate()->getSupportedChartTwoDataTypes(chartDataTypes); + if ( ! chartDataTypes.empty()) { + haveChartableFileFlag = true; + break; + } + } + + if (haveChartableFileFlag) { + if (m_modelChartTwo == NULL) { + m_modelChartTwo = new ModelChartTwo(this); + EventModelAdd eventAddModel(m_modelChartTwo); + EventManager::get()->sendEvent(eventAddModel.getPointer()); + + if (m_isSpecFileBeingRead == false) { + m_modelChartTwo->initializeOverlays(); + } + } + } + else { + if (m_modelChartTwo != NULL) { + EventModelDelete eventDeleteModel(m_modelChartTwo); + EventManager::get()->sendEvent(eventDeleteModel.getPointer()); + delete m_modelChartTwo; + m_modelChartTwo = NULL; } } } @@ -5259,10 +5290,10 @@ void Brain::updateAfterFilesAddedOrRemoved() { updateBrainStructures(); - updateChartModel(); + updateSurfaceMontageModel(); updateVolumeSliceModel(); updateWholeBrainModel(); - updateSurfaceMontageModel(); + updateChartModel(); updateFiberTrajectoryMatchingFiberOrientationFiles(); } diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index f14c94878..2eee77f44 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -930,14 +930,12 @@ BrowserTabContent::getOverlaySet() const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() { + if (m_chartTwoModel == NULL) { + return NULL; + } + CaretAssert(m_chartTwoModel); return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); - -// Model* model = getModelForDisplay(); -// if (model != NULL) { -// return model->getChartTwoOverlaySet(m_tabNumber); -// } -// return NULL; } /** @@ -946,14 +944,11 @@ BrowserTabContent::getChartTwoOverlaySet() const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() const { + if (m_chartTwoModel == NULL) { + return NULL; + } CaretAssert(m_chartTwoModel); return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); - -// const Model* model = getModelForDisplay(); -// if (model != NULL) { -// return model->getChartTwoOverlaySet(m_tabNumber); -// } -// return NULL; } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index fef737dca..3f031623c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1692,6 +1692,14 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent this->viewModeChartOneRadioButton->setEnabled(browserTabContent->isChartOneModelValid()); this->viewModeChartTwoRadioButton->setEnabled(browserTabContent->isChartTwoModelValid()); } + else { + this->viewModeSurfaceRadioButton->setEnabled(false); + this->viewModeSurfaceMontageRadioButton->setEnabled(false); + this->viewModeVolumeRadioButton->setEnabled(false); + this->viewModeWholeBrainRadioButton->setEnabled(false); + this->viewModeChartOneRadioButton->setEnabled(false); + this->viewModeChartTwoRadioButton->setEnabled(false); + } switch (modelType) { case ModelTypeEnum::MODEL_TYPE_INVALID: -- GitLab From 64da537e3156090dfb9d75c6eec98027f054a8b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 8 Aug 2017 14:33:18 -0500 Subject: [PATCH 347/755] Removed some recent kludges that were added to try and fix building on windows due to using newer OpenGL functions. --- src/Desktop/CMakeLists.txt | 7 -- src/Graphics/CMakeLists.txt | 1 - src/Graphics/CaretOpenGLInclude.h | 1 - .../CaretOpenGLWindowsFunctionsKludge.h | 92 ------------------- 4 files changed, 101 deletions(-) delete mode 100755 src/Graphics/CaretOpenGLWindowsFunctionsKludge.h diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index 618073524..f28af31be 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -34,13 +34,6 @@ IF (UNIX) IF (NOT APPLE) FIND_PACKAGE(OpenGL) ENDIF (NOT APPLE) -ELSE (UNIX) - FIND_PACKAGE(OpenGL) - #INCLUDE(${OPENGL_INCLUDE_DIR}) - - MESSAGE("OpenGL Include Dir: ${OPENGL_INCLUDE_DIR}") - MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") - MESSAGE("OpenGL Library path ${OPENGL_gl_LIBRARY}") ENDIF (UNIX) # diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 062afeabd..aad89faa0 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -33,7 +33,6 @@ ENDIF (OPENGL_FOUND) # ADD_LIBRARY(Graphics CaretOpenGLInclude.h -CaretOpenGLWindowsFunctionsKludge.h EventGraphicsOpenGLCreateBufferObject.h EventGraphicsOpenGLCreateTextureName.h EventGraphicsOpenGLDeleteBufferObject.h diff --git a/src/Graphics/CaretOpenGLInclude.h b/src/Graphics/CaretOpenGLInclude.h index 0355afb6a..d90329cdb 100644 --- a/src/Graphics/CaretOpenGLInclude.h +++ b/src/Graphics/CaretOpenGLInclude.h @@ -29,7 +29,6 @@ #ifdef CARET_OS_WINDOWS #include -#include "CaretOpenGLWindowsFunctionsKludge.h" #endif #ifdef CARET_OS_MACOSX #include diff --git a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h b/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h deleted file mode 100755 index 41fe5577b..000000000 --- a/src/Graphics/CaretOpenGLWindowsFunctionsKludge.h +++ /dev/null @@ -1,92 +0,0 @@ - -/** - * Created on July 28, 2017 by John Harwell - * This is a temporary kludge to fix errors on Windows. - * This file contains OpenGL definitions that are missing on windows. - */ -#ifndef __CARET_KLUDGE_h_ -#define __CARET_KLUDGE_h_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2013-2017 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ -/* -** This header is generated from the Khronos OpenGL / OpenGL ES XML -** API Registry. The current version of the Registry, generator scripts -** used to make the header, and the header can be found at -** https://github.com/KhronosGroup/OpenGL-Registry -*/ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -#include -#include - -/* Generated C header for: - * API: gl - * Profile: compatibility - * Versions considered: .* - * Versions emitted: 1\.[2-9]|[234]\.[0-9] - * Default extensions included: gl - * Additional extensions included: _nomatch_^ - * Extensions removed: _nomatch_^ - */ -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_STREAM_DRAW 0x88E0 -#define GL_STATIC_DRAW 0x88E4 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 - -typedef ptrdiff_t GLsizeiptr; - -GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); - - -#ifdef __cplusplus -} -#endif - -#endif -- GitLab From d20dc254d01efcea35c06bb7e30698756dc3303c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 9 Aug 2017 10:36:33 -0500 Subject: [PATCH 348/755] Added loading of line charts for scalar data files yoked to a map-index file (changing selected map in a map file loads line chart for row index from scalar data series file). --- src/Brain/ChartTwoOverlay.cxx | 33 ++++++----- src/Brain/ChartTwoOverlaySet.cxx | 17 +++++- src/Brain/ChartingDataManager.cxx | 5 ++ src/Brain/ModelChartTwo.cxx | 85 ++++++++++++++++++++-------- src/Brain/ModelChartTwo.h | 3 + src/GuiQt/MapYokingGroupComboBox.cxx | 8 ++- 6 files changed, 106 insertions(+), 45 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index f19a26e13..17f4cc4b3 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -435,32 +435,35 @@ ChartTwoOverlay::isMapYokingSupported() const bool ChartTwoOverlay::isMapYokingSupportedPrivate(const CaretMappableDataFile* mapFile) const { + if (mapFile == NULL) { + return false; + } + + if (mapFile->getNumberOfMaps() < 2) { + return false; + } + bool supportedFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - supportedFlag = true; + if (mapFile->isSurfaceMappable() + || mapFile->isVolumeMappable()) { + supportedFlag = true; + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + supportedFlag = true; + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - supportedFlag = true; - break; - } - - if (supportedFlag) { - supportedFlag = false; - - if (mapFile != NULL) { - if (mapFile->getNumberOfMaps() > 1) { - if (mapFile->isSurfaceMappable() - || mapFile->isVolumeMappable()) { - supportedFlag = true; - } + if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + supportedFlag = true; } - } + break; } return supportedFlag; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index c7c81acdb..44c3886b6 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -680,9 +680,20 @@ ChartTwoOverlaySet::receiveEvent(Event* event) if (mapFile != NULL) { if (overlay->isMapYokingSupported()) { - if (yokingGroupMapIndex < mapFile->getNumberOfMaps()) { - overlay->setSelectionData(mapFile, - yokingGroupMapIndex); + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + if (yokingGroupMapIndex < mapFile->getNumberOfMaps()) { + overlay->setSelectionData(mapFile, + yokingGroupMapIndex); + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; } if (mapFile == eventMapFile) { diff --git a/src/Brain/ChartingDataManager.cxx b/src/Brain/ChartingDataManager.cxx index 9ce6d2ee7..584477ee0 100644 --- a/src/Brain/ChartingDataManager.cxx +++ b/src/Brain/ChartingDataManager.cxx @@ -82,6 +82,11 @@ ChartingDataManager::receiveEvent(Event* event) modelChart->loadChartDataForYokedCiftiMappableFiles(yokeMapEvent->getMapYokingGroup(), yokeMapEvent->getMapIndex()); } + ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); + if (modelChartTwo != NULL) { + modelChartTwo->loadChartDataForYokedScalarDataSeriesFiles(yokeMapEvent->getMapYokingGroup(), + yokeMapEvent->getMapIndex()); + } } } diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 8a943cdcb..57718bed5 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -99,16 +99,6 @@ ModelChartTwo::ModelChartTwo(Brain* brain) m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", m_selectedChartTwoDataType); -// m_sceneAssistant->add("m_histogramChartOverlaySetArray", -// "ChartTwoOverlaySetArray", -// m_histogramChartOverlaySetArray.get()); -// m_sceneAssistant->add("m_matrixChartOverlaySetArray", -// "ChartTwoOverlaySetArray", -// m_matrixChartOverlaySetArray.get()); -// m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", -// "ChartTwoOverlaySetArray", -// m_lineSeriesChartOverlaySetArray.get()); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } @@ -247,7 +237,7 @@ ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* cifti { CaretAssert(ciftiMapFile); - std::vector tabIndices; + //std::vector tabIndices; EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); @@ -259,6 +249,65 @@ ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* cifti mapFileDataSelector); EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } + +/** + * Load line chart data for yoked CIFTI scalar data series files + * + * @param mapYokingGroup + * The map yoking group. + * @param mapIndex + * The map index. + */ +void +ModelChartTwo::loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex) +{ + if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + return; + } + + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + const std::vector tabIndices = tabIndicesEvent.getAllBrowserTabIndices(); + + /* + * Find Cifti Scalar Data Series Files in valid Chart Overlays that + * have chart line series data loading enabled + */ + std::set dataSeriesFiles; + for (auto tabIndex : tabIndices) { + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + if (m_selectedChartTwoDataType[tabIndex] == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { + const ChartTwoOverlaySet* overlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); + CaretAssert(overlaySet); + + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t iOverlay = 0; iOverlay < numOverlays; iOverlay++) { + const ChartTwoOverlay* overlay = overlaySet->getOverlay(iOverlay); + CaretAssert(overlay); + + if (overlay->isEnabled() + && overlay->isLineSeriesLoadingEnabled()) { + if (overlay->getMapYokingGroup() == mapYokingGroup) { + CaretMappableDataFile* mapFile = overlay->getSelectedMapFile(); + if (mapFile != NULL) { + if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(mapFile); + CaretAssert(scalarDataSeriesFile); + dataSeriesFiles.insert(scalarDataSeriesFile); + } + } + } + } + } + } + } + + for (auto seriesFile : dataSeriesFiles) { + loadChartDataForCiftiMappableFileRow(seriesFile, mapIndex); + } +} + /** * Receive an event. * @@ -474,15 +523,6 @@ ModelChartTwo::saveModelSpecificInformationToScene(const SceneAttributes* sceneA m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - // m_sceneAssistant->add("m_histogramChartOverlaySetArray", - // "ChartTwoOverlaySetArray", - // m_histogramChartOverlaySetArray.get()); - // m_sceneAssistant->add("m_matrixChartOverlaySetArray", - // "ChartTwoOverlaySetArray", - // m_matrixChartOverlaySetArray.get()); - // m_sceneAssistant->add("m_lineSeriesChartOverlaySetArray", - // "ChartTwoOverlaySetArray", - // m_lineSeriesChartOverlaySetArray.get()); } /** @@ -856,11 +896,6 @@ ModelChartTwo::restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, CaretAssert(chartOneMatrixDisplayProperties); -// ChartTwoMatrixDisplayProperties* chartTwoMatrixDisplayProperties = getChartTwoMatrixDisplayProperties(tabIndex); -// CaretAssert(chartTwoMatrixDisplayProperties); -// chartTwoMatrixDisplayProperties->resetPropertiesToDefault(); -// chartTwoMatrixDisplayProperties->setGridLinesDisplayed(chartOneMatrixDisplayProperties->isGridLinesDisplayed()); -// chartTwoMatrixDisplayProperties->setSelectedRowColumnHighlighted(chartOneMatrixDisplayProperties->isSelectedRowColumnHighlighted()); AnnotationColorBar* chartOneColorBar = chartOneMatrixDisplayProperties->getColorBar(); EventBrowserTabGet getTabEvent(tabIndex); diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index c8d18334d..d8ed626cc 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -74,6 +74,9 @@ namespace caret { void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); + void loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex); + virtual OverlaySet* getOverlaySet(const int tabIndex) override; virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; diff --git a/src/GuiQt/MapYokingGroupComboBox.cxx b/src/GuiQt/MapYokingGroupComboBox.cxx index a51bf45e0..1e8c58059 100644 --- a/src/GuiQt/MapYokingGroupComboBox.cxx +++ b/src/GuiQt/MapYokingGroupComboBox.cxx @@ -216,8 +216,12 @@ MapYokingGroupComboBox::validateYokingChange(ChartTwoOverlay* chartOverlay) bool selectionStatus = chartOverlay->isEnabled(); if ((mapFile != NULL) - && (chartOverlay->isMapYokingSupported()) - && (selectedIndex >= 0)) { + && chartOverlay->isMapYokingSupported()) { + if (mapFile->getNumberOfMaps() > 0) { + if (selectedIndex < 0) { + selectedIndex = 0; + } + } const YokeValidationResult result = validateYoking(mapFile, selectedIndex, selectionStatus); -- GitLab From f6cf3815314f6c3a70b127b21dcf790946e71787 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 11 Aug 2017 16:31:07 -0500 Subject: [PATCH 349/755] Added a default line width in pixels to Line Chart Files. The default line width is not saved in the data file but is saved into a scene for the data file. Adjustment of the default line width is performed on the Line Series History dialog. --- src/Charting/ChartTwoDataCartesian.cxx | 2 + src/Charting/ChartTwoLineSeriesHistory.cxx | 55 ++++++++++++++++--- src/Charting/ChartTwoLineSeriesHistory.h | 8 +++ src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 45 +++++++++++++-- src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 4 ++ 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 214ec2242..dd2b5d58a 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -513,5 +513,7 @@ ChartTwoDataCartesian::restoreFromScene(const SceneAttributes* sceneAttributes, } } } + + setColor(getColor()); } diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index f99c9fb2b..83311f121 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -174,6 +174,8 @@ ChartTwoLineSeriesHistory::initializeInstance() m_defaultColor = ChartTwoLineSeriesHistory::generateDefaultColor(); validateDefaultColor(); + m_defaultLineWidth = 1.0f; + const int32_t defaultHistoryCount = 5; m_loadingEnabled = false; @@ -184,6 +186,8 @@ ChartTwoLineSeriesHistory::initializeInstance() &m_loadingEnabled); m_sceneAssistant->add("m_defaultColor", &m_defaultColor); + m_sceneAssistant->add("m_defaultLineWidth", + &m_defaultLineWidth); m_sceneAssistant->add("m_displayCount", &m_displayCount); } @@ -204,10 +208,11 @@ ChartTwoLineSeriesHistory::copyHelperChartTwoLineSeriesHistory(const ChartTwoLin ChartTwoDataCartesian* cartData = item->clone(); CaretAssert(cartData); - addHistoryItem(cartData); + addHistoryItemNoDefaults(cartData); } m_defaultColor = obj.m_defaultColor; + m_defaultLineWidth = obj.m_defaultLineWidth; m_displayCount = obj.m_displayCount; validateDefaultColor(); } @@ -240,6 +245,30 @@ ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultCol // } } +/** + * @return Default width of lines + */ +float +ChartTwoLineSeriesHistory::getDefaultLineWidth() const +{ + return m_defaultLineWidth; +} + +/** + * Set Default width of lines + * + * @param defaultLineWidth + * New value for Default width of lines + */ +void +ChartTwoLineSeriesHistory::setDefaultLineWidth(const float defaultLineWidth) +{ + if (defaultLineWidth != m_defaultLineWidth) { + m_defaultLineWidth = defaultLineWidth; + setModified(); + } +} + /** * @return Count of items for display. */ @@ -293,7 +322,7 @@ int32_t ChartTwoLineSeriesHistory::getHistoryCount() const /** * Add a history item. This instance takes ownership of the item - * and will delete it. Default color is assigned to item. + * and will delete it. Defaults such as line color and width assigned to item. * * @param historyItem * Added to history. @@ -303,6 +332,20 @@ ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); historyItem->setColor(m_defaultColor); + historyItem->setLineWidth(m_defaultLineWidth); + addHistoryItemNoDefaults(historyItem); +} + +/** + * Add a history item. No defaults are applied to the history items. + * + * @param historyItem + * Added to history. + */ +void +ChartTwoLineSeriesHistory::addHistoryItemNoDefaults(ChartTwoDataCartesian* historyItem) +{ + CaretAssert(historyItem); m_chartHistory.push_front(historyItem); updateDisplayedHistoryItems(); } @@ -479,13 +522,7 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut historyItem->restoreFromScene(sceneAttributes, historyClass); - /* - * Note: addHistoryItem() assigns the default color so - * need to update color - */ - const CaretColorEnum::Enum color = historyItem->getColor(); - addHistoryItem(historyItem); - historyItem->setColor(color); + addHistoryItemNoDefaults(historyItem); } } diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index b7b563450..3a0ecc94c 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -53,6 +53,10 @@ namespace caret { void setDefaultColor(const CaretColorEnum::Enum defaultColor); + float getDefaultLineWidth() const; + + void setDefaultLineWidth(const float defaultLineWidth); + int32_t getDisplayCount() const; void setDisplayCount(const int32_t count); @@ -103,6 +107,8 @@ namespace caret { void updateDisplayedHistoryItems(); + void addHistoryItemNoDefaults(ChartTwoDataCartesian* historyItem); + static CaretColorEnum::Enum generateDefaultColor(); void validateDefaultColor(); @@ -115,6 +121,8 @@ namespace caret { CaretColorEnum::Enum m_defaultColor = CaretColorEnum::BLUE; + float m_defaultLineWidth = 1.0f; + int32_t m_displayCount; static int32_t s_defaultColorIndexGenerator; diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 7c63e1354..83840a266 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -82,6 +82,16 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent QObject::connect(m_defaultColorComboBox, &CaretColorEnumComboBox::colorSelected, this, &ChartTwoLineSeriesHistoryDialog::defaultColorSelected); + QLabel* defaultLineWidthLabel = new QLabel("Default Line Width: "); + m_defaultLineWidthSpinBox = new QDoubleSpinBox(); + m_defaultLineWidthSpinBox->setRange(0.0, 100000.0); + m_defaultLineWidthSpinBox->setDecimals(2); + m_defaultLineWidthSpinBox->setSingleStep(0.1); + m_defaultLineWidthSpinBox->setToolTip("Default width of new chart lines"); + defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->toolTip()); + QObject::connect(m_defaultLineWidthSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &ChartTwoLineSeriesHistoryDialog::defaultLineWidthChanged); + QToolButton* removeAllHistoryToolButton = new QToolButton(); removeAllHistoryToolButton->setText("Remove All History..."); QObject::connect(removeAllHistoryToolButton, &QToolButton::clicked, @@ -118,12 +128,17 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent topLayout->setColumnStretch(1, 0); topLayout->setColumnStretch(2, 0); topLayout->setColumnStretch(3, 100); - topLayout->addWidget(defaultColorLabel, 0, 0); - topLayout->addWidget(m_defaultColorComboBox->getWidget(), 0, 1); - topLayout->addWidget(m_filenameLabel, 0, 2, 1, 2, Qt::AlignLeft); - topLayout->addWidget(viewedMaximumLabel, 1, 0); - topLayout->addWidget(m_viewedMaximumCountSpinBox, 1, 1); - topLayout->addWidget(removeAllHistoryToolButton, 1, 2); + int gridRow = 0; + topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); + topLayout->addWidget(m_defaultLineWidthSpinBox, gridRow, 1); + gridRow++; + topLayout->addWidget(defaultColorLabel, gridRow, 0); + topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 1); + topLayout->addWidget(m_filenameLabel, gridRow, 2, 1, 2, Qt::AlignLeft); + gridRow++; + topLayout->addWidget(viewedMaximumLabel, gridRow, 0); + topLayout->addWidget(m_viewedMaximumCountSpinBox, gridRow, 1); + topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); @@ -222,6 +237,9 @@ ChartTwoLineSeriesHistoryDialog::updateDialogContentPrivate() m_filenameLabel->setToolTip(mapFile->getFileName()); } m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); + m_defaultLineWidthSpinBox->blockSignals(true); + m_defaultLineWidthSpinBox->setValue(lineSeriesHistory->getDefaultLineWidth()); + m_defaultLineWidthSpinBox->blockSignals(false); m_viewedMaximumCountSpinBox->blockSignals(true); m_viewedMaximumCountSpinBox->setValue(lineSeriesHistory->getDisplayCount()); @@ -540,6 +558,21 @@ ChartTwoLineSeriesHistoryDialog::defaultColorSelected(const CaretColorEnum::Enum } } +/** + * Called when line width is changed + * + * @param defaultLineWidth + * New default line width. + */ +void +ChartTwoLineSeriesHistoryDialog::defaultLineWidthChanged(double defaultLineWidth) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDefaultLineWidth(defaultLineWidth); + } +} + /** * Gets called when display last count is changed. * diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h index 2631fd21f..9392a8d0e 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h @@ -72,6 +72,8 @@ namespace caret { void defaultColorSelected(const CaretColorEnum::Enum color); + void defaultLineWidthChanged(double); + void viewedMaximumSpinBoxValueChanged(int); private: @@ -110,6 +112,8 @@ namespace caret { CaretColorEnumComboBox* m_defaultColorComboBox; + QDoubleSpinBox* m_defaultLineWidthSpinBox; + QSpinBox* m_viewedMaximumCountSpinBox; static const int32_t COLUMN_VIEW = 0; -- GitLab From db5394137a3716dca9c5d026634df4a0459d04c2 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 22 Aug 2017 19:38:15 -0500 Subject: [PATCH 350/755] never color nan, switch NiftiIO datatype range checking to a typedef to remove "unused variable" warnings also switch datatype range checking to c++11 lowest() --- src/Files/NodeAndVoxelColoring.cxx | 13 ++++++++++--- src/Nifti/NiftiIO.h | 13 +++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Files/NodeAndVoxelColoring.cxx b/src/Files/NodeAndVoxelColoring.cxx index 5318bccf9..17c116cbf 100644 --- a/src/Files/NodeAndVoxelColoring.cxx +++ b/src/Files/NodeAndVoxelColoring.cxx @@ -38,7 +38,7 @@ #include "GroupAndNameHierarchyItem.h" #include "Palette.h" #include "PaletteColorMapping.h" -#include "CaretOMP.h" +#include "MathFunctions.h" using namespace caret; @@ -237,11 +237,18 @@ NodeAndVoxelColoring::colorScalarsWithPalettePrivate(const FastStatistics* stati continue; } } - else { + else if (MathFunctions::isNaN(scalar)) { + continue;//TSC: never color NaN + } else { /* * May be very near zero so force to zero. + * + * TSC: that seems wrong, leave the normalized value alone + * if the data value is near zero, that doesn't mean the palette settings aren't also near zero + * therefore, normalized value may not be near zero, which is important + * */ - normalizedValues[i] = 0.0; + //normalizedValues[i] = 0.0; if (hideZeroValues) { continue; } diff --git a/src/Nifti/NiftiIO.h b/src/Nifti/NiftiIO.h index 3392bf949..732a8b77b 100644 --- a/src/Nifti/NiftiIO.h +++ b/src/Nifti/NiftiIO.h @@ -288,14 +288,15 @@ namespace caret template TO NiftiIO::clamp(const FROM& in) { - std::numeric_limits mylimits; - if (mylimits.max() < in) return mylimits.max(); - if (mylimits.is_integer)//c++11 can use lowest() instead of this mess + typedef std::numeric_limits mylimits; + if (mylimits::max() < in) return mylimits::max(); + if (mylimits::lowest() > in) return mylimits::lowest(); + /*if (mylimits::is_integer)//here is a c++03 solution to missing ::lowest { - if (mylimits.min() > in) return mylimits.min(); + if (mylimits::min() > in) return mylimits::min(); } else { - if (-mylimits.max() > in) return -mylimits.max(); - } + if (-mylimits::max() > in) return -mylimits::max(); + }//*/ return (TO)in; } } -- GitLab From 45a778631325f0af7ff4df6fd38031156dc6404c Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 23 Aug 2017 19:50:10 -0500 Subject: [PATCH 351/755] add mode to -volume-weighted-stats for matching maps to the weight file --- .../OperationVolumeWeightedStats.cxx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Operations/OperationVolumeWeightedStats.cxx b/src/Operations/OperationVolumeWeightedStats.cxx index 6e0802993..3587627ed 100644 --- a/src/Operations/OperationVolumeWeightedStats.cxx +++ b/src/Operations/OperationVolumeWeightedStats.cxx @@ -51,6 +51,7 @@ OperationParameters* OperationVolumeWeightedStats::getParameters() OptionalParameter* weightVolumeOpt = ret->createOptionalParameter(2, "-weight-volume", "use weights from a volume file"); weightVolumeOpt->addVolumeParameter(1, "weight-volume", "volume file containing the weights"); + weightVolumeOpt->createOptionalParameter(2, "-match-maps", "each subvolume of input uses the corresponding subvolume from the weights file"); OptionalParameter* subvolOpt = ret->createOptionalParameter(3, "-subvolume", "only display output for one subvolume"); subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); @@ -275,11 +276,21 @@ void OperationVolumeWeightedStats::useParameters(OperationParameters* myParams, OptionalParameter* weightVolumeOpt = myParams->getOptionalParameter(2); VolumeFile* myWeights = NULL; const float* weightData = NULL; + bool matchSubvolWeights = false; if (weightVolumeOpt->m_present) { myWeights = weightVolumeOpt->getVolume(1); if (!myWeights->matchesVolumeSpace(input)) throw OperationException("weight volume doesn't match volume space of input"); - weightData = myWeights->getFrame(); + if (weightVolumeOpt->getOptionalParameter(2)->m_present) + { + if (myWeights->getDimensions()[3] != dims[3]) + { + throw OperationException("-match-maps specified, but weights file has different number of subvolumes than input"); + } + matchSubvolWeights = true; + } else { + weightData = myWeights->getFrame(); + } } int subvol = -1; OptionalParameter* subvolOpt = myParams->getOptionalParameter(3); @@ -300,7 +311,7 @@ void OperationVolumeWeightedStats::useParameters(OperationParameters* myParams, { if (myRoi->getDimensions()[3] != dims[3]) { - throw OperationException("-match-maps specified, but roi has different number of subvolumes than input"); + throw OperationException("-match-maps specified, but roi file has different number of subvolumes than input"); } matchSubvolMode = true; } else { @@ -353,6 +364,10 @@ void OperationVolumeWeightedStats::useParameters(OperationParameters* myParams, { roiData = myRoi->getFrame(i); } + if (matchSubvolWeights) + { + weightData = myWeights->getFrame(i); + } float result; if (weightData != NULL) { @@ -370,6 +385,10 @@ void OperationVolumeWeightedStats::useParameters(OperationParameters* myParams, { roiData = myRoi->getFrame(subvol); } + if (matchSubvolWeights) + { + weightData = myWeights->getFrame(subvol); + } float result; if (weightData != NULL) { -- GitLab From 725099387c6930677027f1bb199ff90aacb7ef34 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 09:23:47 -0500 Subject: [PATCH 352/755] WB-729: Tab Dragging: Multiple signals (tabMoved(int,int) and currentChanged(int)) are emitted by QTabBar when a tab is moved. The signal currentChanged(int) is also emitted when the user selects a tab. The update graphics request has been removed from tabMoved() since it is not needed. The timer logic for tab highlighting in currentChanged() has been revised. If the timer is running, it is canceled and restarted. Previously, a static method in QTimer was used and it was possible for more than one of these timers to be active and causing graphics updates. There is no signals emitted when moving of a tab starts and stops. It might be possible to extend the QTabBar class and detect tab movement in the 'drag virtual methods' although they may not apply to a tab being moved. Another possibility is to override the mouse press and release virtual methods. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 25 +++++++++++++++++-------- src/GuiQt/BrainBrowserWindowToolBar.h | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 3f031623c..026477596 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1243,10 +1243,6 @@ void BrainBrowserWindowToolBar::closeSelectedTab() { tabCloseSelected(this->tabBar->currentIndex()); -// const int tabIndex = this->tabBar->currentIndex(); -// if (this->tabBar->count() > 1) { -// this->tabClosed(tabIndex); -// } } /** @@ -1272,13 +1268,26 @@ BrainBrowserWindowToolBar::selectedTabChanged(int indx) /* * Short timer that will reset the tab highlighting */ + if (m_tileTabsHighlightingTimer == NULL) { + m_tileTabsHighlightingTimer = new QTimer(this); + QObject::connect(m_tileTabsHighlightingTimer, &QTimer::timeout, + this, &BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting); + } + + /* + * Note: There is no need to 'stop' the timer if it is running + * as the start() method will stop and restart the timer + */ const int timeInMilliseconds = 750; - QTimer::singleShot(timeInMilliseconds, - this, SLOT(resetTabIndexForTileTabsHighlighting())); + m_tileTabsHighlightingTimer->setSingleShot(true); + m_tileTabsHighlightingTimer->start(timeInMilliseconds); } } } - + + /* + * Graphics must be updated so border is visible around the selected tab + */ this->updateGraphicsWindow(); } @@ -1338,7 +1347,7 @@ BrainBrowserWindowToolBar::tabClosed(int tabIndex) void BrainBrowserWindowToolBar::tabMoved(int /*from*/, int /*to*/) { - this->updateGraphicsWindow(); + /* No need to redraw as the selectedTabChanged() is also called when a tab is moved */ } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index d0bebf063..3156c9f0e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -434,6 +434,7 @@ namespace caret { * box around it. */ int32_t m_tabIndexForTileTabsHighlighting; + QTimer* m_tileTabsHighlightingTimer = NULL; bool isContructorFinished; bool isDestructionInProgress; -- GitLab From 08c70c5bc3fe6434da0e3642e3b88bbcf2a87612 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 09:43:28 -0500 Subject: [PATCH 353/755] Resolve WB-728 Image Captured Message - Reduced time of 'captured message' from 2.0 seconds to 0.5 seconds. --- src/GuiQt/ImageCaptureDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/ImageCaptureDialog.cxx b/src/GuiQt/ImageCaptureDialog.cxx index c7522121b..2977dbdc5 100644 --- a/src/GuiQt/ImageCaptureDialog.cxx +++ b/src/GuiQt/ImageCaptureDialog.cxx @@ -1206,7 +1206,7 @@ ImageCaptureDialog::applyButtonClicked() CaretAssert(parent); WuQTimedMessageDisplay::show(parent, - 2.0, + 0.5, "Image captured"); } -- GitLab From ab4fd26f2b4783cf3d55daf927f48d47cfc0cc52 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 11:26:23 -0500 Subject: [PATCH 354/755] Resolve WB-706 View Mode Labels - Changed 'Chart' to 'Chart Old' and 'Chart Two' to 'Chart' --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 026477596..996d7cace 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1624,8 +1624,8 @@ BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTab QWidget* BrainBrowserWindowToolBar::createViewWidget() { - this->viewModeChartOneRadioButton = new QRadioButton("Chart"); - this->viewModeChartTwoRadioButton = new QRadioButton("Chart Two"); + this->viewModeChartOneRadioButton = new QRadioButton("Chart Old"); + this->viewModeChartTwoRadioButton = new QRadioButton("Chart"); this->viewModeSurfaceRadioButton = new QRadioButton("Surface"); this->viewModeSurfaceMontageRadioButton = new QRadioButton("Montage"); this->viewModeVolumeRadioButton = new QRadioButton("Volume"); -- GitLab From 60cc9153a31c3a4d3c4b7df56a5a17ad5289bccc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 16:19:48 -0500 Subject: [PATCH 355/755] Fixed bug in restoration of SceneObjectMapIntegerKey that occurred if the key in the map were not sequential starting at zero. --- src/Scenes/SceneObjectMapIntegerKey.cxx | 9 +++++++++ src/Scenes/SceneObjectMapIntegerKey.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/Scenes/SceneObjectMapIntegerKey.cxx b/src/Scenes/SceneObjectMapIntegerKey.cxx index 987493023..362a43936 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.cxx +++ b/src/Scenes/SceneObjectMapIntegerKey.cxx @@ -78,6 +78,15 @@ SceneObjectMapIntegerKey::~SceneObjectMapIntegerKey() } } +/** + * @return True if this map's content is empty, else false. + */ +bool +SceneObjectMapIntegerKey::isEmpty() const +{ + return m_dataMap.empty(); +} + /** * @return All descendant SceneClasses (children, grandchildren, etc.) of this instance. */ diff --git a/src/Scenes/SceneObjectMapIntegerKey.h b/src/Scenes/SceneObjectMapIntegerKey.h index aa558a5b3..9c430d16e 100644 --- a/src/Scenes/SceneObjectMapIntegerKey.h +++ b/src/Scenes/SceneObjectMapIntegerKey.h @@ -123,6 +123,8 @@ namespace caret { virtual SceneObject* clone() const; + bool isEmpty() const; + private: typedef std::map DATA_MAP; -- GitLab From 0aeff7fbc2e7d15e13b97fbc223149a6ed169532 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 16:21:44 -0500 Subject: [PATCH 356/755] Resolve WB-730 Chart History Inflates Scene File Size. Maximum retained history is now limited to 20 items. Only history items selected for viewing are added to the scene file. --- src/Charting/ChartTwoLineSeriesHistory.cxx | 71 ++++++++++++++----- src/Charting/ChartTwoLineSeriesHistory.h | 5 +- src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 18 +++-- 3 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 83311f121..ae2f3f93e 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -239,10 +239,6 @@ ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultCol validateDefaultColor(); setModified(); } - -// for (auto chartData : m_chartHistory) { -// chartData->setColor(defaultColor); -// } } /** @@ -300,8 +296,8 @@ ChartTwoLineSeriesHistory::setDisplayCount(const int32_t count) void ChartTwoLineSeriesHistory::updateDisplayedHistoryItems() { int32_t itemsDisplayedCount = 0; - const int32_t numItems = getHistoryCount(); - for (int32_t i = 0; i < numItems; i++) { + const int32_t historyCount = getHistoryCount(); + for (int32_t i = 0; i < historyCount; i++) { ChartTwoDataCartesian* item = getHistoryItem(i); if (item->isSelected()) { itemsDisplayedCount++; @@ -310,12 +306,41 @@ void ChartTwoLineSeriesHistory::updateDisplayedHistoryItems() } } } + + /* + * Limit the number of history items to + * avoid excessive memory usage + */ + const int32_t maximumItems = std::max(m_displayCount, + s_maximumRetainedHistoryCount); + if (historyCount > maximumItems) { + for (int32_t i = maximumItems; i < historyCount; i++) { + CaretAssertVectorIndex(m_chartHistory, i); + CaretAssert(m_chartHistory[i]); + delete m_chartHistory[i]; + m_chartHistory[i]= NULL; + } + + m_chartHistory.resize(maximumItems); + } +} + +/** + * @return The maximum number of history items that are + * retained. + */ +int32_t +ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount() +{ + return s_maximumRetainedHistoryCount; } + /** * @return Count of items in history. */ -int32_t ChartTwoLineSeriesHistory::getHistoryCount() const +int32_t +ChartTwoLineSeriesHistory::getHistoryCount() const { return m_chartHistory.size(); } @@ -334,6 +359,7 @@ ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) historyItem->setColor(m_defaultColor); historyItem->setLineWidth(m_defaultLineWidth); addHistoryItemNoDefaults(historyItem); + updateDisplayedHistoryItems(); } /** @@ -346,8 +372,7 @@ void ChartTwoLineSeriesHistory::addHistoryItemNoDefaults(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); - m_chartHistory.push_front(historyItem); - updateDisplayedHistoryItems(); + m_chartHistory.push_front(historyItem); } /** @@ -459,7 +484,7 @@ ChartTwoLineSeriesHistory::saveToScene(const SceneAttributes* sceneAttributes, sceneClass); /* - * Save chart history + * Save chart history but only the displayed items */ const int32_t numHistory = static_cast(m_chartHistory.size()); if (numHistory > 0) { @@ -467,11 +492,20 @@ ChartTwoLineSeriesHistory::saveToScene(const SceneAttributes* sceneAttributes, SceneObjectDataTypeEnum::SCENE_CLASS); for (int32_t i = 0; i < numHistory; i++) { CaretAssertVectorIndex(m_chartHistory, i); - chartHistoryMap->addClass(i, - m_chartHistory[i]->saveToScene(sceneAttributes, - "m_chartHistory")); + if (m_chartHistory[i]->isSelected()) { + chartHistoryMap->addClass(i, + m_chartHistory[i]->saveToScene(sceneAttributes, + "m_chartHistory")); + } + } + + if (chartHistoryMap->isEmpty()) { + delete chartHistoryMap; + chartHistoryMap = NULL; + } + else { + sceneClass->addChild(chartHistoryMap); } - sceneClass->addChild(chartHistoryMap); } // Uncomment if sub-classes must save to scene @@ -508,13 +542,14 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut /* * Restore chart matrix properties + * Need to reverse keys since items are added on at beginning */ const SceneObjectMapIntegerKey* chartHistoryMap = sceneClass->getMapIntegerKey("m_chartHistoryMap"); if (chartHistoryMap != NULL) { - const std::vector indices = chartHistoryMap->getKeys(); - const int32_t numIndices = static_cast(indices.size()); - for (int32_t i = (numIndices - 1); i >= 0; i--) { - const SceneClass* historyClass = chartHistoryMap->classValue(i); + std::vector indices = chartHistoryMap->getKeys(); + std::reverse(indices.begin(), indices.end()); + for (auto itemIndex : indices) { + const SceneClass* historyClass = chartHistoryMap->classValue(itemIndex); ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, CaretUnitsTypeEnum::NONE, CaretUnitsTypeEnum::NONE, diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 3a0ecc94c..6e7c5f42f 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -87,7 +87,7 @@ namespace caret { virtual void clearModified() override; - + static int32_t getMaximumRetainedHistoryCount(); // If there will be sub-classes of this class that need to save @@ -127,12 +127,15 @@ namespace caret { static int32_t s_defaultColorIndexGenerator; + static const int32_t s_maximumRetainedHistoryCount; + // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ int32_t ChartTwoLineSeriesHistory::s_defaultColorIndexGenerator = 0; + const int32_t ChartTwoLineSeriesHistory::s_maximumRetainedHistoryCount = 20; #endif // __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ } // namespace diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 83840a266..6793e6793 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -66,9 +66,12 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent : WuQDialogNonModal("Line-Series History", parent) { + const AString maxHistoryString(AString::number(ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount())); const AString defaultColorToolTip("Color assigned to newly added line-series items"); const AString displayMaximumToolTip("Maximum number of line-series items enabled for viewing\n" - "As new items are added, older items are disabled for viewing"); + "As new items are added, older items are disabled for viewing\n" + "The number of history items retained (including those not\n" + "displayed) is limited to this value or " + maxHistoryString + ", whichever is larger."); m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); @@ -127,18 +130,19 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent topLayout->setColumnStretch(0, 0); topLayout->setColumnStretch(1, 0); topLayout->setColumnStretch(2, 0); - topLayout->setColumnStretch(3, 100); + topLayout->setColumnStretch(3, 0); + topLayout->setColumnStretch(4, 100); int gridRow = 0; + topLayout->addWidget(m_filenameLabel, gridRow, 0, 1, 5, Qt::AlignLeft); + gridRow++; topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); topLayout->addWidget(m_defaultLineWidthSpinBox, gridRow, 1); - gridRow++; - topLayout->addWidget(defaultColorLabel, gridRow, 0); - topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 1); - topLayout->addWidget(m_filenameLabel, gridRow, 2, 1, 2, Qt::AlignLeft); + topLayout->addWidget(defaultColorLabel, gridRow, 2); + topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 3); gridRow++; topLayout->addWidget(viewedMaximumLabel, gridRow, 0); topLayout->addWidget(m_viewedMaximumCountSpinBox, gridRow, 1); - topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2); + topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2, 1, 2, Qt::AlignLeft); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); -- GitLab From 15c206edf76305943c324ee4c695901e746fcd6c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 15 Aug 2017 16:34:51 -0500 Subject: [PATCH 357/755] Resolve WB-703 Default maximum line series history to display one item. One item is now the default maximum. Note that the maximum number is saved to and restored from scenes. --- src/Charting/ChartTwoLineSeriesHistory.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index ae2f3f93e..665359bea 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -176,7 +176,7 @@ ChartTwoLineSeriesHistory::initializeInstance() m_defaultLineWidth = 1.0f; - const int32_t defaultHistoryCount = 5; + const int32_t defaultHistoryCount = 1; m_loadingEnabled = false; m_sceneAssistant = new SceneClassAssistant(); -- GitLab From 2518b340b9f6e8b21e3d07b778dcddcafdb4db26 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 18 Aug 2017 16:10:50 -0500 Subject: [PATCH 358/755] Revised axes that user percentages sizes is partially implemented. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1741 +++++++++++++++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 130 +- src/Brain/ChartTwoOverlaySet.cxx | 28 +- src/Brain/ChartTwoOverlaySet.h | 7 + src/Charting/ChartTwoCartesianAxis.cxx | 83 +- src/Charting/ChartTwoCartesianAxis.h | 33 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 238 ++- .../BrainBrowserWindowToolBarChartTwoAxes.h | 22 +- 8 files changed, 2041 insertions(+), 241 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 4d5bd3b73..7e13a7232 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -284,7 +284,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, annotationsOut = m_annotationsForDrawingOutput; } - /** * Draw a histogram or line series chart. * @@ -345,12 +344,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Get the histogram drawing information and overall extent */ - float xMin = std::numeric_limits::max(); - float xMax = -std::numeric_limits::max(); + float xMinBottom = std::numeric_limits::max(); + float xMaxBottom = -std::numeric_limits::max(); + float xMinTop = std::numeric_limits::max(); + float xMaxTop = -std::numeric_limits::max(); float yMinLeft = std::numeric_limits::max(); float yMaxLeft = -std::numeric_limits::max(); float yMinRight = std::numeric_limits::max(); float yMaxRight = -std::numeric_limits::max(); + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -376,10 +378,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); AString errorMessage; histogramDrawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, - selectedIndex, - chartOverlay->getCartesianVerticalAxisLocation(), - (chartOverlay->isAllMapsSupported() - && chartOverlay->isAllMapsSelected())))); + selectedIndex, + chartOverlay->getCartesianVerticalAxisLocation(), + (chartOverlay->isAllMapsSupported() + && chartOverlay->isAllMapsSelected())))); const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, (chartOverlay->isAllMapsSupported() && chartOverlay->isAllMapsSelected())); @@ -387,8 +389,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); if (histogramMaxX > histogramMinX) { - xMin = std::min(xMin, histogramMinX); - xMax = std::max(xMax, histogramMaxX); + xMinBottom = std::min(xMinBottom, histogramMinX); + xMaxBottom = std::max(xMaxBottom, histogramMaxX); + xMinTop = std::min(xMinTop, histogramMinX); + xMaxTop = std::max(xMaxTop, histogramMaxX); switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: @@ -420,8 +424,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if (data->isSelected()) { BoundingBox boundingBox; if (data->getBounds(boundingBox)) { - xMin = std::min(xMin, boundingBox.getMinX()); - xMax = std::max(xMax, boundingBox.getMaxX()); + xMinBottom = std::min(xMinBottom, boundingBox.getMinX()); + xMaxBottom = std::max(xMaxBottom, boundingBox.getMaxX()); + xMinTop = std::min(xMinTop, boundingBox.getMinX()); + xMaxTop = std::max(xMaxTop, boundingBox.getMaxX()); switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: @@ -452,8 +458,33 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Bounds valid? */ - if ((xMin < xMax) - && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { + const bool xBottomValid = (xMinBottom < xMaxBottom); + const bool xTopValid = (xMinTop < xMaxTop); + const bool xValid = (xBottomValid || xTopValid); + const bool yLeftValid = (yMinLeft < yMaxLeft); + const bool yRightValid = (yMinRight < yMaxRight); + const bool yValid = (yLeftValid || yRightValid); + if (xValid || yValid) { + /* + * Make invalid ranges zero + */ + if ( ! yLeftValid) { + yMinLeft = 0.0; + yMaxLeft = 0.0; + } + if ( ! yRightValid) { + yMinRight = 0.0; + yMaxRight = 0.0; + } + if ( ! xTopValid) { + xMinTop = 0.0; + xMaxTop = 0.0; + } + if ( ! xBottomValid) { + xMinBottom = 0.0; + xMaxBottom = 0.0; + } + /* * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. @@ -494,7 +525,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); - double width = 0.0, height = 0.0; + //double width = 0.0, height = 0.0; GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); @@ -513,23 +544,91 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch bool allowTopAxisFlag = false; - if (m_chartOverlaySet->isChartTitleDisplayed()) { - double titleHeight = 0.0; - estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); - margins.m_top = std::max(margins.m_top, titleHeight); - } +// if (m_chartOverlaySet->isChartTitleDisplayed()) { +// double titleHeight = 0.0; +// estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); +// margins.m_top = std::max(margins.m_top, titleHeight); +// } - estimateCartesianChartAxisLegendsWidthHeight(yMinLeft, yMaxLeft, tabViewportWidth, tabViewportHeight, leftAxis, leftAxisLabel, width, height); - margins.m_left = std::max(margins.m_left, width); - estimateCartesianChartAxisLegendsWidthHeight(yMinRight, yMaxRight, tabViewportWidth, tabViewportHeight, rightAxis, rightAxisLabel, width, height); - margins.m_right = std::max(margins.m_right, width); - if (allowTopAxisFlag) { - CaretAssertMessage(0, "For top axis, will need to make space for chart title"); - estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, topAxis, NULL, width, height); - margins.m_top = std::max(margins.m_top, height); - } - estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, tabViewportWidth, tabViewportHeight, bottomAxis, bottomAxisLabel, width, height); - margins.m_bottom = std::max(margins.m_bottom, height); + const float lineWidthPercentage = m_chartOverlaySet->getAxisLineThickness(); + + /* + * Estimate axes sizes NEW + */ + AxisDrawingInfo leftAxisInfo(m_textRenderer, + m_viewport, + xMinBottom, + xMaxBottom, + yMinLeft, + yMaxLeft, + ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT, + leftAxis, + "Left", + lineWidthPercentage); + AxisDrawingInfo rightAxisInfo(m_textRenderer, + m_viewport, + xMinTop, + xMaxTop, + yMinRight, + yMaxRight, + ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT, + rightAxis, + "Right", + lineWidthPercentage); + AxisDrawingInfo bottomAxisInfo(m_textRenderer, + m_viewport, + xMinBottom, + xMaxBottom, + yMinLeft, + yMaxLeft, + ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM, + bottomAxis, + "Bottom", + lineWidthPercentage); + AxisDrawingInfo topAxisInfo(m_textRenderer, + m_viewport, + xMinTop, + xMaxTop, + yMinLeft, + yMaxLeft, + ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP, + topAxis, + "Top", + lineWidthPercentage); + + const float bottomAxisHeight = bottomAxisInfo.m_axisHeight; + const float topAxisHeight = topAxisInfo.m_axisHeight; + const float leftAxisWidth = leftAxisInfo.m_axisWidth; + const float rightAxisWidth = rightAxisInfo.m_axisWidth; + + leftAxisInfo.setAxisViewport(bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth); + rightAxisInfo.setAxisViewport(bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth); + bottomAxisInfo.setAxisViewport(bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth); + topAxisInfo.setAxisViewport(bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth); + + const float foregroundRGBA[4] = { + m_fixedPipelineDrawing->m_foregroundColorFloat[0], + m_fixedPipelineDrawing->m_foregroundColorFloat[1], + m_fixedPipelineDrawing->m_foregroundColorFloat[2], + 1.0f + }; + + leftAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); + rightAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); + bottomAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); + topAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); /* * Ensure that there is sufficient space for the axes data display. @@ -537,82 +636,30 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if ((tabViewportWidth > (marginSize * 3)) && (tabViewportHeight > (marginSize * 3))) { - float axisMinimumValue = 0.0; - float axisMaximumValue = 0.0; - - /* Draw legends and grids */ - if (drawChartAxisCartesian(yMinLeft, - yMaxLeft, - tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - leftAxis, - leftAxisLabel, - axisMinimumValue, - axisMaximumValue)) { - yMinLeft = axisMinimumValue; - yMaxLeft = axisMaximumValue; - } - - if (drawChartAxisCartesian(yMinRight, - yMaxRight, - tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - rightAxis, - rightAxisLabel, - axisMinimumValue, - axisMaximumValue)) { - yMinRight = axisMinimumValue; - yMaxRight = axisMaximumValue; - } - if (drawChartAxisCartesian(xMin, - xMax, - tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - bottomAxis, - bottomAxisLabel, - axisMinimumValue, - axisMaximumValue)) { - xMin = axisMinimumValue; - xMax = axisMaximumValue; - } + leftAxisInfo.drawAxis(this, foregroundRGBA, yMinLeft, yMaxLeft); + rightAxisInfo.drawAxis(this, foregroundRGBA, yMinRight, yMaxRight); + topAxisInfo.drawAxis(this, foregroundRGBA, xMinTop, xMaxTop); + bottomAxisInfo.drawAxis(this, foregroundRGBA, xMinBottom, xMaxBottom); - if (allowTopAxisFlag) { - drawChartAxisCartesian(xMin, - xMax, - tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - topAxis, - NULL, - axisMinimumValue, - axisMaximumValue); - } - if (m_chartOverlaySet->isChartTitleDisplayed()) { - drawChartTitle(tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - chartTitle); - } +// if (m_chartOverlaySet->isChartTitleDisplayed()) { +// drawChartTitle(tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// chartTitle); +// } drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, - margins, + m_chartOverlaySet->getAxisLineThickness(), + bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth, true, /* draw the box */ chartGraphicsDrawingViewport); } @@ -653,13 +700,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch glMatrixMode(GL_PROJECTION); glLoadIdentity(); + CaretAssert(xMinBottom < xMaxBottom); if (leftVerticalAxisFlag) { - glOrtho(xMin, xMax, + glOrtho(xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, -10.0, 10.0); } else { - glOrtho(xMin, xMax, + glOrtho(xMinBottom, xMaxBottom, yMinRight, yMaxRight, -10.0, 10.0); } @@ -779,13 +827,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch glMatrixMode(GL_PROJECTION); glLoadIdentity(); + CaretAssert(xMinBottom < xMaxBottom); if (leftVerticalAxisFlag) { - glOrtho(xMin, xMax, + CaretAssert(yMinLeft < yMaxLeft); + glOrtho(xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, -10.0, 10.0); } else { - glOrtho(xMin, xMax, + CaretAssert(yMinRight < yMaxRight); + glOrtho(xMinBottom, xMaxBottom, yMinRight, yMaxRight, -10.0, 10.0); } @@ -845,7 +896,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch m_fixedPipelineDrawing->enableLineAntiAliasing(); glLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); + lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); } @@ -861,6 +912,645 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } + +///** +// * Draw a histogram or line series chart. +// * +// * @param chartDataType +// * Type of chart to draw. +// */ +//void +//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType) +//{ +// bool drawHistogramFlag = false; +// bool drawLineSeriesFlag = false; +// switch (chartDataType) { +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: +// CaretAssert(0); +// return; +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: +// drawHistogramFlag = true; +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: +// drawLineSeriesFlag = true; +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: +// CaretAssert(0); +// return; +// break; +// } +// +// const int32_t tabViewportX = m_viewport[0]; +// const int32_t tabViewportY = m_viewport[1]; +// const int32_t tabViewportWidth = m_viewport[2]; +// const int32_t tabViewportHeight = m_viewport[3]; +// +// int32_t chartGraphicsDrawingViewport[4] = { +// tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight +// }; +// +// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); +// CaretAssert(numberOfOverlays > 0); +// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); +// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); +// if (drawHistogramFlag) { +// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); +// } +// else if (drawLineSeriesFlag) { +// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); +// } +// else { +// CaretAssert(0); +// } +// +// std::vector> histogramDrawingInfo; +// std::deque lineSeriesChartsToDraw; +// +// /* +// * Get the histogram drawing information and overall extent +// */ +// float xMin = std::numeric_limits::max(); +// float xMax = -std::numeric_limits::max(); +// float yMinLeft = std::numeric_limits::max(); +// float yMaxLeft = -std::numeric_limits::max(); +// float yMinRight = std::numeric_limits::max(); +// float yMaxRight = -std::numeric_limits::max(); +// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { +// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); +// if ( ! chartOverlay->isEnabled()) { +// continue; +// } +// +// CaretMappableDataFile* mapFile = NULL; +// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; +// int32_t selectedIndex = -1; +// chartOverlay->getSelectionData(mapFile, +// selectedIndexType, +// selectedIndex); +// if (mapFile == NULL) { +// continue; +// } +// +// ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); +// +// if (drawHistogramFlag) { +// ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); +// +// if (histogramChart->isValid()) { +// CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); +// AString errorMessage; +// histogramDrawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, +// selectedIndex, +// chartOverlay->getCartesianVerticalAxisLocation(), +// (chartOverlay->isAllMapsSupported() +// && chartOverlay->isAllMapsSelected())))); +// const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, +// (chartOverlay->isAllMapsSupported() +// && chartOverlay->isAllMapsSelected())); +// CaretAssert(histogram); +// float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; +// histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); +// if (histogramMaxX > histogramMinX) { +// xMin = std::min(xMin, histogramMinX); +// xMax = std::max(xMax, histogramMaxX); +// +// switch (chartOverlay->getCartesianVerticalAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// yMinRight = std::min(yMinRight, 0.0f); +// yMaxRight = std::max(yMaxRight, histogramMaxY); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// yMinLeft = std::min(yMinLeft, 0.0f); +// yMaxLeft = std::max(yMaxLeft, histogramMaxY); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); +// break; +// } +// } +// } +// } +// +// if (drawLineSeriesFlag) { +// const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); +// const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); +// const int32_t numHistory = lineSeriesHistory->getHistoryCount(); +// for (int32_t iHistory = (numHistory - 1); iHistory >= 0; iHistory--) { +// const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); +// CaretAssert(data); +// if (data->isSelected()) { +// BoundingBox boundingBox; +// if (data->getBounds(boundingBox)) { +// xMin = std::min(xMin, boundingBox.getMinX()); +// xMax = std::max(xMax, boundingBox.getMaxX()); +// +// switch (chartOverlay->getCartesianVerticalAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// yMinRight = std::min(yMinRight, boundingBox.getMinY()); +// yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); +// yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); +// break; +// } +// +// lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, +// data, +// chartOverlay->getCartesianVerticalAxisLocation())); +// } +// } +// } +// } +// } +// +// /* +// * Bounds valid? +// */ +// if ((xMin < xMax) +// && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { +// /* +// * Margin is region around the chart in which +// * the axes legends, values, and ticks are drawn. +// */ +// const double marginSize = 10; +// Margins margins(marginSize); +// +// ChartTwoCartesianAxis* leftAxis = NULL; +// ChartTwoCartesianAxis* rightAxis = NULL; +// ChartTwoCartesianAxis* bottomAxis = NULL; +// ChartTwoCartesianAxis* topAxis = NULL; +// +// std::vector displayedAxes; +// AnnotationPercentSizeText* leftAxisLabel = NULL; +// AnnotationPercentSizeText* rightAxisLabel = NULL; +// AnnotationPercentSizeText* bottomAxisLabel = NULL; +// m_chartOverlaySet->getDisplayedChartAxes(displayedAxes, +// leftAxisLabel, +// rightAxisLabel, +// bottomAxisLabel); +// for (auto axis : displayedAxes) { +// CaretAssert(axis); +// switch (axis->getAxisLocation()) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// bottomAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// leftAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// rightAxis = axis; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// topAxis = axis; +// break; +// } +// } +// +// AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); +// +// //double width = 0.0, height = 0.0; +// +// GLint vp[4]; +// glGetIntegerv(GL_VIEWPORT, vp); +// +// glViewport(tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight); +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// glOrtho(0, tabViewportWidth, 0, tabViewportHeight, -1.0, 1.0); +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool allowTopAxisFlag = false; +// +// if (m_chartOverlaySet->isChartTitleDisplayed()) { +// double titleHeight = 0.0; +// estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); +// margins.m_top = std::max(margins.m_top, titleHeight); +// } +// +// const float lineWidthPercentage = m_chartOverlaySet->getAxisLineThickness(); +// +// /* +// * Estimate axes sizes OLD +// */ +// AxisSizeInfo leftAxisSizeInfo; +// estimateCartesianChartAxisLegendsWidthHeight(yMinLeft, yMaxLeft, +// tabViewportWidth, tabViewportHeight, lineWidthPercentage, +// leftAxis, leftAxisLabel, leftAxisSizeInfo); +// margins.m_left = std::max(margins.m_left, leftAxisSizeInfo.m_width); +// AxisSizeInfo rightAxisSizeInfo; +// estimateCartesianChartAxisLegendsWidthHeight(yMinRight, yMaxRight, +// tabViewportWidth, tabViewportHeight, lineWidthPercentage, +// rightAxis, rightAxisLabel, rightAxisSizeInfo); +// margins.m_right = std::max(margins.m_right, rightAxisSizeInfo.m_width); +// AxisSizeInfo topAxisSizeInfo; +// if (allowTopAxisFlag) { +// CaretAssertMessage(0, "For top axis, will need to make space for chart title"); +// estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, +// tabViewportWidth, tabViewportHeight, lineWidthPercentage, +// topAxis, NULL, topAxisSizeInfo); +// margins.m_top = std::max(margins.m_top, topAxisSizeInfo.m_height); +// } +// AxisSizeInfo bottomAxisSizeInfo; +// estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, +// tabViewportWidth, tabViewportHeight, lineWidthPercentage, +// bottomAxis, bottomAxisLabel, bottomAxisSizeInfo); +// margins.m_bottom = std::max(margins.m_bottom, bottomAxisSizeInfo.m_height); +// +// /* +// * Estimate axes sizes NEW +// */ +// AxisDrawingInfo leftAxisInfo(m_textRenderer, +// m_viewport, +// xMin, +// xMax, +// yMinLeft, +// yMaxLeft, +// leftAxis, +// "Left", +// lineWidthPercentage); +// AxisDrawingInfo rightAxisInfo(m_textRenderer, +// m_viewport, +// xMin, +// xMax, +// yMinRight, +// yMaxRight, +// rightAxis, +// "Right", +// lineWidthPercentage); +// AxisDrawingInfo bottomAxisInfo(m_textRenderer, +// m_viewport, +// xMin, +// xMax, +// yMinLeft, +// yMaxLeft, +// bottomAxis, +// "Bottom", +// lineWidthPercentage); +// AxisDrawingInfo topAxisInfo(m_textRenderer, +// m_viewport, +// xMin, +// xMax, +// yMinLeft, +// yMaxLeft, +// topAxis, +// "Top", +// lineWidthPercentage); +// +// /* +// * Ensure that there is sufficient space for the axes data display. +// */ +// if ((tabViewportWidth > (marginSize * 3)) +// && (tabViewportHeight > (marginSize * 3))) { +// +// float axisMinimumValue = 0.0; +// float axisMaximumValue = 0.0; +// +// /* Draw legends and grids */ +// if (drawChartAxisCartesian(yMinLeft, +// yMaxLeft, +// tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// leftAxisSizeInfo, +// leftAxis, +// leftAxisLabel, +// axisMinimumValue, +// axisMaximumValue)) { +// yMinLeft = axisMinimumValue; +// yMaxLeft = axisMaximumValue; +// } +// +// if (drawChartAxisCartesian(yMinRight, +// yMaxRight, +// tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// rightAxisSizeInfo, +// rightAxis, +// rightAxisLabel, +// axisMinimumValue, +// axisMaximumValue)) { +// yMinRight = axisMinimumValue; +// yMaxRight = axisMaximumValue; +// } +// if (drawChartAxisCartesian(xMin, +// xMax, +// tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// bottomAxisSizeInfo, +// bottomAxis, +// bottomAxisLabel, +// axisMinimumValue, +// axisMaximumValue)) { +// xMin = axisMinimumValue; +// xMax = axisMaximumValue; +// } +// +// if (allowTopAxisFlag) { +// drawChartAxisCartesian(xMin, +// xMax, +// tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// topAxisSizeInfo, +// topAxis, +// NULL, +// axisMinimumValue, +// axisMaximumValue); +// } +// +// if (m_chartOverlaySet->isChartTitleDisplayed()) { +// drawChartTitle(tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// margins, +// chartTitle); +// } +// +// drawChartGraphicsBoxAndSetViewport(tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// m_chartOverlaySet->getAxisLineThickness(), +// margins, +// true, /* draw the box */ +// chartGraphicsDrawingViewport); +// } +// +// glViewport(chartGraphicsDrawingViewport[0], +// chartGraphicsDrawingViewport[1], +// chartGraphicsDrawingViewport[2], +// chartGraphicsDrawingViewport[3]); +// +// +// if (drawHistogramFlag) { +// /* +// * Draw the bars for all histogram and then draw the envelopes +// * so the envelopes are not obscured by the bars +// */ +// for (auto& drawInfo : histogramDrawingInfo) { +// if (drawInfo->m_histogramChart->isValid()) { +// const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); +// CaretAssert(cmdf); +// const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); +// const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); +// const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); +// +// if (drawBarsFlag +// || drawEnvelopeFlag) { +// bool leftVerticalAxisFlag = true; +// switch (drawInfo->m_verticalAxisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// leftVerticalAxisFlag = false; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// break; +// } +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// if (leftVerticalAxisFlag) { +// glOrtho(xMin, xMax, +// yMinLeft, yMaxLeft, +// -10.0, 10.0); +// } +// else { +// glOrtho(xMin, xMax, +// yMinRight, yMaxRight, +// -10.0, 10.0); +// } +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool applyTransformationsFlag = false; +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = chartGraphicsDrawingViewport[2]; +// const float chartHeight = chartGraphicsDrawingViewport[3]; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// /* +// * Save the transformation matrices and the viewport +// * If there is more than one line chart, this code will be executed +// * several times but since the top overlay is drawn last, the contents +// * of the top overlay will be used. +// */ +// updateViewportContentForCharting(chartGraphicsDrawingViewport); +// +// ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = +// drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, +// drawInfo->m_allMapsSelected); +// +// if (histogramPrimitives != NULL) { +// const float ENVELOPE_LINE_WIDTH = 1.0; +// +// if (m_identificationModeFlag) { +// int32_t primitiveIndex = -1; +// float primitiveDepth = 0.0; +// +// if (drawBarsFlag) { +// /* +// * Scale histogram bars in Y-axis so that identification +// * will function when mouse is above a bar. This is helpful +// * for identification of bars with a very small height. +// */ +// glPushMatrix(); +// glScalef(1.0, 1000.0, 1.0); +// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// histogramPrimitives->getBarsPrimitive(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// primitiveIndex, +// primitiveDepth); +// glPopMatrix(); +// } +// else if (drawEnvelopeFlag) { +// /* +// * Increase line width for identification +// */ +// glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); +// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// histogramPrimitives->getEnvelopePrimitive(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// primitiveIndex, +// primitiveDepth); +// } +// +// if (primitiveIndex >= 0) { +// if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { +// m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), +// drawInfo->m_mapIndex, +// primitiveIndex, +// drawInfo->m_allMapsSelected); +// } +// } +// } +// else { +// drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); +// if (drawBarsFlag) { +// drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); +// } +// if (drawEnvelopeFlag) { +// glLineWidth(ENVELOPE_LINE_WIDTH); +// m_fixedPipelineDrawing->enableLineAntiAliasing(); +// drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); +// m_fixedPipelineDrawing->disableLineAntiAliasing(); +// } +// } +// } +// } +// } +// } +// } +// if (drawLineSeriesFlag) { +// for (const auto lineChart : lineSeriesChartsToDraw) { +// bool leftVerticalAxisFlag = true; +// switch (lineChart.m_verticalAxisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// leftVerticalAxisFlag = false; +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// break; +// } +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// if (leftVerticalAxisFlag) { +// glOrtho(xMin, xMax, +// yMinLeft, yMaxLeft, +// -10.0, 10.0); +// } +// else { +// glOrtho(xMin, xMax, +// yMinRight, yMaxRight, +// -10.0, 10.0); +// } +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// bool applyTransformationsFlag = false; +// if (applyTransformationsFlag) { +// glTranslatef(m_translation[0], +// m_translation[1], +// 0.0); +// +// const float chartWidth = chartGraphicsDrawingViewport[2]; +// const float chartHeight = chartGraphicsDrawingViewport[3]; +// const float halfWidth = chartWidth / 2.0; +// const float halfHeight = chartHeight / 2.0; +// glTranslatef(halfWidth, +// halfHeight, +// 0.0); +// glScalef(m_zooming, +// m_zooming, +// 1.0); +// glTranslatef(-halfWidth, +// -halfHeight, +// 0.0); +// } +// +// const float LINE_SERIES_LINE_WIDTH = 1.0f; +// if (m_identificationModeFlag) { +// int32_t primitiveIndex = -1; +// float primitiveDepth = 0.0; +// +// glLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); +// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// primitiveIndex, +// primitiveDepth); +// +// if (primitiveIndex >= 0) { +// if (m_selectionItemLineSeries->isOtherScreenDepthCloserToViewer(primitiveDepth)) { +// m_selectionItemLineSeries->setLineSeriesChart(const_cast(lineChart.m_lineSeriesChart), +// const_cast(lineChart.m_chartTwoCartesianData), +// primitiveIndex); +// } +// } +// } +// else { +// /* +// * Note: Anti-aliasing is only enabled when drawing the line. +// * Anti-aliasing cannot be enabled during identification since +// * identification encodes information in the colors (anti-aliasing +// * will alter the colors during drawing). +// */ +// m_fixedPipelineDrawing->enableLineAntiAliasing(); +// glLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); +// GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); +// m_fixedPipelineDrawing->disableLineAntiAliasing(); +// } +// +// /* +// * Save the transformation matrices and the viewport +// * If there is more than one line chart, this code will be executed +// * several times but since the top overlay is drawn last, the contents +// * of the top overlay will be used. +// */ +// updateViewportContentForCharting(chartGraphicsDrawingViewport); +// } +// } +// } +//} + /** * Draw a matrix chart. */ @@ -908,6 +1598,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() tabViewportY, tabViewportWidth, tabViewportHeight, + m_chartOverlaySet->getAxisLineThickness(), margins, false, /* do not draw box */ chartGraphicsDrawingViewport); @@ -1311,27 +2002,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateChartTitleHeight(const float vi * Widgth of viewport. * @param viewportHeight * Height of viewport. + * @param lineWidthPercentage + * The line width percentage. * @param cartesianAxis * The axis. * @param chartAxisLabel * Label for the axis. - * @param widthOut - * Width of text out. - * @param heightOut - * Height of text out. + * @param axisSizeInfo + * Output size info for the axis */ void BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, const float maximumDataValue, const float viewportWidth, const float viewportHeight, + const float lineWidthPercentage, ChartTwoCartesianAxis* cartesianAxis, AnnotationPercentSizeText* chartAxisLabel, - double& widthOut, - double& heightOut) + AxisSizeInfo& axisSizeInfoOut) { - widthOut = 0; - heightOut = 0; + double widthOut = 0; + double heightOut = 0; if (cartesianAxis == NULL) { return; @@ -1343,13 +2034,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH return; } - /* - * The percentage height from the label is also used - * by the axis numeric values. - */ CaretAssert(chartAxisLabel); chartAxisLabel->setTabIndex(m_tabIndex); + const float paddingSize = convertPercentageOfViewportToPixels(cartesianAxis->getPaddingSize(), + viewportHeight); + const float lineWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, + viewportHeight); + const float tickLength = lineWidth * 2.0f; + const float padTicksSize = (paddingSize + tickLength); + /* * The length of the axis does not matter here. * We are just estimating the width and height of the axes text labels. @@ -1372,21 +2066,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH * (so font size, style) are the same. We are only finding * height and width of all numeric values. */ - AnnotationPercentSizeText numericValueAnnotation(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - numericValueAnnotation = *chartAxisLabel; + AnnotationPercentSizeText textAnnotation(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + //numericValueAnnotation = *chartAxisLabel; + double numericsWidthOrHeight = 0.0; + textAnnotation.setFontPercentViewportSize(cartesianAxis->getNumericsTextSize()); for (std::vector::iterator iter = scaleValuesText.begin(); iter != scaleValuesText.end(); iter++) { const AString text = *iter; if ( ! text.isEmpty()) { - numericValueAnnotation.setText(text); + textAnnotation.setText(text); double textWidth = 0.0; double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(numericValueAnnotation, viewportWidth, viewportHeight, textWidth, textHeight); + m_textRenderer->getTextWidthHeightInPixels(textAnnotation, viewportWidth, viewportHeight, textWidth, textHeight); widthOut = std::max(widthOut, textWidth); heightOut = std::max(heightOut, textHeight); + + switch (cartesianAxis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + numericsWidthOrHeight = std::max(numericsWidthOrHeight, textHeight); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + numericsWidthOrHeight = std::max(numericsWidthOrHeight, textWidth); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + numericsWidthOrHeight = std::max(numericsWidthOrHeight, textWidth); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + numericsWidthOrHeight = std::max(numericsWidthOrHeight, textHeight); + break; + } } } @@ -1397,44 +2108,81 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: if (heightOut > 0) { - heightOut += s_tickLength; + heightOut += s_tickLengthPixels; } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: if (widthOut > 0) { - widthOut += s_tickLength; + widthOut += s_tickLengthPixels; } break; } + double labelHeight = 0.0; if (cartesianAxis->isShowLabel()) { double labelWidth = 0.0; - double labelHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(*chartAxisLabel, viewportWidth, viewportHeight, labelWidth, labelHeight); + textAnnotation.setFontPercentViewportSize(cartesianAxis->getLabelTextSize()); + textAnnotation.setText(chartAxisLabel->getText()); + m_textRenderer->getTextWidthHeightInPixels(textAnnotation, viewportWidth, viewportHeight, labelWidth, labelHeight); switch (cartesianAxis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += labelHeight; + heightOut += (labelHeight + padTicksSize); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += labelHeight; + widthOut += (labelHeight + padTicksSize); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += labelHeight; + widthOut += (labelHeight + padTicksSize); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += labelHeight; + heightOut += (labelHeight + padTicksSize); break; } } + + AxisSizeInfo sizeInfo(widthOut, + heightOut, + paddingSize, + lineWidthPercentage, + tickLength, + labelHeight, + numericsWidthOrHeight); + axisSizeInfoOut = sizeInfo; +} + +/** + * Convert a percentage of viewport width or height to pixels. + * When percentage width or height is zero, zero will be returned. + * Otherwise the returned value will ALWAYS be at least one. + * + * @param percentageWidthOrHeight + * The percentage of width or height (ranges 0.0 to 100.0). + * @param viewportWidthOrHeight + * The viewport width or height. + * @return + * Pixels size value. + */ +float +BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToPixels(const float percentageWidthOrHeight, + const float viewportWidthOrHeight) +{ + if (percentageWidthOrHeight <= 0.0f) { + return 0.0f; + } + + const float minimumWidthOrHeight = 1.0f; + const float pixelsWidthOrHeight = std::max((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight, + minimumWidthOrHeight); + return pixelsWidthOrHeight; } /** * Draw the chart graphics surrounding box and set the graphics viewport. - * drawChartGraphicsBoxAndSetViewport + * * @param vpX * Viewport X * @param vpY @@ -1443,6 +2191,104 @@ BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthH * Viewport width * @param vpHeight * Viewport height + * @param lineThicknessPercentage + * Thickness of lines in percentage of viewport height + * @param bottomAxisHeight + * Height of bottom axis + * @param topAxisHeight + * Height of top axis + * @param leftAxisWidth + * Width of left axis + * @param rightAxisWidth + * Width of right axis + * @param drawBoxFlag + * Controls drawing of box. + * @param chartGraphicsDrawingViewportOut + * Output containing viewport for drawing chart graphics within + * the box/grid that is adjusted for the box's line thickness. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const float lineThicknessPercentage, + const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth, const bool drawBoxFlag, + int32_t chartGraphicsDrawingViewportOut[4]) +{ + const float lineThicknessPixels = convertPercentageOfViewportToPixels(lineThicknessPercentage, + vpHeight); + const float halfGridLineWidth = lineThicknessPixels / 2.0; + + const float gridLeft = vpX + leftAxisWidth; + const float gridRight = vpX + vpWidth - rightAxisWidth; + const float gridBottom = vpY + bottomAxisHeight; + const float gridTop = vpY + vpHeight - topAxisHeight; + + glViewport(vpX, + vpY, + vpWidth, + vpHeight); + + if (drawBoxFlag) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(vpX, (vpX + vpWidth), + vpY, (vpY + vpHeight), + -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + std::unique_ptr gridData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + gridData->reserveForNumberOfVertices(8); + gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); + gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); + gridData->addVertex(gridRight - halfGridLineWidth, gridTop); + gridData->addVertex(gridRight, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); + gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); + gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); + glLineWidth(lineThicknessPixels); + drawPrimitivePrivate(gridData.get()); + } + + /* + * Region inside the grid's box + */ + const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); + const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); + const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); + const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); + + const int32_t graphicsWidth = graphicsRight - graphicsLeft; + const int32_t graphicsHeight = graphicsTop - graphicsBottom; + chartGraphicsDrawingViewportOut[0] = graphicsLeft; + chartGraphicsDrawingViewportOut[1] = graphicsBottom; + chartGraphicsDrawingViewportOut[2] = graphicsWidth; + chartGraphicsDrawingViewportOut[3] = graphicsHeight; +} + + +/** + * Draw the chart graphics surrounding box and set the graphics viewport. + * + * @param vpX + * Viewport X + * @param vpY + * Viewport Y + * @param vpWidth + * Viewport width + * @param vpHeight + * Viewport height + * @param lineThickness + * Thickness of lines in percentage of viewport height * @param marginSize * Margin around grid/box * @param drawBoxFlag @@ -1456,11 +2302,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const float vpY, const float vpWidth, const float vpHeight, + const float lineThickness, const Margins& margins, const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]) { - const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; + const float lineThicknessPixels = convertPercentageOfViewportToPixels(lineThickness, + vpHeight); + const float halfGridLineWidth = lineThicknessPixels / 2.0; const float gridLeft = vpX + margins.m_left; const float gridRight = vpX + vpWidth - margins.m_right; @@ -1494,17 +2343,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); - glLineWidth(GRID_LINE_WIDTH); + glLineWidth(lineThicknessPixels); drawPrimitivePrivate(gridData.get()); } /* * Region inside the grid's box */ - const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(GRID_LINE_WIDTH + 1.0)); - const int32_t graphicsRight = static_cast(gridRight - std::floor(GRID_LINE_WIDTH + 1.0)); - const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(GRID_LINE_WIDTH + 1.0)); - const int32_t graphicsTop = static_cast(gridTop - std::floor(GRID_LINE_WIDTH + 1.0)); + const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); + const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); + const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); + const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; @@ -1533,6 +2382,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons * Margin around graphics region. The margin corresponding to the * axis may be changed so that all text in the axis is visible * (and not cut off). + * @param axisSizeInfo + * Size info for the axis * @param axis * Axis that is drawn. * @param chartAxisLabel @@ -1552,6 +2403,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini const float tabViewportWidth, const float tabViewportHeight, const Margins& margins, + const AxisSizeInfo& axisSizeInfo, ChartTwoCartesianAxis* axis, AnnotationPercentSizeText* chartAxisLabel, float& axisMinimumOut, @@ -1641,11 +2493,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini */ AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - annotationText = *chartAxisLabel; + //annotationText = *chartAxisLabel; annotationText.setCustomTextColor(rgba); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); annotationText.setTabIndex(m_tabIndex); + annotationText.setFontPercentViewportSize(axis->getNumericsTextSize()); if (numScaleValuesToDraw > 0) { const bool showTicksEnabledFlag = axis->isShowTickmarks(); @@ -1670,7 +2523,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; tickStartY = margins.m_bottom; tickEndX = tickStartX; - tickEndY = tickStartY - s_tickLength; + tickEndY = tickStartY - axisSizeInfo.m_tickLength; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); if (i == firstTickIndex) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); @@ -1684,7 +2537,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; tickStartY = tabViewportHeight - margins.m_top; tickEndX = tickStartX; - tickEndY = tickStartY + s_tickLength; + tickEndY = tickStartY + s_tickLengthPixels; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); if (i == firstTickIndex) { annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); @@ -1697,7 +2550,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: tickStartX = margins.m_left; tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickEndX = tickStartX - s_tickLength; + tickEndX = tickStartX - s_tickLengthPixels; tickEndY = tickStartY; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); if (i == firstTickIndex) { @@ -1711,7 +2564,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: tickStartX = tabViewportWidth - margins.m_right; tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickEndX = tickStartX + s_tickLength; + tickEndX = tickStartX + s_tickLengthPixels; tickEndY = tickStartY; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); if (i == firstTickIndex) { @@ -1757,7 +2610,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini annotationText); } - glLineWidth(GRID_LINE_WIDTH); + glLineWidth(axisSizeInfo.m_linesWidth); drawPrimitivePrivate(ticksData.get()); @@ -1765,8 +2618,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini if (chartAxisLabel != NULL) { const AString axisTitle = chartAxisLabel->getText(); if ( ! axisTitle.isEmpty()) { - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + annotationText.setText(axisTitle); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); float labelTabX = axisVpWidth / 2.0; float labelTabY = axisVpHeight / 2.0; @@ -1775,46 +2629,51 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float mini case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: labelTabX = (axisVpWidth / 2.0) + margins.m_left; labelTabY = textMarginOffset; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - chartAxisLabel->setRotationAngle(0.0); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + annotationText.setRotationAngle(0.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: labelTabX = (axisVpWidth / 2.0) + margins.m_left; labelTabY = tabViewportHeight - textMarginOffset; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setRotationAngle(0.0); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + annotationText.setRotationAngle(0.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: labelTabX = textMarginOffset; labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setRotationAngle(-90.0); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + annotationText.setRotationAngle(-90.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: labelTabX = tabViewportWidth - textMarginOffset; labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - chartAxisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartAxisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartAxisLabel->setRotationAngle(90.0); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setRotationAngle(90.0); break; } if ((axisVpWidth > 0.0) && (axisVpHeight > 0.0)) { - chartAxisLabel->setCustomTextColor(rgba); - chartAxisLabel->setTextColor(CaretColorEnum::CUSTOM); - chartAxisLabel->setTabIndex(m_tabIndex); - chartAxisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); + annotationText.setCustomTextColor(rgba); + annotationText.setTextColor(CaretColorEnum::CUSTOM); + annotationText.setFontPercentViewportSize(axis->getLabelTextSize()); + //annotationText.setTabIndex(m_tabIndex); + //annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; - chartAxisLabel->getCoordinate()->setXYZ(tabPercentageX, + annotationText.getCoordinate()->setXYZ(tabPercentageX, tabPercentageY, 0.0f); - m_annotationsForDrawingOutput.push_back(chartAxisLabel); + m_textRenderer->drawTextAtViewportCoords(labelTabX, + labelTabY, + 0.0, + annotationText); + //m_annotationsForDrawingOutput.push_back(chartAxisLabel); } } @@ -1975,3 +2834,561 @@ m_allMapsSelected(allMapsSelected) BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() { } + +/** + * Constructor. + * + * @param textRenderer + * The text renderer. + * @param tabViewport + * Viewport of the tab containing the chart. + * @param dataMinX + * Minimum X-data value. + * @param dataMaxX + * Maximum X-data value. + * @param dataMinY + * Minimum Y-data value. + * @param dataMaxX + * Maximum Y-data value. + * @param axis + * Axis being setup. + * @param lineWidthPercentage + * The line width percentage. + */ +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::AxisDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, + const int32_t tabViewport[4], + const float dataMinX, + const float dataMaxX, + const float dataMinY, + const float dataMaxY, + const ChartAxisLocationEnum::Enum axisLocation, + const ChartTwoCartesianAxis* axis, + const AString& labelText, + const float lineWidthPercentage) +: m_axisLocation(axisLocation), +m_axis(axis), +m_textRenderer(textRenderer), +m_tabViewportX(tabViewport[0]), +m_tabViewportY(tabViewport[1]), +m_tabViewportWidth(tabViewport[2]), +m_tabViewportHeight(tabViewport[3]) +{ + m_axisValid = false; + m_axisWidth = 0.0f; + m_axisHeight = 0.0f; + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_axisMinimumValue = dataMinX; + m_axisMaximumValue = dataMaxX; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_axisMinimumValue = dataMinY; + m_axisMaximumValue = dataMaxY; + break; + } + + m_axisDisplayedFlag = false; + if (m_axis != NULL) { + CaretAssert(m_axis->getAxisLocation() == axisLocation); + m_axisDisplayedFlag = (axis->isEnabledByChart() + && axis->isDisplayedByUser()); + } + if ( ! m_axisDisplayedFlag) { + /* + * If axis is not displayed, use padding with 1% of space + */ + const float emptyAxisPaddingPercentage = 1.0f; + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_axisHeight = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, + m_tabViewportHeight); + m_labelPaddingSizePixels = m_axisHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_axisWidth = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, + m_tabViewportWidth); + m_labelPaddingSizePixels = m_axisWidth; + break; + } + + return; + } + + if (m_axis == NULL) { + return; + } + m_axisValid = true; + + /* + * Padding is percentage width or height dependent upon axis + */ + m_labelPaddingSizePixels = 0.0; + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), + m_tabViewportHeight); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), + m_tabViewportHeight); + break; + } + + m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(1.0f, m_tabViewportHeight); + + float dataMinimumValue = 0.0f; + float dataMaximumValue = 0.0f; + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + dataMinimumValue = dataMinX; + dataMaximumValue = dataMaxX; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + dataMinimumValue = dataMinY; + dataMaximumValue = dataMaxY; + break; + } + + m_lineDrawingWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, + m_tabViewportHeight); + m_tickLength = 0.0f; + if (m_axis->isShowTickmarks()) { + m_tickLength = m_lineDrawingWidth; // * 2.0f; + } + + float labelWidth = 0.0f; + float labelHeight = 0.0f; + initializeLabel(labelText, labelWidth, labelHeight); + + float numericsWidth = 0.0f; + float numericsHeight = 0.0f; + initializeNumericText(dataMinimumValue, dataMaximumValue, numericsWidth, numericsHeight); + + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_axisHeight = m_labelPaddingSizePixels + labelHeight + numericsHeight + m_labelPaddingSizePixels + m_tickLength; + CaretAssert(m_axisHeight >= 0.0f); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + /* Note: label is rotated on left/right so use it's height */ + m_axisWidth = m_labelPaddingSizePixels + labelHeight + numericsWidth + m_labelPaddingSizePixels + m_tickLength; + CaretAssert(m_axisWidth >= 0.0f); + break; + } +} + +/** + * Initialize the numeric text + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const AString& labelText, + float& widthOut, + float& heightOut) +{ + widthOut = 0.0f; + heightOut = 0.0f; + + if (m_axis == NULL) { + return; + } + + AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + if (m_axis->isShowLabel()) { + float xyz[3] = { 0.0f, 0.0f, 0.0f }; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + xyz[0] = 0.5f; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + xyz[0] = 0.5f; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + xyz[1] = 0.5f; + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + text->setRotationAngle(-90.0f); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + xyz[1] = 0.5f; + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + text->setRotationAngle(-90.0f); + break; + } + text->setText(labelText); + text->setFontPercentViewportSize(m_axis->getLabelTextSize()); + text->getCoordinate()->setXYZ(xyz); + + double textWidth = 0.0; + double textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*text, + m_tabViewportWidth, m_tabViewportHeight, + textWidth, textHeight); + widthOut = textWidth; + heightOut = textHeight; + } + + m_labelText.reset(text); +} + +/** + * Initialize the numeric text + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText(const float dataMinimumDataValue, + const float dataMaximumDataValue, + float& maxWidthOut, + float& maxHeightOut) +{ + maxWidthOut = 0.0f; + maxHeightOut = 0.0f; + + if (m_axis == NULL) { + return; + } + + /* + * Using an axis length of 1.0 will result in the + * offsets ranging (0.0 to 1.0) + */ + const float axisLength = 1.0; + std::vector scaleValuePositions; + std::vector scaleValuesText; + m_axis->getScaleValuesAndOffsets(dataMinimumDataValue, + dataMaximumDataValue, + axisLength, + m_axisMinimumValue, + m_axisMaximumValue, + scaleValuePositions, + scaleValuesText); + + CaretAssert(scaleValuePositions.size() == scaleValuesText.size()); + const int32_t numValues = static_cast(scaleValuesText.size()); + const int32_t firstIndex = 0; + const int32_t lastIndex = (numValues - 1); + for (int32_t i = 0; i < numValues; i++) { + AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + text->setFontPercentViewportSize(m_axis->getNumericsTextSize()); + + float xyz[3] = { 0.0f, 0.0f, 0.0f }; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + xyz[0] = scaleValuePositions[i]; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + if (i == firstIndex) { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + } + else if (i == lastIndex) { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + } + else { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + xyz[0] = scaleValuePositions[i]; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + if (i == firstIndex) { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + } + else if (i == lastIndex) { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + } + else { + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + xyz[1] = scaleValuePositions[i]; + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + if (i == firstIndex) { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + } + else if (i == lastIndex) { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + } + else { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + } + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + xyz[1] = scaleValuePositions[i]; + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + if (i == firstIndex) { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); + } + else if (i == lastIndex) { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + } + else { + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + } + break; + } + text->setText(scaleValuesText[i]); + + text->getCoordinate()->setXYZ(xyz); + + double textWidth = 0.0; + double textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*text, + m_tabViewportWidth, m_tabViewportHeight, + textWidth, textHeight); + + maxWidthOut = std::max(maxWidthOut, static_cast(textWidth)); + maxHeightOut = std::max(maxHeightOut, static_cast(textHeight)); + + m_numericsText.push_back(std::unique_ptr(text)); + } +} + +/** + * Set the axis viewport + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth) +{ + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_axisWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_axisHeight = m_tabViewportHeight - (bottomAxisHeight + topAxisHeight); + break; + } + if (m_axisWidth < 1.0f) { + m_axisWidth = 1.0f; + } + if (m_axisHeight < 1.0f) { + m_axisHeight = 1.0f; + } + + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + m_axisViewport[0] = leftAxisWidth; + m_axisViewport[1] = m_tabViewportY; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + m_axisViewport[0] = leftAxisWidth; + m_axisViewport[1] = m_tabViewportX + m_tabViewportHeight - topAxisHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + m_axisViewport[0] = m_tabViewportX; + m_axisViewport[1] = bottomAxisHeight; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + m_axisViewport[0] = m_tabViewportX + m_tabViewportWidth - rightAxisWidth; + m_axisViewport[1] = m_tabViewportY + bottomAxisHeight; + break; + } + + m_axisViewport[2] = m_axisWidth; + m_axisViewport[3] = m_axisHeight; + + CaretAssert(m_axisViewport[0] >= 0.0f); + CaretAssert(m_axisViewport[1] >= 0.0f); + CaretAssert(m_axisViewport[2] >= 0.0f); + CaretAssert(m_axisViewport[3] >= 0.0f); +} + +void +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4]) +{ + if (m_axis == NULL) { + return; + } + + if ( ! m_axisValid) { + return; + } + + if ( ! m_axisDisplayedFlag) { + return; + } + + const float vpX = m_axisViewport[0]; + const float vpY = m_axisViewport[1]; + const float vpWidth = m_axisViewport[2]; + const float vpHeight = m_axisViewport[3]; + + if (m_axis->isShowLabel()) { + float xyz[3]; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + xyz[0] = vpX + (vpWidth / 2.0f); + xyz[1] = vpY + m_labelPaddingSizePixels; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + xyz[0] = vpX + m_labelPaddingSizePixels; + xyz[1] = vpY + (vpHeight / 2.0f); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + xyz[0] = vpX + vpWidth - m_labelPaddingSizePixels; + xyz[1] = vpY + (vpHeight / 2.0f); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + xyz[0] = vpX + (vpWidth / 2.0f); + xyz[1] = vpY + vpHeight - m_labelPaddingSizePixels; + break; + } + m_labelText->setTextColor(CaretColorEnum::CUSTOM); + m_labelText->setCustomTextColor(foregroundFloatRGBA); + m_labelText->getCoordinate()->setXYZ(xyz); + } + + for (auto& text : m_numericsText) { + float xyz[3]; + text->getCoordinate()->getXYZ(xyz); + + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + xyz[0] = vpX + (vpWidth * xyz[0]); + xyz[1] = vpY + vpHeight - m_tickLength - m_labelPaddingSizePixels; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + xyz[0] = vpX + vpWidth - m_tickLength - m_labelPaddingSizePixels; + xyz[1] = vpY + (vpHeight * xyz[1]); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + xyz[0] = vpX + m_tickLength + m_labelPaddingSizePixels; + xyz[1] = vpY + (vpHeight * xyz[1]); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + xyz[0] = vpX + (vpWidth * xyz[0]); + xyz[1] = vpY + m_tickLength + m_labelPaddingSizePixels; + break; + } + + text->setTextColor(CaretColorEnum::CUSTOM); + text->setCustomTextColor(foregroundFloatRGBA); + text->getCoordinate()->setXYZ(xyz); + } +} + + +void +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, + const float foregroundFloatRGBA[4], + float& axisMinimumValueOut, + float& axisMaximumValueOut) +{ + axisMinimumValueOut = m_axisMinimumValue; + axisMaximumValueOut = m_axisMaximumValue; + + if (m_axis == NULL) { + return; + } + if ( ! m_axisValid) { + return; + } + + if ( ! m_axisDisplayedFlag) { + return; + } + + glColor3f(1.0, 0.0, 0.0); + glLineWidth(1.0); + glBegin(GL_LINE_LOOP); + glVertex2f(m_axisViewport[0], m_axisViewport[1]); + glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); + glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); + glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); + glEnd(); + + const int32_t numScaleValuesToDraw = static_cast(m_numericsText.size()); + + if (numScaleValuesToDraw > 0) { + const bool showTicksEnabledFlag = m_axis->isShowTickmarks(); + + std::unique_ptr ticksData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + foregroundFloatRGBA)); + ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); + + const int32_t firstTickIndex = 0; + const int32_t lastTickIndex = numScaleValuesToDraw - 1; + + for (int32_t i = 0; i < numScaleValuesToDraw; i++) { + CaretAssertVectorIndex(m_numericsText, i); + const AnnotationPercentSizeText* text = m_numericsText[i].get(); + float xyz[3]; + text->getCoordinate()->getXYZ(xyz); + const float textX = xyz[0]; + const float textY = xyz[1]; + + float tickStartX = textX; + float tickStartY = textY; + float tickEndX = 0.0; + float tickEndY = 0.0; + + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + tickStartY += m_labelPaddingSizePixels; + tickEndX = tickStartX; + tickEndY = tickStartY + m_tickLength; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + tickStartY -= m_labelPaddingSizePixels; + tickEndX = tickStartX; + tickEndY = tickStartY - m_tickLength; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + tickStartX += m_labelPaddingSizePixels; + tickEndX = tickStartX + m_tickLength; + tickEndY = tickStartY; + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + tickStartX -= m_labelPaddingSizePixels; + tickEndX = tickStartX - m_tickLength; + tickEndY = tickStartY; + break; + } + + if (showTicksEnabledFlag) { + if ((i != firstTickIndex) + && (i != lastTickIndex)) { + ticksData->addVertex(tickStartX, tickStartY); + ticksData->addVertex(tickEndX, tickEndY); + } + } + + m_textRenderer->drawTextAtViewportCoords(textX, + textY, + 0.0, + *text); + } + + glLineWidth(m_lineDrawingWidth); + chartDrawing->drawPrimitivePrivate(ticksData.get()); + } + + if (m_axis->isShowLabel()) { + float xyz[3]; + m_labelText->getCoordinate()->getXYZ(xyz); + m_textRenderer->drawTextAtViewportCoords(xyz[0], + xyz[1], + 0.0, + *(m_labelText.get())); + } +} \ No newline at end of file diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 6d0a09e3b..157fa12a8 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -115,6 +115,114 @@ namespace caret { int32_t m_min = 9999999; int32_t m_max = -9999999; }; + + class AxisDrawingInfo { + public: + AxisDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, + const int32_t tabViewport[4], + const float dataMinX, + const float dataMaxX, + const float dataMinY, + const float dataMaxY, + const ChartAxisLocationEnum::Enum axisLocation, + const ChartTwoCartesianAxis* axis, + const AString& labelText, + const float lineWidthPercentage); + + void setAxisViewport(const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth); + + void setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4]); + + void drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, + const float foregroundFloatRGBA[4], + float& axisMinimumValueOut, + float& axisMaximumValueOut); + + std::unique_ptr m_labelText; + + std::vector> m_numericsText; + + float m_axisWidth = 0.0f; + float m_axisHeight = 0.0f; + + /** Axis minimum value is produced by the axis scaling user/auto */ + float m_axisMinimumValue = 0.0f; + float m_axisMaximumValue = 0.0f; + + float m_labelPaddingSizePixels = 0.0f; + float m_numericsPaddingSizePixels = 0.0f; + bool m_axisValid = false; + bool m_axisDisplayedFlag = false; + + int32_t m_axisViewport[4]; + + private: + const ChartAxisLocationEnum::Enum m_axisLocation; + const ChartTwoCartesianAxis* m_axis; + BrainOpenGLTextRenderInterface* m_textRenderer; + const float m_tabViewportX = 0.0f; + const float m_tabViewportY = 0.0f; + const float m_tabViewportWidth = 0.0f; + const float m_tabViewportHeight = 0.0f; + float m_lineDrawingWidth = 1.0f; + float m_tickLength = 0.0f; + + void initializeNumericText(const float dataMinimumDataValue, + const float dataMaximumDataValue, + float& maxWidthOut, + float& maxHeightOut); + + void initializeLabel(const AString& labelText, + float& widthOut, + float& heightOut); + + }; + + class AxisSizeInfo { + public: + AxisSizeInfo() + : m_width(0.0), + m_height(0.0), + m_paddingSize(0.0), + m_linesWidth(0.0), + m_tickLength(0.0), + m_axisSize(0.0), + m_labelOffset(0.0), + m_numericsOffset(0.0) { } + + AxisSizeInfo(const double width, + const double height, + const double paddingSize, + const double linesWidth, + const double tickLength, + const double labelHeight, + const double numericsWidthOrHeight) + : m_width(width), + m_height(height), + m_paddingSize(paddingSize), + m_linesWidth(linesWidth), + m_tickLength(tickLength) { + m_labelOffset = m_paddingSize; + m_axisSize = (m_paddingSize + + labelHeight + + numericsWidthOrHeight + + tickLength); + m_numericsOffset = m_axisSize - tickLength; + } + + double m_width; + double m_height; + double m_paddingSize; + double m_linesWidth; + double m_tickLength; + + double m_axisSize; + double m_labelOffset; + double m_numericsOffset; + }; BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); @@ -138,10 +246,22 @@ namespace caret { const float vpY, const float vpWidth, const float vpHeight, + const float lineThickness, const Margins& margins, const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]); + void drawChartGraphicsBoxAndSetViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const float lineThicknessPercentage, + const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth, const bool drawBoxFlag, + int32_t chartGraphicsDrawingViewportOut[4]); + bool drawChartAxisCartesian(const float minimumDataValue, const float maximumDataValue, const float tabViewportX, @@ -149,6 +269,7 @@ namespace caret { const float tabViewportWidth, const float tabViewportHeight, const Margins& margins, + const AxisSizeInfo& axisSizeInfo, ChartTwoCartesianAxis* axis, AnnotationPercentSizeText* chartAxisLabel, float& axisMinimumOut, @@ -165,10 +286,10 @@ namespace caret { const float maximumDataValue, const float viewportWidth, const float viewportHeight, + const float lineWidthPercentage, ChartTwoCartesianAxis* cartesianAxis, AnnotationPercentSizeText* chartAxisLabel, - double& widthOut, - double& heightOut); + AxisSizeInfo& axisSizeInfoOut); void estimateChartTitleHeight(const float viewportWidth, const float viewportHeight, @@ -179,6 +300,9 @@ namespace caret { void updateViewportContentForCharting(const int32_t viewport[4]); + static float convertPercentageOfViewportToPixels(const float percentageWidthOrHeight, + const float viewportWidthOrHeight); + Brain* m_brain; BrainOpenGLViewportContent* m_viewportContent; @@ -224,7 +348,7 @@ namespace caret { static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; - static constexpr float s_tickLength = 5.0; + static constexpr float s_tickLengthPixels = 5.0; // ADD_NEW_MEMBERS_HERE diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 44c3886b6..ba28a8d14 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -130,7 +130,8 @@ m_tabIndex(tabIndex) m_chartTitle = createChartTitle(); m_chartTitleDisplayedFlag = true; - + m_axisLineThickness = 1.0f; + m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartAxisLeft", "ChartTwoCartesianAxis", @@ -150,6 +151,8 @@ m_tabIndex(tabIndex) m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); + m_sceneAssistant->add("m_axisLineThickness", + &m_axisLineThickness); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays.push_back(std::make_shared(this, @@ -193,6 +196,7 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; *m_chartTitle = *overlaySet->m_chartTitle; m_chartTitleDisplayedFlag = overlaySet->m_chartTitleDisplayedFlag; + m_axisLineThickness = overlaySet->m_axisLineThickness; m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } @@ -211,6 +215,7 @@ ChartTwoOverlaySet::copyCartesianAxes(const ChartTwoOverlaySet* overlaySet) *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; *m_chartAxisRight = *overlaySet->m_chartAxisRight; *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; + m_axisLineThickness = overlaySet->m_axisLineThickness; } /** @@ -943,6 +948,27 @@ ChartTwoOverlaySet::setChartTitleDislayed(const bool status) m_chartTitleDisplayedFlag = status; } +/** + * @return Thickness of box around chart and tick marks on axes + */ +float +ChartTwoOverlaySet::getAxisLineThickness() const +{ + return m_axisLineThickness; +} + +/** + * Set Thickness of box around chart and tick marks on axes + * + * @param axisLineThickness + * New value for Thickness of box around chart and tick marks on axes + */ +void +ChartTwoOverlaySet::setAxisLineThickness(const float axisLineThickness) +{ + m_axisLineThickness = axisLineThickness; +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 04dabbcdd..7afa1dd2e 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -95,6 +95,10 @@ namespace caret { void resetOverlayYokingToOff(); + float getAxisLineThickness() const; + + void setAxisLineThickness(const float axisLineThickness); + // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -157,6 +161,9 @@ namespace caret { bool m_inFirstOverlayChangedMethodFlag = false; + /** Thickness of box around chart and tick marks on axes*/ + float m_axisLineThickness = 1.0; + // ADD_NEW_MEMBERS_HERE friend class ChartTwoOverlay; diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 501cb49a2..0c4866b32 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -92,6 +92,12 @@ m_axisLocation(axisLocation) &m_showLabel); m_sceneAssistant->add("m_titleOverlayIndex", &m_titleOverlayIndex); + m_sceneAssistant->add("m_labelTextSize", + &m_labelTextSize); + m_sceneAssistant->add("m_numericsTextSize", + &m_numericsTextSize); + m_sceneAssistant->add("m_paddingSize", + &m_paddingSize); } /** @@ -157,6 +163,9 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_enabledByChart = obj.m_enabledByChart; m_showTickmarks = obj.m_showTickmarks; m_showLabel = obj.m_showLabel; + m_labelTextSize = obj.m_labelTextSize; + m_numericsTextSize = obj.m_numericsTextSize; + m_paddingSize = obj.m_paddingSize; limitUserScaleMinMaxToValidRange(); } @@ -505,6 +514,69 @@ ChartTwoCartesianAxis::setLabelOverlayIndex(const int32_t labelOverlayIndex) m_titleOverlayIndex = labelOverlayIndex; } +/** + * @return size of label text + */ +float +ChartTwoCartesianAxis::getLabelTextSize() const +{ + return m_labelTextSize; +} + +/** + * Set size of label text + * + * @param labelTextSize + * New value for size of label text + */ +void +ChartTwoCartesianAxis::setLabelTextSize(const float labelTextSize) +{ + m_labelTextSize = labelTextSize; +} + +/** + * @return size of numerics text + */ +float +ChartTwoCartesianAxis::getNumericsTextSize() const +{ + return m_numericsTextSize; +} + +/** + * Set size of numerics text + * + * @param numericsTextSize + * New value for size of numerics text + */ +void +ChartTwoCartesianAxis::setNumericsTextSize(const float numericsTextSize) +{ + m_numericsTextSize = numericsTextSize; +} + +/** + * @return size of padding + */ +float +ChartTwoCartesianAxis::getPaddingSize() const +{ + return m_paddingSize; +} + +/** + * Set size of padding + * + * @param paddingSize + * New value for size of padding + */ +void +ChartTwoCartesianAxis::setPaddingSize(const float paddingSize) +{ + m_paddingSize = paddingSize; +} + /** * Save information specific to this type of model to the scene. * @@ -629,8 +701,8 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, * Minimum data value * @param maximumDataValue * Maximum data value - * @param axisLengthInPixels - * Length of axis in pixels. + * @param axisLength + * Length of axis (no specific unit type is assumed) * @param minimumOut * Output minimum value for autoranging. * @param maximumOut @@ -645,7 +717,7 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, bool ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, const float maximumDataValue, - const float axisLengthInPixels, + const float axisLength, float& minimumOut, float& maximumOut, std::vector& scaleValuesOffsetInPixelsOut, @@ -659,7 +731,8 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, scaleValuesOffsetInPixelsOut.clear(); scaleValuesOut.clear(); - if (axisLengthInPixels < 25.0) { + if (axisLength <= 0.0) { + CaretAssert(0); return false; } @@ -822,7 +895,7 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, if ((labelParametricValue >= 0.0) && (labelParametricValue <= 1.0)) { - const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; + const float labelPixelsPosition = axisLength * labelParametricValue; labelNumericValues.push_back(labelValueForText); scaleValuesOffsetInPixelsOut.push_back(labelPixelsPosition); } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 278e59444..1c1f07c8a 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -102,9 +102,21 @@ namespace caret { void setShowLabel(const bool showLabel); + float getLabelTextSize() const; + + void setLabelTextSize(const float labelTextSize); + + float getNumericsTextSize() const; + + void setNumericsTextSize(const float numericsTextSize); + + float getPaddingSize() const; + + void setPaddingSize(const float paddingSize); + bool getScaleValuesAndOffsets(const float minimumDataValue, const float maximumDataValue, - const float axisLengthInPixels, + const float axisLength, float& minimumOut, float& maximumOut, std::vector& scaleValuesOffsetInPixelsOut, @@ -156,16 +168,16 @@ namespace caret { const ChartAxisLocationEnum::Enum m_axisLocation; /** Allowable range minimum NOT SAVED TO SCENE */ - mutable float m_rangeMinimumValue = 0.0; + mutable float m_rangeMinimumValue = 0.0f; /** Allowable range maximum NOT SAVED TO SCENE */ - mutable float m_rangeMaximumValue = 1.0; + mutable float m_rangeMaximumValue = 1.0f; - mutable float m_userScaleMinimumValue = -100.0; + mutable float m_userScaleMinimumValue = -100.0f; - mutable float m_userScaleMaximumValue = 100.0; + mutable float m_userScaleMaximumValue = 100.0f; - float m_axisLabelsStepValue = 1.0; + float m_axisLabelsStepValue = 1.0f; int32_t m_userDigitsRightOfDecimal = 1; @@ -182,6 +194,15 @@ namespace caret { int32_t m_userNumberOfSubdivisions = 2; + /** size of label text*/ + float m_labelTextSize = 5.0f; + + /** size of numerics text*/ + float m_numericsTextSize = 5.0f; + + /** size of padding*/ + float m_paddingSize = 0.0f; + bool m_enabledByChart = false; bool m_showTickmarks = true; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index b40b4556b..9d58e2bfe 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -76,6 +76,9 @@ using namespace caret; BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar) { + m_chartOverlaySet = NULL; + m_chartAxis = NULL; + m_axisDisplayedByUserCheckBox = new QCheckBox("Show Axis"); m_axisDisplayedByUserCheckBox->setToolTip("Show/hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, @@ -155,6 +158,33 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis when Auto is not checked"); + /* + * Size spin boxes + */ + m_labelSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_labelSizeSpinBox->setSuffix("%"); + QObject::connect(m_labelSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height"); + + m_numericsSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_numericsSizeSpinBox->setSuffix("%"); + QObject::connect(m_numericsSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height"); + + m_linesTicksSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_linesTicksSizeSpinBox->setSuffix("%"); + QObject::connect(m_linesTicksSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines and ticks as percentage of tab height"); + + m_paddingSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_paddingSizeSpinBox->setSuffix("%"); + QObject::connect(m_paddingSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); + /* * Group widgets for blocking signals */ @@ -172,12 +202,37 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); m_widgetGroup->add(m_numericSubdivisionsModeComboBox->getWidget()); m_widgetGroup->add(m_userSubdivisionsSpinBox); + m_widgetGroup->add(m_labelSizeSpinBox); + m_widgetGroup->add(m_numericsSizeSpinBox); + m_widgetGroup->add(m_linesTicksSizeSpinBox); + m_widgetGroup->add(m_paddingSizeSpinBox); + + /* + * Size layout + */ + QWidget* sizesWidget = new QWidget(); + QGridLayout* sizesLayout = new QGridLayout(sizesWidget); + WuQtUtilities::setLayoutSpacingAndMargins(sizesLayout, 3, 0); + int32_t sizesRow = 0; + sizesLayout->addWidget(new QLabel("Label"), sizesRow, 0); + sizesLayout->addWidget(m_labelSizeSpinBox, sizesRow, 1); + sizesRow++; + sizesLayout->addWidget(new QLabel("Numerics"), sizesRow, 0); + sizesLayout->addWidget(m_numericsSizeSpinBox, sizesRow, 1); + sizesRow++; + sizesLayout->addWidget(new QLabel("Lines/Ticks"), sizesRow, 0); + sizesLayout->addWidget(m_linesTicksSizeSpinBox, sizesRow, 1); + sizesRow++; + sizesLayout->addWidget(new QLabel("Padding"), sizesRow, 0); + sizesLayout->addWidget(m_paddingSizeSpinBox, sizesRow, 1); + sizesRow++; /* * Show widgets layout */ QWidget* showWidget = new QWidget(); QGridLayout* showLayout = new QGridLayout(showWidget); + WuQtUtilities::setLayoutSpacingAndMargins(showLayout, 8, 0); int32_t axisRow = 0; showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); axisRow++; @@ -246,12 +301,14 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra */ QGridLayout* gridLayout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 3, 0); - gridLayout->addLayout(topLayout, 0, 0, 1, 5); + gridLayout->addLayout(topLayout, 0, 0, 1, 7); gridLayout->addWidget(showWidget, 1, 0, Qt::AlignTop); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1); - gridLayout->addWidget(rangeWidget, 1, 2); + gridLayout->addWidget(sizesWidget, 1, 2, Qt::AlignTop); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 3); - gridLayout->addWidget(numericsWidget, 1, 4); + gridLayout->addWidget(rangeWidget, 1, 4, Qt::AlignTop); + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 5); + gridLayout->addWidget(numericsWidget, 1, 6, Qt::AlignTop); QVBoxLayout* dialogLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); @@ -434,13 +491,13 @@ BrainBrowserWindowToolBarChartTwoAxes::getSelectedAxisLocation() const void BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browserTabContent) { - ChartTwoOverlaySet* chartOverlaySet = NULL; + m_chartOverlaySet = NULL; std::vector validAxesLocations; ChartTwoCartesianAxis* selectedAxis = NULL; AnnotationPercentSizeText* axisLabel = NULL; getSelectionData(browserTabContent, - chartOverlaySet, + m_chartOverlaySet, validAxesLocations, selectedAxis, axisLabel); @@ -448,7 +505,7 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_widgetGroup->blockAllSignals(true); m_chartAxis = selectedAxis; - if ((chartOverlaySet != NULL) + if ((m_chartOverlaySet != NULL) && (m_chartAxis != NULL)) { m_axisComboBox->setupWithItems(validAxesLocations); m_axisComboBox->setSelectedItem(m_chartAxis->getAxisLocation()); @@ -471,7 +528,12 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); - const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); + m_labelSizeSpinBox->setValue(m_chartAxis->getLabelTextSize()); + m_numericsSizeSpinBox->setValue(m_chartAxis->getNumericsTextSize()); + m_linesTicksSizeSpinBox->setValue(m_chartOverlaySet->getAxisLineThickness()); + m_paddingSizeSpinBox->setValue(m_chartAxis->getPaddingSize()); + + const int32_t overlayCount = m_chartOverlaySet->getNumberOfDisplayedOverlays(); int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); if (overlayCount < comboBoxCount) { @@ -496,61 +558,61 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_widgetGroup->blockAllSignals(false); } -/** - * Update the content with the given axis. - * - * @param chartOverlaySet - * Chart overlay set containing axis. - * @param chartAxis - * New chart axis content. - */ -void -BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartOverlaySet, - ChartTwoCartesianAxis* chartAxis) -{ - m_chartAxis = chartAxis; - - if ((chartOverlaySet != NULL) - && (m_chartAxis != NULL)) { - m_widgetGroup->blockAllSignals(true); - m_axisDisplayedByUserCheckBox->setChecked(chartAxis->isDisplayedByUser()); - m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); - float rangeMin(0.0), rangeMax(0.0); - m_chartAxis->getRange(rangeMin, rangeMax); - m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); - m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); - m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); - m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); - m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); - m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); - const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); - m_userNumericFormatComboBox->setSelectedItem(numericFormat); - m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); - m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); - m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); - m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); - m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); - - const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); - int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); - const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); - if (overlayCount < comboBoxCount) { - m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); - } - else if (overlayCount > comboBoxCount) { - for (int32_t j = comboBoxCount; j < overlayCount; j++) { - m_axisLabelFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); - } - } - - if ((selectedOverlayIndex >= 0) - && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { - m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); - } - - m_widgetGroup->blockAllSignals(false); - } -} +///** +// * Update the content with the given axis. +// * +// * @param chartOverlaySet +// * Chart overlay set containing axis. +// * @param chartAxis +// * New chart axis content. +// */ +//void +//BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartOverlaySet, +// ChartTwoCartesianAxis* chartAxis) +//{ +// m_chartAxis = chartAxis; +// +// if ((chartOverlaySet != NULL) +// && (m_chartAxis != NULL)) { +// m_widgetGroup->blockAllSignals(true); +// m_axisDisplayedByUserCheckBox->setChecked(chartAxis->isDisplayedByUser()); +// m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); +// float rangeMin(0.0), rangeMax(0.0); +// m_chartAxis->getRange(rangeMin, rangeMax); +// m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); +// m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); +// m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); +// m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); +// m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); +// m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); +// const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); +// m_userNumericFormatComboBox->setSelectedItem(numericFormat); +// m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); +// m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); +// m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); +// m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); +// m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); +// +// const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); +// int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); +// const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); +// if (overlayCount < comboBoxCount) { +// m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); +// } +// else if (overlayCount > comboBoxCount) { +// for (int32_t j = comboBoxCount; j < overlayCount; j++) { +// m_axisLabelFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); +// } +// } +// +// if ((selectedOverlayIndex >= 0) +// && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { +// m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); +// } +// +// m_widgetGroup->blockAllSignals(false); +// } +//} /** * Called when a widget is changed by the user. @@ -572,6 +634,11 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); + m_chartAxis->setLabelTextSize(m_labelSizeSpinBox->value()); + m_chartOverlaySet->setAxisLineThickness(m_linesTicksSizeSpinBox->value()); + m_chartAxis->setNumericsTextSize(m_numericsSizeSpinBox->value()); + m_chartAxis->setPaddingSize(m_paddingSizeSpinBox->value()); + const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); CaretAssert(tabContent); @@ -664,6 +731,53 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumVal } } +///** +// * Called when the label size value is changed. +// * +// * @param value +// * New value. +// */ +//void +//BrainBrowserWindowToolBarChartTwoAxes::labelSizeValueChanged(double value) +//{ +//} +// +///** +// * Called when the numerics size value is changed. +// * +// * @param value +// * New value. +// */ +//void +//BrainBrowserWindowToolBarChartTwoAxes::numericsSizeValueChanged(double) +//{ +// +//} +// +///** +// * Called when the lines/ticks size value is changed. +// * +// * @param value +// * New value. +// */ +//void +//BrainBrowserWindowToolBarChartTwoAxes::linesTicksSizeValueChanged(double) +//{ +// +//} +// +///** +// * Called when the padding size value is changed. +// * +// * @param value +// * New value. +// */ +//void +//BrainBrowserWindowToolBarChartTwoAxes::paddingSizeValueChanged(double) +//{ +// +//} + /** * Called when a widget is changed by a slot using a bool parameter. * Parameters must match when using function pointers. diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index c5099b79a..4f4915126 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -72,6 +72,14 @@ namespace caret { void axisLabelToolButtonClicked(bool); +// void labelSizeValueChanged(double); +// +// void numericsSizeValueChanged(double); +// +// void linesTicksSizeValueChanged(double); +// +// void paddingSizeValueChanged(double); +// private: BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); @@ -85,8 +93,8 @@ namespace caret { ChartTwoCartesianAxis* &selectedAxisOut, AnnotationPercentSizeText* &axisLabelOut) const; - void updateControls(ChartTwoOverlaySet* chartOverlaySet, - ChartTwoCartesianAxis* chartAxis); +// void updateControls(ChartTwoOverlaySet* chartOverlaySet, +// ChartTwoCartesianAxis* chartAxis); void updateControls(BrowserTabContent* browserTabContent); @@ -120,6 +128,16 @@ namespace caret { QSpinBox* m_userSubdivisionsSpinBox; + QDoubleSpinBox* m_labelSizeSpinBox; + + QDoubleSpinBox* m_numericsSizeSpinBox; + + QDoubleSpinBox* m_linesTicksSizeSpinBox; + + QDoubleSpinBox* m_paddingSizeSpinBox; + + ChartTwoOverlaySet* m_chartOverlaySet; + ChartTwoCartesianAxis* m_chartAxis; WuQWidgetObjectGroup* m_widgetGroup; -- GitLab From 222a4a7bfd57e7f3b78a3cd1201662c43515f911 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 22 Aug 2017 16:32:57 -0500 Subject: [PATCH 359/755] Continuing revision of chart axes. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 1808 ++++------------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 156 +- src/Brain/ChartTwoOverlaySet.cxx | 181 +- src/Brain/ChartTwoOverlaySet.h | 23 +- src/Charting/CMakeLists.txt | 2 + src/Charting/ChartTwoTitle.cxx | 274 +++ src/Charting/ChartTwoTitle.h | 114 ++ src/Files/ChartableTwoFileBaseChart.cxx | 165 +- src/Files/ChartableTwoFileBaseChart.h | 20 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 137 +- .../BrainBrowserWindowToolBarChartTwoAxes.h | 14 +- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 55 +- .../BrainBrowserWindowToolBarChartTwoTitle.h | 8 + 13 files changed, 1035 insertions(+), 1922 deletions(-) create mode 100644 src/Charting/ChartTwoTitle.cxx create mode 100644 src/Charting/ChartTwoTitle.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 7e13a7232..f7d631cc0 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -43,6 +43,7 @@ #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" +#include "ChartTwoTitle.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileMatrixChart.h" @@ -353,6 +354,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch float yMinRight = std::numeric_limits::max(); float yMaxRight = -std::numeric_limits::max(); + /* + * Find histograms or line-series charts for drawing + * and also find min/max coordinates on axes + */ for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -485,26 +490,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch xMaxBottom = 0.0; } - /* - * Margin is region around the chart in which - * the axes legends, values, and ticks are drawn. - */ - const double marginSize = 10; - Margins margins(marginSize); - ChartTwoCartesianAxis* leftAxis = NULL; ChartTwoCartesianAxis* rightAxis = NULL; ChartTwoCartesianAxis* bottomAxis = NULL; ChartTwoCartesianAxis* topAxis = NULL; std::vector displayedAxes; - AnnotationPercentSizeText* leftAxisLabel = NULL; - AnnotationPercentSizeText* rightAxisLabel = NULL; - AnnotationPercentSizeText* bottomAxisLabel = NULL; - m_chartOverlaySet->getDisplayedChartAxes(displayedAxes, - leftAxisLabel, - rightAxisLabel, - bottomAxisLabel); + m_chartOverlaySet->getDisplayedChartAxes(displayedAxes); for (auto axis : displayedAxes) { CaretAssert(axis); switch (axis->getAxisLocation()) { @@ -523,7 +515,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } - AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); + ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); //double width = 0.0, height = 0.0; @@ -542,18 +534,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - bool allowTopAxisFlag = false; - -// if (m_chartOverlaySet->isChartTitleDisplayed()) { -// double titleHeight = 0.0; -// estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); -// margins.m_top = std::max(margins.m_top, titleHeight); -// } - const float lineWidthPercentage = m_chartOverlaySet->getAxisLineThickness(); /* - * Estimate axes sizes NEW + * Estimate size of title + */ + TitleDrawingInfo titleInfo(m_textRenderer, + m_viewport, + chartTitle); + + /* + * Estimate axes sizes but at this point we can only find the + * size one dimension (x or y) */ AxisDrawingInfo leftAxisInfo(m_textRenderer, m_viewport, @@ -563,7 +555,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT, leftAxis, - "Left", + m_chartOverlaySet->getAxisLabel(leftAxis), lineWidthPercentage); AxisDrawingInfo rightAxisInfo(m_textRenderer, m_viewport, @@ -573,7 +565,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxRight, ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT, rightAxis, - "Right", + m_chartOverlaySet->getAxisLabel(rightAxis), lineWidthPercentage); AxisDrawingInfo bottomAxisInfo(m_textRenderer, m_viewport, @@ -583,7 +575,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM, bottomAxis, - "Bottom", + m_chartOverlaySet->getAxisLabel(bottomAxis), lineWidthPercentage); AxisDrawingInfo topAxisInfo(m_textRenderer, m_viewport, @@ -593,27 +585,40 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP, topAxis, - "Top", + m_chartOverlaySet->getAxisLabel(topAxis), lineWidthPercentage); - const float bottomAxisHeight = bottomAxisInfo.m_axisHeight; + float topTitleHeight = titleInfo.m_titleHeight; const float topAxisHeight = topAxisInfo.m_axisHeight; + if (titleInfo.m_titleDisplayedFlag) { + topAxisInfo.m_axisHeight = 0.0f; + } + else { + topTitleHeight = 0.0f; + } + const float bottomAxisHeight = bottomAxisInfo.m_axisHeight; const float leftAxisWidth = leftAxisInfo.m_axisWidth; const float rightAxisWidth = rightAxisInfo.m_axisWidth; - leftAxisInfo.setAxisViewport(bottomAxisHeight, + titleInfo.setTitleViewport(leftAxisWidth, + rightAxisWidth); + leftAxisInfo.setAxisViewport(topTitleHeight, + bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); - rightAxisInfo.setAxisViewport(bottomAxisHeight, + rightAxisInfo.setAxisViewport(topTitleHeight, + bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); - bottomAxisInfo.setAxisViewport(bottomAxisHeight, + bottomAxisInfo.setAxisViewport(topTitleHeight, + bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); - topAxisInfo.setAxisViewport(bottomAxisHeight, + topAxisInfo.setAxisViewport(topTitleHeight, + bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); @@ -633,29 +638,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Ensure that there is sufficient space for the axes data display. */ - if ((tabViewportWidth > (marginSize * 3)) - && (tabViewportHeight > (marginSize * 3))) { + if ((tabViewportWidth > (leftAxisWidth + rightAxisWidth)) + && (tabViewportHeight > (bottomAxisHeight + topAxisHeight + topTitleHeight))) { + titleInfo.drawTitle(foregroundRGBA); leftAxisInfo.drawAxis(this, foregroundRGBA, yMinLeft, yMaxLeft); rightAxisInfo.drawAxis(this, foregroundRGBA, yMinRight, yMaxRight); topAxisInfo.drawAxis(this, foregroundRGBA, xMinTop, xMaxTop); bottomAxisInfo.drawAxis(this, foregroundRGBA, xMinBottom, xMaxBottom); -// if (m_chartOverlaySet->isChartTitleDisplayed()) { -// drawChartTitle(tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// chartTitle); -// } - drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), + topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, @@ -912,645 +910,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } - -///** -// * Draw a histogram or line series chart. -// * -// * @param chartDataType -// * Type of chart to draw. -// */ -//void -//BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType) -//{ -// bool drawHistogramFlag = false; -// bool drawLineSeriesFlag = false; -// switch (chartDataType) { -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: -// CaretAssert(0); -// return; -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: -// drawHistogramFlag = true; -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: -// drawLineSeriesFlag = true; -// break; -// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: -// CaretAssert(0); -// return; -// break; -// } -// -// const int32_t tabViewportX = m_viewport[0]; -// const int32_t tabViewportY = m_viewport[1]; -// const int32_t tabViewportWidth = m_viewport[2]; -// const int32_t tabViewportHeight = m_viewport[3]; -// -// int32_t chartGraphicsDrawingViewport[4] = { -// tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight -// }; -// -// const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); -// CaretAssert(numberOfOverlays > 0); -// const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); -// const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); -// if (drawHistogramFlag) { -// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); -// } -// else if (drawLineSeriesFlag) { -// CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); -// } -// else { -// CaretAssert(0); -// } -// -// std::vector> histogramDrawingInfo; -// std::deque lineSeriesChartsToDraw; -// -// /* -// * Get the histogram drawing information and overall extent -// */ -// float xMin = std::numeric_limits::max(); -// float xMax = -std::numeric_limits::max(); -// float yMinLeft = std::numeric_limits::max(); -// float yMaxLeft = -std::numeric_limits::max(); -// float yMinRight = std::numeric_limits::max(); -// float yMaxRight = -std::numeric_limits::max(); -// for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { -// ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); -// if ( ! chartOverlay->isEnabled()) { -// continue; -// } -// -// CaretMappableDataFile* mapFile = NULL; -// ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; -// int32_t selectedIndex = -1; -// chartOverlay->getSelectionData(mapFile, -// selectedIndexType, -// selectedIndex); -// if (mapFile == NULL) { -// continue; -// } -// -// ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); -// -// if (drawHistogramFlag) { -// ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); -// -// if (histogramChart->isValid()) { -// CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); -// AString errorMessage; -// histogramDrawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, -// selectedIndex, -// chartOverlay->getCartesianVerticalAxisLocation(), -// (chartOverlay->isAllMapsSupported() -// && chartOverlay->isAllMapsSelected())))); -// const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, -// (chartOverlay->isAllMapsSupported() -// && chartOverlay->isAllMapsSelected())); -// CaretAssert(histogram); -// float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; -// histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); -// if (histogramMaxX > histogramMinX) { -// xMin = std::min(xMin, histogramMinX); -// xMax = std::max(xMax, histogramMaxX); -// -// switch (chartOverlay->getCartesianVerticalAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// yMinRight = std::min(yMinRight, 0.0f); -// yMaxRight = std::max(yMaxRight, histogramMaxY); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// yMinLeft = std::min(yMinLeft, 0.0f); -// yMaxLeft = std::max(yMaxLeft, histogramMaxY); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); -// break; -// } -// } -// } -// } -// -// if (drawLineSeriesFlag) { -// const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); -// const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); -// const int32_t numHistory = lineSeriesHistory->getHistoryCount(); -// for (int32_t iHistory = (numHistory - 1); iHistory >= 0; iHistory--) { -// const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); -// CaretAssert(data); -// if (data->isSelected()) { -// BoundingBox boundingBox; -// if (data->getBounds(boundingBox)) { -// xMin = std::min(xMin, boundingBox.getMinX()); -// xMax = std::max(xMax, boundingBox.getMaxX()); -// -// switch (chartOverlay->getCartesianVerticalAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// yMinRight = std::min(yMinRight, boundingBox.getMinY()); -// yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); -// yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); -// break; -// } -// -// lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, -// data, -// chartOverlay->getCartesianVerticalAxisLocation())); -// } -// } -// } -// } -// } -// -// /* -// * Bounds valid? -// */ -// if ((xMin < xMax) -// && ((yMinLeft < yMaxLeft) || (yMinRight < yMaxRight))) { -// /* -// * Margin is region around the chart in which -// * the axes legends, values, and ticks are drawn. -// */ -// const double marginSize = 10; -// Margins margins(marginSize); -// -// ChartTwoCartesianAxis* leftAxis = NULL; -// ChartTwoCartesianAxis* rightAxis = NULL; -// ChartTwoCartesianAxis* bottomAxis = NULL; -// ChartTwoCartesianAxis* topAxis = NULL; -// -// std::vector displayedAxes; -// AnnotationPercentSizeText* leftAxisLabel = NULL; -// AnnotationPercentSizeText* rightAxisLabel = NULL; -// AnnotationPercentSizeText* bottomAxisLabel = NULL; -// m_chartOverlaySet->getDisplayedChartAxes(displayedAxes, -// leftAxisLabel, -// rightAxisLabel, -// bottomAxisLabel); -// for (auto axis : displayedAxes) { -// CaretAssert(axis); -// switch (axis->getAxisLocation()) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// bottomAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// leftAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// rightAxis = axis; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// topAxis = axis; -// break; -// } -// } -// -// AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); -// -// //double width = 0.0, height = 0.0; -// -// GLint vp[4]; -// glGetIntegerv(GL_VIEWPORT, vp); -// -// glViewport(tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight); -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// glOrtho(0, tabViewportWidth, 0, tabViewportHeight, -1.0, 1.0); -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool allowTopAxisFlag = false; -// -// if (m_chartOverlaySet->isChartTitleDisplayed()) { -// double titleHeight = 0.0; -// estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); -// margins.m_top = std::max(margins.m_top, titleHeight); -// } -// -// const float lineWidthPercentage = m_chartOverlaySet->getAxisLineThickness(); -// -// /* -// * Estimate axes sizes OLD -// */ -// AxisSizeInfo leftAxisSizeInfo; -// estimateCartesianChartAxisLegendsWidthHeight(yMinLeft, yMaxLeft, -// tabViewportWidth, tabViewportHeight, lineWidthPercentage, -// leftAxis, leftAxisLabel, leftAxisSizeInfo); -// margins.m_left = std::max(margins.m_left, leftAxisSizeInfo.m_width); -// AxisSizeInfo rightAxisSizeInfo; -// estimateCartesianChartAxisLegendsWidthHeight(yMinRight, yMaxRight, -// tabViewportWidth, tabViewportHeight, lineWidthPercentage, -// rightAxis, rightAxisLabel, rightAxisSizeInfo); -// margins.m_right = std::max(margins.m_right, rightAxisSizeInfo.m_width); -// AxisSizeInfo topAxisSizeInfo; -// if (allowTopAxisFlag) { -// CaretAssertMessage(0, "For top axis, will need to make space for chart title"); -// estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, -// tabViewportWidth, tabViewportHeight, lineWidthPercentage, -// topAxis, NULL, topAxisSizeInfo); -// margins.m_top = std::max(margins.m_top, topAxisSizeInfo.m_height); -// } -// AxisSizeInfo bottomAxisSizeInfo; -// estimateCartesianChartAxisLegendsWidthHeight(xMin, xMax, -// tabViewportWidth, tabViewportHeight, lineWidthPercentage, -// bottomAxis, bottomAxisLabel, bottomAxisSizeInfo); -// margins.m_bottom = std::max(margins.m_bottom, bottomAxisSizeInfo.m_height); -// -// /* -// * Estimate axes sizes NEW -// */ -// AxisDrawingInfo leftAxisInfo(m_textRenderer, -// m_viewport, -// xMin, -// xMax, -// yMinLeft, -// yMaxLeft, -// leftAxis, -// "Left", -// lineWidthPercentage); -// AxisDrawingInfo rightAxisInfo(m_textRenderer, -// m_viewport, -// xMin, -// xMax, -// yMinRight, -// yMaxRight, -// rightAxis, -// "Right", -// lineWidthPercentage); -// AxisDrawingInfo bottomAxisInfo(m_textRenderer, -// m_viewport, -// xMin, -// xMax, -// yMinLeft, -// yMaxLeft, -// bottomAxis, -// "Bottom", -// lineWidthPercentage); -// AxisDrawingInfo topAxisInfo(m_textRenderer, -// m_viewport, -// xMin, -// xMax, -// yMinLeft, -// yMaxLeft, -// topAxis, -// "Top", -// lineWidthPercentage); -// -// /* -// * Ensure that there is sufficient space for the axes data display. -// */ -// if ((tabViewportWidth > (marginSize * 3)) -// && (tabViewportHeight > (marginSize * 3))) { -// -// float axisMinimumValue = 0.0; -// float axisMaximumValue = 0.0; -// -// /* Draw legends and grids */ -// if (drawChartAxisCartesian(yMinLeft, -// yMaxLeft, -// tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// leftAxisSizeInfo, -// leftAxis, -// leftAxisLabel, -// axisMinimumValue, -// axisMaximumValue)) { -// yMinLeft = axisMinimumValue; -// yMaxLeft = axisMaximumValue; -// } -// -// if (drawChartAxisCartesian(yMinRight, -// yMaxRight, -// tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// rightAxisSizeInfo, -// rightAxis, -// rightAxisLabel, -// axisMinimumValue, -// axisMaximumValue)) { -// yMinRight = axisMinimumValue; -// yMaxRight = axisMaximumValue; -// } -// if (drawChartAxisCartesian(xMin, -// xMax, -// tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// bottomAxisSizeInfo, -// bottomAxis, -// bottomAxisLabel, -// axisMinimumValue, -// axisMaximumValue)) { -// xMin = axisMinimumValue; -// xMax = axisMaximumValue; -// } -// -// if (allowTopAxisFlag) { -// drawChartAxisCartesian(xMin, -// xMax, -// tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// topAxisSizeInfo, -// topAxis, -// NULL, -// axisMinimumValue, -// axisMaximumValue); -// } -// -// if (m_chartOverlaySet->isChartTitleDisplayed()) { -// drawChartTitle(tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// margins, -// chartTitle); -// } -// -// drawChartGraphicsBoxAndSetViewport(tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// m_chartOverlaySet->getAxisLineThickness(), -// margins, -// true, /* draw the box */ -// chartGraphicsDrawingViewport); -// } -// -// glViewport(chartGraphicsDrawingViewport[0], -// chartGraphicsDrawingViewport[1], -// chartGraphicsDrawingViewport[2], -// chartGraphicsDrawingViewport[3]); -// -// -// if (drawHistogramFlag) { -// /* -// * Draw the bars for all histogram and then draw the envelopes -// * so the envelopes are not obscured by the bars -// */ -// for (auto& drawInfo : histogramDrawingInfo) { -// if (drawInfo->m_histogramChart->isValid()) { -// const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); -// CaretAssert(cmdf); -// const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); -// const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); -// const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); -// -// if (drawBarsFlag -// || drawEnvelopeFlag) { -// bool leftVerticalAxisFlag = true; -// switch (drawInfo->m_verticalAxisLocation) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// leftVerticalAxisFlag = false; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// break; -// } -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// if (leftVerticalAxisFlag) { -// glOrtho(xMin, xMax, -// yMinLeft, yMaxLeft, -// -10.0, 10.0); -// } -// else { -// glOrtho(xMin, xMax, -// yMinRight, yMaxRight, -// -10.0, 10.0); -// } -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool applyTransformationsFlag = false; -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = chartGraphicsDrawingViewport[2]; -// const float chartHeight = chartGraphicsDrawingViewport[3]; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// /* -// * Save the transformation matrices and the viewport -// * If there is more than one line chart, this code will be executed -// * several times but since the top overlay is drawn last, the contents -// * of the top overlay will be used. -// */ -// updateViewportContentForCharting(chartGraphicsDrawingViewport); -// -// ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = -// drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, -// drawInfo->m_allMapsSelected); -// -// if (histogramPrimitives != NULL) { -// const float ENVELOPE_LINE_WIDTH = 1.0; -// -// if (m_identificationModeFlag) { -// int32_t primitiveIndex = -1; -// float primitiveDepth = 0.0; -// -// if (drawBarsFlag) { -// /* -// * Scale histogram bars in Y-axis so that identification -// * will function when mouse is above a bar. This is helpful -// * for identification of bars with a very small height. -// */ -// glPushMatrix(); -// glScalef(1.0, 1000.0, 1.0); -// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// histogramPrimitives->getBarsPrimitive(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// primitiveIndex, -// primitiveDepth); -// glPopMatrix(); -// } -// else if (drawEnvelopeFlag) { -// /* -// * Increase line width for identification -// */ -// glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); -// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// histogramPrimitives->getEnvelopePrimitive(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// primitiveIndex, -// primitiveDepth); -// } -// -// if (primitiveIndex >= 0) { -// if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { -// m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), -// drawInfo->m_mapIndex, -// primitiveIndex, -// drawInfo->m_allMapsSelected); -// } -// } -// } -// else { -// drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); -// if (drawBarsFlag) { -// drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); -// } -// if (drawEnvelopeFlag) { -// glLineWidth(ENVELOPE_LINE_WIDTH); -// m_fixedPipelineDrawing->enableLineAntiAliasing(); -// drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); -// m_fixedPipelineDrawing->disableLineAntiAliasing(); -// } -// } -// } -// } -// } -// } -// } -// if (drawLineSeriesFlag) { -// for (const auto lineChart : lineSeriesChartsToDraw) { -// bool leftVerticalAxisFlag = true; -// switch (lineChart.m_verticalAxisLocation) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// leftVerticalAxisFlag = false; -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// break; -// } -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// if (leftVerticalAxisFlag) { -// glOrtho(xMin, xMax, -// yMinLeft, yMaxLeft, -// -10.0, 10.0); -// } -// else { -// glOrtho(xMin, xMax, -// yMinRight, yMaxRight, -// -10.0, 10.0); -// } -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// bool applyTransformationsFlag = false; -// if (applyTransformationsFlag) { -// glTranslatef(m_translation[0], -// m_translation[1], -// 0.0); -// -// const float chartWidth = chartGraphicsDrawingViewport[2]; -// const float chartHeight = chartGraphicsDrawingViewport[3]; -// const float halfWidth = chartWidth / 2.0; -// const float halfHeight = chartHeight / 2.0; -// glTranslatef(halfWidth, -// halfHeight, -// 0.0); -// glScalef(m_zooming, -// m_zooming, -// 1.0); -// glTranslatef(-halfWidth, -// -halfHeight, -// 0.0); -// } -// -// const float LINE_SERIES_LINE_WIDTH = 1.0f; -// if (m_identificationModeFlag) { -// int32_t primitiveIndex = -1; -// float primitiveDepth = 0.0; -// -// glLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); -// GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// primitiveIndex, -// primitiveDepth); -// -// if (primitiveIndex >= 0) { -// if (m_selectionItemLineSeries->isOtherScreenDepthCloserToViewer(primitiveDepth)) { -// m_selectionItemLineSeries->setLineSeriesChart(const_cast(lineChart.m_lineSeriesChart), -// const_cast(lineChart.m_chartTwoCartesianData), -// primitiveIndex); -// } -// } -// } -// else { -// /* -// * Note: Anti-aliasing is only enabled when drawing the line. -// * Anti-aliasing cannot be enabled during identification since -// * identification encodes information in the colors (anti-aliasing -// * will alter the colors during drawing). -// */ -// m_fixedPipelineDrawing->enableLineAntiAliasing(); -// glLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); -// GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); -// m_fixedPipelineDrawing->disableLineAntiAliasing(); -// } -// -// /* -// * Save the transformation matrices and the viewport -// * If there is more than one line chart, this code will be executed -// * several times but since the top overlay is drawn last, the contents -// * of the top overlay will be used. -// */ -// updateViewportContentForCharting(chartGraphicsDrawingViewport); -// } -// } -// } -//} - /** * Draw a matrix chart. */ @@ -1569,37 +928,50 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() tabViewportHeight }; - Margins margins(3); + /* + * Estimate size of title + */ + float titleHeight = 0.0f; + ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); + TitleDrawingInfo titleInfo(m_textRenderer, + m_viewport, + chartTitle); - AnnotationPercentSizeText* chartTitle = m_chartOverlaySet->getChartTitle(); - if (m_chartOverlaySet->isChartTitleDisplayed()) { - double titleHeight = 0.0; - estimateChartTitleHeight(tabViewportWidth, tabViewportHeight, chartTitle, titleHeight); - if (titleHeight > 0.0) { - margins.m_top = std::max(margins.m_top, titleHeight + 2); - } + float bottomMargin = 3.0f; + float topMargin = 3.0f; + float leftMargin = 3.0f; + float rightMargin = 3.0f; + if (titleInfo.m_titleDisplayedFlag) { + topMargin = 0.0f; + titleHeight = titleInfo.m_titleHeight; } + titleInfo.setTitleViewport(leftMargin, + rightMargin); + glViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight); - if (m_chartOverlaySet->isChartTitleDisplayed()) { - drawChartTitle(tabViewportX, - tabViewportY, - tabViewportWidth, - tabViewportHeight, - margins, - chartTitle); - } + const float foregroundRGBA[4] = { + m_fixedPipelineDrawing->m_foregroundColorFloat[0], + m_fixedPipelineDrawing->m_foregroundColorFloat[1], + m_fixedPipelineDrawing->m_foregroundColorFloat[2], + 1.0f + }; + titleInfo.drawTitle(foregroundRGBA); drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), - margins, + titleHeight, + bottomMargin, + topMargin, + leftMargin, + rightMargin, false, /* do not draw box */ chartGraphicsDrawingViewport); @@ -1954,206 +1326,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() } -/** - * Estimate the size of the chart title - * - * @param viewportWidth - * Widgth of viewport. - * @param viewportHeight - * Height of viewport. - * @param chartTitle - * Title for the chart. - * @param heightOut - * Height of text out. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::estimateChartTitleHeight(const float viewportWidth, - const float viewportHeight, - AnnotationPercentSizeText* chartTitle, - double& heightOut) -{ - CaretAssert(chartTitle); - - heightOut = 0; - - if (chartTitle->getText().trimmed().isEmpty()) { - return; - } - - /* - * The percentage height from the label is also used - * by the axis numeric values. - */ - chartTitle->setTabIndex(m_tabIndex); - - - double dummyWidth = 0.0; - m_textRenderer->getTextWidthHeightInPixels(*chartTitle, viewportWidth, viewportHeight, dummyWidth, heightOut); -} - -/** - * Estimate the size of the axis' text. - * - * @param minimumDataValue - * Minimum data value - * @param maximumDataValue - * Maximum data value - * @param viewportWidth - * Widgth of viewport. - * @param viewportHeight - * Height of viewport. - * @param lineWidthPercentage - * The line width percentage. - * @param cartesianAxis - * The axis. - * @param chartAxisLabel - * Label for the axis. - * @param axisSizeInfo - * Output size info for the axis - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, - const float maximumDataValue, - const float viewportWidth, - const float viewportHeight, - const float lineWidthPercentage, - ChartTwoCartesianAxis* cartesianAxis, - AnnotationPercentSizeText* chartAxisLabel, - AxisSizeInfo& axisSizeInfoOut) -{ - double widthOut = 0; - double heightOut = 0; - - if (cartesianAxis == NULL) { - return; - } - if ( ! cartesianAxis->isEnabledByChart()) { - return; - } - if ( ! cartesianAxis->isDisplayedByUser()) { - return; - } - - CaretAssert(chartAxisLabel); - chartAxisLabel->setTabIndex(m_tabIndex); - - const float paddingSize = convertPercentageOfViewportToPixels(cartesianAxis->getPaddingSize(), - viewportHeight); - const float lineWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, - viewportHeight); - const float tickLength = lineWidth * 2.0f; - const float padTicksSize = (paddingSize + tickLength); - - /* - * The length of the axis does not matter here. - * We are just estimating the width and height of the axes text labels. - */ - const float axisLength = 1000.0; - float minimumValue = 0.0; - float maximumValue = 0.0; - std::vector scaleValueOffsetInPixels; - std::vector scaleValuesText; - cartesianAxis->getScaleValuesAndOffsets(minimumDataValue, - maximumDataValue, - axisLength, - minimumValue, - maximumValue, - scaleValueOffsetInPixels, - scaleValuesText); - - /* - * For sizing text for numeric values, copy the label annotation - * (so font size, style) are the same. We are only finding - * height and width of all numeric values. - */ - AnnotationPercentSizeText textAnnotation(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - //numericValueAnnotation = *chartAxisLabel; - double numericsWidthOrHeight = 0.0; - textAnnotation.setFontPercentViewportSize(cartesianAxis->getNumericsTextSize()); - for (std::vector::iterator iter = scaleValuesText.begin(); - iter != scaleValuesText.end(); - iter++) { - const AString text = *iter; - if ( ! text.isEmpty()) { - textAnnotation.setText(text); - double textWidth = 0.0; - double textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(textAnnotation, viewportWidth, viewportHeight, textWidth, textHeight); - - widthOut = std::max(widthOut, textWidth); - heightOut = std::max(heightOut, textHeight); - - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - numericsWidthOrHeight = std::max(numericsWidthOrHeight, textHeight); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - numericsWidthOrHeight = std::max(numericsWidthOrHeight, textWidth); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - numericsWidthOrHeight = std::max(numericsWidthOrHeight, textWidth); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - numericsWidthOrHeight = std::max(numericsWidthOrHeight, textHeight); - break; - } - } - } - - /* - * Add space for the numeric value tick marks - */ - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - if (heightOut > 0) { - heightOut += s_tickLengthPixels; - } - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - if (widthOut > 0) { - widthOut += s_tickLengthPixels; - } - break; - } - - double labelHeight = 0.0; - if (cartesianAxis->isShowLabel()) { - double labelWidth = 0.0; - textAnnotation.setFontPercentViewportSize(cartesianAxis->getLabelTextSize()); - textAnnotation.setText(chartAxisLabel->getText()); - m_textRenderer->getTextWidthHeightInPixels(textAnnotation, viewportWidth, viewportHeight, labelWidth, labelHeight); - - switch (cartesianAxis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - heightOut += (labelHeight + padTicksSize); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += (labelHeight + padTicksSize); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - /** Text is rotated 90 degrees so use HEIGHT */ - widthOut += (labelHeight + padTicksSize); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - heightOut += (labelHeight + padTicksSize); - break; - } - } - - AxisSizeInfo sizeInfo(widthOut, - heightOut, - paddingSize, - lineWidthPercentage, - tickLength, - labelHeight, - numericsWidthOrHeight); - axisSizeInfoOut = sizeInfo; -} - /** * Convert a percentage of viewport width or height to pixels. * When percentage width or height is zero, zero will be returned. @@ -2193,6 +1365,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToPixels(con * Viewport height * @param lineThicknessPercentage * Thickness of lines in percentage of viewport height + * @param titleHeight + * Height of the title * @param bottomAxisHeight * Height of bottom axis * @param topAxisHeight @@ -2213,10 +1387,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const float vpWidth, const float vpHeight, const float lineThicknessPercentage, + const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, - const float rightAxisWidth, const bool drawBoxFlag, + const float rightAxisWidth, + const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]) { const float lineThicknessPixels = convertPercentageOfViewportToPixels(lineThicknessPercentage, @@ -2226,95 +1402,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const float gridLeft = vpX + leftAxisWidth; const float gridRight = vpX + vpWidth - rightAxisWidth; const float gridBottom = vpY + bottomAxisHeight; - const float gridTop = vpY + vpHeight - topAxisHeight; - - glViewport(vpX, - vpY, - vpWidth, - vpHeight); - - if (drawBoxFlag) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(vpX, (vpX + vpWidth), - vpY, (vpY + vpHeight), - -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - std::unique_ptr gridData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - gridData->reserveForNumberOfVertices(8); - gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); - gridData->addVertex(gridRight - halfGridLineWidth, gridTop); - gridData->addVertex(gridRight, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); - gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); - glLineWidth(lineThicknessPixels); - drawPrimitivePrivate(gridData.get()); - } - - /* - * Region inside the grid's box - */ - const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); - const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); - const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); - const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); - - const int32_t graphicsWidth = graphicsRight - graphicsLeft; - const int32_t graphicsHeight = graphicsTop - graphicsBottom; - chartGraphicsDrawingViewportOut[0] = graphicsLeft; - chartGraphicsDrawingViewportOut[1] = graphicsBottom; - chartGraphicsDrawingViewportOut[2] = graphicsWidth; - chartGraphicsDrawingViewportOut[3] = graphicsHeight; -} - - -/** - * Draw the chart graphics surrounding box and set the graphics viewport. - * - * @param vpX - * Viewport X - * @param vpY - * Viewport Y - * @param vpWidth - * Viewport width - * @param vpHeight - * Viewport height - * @param lineThickness - * Thickness of lines in percentage of viewport height - * @param marginSize - * Margin around grid/box - * @param drawBoxFlag - * Controls drawing of box. - * @param chartGraphicsDrawingViewportOut - * Output containing viewport for drawing chart graphics within - * the box/grid that is adjusted for the box's line thickness. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, - const float lineThickness, - const Margins& margins, - const bool drawBoxFlag, - int32_t chartGraphicsDrawingViewportOut[4]) -{ - const float lineThicknessPixels = convertPercentageOfViewportToPixels(lineThickness, - vpHeight); - const float halfGridLineWidth = lineThicknessPixels / 2.0; - - const float gridLeft = vpX + margins.m_left; - const float gridRight = vpX + vpWidth - margins.m_right; - const float gridBottom = vpY + margins.m_bottom; - const float gridTop = vpY + vpHeight - margins.m_top; + const float gridTop = vpY + vpHeight - topAxisHeight - titleHeight; glViewport(vpX, vpY, @@ -2350,10 +1438,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons /* * Region inside the grid's box */ - const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); - const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); - const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); - const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); + const int32_t graphicsLeft = static_cast(gridLeft); + const int32_t graphicsRight = static_cast(gridRight); + const int32_t graphicsBottom = static_cast(gridBottom); + const int32_t graphicsTop = static_cast(gridTop); +// const int32_t graphicsLeft = static_cast(gridLeft + 0.5f); +// const int32_t graphicsRight = static_cast(gridRight - 0.5f); +// const int32_t graphicsBottom = static_cast(gridBottom + 0.5f); +// const int32_t graphicsTop = static_cast(gridTop - 0.5f); +// const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(halfGridLineWidth + 1.0)); +// const int32_t graphicsRight = static_cast(gridRight - std::floor(halfGridLineWidth + 1.0)); +// const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(halfGridLineWidth + 1.0)); +// const int32_t graphicsTop = static_cast(gridTop - std::floor(halfGridLineWidth + 1.0)); +// const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); +// const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); +// const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); +// const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; @@ -2363,413 +1463,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons chartGraphicsDrawingViewportOut[3] = graphicsHeight; } -/** - * Draw the chart axes grid/box - * - * @param minimumDataValue - * Minimum data value - * @param maximumDataValue - * Maximum data value - * @param tabViewportX - * Viewport X for all chart content - * @param tabViewportY - * Viewport Y for all chart content - * @param tabViewportWidth - * Viewport width for all chart content - * @param tabViewportHeight - * Viewport height for all chart content - * @param margins - * Margin around graphics region. The margin corresponding to the - * axis may be changed so that all text in the axis is visible - * (and not cut off). - * @param axisSizeInfo - * Size info for the axis - * @param axis - * Axis that is drawn. - * @param chartAxisLabel - * Axis label. - * @param axisMinimumOut - * Minimum value along the axis. - * @param axisMaximumOut - * Maximum value along the axis. - * @return - * True if the axis is valid and was drawn, else false. - */ -bool -BrainOpenGLChartTwoDrawingFixedPipeline::drawChartAxisCartesian(const float minimumDataValue, - const float maximumDataValue, - const float tabViewportX, - const float tabViewportY, - const float tabViewportWidth, - const float tabViewportHeight, - const Margins& margins, - const AxisSizeInfo& axisSizeInfo, - ChartTwoCartesianAxis* axis, - AnnotationPercentSizeText* chartAxisLabel, - float& axisMinimumOut, - float& axisMaximumOut) -{ - if (axis == NULL) { - return false; - } - if ( ! axis->isEnabledByChart()) { - return false; - } - - int32_t axisVpX = 0; - int32_t axisVpY = 0; - int32_t axisVpWidth = 0; - int32_t axisVpHeight = 0; - float axisLength = 0.0; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisVpX = tabViewportX + margins.m_left; - axisVpY = tabViewportY; - axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); - axisVpHeight = margins.m_bottom; - axisLength = axisVpWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisVpX = tabViewportX + margins.m_left; - axisVpY = tabViewportY + tabViewportHeight - margins.m_top; - axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); - axisVpHeight = margins.m_top; - axisLength = axisVpWidth; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisVpX = tabViewportX; - axisVpY = tabViewportY + margins.m_bottom; - axisVpWidth = margins.m_left + 1; /* so ticks go to box */ - axisVpHeight = tabViewportHeight - (margins.m_bottom + margins.m_top); - axisLength = axisVpHeight; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisVpX = tabViewportX + tabViewportWidth - margins.m_right; - axisVpY = tabViewportY + margins.m_bottom; - axisVpWidth = margins.m_right; - axisVpHeight = tabViewportHeight - (margins.m_bottom + margins.m_top); - axisLength = axisVpHeight; - break; - } - - std::vector scaleValueOffsetInPixels; - std::vector scaleValuesText; - const bool validAxisFlag = axis->getScaleValuesAndOffsets(minimumDataValue, - maximumDataValue, - axisLength, - axisMinimumOut, - axisMaximumOut, - scaleValueOffsetInPixels, - scaleValuesText); - if ( ! validAxisFlag) { - return false; - } - - /* - * If user has disabled display of axis no further action is needed - * as the axisMinimumOut and axisMaximumOut have been calculated - */ - if ( ! axis->isDisplayedByUser()) { - /* - * Even though axis is not displayed, declare the axis as valid - * so that axisMinimumOut and axisMaximumOut are used by caller - * of this method. Otherwise, height of chart will 'jump' as - * axis is turned on/off - */ - return true; - } - - const float rgba[4] = { - m_fixedPipelineDrawing->m_foregroundColorFloat[0], - m_fixedPipelineDrawing->m_foregroundColorFloat[1], - m_fixedPipelineDrawing->m_foregroundColorFloat[2], - 1.0 - }; - - const int32_t numScaleValuesToDraw = static_cast(scaleValuesText.size()); - - /* - * For scale text, make a copy of the axis label so font properties match - */ - AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - //annotationText = *chartAxisLabel; - annotationText.setCustomTextColor(rgba); - annotationText.setTextColor(CaretColorEnum::CUSTOM); - annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - annotationText.setTabIndex(m_tabIndex); - annotationText.setFontPercentViewportSize(axis->getNumericsTextSize()); - - if (numScaleValuesToDraw > 0) { - const bool showTicksEnabledFlag = axis->isShowTickmarks(); - - std::unique_ptr ticksData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); - - const int32_t firstTickIndex = 0; - const int32_t lastTickIndex = numScaleValuesToDraw - 1; - - for (int32_t i = 0; i < numScaleValuesToDraw; i++) { - float tickStartX = 0.0; - float tickStartY = 0.0; - float tickEndX = 0.0; - float tickEndY = 0.0; - const float halfGridLineWidth = GRID_LINE_WIDTH / 2.0; - - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickStartY = margins.m_bottom; - tickEndX = tickStartX; - tickEndY = tickStartY - axisSizeInfo.m_tickLength; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - if (i == firstTickIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - } - else if (i == lastTickIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - } - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - tickStartX = margins.m_left + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickStartY = tabViewportHeight - margins.m_top; - tickEndX = tickStartX; - tickEndY = tickStartY + s_tickLengthPixels; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - if (i == firstTickIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - } - else if (i == lastTickIndex) { - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - } - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - tickStartX = margins.m_left; - tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickEndX = tickStartX - s_tickLengthPixels; - tickEndY = tickStartY; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - if (i == firstTickIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - } - else if (i == lastTickIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - } - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - tickStartX = tabViewportWidth - margins.m_right; - tickStartY = margins.m_bottom + scaleValueOffsetInPixels[i] + halfGridLineWidth; - tickEndX = tickStartX + s_tickLengthPixels; - tickEndY = tickStartY; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - if (i == firstTickIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - } - else if (i == lastTickIndex) { - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - } - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - break; - } - - if (showTicksEnabledFlag) { - if ((i != firstTickIndex) - && (i != lastTickIndex)) { - ticksData->addVertex(tickStartX, tickStartY); - ticksData->addVertex(tickEndX, tickEndY); - } - } - - float textX = tickEndX; - float textY = tickEndY; - const float textOffset = 3.0; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - textY -= textOffset; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - textY += textOffset; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - textX -= textOffset; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - textX += textOffset; - break; - } - annotationText.setText(scaleValuesText[i]); - - m_textRenderer->drawTextAtViewportCoords(textX, - textY, - 0.0, - annotationText); - } - - glLineWidth(axisSizeInfo.m_linesWidth); - drawPrimitivePrivate(ticksData.get()); - - - if (axis->isShowLabel()) { - if (chartAxisLabel != NULL) { - const AString axisTitle = chartAxisLabel->getText(); - if ( ! axisTitle.isEmpty()) { - annotationText.setText(axisTitle); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - - float labelTabX = axisVpWidth / 2.0; - float labelTabY = axisVpHeight / 2.0; - const float textMarginOffset = 5.0; - switch (axis->getAxisLocation()) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - labelTabX = (axisVpWidth / 2.0) + margins.m_left; - labelTabY = textMarginOffset; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - annotationText.setRotationAngle(0.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - labelTabX = (axisVpWidth / 2.0) + margins.m_left; - labelTabY = tabViewportHeight - textMarginOffset; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - annotationText.setRotationAngle(0.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - labelTabX = textMarginOffset; - labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - annotationText.setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - labelTabX = tabViewportWidth - textMarginOffset; - labelTabY = (axisVpHeight / 2.0) + margins.m_bottom; - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setRotationAngle(90.0); - break; - } - - if ((axisVpWidth > 0.0) - && (axisVpHeight > 0.0)) { - annotationText.setCustomTextColor(rgba); - annotationText.setTextColor(CaretColorEnum::CUSTOM); - annotationText.setFontPercentViewportSize(axis->getLabelTextSize()); - //annotationText.setTabIndex(m_tabIndex); - //annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; - const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; - annotationText.getCoordinate()->setXYZ(tabPercentageX, - tabPercentageY, - 0.0f); - - m_textRenderer->drawTextAtViewportCoords(labelTabX, - labelTabY, - 0.0, - annotationText); - //m_annotationsForDrawingOutput.push_back(chartAxisLabel); - } - - } - } - } - - return true; - } - - return false; -} - -/** - * Draw the chart axes grid/box - * - * @param tabViewportX - * Viewport X for all chart content - * @param tabViewportY - * Viewport Y for all chart content - * @param tabViewportWidth - * Viewport width for all chart content - * @param tabViewportHeight - * Viewport height for all chart content - * @param margins - * Margin around graphics region. The margin corresponding to the - * axis may be changed so that all text in the axis is visible - * (and not cut off). - * @param chartTitle - * The chart title annotation. - */ -void -BrainOpenGLChartTwoDrawingFixedPipeline::drawChartTitle(const float tabViewportX, - const float tabViewportY, - const float tabViewportWidth, - const float tabViewportHeight, - const Margins& margins, - AnnotationPercentSizeText* chartTitle) -{ - if (chartTitle == NULL) { - return; - } - - const AString text = chartTitle->getText().trimmed(); - if (text.isEmpty()) { - return; - } - - int32_t axisVpX = 0; - int32_t axisVpY = 0; - int32_t axisVpWidth = 0; - int32_t axisVpHeight = 0; - float axisLength = 0.0; - axisVpX = tabViewportX + margins.m_left; - axisVpY = tabViewportY + tabViewportHeight - margins.m_top; - axisVpWidth = tabViewportWidth - (margins.m_left + margins.m_right); - axisVpHeight = margins.m_top; - axisLength = axisVpWidth; - - const float rgba[4] = { - m_fixedPipelineDrawing->m_foregroundColorFloat[0], - m_fixedPipelineDrawing->m_foregroundColorFloat[1], - m_fixedPipelineDrawing->m_foregroundColorFloat[2], - 1.0 - }; - - chartTitle->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartTitle->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - - float labelTabX = axisVpWidth / 2.0; - float labelTabY = axisVpHeight / 2.0; - const float textMarginOffset = 5.0; - labelTabX = (axisVpWidth / 2.0) + margins.m_left; - labelTabY = tabViewportHeight - textMarginOffset; - chartTitle->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - chartTitle->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - chartTitle->setRotationAngle(0.0); - - if ((axisVpWidth > 0.0) - && (axisVpHeight > 0.0)) { - chartTitle->setCustomTextColor(rgba); - chartTitle->setTextColor(CaretColorEnum::CUSTOM); - chartTitle->setTabIndex(m_tabIndex); - chartTitle->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - const float tabPercentageX = (labelTabX / tabViewportWidth) * 100.0f; - const float tabPercentageY = (labelTabY / tabViewportHeight) * 100.0f; - chartTitle->getCoordinate()->setXYZ(tabPercentageX, - tabPercentageY, - 0.0f); - - m_annotationsForDrawingOutput.push_back(chartTitle); - } -} - - /** * Update the viewport content with charting viewport and matrices. + * + * @param viewport + * The viewport. */ void BrainOpenGLChartTwoDrawingFixedPipeline::updateViewportContentForCharting(const int32_t viewport[4]) @@ -2850,8 +1548,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramCh * Minimum Y-data value. * @param dataMaxX * Maximum Y-data value. + * @param axisLocation + * Location of axis as 'axis' may be NULL. * @param axis * Axis being setup. + * @param labelText + * Text for the label. * @param lineWidthPercentage * The line width percentage. */ @@ -2868,8 +1570,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::AxisDrawingInfo(BrainO : m_axisLocation(axisLocation), m_axis(axis), m_textRenderer(textRenderer), -m_tabViewportX(tabViewport[0]), -m_tabViewportY(tabViewport[1]), m_tabViewportWidth(tabViewport[2]), m_tabViewportHeight(tabViewport[3]) { @@ -2888,6 +1588,8 @@ m_tabViewportHeight(tabViewport[3]) m_axisMaximumValue = dataMaxY; break; } + float dataMinimumValue = m_axisMinimumValue; + float dataMaximumValue = m_axisMaximumValue; m_axisDisplayedFlag = false; if (m_axis != NULL) { @@ -2897,7 +1599,7 @@ m_tabViewportHeight(tabViewport[3]) } if ( ! m_axisDisplayedFlag) { /* - * If axis is not displayed, use padding with 1% of space + * If axis is not displayed, use padding with a small percentage of space. */ const float emptyAxisPaddingPercentage = 1.0f; switch (axisLocation) { @@ -2924,36 +1626,25 @@ m_tabViewportHeight(tabViewport[3]) m_axisValid = true; /* - * Padding is percentage width or height dependent upon axis + * Padding values are percentages so convert to pixels. */ - m_labelPaddingSizePixels = 0.0; + const float numericsTicksPaddingPercentage = 1.0f; + m_labelPaddingSizePixels = 0.0f; + m_numericsTicksPaddingSizePixels = 0.0f; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), m_tabViewportHeight); + m_numericsTicksPaddingSizePixels = convertPercentageOfViewportToPixels(numericsTicksPaddingPercentage, + m_tabViewportHeight); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), m_tabViewportHeight); - break; - } - - m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(1.0f, m_tabViewportHeight); - - float dataMinimumValue = 0.0f; - float dataMaximumValue = 0.0f; - switch (axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - dataMinimumValue = dataMinX; - dataMaximumValue = dataMaxX; - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - dataMinimumValue = dataMinY; - dataMaximumValue = dataMaxY; + m_numericsTicksPaddingSizePixels = convertPercentageOfViewportToPixels(numericsTicksPaddingPercentage, + m_tabViewportHeight); break; } @@ -2964,31 +1655,48 @@ m_tabViewportHeight(tabViewport[3]) m_tickLength = m_lineDrawingWidth; // * 2.0f; } + /* + * Width/height of label + */ float labelWidth = 0.0f; float labelHeight = 0.0f; initializeLabel(labelText, labelWidth, labelHeight); + /* + * Maximum width/height of numeric values + */ float numericsWidth = 0.0f; float numericsHeight = 0.0f; initializeNumericText(dataMinimumValue, dataMaximumValue, numericsWidth, numericsHeight); + /* + * Width or height for this axis + */ switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - m_axisHeight = m_labelPaddingSizePixels + labelHeight + numericsHeight + m_labelPaddingSizePixels + m_tickLength; + m_axisHeight = m_labelPaddingSizePixels + labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength; CaretAssert(m_axisHeight >= 0.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: /* Note: label is rotated on left/right so use it's height */ - m_axisWidth = m_labelPaddingSizePixels + labelHeight + numericsWidth + m_labelPaddingSizePixels + m_tickLength; + m_axisWidth = m_labelPaddingSizePixels + labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength; CaretAssert(m_axisWidth >= 0.0f); break; } } /** - * Initialize the numeric text + * Initialize the numeric label by creating an annotation for the label + * and determining the width and height of the label. + * + * @param labelText + * Text of the label. + * @param widthOut + * Output with width of label. + * @param heightOut + * Height of label. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const AString& labelText, @@ -3047,7 +1755,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const } /** - * Initialize the numeric text + * Initialize the numeric text by creating an annotation for each numeric value + * and find the maximum width and height of the numeric values. + * + * @param dataMinimumDataValue + * Minimum data value for axis + * @param dataMaximumDataValue + * Maximum data value for axis + * @param maxWidthOut + * Output with maximum width of numeric text. + * @param maxHeightOut + * Output with maximum height of numeric text. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText(const float dataMinimumDataValue, @@ -3154,18 +1872,33 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( maxWidthOut = std::max(maxWidthOut, static_cast(textWidth)); maxHeightOut = std::max(maxHeightOut, static_cast(textHeight)); + text->setText(scaleValuesText[i]); m_numericsText.push_back(std::unique_ptr(text)); } } /** - * Set the axis viewport + * Set the axis viewport. Once the width of the left and right and the height of the + * bottom and top axes are known, we can determine the sizes of each axis and set + * calculate the viewport for the axis. + * + * @param titleHeight + * Height of the title. + * @param bottomAxisHeight + * Height of the bottom axis. + * @param topAxisHeight + * Height of the top axis. + * @param leftAxisWidth + * Width of the left axis. + * @param rightAxisWidth + * Width of the right axis. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const float bottomAxisHeight, - const float topAxisHeight, - const float leftAxisWidth, - const float rightAxisWidth) +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const float titleHeight, + const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth) { switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: @@ -3174,7 +1907,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - m_axisHeight = m_tabViewportHeight - (bottomAxisHeight + topAxisHeight); + m_axisHeight = m_tabViewportHeight - (bottomAxisHeight + topAxisHeight + titleHeight); break; } if (m_axisWidth < 1.0f) { @@ -3187,19 +1920,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: m_axisViewport[0] = leftAxisWidth; - m_axisViewport[1] = m_tabViewportY; + m_axisViewport[1] = 0.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisViewport[0] = leftAxisWidth; - m_axisViewport[1] = m_tabViewportX + m_tabViewportHeight - topAxisHeight; + m_axisViewport[1] = m_tabViewportHeight - topAxisHeight - titleHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - m_axisViewport[0] = m_tabViewportX; + m_axisViewport[0] = 0.0f; m_axisViewport[1] = bottomAxisHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - m_axisViewport[0] = m_tabViewportX + m_tabViewportWidth - rightAxisWidth; - m_axisViewport[1] = m_tabViewportY + bottomAxisHeight; + m_axisViewport[0] = m_tabViewportWidth - rightAxisWidth; + m_axisViewport[1] = bottomAxisHeight; break; } @@ -3212,6 +1945,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const CaretAssert(m_axisViewport[3] >= 0.0f); } +/** + * Set the coordinates for the label and the numerics once we know the + * viewport for the axis. + * + * @param foregroundFloatRGBA + * Color of the foreground. + */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4]) { @@ -3264,19 +2004,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = vpX + (vpWidth * xyz[0]); - xyz[1] = vpY + vpHeight - m_tickLength - m_labelPaddingSizePixels; + xyz[1] = vpY + vpHeight - m_tickLength - m_numericsTicksPaddingSizePixels; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - xyz[0] = vpX + vpWidth - m_tickLength - m_labelPaddingSizePixels; + xyz[0] = vpX + vpWidth - m_tickLength - m_numericsTicksPaddingSizePixels; xyz[1] = vpY + (vpHeight * xyz[1]); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - xyz[0] = vpX + m_tickLength + m_labelPaddingSizePixels; + xyz[0] = vpX + m_tickLength + m_numericsTicksPaddingSizePixels; xyz[1] = vpY + (vpHeight * xyz[1]); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = vpX + (vpWidth * xyz[0]); - xyz[1] = vpY + m_tickLength + m_labelPaddingSizePixels; + xyz[1] = vpY + m_tickLength + m_numericsTicksPaddingSizePixels; break; } @@ -3286,7 +2026,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo } } - +/** + * Draw the axis. + * + * @param chartDrawing + * The chart drawing parent. + * @param foregroundFloatRGBA + * Color of the foreground. + * @param axisMinimumValueOut + * Output containing the minimum value for the axis + * @param axisMaximumValueOut + * Output containing the maximum value for the axis + */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, const float foregroundFloatRGBA[4], @@ -3307,14 +2058,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh return; } - glColor3f(1.0, 0.0, 0.0); - glLineWidth(1.0); - glBegin(GL_LINE_LOOP); - glVertex2f(m_axisViewport[0], m_axisViewport[1]); - glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); - glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); - glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); - glEnd(); +// glColor3f(1.0, 0.0, 0.0); +// glLineWidth(2.0); +// glBegin(GL_LINE_LOOP); +// glVertex2f(m_axisViewport[0], m_axisViewport[1]); +// glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); +// glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); +// glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); +// glEnd(); const int32_t numScaleValuesToDraw = static_cast(m_numericsText.size()); @@ -3330,36 +2081,41 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh const int32_t lastTickIndex = numScaleValuesToDraw - 1; for (int32_t i = 0; i < numScaleValuesToDraw; i++) { + /* + * Coordinate of numeric value text + */ CaretAssertVectorIndex(m_numericsText, i); - const AnnotationPercentSizeText* text = m_numericsText[i].get(); + AnnotationPercentSizeText* text = m_numericsText[i].get(); float xyz[3]; text->getCoordinate()->getXYZ(xyz); const float textX = xyz[0]; const float textY = xyz[1]; + /* + * Offset the tick from its corresponding numeric value + */ float tickStartX = textX; float tickStartY = textY; float tickEndX = 0.0; float tickEndY = 0.0; - switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - tickStartY += m_labelPaddingSizePixels; + tickStartY += m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; tickEndY = tickStartY + m_tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - tickStartY -= m_labelPaddingSizePixels; + tickStartY -= m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; tickEndY = tickStartY - m_tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - tickStartX += m_labelPaddingSizePixels; + tickStartX += m_numericsTicksPaddingSizePixels; tickEndX = tickStartX + m_tickLength; tickEndY = tickStartY; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - tickStartX -= m_labelPaddingSizePixels; + tickStartX -= m_numericsTicksPaddingSizePixels; tickEndX = tickStartX - m_tickLength; tickEndY = tickStartY; break; @@ -3379,6 +2135,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh *text); } + /* + * Draw the ticks. + */ glLineWidth(m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } @@ -3391,4 +2150,141 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh 0.0, *(m_labelText.get())); } -} \ No newline at end of file +} + +/** + * Constructor. + * + * @param textRenderer + * The text renderer. + * @param tabViewport + * Viewport of the tab containing the chart. + * @param title + * The chart title. + */ +BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::TitleDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, + const int32_t tabViewport[4], + const ChartTwoTitle* title) +: m_textRenderer(textRenderer), +m_tabViewportWidth(tabViewport[2]), +m_tabViewportHeight(tabViewport[3]), +m_title(title) +{ + const AString titleText = m_title->getText().trimmed(); + m_titleDisplayedFlag = (m_title->isDisplayed() + && ( ! titleText.isEmpty())); + + if ( ! m_titleDisplayedFlag) { + /* + * If axis is not displayed, use padding with a small percentage of space. + */ + const float emptyAxisPaddingPercentage = 1.0f; + m_paddingSizePixels = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, + m_tabViewportHeight); + m_titleHeight = m_paddingSizePixels; + return; + } + + m_paddingSizePixels = convertPercentageOfViewportToPixels(m_title->getPaddingSize(), + m_tabViewportHeight); + + AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + float xyz[3] = { 0.0f, 0.0f, 0.0f }; + xyz[0] = 0.5f; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + text->setText(titleText); + text->setFontPercentViewportSize(m_title->getTextSize()); + text->getCoordinate()->setXYZ(xyz); + + double m_textWidth = 0.0; + double m_textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*text, + m_tabViewportWidth, m_tabViewportHeight, + m_textWidth, m_textHeight); + m_text.reset(text); + + m_titleHeight = m_paddingSizePixels + m_textHeight; + CaretAssert(m_titleHeight >= 0.0f); +} + +/** + * Set the title viewport. Once the width of the left and right and the height of the + * bottom and top axes are known, we can determine the sizes for the title. + * + * @param leftAxisWidth + * Width of the left axis. + * @param rightAxisWidth + * Width of the right axis. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::setTitleViewport(const float leftAxisWidth, + const float rightAxisWidth) +{ + if ( ! m_titleDisplayedFlag) { + return; + } + + m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); + if (m_titleWidth < 1.0f) { + m_titleWidth = 1.0f; + } + if (m_titleHeight < 1.0f) { + m_titleHeight = 1.0f; + } + + m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); + m_titleViewport[0] = leftAxisWidth; + m_titleViewport[1] = /*m_tabViewportY + */m_tabViewportHeight - m_titleHeight; + + m_titleViewport[2] = m_titleWidth; + m_titleViewport[3] = m_titleHeight; + + CaretAssert(m_titleViewport[0] >= 0.0f); + CaretAssert(m_titleViewport[1] >= 0.0f); + CaretAssert(m_titleViewport[2] >= 0.0f); + CaretAssert(m_titleViewport[3] >= 0.0f); + + float xyz[3]; + m_text->getCoordinate()->getXYZ(xyz); + xyz[0] = m_titleViewport[0] + (m_titleWidth / 2.0f); + xyz[1] = m_titleViewport[1] + m_titleHeight - m_paddingSizePixels; + m_text->getCoordinate()->setXYZ(xyz); +} + +/** + * Draw the title. + * + * @param foregroundFloatRGBA + * Color of the foreground. + */ +void +BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float foregroundFloatRGBA[4]) +{ + if (m_title == NULL) { + return; + } + if ( ! m_titleDisplayedFlag) { + return; + } + + // glColor3f(1.0, 0.0, 0.0); + // glLineWidth(2.0); + // glBegin(GL_LINE_LOOP); + // glVertex2f(m_axisViewport[0], m_axisViewport[1]); + // glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); + // glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); + // glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); + // glEnd(); + + m_text->setTextColor(CaretColorEnum::CUSTOM); + m_text->setCustomTextColor(foregroundFloatRGBA); + + float xyz[3]; + m_text->getCoordinate()->getXYZ(xyz); + m_textRenderer->drawTextAtViewportCoords(xyz[0], + xyz[1], + 0.0, + *(m_text.get())); +} diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 157fa12a8..da395c998 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -37,6 +37,7 @@ namespace caret { class ChartTwoCartesianAxis; class ChartTwoDataCartesian; class ChartTwoOverlaySet; + class ChartTwoTitle; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; @@ -64,6 +65,9 @@ namespace caret { // ADD_NEW_METHODS_HERE private: + /** + * Contains histogram for drawing + */ class HistogramChartDrawingInfo { public: HistogramChartDrawingInfo(ChartableTwoFileHistogramChart* histogramChart, @@ -79,6 +83,9 @@ namespace caret { ~HistogramChartDrawingInfo(); }; + /** + * Contains line chart for drawing + */ class LineSeriesChartDrawingInfo { public: LineSeriesChartDrawingInfo(const ChartableTwoFileLineSeriesChart* lineSeriesChart, @@ -93,29 +100,38 @@ namespace caret { const ChartAxisLocationEnum::Enum m_verticalAxisLocation; }; - class Margins { + /** + * Determines size of title and draws the title + */ + class TitleDrawingInfo { public: - Margins(const double defaultSize) { - m_bottom = defaultSize; - m_left = defaultSize; - m_right = defaultSize; - m_top = defaultSize; - } + TitleDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, + const int32_t tabViewport[4], + const ChartTwoTitle* title); - double m_bottom; - double m_left; - double m_right; - double m_top; - }; - - class RowColumnMinMax { - public: - RowColumnMinMax() { } - - int32_t m_min = 9999999; - int32_t m_max = -9999999; + void setTitleViewport(const float leftAxisWidth, + const float rightAxisWidth); + + void drawTitle(const float foregroundFloatRGBA[4]); + + float m_titleHeight = 0.0f; + float m_titleWidth = 0.0f; + bool m_titleDisplayedFlag; + + private: + BrainOpenGLTextRenderInterface* m_textRenderer; + const float m_tabViewportWidth = 0.0f; + const float m_tabViewportHeight = 0.0f; + const ChartTwoTitle* m_title; + + std::unique_ptr m_text; + float m_paddingSizePixels = 0.0f; + float m_titleViewport[4]; }; + /** + * Determines size of an axis and draws the axis + */ class AxisDrawingInfo { public: AxisDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, @@ -129,7 +145,8 @@ namespace caret { const AString& labelText, const float lineWidthPercentage); - void setAxisViewport(const float bottomAxisHeight, + void setAxisViewport(const float titleHeight, + const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth); @@ -153,7 +170,7 @@ namespace caret { float m_axisMaximumValue = 0.0f; float m_labelPaddingSizePixels = 0.0f; - float m_numericsPaddingSizePixels = 0.0f; + float m_numericsTicksPaddingSizePixels = 1.0f; bool m_axisValid = false; bool m_axisDisplayedFlag = false; @@ -163,8 +180,6 @@ namespace caret { const ChartAxisLocationEnum::Enum m_axisLocation; const ChartTwoCartesianAxis* m_axis; BrainOpenGLTextRenderInterface* m_textRenderer; - const float m_tabViewportX = 0.0f; - const float m_tabViewportY = 0.0f; const float m_tabViewportWidth = 0.0f; const float m_tabViewportHeight = 0.0f; float m_lineDrawingWidth = 1.0f; @@ -181,49 +196,6 @@ namespace caret { }; - class AxisSizeInfo { - public: - AxisSizeInfo() - : m_width(0.0), - m_height(0.0), - m_paddingSize(0.0), - m_linesWidth(0.0), - m_tickLength(0.0), - m_axisSize(0.0), - m_labelOffset(0.0), - m_numericsOffset(0.0) { } - - AxisSizeInfo(const double width, - const double height, - const double paddingSize, - const double linesWidth, - const double tickLength, - const double labelHeight, - const double numericsWidthOrHeight) - : m_width(width), - m_height(height), - m_paddingSize(paddingSize), - m_linesWidth(linesWidth), - m_tickLength(tickLength) { - m_labelOffset = m_paddingSize; - m_axisSize = (m_paddingSize - + labelHeight - + numericsWidthOrHeight - + tickLength); - m_numericsOffset = m_axisSize - tickLength; - } - - double m_width; - double m_height; - double m_paddingSize; - double m_linesWidth; - double m_tickLength; - - double m_axisSize; - double m_labelOffset; - double m_numericsOffset; - }; - BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); BrainOpenGLChartTwoDrawingFixedPipeline& operator=(const BrainOpenGLChartTwoDrawingFixedPipeline&); @@ -242,60 +214,19 @@ namespace caret { void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); - void drawChartGraphicsBoxAndSetViewport(const float vpX, - const float vpY, - const float vpWidth, - const float vpHeight, - const float lineThickness, - const Margins& margins, - const bool drawBoxFlag, - int32_t chartGraphicsDrawingViewportOut[4]); - void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const float lineThicknessPercentage, + const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, - const float rightAxisWidth, const bool drawBoxFlag, + const float rightAxisWidth, + const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]); - bool drawChartAxisCartesian(const float minimumDataValue, - const float maximumDataValue, - const float tabViewportX, - const float tabViewportY, - const float tabViewportWidth, - const float tabViewportHeight, - const Margins& margins, - const AxisSizeInfo& axisSizeInfo, - ChartTwoCartesianAxis* axis, - AnnotationPercentSizeText* chartAxisLabel, - float& axisMinimumOut, - float& axisMaximumOut); - - void drawChartTitle(const float tabViewportX, - const float tabViewportY, - const float tabViewportWidth, - const float tabViewportHeight, - const Margins& margins, - AnnotationPercentSizeText* chartTitle); - - void estimateCartesianChartAxisLegendsWidthHeight(const float minimumDataValue, - const float maximumDataValue, - const float viewportWidth, - const float viewportHeight, - const float lineWidthPercentage, - ChartTwoCartesianAxis* cartesianAxis, - AnnotationPercentSizeText* chartAxisLabel, - AxisSizeInfo& axisSizeInfoOut); - - void estimateChartTitleHeight(const float viewportWidth, - const float viewportHeight, - AnnotationPercentSizeText* chartTitle, - double& heightOut); - void drawPrimitivePrivate(GraphicsPrimitive* primitive); void updateViewportContentForCharting(const int32_t viewport[4]); @@ -337,8 +268,6 @@ namespace caret { SelectionItemChartTwoMatrix* m_selectionItemMatrix; - const float GRID_LINE_WIDTH = 2.0; - bool m_identificationModeFlag; /** These annotations will be drawn by the annotation drawing code */ @@ -348,9 +277,6 @@ namespace caret { static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; - static constexpr float s_tickLengthPixels = 5.0; - - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index ba28a8d14..88330a164 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -29,6 +29,7 @@ #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" +#include "ChartTwoTitle.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" @@ -127,9 +128,8 @@ m_tabIndex(tabIndex) break; } - m_chartTitle = createChartTitle(); + m_title = std::unique_ptr(new ChartTwoTitle()); - m_chartTitleDisplayedFlag = true; m_axisLineThickness = 1.0f; m_sceneAssistant = new SceneClassAssistant(); @@ -143,12 +143,9 @@ m_tabIndex(tabIndex) "ChartTwoCartesianAxis", m_chartAxisBottom.get()); - m_sceneAssistant->add("m_chartTitle", - "AnnotationPercentSizeText", - m_chartTitle.get()); - m_sceneAssistant->add("m_chartTitleDisplayedFlag", - &m_chartTitleDisplayedFlag); - + m_sceneAssistant->add("m_title", + "ChartTwoTitle", + m_title.get()); m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); m_sceneAssistant->add("m_axisLineThickness", @@ -194,8 +191,7 @@ ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; *m_chartAxisRight = *overlaySet->m_chartAxisRight; *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; - *m_chartTitle = *overlaySet->m_chartTitle; - m_chartTitleDisplayedFlag = overlaySet->m_chartTitleDisplayedFlag; + *m_title = *overlaySet->m_title; m_axisLineThickness = overlaySet->m_axisLineThickness; m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; @@ -218,32 +214,6 @@ ChartTwoOverlaySet::copyCartesianAxes(const ChartTwoOverlaySet* overlaySet) m_axisLineThickness = overlaySet->m_axisLineThickness; } -/** - * @return A new instance for the chart title. - */ -std::unique_ptr -ChartTwoOverlaySet::createChartTitle() -{ - std::unique_ptr title = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); - title->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); - - title->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - title->setTabIndex(0); - title->setTextColor(CaretColorEnum::RED); - title->setLineColor(CaretColorEnum::NONE); - title->setBackgroundColor(CaretColorEnum::NONE); - - title->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - title->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - title->setFontPercentViewportSize(5.0f); - - title->setText(""); - - return title; -} - - /** * @return Returns the top-most overlay regardless of its enabled status. */ @@ -330,7 +300,7 @@ ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionO { descriptionOut.addLine("Overlay Set"); descriptionOut.pushIndentation(); - descriptionOut.addLine(" Title: " + (m_chartTitleDisplayedFlag ? m_chartTitle->getText() : "Disabled by user")); + descriptionOut.addLine(" Title: " + (m_title->isDisplayed() ? m_title->getText() : "Disabled by user")); descriptionOut.popIndentation(); const int numOverlays = getNumberOfDisplayedOverlays(); @@ -721,7 +691,7 @@ ChartTwoOverlaySet::receiveEvent(Event* event) EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); CaretAssert(chartLabelEvent); - chartLabelEvent->addAnnotationChartLabel(m_chartTitle.get()); + //chartLabelEvent->addAnnotationChartLabel(m_chartTitle.get()); } } @@ -730,23 +700,11 @@ ChartTwoOverlaySet::receiveEvent(Event* event) * * @param axesOut * Output containing the displayed axes. - * @param leftAxisLabelOut - * Label for left axis (may be NULL if axis not displayed). - * @param rightAxisLabelOut - * Label for right axis (may be NULL if axis not displayed). - * @param bottomAxisLabelOut - * Label for bottom axis (may be NULL if axis not displayed). */ void -ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut, - AnnotationPercentSizeText* &leftAxisLabelOut, - AnnotationPercentSizeText* &rightAxisLabelOut, - AnnotationPercentSizeText* &bottomAxisLabelOut) const +ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut) const { axesOut.clear(); - leftAxisLabelOut = NULL; - rightAxisLabelOut = NULL; - bottomAxisLabelOut = NULL; AString lineSeriesDataTypeName; @@ -836,33 +794,31 @@ ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& a if (m_chartAxisBottom->isEnabledByChart()) { axesOut.push_back(m_chartAxisBottom.get()); - - bottomAxisLabelOut = getAxisLabel(m_chartAxisBottom.get()); } if (m_chartAxisLeft->isEnabledByChart()) { axesOut.push_back(m_chartAxisLeft.get()); - - leftAxisLabelOut = getAxisLabel(m_chartAxisLeft.get()); } if (m_chartAxisRight->isEnabledByChart()) { axesOut.push_back(m_chartAxisRight.get()); - - rightAxisLabelOut = getAxisLabel(m_chartAxisRight.get()); } } /** - * Get the annotation for the axis label. + * Get the text for the axis label. * * @param axis * The cartesian axis. * @return - * Pointer to annotation containing label or NULL if invalid. + * Text for the axis label. */ -AnnotationPercentSizeText* +AString ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const { - AnnotationPercentSizeText* label = NULL; + if (axis == NULL) { + return ""; + } + + AString label; const int32_t overlayTitleIndex = axis->getLabelOverlayIndex(m_numberOfDisplayedOverlays); const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); @@ -907,45 +863,84 @@ ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const break; } } + return label; } /** - * @return The chart title. + * Set the text for the axis label. + * + * @param axis + * The cartesian axis. + * @param label + * New text for the axis label. */ -AnnotationPercentSizeText* -ChartTwoOverlaySet::getChartTitle() +void +ChartTwoOverlaySet::setAxisLabel(const ChartTwoCartesianAxis* axis, + const AString& label) { - return m_chartTitle.get(); + const int32_t overlayTitleIndex = axis->getLabelOverlayIndex(m_numberOfDisplayedOverlays); + const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); + CaretMappableDataFile* mapFile = chartOverlay->getSelectedMapFile(); + if (mapFile != NULL) { + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + mapFile->getChartingDelegate()->getHistogramCharting()->setBottomAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + mapFile->getChartingDelegate()->getHistogramCharting()->setLeftRightAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + mapFile->getChartingDelegate()->getHistogramCharting()->setLeftRightAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + switch (axis->getAxisLocation()) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + mapFile->getChartingDelegate()->getLineSeriesCharting()->setBottomAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + mapFile->getChartingDelegate()->getLineSeriesCharting()->setLeftRightAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + mapFile->getChartingDelegate()->getLineSeriesCharting()->setLeftRightAxisTitle(label); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + CaretAssert(0); + break; + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + } } -/** - * @return The chart title. - */ -const AnnotationPercentSizeText* -ChartTwoOverlaySet::getChartTitle() const -{ - return m_chartTitle.get(); -} /** - * @return True if chart title displayed, else false. + * @return The chart title. */ -bool ChartTwoOverlaySet::isChartTitleDisplayed() const +ChartTwoTitle* +ChartTwoOverlaySet::getChartTitle() { - return m_chartTitleDisplayedFlag; + return m_title.get(); } /** - * Set chart title displayed - * - * @param status - * New status. + * @return The chart title. */ -void -ChartTwoOverlaySet::setChartTitleDislayed(const bool status) +const ChartTwoTitle* +ChartTwoOverlaySet::getChartTitle() const { - m_chartTitleDisplayedFlag = status; + return m_title.get(); } /** @@ -1027,12 +1022,28 @@ ChartTwoOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, return; } - m_chartTitle->setText(""); - m_chartTitleDisplayedFlag = false; + m_title->reset(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + /* + * Title was originally saved as text and boolean + */ + const SceneClass* oldChartTitleClass = sceneClass->getClass("m_chartTitle"); + if (oldChartTitleClass != NULL) { + if (oldChartTitleClass->getClassName() == "AnnotationPercentSizeText") { + std::unique_ptr title = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); + title->setText(""); + title->restoreFromScene(sceneAttributes, oldChartTitleClass); + + m_title->setText(title->getText()); + m_title->setDisplayed(sceneClass->getBooleanValue("m_chartTitleDisplayedFlag", + false)); + } + } + const SceneClassArray* overlayClassArray = sceneClass->getClassArray("m_overlays"); if (overlayClassArray != NULL) { const int32_t numOverlays = std::min(overlayClassArray->getNumberOfArrayElements(), diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 7afa1dd2e..66161de40 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -34,6 +34,7 @@ namespace caret { class CaretMappableDataFile; class ChartTwoCartesianAxis; class ChartTwoOverlay; + class ChartTwoTitle; class PlainTextStringBuilder; class SceneClassAssistant; @@ -66,20 +67,16 @@ namespace caret { ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); - void getDisplayedChartAxes(std::vector& axesOut, - AnnotationPercentSizeText* &leftAxisLabelOut, - AnnotationPercentSizeText* &rightAxisLabelOut, - AnnotationPercentSizeText* &bottomAxisLabelOut) const; + void getDisplayedChartAxes(std::vector& axesOut) const; - AnnotationPercentSizeText* getAxisLabel(const ChartTwoCartesianAxis* axis) const; + AString getAxisLabel(const ChartTwoCartesianAxis* axis) const; - AnnotationPercentSizeText* getChartTitle(); + void setAxisLabel(const ChartTwoCartesianAxis* axis, + const AString& label); - const AnnotationPercentSizeText* getChartTitle() const; + ChartTwoTitle* getChartTitle(); - bool isChartTitleDisplayed() const; - - void setChartTitleDislayed(const bool status); + const ChartTwoTitle* getChartTitle() const; void insertOverlayAbove(const int32_t overlayIndex); @@ -135,8 +132,6 @@ namespace caret { void firstOverlaySelectionChanged(); - std::unique_ptr createChartTitle(); - SceneClassAssistant* m_sceneAssistant; std::vector> m_overlays; @@ -153,10 +148,8 @@ namespace caret { const int32_t m_tabIndex; - std::unique_ptr m_chartTitle; + std::unique_ptr m_title; - bool m_chartTitleDisplayedFlag = false; - int32_t m_numberOfDisplayedOverlays; bool m_inFirstOverlayChangedMethodFlag = false; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index 902c0f75d..f56400f2f 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -51,6 +51,7 @@ ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h ChartTwoNumericSubdivisionsModeEnum.h ChartTwoLineSeriesHistory.h +ChartTwoTitle.h EventChartTwoAttributesChanged.h EventChartTwoLoadLineSeriesData.h MapFileDataSelector.h @@ -91,6 +92,7 @@ ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx ChartTwoNumericSubdivisionsModeEnum.cxx ChartTwoLineSeriesHistory.cxx +ChartTwoTitle.cxx EventChartTwoAttributesChanged.cxx EventChartTwoLoadLineSeriesData.cxx MapFileDataSelector.cxx diff --git a/src/Charting/ChartTwoTitle.cxx b/src/Charting/ChartTwoTitle.cxx new file mode 100644 index 000000000..67a1225f3 --- /dev/null +++ b/src/Charting/ChartTwoTitle.cxx @@ -0,0 +1,274 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __CHART_TWO_TITLE_DECLARE__ +#include "ChartTwoTitle.h" +#undef __CHART_TWO_TITLE_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" + +using namespace caret; + + + +/** + * \class caret::ChartTwoTitle + * \brief Title and its attributes for charts. + * \ingroup Charting + */ + +/** + * Constructor. + */ +ChartTwoTitle::ChartTwoTitle() +: CaretObjectTracksModification() +{ + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + + reset(); + + m_sceneAssistant->add("m_displayed", + &m_displayed); + m_sceneAssistant->add("m_paddingSize", + &m_paddingSize); + m_sceneAssistant->add("m_text", + &m_text); + m_sceneAssistant->add("m_textSize", + &m_textSize); +} + +/** + * Destructor. + */ +ChartTwoTitle::~ChartTwoTitle() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +ChartTwoTitle::ChartTwoTitle(const ChartTwoTitle& obj) +: CaretObjectTracksModification(obj) +{ + this->copyHelperChartTwoTitle(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +ChartTwoTitle& +ChartTwoTitle::operator=(const ChartTwoTitle& obj) +{ + if (this != &obj) { + CaretObjectTracksModification::operator=(obj); + this->copyHelperChartTwoTitle(obj); + } + return *this; +} + +/** + * Reset this instance to its default values. + */ +void +ChartTwoTitle::reset() +{ + m_displayed = false; + m_paddingSize = 1.0f; + m_text = ""; + m_textSize = 5.0f; +} + + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +ChartTwoTitle::copyHelperChartTwoTitle(const ChartTwoTitle& obj) +{ + m_displayed = obj.m_displayed; + m_paddingSize = obj.m_paddingSize; + m_text = obj.m_text; + m_textSize = obj.m_textSize; +} + +/** + * @return Padding between title and edge of viewport + */ +float +ChartTwoTitle::getPaddingSize() const +{ + return m_paddingSize; +} + +/** + * Set Padding between title and edge of viewport + * + * @param paddingSize + * New value for Padding between title and edge of viewport + */ +void +ChartTwoTitle::setPaddingSize(const float paddingSize) +{ + if (paddingSize != m_paddingSize) { + m_paddingSize = paddingSize; + setModified(); + } +} + +/** + * @return Size of title characters when drawing + */ +float +ChartTwoTitle::getTextSize() const +{ + return m_textSize; +} + +/** + * Set Size of title characters when drawing + * + * @param textSize + * New value for Size of title characters when drawing + */ +void +ChartTwoTitle::setTextSize(const float textSize) +{ + if (textSize != m_textSize) { + m_textSize = textSize; + setModified(); + } +} + +/** + * @return text displayed as title + */ +AString +ChartTwoTitle::getText() const +{ + return m_text; +} + +/** + * Set text displayed as title + * + * @param text + * New value for text displayed as title + */ +void +ChartTwoTitle::setText(const AString& text) +{ + if (text != m_text) { + m_text = text; + setModified(); + } +} + +/** + * @return display status of title + */ +bool +ChartTwoTitle::isDisplayed() const +{ + return m_displayed; +} + +/** + * Set display status of title + * + * @param displayed + * New value for display status of title + */ +void +ChartTwoTitle::setDisplayed(const bool displayed) +{ + if (displayed != m_displayed) { + m_displayed = displayed; + setModified(); + } +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +ChartTwoTitle::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "ChartTwoTitle", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +ChartTwoTitle::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + diff --git a/src/Charting/ChartTwoTitle.h b/src/Charting/ChartTwoTitle.h new file mode 100644 index 000000000..72537ea03 --- /dev/null +++ b/src/Charting/ChartTwoTitle.h @@ -0,0 +1,114 @@ +#ifndef __CHART_TWO_TITLE_H__ +#define __CHART_TWO_TITLE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObjectTracksModification.h" + +#include "SceneableInterface.h" + + +namespace caret { + class SceneClassAssistant; + + class ChartTwoTitle : public CaretObjectTracksModification, public SceneableInterface { + + public: + ChartTwoTitle(); + + virtual ~ChartTwoTitle(); + + ChartTwoTitle(const ChartTwoTitle& obj); + + ChartTwoTitle& operator=(const ChartTwoTitle& obj); + + float getPaddingSize() const; + + void setPaddingSize(const float paddingSize); + + float getTextSize() const; + + void setTextSize(const float textSize); + + AString getText() const; + + void setText(const AString& text); + + bool isDisplayed() const; + + void setDisplayed(const bool displayed); + + void reset(); + + // ADD_NEW_METHODS_HERE + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + void copyHelperChartTwoTitle(const ChartTwoTitle& obj); + + std::unique_ptr m_sceneAssistant; + + /** Padding between title and edge of viewport*/ + float m_paddingSize; + + /** Size of title characters when drawing*/ + float m_textSize; + + /** text displayed as title*/ + AString m_text; + + /** display status of title*/ + bool m_displayed; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __CHART_TWO_TITLE_DECLARE__ + // +#endif // __CHART_TWO_TITLE_DECLARE__ + +} // namespace +#endif //__CHART_TWO_TITLE_H__ diff --git a/src/Files/ChartableTwoFileBaseChart.cxx b/src/Files/ChartableTwoFileBaseChart.cxx index 865aae2d6..c4363a574 100644 --- a/src/Files/ChartableTwoFileBaseChart.cxx +++ b/src/Files/ChartableTwoFileBaseChart.cxx @@ -25,6 +25,8 @@ #include "AnnotationPercentSizeText.h" #include "CaretAssert.h" +#include "CaretMappableDataFile.h" +#include "CiftiMappableDataFile.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -50,10 +52,6 @@ using namespace caret; * to support loading of older scenes. */ -#include "CaretMappableDataFile.h" -#include "CiftiMappableDataFile.h" -#include "EventAnnotationChartLabelGet.h" -#include "SceneClassAssistant.h" /** * Constructor. @@ -75,25 +73,13 @@ m_parentCaretMappableDataFile(parentCaretMappableDataFile) /* will be NULL if file is not a cifti mappable file */ m_parentCiftiMappableDataFile = dynamic_cast(m_parentCaretMappableDataFile); - m_bottomAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); - m_bottomAxisTitle->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); - - m_leftRightAxisTitle = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, - AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); - m_leftRightAxisTitle->setPropertiesForSpecializedUsage(Annotation::PropertiesSpecializedUsage::CHART_LABEL); - - - initializeAxisLabel(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); - initializeAxisLabel(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + setDefaultAxisTitles(); m_sceneAssistant = new SceneClassAssistant(); - m_sceneAssistant->add("m_bottomAxisTitle", - "AnnotationPercentSizeText", - m_bottomAxisTitle.get()); - m_sceneAssistant->add("m_leftRightAxisTitle", - "AnnotationPercentSizeText", - m_leftRightAxisTitle.get()); + m_sceneAssistant->add("m_bottomAxisTitleText", + &m_bottomAxisTitleText); + m_sceneAssistant->add("m_leftRightAxisTitleText", + &m_leftRightAxisTitleText); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); } @@ -108,51 +94,26 @@ ChartableTwoFileBaseChart::~ChartableTwoFileBaseChart() } /** - * Initialize an axis' label + * Set the default titles for the axes. + */ +void +ChartableTwoFileBaseChart::setDefaultAxisTitles() +{ + m_bottomAxisTitleText = setDefaultAxisTitle(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); + m_leftRightAxisTitleText = setDefaultAxisTitle(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); +} + +/** + * Set the default axis title. * - * @param axisLabel - * Annotation containing label. * @param axisLocation - * Location of axis. + * Location of the axis. */ -void ChartableTwoFileBaseChart::initializeAxisLabel(AnnotationPercentSizeText* axisLabel, - const ChartAxisLocationEnum::Enum axisLocation) +AString +ChartableTwoFileBaseChart::setDefaultAxisTitle(const ChartAxisLocationEnum::Enum axisLocation) { - CaretAssert(axisLabel); - - axisLabel->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); - axisLabel->setTabIndex(0); - axisLabel->setTextColor(CaretColorEnum::RED); - axisLabel->setLineColor(CaretColorEnum::NONE); - axisLabel->setBackgroundColor(CaretColorEnum::NONE); - - axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - axisLabel->setFontPercentViewportSize(s_defaultFontPercentViewportSize); - AString title; - switch (axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - axisLabel->setRotationAngle(-90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - axisLabel->setRotationAngle(90.0); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - axisLabel->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - axisLabel->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - break; - } - switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: @@ -202,8 +163,8 @@ void ChartableTwoFileBaseChart::initializeAxisLabel(AnnotationPercentSizeText* a } break; } - - axisLabel->setText(title); + + return title; } @@ -224,19 +185,8 @@ ChartableTwoFileBaseChart::toString() const * An event for which this instance is listening. */ void -ChartableTwoFileBaseChart::receiveEvent(Event* event) +ChartableTwoFileBaseChart::receiveEvent(Event* /*event*/) { - if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { - /* - * The events intended for overlays are received here so that - * only DISPLAYED overlays are updated. - */ - EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); - CaretAssert(chartLabelEvent); - - chartLabelEvent->addAnnotationChartLabel(m_bottomAxisTitle.get()); - chartLabelEvent->addAnnotationChartLabel(m_leftRightAxisTitle.get()); - } } /** @@ -313,46 +263,58 @@ ChartableTwoFileBaseChart::updateChartTwoCompoundDataTypeAfterFileChanges(const m_compoundChartDataType = compoundChartDataType; - initializeAxisLabel(m_bottomAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); - initializeAxisLabel(m_leftRightAxisTitle.get(), ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); + setDefaultAxisTitles(); } /** - * @return Annotation for the bottom axis title. + * @return Annotation for the bottom axis title (const method) */ -const AnnotationPercentSizeText* +AString ChartableTwoFileBaseChart::getBottomAxisTitle() const { - return m_bottomAxisTitle.get(); + return m_bottomAxisTitleText; } /** - * @return Annotation for the bottom axis title (const method) + * Set the bottom axis title. + * + * @param title + * New bottom axis title. */ -AnnotationPercentSizeText* -ChartableTwoFileBaseChart::getBottomAxisTitle() +void +ChartableTwoFileBaseChart::setBottomAxisTitle(const AString& title) { - return m_bottomAxisTitle.get(); + if (title != m_bottomAxisTitleText) { + m_bottomAxisTitleText = title; + setModified(); + } } /** - * @return Annotation for the bottom axis title. + * @return Annotation for the bottom axis title (const method) */ -const AnnotationPercentSizeText* +AString ChartableTwoFileBaseChart::getLeftRightAxisTitle() const { - return m_leftRightAxisTitle.get(); + return m_leftRightAxisTitleText; } /** - * @return Annotation for the bottom axis title (const method) + * Set the left/right axis title. + * + * @param title + * New left/right axis title. */ -AnnotationPercentSizeText* -ChartableTwoFileBaseChart::getLeftRightAxisTitle() +void +ChartableTwoFileBaseChart::setLeftRightAxisTitle(const AString& title) { - return m_leftRightAxisTitle.get(); + if (title != m_leftRightAxisTitleText) { + m_leftRightAxisTitleText = title; + setModified(); + } } + /** * Save information specific to this type of model to the scene. * @@ -370,7 +332,7 @@ ChartableTwoFileBaseChart::saveToScene(const SceneAttributes* sceneAttributes, { SceneClass* sceneClass = new SceneClass(instanceName, "ChartableTwoFileBaseChart", - 2); + 3); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -399,15 +361,30 @@ ChartableTwoFileBaseChart::restoreFromScene(const SceneAttributes* sceneAttribut return; } + setDefaultAxisTitles(); + m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); - if (sceneClass->getVersionNumber() <= 1) { - m_bottomAxisTitle->setFontPercentViewportSize(s_defaultFontPercentViewportSize); - m_leftRightAxisTitle->setFontPercentViewportSize(s_defaultFontPercentViewportSize); + if (sceneClass->getVersionNumber() <= 2) { + AnnotationPercentSizeText bottomTitle(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + bottomTitle.restoreFromScene(sceneAttributes, + sceneClass->getClass("m_bottomAxisTitle")); + if ( ! bottomTitle.getText().isEmpty()) { + m_bottomAxisTitleText = bottomTitle.getText(); + } + + AnnotationPercentSizeText leftRightTitle(AnnotationAttributesDefaultTypeEnum::NORMAL, + AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); + leftRightTitle.restoreFromScene(sceneAttributes, + sceneClass->getClass("m_leftRightAxisTitle")); + if ( ! leftRightTitle.getText().isEmpty()) { + m_leftRightAxisTitleText = leftRightTitle.getText(); + } } } diff --git a/src/Files/ChartableTwoFileBaseChart.h b/src/Files/ChartableTwoFileBaseChart.h index 36260a370..010fc8bd8 100644 --- a/src/Files/ChartableTwoFileBaseChart.h +++ b/src/Files/ChartableTwoFileBaseChart.h @@ -31,7 +31,6 @@ namespace caret { - class AnnotationPercentSizeText; class CaretMappableDataFile; class CiftiMappableDataFile; class SceneClassAssistant; @@ -67,13 +66,13 @@ namespace caret { ChartTwoCompoundDataType getChartTwoCompoundDataType() const; - const AnnotationPercentSizeText* getBottomAxisTitle() const; + AString getBottomAxisTitle() const; - AnnotationPercentSizeText* getBottomAxisTitle(); + void setBottomAxisTitle(const AString& title); - const AnnotationPercentSizeText* getLeftRightAxisTitle() const; + AString getLeftRightAxisTitle() const; - AnnotationPercentSizeText* getLeftRightAxisTitle(); + void setLeftRightAxisTitle(const AString& title); // ADD_NEW_METHODS_HERE @@ -108,9 +107,10 @@ namespace caret { ChartableTwoFileBaseChart& operator=(const ChartableTwoFileBaseChart&); - void initializeAxisLabel(AnnotationPercentSizeText* axisLabel, - const ChartAxisLocationEnum::Enum axisLocation); - + void setDefaultAxisTitles(); + + AString setDefaultAxisTitle(const ChartAxisLocationEnum::Enum axisLocation); + const ChartTwoDataTypeEnum::Enum m_chartType; CaretMappableDataFile* m_parentCaretMappableDataFile; @@ -121,9 +121,9 @@ namespace caret { ChartTwoCompoundDataType m_compoundChartDataType; - std::unique_ptr m_bottomAxisTitle; + AString m_bottomAxisTitleText; - std::unique_ptr m_leftRightAxisTitle; + AString m_leftRightAxisTitleText; static float constexpr s_defaultFontPercentViewportSize = 5.0; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 9d58e2bfe..21cb08e7f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -373,20 +373,16 @@ BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserT * The valid axes locations. * @param selectedAxisOut * Output with selected axis (may be NULL) - * @param axisLabelOut - * Output with the axis text label. */ void BrainBrowserWindowToolBarChartTwoAxes::getSelectionData(BrowserTabContent* browserTabContent, ChartTwoOverlaySet* &chartOverlaySetOut, std::vector& validAxesLocationsOut, - ChartTwoCartesianAxis* &selectedAxisOut, - AnnotationPercentSizeText* &axisLabelOut) const + ChartTwoCartesianAxis* &selectedAxisOut) const { chartOverlaySetOut = NULL; validAxesLocationsOut.clear(); selectedAxisOut = NULL; - axisLabelOut = NULL; if (browserTabContent == NULL) { return; @@ -415,13 +411,7 @@ BrainBrowserWindowToolBarChartTwoAxes::getSelectionData(BrowserTabContent* brows int32_t defaultAxisIndex = -1; std::vector axes; - AnnotationPercentSizeText* leftAxisLabel = NULL; - AnnotationPercentSizeText* rightAxisLabel = NULL; - AnnotationPercentSizeText* bottomAxisLabel = NULL; - chartOverlaySetOut->getDisplayedChartAxes(axes, - leftAxisLabel, - rightAxisLabel, - bottomAxisLabel); + chartOverlaySetOut->getDisplayedChartAxes(axes); const int32_t numAxes = static_cast(axes.size()); for (int32_t i = 0; i < numAxes; i++) { const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); @@ -453,14 +443,9 @@ BrainBrowserWindowToolBarChartTwoAxes::getSelectionData(BrowserTabContent* brows CaretAssertVectorIndex(axes, defaultAxisIndex); selectedAxisOut = axes[defaultAxisIndex]; } - - if (selectedAxisOut != NULL) { - axisLabelOut = chartOverlaySetOut->getAxisLabel(selectedAxisOut); - } } } } - } /** @@ -494,13 +479,11 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_chartOverlaySet = NULL; std::vector validAxesLocations; ChartTwoCartesianAxis* selectedAxis = NULL; - AnnotationPercentSizeText* axisLabel = NULL; getSelectionData(browserTabContent, m_chartOverlaySet, validAxesLocations, - selectedAxis, - axisLabel); + selectedAxis); m_widgetGroup->blockAllSignals(true); @@ -558,62 +541,6 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_widgetGroup->blockAllSignals(false); } -///** -// * Update the content with the given axis. -// * -// * @param chartOverlaySet -// * Chart overlay set containing axis. -// * @param chartAxis -// * New chart axis content. -// */ -//void -//BrainBrowserWindowToolBarChartTwoAxes::updateControls(ChartTwoOverlaySet* chartOverlaySet, -// ChartTwoCartesianAxis* chartAxis) -//{ -// m_chartAxis = chartAxis; -// -// if ((chartOverlaySet != NULL) -// && (m_chartAxis != NULL)) { -// m_widgetGroup->blockAllSignals(true); -// m_axisDisplayedByUserCheckBox->setChecked(chartAxis->isDisplayedByUser()); -// m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); -// float rangeMin(0.0), rangeMax(0.0); -// m_chartAxis->getRange(rangeMin, rangeMax); -// m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); -// m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); -// m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); -// m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); -// m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); -// m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); -// const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); -// m_userNumericFormatComboBox->setSelectedItem(numericFormat); -// m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); -// m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); -// m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); -// m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); -// m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); -// -// const int32_t overlayCount = chartOverlaySet->getNumberOfDisplayedOverlays(); -// int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); -// const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); -// if (overlayCount < comboBoxCount) { -// m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); -// } -// else if (overlayCount > comboBoxCount) { -// for (int32_t j = comboBoxCount; j < overlayCount; j++) { -// m_axisLabelFromOverlayComboBox->addItem("Overlay " + AString::number(j + 1)); -// } -// } -// -// if ((selectedOverlayIndex >= 0) -// && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { -// m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); -// } -// -// m_widgetGroup->blockAllSignals(false); -// } -//} - /** * Called when a widget is changed by the user. */ @@ -731,53 +658,6 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumVal } } -///** -// * Called when the label size value is changed. -// * -// * @param value -// * New value. -// */ -//void -//BrainBrowserWindowToolBarChartTwoAxes::labelSizeValueChanged(double value) -//{ -//} -// -///** -// * Called when the numerics size value is changed. -// * -// * @param value -// * New value. -// */ -//void -//BrainBrowserWindowToolBarChartTwoAxes::numericsSizeValueChanged(double) -//{ -// -//} -// -///** -// * Called when the lines/ticks size value is changed. -// * -// * @param value -// * New value. -// */ -//void -//BrainBrowserWindowToolBarChartTwoAxes::linesTicksSizeValueChanged(double) -//{ -// -//} -// -///** -// * Called when the padding size value is changed. -// * -// * @param value -// * New value. -// */ -//void -//BrainBrowserWindowToolBarChartTwoAxes::paddingSizeValueChanged(double) -//{ -// -//} - /** * Called when a widget is changed by a slot using a bool parameter. * Parameters must match when using function pointers. @@ -817,22 +697,21 @@ BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked(bool) ChartTwoOverlaySet* chartOverlaySet = NULL; std::vector validAxesLocations; ChartTwoCartesianAxis* selectedAxis = NULL; - AnnotationPercentSizeText* axisLabel = NULL; getSelectionData(getTabContentFromSelectedTab(), chartOverlaySet, validAxesLocations, - selectedAxis, - axisLabel); + selectedAxis); - if (axisLabel != NULL) { + if ((chartOverlaySet != NULL) + && (selectedAxis != NULL)) { WuQDataEntryDialog newNameDialog("Axis Label", m_axisLabelToolButton); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); - lineEdit->setText(axisLabel->getText()); + lineEdit->setText(chartOverlaySet->getAxisLabel(selectedAxis)); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); - axisLabel->setText(name); + chartOverlaySet->setAxisLabel(selectedAxis, name); valueChanged(); } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 4f4915126..a63bf0a3d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -72,14 +72,6 @@ namespace caret { void axisLabelToolButtonClicked(bool); -// void labelSizeValueChanged(double); -// -// void numericsSizeValueChanged(double); -// -// void linesTicksSizeValueChanged(double); -// -// void paddingSizeValueChanged(double); -// private: BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); @@ -90,11 +82,7 @@ namespace caret { void getSelectionData(BrowserTabContent* browserTabContent, ChartTwoOverlaySet* &chartOverlaySetOut, std::vector& validAxesLocationsOut, - ChartTwoCartesianAxis* &selectedAxisOut, - AnnotationPercentSizeText* &axisLabelOut) const; - -// void updateControls(ChartTwoOverlaySet* chartOverlaySet, -// ChartTwoCartesianAxis* chartAxis); + ChartTwoCartesianAxis* &selectedAxisOut) const; void updateControls(BrowserTabContent* browserTabContent); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index e1a2588a2..4145c5609 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -24,6 +24,9 @@ #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ #include +#include +#include +#include #include #include #include @@ -33,6 +36,7 @@ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartTwoOverlaySet.h" +#include "ChartTwoTitle.h" #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQtUtilities.h" @@ -67,10 +71,26 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B WuQtUtilities::setToolButtonStyleForQt5Mac(editTitleToolButton); editTitleToolButton->setDefaultAction(editTitleAction); - QVBoxLayout* layout = new QVBoxLayout(this); + m_titleSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_titleSizeSpinBox->setSuffix("%"); + QObject::connect(m_titleSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); + m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); + + m_paddingSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); + m_paddingSizeSpinBox->setSuffix("%"); + QObject::connect(m_paddingSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); + + m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); + QGridLayout* layout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); - layout->addWidget(m_showTitleCheckBox, 0, Qt::AlignHCenter); - layout->addWidget(editTitleToolButton, 0, Qt::AlignHCenter); + layout->addWidget(m_showTitleCheckBox, 0, 0, 1, 2, Qt::AlignHCenter); + layout->addWidget(new QLabel("Size"), 1, 0); + layout->addWidget(m_titleSizeSpinBox, 1, 1); + layout->addWidget(new QLabel("Padding"), 2, 0); + layout->addWidget(m_paddingSizeSpinBox, 2, 1); + layout->addWidget(editTitleToolButton, 3, 0, 1, 2, Qt::AlignHCenter); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -104,7 +124,16 @@ BrainBrowserWindowToolBarChartTwoTitle::updateContent(BrowserTabContent* browser if (m_chartOverlaySet != NULL) { setEnabled(true); - m_showTitleCheckBox->setChecked(m_chartOverlaySet->isChartTitleDisplayed()); + const ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); + m_showTitleCheckBox->setChecked(chartTitle->isDisplayed()); + + m_titleSizeSpinBox->blockSignals(true); + m_titleSizeSpinBox->setValue(chartTitle->getTextSize()); + m_titleSizeSpinBox->blockSignals(false); + + m_paddingSizeSpinBox->blockSignals(true); + m_paddingSizeSpinBox->setValue(chartTitle->getPaddingSize()); + m_paddingSizeSpinBox->blockSignals(false); } else { setEnabled(false); @@ -121,7 +150,23 @@ void BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxToggled(bool checked) { if (m_chartOverlaySet != NULL) { - m_chartOverlaySet->setChartTitleDislayed(checked); + ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); + chartTitle->setDisplayed(checked); + this->updateGraphicsWindow(); + this->updateOtherYokedWindows(); + } +} + +/** + * Called when a size spin box value is changed + */ +void +BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged(double) +{ + if (m_chartOverlaySet != NULL) { + ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); + chartTitle->setTextSize(m_titleSizeSpinBox->value()); + chartTitle->setPaddingSize(m_paddingSizeSpinBox->value()); this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h index f0c9129cd..40a962639 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h @@ -25,6 +25,7 @@ #include "BrainBrowserWindowToolBarComponent.h" class QCheckBox; +class QDoubleSpinBox; namespace caret { @@ -47,6 +48,8 @@ namespace caret { void showTitleCheckBoxToggled(bool); + void sizeSpinBoxValueChanged(double); + private: BrainBrowserWindowToolBarChartTwoTitle(const BrainBrowserWindowToolBarChartTwoTitle&); @@ -54,6 +57,11 @@ namespace caret { QCheckBox* m_showTitleCheckBox; + QDoubleSpinBox* m_titleSizeSpinBox; + + QDoubleSpinBox* m_paddingSizeSpinBox; + + ChartTwoOverlaySet* m_chartOverlaySet; // ADD_NEW_MEMBERS_HERE -- GitLab From 34c6ccbe5ede173de572aab696a79758b2005b66 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 23 Aug 2017 12:38:28 -0500 Subject: [PATCH 360/755] Continuing updates for charting: Resolve WB-721 Different font sizes for chart label and numeric values (In the Toolbar's Chart Axes are separate controls setting the size, as a percentage of viewport height, for both the label and the numeric values). Mostly Resolve WB-722 Adjustable line thickness for chart axis and padding (Padding has been to Toolbar's Chart Axes and its value is a percentage of viewport height; control of line thickness has been added as a percentage of viewport height, but still drawing with OpenGL lines that have a limited line width. Resolve WB-724 Axis Label for charts appears in only one tab (has been fixed). Resolve WB-725 Chart text axis size should be a tab property (controls for label size, scale size and padding are now tab properties). Improved drawing so that axis tick marks align with corresponding data values. --- src/Brain/BrainOpenGL.cxx | 38 ++ src/Brain/BrainOpenGL.h | 4 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 369 ++++++++++-------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 9 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 42 +- src/Brain/BrainOpenGLFixedPipeline.h | 4 - .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 97 ++--- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 19 +- 8 files changed, 331 insertions(+), 251 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index d2bf503f8..30c192bf7 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -395,6 +395,44 @@ BrainOpenGL::getTextRenderer() return m_textRenderer; } +/** + * Set the OpenGL line width. Value is clamped + * to minimum and maximum values to prevent + * OpenGL error caused by invalid line width. + */ +void +BrainOpenGL::setLineWidth(const float lineWidth) +{ + if (lineWidth > s_maxLineWidth) { + glLineWidth(s_maxLineWidth); + } + else if (lineWidth < s_minLineWidth) { + glLineWidth(s_minLineWidth); + } + else { + glLineWidth(lineWidth); + } +} + +/** + * Set the OpenGL point size. Value is clamped + * to minimum and maximum values to prevent + * OpenGL error caused by invalid point size. + */ +void +BrainOpenGL::setPointSize(const float pointSize) +{ + if (pointSize > s_maxPointSize) { + glPointSize(s_maxPointSize); + } + else if (pointSize < s_minPointSize) { + glPointSize(s_minPointSize); + } + else { + glPointSize(pointSize); + } +} + /** * Get the minimum and maximum values for the size of a point. * @param minPointSizeOut diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index b71c7117a..52b80e412 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -135,6 +135,10 @@ namespace caret { void getBackgroundColor(uint8_t backgroundColor[3]) const; + static void setLineWidth(const float lineWidth); + + static void setPointSize(const float pointSize); + static void getMinMaxPointSize(float& minPointSizeOut, float& maxPointSizeOut); static void getMinMaxLineWidth(float& minLineWidthOut, float& maxLineWidthOut); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index f7d631cc0..bd161f740 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -69,8 +69,10 @@ using namespace caret; +static bool debugFlag = false; + /** - * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline + * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline * \brief Drawing of version two charts. * \ingroup Brain */ @@ -82,6 +84,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline : BrainOpenGLChartTwoDrawingInterface() { m_preferences = SessionManager::get()->getCaretPreferences(); + + BrainOpenGL::getMinMaxLineWidth(s_minimumLineWidthOpenGL, + s_maximumLineWidthOpenGL); } /** @@ -146,16 +151,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; - + m_selectionItemAnnotation = m_brain->getSelectionManager()->getAnnotationIdentification(); m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); - + m_fixedPipelineDrawing->disableLighting(); /* - * Find color bars for this tab and decrease height of + * Find color bars for this tab and decrease height of * viewport so chart is above color bars. */ std::vector colorBars; @@ -220,11 +225,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, drawHistogramFlag = false; } if ( (! m_selectionItemLineSeries->isEnabledForSelection()) - && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { + && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { drawLineSeriesFlag = false; } if ( (! m_selectionItemMatrix->isEnabledForSelection()) - && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { + && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { drawMatrixFlag = false; } if (drawHistogramFlag @@ -253,8 +258,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; topOverlay->getSelectionData(mapFile, - selectedIndexType, - selectedIndex); + selectedIndexType, + selectedIndex); if (mapFile != NULL) { const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); switch (chartDataType) { @@ -600,6 +605,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const float leftAxisWidth = leftAxisInfo.m_axisWidth; const float rightAxisWidth = rightAxisInfo.m_axisWidth; + /* + * The constructors were only able to find width or height but not both. + * Now we can find the other value. + */ titleInfo.setTitleViewport(leftAxisWidth, rightAxisWidth); leftAxisInfo.setAxisViewport(topTitleHeight, @@ -609,19 +618,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch rightAxisWidth); rightAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, - topAxisHeight, - leftAxisWidth, - rightAxisWidth); + topAxisHeight, + leftAxisWidth, + rightAxisWidth); bottomAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, - topAxisHeight, - leftAxisWidth, - rightAxisWidth); + topAxisHeight, + leftAxisWidth, + rightAxisWidth); topAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, - topAxisHeight, - leftAxisWidth, - rightAxisWidth); + topAxisHeight, + leftAxisWidth, + rightAxisWidth); const float foregroundRGBA[4] = { m_fixedPipelineDrawing->m_foregroundColorFloat[0], @@ -630,10 +639,16 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch 1.0f }; - leftAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); - rightAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); - bottomAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); - topAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA); + const float graphicsBoxLineThickness = convertPercentageOfViewportToPixels(m_chartOverlaySet->getAxisLineThickness(), + tabViewportHeight); + leftAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, + graphicsBoxLineThickness); + rightAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, + graphicsBoxLineThickness); + bottomAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, + graphicsBoxLineThickness); + topAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, + graphicsBoxLineThickness); /* * Ensure that there is sufficient space for the axes data display. @@ -773,7 +788,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Increase line width for identification */ - glLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); + BrainOpenGL::setLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, @@ -797,7 +812,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { - glLineWidth(ENVELOPE_LINE_WIDTH); + BrainOpenGL::setLineWidth(ENVELOPE_LINE_WIDTH); m_fixedPipelineDrawing->enableLineAntiAliasing(); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); @@ -868,7 +883,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch int32_t primitiveIndex = -1; float primitiveDepth = 0.0; - glLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); + BrainOpenGL::setLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), m_fixedPipelineDrawing->mouseX, @@ -892,7 +907,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch * will alter the colors during drawing). */ m_fixedPipelineDrawing->enableLineAntiAliasing(); - glLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); + BrainOpenGL::setLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); @@ -1126,10 +1141,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, - const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, - const float cellWidth, - const float cellHeight, - const float zooming) + const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, + const float cellWidth, + const float cellHeight, + const float zooming) { GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType); if (matrixPrimitive == NULL) { @@ -1242,7 +1257,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowOutlineData4f->addVertex(maxX, maxY); rowOutlineData4f->addVertex(minX, maxY); const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); + BrainOpenGL::setLineWidth(highlightLineWidth); drawPrimitivePrivate(rowOutlineData4f.get()); } @@ -1274,7 +1289,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnOutlineData4f->addVertex(maxX, maxY); columnOutlineData4f->addVertex(minX, maxY); const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - glLineWidth(highlightLineWidth); + BrainOpenGL::setLineWidth(highlightLineWidth); drawPrimitivePrivate(columnOutlineData4f.get()); } } @@ -1346,9 +1361,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToPixels(con return 0.0f; } - const float minimumWidthOrHeight = 1.0f; - const float pixelsWidthOrHeight = std::max((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight, - minimumWidthOrHeight); + float pixelsWidthOrHeight = ((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight); + if (pixelsWidthOrHeight < s_minimumLineWidthOpenGL) { + pixelsWidthOrHeight = s_minimumLineWidthOpenGL; + } + if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { + pixelsWidthOrHeight = s_maximumLineWidthOpenGL; + } + return pixelsWidthOrHeight; } @@ -1399,61 +1419,50 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons vpHeight); const float halfGridLineWidth = lineThicknessPixels / 2.0; - const float gridLeft = vpX + leftAxisWidth; - const float gridRight = vpX + vpWidth - rightAxisWidth; - const float gridBottom = vpY + bottomAxisHeight; - const float gridTop = vpY + vpHeight - topAxisHeight - titleHeight; - glViewport(vpX, vpY, vpWidth, vpHeight); if (drawBoxFlag) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(vpX, (vpX + vpWidth), - vpY, (vpY + vpHeight), - -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + /* + * For box, set coordinates for the middle of the line + */ + const float boxLeft = vpX + leftAxisWidth + halfGridLineWidth; + const float boxRight = vpX + vpWidth - rightAxisWidth - halfGridLineWidth; + const float boxBottom = vpY + bottomAxisHeight + halfGridLineWidth; + const float boxTop = vpY + vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; - std::unique_ptr gridData + /* + * We adjust the horizontal lines by half the line width. + * Otherwise, there will be 'corner gaps' where the horizontal + * and vertical lines are joined + */ + std::unique_ptr boxData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); - gridData->reserveForNumberOfVertices(8); - gridData->addVertex(gridLeft, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight, gridBottom + halfGridLineWidth); - gridData->addVertex(gridRight - halfGridLineWidth, gridBottom); - gridData->addVertex(gridRight - halfGridLineWidth, gridTop); - gridData->addVertex(gridRight, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft, gridTop - halfGridLineWidth); - gridData->addVertex(gridLeft + halfGridLineWidth, gridTop); - gridData->addVertex(gridLeft + halfGridLineWidth, gridBottom); - glLineWidth(lineThicknessPixels); - drawPrimitivePrivate(gridData.get()); + const float cornerOffset = halfGridLineWidth; + boxData->reserveForNumberOfVertices(8); + boxData->addVertex(boxLeft - cornerOffset, boxBottom); + boxData->addVertex(boxRight + cornerOffset, boxBottom); + boxData->addVertex(boxRight, boxBottom); + boxData->addVertex(boxRight, boxTop); + boxData->addVertex(boxRight + cornerOffset, boxTop); + boxData->addVertex(boxLeft - cornerOffset, boxTop); + boxData->addVertex(boxLeft, boxTop); + boxData->addVertex(boxLeft, boxBottom); + BrainOpenGL::setLineWidth(lineThicknessPixels); + drawPrimitivePrivate(boxData.get()); } /* - * Region inside the grid's box + * Region INSIDE the grid's box so that any data plots + * are WITHIN the box */ - const int32_t graphicsLeft = static_cast(gridLeft); - const int32_t graphicsRight = static_cast(gridRight); - const int32_t graphicsBottom = static_cast(gridBottom); - const int32_t graphicsTop = static_cast(gridTop); -// const int32_t graphicsLeft = static_cast(gridLeft + 0.5f); -// const int32_t graphicsRight = static_cast(gridRight - 0.5f); -// const int32_t graphicsBottom = static_cast(gridBottom + 0.5f); -// const int32_t graphicsTop = static_cast(gridTop - 0.5f); -// const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(halfGridLineWidth + 1.0)); -// const int32_t graphicsRight = static_cast(gridRight - std::floor(halfGridLineWidth + 1.0)); -// const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(halfGridLineWidth + 1.0)); -// const int32_t graphicsTop = static_cast(gridTop - std::floor(halfGridLineWidth + 1.0)); -// const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(lineThicknessPixels + 1.0)); -// const int32_t graphicsRight = static_cast(gridRight - std::floor(lineThicknessPixels + 1.0)); -// const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(lineThicknessPixels + 1.0)); -// const int32_t graphicsTop = static_cast(gridTop - std::floor(lineThicknessPixels + 1.0)); + const float graphicsLeft = vpX + leftAxisWidth + lineThicknessPixels; + const float graphicsRight = vpX + vpWidth - rightAxisWidth - lineThicknessPixels; + const float graphicsBottom = vpY + bottomAxisHeight + lineThicknessPixels; + const float graphicsTop = vpY + vpHeight - topAxisHeight - titleHeight - lineThicknessPixels; const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; @@ -1595,7 +1604,7 @@ m_tabViewportHeight(tabViewport[3]) if (m_axis != NULL) { CaretAssert(m_axis->getAxisLocation() == axisLocation); m_axisDisplayedFlag = (axis->isEnabledByChart() - && axis->isDisplayedByUser()); + && axis->isDisplayedByUser()); } if ( ! m_axisDisplayedFlag) { /* @@ -1606,13 +1615,13 @@ m_tabViewportHeight(tabViewport[3]) case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisHeight = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, - m_tabViewportHeight); + m_tabViewportHeight); m_labelPaddingSizePixels = m_axisHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_axisWidth = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, - m_tabViewportWidth); + m_tabViewportWidth); m_labelPaddingSizePixels = m_axisWidth; break; } @@ -1635,7 +1644,7 @@ m_tabViewportHeight(tabViewport[3]) case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), - m_tabViewportHeight); + m_tabViewportHeight); m_numericsTicksPaddingSizePixels = convertPercentageOfViewportToPixels(numericsTicksPaddingPercentage, m_tabViewportHeight); break; @@ -1649,10 +1658,12 @@ m_tabViewportHeight(tabViewport[3]) } m_lineDrawingWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, - m_tabViewportHeight); + m_tabViewportHeight); m_tickLength = 0.0f; if (m_axis->isShowTickmarks()) { - m_tickLength = m_lineDrawingWidth; // * 2.0f; + const float tickLengthPercentage = 1.0f; + m_tickLength = convertPercentageOfViewportToPixels(tickLengthPercentage, m_tabViewportHeight); + //m_tickLength = m_lineDrawingWidth; // * 2.0f; } /* @@ -1670,18 +1681,19 @@ m_tabViewportHeight(tabViewport[3]) initializeNumericText(dataMinimumValue, dataMaximumValue, numericsWidth, numericsHeight); /* - * Width or height for this axis + * For the bottom and the top, we now have its height but we do not yet know its width + * and likewise for left and right. */ switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - m_axisHeight = m_labelPaddingSizePixels + labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength; + m_axisHeight = std::ceil(m_labelPaddingSizePixels + labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisHeight >= 0.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: /* Note: label is rotated on left/right so use it's height */ - m_axisWidth = m_labelPaddingSizePixels + labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength; + m_axisWidth = std::ceil(m_labelPaddingSizePixels + labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisWidth >= 0.0f); break; } @@ -1696,7 +1708,7 @@ m_tabViewportHeight(tabViewport[3]) * @param widthOut * Output with width of label. * @param heightOut - * Height of label. + * Output with hight of label. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const AString& labelText, @@ -1745,8 +1757,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const double textWidth = 0.0; double textHeight = 0.0; m_textRenderer->getTextWidthHeightInPixels(*text, - m_tabViewportWidth, m_tabViewportHeight, - textWidth, textHeight); + m_tabViewportWidth, m_tabViewportHeight, + textWidth, textHeight); widthOut = textWidth; heightOut = textHeight; } @@ -1788,13 +1800,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( std::vector scaleValuePositions; std::vector scaleValuesText; m_axis->getScaleValuesAndOffsets(dataMinimumDataValue, - dataMaximumDataValue, - axisLength, - m_axisMinimumValue, - m_axisMaximumValue, - scaleValuePositions, - scaleValuesText); + dataMaximumDataValue, + axisLength, + m_axisMinimumValue, + m_axisMaximumValue, + scaleValuePositions, + scaleValuesText); + /* + * For each numeric value, create a text annotation and determine the + * width and height of the text. Also, set either the X or Y-coordinate + * with the normalized coordinate (zero to one) that will be used + * later to position the numeric value. + */ CaretAssert(scaleValuePositions.size() == scaleValuesText.size()); const int32_t numValues = static_cast(scaleValuesText.size()); const int32_t firstIndex = 0; @@ -1819,7 +1837,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); } break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = scaleValuePositions[i]; text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); if (i == firstIndex) { @@ -1878,9 +1896,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( } /** - * Set the axis viewport. Once the width of the left and right and the height of the - * bottom and top axes are known, we can determine the sizes of each axis and set - * calculate the viewport for the axis. + * Set the axis viewport. + * + * In the constructor, we were able to determine the width of the left and right + * axes and the height of the bottom and top axes. Now we can determine + * the size of the other dimension and computer a viewport for the axis. * * @param titleHeight * Height of the title. @@ -1946,14 +1966,17 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const } /** - * Set the coordinates for the label and the numerics once we know the - * viewport for the axis. + * When this method is called, we have the viewport for the axis and we can now use the + * viewport to position the numerical value and the label. * * @param foregroundFloatRGBA * Color of the foreground. + * @param graphicsBoxLineThickness + * Line thickness of the graphics box. */ void -BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4]) +BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4], + const float graphicsBoxLineThickness) { if (m_axis == NULL) { return; @@ -1966,12 +1989,42 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo if ( ! m_axisDisplayedFlag) { return; } - - const float vpX = m_axisViewport[0]; - const float vpY = m_axisViewport[1]; - const float vpWidth = m_axisViewport[2]; - const float vpHeight = m_axisViewport[3]; + /* + * Adjust the 'viewport' to account for the thickness of the lines + * for the box that contains the plot of data + */ + float vpX = m_axisViewport[0]; + float vpY = m_axisViewport[1]; + float vpWidth = m_axisViewport[2]; + float vpHeight = m_axisViewport[3]; + switch (m_axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + vpX += graphicsBoxLineThickness; + vpWidth -= (graphicsBoxLineThickness * 2.0); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + vpY += graphicsBoxLineThickness; + vpHeight -= (graphicsBoxLineThickness * 2.0); + break; + } + + if (debugFlag) { + glColor3f(1.0, 0.0, 0.0); + BrainOpenGL::setLineWidth(1.0); + glBegin(GL_LINE_LOOP); + glVertex2f(vpX, vpY); + glVertex2f(vpX + vpWidth, vpY); + glVertex2f(vpX + vpWidth, vpY + vpHeight); + glVertex2f(vpX, vpY + vpHeight); + glEnd(); + } + + /* + * 'Center' the label in the viewport + */ if (m_axis->isShowLabel()) { float xyz[3]; switch (m_axisLocation) { @@ -1996,7 +2049,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo m_labelText->setCustomTextColor(foregroundFloatRGBA); m_labelText->getCoordinate()->setXYZ(xyz); } - + + /* + * Now convert the 'normalized' (zero to one) numeric value coordinate + * to real coordinate. + */ for (auto& text : m_numericsText) { float xyz[3]; text->getCoordinate()->getXYZ(xyz); @@ -2028,7 +2085,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo /** * Draw the axis. - * + * * @param chartDrawing * The chart drawing parent. * @param foregroundFloatRGBA @@ -2058,15 +2115,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh return; } -// glColor3f(1.0, 0.0, 0.0); -// glLineWidth(2.0); -// glBegin(GL_LINE_LOOP); -// glVertex2f(m_axisViewport[0], m_axisViewport[1]); -// glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); -// glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); -// glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); -// glEnd(); - const int32_t numScaleValuesToDraw = static_cast(m_numericsText.size()); if (numScaleValuesToDraw > 0) { @@ -2092,31 +2140,35 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh const float textY = xyz[1]; /* - * Offset the tick from its corresponding numeric value + * Tick starts at an offset from its corresponding numerical value. + * The length of the tick is increased by half the line width so + * that the tick connects to the box around the data plot without + * a gap. */ float tickStartX = textX; float tickStartY = textY; float tickEndX = 0.0; float tickEndY = 0.0; + const float tickLength = m_tickLength + (m_lineDrawingWidth / 2.0f); switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: tickStartY += m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; - tickEndY = tickStartY + m_tickLength; + tickEndY = tickStartY + tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: tickStartY -= m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; - tickEndY = tickStartY - m_tickLength; + tickEndY = tickStartY - tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: tickStartX += m_numericsTicksPaddingSizePixels; - tickEndX = tickStartX + m_tickLength; + tickEndX = tickStartX + tickLength; tickEndY = tickStartY; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: tickStartX -= m_numericsTicksPaddingSizePixels; - tickEndX = tickStartX - m_tickLength; + tickEndX = tickStartX - tickLength; tickEndY = tickStartY; break; } @@ -2129,19 +2181,25 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh } } + /* + * Draw the numeric value. + */ m_textRenderer->drawTextAtViewportCoords(textX, textY, 0.0, *text); } - + /* * Draw the ticks. */ - glLineWidth(m_lineDrawingWidth); + BrainOpenGL::setLineWidth(m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } + /* + * Draw the label + */ if (m_axis->isShowLabel()) { float xyz[3]; m_labelText->getCoordinate()->getXYZ(xyz); @@ -2188,21 +2246,24 @@ m_title(title) m_paddingSizePixels = convertPercentageOfViewportToPixels(m_title->getPaddingSize(), m_tabViewportHeight); + /* + * Create a text annotation for drawing the title + */ AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); - float xyz[3] = { 0.0f, 0.0f, 0.0f }; - xyz[0] = 0.5f; - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - text->setText(titleText); - text->setFontPercentViewportSize(m_title->getTextSize()); - text->getCoordinate()->setXYZ(xyz); - - double m_textWidth = 0.0; - double m_textHeight = 0.0; - m_textRenderer->getTextWidthHeightInPixels(*text, - m_tabViewportWidth, m_tabViewportHeight, - m_textWidth, m_textHeight); + float xyz[3] = { 0.0f, 0.0f, 0.0f }; + xyz[0] = 0.5f; + text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + text->setText(titleText); + text->setFontPercentViewportSize(m_title->getTextSize()); + text->getCoordinate()->setXYZ(xyz); + + double m_textWidth = 0.0; + double m_textHeight = 0.0; + m_textRenderer->getTextWidthHeightInPixels(*text, + m_tabViewportWidth, m_tabViewportHeight, + m_textWidth, m_textHeight); m_text.reset(text); m_titleHeight = m_paddingSizePixels + m_textHeight; @@ -2225,7 +2286,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::setTitleViewport(cons if ( ! m_titleDisplayedFlag) { return; } - + m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); if (m_titleWidth < 1.0f) { m_titleWidth = 1.0f; @@ -2236,7 +2297,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::setTitleViewport(cons m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); m_titleViewport[0] = leftAxisWidth; - m_titleViewport[1] = /*m_tabViewportY + */m_tabViewportHeight - m_titleHeight; + m_titleViewport[1] = m_tabViewportHeight - m_titleHeight; m_titleViewport[2] = m_titleWidth; m_titleViewport[3] = m_titleHeight; @@ -2269,22 +2330,24 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float return; } - // glColor3f(1.0, 0.0, 0.0); - // glLineWidth(2.0); - // glBegin(GL_LINE_LOOP); - // glVertex2f(m_axisViewport[0], m_axisViewport[1]); - // glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1]); - // glVertex2f(m_axisViewport[0] + m_axisViewport[2], m_axisViewport[1] + m_axisViewport[3]); - // glVertex2f(m_axisViewport[0], m_axisViewport[1] + m_axisViewport[3]); - // glEnd(); + if (debugFlag) { + glColor3f(1.0, 0.0, 0.0); + BrainOpenGL::setLineWidth(2.0); + glBegin(GL_LINE_LOOP); + glVertex2f(m_titleViewport[0], m_titleViewport[1]); + glVertex2f(m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1]); + glVertex2f(m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3]); + glVertex2f(m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3]); + glEnd(); + } m_text->setTextColor(CaretColorEnum::CUSTOM); m_text->setCustomTextColor(foregroundFloatRGBA); - float xyz[3]; - m_text->getCoordinate()->getXYZ(xyz); - m_textRenderer->drawTextAtViewportCoords(xyz[0], - xyz[1], - 0.0, - *(m_text.get())); + float xyz[3]; + m_text->getCoordinate()->getXYZ(xyz); + m_textRenderer->drawTextAtViewportCoords(xyz[0], + xyz[1], + 0.0, + *(m_text.get())); } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index da395c998..43c62499c 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -151,7 +151,8 @@ namespace caret { const float leftAxisWidth, const float rightAxisWidth); - void setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4]); + void setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4], + const float graphicsBoxLineThickness); void drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, const float foregroundFloatRGBA[4], @@ -273,6 +274,9 @@ namespace caret { /** These annotations will be drawn by the annotation drawing code */ std::vector m_annotationsForDrawingOutput; + static float s_minimumLineWidthOpenGL; + static float s_maximumLineWidthOpenGL; + static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; @@ -282,7 +286,8 @@ namespace caret { }; #ifdef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ - // + float BrainOpenGLChartTwoDrawingFixedPipeline::s_minimumLineWidthOpenGL = 1.0f; + float BrainOpenGLChartTwoDrawingFixedPipeline::s_maximumLineWidthOpenGL = 1.0f; #endif // __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ } // namespace diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index b56110c79..9084dee0e 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -1159,7 +1159,7 @@ BrainOpenGLFixedPipeline::applyClippingPlanes(const ClippingDataType clippingDat if (m_clippingPlaneGroup->isDisplayClippingBoxSelected()) { glColor3f(1.0, 0.0, 0.0); - glLineWidth(2.0); + setLineWidth(2.0); glPushMatrix(); glTranslatef(panning[0], panning[1], panning[2]); @@ -2976,46 +2976,6 @@ BrainOpenGLFixedPipeline::unstretchedBorderLineTest(const float p1[3], return false; } - -/** - * Set the OpenGL line width. Value is clamped - * to minimum and maximum values to prevent - * OpenGL error caused by invalid line width. - */ -void -BrainOpenGLFixedPipeline::setLineWidth(const float lineWidth) -{ - if (lineWidth > s_maxLineWidth) { - glLineWidth(s_maxLineWidth); - } - else if (lineWidth < s_minLineWidth) { - glLineWidth(s_minLineWidth); - } - else { - glLineWidth(lineWidth); - } -} - -/** - * Set the OpenGL point size. Value is clamped - * to minimum and maximum values to prevent - * OpenGL error caused by invalid point size. - */ -void -BrainOpenGLFixedPipeline::setPointSize(const float pointSize) -{ - if (pointSize > s_maxPointSize) { - glPointSize(s_maxPointSize); - } - else if (pointSize < s_minPointSize) { - glPointSize(s_minPointSize); - } - else { - glPointSize(pointSize); - } -} - - /** * Draw foci on a surface. * @param surface diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 44ca549b2..deac26cd2 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -483,10 +483,6 @@ namespace caret { const int barycentricNodes[3], const int numberOfNodes); - void setLineWidth(const float lineWidth); - - void setPointSize(const float pointSize); - enum ClippingDataType { CLIPPING_DATA_TYPE_FEATURES, CLIPPING_DATA_TYPE_SURFACE, diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 21cb08e7f..7013aab58 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -79,11 +79,24 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_chartOverlaySet = NULL; m_chartAxis = NULL; - m_axisDisplayedByUserCheckBox = new QCheckBox("Show Axis"); + /* + * 'Show' checkboxes + */ + m_axisDisplayedByUserCheckBox = new QCheckBox("Axis"); m_axisDisplayedByUserCheckBox->setToolTip("Show/hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); + m_showTickMarksCheckBox = new QCheckBox("Ticks"); + QObject::connect(m_showTickMarksCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); + + m_showLabelCheckBox = new QCheckBox("Label"); + QObject::connect(m_showLabelCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_showLabelCheckBox->setToolTip("Show label on axis"); + /* * Axes selection */ @@ -94,7 +107,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_axisComboBox->getWidget()->setToolTip("Choose axis for editing"); /* - * Controls for axis parameters + * Controls for layer selection and label editing */ m_axisLabelToolButton = new QToolButton(); m_axisLabelToolButton->setText("Edit Label..."); @@ -103,6 +116,15 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisLabelToolButton); m_axisLabelToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); + QLabel* axisLabelFromOverlayLabel = new QLabel("Label From File In"); + m_axisLabelFromOverlayComboBox = new QComboBox(); + m_axisLabelFromOverlayComboBox->setToolTip("Label for axis is from file in selected layer"); + QObject::connect(m_axisLabelFromOverlayComboBox, static_cast(&QComboBox::activated), + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); + + /* + * Range controls + */ m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); m_autoUserRangeComboBox->setup(); QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, @@ -120,22 +142,9 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); - m_showTickMarksCheckBox = new QCheckBox("Show Ticks"); - QObject::connect(m_showTickMarksCheckBox, &QCheckBox::clicked, - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); - m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); - - m_showLabelCheckBox = new QCheckBox("Show Label"); - QObject::connect(m_showLabelCheckBox, &QCheckBox::clicked, - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); - m_showLabelCheckBox->setToolTip("Show label on axis"); - - QLabel* axisLabelFromOverlayLabel = new QLabel("Label From File In"); - m_axisLabelFromOverlayComboBox = new QComboBox(); - m_axisLabelFromOverlayComboBox->setToolTip("Label for axis is from file in selected layer"); - QObject::connect(m_axisLabelFromOverlayComboBox, static_cast(&QComboBox::activated), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); - + /* + * Format controls + */ m_userNumericFormatComboBox = new EnumComboBoxTemplate(this); m_userNumericFormatComboBox->setup(); QObject::connect(m_userNumericFormatComboBox, &EnumComboBoxTemplate::itemActivated, @@ -165,25 +174,25 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_labelSizeSpinBox->setSuffix("%"); QObject::connect(m_labelSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); - m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height"); + m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); m_numericsSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); m_numericsSizeSpinBox->setSuffix("%"); QObject::connect(m_numericsSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); - m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height"); + m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); m_linesTicksSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); m_linesTicksSizeSpinBox->setSuffix("%"); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); - m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines and ticks as percentage of tab height"); + m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); m_paddingSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); m_paddingSizeSpinBox->setSuffix("%"); QObject::connect(m_paddingSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); - m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); + m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); /* * Group widgets for blocking signals @@ -217,15 +226,15 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra sizesLayout->addWidget(new QLabel("Label"), sizesRow, 0); sizesLayout->addWidget(m_labelSizeSpinBox, sizesRow, 1); sizesRow++; - sizesLayout->addWidget(new QLabel("Numerics"), sizesRow, 0); + sizesLayout->addWidget(new QLabel("Scale"), sizesRow, 0); sizesLayout->addWidget(m_numericsSizeSpinBox, sizesRow, 1); sizesRow++; - sizesLayout->addWidget(new QLabel("Lines/Ticks"), sizesRow, 0); - sizesLayout->addWidget(m_linesTicksSizeSpinBox, sizesRow, 1); - sizesRow++; - sizesLayout->addWidget(new QLabel("Padding"), sizesRow, 0); + sizesLayout->addWidget(new QLabel("Pad"), sizesRow, 0); sizesLayout->addWidget(m_paddingSizeSpinBox, sizesRow, 1); sizesRow++; + sizesLayout->addWidget(new QLabel("Lines"), sizesRow, 0); + sizesLayout->addWidget(m_linesTicksSizeSpinBox, sizesRow, 1); + sizesRow++; /* * Show widgets layout @@ -234,6 +243,8 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QGridLayout* showLayout = new QGridLayout(showWidget); WuQtUtilities::setLayoutSpacingAndMargins(showLayout, 8, 0); int32_t axisRow = 0; + showLayout->addWidget(new QLabel("Show"), axisRow, 0, Qt::AlignHCenter); + axisRow++; showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_showLabelCheckBox, axisRow, 0); @@ -250,16 +261,16 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QGridLayout* rangeLayout = new QGridLayout(rangeWidget); WuQtUtilities::setLayoutSpacingAndMargins(rangeLayout, 3, 0); int rangeRow = 0; - rangeLayout->addWidget(new QLabel("Range Mode"), rangeRow, 0); + rangeLayout->addWidget(new QLabel("Range"), rangeRow, 0); m_autoUserRangeComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); rangeLayout->addWidget(m_autoUserRangeComboBox->getWidget(), rangeRow, 1); rangeRow++; m_userMinimumValueSpinBox->setFixedWidth(90); m_userMaximumValueSpinBox->setFixedWidth(90); - rangeLayout->addWidget(new QLabel("User Max"), rangeRow, 0); + rangeLayout->addWidget(new QLabel("Max"), rangeRow, 0); rangeLayout->addWidget(m_userMaximumValueSpinBox, rangeRow, 1); rangeRow++; - rangeLayout->addWidget(new QLabel("User Min"), rangeRow, 0); + rangeLayout->addWidget(new QLabel("Min"), rangeRow, 0); rangeLayout->addWidget(m_userMinimumValueSpinBox, rangeRow, 1); /* @@ -268,19 +279,17 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra QWidget* numericsWidget = new QWidget(); QGridLayout* numericsLayout = new QGridLayout(numericsWidget); WuQtUtilities::setLayoutSpacingAndMargins(numericsLayout, 3, 0); - int COLUMN_ONE = 0; - int COLUMN_TWO = 1; - int COLUMN_THREE = 2; int numericsRow = 0; - numericsLayout->addWidget(new QLabel("Format"), numericsRow, COLUMN_ONE); - numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), numericsRow, COLUMN_TWO, 1, 2); + numericsLayout->addWidget(new QLabel("Format"), numericsRow, 0); + numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), numericsRow, 1); + numericsRow++; + numericsLayout->addWidget(new QLabel("Decimals"), numericsRow, 0); + numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, numericsRow, 1); numericsRow++; - numericsLayout->addWidget(new QLabel("Decimals"), numericsRow, COLUMN_ONE); - numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, numericsRow, COLUMN_TWO, 1, 2); + numericsLayout->addWidget(new QLabel("Subdivisions"), numericsRow, 0); + numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), numericsRow, 1); numericsRow++; - numericsLayout->addWidget(new QLabel("Subdivisions"), numericsRow, COLUMN_ONE); - numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), numericsRow, COLUMN_TWO); - numericsLayout->addWidget(m_userSubdivisionsSpinBox, numericsRow, COLUMN_THREE); + numericsLayout->addWidget(m_userSubdivisionsSpinBox, numericsRow, 1); /* * Top layout @@ -310,10 +319,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 5); gridLayout->addWidget(numericsWidget, 1, 6, Qt::AlignTop); - QVBoxLayout* dialogLayout = new QVBoxLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 2); - dialogLayout->addLayout(gridLayout); - dialogLayout->addStretch(); + QVBoxLayout* layout = new QVBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 2); + layout->addLayout(gridLayout); + layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 4145c5609..5ba333707 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -84,13 +84,18 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); QGridLayout* layout = new QGridLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); - layout->addWidget(m_showTitleCheckBox, 0, 0, 1, 2, Qt::AlignHCenter); - layout->addWidget(new QLabel("Size"), 1, 0); - layout->addWidget(m_titleSizeSpinBox, 1, 1); - layout->addWidget(new QLabel("Padding"), 2, 0); - layout->addWidget(m_paddingSizeSpinBox, 2, 1); - layout->addWidget(editTitleToolButton, 3, 0, 1, 2, Qt::AlignHCenter); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); //4, 5); + int row = 0; + layout->addWidget(m_showTitleCheckBox, row, 0, 1, 2, Qt::AlignHCenter); + row++; + layout->addWidget(new QLabel("Size"), row, 0); + layout->addWidget(m_titleSizeSpinBox, row, 1); + row++; + layout->addWidget(new QLabel("Pad"), row, 0); + layout->addWidget(m_paddingSizeSpinBox, row, 1); + row++; + layout->addWidget(editTitleToolButton, row, 0, 1, 2, Qt::AlignHCenter); + row++; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); -- GitLab From 5c45830b522294acc840d2fc77f1640ea9244ab8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 24 Aug 2017 10:06:28 -0500 Subject: [PATCH 361/755] Resolve WB-724 Edit chart axis labels by clicking on them: In view mode, one may edit a chart axis label by using a right-click (control-click on Mac). Also, fixed mysterious missing chart when all y-values were zero. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 187 ++++++++++++++++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 10 + src/Brain/CMakeLists.txt | 2 + src/Brain/SelectionItemChartTwoLabel.cxx | 165 ++++++++++++++++ src/Brain/SelectionItemChartTwoLabel.h | 78 ++++++++ src/Brain/SelectionItemDataTypeEnum.cxx | 4 + src/Brain/SelectionItemDataTypeEnum.h | 2 + src/Brain/SelectionManager.cxx | 21 ++ src/Brain/SelectionManager.h | 7 + src/GuiQt/UserInputModeView.cxx | 50 +++++ src/GuiQt/UserInputModeView.h | 2 + src/GuiQt/UserInputModeViewContextMenu.cxx | 98 ++++++++- src/GuiQt/UserInputModeViewContextMenu.h | 4 + 13 files changed, 604 insertions(+), 26 deletions(-) create mode 100644 src/Brain/SelectionItemChartTwoLabel.cxx create mode 100644 src/Brain/SelectionItemChartTwoLabel.h diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index bd161f740..9a99773b8 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -63,6 +63,7 @@ #include "SessionManager.h" #include "SelectionItemAnnotation.h" #include "SelectionItemChartTwoHistogram.h" +#include "SelectionItemChartTwoLabel.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionManager.h" @@ -156,6 +157,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); + m_selectionItemChartLabel = m_brain->getSelectionManager()->getChartTwoLabelIdentification(); m_fixedPipelineDrawing->disableLighting(); @@ -221,11 +223,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if ( (! m_selectionItemHistogram->isEnabledForSelection()) - && (! m_selectionItemAnnotation->isEnabledForSelection()) ){ + && (! m_selectionItemAnnotation->isEnabledForSelection()) + && (! m_selectionItemChartLabel->isEnabledForSelection()) ) { drawHistogramFlag = false; } if ( (! m_selectionItemLineSeries->isEnabledForSelection()) - && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { + && (! m_selectionItemAnnotation->isEnabledForSelection()) + && (! m_selectionItemChartLabel->isEnabledForSelection()) ) { drawLineSeriesFlag = false; } if ( (! m_selectionItemMatrix->isEnabledForSelection()) @@ -467,14 +471,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Bounds valid? + * For X, maximum value must be greater than minimum value + * For Y, maximum value must be greater than or equal to minimum value since + * all data points may be zero. */ const bool xBottomValid = (xMinBottom < xMaxBottom); const bool xTopValid = (xMinTop < xMaxTop); const bool xValid = (xBottomValid || xTopValid); - const bool yLeftValid = (yMinLeft < yMaxLeft); - const bool yRightValid = (yMinRight < yMaxRight); + const bool yLeftValid = (yMinLeft <= yMaxLeft); + const bool yRightValid = (yMinRight <= yMaxRight); const bool yValid = (yLeftValid || yRightValid); - if (xValid || yValid) { + if (xValid && yValid) { + /* + * If Y-range is zero, make it a non-zero range. + * Otherwise, the orthographic projection will be invalid + */ + const float smallValue = 0.00001; + const float smallRange = 0.01; + if (yLeftValid) { + const float diff = yMaxLeft - yMinLeft; + if (diff < smallValue) { + yMinLeft -= smallRange; + yMaxLeft += smallRange; + } + } + if (yRightValid) { + const float diff = yMaxRight - yMinRight; + if (diff < smallValue) { + yMinRight -= smallRange; + yMaxRight += smallRange; + } + } + /* * Make invalid ranges zero */ @@ -657,10 +685,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch && (tabViewportHeight > (bottomAxisHeight + topAxisHeight + topTitleHeight))) { titleInfo.drawTitle(foregroundRGBA); - leftAxisInfo.drawAxis(this, foregroundRGBA, yMinLeft, yMaxLeft); - rightAxisInfo.drawAxis(this, foregroundRGBA, yMinRight, yMaxRight); - topAxisInfo.drawAxis(this, foregroundRGBA, xMinTop, xMaxTop); - bottomAxisInfo.drawAxis(this, foregroundRGBA, xMinBottom, xMaxBottom); + leftAxisInfo.drawAxis(this, + m_chartOverlaySet, + m_fixedPipelineDrawing->getContextSharingGroupPointer(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + foregroundRGBA, + yMinLeft, + yMaxLeft); + rightAxisInfo.drawAxis(this, + m_chartOverlaySet, + m_fixedPipelineDrawing->getContextSharingGroupPointer(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + foregroundRGBA, + yMinRight, + yMaxRight); + topAxisInfo.drawAxis(this, + m_chartOverlaySet, + m_fixedPipelineDrawing->getContextSharingGroupPointer(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + foregroundRGBA, + xMinTop, + xMaxTop); + bottomAxisInfo.drawAxis(this, + m_chartOverlaySet, + m_fixedPipelineDrawing->getContextSharingGroupPointer(), + m_fixedPipelineDrawing->mouseX, + m_fixedPipelineDrawing->mouseY, + foregroundRGBA, + xMinBottom, + xMaxBottom); drawChartGraphicsBoxAndSetViewport(tabViewportX, @@ -1669,9 +1725,7 @@ m_tabViewportHeight(tabViewport[3]) /* * Width/height of label */ - float labelWidth = 0.0f; - float labelHeight = 0.0f; - initializeLabel(labelText, labelWidth, labelHeight); + initializeLabel(labelText, m_labelWidth, m_labelHeight); /* * Maximum width/height of numeric values @@ -1687,13 +1741,13 @@ m_tabViewportHeight(tabViewport[3]) switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - m_axisHeight = std::ceil(m_labelPaddingSizePixels + labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength); + m_axisHeight = std::ceil(m_labelPaddingSizePixels + m_labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisHeight >= 0.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: /* Note: label is rotated on left/right so use it's height */ - m_axisWidth = std::ceil(m_labelPaddingSizePixels + labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength); + m_axisWidth = std::ceil(m_labelPaddingSizePixels + m_labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisWidth >= 0.0f); break; } @@ -2026,7 +2080,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo * 'Center' the label in the viewport */ if (m_axis->isShowLabel()) { - float xyz[3]; + float xyz[3] = { 0.0, 0.0, 0.0 }; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = vpX + (vpWidth / 2.0f); @@ -2055,7 +2109,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo * to real coordinate. */ for (auto& text : m_numericsText) { - float xyz[3]; + float xyz[3] = { 0.0, 0.0, 0.0 }; text->getCoordinate()->getXYZ(xyz); switch (m_axisLocation) { @@ -2088,6 +2142,14 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo * * @param chartDrawing * The chart drawing parent. + * @param chartTwoOverlaySet + * Chart overlay set containing the axis. + * @param openGLContextSharingGroupPointer + * Pointer to current OpenGL context. + * @param mouseX + * X-coordinate of the mouse. + * @param mouseY + * Y-coordinate of the mouse. * @param foregroundFloatRGBA * Color of the foreground. * @param axisMinimumValueOut @@ -2097,6 +2159,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, + ChartTwoOverlaySet* chartTwoOverlaySet, + void* openGLContextSharingGroupPointer, + const int32_t mouseX, + const int32_t mouseY, const float foregroundFloatRGBA[4], float& axisMinimumValueOut, float& axisMaximumValueOut) @@ -2203,10 +2269,91 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh if (m_axis->isShowLabel()) { float xyz[3]; m_labelText->getCoordinate()->getXYZ(xyz); - m_textRenderer->drawTextAtViewportCoords(xyz[0], - xyz[1], - 0.0, - *(m_labelText.get())); + if (chartDrawing->m_identificationModeFlag) { + /* + * For identification simply draw a box in a single quad + */ + int32_t primitiveIndex = -1; + float primitiveDepth = 0.0; + + float bottomLeft[3], bottomRight[3], topLeft[3], topRight[3]; + m_textRenderer->getBoundsForTextAtViewportCoords(*(m_labelText.get()), xyz[0], xyz[1], xyz[2], + m_tabViewportWidth, m_tabViewportHeight, + bottomLeft, bottomRight, topRight, topLeft); + + std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, + foregroundFloatRGBA)); + boxPrimitive->reserveForNumberOfVertices(4); + boxPrimitive->addVertex(bottomLeft); + boxPrimitive->addVertex(bottomRight); + boxPrimitive->addVertex(topRight); + boxPrimitive->addVertex(topLeft); + +// Complete offsets and maybe examine alignments from the text annotation to set the offsets +// +// float horizSize = 0.0f; +// float vertSize = 0.0f; +// switch (m_axisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// horizSize = m_labelWidth; +// vertSize = m_labelHeight; +// xyz[1] += (vertSize / 2.0f); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// horizSize = m_labelWidth; +// vertSize = m_labelHeight; +// xyz[1] -= (vertSize / 2.0f); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// /* +// * Label is drawn rotated 90 degrees ! +// */ +// horizSize = m_labelHeight; +// vertSize = m_labelWidth; +// xyz[0] += (horizSize / 2.0f); +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// /* +// * Label is drawn rotated 90 degrees ! +// */ +// horizSize = m_labelHeight; +// vertSize = m_labelWidth; +// xyz[0] -= (horizSize / 2.0f); +// break; +// } +// +// const float halfWidth = horizSize / 2.0f; +// const float halfHeight = vertSize / 2.0f; +// const float left = xyz[0] - halfWidth; +// const float right = xyz[0] + halfWidth; +// const float bottom = xyz[1] - halfHeight; +// const float top = xyz[1] + halfHeight; +// std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, +// foregroundFloatRGBA)); +// boxPrimitive->addVertex(left, bottom, 0.0f); +// boxPrimitive->addVertex(right, bottom, 0.0f); +// boxPrimitive->addVertex(right, top, 0.0f); +// boxPrimitive->addVertex(left, top, 0.0f); + + GraphicsEngineDataOpenGL::drawWithSelection(openGLContextSharingGroupPointer, + boxPrimitive.get(), + mouseX, + mouseY, + primitiveIndex, + primitiveDepth); + + if (primitiveIndex >= 0) { + if (chartDrawing->m_selectionItemChartLabel->isOtherScreenDepthCloserToViewer(primitiveDepth)) { + chartDrawing->m_selectionItemChartLabel->setChartTwoCartesianAxis(const_cast(m_axis), + chartTwoOverlaySet); + } + } + } + else { + m_textRenderer->drawTextAtViewportCoords(xyz[0], + xyz[1], + 0.0, + *(m_labelText.get())); + } } } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 43c62499c..cf8cd80e7 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -44,6 +44,7 @@ namespace caret { class GraphicsPrimitive; class SelectionItemAnnotation; class SelectionItemChartTwoHistogram; + class SelectionItemChartTwoLabel; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; @@ -155,6 +156,10 @@ namespace caret { const float graphicsBoxLineThickness); void drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, + ChartTwoOverlaySet* chartTwoOverlaySet, + void* openGLContextSharingGroupPointer, + const int32_t mouseX, + const int32_t mouseY, const float foregroundFloatRGBA[4], float& axisMinimumValueOut, float& axisMaximumValueOut); @@ -185,6 +190,8 @@ namespace caret { const float m_tabViewportHeight = 0.0f; float m_lineDrawingWidth = 1.0f; float m_tickLength = 0.0f; + float m_labelWidth = 0.0f; + float m_labelHeight = 0.0f; void initializeNumericText(const float dataMinimumDataValue, const float dataMaximumDataValue, @@ -269,6 +276,8 @@ namespace caret { SelectionItemChartTwoMatrix* m_selectionItemMatrix; + SelectionItemChartTwoLabel* m_selectionItemChartLabel; + bool m_identificationModeFlag; /** These annotations will be drawn by the annotation drawing code */ @@ -283,6 +292,7 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + friend class AxisDrawingInfo; }; #ifdef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 3cd2d626b..ee1f469c8 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -161,6 +161,7 @@ SelectionItemChartFrequencySeries.h SelectionItemChartMatrix.h SelectionItemChartTimeSeries.h SelectionItemChartTwoHistogram.h +SelectionItemChartTwoLabel.h SelectionItemChartTwoLineSeries.h SelectionItemChartTwoMatrix.h SelectionItemCiftiConnectivityMatrixRowColumn.h @@ -306,6 +307,7 @@ SelectionItemChartFrequencySeries.cxx SelectionItemChartMatrix.cxx SelectionItemChartTimeSeries.cxx SelectionItemChartTwoHistogram.cxx +SelectionItemChartTwoLabel.cxx SelectionItemChartTwoLineSeries.cxx SelectionItemChartTwoMatrix.cxx SelectionItemCiftiConnectivityMatrixRowColumn.cxx diff --git a/src/Brain/SelectionItemChartTwoLabel.cxx b/src/Brain/SelectionItemChartTwoLabel.cxx new file mode 100644 index 000000000..c823b6190 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoLabel.cxx @@ -0,0 +1,165 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ +#include "SelectionItemChartTwoLabel.h" +#undef __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::SelectionItemChartTwoLabel + * \brief Selection of chart version two label + * \ingroup Brain + */ + +/** + * Constructor. + */ +SelectionItemChartTwoLabel::SelectionItemChartTwoLabel() +: SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LABEL) +{ + m_chartTwoCartesianAxis = NULL; + m_chartTwoOverlaySet = NULL; +} + +/** + * Destructor. + */ +SelectionItemChartTwoLabel::~SelectionItemChartTwoLabel() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +SelectionItemChartTwoLabel::SelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj) +: SelectionItem(obj) +{ + this->copyHelperSelectionItemChartTwoLabel(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +SelectionItemChartTwoLabel& +SelectionItemChartTwoLabel::operator=(const SelectionItemChartTwoLabel& obj) +{ + if (this != &obj) { + SelectionItem::operator=(obj); + this->copyHelperSelectionItemChartTwoLabel(obj); + } + return *this; +} + +/** + * @return The cartesian axis. + */ +const ChartTwoCartesianAxis* +SelectionItemChartTwoLabel::getChartTwoCartesianAxis() const +{ + return m_chartTwoCartesianAxis; +} + +/** + * @return The cartesian axis. + */ +ChartTwoCartesianAxis* +SelectionItemChartTwoLabel::getChartTwoCartesianAxis() +{ + return m_chartTwoCartesianAxis; +} + +/** + * @return The chart overlay set. + */ +ChartTwoOverlaySet* +SelectionItemChartTwoLabel::getChartOverlaySet() +{ + return m_chartTwoOverlaySet; +} + +/** + * @return The chart overlay set. + */ +const ChartTwoOverlaySet* +SelectionItemChartTwoLabel::getChartOverlaySet() const +{ + return m_chartTwoOverlaySet; +} + +/** + * Set selection. + * + * @param chartTwoCartesianAxis + * The cartesian axis. + * @param chartOverlaySet + * The chart overlay set + */ +void +SelectionItemChartTwoLabel::setChartTwoCartesianAxis(ChartTwoCartesianAxis* chartTwoCartesianAxis, + ChartTwoOverlaySet* chartOverlaySet) +{ + m_chartTwoCartesianAxis = chartTwoCartesianAxis; + m_chartTwoOverlaySet = chartOverlaySet; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +SelectionItemChartTwoLabel::copyHelperSelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj) +{ + m_chartTwoCartesianAxis = obj.m_chartTwoCartesianAxis; + m_chartTwoOverlaySet = obj.m_chartTwoOverlaySet; +} + +/** + * @return True if the selected chart label is valid, else false. + */ +bool +SelectionItemChartTwoLabel::isValid() const +{ + return ((m_chartTwoCartesianAxis != NULL) + && (m_chartTwoOverlaySet != NULL)); +} + +/** + * Reset the selections. + */ +void +SelectionItemChartTwoLabel::reset() +{ + m_chartTwoCartesianAxis = NULL; + m_chartTwoOverlaySet = NULL; +} + diff --git a/src/Brain/SelectionItemChartTwoLabel.h b/src/Brain/SelectionItemChartTwoLabel.h new file mode 100644 index 000000000..075f03e02 --- /dev/null +++ b/src/Brain/SelectionItemChartTwoLabel.h @@ -0,0 +1,78 @@ +#ifndef __SELECTION_ITEM_CHART_TWO_LABEL_H__ +#define __SELECTION_ITEM_CHART_TWO_LABEL_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "SelectionItem.h" + + + +namespace caret { + + class ChartTwoCartesianAxis; + class ChartTwoOverlaySet; + + class SelectionItemChartTwoLabel : public SelectionItem { + + public: + SelectionItemChartTwoLabel(); + + virtual ~SelectionItemChartTwoLabel(); + + SelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj); + + SelectionItemChartTwoLabel& operator=(const SelectionItemChartTwoLabel& obj); + + virtual bool isValid() const override; + + virtual void reset() override; + + const ChartTwoCartesianAxis* getChartTwoCartesianAxis() const; + + ChartTwoCartesianAxis* getChartTwoCartesianAxis(); + + const ChartTwoOverlaySet* getChartOverlaySet() const; + + ChartTwoOverlaySet* getChartOverlaySet(); + + void setChartTwoCartesianAxis(ChartTwoCartesianAxis* ChartTwoCartesianAxis, + ChartTwoOverlaySet* chartOverlaySet); + + // ADD_NEW_METHODS_HERE + + private: + void copyHelperSelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj); + + ChartTwoCartesianAxis* m_chartTwoCartesianAxis; + + ChartTwoOverlaySet* m_chartTwoOverlaySet; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ + // +#endif // __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ + +} // namespace +#endif //__SELECTION_ITEM_CHART_TWO_LABEL_H__ diff --git a/src/Brain/SelectionItemDataTypeEnum.cxx b/src/Brain/SelectionItemDataTypeEnum.cxx index fc165a10e..7d1b29855 100644 --- a/src/Brain/SelectionItemDataTypeEnum.cxx +++ b/src/Brain/SelectionItemDataTypeEnum.cxx @@ -107,6 +107,10 @@ SelectionItemDataTypeEnum::initialize() "CHART_TWO_LINE_SERIES", "Line-Series Chart Two")); + enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_LABEL, + "CHART_TWO_LABEL", + "Label Chart Two")); + enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_MATRIX, "CHART_TWO_MATRIX", "Matrix Chart Two")); diff --git a/src/Brain/SelectionItemDataTypeEnum.h b/src/Brain/SelectionItemDataTypeEnum.h index 965735320..5ce2bf9d1 100644 --- a/src/Brain/SelectionItemDataTypeEnum.h +++ b/src/Brain/SelectionItemDataTypeEnum.h @@ -59,6 +59,8 @@ public: CHART_TIME_SERIES, /** Version Two Chart Histogram */ CHART_TWO_HISTOGRAM, + /** Version Two Chart Label */ + CHART_TWO_LABEL, /** Version Two Chart Line-Series */ CHART_TWO_LINE_SERIES, /** Version Two Chart Matrix */ diff --git a/src/Brain/SelectionManager.cxx b/src/Brain/SelectionManager.cxx index 1fc97a436..91b24486a 100644 --- a/src/Brain/SelectionManager.cxx +++ b/src/Brain/SelectionManager.cxx @@ -38,6 +38,7 @@ #include "SelectionItemChartMatrix.h" #include "SelectionItemChartTimeSeries.h" #include "SelectionItemChartTwoHistogram.h" +#include "SelectionItemChartTwoLabel.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" @@ -76,6 +77,7 @@ SelectionManager::SelectionManager() m_chartDataFrequencyIdentification = new SelectionItemChartFrequencySeries(); m_chartMatrixIdentification = new SelectionItemChartMatrix(); m_chartTwoHistogramIdentification = std::unique_ptr(new SelectionItemChartTwoHistogram()); + m_chartTwoLabelIdentification = std::unique_ptr(new SelectionItemChartTwoLabel()); m_chartTwoLineSeriesIdentification = std::unique_ptr(new SelectionItemChartTwoLineSeries()); m_chartTwoMatrixIdentification = std::unique_ptr(new SelectionItemChartTwoMatrix()); @@ -99,6 +101,7 @@ SelectionManager::SelectionManager() m_allSelectionItems.push_back(m_chartMatrixIdentification); m_allSelectionItems.push_back(m_chartTimeSeriesIdentification); m_allSelectionItems.push_back(m_chartTwoHistogramIdentification.get()); + m_allSelectionItems.push_back(m_chartTwoLabelIdentification.get()); m_allSelectionItems.push_back(m_chartTwoLineSeriesIdentification.get()); m_allSelectionItems.push_back(m_chartTwoMatrixIdentification.get()); m_allSelectionItems.push_back(m_ciftiConnectivityMatrixRowColumnIdentfication); @@ -768,6 +771,24 @@ SelectionManager::getChartTwoLineSeriesIdentification() const return m_chartTwoLineSeriesIdentification.get(); } +/** + * @return Identification for chart two label identification + */ +SelectionItemChartTwoLabel* +SelectionManager::getChartTwoLabelIdentification() +{ + return m_chartTwoLabelIdentification.get(); +} + +/** + * @return Identification for chart two label identification + */ +const SelectionItemChartTwoLabel* +SelectionManager::getChartTwoLabelIdentification() const +{ + return m_chartTwoLabelIdentification.get(); +} + /** * @return Identification for chart two matrix identification. */ diff --git a/src/Brain/SelectionManager.h b/src/Brain/SelectionManager.h index cae784499..731496ee3 100644 --- a/src/Brain/SelectionManager.h +++ b/src/Brain/SelectionManager.h @@ -38,6 +38,7 @@ namespace caret { class SelectionItemChartMatrix; class SelectionItemChartTimeSeries; class SelectionItemChartTwoHistogram; + class SelectionItemChartTwoLabel; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; class SelectionItemCiftiConnectivityMatrixRowColumn; @@ -141,6 +142,10 @@ namespace caret { const SelectionItemChartTwoLineSeries* getChartTwoLineSeriesIdentification() const; + SelectionItemChartTwoLabel* getChartTwoLabelIdentification(); + + const SelectionItemChartTwoLabel* getChartTwoLabelIdentification() const; + SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification(); const SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification() const; @@ -198,6 +203,8 @@ namespace caret { std::unique_ptr m_chartTwoLineSeriesIdentification; + std::unique_ptr m_chartTwoLabelIdentification; + std::unique_ptr m_chartTwoMatrixIdentification; SelectionItemCiftiConnectivityMatrixRowColumn* m_ciftiConnectivityMatrixRowColumnIdentfication; diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index 3614e5b10..94f88d5f3 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -20,6 +20,7 @@ /*LICENSE_END*/ #include +#include #define __USER_INPUT_MODE_VIEW_DECLARE__ #include "UserInputModeView.h" @@ -29,12 +30,17 @@ #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" +#include "ChartTwoCartesianAxis.h" +#include "ChartTwoOverlaySet.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventUpdateYokedWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "MouseEvent.h" +#include "SelectionItemChartTwoLabel.h" +#include "SelectionManager.h" #include "UserInputModeViewContextMenu.h" +#include "WuQDataEntryDialog.h" using namespace caret; @@ -162,6 +168,50 @@ UserInputModeView::toString() const return "UserInputModeView"; } +/** + * Process a mouse left double-click event. + * + * @param mouseEvent + * Mouse event information. + */ +void +UserInputModeView::mouseLeftDoubleClick(const MouseEvent& mouseEvent) +{ + const bool allowDoubleClickToEditChartLabel = false; + if (allowDoubleClickToEditChartLabel) { + const int32_t mouseX = mouseEvent.getX(); + const int32_t mouseY = mouseEvent.getY(); + + BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); + SelectionManager* idManager = openGLWidget->performIdentification(mouseX, + mouseY, + false); + CaretAssert(idManager); + SelectionItemChartTwoLabel* labelID = idManager->getChartTwoLabelIdentification(); + if (labelID->isValid()) { + ChartTwoCartesianAxis* axis = labelID->getChartTwoCartesianAxis(); + ChartTwoOverlaySet* chartOverlaySet = labelID->getChartOverlaySet(); + if ((axis != NULL) + && (chartOverlaySet != NULL)) { + WuQDataEntryDialog newNameDialog("Axis Label", + openGLWidget); + QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); + lineEdit->setText(chartOverlaySet->getAxisLabel(axis)); + if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { + const AString name = lineEdit->text().trimmed(); + chartOverlaySet->setAxisLabel(axis, + name); + + /* + * Update graphics. + */ + updateGraphics(mouseEvent); + } + } + } + } +} + /** * Process a mouse left click event. * diff --git a/src/GuiQt/UserInputModeView.h b/src/GuiQt/UserInputModeView.h index 59a9f40f4..e11923075 100644 --- a/src/GuiQt/UserInputModeView.h +++ b/src/GuiQt/UserInputModeView.h @@ -42,6 +42,8 @@ namespace caret { virtual CursorEnum::Enum getCursor() const; + virtual void mouseLeftDoubleClick(const MouseEvent& mouseEvent); + virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithShift(const MouseEvent& mouseEvent); diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index 6728c5b03..fc78fa938 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -20,6 +20,7 @@ /*LICENSE_END*/ #include +#include #define __USER_INPUT_MODE_VIEW_CONTEXT_MENU_DECLARE__ #include "UserInputModeViewContextMenu.h" @@ -34,6 +35,8 @@ #include "BrowserTabContent.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartingDataManager.h" +#include "ChartTwoCartesianAxis.h" +#include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryFile.h" @@ -57,6 +60,7 @@ #include "Model.h" #include "ProgressReportingDialog.h" #include "SelectionItemBorderSurface.h" +#include "SelectionItemChartTwoLabel.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemSurfaceNode.h" @@ -67,6 +71,7 @@ #include "Surface.h" #include "UserInputModeFociWidget.h" #include "VolumeFile.h" +#include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -109,6 +114,11 @@ UserInputModeViewContextMenu::UserInputModeViewContextMenu(SelectionManager* sel */ addBorderRegionOfInterestActions(); + /* + * Add the chart actions + */ + addChartActions(); + /* * Add the foci actions. */ @@ -117,16 +127,41 @@ UserInputModeViewContextMenu::UserInputModeViewContextMenu(SelectionManager* sel /* * Show Label ROI operations only for surfaces */ - addLabelRegionOfInterestActions(); + addLabelRegionOfInterestActions(); const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); - if (this->actions().count() > 0) { - this->addSeparator(); + bool showRemoveVertexSymbolsFlag = false; + if (this->browserTabContent != NULL) { + switch (this->browserTabContent->getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + showRemoveVertexSymbolsFlag = true; + break; + } + } + if (showRemoveVertexSymbolsFlag) { + if (this->actions().count() > 0) { + this->addSeparator(); + } + this->addAction("Remove All Vertex Identification Symbols", + this, + SLOT(removeAllNodeIdentificationSymbolsSelected())); } - this->addAction("Remove All Vertex Identification Symbols", - this, - SLOT(removeAllNodeIdentificationSymbolsSelected())); if (idSymbol->isValid()) { const AString text = ("Remove Identification of Vertices " @@ -644,6 +679,57 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() true); } +/** + * Add chart options to the menu + */ +void +UserInputModeViewContextMenu::addChartActions() +{ + QList chartActions; + + SelectionItemChartTwoLabel* labelID = this->selectionManager->getChartTwoLabelIdentification(); + if (labelID->isValid()) { + chartActions.push_back(WuQtUtilities::createAction("Edit Chart Axis Label...", + "", + this, + this, + SLOT(editChartLabelSelected()))); + } + + addActionsToMenu(chartActions, true); +} + +/** + * Called to edit the chart label. + */ +void +UserInputModeViewContextMenu::editChartLabelSelected() +{ + SelectionItemChartTwoLabel* labelID = this->selectionManager->getChartTwoLabelIdentification(); + if (labelID->isValid()) { + ChartTwoCartesianAxis* axis = labelID->getChartTwoCartesianAxis(); + ChartTwoOverlaySet* chartOverlaySet = labelID->getChartOverlaySet(); + if ((axis != NULL) + && (chartOverlaySet != NULL)) { + WuQDataEntryDialog newNameDialog("Axis Label", + this); + QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); + lineEdit->setText(chartOverlaySet->getAxisLabel(axis)); + if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { + const AString name = lineEdit->text().trimmed(); + chartOverlaySet->setAxisLabel(axis, + name); + + /* + * Update graphics. + */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + } + } +} + /** * Add the foci options to the menu. */ diff --git a/src/GuiQt/UserInputModeViewContextMenu.h b/src/GuiQt/UserInputModeViewContextMenu.h index 0fc744c8f..d92c209f6 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.h +++ b/src/GuiQt/UserInputModeViewContextMenu.h @@ -90,6 +90,8 @@ namespace caret { void borderDataSeriesSelected(); + void editChartLabelSelected(); + private: class ParcelConnectivity { public: @@ -144,6 +146,8 @@ namespace caret { void addBorderRegionOfInterestActions(); + void addChartActions(); + void addFociActions(); void addLabelRegionOfInterestActions(); -- GitLab From a027c7234c6de7c402d602ccfdfd94f1c153c6f1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 25 Aug 2017 14:51:52 -0500 Subject: [PATCH 362/755] Add new WuQDoubleSpinBox which encapsulates a QDoubleSpinBox so that 'digits right of decimal' can be automatically set and so that the 'increment' can be set as a percentage of the data range instead of a fixed value. Use the new WuQDoubleSpinBox in the Toolbar's Chart Axes and Title sections. --- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 50 +- .../BrainBrowserWindowToolBarChartTwoAxes.h | 13 +- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 18 +- .../BrainBrowserWindowToolBarChartTwoTitle.h | 6 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/WuQDoubleSpinBox.cxx | 571 ++++++++++++++++++ src/GuiQt/WuQDoubleSpinBox.h | 174 ++++++ src/GuiQt/WuQWidget.cxx | 32 + src/GuiQt/WuQWidget.h | 4 + 9 files changed, 830 insertions(+), 41 deletions(-) create mode 100644 src/GuiQt/WuQDoubleSpinBox.cxx create mode 100644 src/GuiQt/WuQDoubleSpinBox.h diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 7013aab58..beafe21e6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -54,6 +54,7 @@ #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" +#include "WuQDoubleSpinBox.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" @@ -131,14 +132,17 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_autoUserRangeComboBox->getWidget()->setToolTip("Choose auto or user axis range scaling"); - const double bigValue = 999999.0; - m_userMinimumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); - QObject::connect(m_userMinimumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_userMinimumValueSpinBox = new WuQDoubleSpinBox(this); + m_userMinimumValueSpinBox->setDecimalsModeAuto(); + m_userMinimumValueSpinBox->setSingleStepPercentage(1.0); + QObject::connect(m_userMinimumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged); m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); - m_userMaximumValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigValue, bigValue, 1.0, 1); - QObject::connect(m_userMaximumValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_userMaximumValueSpinBox = new WuQDoubleSpinBox(this); + m_userMaximumValueSpinBox->setDecimalsModeAuto(); + m_userMaximumValueSpinBox->setSingleStepPercentage(1.0); + QObject::connect(m_userMaximumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); @@ -170,27 +174,27 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra /* * Size spin boxes */ - m_labelSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_labelSizeSpinBox->setSuffix("%"); - QObject::connect(m_labelSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_labelSizeSpinBox = new WuQDoubleSpinBox(this); + m_labelSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + QObject::connect(m_labelSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); - m_numericsSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_numericsSizeSpinBox->setSuffix("%"); - QObject::connect(m_numericsSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_numericsSizeSpinBox = new WuQDoubleSpinBox(this); + m_numericsSizeSpinBox->copySettings(m_labelSizeSpinBox); + QObject::connect(m_numericsSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); - m_linesTicksSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_linesTicksSizeSpinBox->setSuffix("%"); - QObject::connect(m_linesTicksSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); + m_linesTicksSizeSpinBox->copySettings(m_labelSizeSpinBox); + QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); - m_paddingSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_paddingSizeSpinBox->setSuffix("%"); - QObject::connect(m_paddingSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); + m_paddingSizeSpinBox->copySettings(m_labelSizeSpinBox); + QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); @@ -224,16 +228,16 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra WuQtUtilities::setLayoutSpacingAndMargins(sizesLayout, 3, 0); int32_t sizesRow = 0; sizesLayout->addWidget(new QLabel("Label"), sizesRow, 0); - sizesLayout->addWidget(m_labelSizeSpinBox, sizesRow, 1); + sizesLayout->addWidget(m_labelSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Scale"), sizesRow, 0); - sizesLayout->addWidget(m_numericsSizeSpinBox, sizesRow, 1); + sizesLayout->addWidget(m_numericsSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Pad"), sizesRow, 0); - sizesLayout->addWidget(m_paddingSizeSpinBox, sizesRow, 1); + sizesLayout->addWidget(m_paddingSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Lines"), sizesRow, 0); - sizesLayout->addWidget(m_linesTicksSizeSpinBox, sizesRow, 1); + sizesLayout->addWidget(m_linesTicksSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; /* @@ -268,10 +272,10 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_userMinimumValueSpinBox->setFixedWidth(90); m_userMaximumValueSpinBox->setFixedWidth(90); rangeLayout->addWidget(new QLabel("Max"), rangeRow, 0); - rangeLayout->addWidget(m_userMaximumValueSpinBox, rangeRow, 1); + rangeLayout->addWidget(m_userMaximumValueSpinBox->getWidget(), rangeRow, 1); rangeRow++; rangeLayout->addWidget(new QLabel("Min"), rangeRow, 0); - rangeLayout->addWidget(m_userMinimumValueSpinBox, rangeRow, 1); + rangeLayout->addWidget(m_userMinimumValueSpinBox->getWidget(), rangeRow, 1); /* * Numerics widgets layout diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index a63bf0a3d..d74533be9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -39,6 +39,7 @@ namespace caret { class ChartTwoCartesianAxisWidget; class ChartTwoOverlaySet; class EnumComboBoxTemplate; + class WuQDoubleSpinBox; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarChartTwoAxes : public BrainBrowserWindowToolBarComponent { @@ -100,9 +101,9 @@ namespace caret { EnumComboBoxTemplate* m_autoUserRangeComboBox; - QDoubleSpinBox* m_userMinimumValueSpinBox; + WuQDoubleSpinBox* m_userMinimumValueSpinBox; - QDoubleSpinBox* m_userMaximumValueSpinBox; + WuQDoubleSpinBox* m_userMaximumValueSpinBox; QCheckBox* m_showTickMarksCheckBox; @@ -116,13 +117,13 @@ namespace caret { QSpinBox* m_userSubdivisionsSpinBox; - QDoubleSpinBox* m_labelSizeSpinBox; + WuQDoubleSpinBox* m_labelSizeSpinBox; - QDoubleSpinBox* m_numericsSizeSpinBox; + WuQDoubleSpinBox* m_numericsSizeSpinBox; - QDoubleSpinBox* m_linesTicksSizeSpinBox; + WuQDoubleSpinBox* m_linesTicksSizeSpinBox; - QDoubleSpinBox* m_paddingSizeSpinBox; + WuQDoubleSpinBox* m_paddingSizeSpinBox; ChartTwoOverlaySet* m_chartOverlaySet; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 5ba333707..63bc8a1d2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -24,7 +24,6 @@ #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ #include -#include #include #include #include @@ -39,6 +38,7 @@ #include "ChartTwoTitle.h" #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" +#include "WuQDoubleSpinBox.h" #include "WuQtUtilities.h" using namespace caret; @@ -71,15 +71,15 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B WuQtUtilities::setToolButtonStyleForQt5Mac(editTitleToolButton); editTitleToolButton->setDefaultAction(editTitleAction); - m_titleSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_titleSizeSpinBox->setSuffix("%"); - QObject::connect(m_titleSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_titleSizeSpinBox = new WuQDoubleSpinBox(this); + m_titleSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + QObject::connect(m_titleSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); - m_paddingSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(0.0, 100.0, 1.0, 1); - m_paddingSizeSpinBox->setSuffix("%"); - QObject::connect(m_paddingSizeSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); + m_paddingSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); @@ -89,10 +89,10 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B layout->addWidget(m_showTitleCheckBox, row, 0, 1, 2, Qt::AlignHCenter); row++; layout->addWidget(new QLabel("Size"), row, 0); - layout->addWidget(m_titleSizeSpinBox, row, 1); + layout->addWidget(m_titleSizeSpinBox->getWidget(), row, 1); row++; layout->addWidget(new QLabel("Pad"), row, 0); - layout->addWidget(m_paddingSizeSpinBox, row, 1); + layout->addWidget(m_paddingSizeSpinBox->getWidget(), row, 1); row++; layout->addWidget(editTitleToolButton, row, 0, 1, 2, Qt::AlignHCenter); row++; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h index 40a962639..9bd0379c5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h @@ -25,11 +25,11 @@ #include "BrainBrowserWindowToolBarComponent.h" class QCheckBox; -class QDoubleSpinBox; namespace caret { class ChartTwoOverlaySet; + class WuQDoubleSpinBox; class BrainBrowserWindowToolBarChartTwoTitle : public BrainBrowserWindowToolBarComponent { Q_OBJECT @@ -57,9 +57,9 @@ namespace caret { QCheckBox* m_showTitleCheckBox; - QDoubleSpinBox* m_titleSizeSpinBox; + WuQDoubleSpinBox* m_titleSizeSpinBox; - QDoubleSpinBox* m_paddingSizeSpinBox; + WuQDoubleSpinBox* m_paddingSizeSpinBox; ChartTwoOverlaySet* m_chartOverlaySet; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 96aa198e6..19ac8ffbf 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -185,6 +185,7 @@ ELSE() WuQDialogModal.h WuQDialogNonModal.h WuQDoubleSlider.h + WuQDoubleSpinBox.h WuQEventBlockingFilter.h WuQGridLayoutGroup.h WuQGroupBoxExclusiveWidget.h @@ -411,6 +412,7 @@ WuQDialog.h WuQDialogModal.h WuQDialogNonModal.h WuQDoubleSlider.h +WuQDoubleSpinBox.h WuQEventBlockingFilter.h WuQFactory.h WuQGridLayoutGroup.h @@ -623,6 +625,7 @@ WuQDialog.cxx WuQDialogModal.cxx WuQDialogNonModal.cxx WuQDoubleSlider.cxx +WuQDoubleSpinBox.cxx WuQEventBlockingFilter.cxx WuQFactory.cxx WuQGridLayoutGroup.cxx diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx new file mode 100644 index 000000000..68c5a7953 --- /dev/null +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -0,0 +1,571 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ +#include "WuQDoubleSpinBox.h" +#undef __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ + +#include +#include + +#include + +#include "AString.h" +#include "CaretAssert.h" + +using namespace caret; + +/** + * \class caret::WuQDoubleSpinBox + * \brief Customizable double spin box + * \ingroup GuiQt + * + * An 'extension' of QDoubleSpinBox. There are methods in + * QDoubleSpinBox that we would like to override but the methods + * are not virtual. So, extend WuQWidget (which extends QObject), + * encapsulate QDoubleSpinbox, and implement needed methods. + * + * Two added features are: + * (1) Ability to automatically compute digits right of decimal + * based upon the range of the data. + * (2) Ablity to set increment/decrement values as a percentage + * of the range of data. + * + * Unlike QDoubleSpinBox, the valueChanged() signal DOES NOT get + * emitted when setValue() is called. + */ + +/** + * Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, + * a step value of 1.0 and a precision of 2 decimal places. + * The value is initially set to 0.00. The spin box has the given parent. + * + * @param parent + * The parent widget. + */ +WuQDoubleSpinBox::WuQDoubleSpinBox(QWidget* parent) +: WuQWidget(parent), +m_decimalsMode(DecimalsMode::DECIMALS_FIXED), +m_singleStepMode(SingleStepMode::SINGLE_STEP_FIXED) +{ + /* + * Create the spin box and initialize it + */ + m_spinBox = new QDoubleSpinBox(); + m_spinBox->setRange(0.0, 99.99); + m_spinBox->setSingleStep(1.0); + m_spinBox->setDecimals(2); + m_spinBox->setValue(0.0); + + QObject::connect(m_spinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &WuQDoubleSpinBox::valueChangedPrivate); +} + +/** + * Destructor. + */ +WuQDoubleSpinBox::~WuQDoubleSpinBox() +{ +} + +/** + * @return The encapsulated widget. Usually used to + * add the widget to a layout. + */ +QWidget* +WuQDoubleSpinBox::getWidget() +{ + return m_spinBox; +} + +/** + * Setup for percentage values. Percentage range + * [0.0, 100], with 2 digits right of decimal, + * a single step of 0.1, and a '%' suffix. + * + * @param minimumPercentage + * Minimum percentage (must be in range [0.0, 100.0] + * @param maximumPercentage + * Maximum percentage (must be in range [0.0, 100.0] + */ +void +WuQDoubleSpinBox::setupForPercentage(const double minimumPercentage, + const double maximumPercentage) +{ + setRange(minimumPercentage, + maximumPercentage); + setDecimals(2); + setSingleStepPercentage(0.1); + setSuffix("%"); +} + +/** + * Copy all setting from the given spin box + * + * @param copyFromSpinBox + * Spinbox from which settings are copied to 'this' instance + */ +void +WuQDoubleSpinBox::copySettings(const WuQDoubleSpinBox* copyFromSpinBox) +{ + CaretAssert(copyFromSpinBox); + + setRange(copyFromSpinBox->minimum(), copyFromSpinBox->maximum()); + m_decimalsMode = copyFromSpinBox->m_decimalsMode; + switch (copyFromSpinBox->m_decimalsMode) { + case DecimalsMode::DECIMALS_AUTO: + setDecimalsModeAuto(); + break; + case DecimalsMode::DECIMALS_FIXED: + setDecimals(copyFromSpinBox->decimals()); + break; + } + + setPrefix(copyFromSpinBox->prefix()); + setSuffix(copyFromSpinBox->suffix()); + + setSingleStep(copyFromSpinBox->singleStep()); + m_singleStepPercentage = copyFromSpinBox->m_singleStepPercentage; + m_singleStepMode = copyFromSpinBox->m_singleStepMode; + switch (m_singleStepMode) { + case SingleStepMode::SINGLE_STEP_FIXED: + break; + case SingleStepMode::SINGLE_STEP_PERCENTAGE: + setSingleStepPercentage(copyFromSpinBox->singleStepPercentage()); + break; + } + + + +} + + +///** +// * Explicit conversion to QWidget +// */ +//WuQDoubleSpinBox::operator +//QWidget*() const +//{ +// return m_spinBox; +//} + +/** + * @return The decimals mode. + */ +WuQDoubleSpinBox::DecimalsMode +WuQDoubleSpinBox::decimalsMode() const +{ + return m_decimalsMode; +} + +/** + * Set the decimals mode to auto. To exit auto use setDecimals(int). + */ +void +WuQDoubleSpinBox::setDecimalsModeAuto() +{ + m_decimalsMode = DecimalsMode::DECIMALS_AUTO; + updateDecimalsForAutoMode(); +} + +/** + * @return Digits right of decimal point + */ +int +WuQDoubleSpinBox::decimals() const +{ + return m_spinBox->decimals(); +} + +/** + * Sets fixed number of decimals the spinbox will use for displaying and interpreting doubles. + * + * Also sets the DecimalMode to a fixed number of digits right of the decimal. + * + * @param prec + * Number of digits right of decimal + */ +void +WuQDoubleSpinBox::setDecimals(int prec) +{ + m_decimalsMode = DecimalsMode::DECIMALS_FIXED; + m_spinBox->setDecimals(prec); +} + +/** + * Compute the number of digits right of the decimal point for + * the given range of data. + * + * @param range + * Range of the data. + * @return + * Number of digits right of decimal point. + */ +int32_t +WuQDoubleSpinBox::computeDigitsRightOfDecimal(const double dataRange) +{ + const double range = ((dataRange >=0) ? dataRange : -dataRange); + + int32_t numDecimals = 3; + if (range > 0.0) { + int32_t logValue = static_cast(std::log10(range)); + + if (logValue == 0) { + numDecimals = 3; + } + else if (logValue > 0) { // range > 1 + numDecimals = 4 - logValue; + } + else if (logValue < 0) { // 0 < range < 1 + numDecimals = 3 - logValue; + } + + if (numDecimals < 1) { + numDecimals = 1; + } + else if (numDecimals > 15) { + numDecimals = 15; + } + } + + return numDecimals; +} + +/** + * Used for testing computation of digits right of decimal point. + */ +void +WuQDoubleSpinBox::testDigitsRightOfDecimal() +{ + { + const double value = 0.0; + const int32_t decimals = computeDigitsRightOfDecimal(value); + AString s = QString("Range: %1 decimals: %2").arg(value, 10).arg(decimals, 5); + std::cout << s << std::endl; + } + + for (int32_t exponent = -10; exponent <= 10; exponent++) { + const double value = std::pow(10.0, exponent); + const int32_t decimals = computeDigitsRightOfDecimal(value); + AString s = QString("Range: %1 decimals: %2 lo10: %3").arg(value, 10).arg(decimals, 5).arg((int)std::log10(value)); + std::cout << s << std::endl; + } + std::cout << std::endl << std::endl; +} + +/** + * Update the decimals for AUTO mode + */ +void +WuQDoubleSpinBox::updateDecimalsForAutoMode() +{ + static bool decimalsTestFlag = false; + if (decimalsTestFlag) { + testDigitsRightOfDecimal(); + decimalsTestFlag = false; + } + + switch (m_decimalsMode) { + case DecimalsMode::DECIMALS_AUTO: + m_spinBox->setDecimals(computeDigitsRightOfDecimal(m_spinBox->maximum() + - m_spinBox->minimum())); + break; + case DecimalsMode::DECIMALS_FIXED: + break; + } +} + +/** + * @return Minimum displayed value. + */ +double +WuQDoubleSpinBox::minimum() const +{ + return m_spinBox->minimum(); +} + +/** + * @return Maximum displayed value. + */ +double +WuQDoubleSpinBox::maximum() const +{ + return m_spinBox->maximum(); +} + +/** + * Sets the maximum value displayed in the spin box. + * + * @param max + * New maximum value. + */ +void +WuQDoubleSpinBox::setMaximum(double max) +{ + m_spinBox->setMaximum(max); + updateDecimalsForAutoMode(); + updateSingleStepPercentage(); +} + +/** + * Sets the minimum value displayed in the spin box. + * + * @param min + * New minimum value. + */ +void +WuQDoubleSpinBox::setMinimum(double min) +{ + m_spinBox->setMinimum(min); + updateDecimalsForAutoMode(); + updateSingleStepPercentage(); +} + +/** + * @return Prefix prepended to start of displayed value. + */ +QString +WuQDoubleSpinBox::prefix() const +{ + return m_spinBox->prefix(); +} + +/** + * Set the prefix is prepended to the start of the displayed value. + * Typical use is to display a unit of measurement or a currency symbol. + * + * @param prefix + * New prefix + */ +void +WuQDoubleSpinBox::setPrefix(const QString &prefix) +{ + m_spinBox->setPrefix(prefix); +} + +/** + * Convenience function to set the minimum and maximum values with a single function call. + * + * @param minimum + * New minimum value. + * @param maximum + * New maximum value. + */ +void +WuQDoubleSpinBox::setRange(double minimum, double maximum) +{ + m_spinBox->setRange(minimum, maximum); + updateDecimalsForAutoMode(); + updateSingleStepPercentage(); +} + +/** + * Set the step value. When the user uses the arrows to change the + * spin box's value the value will be incremented/decremented by the + * amount of the given value. + * + * NOTE: When this method is called, the SingleStepMode is set + * to SINGLE_STEP_FIXED + * + * @param value + * New step value. + */ +void +WuQDoubleSpinBox::setSingleStep(double value) +{ + CaretAssert(value >= 0.0); + + m_spinBox->setSingleStep(value); + m_singleStepMode = SingleStepMode::SINGLE_STEP_FIXED; +} + +/** + * Set the step value. When the user uses the arrows to change the + * spin box's value the value will be incremented/decremented by a + * percentage of the minimum and maximum values. + * + * NOTE: When this method is called, the SingleStepMode is set + * to SINGLE_STEP_PERCENTAGE. + * + * @param percentage + * The step percentage that ranges (0.0, 100.0]. + */ +void +WuQDoubleSpinBox::setSingleStepPercentage(double percentage) +{ + CaretAssert(percentage > 0.0); + CaretAssert(percentage <= 100.0); + + m_singleStepPercentage = percentage; + m_singleStepMode = SingleStepMode::SINGLE_STEP_PERCENTAGE; + + updateSingleStepPercentage(); +} + +/** + * Update the single step percentage when the minimum value, + * maximum value, or step percentage is changed. + */ +void +WuQDoubleSpinBox::updateSingleStepPercentage() +{ + switch (m_singleStepMode) { + case SingleStepMode::SINGLE_STEP_FIXED: + break; + case SingleStepMode::SINGLE_STEP_PERCENTAGE: + { + const double minValue = m_spinBox->minimum(); + const double maxValue = m_spinBox->maximum(); + const double dataRange = maxValue - minValue; + + double stepValue = 0.0; + if (dataRange > 0.0) { + stepValue = dataRange * (m_singleStepPercentage / 100.0); + } + + m_spinBox->setSingleStep(stepValue); + } + break; + } +} + +/** + * Set the suffix is append to the start of the displayed value. + * Typical use is to display a unit of measurement or a currency symbol. + * + * @param suffix + * New suffix + */ +void +WuQDoubleSpinBox::setSuffix(const QString &suffix) +{ + m_spinBox->setSuffix(suffix); +} + +/** + * @return The single step value. + */ +double +WuQDoubleSpinBox::singleStep() const +{ + return m_spinBox->singleStep(); +} + +/** + * @return The single step mode. + */ +WuQDoubleSpinBox::SingleStepMode +WuQDoubleSpinBox::singleStepMode() const +{ + return m_singleStepMode; +} + +/** + * @return The single step percentage value. + */ +double +WuQDoubleSpinBox::singleStepPercentage() const +{ + return m_singleStepPercentage; +} + +/** + * @return The suffix. + */ +QString +WuQDoubleSpinBox::suffix() const +{ + return m_spinBox->suffix(); +} + +/** + * This virtual function is used by the spin box whenever it needs to + * display the given value. The default implementation returns a + * string containing value printed using QWidget::locale().toString(value, QLatin1Char('f'), + * decimals()) and will remove the thousand separator unless setGroupSeparatorShown() is set. + * Reimplementations may return anything. + * + * @return Text representation of current value. + */ +QString +WuQDoubleSpinBox::textFromValue(double value) const +{ + return m_spinBox->textFromValue(value); +} + +/** + * @return Current value as double. + */ +double +WuQDoubleSpinBox::value() const +{ + return m_spinBox->value(); +} + +/** + * This virtual function is used by the spin box whenever it needs to + * interpret text entered by the user as a value. + * Subclasses that need to display spin box values in a non-numeric way + * need to reimplement this function. + * + * @return double value from the given text value. + */ +double +WuQDoubleSpinBox::valueFromText(const QString &text) const +{ + return m_spinBox->valueFromText(text); +} + + +/** + * Slot to set the value. Unlike QDoubleSpinBox::setValue() + * this method DOES NOT cause the valueChanged() signal to + * be emitted. + * + * @param val + * New value for spin box. + */ +void WuQDoubleSpinBox::setValue(double val) +{ + QSignalBlocker blocker(m_spinBox); + m_spinBox->setValue(val); +} + +/** + * Called when the enapsulated spin box's value changed signal is emitted. + * Use 'this' instance of signal blocking to prevent a signal from + * being emitted. This allows user to use WuQDoubleSpinBox::blockSignals(). + * + * @param d + * Value contained in the spin box. + */ +void +WuQDoubleSpinBox::valueChangedPrivate(double d) +{ + if (signalsBlocked()) { + return; + } + + emit valueChanged(d); +} + +// ADD_NEW_METHODS_HERE + diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h new file mode 100644 index 000000000..a648816fb --- /dev/null +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -0,0 +1,174 @@ +#ifndef __WU_Q_DOUBLE_SPIN_BOX_H__ +#define __WU_Q_DOUBLE_SPIN_BOX_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQWidget.h" + +class QDoubleSpinBox; + +namespace caret { + + class WuQDoubleSpinBox : public WuQWidget { + + Q_OBJECT + + public: + /** + * Mode for decimals (digits right of decimal) + */ + enum class DecimalsMode { + /** + * Number of decimals is calculated from the range of data + */ + DECIMALS_AUTO, + /** + * Number of decimals is fixed by calling setDecimals(int) + * (Normal spin box functionality) + */ + DECIMALS_FIXED + }; + + /** + * Mode for single step (increment/decrement) arrows + */ + enum class SingleStepMode { + /** + * Step by a fixed amount (normal spin box functionality) + */ + SINGLE_STEP_FIXED, + /** + * Step by a percenage of data range + */ + SINGLE_STEP_PERCENTAGE + }; + + WuQDoubleSpinBox(QWidget* parent); + + virtual ~WuQDoubleSpinBox(); + + virtual QWidget* getWidget(); + + void setupForPercentage(const double minimumPercentage, + const double maximumPercentage); + + void copySettings(const WuQDoubleSpinBox* copyFromSpinBox); + + QString cleanText() const; + + int decimals() const; + + double maximum() const; + + double minimum() const; + + QString prefix() const; + + DecimalsMode decimalsMode() const; + + void setDecimals(int prec); + + void setDecimalsModeAuto(); + + void setMaximum(double max); + + void setMinimum(double min); + + void setPrefix(const QString &prefix); + + void setRange(double minimum, double maximum); + + void setSingleStep(double value); + + void setSingleStepPercentage(double percentage); + + void setSuffix(const QString &suffix); + + double singleStep() const; + + SingleStepMode singleStepMode() const; + + double singleStepPercentage() const; + + QString suffix() const; + + virtual QString textFromValue(double value) const; + + double value() const; + + virtual double valueFromText(const QString &text) const; + + // ADD_NEW_METHODS_HERE + + public slots: + void setValue(double val); + + signals: + /** + * This signal is emitted when the value changes. + * + * Example of signal connection: + * QObject::connect(m_spinBox, static_cast(&QDoubleSpinBox::valueChanged), + * this, &WuQDoubleSpinBox::valueChanged); + * + * @param d + * New value. + */ + void valueChanged(double d); + + private slots: + void valueChangedPrivate(double d); + + private: + WuQDoubleSpinBox(const WuQDoubleSpinBox&); + + WuQDoubleSpinBox& operator=(const WuQDoubleSpinBox&); + + void updateSingleStepPercentage(); + + void updateDecimalsForAutoMode(); + + int32_t computeDigitsRightOfDecimal(const double dataRange); + + void testDigitsRightOfDecimal(); + + QDoubleSpinBox* m_spinBox; + + DecimalsMode m_decimalsMode = DecimalsMode::DECIMALS_FIXED; + + SingleStepMode m_singleStepMode = SingleStepMode::SINGLE_STEP_FIXED; + + double m_singleStepPercentage = 1.0; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ + // +#endif // __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ + +} // namespace +#endif //__WU_Q_DOUBLE_SPIN_BOX_H__ diff --git a/src/GuiQt/WuQWidget.cxx b/src/GuiQt/WuQWidget.cxx index d49fb4b42..d67959567 100644 --- a/src/GuiQt/WuQWidget.cxx +++ b/src/GuiQt/WuQWidget.cxx @@ -23,6 +23,8 @@ #include "WuQWidget.h" #undef __WU_Q_WIDGET_DECLARE__ +#include + #include "CaretAssert.h" using namespace caret; @@ -67,6 +69,7 @@ using namespace caret; * which will destroy it. */ + /** * Constructor. */ @@ -83,5 +86,34 @@ WuQWidget::~WuQWidget() { } +/** + * Sets both the minimum and maximum width of the widget to w without changing the heights. + * + * @param width + * Width value. + */ +void +WuQWidget::setFixedWidth(int width) +{ + QWidget* widget = getWidget(); + CaretAssert(widget); + widget->setFixedWidth(width); +} + + +/** + * Set the tooltip for this spin box. + * + * @param tooltip + * Text for the tooltip. + */ +void +WuQWidget::setToolTip(const QString& tooltip) +{ + QWidget* widget = getWidget(); + CaretAssert(widget); + widget->setToolTip(tooltip); +} + diff --git a/src/GuiQt/WuQWidget.h b/src/GuiQt/WuQWidget.h index bec83b30f..08e6c14ed 100644 --- a/src/GuiQt/WuQWidget.h +++ b/src/GuiQt/WuQWidget.h @@ -39,6 +39,10 @@ namespace caret { virtual QWidget* getWidget() = 0; + void setToolTip(const QString& tooltip); + + void setFixedWidth(int w); + private: WuQWidget(const WuQWidget&); -- GitLab From db00fdee780c53e21ce101803cee705b729bdcba Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 29 Aug 2017 12:14:12 -0500 Subject: [PATCH 363/755] Improvements to WuQDoubleSpinBox for setting range of data. Helps to resolve WB-719, WB-708, and others. --- src/Brain/ChartTwoOverlay.cxx | 69 +++++ src/Brain/ChartTwoOverlay.h | 3 + src/Brain/ChartTwoOverlaySet.cxx | 258 ++++++++++++------ src/Brain/ChartTwoOverlaySet.h | 11 + src/Charting/CMakeLists.txt | 2 + src/Charting/ChartTwoCartesianAxis.cxx | 76 +++--- src/Charting/ChartTwoCartesianAxis.h | 21 +- src/Charting/ChartTwoLineSeriesHistory.cxx | 36 +++ src/Charting/ChartTwoLineSeriesHistory.h | 3 + .../EventChartTwoAxisGetDataRange.cxx | 111 ++++++++ src/Charting/EventChartTwoAxisGetDataRange.h | 79 ++++++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 17 +- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 4 +- src/GuiQt/WuQDoubleSpinBox.cxx | 252 +++++++++++------ src/GuiQt/WuQDoubleSpinBox.h | 49 +++- 18 files changed, 743 insertions(+), 255 deletions(-) create mode 100644 src/Charting/EventChartTwoAxisGetDataRange.cxx create mode 100644 src/Charting/EventChartTwoAxisGetDataRange.h diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 17f4cc4b3..c1fa00a2f 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -24,6 +24,7 @@ #undef __CHART_TWO_OVERLAY_DECLARE__ #include "AnnotationColorBar.h" +#include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" @@ -36,6 +37,7 @@ #include "EventCaretMappableDataFilesGet.h" #include "EventChartOverlayValidate.h" #include "EventManager.h" +#include "Histogram.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -508,6 +510,73 @@ ChartTwoOverlay::getColorBar() const return m_colorBar.get(); } +/** + * Get a bounding box for data displayed within this overlay. + * Bounds are provided for histogram and line-series charts only. + * + * @param boundingBox + * Upon exit contains bounds for data within this overlay + * @return + * True if the bounds are valid, else false. + */ +bool +ChartTwoOverlay::getBounds(BoundingBox& boundingBoxOut) const +{ + boundingBoxOut.resetForUpdate(); + + if ( ! isEnabled()) { + return false; + } + + CaretMappableDataFile* mapFile = NULL; + SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + + if (mapFile == NULL) { + return false; + } + + ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); + + bool validFlag = false; + + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + { + ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); + const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, + (isAllMapsSupported() + && isAllMapsSelected())); + CaretAssert(histogram); + float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; + histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); + if (histogramMaxX > histogramMinX) { + boundingBoxOut.set(histogramMinX, histogramMaxX, + 0.0f, histogramMaxY, + 0.0f, 0.0f); + validFlag = true; + } + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { + const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); + const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); + validFlag = lineSeriesHistory->getBounds(boundingBoxOut); + } + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + return validFlag; +} + /** * @return The selected map file (NULL if not map file available) */ diff --git a/src/Brain/ChartTwoOverlay.h b/src/Brain/ChartTwoOverlay.h index 6eba54f0e..8c429f844 100644 --- a/src/Brain/ChartTwoOverlay.h +++ b/src/Brain/ChartTwoOverlay.h @@ -34,6 +34,7 @@ namespace caret { class AnnotationColorBar; + class BoundingBox; class CaretMappableDataFile; class ChartTwoOverlaySet; class PlainTextStringBuilder; @@ -132,6 +133,8 @@ namespace caret { void setAllMapsSelected(const bool status); + bool getBounds(BoundingBox& boundingBoxOut) const; + virtual void receiveEvent(Event* event); // ADD_NEW_METHODS_HERE diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 88330a164..286ba844f 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -24,6 +24,7 @@ #undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "AnnotationPercentSizeText.h" +#include "BoundingBox.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" @@ -36,6 +37,7 @@ #include "EventAnnotationChartLabelGet.h" #include "EventBrowserTabGet.h" #include "EventChartTwoAttributesChanged.h" +#include "EventChartTwoAxisGetDataRange.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" @@ -76,9 +78,9 @@ m_tabIndex(tabIndex) { m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; - m_chartAxisLeft = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT)); - m_chartAxisRight = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT)); - m_chartAxisBottom = std::unique_ptr(new ChartTwoCartesianAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); + m_chartAxisLeft = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT)); + m_chartAxisRight = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT)); + m_chartAxisBottom = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); m_chartAxisLeft->setEnabledByChart(false); m_chartAxisRight->setEnabledByChart(false); @@ -90,16 +92,9 @@ m_tabIndex(tabIndex) { m_chartAxisLeft->setEnabledByChart(true); m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); - float rangeMin = 0.0, rangeMax = 0.0; - m_chartAxisLeft->getRange(rangeMin, rangeMax); - rangeMin = 0.0; - m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); - m_chartAxisRight->getRange(rangeMin, rangeMax); - rangeMin = 0.0; - m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); @@ -109,16 +104,9 @@ m_tabIndex(tabIndex) { m_chartAxisLeft->setEnabledByChart(true); m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); - float rangeMin = 0.0, rangeMax = 0.0; - m_chartAxisLeft->getRange(rangeMin, rangeMax); - rangeMin = 0.0; - m_chartAxisLeft->setRange(rangeMin, rangeMax); m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); - m_chartAxisRight->getRange(rangeMin, rangeMax); - rangeMin = 0.0; - m_chartAxisRight->setRange(rangeMin, rangeMax); m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); @@ -162,6 +150,7 @@ m_tabIndex(tabIndex) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } @@ -288,6 +277,44 @@ ChartTwoOverlaySet::getOverlayWeakPointer(const int32_t overlayNumber) return m_overlays[overlayNumber]; } +/** + * @return The displayed overlays which are the overlays + * shown in the Overlay Toolbox and this includes + * overlays that the user may have set to disabled. + */ +std::vector +ChartTwoOverlaySet::getDisplayedOverlays() const +{ + std::vector displayedOverlays; + + const int numOverlays = getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + CaretAssertVectorIndex(m_overlays, i); + displayedOverlays.push_back(m_overlays[i].get()); + } + + return displayedOverlays; +} + +/** + * @return The displayed overlays but only those + * that are enabled by the user. + */ +std::vector +ChartTwoOverlaySet::getEnabledOverlays() const +{ + std::vector enabledOverlays; + + const int numOverlays = getNumberOfDisplayedOverlays(); + for (int32_t i = 0; i < numOverlays; i++) { + CaretAssertVectorIndex(m_overlays, i); + if (m_overlays[i]->isEnabled()) { + enabledOverlays.push_back(m_overlays[i].get()); + } + } + + return enabledOverlays; +} /** * Get a text description of the window's content. @@ -590,6 +617,22 @@ ChartTwoOverlaySet::receiveEvent(Event* event) attributeEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE) { + EventChartTwoAxisGetDataRange* rangeEvent = dynamic_cast(event); + CaretAssert(rangeEvent); + + if (rangeEvent->getChartOverlaySet() == this) { + float minimumValue = 0.0f; + float maximumValue = 0.0f; + if (getDataRangeForAxis(rangeEvent->getChartAxisLocation(), + minimumValue, + maximumValue)) { + rangeEvent->setMinimumAndMaximumValues(minimumValue, + maximumValue); + rangeEvent->setEventProcessed(); + } + } + } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { /* * The events intended for overlays are received here so that @@ -696,91 +739,64 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } /** - * Get the displayed chart axes. + * Get the minimum and maximum values for the given chart axis + * from the ENABLED overlays in this chart overlay set. * - * @param axesOut - * Output containing the displayed axes. + * @param chartAxisLocation + * Location of axis. + * @param minimumValueOut + * Output with minimum value for axis. + * @param maximumValueOut + * Output with maximum value for axis. + * @return + * True if output values are valid, else false. */ -void -ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut) const +bool +ChartTwoOverlaySet::getDataRangeForAxis(const ChartAxisLocationEnum::Enum chartAxisLocation, + float& minimumValueOut, + float& maximumValueOut) const { - axesOut.clear(); - - AString lineSeriesDataTypeName; - - bool showAxesFlag = false; - switch (m_chartDataType) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - showAxesFlag = true; - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - { - const ChartTwoOverlay* primaryOverlay = getPrimaryOverlay(); - if (primaryOverlay != NULL) { - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay::SelectedIndexType indexType; - int32_t mapIndex; - primaryOverlay->getSelectionData(mapFile, indexType, mapIndex); - if (mapFile != NULL) { - const NiftiTimeUnitsEnum::Enum units = mapFile->getMapIntervalUnits(); - switch (units) { - case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: - lineSeriesDataTypeName = "Hertz"; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: - lineSeriesDataTypeName = "milliseconds"; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: - lineSeriesDataTypeName = "parts per million"; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: - lineSeriesDataTypeName = "seconds"; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: - lineSeriesDataTypeName = "data"; - break; - case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: - lineSeriesDataTypeName = "microseconds"; - break; - } - } - } - } - showAxesFlag = true; - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - break; + minimumValueOut = 0.0f; + maximumValueOut = 0.0f; + if ( ! isAxesSupportedByChartDataType()) { + return false; } - - bool showBottomFlag = false; - bool showLeftFlag = false; - bool showRightFlag = false; - if (showAxesFlag) { - for (auto overlay : m_overlays) { - if (overlay->isEnabled()) { - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; - int32_t selectedIndex = -1; - overlay->getSelectionData(mapFile, - selectedIndexType, - selectedIndex); - if (mapFile != NULL) { - showBottomFlag = true; - switch (overlay->getCartesianVerticalAxisLocation()) { + minimumValueOut = std::numeric_limits::max(); + maximumValueOut = -std::numeric_limits::max(); + + std::vector enabledOverlays = getEnabledOverlays(); + for (auto overlay : enabledOverlays) { + if (overlay->isEnabled()) { + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t selectedIndex = -1; + overlay->getSelectionData(mapFile, + selectedIndexType, + selectedIndex); + if (mapFile != NULL) { + BoundingBox boundingBox; + if (overlay->getBounds(boundingBox)) { + switch (chartAxisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - CaretAssert(0); + minimumValueOut = std::min(minimumValueOut, boundingBox.getMinX()); + maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxX()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - showLeftFlag = true; + if (overlay->getCartesianVerticalAxisLocation() == ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT) { + minimumValueOut = std::min(minimumValueOut, boundingBox.getMinY()); + maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxY()); + } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - showRightFlag = true; + if (overlay->getCartesianVerticalAxisLocation() == ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT) { + minimumValueOut = std::min(minimumValueOut, boundingBox.getMinY()); + maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxY()); + } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - CaretAssert(0); + minimumValueOut = std::min(minimumValueOut, boundingBox.getMinX()); + maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxX()); break; } } @@ -788,6 +804,68 @@ ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& a } } + if (minimumValueOut < maximumValueOut) { + return true; + } + + minimumValueOut = 0.0f; + maximumValueOut = 0.0f; + + return false; +} + +/** + * @return Are axes supported by the chart data type for this overlay set? + */ +bool +ChartTwoOverlaySet::isAxesSupportedByChartDataType() const +{ + bool axisSupportedFlag = false; + switch (m_chartDataType) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + axisSupportedFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + axisSupportedFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + return axisSupportedFlag; +} + + +/** + * Get the displayed chart axes. + * + * @param axesOut + * Output containing the displayed axes. + */ +void +ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut) const +{ + axesOut.clear(); + + AString lineSeriesDataTypeName; + + + float xMin = 0.0f; + float xMax = 0.0f; + float yMinLeft = 0.0f; + float yMaxLeft = 0.0f; + float yMinRight = 0.0f; + float yMaxRight = 0.0f; + + bool showBottomFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM, + xMin, xMax); + bool showLeftFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT, + yMinLeft, yMaxLeft); + bool showRightFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT, + yMinRight, yMaxRight); + m_chartAxisBottom->setEnabledByChart(showBottomFlag); m_chartAxisLeft->setEnabledByChart(showLeftFlag); m_chartAxisRight->setEnabledByChart(showRightFlag); diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index 66161de40..c3af52762 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -24,6 +24,7 @@ #include "BrainConstants.h" #include "CaretObject.h" +#include "ChartAxisLocationEnum.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" @@ -61,6 +62,10 @@ namespace caret { std::weak_ptr getOverlayWeakPointer(const int32_t overlayNumber); + std::vector getDisplayedOverlays() const; + + std::vector getEnabledOverlays() const; + void addDisplayedOverlay(); int32_t getNumberOfDisplayedOverlays() const; @@ -74,6 +79,12 @@ namespace caret { void setAxisLabel(const ChartTwoCartesianAxis* axis, const AString& label); + bool isAxesSupportedByChartDataType() const; + + bool getDataRangeForAxis(const ChartAxisLocationEnum::Enum chartAxisLocation, + float& minimumValueOut, + float& maximumValueOut) const; + ChartTwoTitle* getChartTitle(); const ChartTwoTitle* getChartTitle() const; diff --git a/src/Charting/CMakeLists.txt b/src/Charting/CMakeLists.txt index f56400f2f..590b4d2b2 100644 --- a/src/Charting/CMakeLists.txt +++ b/src/Charting/CMakeLists.txt @@ -53,6 +53,7 @@ ChartTwoNumericSubdivisionsModeEnum.h ChartTwoLineSeriesHistory.h ChartTwoTitle.h EventChartTwoAttributesChanged.h +EventChartTwoAxisGetDataRange.h EventChartTwoLoadLineSeriesData.h MapFileDataSelector.h @@ -94,6 +95,7 @@ ChartTwoNumericSubdivisionsModeEnum.cxx ChartTwoLineSeriesHistory.cxx ChartTwoTitle.cxx EventChartTwoAttributesChanged.cxx +EventChartTwoAxisGetDataRange.cxx EventChartTwoLoadLineSeriesData.cxx MapFileDataSelector.cxx ) diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index 0c4866b32..a846a8122 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -26,6 +26,8 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" +#include "EventChartTwoAxisGetDataRange.h" +#include "EventManager.h" #include "MathFunctions.h" #include "NumericTextFormatting.h" #include "SceneClass.h" @@ -46,18 +48,22 @@ using namespace caret; * * @param axisLocation * Location of the axis (left, right, bottom, top) + * @param parentChartOverlaySet + * Parent of this axis. */ -ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum axisLocation) +ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartTwoOverlaySet* parentChartOverlaySet, + const ChartAxisLocationEnum::Enum axisLocation) : CaretObject(), SceneableInterface(), +m_parentChartOverlaySet(parentChartOverlaySet), m_axisLocation(axisLocation) { /* - * Allowable range minimum and maximum - * NOT SAVED TO SCENE + * Note: Parent chart overlay set is used for sending an event + * to the parent to get the range of data. Note that parent + * chart overlay is in 'Brain' module which we have no access. */ - m_rangeMinimumValue = -std::numeric_limits::max(); - m_rangeMaximumValue = std::numeric_limits::max(); + CaretAssert(m_parentChartOverlaySet); m_showTickmarks = true; m_showLabel = true; @@ -149,8 +155,6 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_titleOverlayIndex = obj.m_titleOverlayIndex; m_displayedByUser = obj.m_displayedByUser; - m_rangeMinimumValue = obj.m_rangeMinimumValue; - m_rangeMaximumValue = obj.m_rangeMaximumValue; m_userScaleMinimumValue = obj.m_userScaleMinimumValue; m_userScaleMaximumValue = obj.m_userScaleMaximumValue; m_axisLabelsStepValue = obj.m_axisLabelsStepValue; @@ -198,7 +202,7 @@ ChartTwoCartesianAxis::setDisplayedByUser(const bool displayedByUser) m_displayedByUser = displayedByUser; } /** - * Get the range of values allowed. + * Get the range of data for this axis. * * @param rangeMinimumOut * Minimum value allowed. @@ -206,28 +210,18 @@ ChartTwoCartesianAxis::setDisplayedByUser(const bool displayedByUser) * Maximum value allowed. */ void -ChartTwoCartesianAxis::getRange(float& rangeMinimumOut, - float& rangeMaximumOut) const +ChartTwoCartesianAxis::getDataRange(float& rangeMinimumOut, + float& rangeMaximumOut) const { - rangeMinimumOut = m_rangeMinimumValue; - rangeMaximumOut = m_rangeMaximumValue; -} - -/** - * Set the range of values allowed. - * - * @param rangeMinimum - * Minimum value allowed. - * @param rangeMaximum - * Maximum value allowed. - */ -void -ChartTwoCartesianAxis::setRange(const float rangeMinimum, - const float rangeMaximum) -{ - m_rangeMinimumValue = rangeMinimum; - m_rangeMaximumValue = rangeMaximum; - limitUserScaleMinMaxToValidRange(); + EventChartTwoAxisGetDataRange rangeEvent(m_parentChartOverlaySet, + m_axisLocation); + EventManager::get()->sendEvent(rangeEvent.getPointer()); + + if ( ! rangeEvent.getMinimumAndMaximumValues(rangeMinimumOut, + rangeMaximumOut)) { + rangeMinimumOut = 0.0f; + rangeMaximumOut = 0.0f; + } } /** @@ -236,12 +230,17 @@ ChartTwoCartesianAxis::setRange(const float rangeMinimum, void ChartTwoCartesianAxis::limitUserScaleMinMaxToValidRange() { - m_userScaleMinimumValue = MathFunctions::limitRange(m_userScaleMinimumValue, - m_rangeMinimumValue, - m_rangeMaximumValue); - m_userScaleMaximumValue = MathFunctions::limitRange(m_userScaleMaximumValue, - m_rangeMinimumValue, - m_rangeMaximumValue); +// float minimumValue = 0.0f; +// float maximumValue = 0.0f; +// getDataRange(minimumValue, +// maximumValue); +// +// m_userScaleMinimumValue = MathFunctions::limitRange(m_userScaleMinimumValue, +// minimumValue, +// maximumValue); +// m_userScaleMaximumValue = MathFunctions::limitRange(m_userScaleMaximumValue, +// minimumValue, +// maximumValue); } /** @@ -665,9 +664,6 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, float minValue = minimumValue; float maxValue = maximumValue; - m_rangeMinimumValue = 0.0; - m_rangeMaximumValue = 0.0; - if (maxValue > minValue) { double scaleStep = 0.0; double scaleMin = 0.0; @@ -685,8 +681,8 @@ ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, stepValueOut = scaleStep; digitsRightOfDecimalOut = digitsRightOfDecimal; - m_rangeMinimumValue = minimumOut; - m_rangeMaximumValue = maximumOut; + //m_rangeMinimumValue = minimumOut; + //m_rangeMaximumValue = maximumOut; return true; } diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 1c1f07c8a..f304dfa6e 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -33,12 +33,14 @@ namespace caret { + class ChartTwoOverlaySet; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { public: - ChartTwoCartesianAxis(const ChartAxisLocationEnum::Enum axisLocation); + ChartTwoCartesianAxis(const ChartTwoOverlaySet* parentChartOverlaySet, + const ChartAxisLocationEnum::Enum axisLocation); virtual ~ChartTwoCartesianAxis(); @@ -52,11 +54,8 @@ namespace caret { void setDisplayedByUser(const bool displayed); - void getRange(float& rangeMinimumOut, - float& rangeMaximumOut) const; - - void setRange(const float rangeMinimum, - const float rangeMaximum); + void getDataRange(float& rangeMinimumOut, + float& rangeMaximumOut) const; float getUserScaleMinimumValue() const; @@ -163,15 +162,11 @@ namespace caret { void limitUserScaleMinMaxToValidRange(); - std::unique_ptr m_sceneAssistant; - - const ChartAxisLocationEnum::Enum m_axisLocation; + const ChartTwoOverlaySet* m_parentChartOverlaySet; - /** Allowable range minimum NOT SAVED TO SCENE */ - mutable float m_rangeMinimumValue = 0.0f; + const ChartAxisLocationEnum::Enum m_axisLocation; - /** Allowable range maximum NOT SAVED TO SCENE */ - mutable float m_rangeMaximumValue = 1.0f; + std::unique_ptr m_sceneAssistant; mutable float m_userScaleMinimumValue = -100.0f; diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 665359bea..18ae26753 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -23,6 +23,7 @@ #include "ChartTwoLineSeriesHistory.h" #undef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ +#include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartTwoDataCartesian.h" @@ -462,6 +463,41 @@ ChartTwoLineSeriesHistory::clearModified() } } +/** + * Get a bounding box for data displayed within this overlay. + * Bounds are provided for histogram and line-series charts only. + * + * @param boundingBox + * Upon exit contains bounds for data within this overlay + * @return + * True if the bounds are valid, else false. + */ +bool +ChartTwoLineSeriesHistory::getBounds(BoundingBox& boundingBoxOut) const +{ + boundingBoxOut.resetForUpdate(); + + bool validFlag = false; + + for (const auto data : m_chartHistory) { + CaretAssert(data); + if (data->isSelected()) { + BoundingBox boundingBox; + if (data->getBounds(boundingBox)) { + boundingBoxOut.update(boundingBox.getMinX(), + boundingBox.getMinY(), + boundingBox.getMinZ()); + boundingBoxOut.update(boundingBox.getMaxX(), + boundingBox.getMaxY(), + boundingBox.getMaxZ()); + validFlag = true; + } + } + } + + return validFlag; +} + /** * Save information specific to this type of model to the scene. * diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 6e7c5f42f..85dae1813 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -31,6 +31,7 @@ namespace caret { + class BoundingBox; class ChartTwoDataCartesian; class SceneClassAssistant; @@ -73,6 +74,8 @@ namespace caret { void clearHistory(); + bool getBounds(BoundingBox& boundingBoxOut) const; + // ADD_NEW_METHODS_HERE virtual AString toString() const override; diff --git a/src/Charting/EventChartTwoAxisGetDataRange.cxx b/src/Charting/EventChartTwoAxisGetDataRange.cxx new file mode 100644 index 000000000..f34aff3a6 --- /dev/null +++ b/src/Charting/EventChartTwoAxisGetDataRange.cxx @@ -0,0 +1,111 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ +#include "EventChartTwoAxisGetDataRange.h" +#undef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventChartTwoAxisGetDataRange + * \brief Event to get the range of data for a chart two axis + * \ingroup Charting + */ + +/** + * Constructor. + */ +EventChartTwoAxisGetDataRange::EventChartTwoAxisGetDataRange(const ChartTwoOverlaySet* chartOverlaySet, + const ChartAxisLocationEnum::Enum chartAxisLocation) +: Event(EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE), +m_chartOverlaySet(chartOverlaySet), +m_chartAxisLocation(chartAxisLocation) +{ + +} + +/** + * Destructor. + */ +EventChartTwoAxisGetDataRange::~EventChartTwoAxisGetDataRange() +{ +} + +/** + * @return The chart overlay set that contains the axis. + */ +const ChartTwoOverlaySet* +EventChartTwoAxisGetDataRange::getChartOverlaySet() const +{ + return m_chartOverlaySet; +} + +/** + * @return The location of the axis. + */ +ChartAxisLocationEnum::Enum +EventChartTwoAxisGetDataRange::getChartAxisLocation() const +{ + return m_chartAxisLocation; +} + +/** + * Get the minimum and maximum values. + * + * @param minimumValue + * The minimum value. + * @param maximumValue + * The maximum value. + * @return + * True if the minimum and maximum are valid, else false. + */ +bool +EventChartTwoAxisGetDataRange::getMinimumAndMaximumValues(float& minimumValue, + float& maximumValue) const +{ + minimumValue = m_minimumValue; + maximumValue = m_maximumValue; + + return m_valuesValidFlag; +} + + +/** + * Set the minimum and maximum values. + * + * @param minimumValue + * The minimum value. + * @param maximumValue + * The maximum value. + */ +void EventChartTwoAxisGetDataRange::setMinimumAndMaximumValues(const float minimumValue, + const float maximumValue) +{ + m_minimumValue = minimumValue; + m_maximumValue = maximumValue; + m_valuesValidFlag = true; +} diff --git a/src/Charting/EventChartTwoAxisGetDataRange.h b/src/Charting/EventChartTwoAxisGetDataRange.h new file mode 100644 index 000000000..207c13fc3 --- /dev/null +++ b/src/Charting/EventChartTwoAxisGetDataRange.h @@ -0,0 +1,79 @@ +#ifndef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ +#define __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "ChartAxisLocationEnum.h" +#include "Event.h" + +namespace caret { + + class ChartTwoOverlaySet; + + class EventChartTwoAxisGetDataRange : public Event { + + public: + EventChartTwoAxisGetDataRange(const ChartTwoOverlaySet* chartOverlaySet, + const ChartAxisLocationEnum::Enum chartAxisLocation); + + virtual ~EventChartTwoAxisGetDataRange(); + + const ChartTwoOverlaySet* getChartOverlaySet() const; + + ChartAxisLocationEnum::Enum getChartAxisLocation() const; + + bool getMinimumAndMaximumValues(float& minimumValue, + float& maximumValue) const; + + void setMinimumAndMaximumValues(const float minimumValue, + const float maximumValue); + + // ADD_NEW_METHODS_HERE + + private: + EventChartTwoAxisGetDataRange(const EventChartTwoAxisGetDataRange&); + + EventChartTwoAxisGetDataRange& operator=(const EventChartTwoAxisGetDataRange&); + + const ChartTwoOverlaySet* m_chartOverlaySet; + + const ChartAxisLocationEnum::Enum m_chartAxisLocation; + + float m_minimumValue = 0.0f; + + float m_maximumValue = 0.0f; + + bool m_valuesValidFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ + // +#endif // __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ + +} // namespace +#endif //__EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 1a45d7499..0a708cd92 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -493,6 +493,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED: + case EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE: case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: case EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG: case EventTypeEnum::EVENT_DATA_FILE_ADD: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 6c519c67a..1b0aef70d 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -190,6 +190,10 @@ EventTypeEnum::initialize() "EVENT_CHART_TWO_ATTRIBUTES_CHANGED", "GUI notification of the change in chart two atttributes")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_AXIS_GET_DATA_RANGE, + "EVENT_CHART_TWO_AXIS_GET_DATA_RANGE", + "Get the range of data for a chart two axis")); + enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", "Load line series data for chart two implementation")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 1c5af4f0d..56527e8bb 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -94,6 +94,8 @@ public: EVENT_CHART_OVERLAY_VALIDATE, /** GUI notification of the change in chart two atttributes */ EVENT_CHART_TWO_ATTRIBUTES_CHANGED, + /** Get the range of data for a chart two axis */ + EVENT_CHART_TWO_AXIS_GET_DATA_RANGE, /** Load chart two line series data */ EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, /** Show the chart two line series history dialog */ diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index beafe21e6..8732ceb02 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -175,25 +175,25 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Size spin boxes */ m_labelSizeSpinBox = new WuQDoubleSpinBox(this); - m_labelSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_labelSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width QObject::connect(m_labelSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); m_numericsSizeSpinBox = new WuQDoubleSpinBox(this); - m_numericsSizeSpinBox->copySettings(m_labelSizeSpinBox); + m_numericsSizeSpinBox->setupRangePercentage(0.0, 99.0); QObject::connect(m_numericsSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); - m_linesTicksSizeSpinBox->copySettings(m_labelSizeSpinBox); + m_linesTicksSizeSpinBox->setupRangePercentage(0.0, 99.0); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); - m_paddingSizeSpinBox->copySettings(m_labelSizeSpinBox); + m_paddingSizeSpinBox->setupRangePercentage(0.0, 99.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); @@ -508,11 +508,12 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_axisDisplayedByUserCheckBox->setChecked(m_chartAxis->isDisplayedByUser()); m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); - float rangeMin(0.0), rangeMax(0.0); - m_chartAxis->getRange(rangeMin, rangeMax); - m_userMinimumValueSpinBox->setRange(rangeMin, rangeMax); + float rangeMin(0.0f), rangeMax(0.0f); + m_chartAxis->getDataRange(rangeMin, rangeMax); + const float exceedMultiplier = 1.0f; + m_userMinimumValueSpinBox->setRangeExceedable(rangeMin, rangeMax, exceedMultiplier); m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); - m_userMaximumValueSpinBox->setRange(rangeMin, rangeMax); + m_userMaximumValueSpinBox->setRangeExceedable(rangeMin, rangeMax, exceedMultiplier); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 63bc8a1d2..2b7878af9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -72,13 +72,13 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B editTitleToolButton->setDefaultAction(editTitleAction); m_titleSizeSpinBox = new WuQDoubleSpinBox(this); - m_titleSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_titleSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width QObject::connect(m_titleSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); - m_paddingSizeSpinBox->setupForPercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_paddingSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx index 68c5a7953..4ee1dae35 100644 --- a/src/GuiQt/WuQDoubleSpinBox.cxx +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -43,14 +43,25 @@ using namespace caret; * are not virtual. So, extend WuQWidget (which extends QObject), * encapsulate QDoubleSpinbox, and implement needed methods. * - * Two added features are: + * Added features are: * (1) Ability to automatically compute digits right of decimal * based upon the range of the data. + * * (2) Ablity to set increment/decrement values as a percentage * of the range of data. * - * Unlike QDoubleSpinBox, the valueChanged() signal DOES NOT get - * emitted when setValue() is called. + * (3) Ability to set an "exceedable" range. A QDoubleSpinBox + * will NOT emit a 'valueChanged' signal if the user tries to + * exceed the minimum or maximum value. 'setRangeExceedable()' + * will allow the minimum and maximum values to be exceeded + * but any auto formatting (decimals, step size) is based + * only on the minimum and maximum values specified. + * + * (4) if 'QDoubleSpinBox::setValue()' is called, it will + * emit the 'valueChanged()' signal which can be problematic + * when updating the value in the spin box. This implementation + * DOES NOT emit the 'valueChanged()' signal when 'setValue()' + * is called. */ /** @@ -62,15 +73,16 @@ using namespace caret; * The parent widget. */ WuQDoubleSpinBox::WuQDoubleSpinBox(QWidget* parent) -: WuQWidget(parent), -m_decimalsMode(DecimalsMode::DECIMALS_FIXED), -m_singleStepMode(SingleStepMode::SINGLE_STEP_FIXED) +: WuQWidget(parent) +//m_decimalsMode(DecimalsMode::FIXED), +//m_singleStepMode(SingleStepMode::FIXED) { /* * Create the spin box and initialize it + * Note that most members are initialized in the header file */ m_spinBox = new QDoubleSpinBox(); - m_spinBox->setRange(0.0, 99.99); + m_spinBox->setRange(m_minimumValue, m_maximumValue); m_spinBox->setSingleStep(1.0); m_spinBox->setDecimals(2); m_spinBox->setValue(0.0); @@ -96,66 +108,48 @@ WuQDoubleSpinBox::getWidget() return m_spinBox; } -/** - * Setup for percentage values. Percentage range - * [0.0, 100], with 2 digits right of decimal, - * a single step of 0.1, and a '%' suffix. - * - * @param minimumPercentage - * Minimum percentage (must be in range [0.0, 100.0] - * @param maximumPercentage - * Maximum percentage (must be in range [0.0, 100.0] - */ -void -WuQDoubleSpinBox::setupForPercentage(const double minimumPercentage, - const double maximumPercentage) -{ - setRange(minimumPercentage, - maximumPercentage); - setDecimals(2); - setSingleStepPercentage(0.1); - setSuffix("%"); -} - -/** - * Copy all setting from the given spin box - * - * @param copyFromSpinBox - * Spinbox from which settings are copied to 'this' instance - */ -void -WuQDoubleSpinBox::copySettings(const WuQDoubleSpinBox* copyFromSpinBox) -{ - CaretAssert(copyFromSpinBox); - - setRange(copyFromSpinBox->minimum(), copyFromSpinBox->maximum()); - m_decimalsMode = copyFromSpinBox->m_decimalsMode; - switch (copyFromSpinBox->m_decimalsMode) { - case DecimalsMode::DECIMALS_AUTO: - setDecimalsModeAuto(); - break; - case DecimalsMode::DECIMALS_FIXED: - setDecimals(copyFromSpinBox->decimals()); - break; - } - - setPrefix(copyFromSpinBox->prefix()); - setSuffix(copyFromSpinBox->suffix()); - - setSingleStep(copyFromSpinBox->singleStep()); - m_singleStepPercentage = copyFromSpinBox->m_singleStepPercentage; - m_singleStepMode = copyFromSpinBox->m_singleStepMode; - switch (m_singleStepMode) { - case SingleStepMode::SINGLE_STEP_FIXED: - break; - case SingleStepMode::SINGLE_STEP_PERCENTAGE: - setSingleStepPercentage(copyFromSpinBox->singleStepPercentage()); - break; - } - - - -} +///** +// * Copy all setting from the given spin box +// * +// * @param copyFromSpinBox +// * Spinbox from which settings are copied to 'this' instance +// */ +//void +//WuQDoubleSpinBox::copySettings(const WuQDoubleSpinBox* copyFromSpinBox) +//{ +// CaretAssert(copyFromSpinBox); +// +// switch (m_rangeMode) { +// case RangeMode::EXCEEDABLE: +// setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); +// break; +// case RangeMode::INCLUSIVE: +// setRange(m_minimumValue, m_maximumValue); +// } +// m_decimalsMode = copyFromSpinBox->m_decimalsMode; +// switch (copyFromSpinBox->m_decimalsMode) { +// case DecimalsMode::AUTO: +// setDecimalsModeAuto(); +// break; +// case DecimalsMode::FIXED: +// setDecimals(copyFromSpinBox->decimals()); +// break; +// } +// +// setPrefix(copyFromSpinBox->prefix()); +// setSuffix(copyFromSpinBox->suffix()); +// +// setSingleStep(copyFromSpinBox->singleStep()); +// m_singleStepPercentage = copyFromSpinBox->m_singleStepPercentage; +// m_singleStepMode = copyFromSpinBox->m_singleStepMode; +// switch (m_singleStepMode) { +// case SingleStepMode::FIXED: +// break; +// case SingleStepMode::PERCENTAGE: +// setSingleStepPercentage(copyFromSpinBox->singleStepPercentage()); +// break; +// } +//} ///** @@ -182,7 +176,7 @@ WuQDoubleSpinBox::decimalsMode() const void WuQDoubleSpinBox::setDecimalsModeAuto() { - m_decimalsMode = DecimalsMode::DECIMALS_AUTO; + m_decimalsMode = DecimalsMode::AUTO; updateDecimalsForAutoMode(); } @@ -206,7 +200,7 @@ WuQDoubleSpinBox::decimals() const void WuQDoubleSpinBox::setDecimals(int prec) { - m_decimalsMode = DecimalsMode::DECIMALS_FIXED; + m_decimalsMode = DecimalsMode::FIXED; m_spinBox->setDecimals(prec); } @@ -284,11 +278,11 @@ WuQDoubleSpinBox::updateDecimalsForAutoMode() } switch (m_decimalsMode) { - case DecimalsMode::DECIMALS_AUTO: - m_spinBox->setDecimals(computeDigitsRightOfDecimal(m_spinBox->maximum() - - m_spinBox->minimum())); + case DecimalsMode::AUTO: + m_spinBox->setDecimals(computeDigitsRightOfDecimal(m_maximumValue + - m_minimumValue)); break; - case DecimalsMode::DECIMALS_FIXED: + case DecimalsMode::FIXED: break; } } @@ -299,7 +293,7 @@ WuQDoubleSpinBox::updateDecimalsForAutoMode() double WuQDoubleSpinBox::minimum() const { - return m_spinBox->minimum(); + return m_minimumValue; } /** @@ -308,7 +302,7 @@ WuQDoubleSpinBox::minimum() const double WuQDoubleSpinBox::maximum() const { - return m_spinBox->maximum(); + return m_maximumValue; } /** @@ -320,9 +314,17 @@ WuQDoubleSpinBox::maximum() const void WuQDoubleSpinBox::setMaximum(double max) { - m_spinBox->setMaximum(max); - updateDecimalsForAutoMode(); - updateSingleStepPercentage(); + m_maximumValue = max; + switch (m_rangeMode) { + case RangeMode::EXCEEDABLE: + setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); + break; + case RangeMode::INCLUSIVE: + break; + } +// m_spinBox->setMaximum(max); +// updateDecimalsForAutoMode(); +// updateSingleStepPercentage(); } /** @@ -334,9 +336,17 @@ WuQDoubleSpinBox::setMaximum(double max) void WuQDoubleSpinBox::setMinimum(double min) { - m_spinBox->setMinimum(min); - updateDecimalsForAutoMode(); - updateSingleStepPercentage(); + m_minimumValue = min; + switch (m_rangeMode) { + case RangeMode::EXCEEDABLE: + setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); + break; + case RangeMode::INCLUSIVE: + break; + } +// m_spinBox->setMinimum(min); +// updateDecimalsForAutoMode(); +// updateSingleStepPercentage(); } /** @@ -363,6 +373,7 @@ WuQDoubleSpinBox::setPrefix(const QString &prefix) /** * Convenience function to set the minimum and maximum values with a single function call. + * Selected value is limited to minimum and maximum. * * @param minimum * New minimum value. @@ -370,20 +381,79 @@ WuQDoubleSpinBox::setPrefix(const QString &prefix) * New maximum value. */ void -WuQDoubleSpinBox::setRange(double minimum, double maximum) +WuQDoubleSpinBox::setRange(double minimum, + double maximum) +{ +// ADD A SET RANGE WITH PADDING OR EXTRA +// THAT USE TRUE RANGE FOR DECIMALS AND THEN +// SETS THE SPIN BOX RANGE WITH EXTRA +// SO THAT THE ARROWS WILL ALWYAS CHANGE VALUES +// + m_minimumValue = minimum; + m_maximumValue = maximum; + m_rangeMode = RangeMode::INCLUSIVE; + m_spinBox->setRange(m_minimumValue, m_maximumValue); + updateDecimalsForAutoMode(); + updateSingleStepPercentage(); +} + +/** + * Convenience function to set the minimum and maximum values with a single function call. + * Selected value is allowed to exceed minimum and maximum by (maximum - minimum) * rangeMultiplier. + * Any automatic formatting or decimals excludes the "exceed amount". + * + * @param minimum + * New minimum value. + * @param maximum + * New maximum value. + * @param rangeMultiplier + * The range multiplier. + */ +void +WuQDoubleSpinBox::setRangeExceedable(double minimum, + double maximum, + double rangeMultiplier) { - m_spinBox->setRange(minimum, maximum); + m_minimumValue = minimum; + m_maximumValue = maximum; + m_rangeMode = RangeMode::EXCEEDABLE; + + m_exceedRangeMultiplier = rangeMultiplier; + const double exceedAmount = (maximum - minimum) * m_exceedRangeMultiplier; + m_spinBox->setRange(m_minimumValue - exceedAmount, m_maximumValue + exceedAmount); + updateDecimalsForAutoMode(); updateSingleStepPercentage(); } +/** + * Set range for percentage values. Percentage range + * [0.0, 100], with 2 digits right of decimal, + * a single step of 0.1, and a '%' suffix. + * + * @param minimumPercentage + * Minimum percentage (must be in range [0.0, 100.0] + * @param maximumPercentage + * Maximum percentage (must be in range [0.0, 100.0] + */ +void +WuQDoubleSpinBox::setupRangePercentage(const double minimumPercentage, + const double maximumPercentage) +{ + setRange(minimumPercentage, + maximumPercentage); + setDecimals(2); + setSingleStepPercentage(0.1); + setSuffix("%"); +} + /** * Set the step value. When the user uses the arrows to change the * spin box's value the value will be incremented/decremented by the * amount of the given value. * * NOTE: When this method is called, the SingleStepMode is set - * to SINGLE_STEP_FIXED + * to FIXED * * @param value * New step value. @@ -394,7 +464,7 @@ WuQDoubleSpinBox::setSingleStep(double value) CaretAssert(value >= 0.0); m_spinBox->setSingleStep(value); - m_singleStepMode = SingleStepMode::SINGLE_STEP_FIXED; + m_singleStepMode = SingleStepMode::FIXED; } /** @@ -403,7 +473,7 @@ WuQDoubleSpinBox::setSingleStep(double value) * percentage of the minimum and maximum values. * * NOTE: When this method is called, the SingleStepMode is set - * to SINGLE_STEP_PERCENTAGE. + * to PERCENTAGE. * * @param percentage * The step percentage that ranges (0.0, 100.0]. @@ -415,7 +485,7 @@ WuQDoubleSpinBox::setSingleStepPercentage(double percentage) CaretAssert(percentage <= 100.0); m_singleStepPercentage = percentage; - m_singleStepMode = SingleStepMode::SINGLE_STEP_PERCENTAGE; + m_singleStepMode = SingleStepMode::PERCENTAGE; updateSingleStepPercentage(); } @@ -428,12 +498,12 @@ void WuQDoubleSpinBox::updateSingleStepPercentage() { switch (m_singleStepMode) { - case SingleStepMode::SINGLE_STEP_FIXED: + case SingleStepMode::FIXED: break; - case SingleStepMode::SINGLE_STEP_PERCENTAGE: + case SingleStepMode::PERCENTAGE: { - const double minValue = m_spinBox->minimum(); - const double maxValue = m_spinBox->maximum(); + const double minValue = m_minimumValue; + const double maxValue = m_maximumValue; const double dataRange = maxValue - minValue; double stepValue = 0.0; diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h index a648816fb..24439767e 100644 --- a/src/GuiQt/WuQDoubleSpinBox.h +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -43,12 +43,12 @@ namespace caret { /** * Number of decimals is calculated from the range of data */ - DECIMALS_AUTO, + AUTO, /** * Number of decimals is fixed by calling setDecimals(int) * (Normal spin box functionality) */ - DECIMALS_FIXED + FIXED }; /** @@ -58,11 +58,26 @@ namespace caret { /** * Step by a fixed amount (normal spin box functionality) */ - SINGLE_STEP_FIXED, + FIXED, /** - * Step by a percenage of data range + * Step by a percentage of data range */ - SINGLE_STEP_PERCENTAGE + PERCENTAGE + }; + + /** + * Mode for data range + */ + enum class RangeMode { + /** + * Normal spin box behavior, values limited inclusively to minimum and maximum + */ + INCLUSIVE, + /** + * May exceed minimum and maximum values. + * Formatted for specified minimum and maximum. + */ + EXCEEDABLE }; WuQDoubleSpinBox(QWidget* parent); @@ -71,10 +86,7 @@ namespace caret { virtual QWidget* getWidget(); - void setupForPercentage(const double minimumPercentage, - const double maximumPercentage); - - void copySettings(const WuQDoubleSpinBox* copyFromSpinBox); + //void copySettings(const WuQDoubleSpinBox* copyFromSpinBox); QString cleanText() const; @@ -100,6 +112,13 @@ namespace caret { void setRange(double minimum, double maximum); + void setRangeExceedable(double minimum, + double maximum, + double rangeMultiplier); + + void setupRangePercentage(const double minimumPercentage, + const double maximumPercentage); + void setSingleStep(double value); void setSingleStepPercentage(double percentage); @@ -156,12 +175,20 @@ namespace caret { QDoubleSpinBox* m_spinBox; - DecimalsMode m_decimalsMode = DecimalsMode::DECIMALS_FIXED; + RangeMode m_rangeMode = RangeMode::INCLUSIVE; + + DecimalsMode m_decimalsMode = DecimalsMode::FIXED; - SingleStepMode m_singleStepMode = SingleStepMode::SINGLE_STEP_FIXED; + SingleStepMode m_singleStepMode = SingleStepMode::FIXED; double m_singleStepPercentage = 1.0; + double m_minimumValue = 0.0; + + double m_maximumValue = 99.0; + + double m_exceedRangeMultiplier = 0.0; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From b8e4411db451412085e04224836cf48d7f9b6623 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 29 Aug 2017 16:38:55 -0500 Subject: [PATCH 364/755] Resolve WB-719 Cannot type past decimal point in annotation font size spin box. Replaced the font size spin box with a WuQDoubleSpinBox. Fixed bug in WuQDoubleSpinBox to ignore update during the type the 'valueChanged' signal is emitted. --- src/GuiQt/AnnotationFontWidget.cxx | 31 +++++------------------------- src/GuiQt/AnnotationFontWidget.h | 4 ++-- src/GuiQt/WuQDoubleSpinBox.cxx | 31 +++++++++++++++++------------- src/GuiQt/WuQDoubleSpinBox.h | 2 ++ 4 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index fd7e40961..3b984e9eb 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -46,7 +46,7 @@ #include "EventManager.h" #include "GuiManager.h" #include "ModelSurfaceMontage.h" -#include "WuQSpecialIncrementDoubleSpinBox.h" +#include "WuQDoubleSpinBox.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -60,19 +60,6 @@ using namespace caret; * \ingroup GuiQt */ -/** - * Processes increment and decrements for double spin box. - */ -class FontSizeFunctionObject : public WuQSpecialIncrementDoubleSpinBox::StepFunctionObject { -public: - double getNewValue(const double currentValue, - const int steps) const { - const double stepAmount = 0.1; - const double outputValue = currentValue + (stepAmount * steps); - return outputValue; - } -}; - /** * Constructor. * @@ -106,16 +93,12 @@ m_browserWindowIndex(browserWindowIndex) /* * Combo box for font size */ - m_fontSizeSpinBox = new WuQSpecialIncrementDoubleSpinBox(new FontSizeFunctionObject); - m_fontSizeSpinBox->setRange(0.0, 1000.0); - m_fontSizeSpinBox->setDecimals(1); - m_fontSizeSpinBox->setSingleStep(0.1); - m_fontSizeSpinBox->setSuffix("%"); + m_fontSizeSpinBox = new WuQDoubleSpinBox(this); + m_fontSizeSpinBox->setupRangePercentage(0.0, 100.0); QObject::connect(m_fontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(fontSizeChanged())); - WuQtUtilities::setToolTipAndStatusTip(m_fontSizeSpinBox, + WuQtUtilities::setToolTipAndStatusTip(m_fontSizeSpinBox->getWidget(), "Change font size (height) as percentage, zero to one-hundred, of viewport height"); - /* * Text color menu @@ -232,7 +215,7 @@ m_browserWindowIndex(browserWindowIndex) fontNameSizeLayout->addWidget(m_fontNameComboBox->getWidget(), 0, 1, 1, 3); fontNameSizeLayout->addWidget(sizeLabel, 1, 0); - fontNameSizeLayout->addWidget(m_fontSizeSpinBox, + fontNameSizeLayout->addWidget(m_fontSizeSpinBox->getWidget(), 1, 1); fontNameSizeLayout->addWidget(styleLabel, 2, 0); fontNameSizeLayout->addLayout(stylesLayout, 2, 1); @@ -464,14 +447,11 @@ void AnnotationFontWidget::updateFontSizeSpinBox(const float value, const bool haveMultipleValuesFlag) { - m_fontSizeSpinBox->blockSignals(true); m_fontSizeSpinBox->setValue(value); - m_fontSizeSpinBox->blockSignals(false); QString fontSizeSuffix("%"); if (haveMultipleValuesFlag) { fontSizeSuffix = "%+"; } - m_fontSizeSpinBox->setSuffix(fontSizeSuffix); } /** @@ -749,7 +729,6 @@ AnnotationFontWidget::fontSizeChanged() } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } /** diff --git a/src/GuiQt/AnnotationFontWidget.h b/src/GuiQt/AnnotationFontWidget.h index b65c3aea5..a7efd389b 100644 --- a/src/GuiQt/AnnotationFontWidget.h +++ b/src/GuiQt/AnnotationFontWidget.h @@ -38,7 +38,7 @@ namespace caret { class AnnotationText; class CaretColorEnumMenu; class EnumComboBoxTemplate; - class WuQSpecialIncrementDoubleSpinBox; + class WuQDoubleSpinBox; class AnnotationFontWidget : public QWidget { @@ -94,7 +94,7 @@ namespace caret { EnumComboBoxTemplate* m_fontNameComboBox; - WuQSpecialIncrementDoubleSpinBox* m_fontSizeSpinBox; + WuQDoubleSpinBox* m_fontSizeSpinBox; QToolButton* m_textColorToolButton; diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx index 4ee1dae35..a368234f7 100644 --- a/src/GuiQt/WuQDoubleSpinBox.cxx +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -74,8 +74,6 @@ using namespace caret; */ WuQDoubleSpinBox::WuQDoubleSpinBox(QWidget* parent) : WuQWidget(parent) -//m_decimalsMode(DecimalsMode::FIXED), -//m_singleStepMode(SingleStepMode::FIXED) { /* * Create the spin box and initialize it @@ -320,11 +318,9 @@ WuQDoubleSpinBox::setMaximum(double max) setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); break; case RangeMode::INCLUSIVE: + setRange(m_minimumValue, m_maximumValue); break; } -// m_spinBox->setMaximum(max); -// updateDecimalsForAutoMode(); -// updateSingleStepPercentage(); } /** @@ -342,11 +338,9 @@ WuQDoubleSpinBox::setMinimum(double min) setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); break; case RangeMode::INCLUSIVE: + setRange(m_minimumValue, m_maximumValue); break; } -// m_spinBox->setMinimum(min); -// updateDecimalsForAutoMode(); -// updateSingleStepPercentage(); } /** @@ -384,11 +378,6 @@ void WuQDoubleSpinBox::setRange(double minimum, double maximum) { -// ADD A SET RANGE WITH PADDING OR EXTRA -// THAT USE TRUE RANGE FOR DECIMALS AND THEN -// SETS THE SPIN BOX RANGE WITH EXTRA -// SO THAT THE ARROWS WILL ALWYAS CHANGE VALUES -// m_minimumValue = minimum; m_maximumValue = maximum; m_rangeMode = RangeMode::INCLUSIVE; @@ -615,6 +604,10 @@ WuQDoubleSpinBox::valueFromText(const QString &text) const */ void WuQDoubleSpinBox::setValue(double val) { + if (m_blockValueUpdateFlag) { + return; + } + QSignalBlocker blocker(m_spinBox); m_spinBox->setValue(val); } @@ -630,11 +623,23 @@ void WuQDoubleSpinBox::setValue(double val) void WuQDoubleSpinBox::valueChangedPrivate(double d) { + if (m_spinBox->signalsBlocked()) { + return; + } if (signalsBlocked()) { return; } + /* + * Emitting the signal may cause a call to the 'setValue()' method. + * We need to prevent this. Otherwise, the spin box will get updated + * with only the first character that was typed by user. + * For example, without this, if the user tried to enter 9.3, + * setValue gets called with only 9 and the user cannot enter the .3. + */ + m_blockValueUpdateFlag = true; emit valueChanged(d); + m_blockValueUpdateFlag = false; } // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h index 24439767e..2b8198322 100644 --- a/src/GuiQt/WuQDoubleSpinBox.h +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -189,6 +189,8 @@ namespace caret { double m_exceedRangeMultiplier = 0.0; + bool m_blockValueUpdateFlag = false; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From c7024b62c0a8bedb186ce8eaeb4039c2d090eaee Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 30 Aug 2017 12:33:33 -0500 Subject: [PATCH 365/755] Resolve WB-705 - Line chart horizontal auto-scale default range : Added a new axis range mode 'Data' (existing modes are Auto and User). When the range mode is Data, the axis minimum and maximum values are the minimum and maximum values from the displayed data. Limits of the min/max spin boxes were corrected in a previous commit. --- src/Brain/ChartTwoOverlaySet.cxx | 4 ++ .../ChartTwoAxisScaleRangeModeEnum.cxx | 30 ++++++--- src/Charting/ChartTwoAxisScaleRangeModeEnum.h | 17 ++++-- src/Charting/ChartTwoCartesianAxis.cxx | 61 +++++++++++++++++-- src/Charting/ChartTwoCartesianAxis.h | 2 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 12 +++- 6 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 286ba844f..94fc19869 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -108,6 +108,10 @@ m_tabIndex(tabIndex) m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); + /* + * X-axis for line series shows full extent of data + */ + m_chartAxisBottom->setScaleRangeMode(ChartTwoAxisScaleRangeModeEnum::DATA); m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); } diff --git a/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx index cb6d2a8aa..bcd52ab51 100644 --- a/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx +++ b/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx @@ -77,15 +77,19 @@ using namespace caret; * * @param guiName * User-friendly name for use in user-interface. + * @param oldName + * An older version of 'name' */ ChartTwoAxisScaleRangeModeEnum::ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, - const AString& name, - const AString& guiName) + const AString& name, + const AString& guiName, + const AString& oldName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; + this->oldName = oldName; } /** @@ -106,13 +110,20 @@ ChartTwoAxisScaleRangeModeEnum::initialize() } initializedFlag = true; - enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_AUTO, - "AXIS_DATA_RANGE_AUTO", - "Auto")); + enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AUTO, + "AUTO", + "Auto", + "AXIS_DATA_RANGE_AUTO")); - enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AXIS_DATA_RANGE_USER, - "AXIS_DATA_RANGE_USER", - "User")); + enumData.push_back(ChartTwoAxisScaleRangeModeEnum(DATA, + "DATA", + "Data", + "AXIS_DATA_RANGE_DATA")); + + enumData.push_back(ChartTwoAxisScaleRangeModeEnum(USER, + "USER", + "User", + "AXIS_DATA_RANGE_USER")); } @@ -176,7 +187,8 @@ ChartTwoAxisScaleRangeModeEnum::fromName(const AString& name, bool* isValidOut) iter != enumData.end(); iter++) { const ChartTwoAxisScaleRangeModeEnum& d = *iter; - if (d.name == name) { + if ((d.name == name) + || (d.oldName == name)) { enumValue = d.enumValue; validFlag = true; break; diff --git a/src/Charting/ChartTwoAxisScaleRangeModeEnum.h b/src/Charting/ChartTwoAxisScaleRangeModeEnum.h index 0317d5344..7aa20fcab 100644 --- a/src/Charting/ChartTwoAxisScaleRangeModeEnum.h +++ b/src/Charting/ChartTwoAxisScaleRangeModeEnum.h @@ -35,10 +35,13 @@ public: * Enumerated values. */ enum Enum { + /** Auto scales and pads for nice numeric scale values */ + AUTO, + /** Scales to minimum and maximum of data */ + DATA, + /** Scales to user-specified minimum and maximum */ /** */ - AXIS_DATA_RANGE_AUTO, - /** */ - AXIS_DATA_RANGE_USER + USER }; @@ -64,8 +67,9 @@ public: private: ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, - const AString& name, - const AString& guiName); + const AString& name, + const AString& guiName, + const AString& oldName); static const ChartTwoAxisScaleRangeModeEnum* findData(const Enum enumValue); @@ -92,6 +96,9 @@ private: /** A user-friendly name that is displayed in the GUI */ AString guiName; + + /** For older version of 'name' */ + AString oldName; }; #ifdef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index a846a8122..ccbd96590 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -738,9 +738,11 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, int32_t labelsDigitsRightOfDecimal = 0; switch (m_scaleRangeMode) { - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + case ChartTwoAxisScaleRangeModeEnum::AUTO: break; - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: + case ChartTwoAxisScaleRangeModeEnum::DATA: + break; + case ChartTwoAxisScaleRangeModeEnum::USER: switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: minimumValue = m_userScaleMinimumValue; @@ -772,13 +774,41 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, } switch (m_scaleRangeMode) { - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO: + case ChartTwoAxisScaleRangeModeEnum::AUTO: m_userScaleMinimumValue = labelsStart; m_userScaleMaximumValue = labelsEnd; break; - case ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER: - labelsStart = m_userScaleMinimumValue; - labelsEnd = m_userScaleMaximumValue; + case ChartTwoAxisScaleRangeModeEnum::DATA: + { + const double range = maximumDataValue - minimumDataValue; + if (range > 0.0) { + const int32_t numSteps = MathFunctions::round((labelsEnd - labelsStart) / labelsStep); + if (numSteps > 0) { + labelsStart = minimumDataValue; + labelsEnd = maximumDataValue; + labelsStep = range / numSteps; + m_userScaleMinimumValue = labelsStart; + m_userScaleMaximumValue = labelsEnd; + } + } + } + break; + case ChartTwoAxisScaleRangeModeEnum::USER: +// labelsStart = m_userScaleMinimumValue; +// labelsEnd = m_userScaleMaximumValue; + { + const double range = m_userScaleMaximumValue - m_userScaleMinimumValue; + if (range > 0.0) { + const int32_t numSteps = MathFunctions::round((labelsEnd - labelsStart) / labelsStep); + if (numSteps > 0) { + labelsStart = m_userScaleMinimumValue; + labelsEnd = m_userScaleMaximumValue; + labelsStep = range / numSteps; + m_userScaleMinimumValue = labelsStart; + m_userScaleMaximumValue = labelsEnd; + } + } + } break; } @@ -830,6 +860,8 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, return false; } + const float onePercentRange = labelsRange * 0.01f; + std::vector labelNumericValues; float labelValue = labelsStart; @@ -900,6 +932,23 @@ ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, } labelValue += tickLabelsStep; + + /* + * It is possible that 'labelValue' may be slightly greater than 'labelsEnd' + * for the last label which results in the last label not displayed. + * So, if the 'labelValue' is slightly greater than 'labelsEnd', + * limit 'labelValue' so that the label at the end of the data range + * is displayed. + * + * Example: labelValue = 73.9500046 + * labelsEnd = 73.9499969 + */ + if (labelValue > labelsEnd) { + const float diff = labelValue - labelsEnd; + if (diff < onePercentRange) { + labelValue = labelsEnd; + } + } } const int32_t numValues = static_cast(labelNumericValues.size()); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index f304dfa6e..453a0e931 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -178,7 +178,7 @@ namespace caret { mutable int32_t m_titleOverlayIndex = 0; - ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_AUTO; + ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AUTO; CaretUnitsTypeEnum::Enum m_units = CaretUnitsTypeEnum::NONE; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 8732ceb02..3c3ae689b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -126,11 +126,17 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra /* * Range controls */ + const AString rangeTooltip("Auto - Adjusts axis range to fit data with some\n" + " padding so that scale value are usually\n" + " whole numbers\n" + "Data - Axis range is limited to minimum and \n" + " maximum values of the data\n" + "User - Axis range is controlled by user"); m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); m_autoUserRangeComboBox->setup(); QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); - m_autoUserRangeComboBox->getWidget()->setToolTip("Choose auto or user axis range scaling"); + m_autoUserRangeComboBox->getWidget()->setToolTip(rangeTooltip); m_userMinimumValueSpinBox = new WuQDoubleSpinBox(this); m_userMinimumValueSpinBox->setDecimalsModeAuto(); @@ -625,7 +631,7 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged(double minimumVal * ensure Auto/User Range selection is USER */ m_autoUserRangeComboBox->getWidget()->blockSignals(true); - m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER); + m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::USER); m_autoUserRangeComboBox->getWidget()->blockSignals(false); /* @@ -656,7 +662,7 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumVal * ensure Auto/User Range selection is USER */ m_autoUserRangeComboBox->getWidget()->blockSignals(true); - m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::AXIS_DATA_RANGE_USER); + m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::USER); m_autoUserRangeComboBox->getWidget()->blockSignals(false); /* -- GitLab From 695e397b9e78d96126c261ba19093a1bc879f0f5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 30 Aug 2017 15:40:50 -0500 Subject: [PATCH 366/755] Prevent crash when the user is editing a chart axis minimum or maximum value that results in the minimum and maximum values becoming the same value. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 42 +++++++++---------- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 8 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 9a99773b8..f9e2018bf 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -482,27 +482,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const bool yRightValid = (yMinRight <= yMaxRight); const bool yValid = (yLeftValid || yRightValid); if (xValid && yValid) { - /* - * If Y-range is zero, make it a non-zero range. - * Otherwise, the orthographic projection will be invalid - */ - const float smallValue = 0.00001; - const float smallRange = 0.01; - if (yLeftValid) { - const float diff = yMaxLeft - yMinLeft; - if (diff < smallValue) { - yMinLeft -= smallRange; - yMaxLeft += smallRange; - } - } - if (yRightValid) { - const float diff = yMaxRight - yMinRight; - if (diff < smallValue) { - yMinRight -= smallRange; - yMaxRight += smallRange; - } - } - /* * Make invalid ranges zero */ @@ -733,6 +712,27 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch chartGraphicsDrawingViewport); } + /* + * When the user is editing an axis minimum or maximum value, + * their difference may become zero which will cause + * a problem with the orthographic projection. So + * in this rare instance, make the maximum value + * slightly larger than the minimum value. + */ + const float smallRange = 0.01; + if (xMinBottom >= xMaxBottom) { + xMaxBottom = xMinBottom + smallRange; + } + if (xMinTop >= xMaxTop) { + xMaxTop = xMinBottom + smallRange; + } + if (yMinLeft >= yMaxLeft) { + yMaxLeft = yMinLeft + smallRange; + } + if (yMinRight >= yMaxRight) { + yMaxRight = yMinRight + smallRange; + } + glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 3c3ae689b..a9499c37c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -638,9 +638,9 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged(double minimumVal * Ensure maximum value is always greater than or equal to minimum */ if (minimumValue > m_userMaximumValueSpinBox->value()) { - m_userMaximumValueSpinBox->blockSignals(true); + m_userMaximumValueSpinBox->getWidget()->blockSignals(true); m_userMaximumValueSpinBox->setValue(minimumValue); - m_userMaximumValueSpinBox->blockSignals(false); + m_userMaximumValueSpinBox->getWidget()->blockSignals(false); } valueChanged(); @@ -669,9 +669,9 @@ BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumVal * Ensure minimum value is always less than or equal to maximum */ if (maximumValue < m_userMinimumValueSpinBox->value()) { - m_userMinimumValueSpinBox->blockSignals(true); + m_userMinimumValueSpinBox->getWidget()->blockSignals(true); m_userMinimumValueSpinBox->setValue(maximumValue); - m_userMinimumValueSpinBox->blockSignals(false); + m_userMinimumValueSpinBox->getWidget()->blockSignals(false); } valueChanged(); -- GitLab From 5b44dea271ea9e306ff74cd0710f85119a956961 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 31 Aug 2017 12:32:19 -0500 Subject: [PATCH 367/755] For the WuQDoubleSpinBox "exceed range" mode, set the spin box minimum and maximum values to that they are a power of ten. --- src/Common/NumericTextFormatting.h | 5 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 5 +- src/GuiQt/WuQDoubleSpinBox.cxx | 281 ++++++++++++++---- src/GuiQt/WuQDoubleSpinBox.h | 31 +- src/GuiQt/WuQWidget.h | 2 +- 5 files changed, 253 insertions(+), 71 deletions(-) diff --git a/src/Common/NumericTextFormatting.h b/src/Common/NumericTextFormatting.h index 411fa8382..a7bea9c97 100644 --- a/src/Common/NumericTextFormatting.h +++ b/src/Common/NumericTextFormatting.h @@ -49,6 +49,9 @@ namespace caret { static void formatValuesIndividually(const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues); + + static AString cleanZerosInValueText(const AString& textValueIn); + // ADD_NEW_METHODS_HERE private: @@ -60,8 +63,6 @@ namespace caret { NumericTextFormatting& operator=(const NumericTextFormatting&); - static AString cleanZerosInValueText(const AString& textValueIn); - static AString removeLeadingZeroFromExponent(const NumericFormatModeEnum::Enum numericFormat, const AString& textValueIn); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index a9499c37c..adcbb1846 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -516,10 +516,9 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); float rangeMin(0.0f), rangeMax(0.0f); m_chartAxis->getDataRange(rangeMin, rangeMax); - const float exceedMultiplier = 1.0f; - m_userMinimumValueSpinBox->setRangeExceedable(rangeMin, rangeMax, exceedMultiplier); + m_userMinimumValueSpinBox->setRangeExceedable(rangeMin, rangeMax); m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); - m_userMaximumValueSpinBox->setRangeExceedable(rangeMin, rangeMax, exceedMultiplier); + m_userMaximumValueSpinBox->setRangeExceedable(rangeMin, rangeMax); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx index a368234f7..57f9fefc6 100644 --- a/src/GuiQt/WuQDoubleSpinBox.cxx +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -30,6 +30,7 @@ #include "AString.h" #include "CaretAssert.h" +#include "NumericTextFormatting.h" using namespace caret; @@ -241,6 +242,58 @@ WuQDoubleSpinBox::computeDigitsRightOfDecimal(const double dataRange) return numDecimals; } +/** + * Compute a reasonable 'exceed range' which is used + * for setting the acceptable values in the spin box + * to the range of data plus a reasonable amount + * above and below. + * + * @param minValue + * The minimum data value. + * @param maxValue + * The maximum data value. + * @param + * Exceed amount for increased range. + */ +double +WuQDoubleSpinBox::computeExceedRange(const double minValue, + const double maxValue) +{ + double exceedRange = 10.0; + + const double range = maxValue - minValue; + if (range >= 1.0) { + const double logVal = std::log10(range); + const double exponent = logVal + 2; + exceedRange = std::pow(10.0, exponent); + } + + return exceedRange; +} + +/** + * Testing of the exceed ragne. + */ +void +WuQDoubleSpinBox::testExceedRange() +{ + { + const double value = 0.0; + const double exceedRange = computeExceedRange(0.0, value); + AString s = QString("Range: %1 execeedRange: %2").arg(value, 10).arg(exceedRange); + std::cout << s << std::endl; + } + + for (int32_t exponent = -10; exponent <= 10; exponent++) { + const double value = std::pow(10.0, exponent); + const double exceedRange = computeExceedRange(0.0, value); + AString s = QString("Range: %1 exceedRange: %2 lo10: %3").arg(value, 10).arg(exceedRange).arg((int)std::log10(value)); + std::cout << s << std::endl; + } + std::cout << std::endl << std::endl; +} + + /** * Used for testing computation of digits right of decimal point. */ @@ -272,6 +325,7 @@ WuQDoubleSpinBox::updateDecimalsForAutoMode() static bool decimalsTestFlag = false; if (decimalsTestFlag) { testDigitsRightOfDecimal(); + testExceedRange(); decimalsTestFlag = false; } @@ -286,61 +340,21 @@ WuQDoubleSpinBox::updateDecimalsForAutoMode() } /** - * @return Minimum displayed value. + * @return Minimum DISPLAYED value. */ double WuQDoubleSpinBox::minimum() const { - return m_minimumValue; + return m_spinBox->minimum(); } /** - * @return Maximum displayed value. + * @return Maximum DISPLAYED value. */ double WuQDoubleSpinBox::maximum() const { - return m_maximumValue; -} - -/** - * Sets the maximum value displayed in the spin box. - * - * @param max - * New maximum value. - */ -void -WuQDoubleSpinBox::setMaximum(double max) -{ - m_maximumValue = max; - switch (m_rangeMode) { - case RangeMode::EXCEEDABLE: - setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); - break; - case RangeMode::INCLUSIVE: - setRange(m_minimumValue, m_maximumValue); - break; - } -} - -/** - * Sets the minimum value displayed in the spin box. - * - * @param min - * New minimum value. - */ -void -WuQDoubleSpinBox::setMinimum(double min) -{ - m_minimumValue = min; - switch (m_rangeMode) { - case RangeMode::EXCEEDABLE: - setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); - break; - case RangeMode::INCLUSIVE: - setRange(m_minimumValue, m_maximumValue); - break; - } + return m_spinBox->maximum(); } /** @@ -366,8 +380,7 @@ WuQDoubleSpinBox::setPrefix(const QString &prefix) } /** - * Convenience function to set the minimum and maximum values with a single function call. - * Selected value is limited to minimum and maximum. + * Set the minimum and maximum values for this spin box. * * @param minimum * New minimum value. @@ -384,35 +397,110 @@ WuQDoubleSpinBox::setRange(double minimum, m_spinBox->setRange(m_minimumValue, m_maximumValue); updateDecimalsForAutoMode(); updateSingleStepPercentage(); + setDataRangeToolTip(); } /** - * Convenience function to set the minimum and maximum values with a single function call. - * Selected value is allowed to exceed minimum and maximum by (maximum - minimum) * rangeMultiplier. + * Set range with an automatically calculated 'exceedAmount', typically + * 100 times the range and a power of 10. + * * Any automatic formatting or decimals excludes the "exceed amount". * * @param minimum * New minimum value. * @param maximum * New maximum value. - * @param rangeMultiplier - * The range multiplier. */ void WuQDoubleSpinBox::setRangeExceedable(double minimum, - double maximum, - double rangeMultiplier) + double maximum) { - m_minimumValue = minimum; - m_maximumValue = maximum; - m_rangeMode = RangeMode::EXCEEDABLE; + const double exceedAmount = computeExceedRange(minimum, maximum); + const double exceedMin = makePowerOfTen(minimum - exceedAmount); + const double exceedMax = makePowerOfTen(maximum + exceedAmount); + + setRangeExceedable(minimum, + maximum, + exceedMin, + exceedMax); +} - m_exceedRangeMultiplier = rangeMultiplier; - const double exceedAmount = (maximum - minimum) * m_exceedRangeMultiplier; - m_spinBox->setRange(m_minimumValue - exceedAmount, m_maximumValue + exceedAmount); +/** + * Set the range of the data and the spin box. + + * All formating is based upon the data minimum and maximum. + * + * @param dataMinimum + * Data minimum value. + * @param dataMaximum + * Data maximum value. + * @param spinBoxMinimum + * Spinbox minimum value. + * @param spinBoxMaximum + * Spinbox maximum value. + */ +void +WuQDoubleSpinBox::setRangeExceedable(const double dataMinimum, + const double dataMaximum, + const double spinBoxMinimum, + const double spinBoxMaximum) +{ + m_minimumValue = dataMinimum; + m_maximumValue = dataMaximum; + m_rangeMode = RangeMode::EXCEEDABLE; + + m_spinBox->setRange(spinBoxMinimum, + spinBoxMaximum); updateDecimalsForAutoMode(); updateSingleStepPercentage(); + setDataRangeToolTip(); +} + +/** + * Increase the value to the next power of ten. + * Example: 8500 becomes 10000 + * + * @param value + * The value. + * @return + * Value increased to next power of ten. + */ +double +WuQDoubleSpinBox::makePowerOfTen(const double value) const +{ + const bool negativeFlag = (value < 0.0); + double valuePositive = std::fabs(value); + const int64_t logVal = static_cast(std::log10(valuePositive) + 1); + double powerTenValue = std::pow(10.0, logVal); + if (negativeFlag) { + powerTenValue = -powerTenValue; + } + return powerTenValue; +} + + +/** + * Set range with a specified 'exceedAmount'. + * Selected value is allowed to exceed minimum and maximum by exceedAmount. + * Any automatic formatting or decimals excludes the "exceed amount". + * + * @param minimum + * New minimum value. + * @param maximum + * New maximum value. + * @param exceedAmount + * The fixed exceed amount. + */ +void +WuQDoubleSpinBox::setRangeExceedable(double minimum, + double maximum, + double exceedAmount) +{ + setRangeExceedable(minimum, + maximum, + minimum - exceedAmount, + maximum + exceedAmount); } /** @@ -434,6 +522,7 @@ WuQDoubleSpinBox::setupRangePercentage(const double minimumPercentage, setDecimals(2); setSingleStepPercentage(0.1); setSuffix("%"); + setDataRangeToolTip(); } /** @@ -642,5 +731,81 @@ WuQDoubleSpinBox::valueChangedPrivate(double d) m_blockValueUpdateFlag = false; } +/** + * Set the tooltip for this spin box. After this + * tooltip, the range of data is displayed. + * + * @param tooltip + * Text for the tooltip. + */ +void +WuQDoubleSpinBox::setToolTip(const QString& tooltip) +{ + m_userToolTip = tooltip; + setDataRangeToolTip(); +} + +/** + * @return Text for a tooltip indicating range of data. + */ +void +WuQDoubleSpinBox::setDataRangeToolTip() const +{ + + AString s; + + if ( ! m_userToolTip.isEmpty()) { + s += (m_userToolTip + "\n"); + } + + s += QString("Data min/max: %1 %2").arg(doubleToString(m_minimumValue)).arg(doubleToString(m_maximumValue)); + + + switch (m_rangeMode) { + case RangeMode::EXCEEDABLE: + { + const double minVal = m_spinBox->minimum(); + const double maxVal = m_spinBox->maximum(); + s += (+ "\n" + + QString("Acceptable min/max: %1 %2").arg(doubleToString(minVal)).arg(doubleToString(maxVal))); + } break; + case RangeMode::INCLUSIVE: + break; + } + + m_spinBox->setToolTip(s); +} + +/** + * Convert the double to a string. If the value + * exceeds maximum float list as 'infinity'. + * + * @param value + * The double value. + * @return + * The string representation. + */ +QString +WuQDoubleSpinBox::doubleToString(const double value) const +{ + QString s; + + if (value >= std::numeric_limits::max()) { + s = "+infinity"; + } + else if (value <= -std::numeric_limits::max()) { + s = "-infinity"; + } + else { + s = QString("%1").arg(value, 0, 'f'); + s = NumericTextFormatting::cleanZerosInValueText(s); + s += m_spinBox->suffix(); + } + + return s; +} + + + // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h index 2b8198322..18c5a56c7 100644 --- a/src/GuiQt/WuQDoubleSpinBox.h +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -104,17 +104,16 @@ namespace caret { void setDecimalsModeAuto(); - void setMaximum(double max); - - void setMinimum(double min); - void setPrefix(const QString &prefix); void setRange(double minimum, double maximum); void setRangeExceedable(double minimum, double maximum, - double rangeMultiplier); + double exceedAmount); + + void setRangeExceedable(double minimum, + double maximum); void setupRangePercentage(const double minimumPercentage, const double maximumPercentage); @@ -139,6 +138,8 @@ namespace caret { virtual double valueFromText(const QString &text) const; + virtual void setToolTip(const QString& tooltip); + // ADD_NEW_METHODS_HERE public slots: @@ -173,6 +174,22 @@ namespace caret { void testDigitsRightOfDecimal(); + double computeExceedRange(const double minValue, + const double maxValue); + + QString doubleToString(const double value) const; + + void testExceedRange(); + + void setRangeExceedable(const double dataMinimum, + const double dataMaximum, + const double spinBoxMinimum, + const double spinBoxMaximum); + + double makePowerOfTen(const double value) const; + + void setDataRangeToolTip() const; + QDoubleSpinBox* m_spinBox; RangeMode m_rangeMode = RangeMode::INCLUSIVE; @@ -187,10 +204,10 @@ namespace caret { double m_maximumValue = 99.0; - double m_exceedRangeMultiplier = 0.0; - bool m_blockValueUpdateFlag = false; + QString m_userToolTip; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/WuQWidget.h b/src/GuiQt/WuQWidget.h index 08e6c14ed..5ffe7fffd 100644 --- a/src/GuiQt/WuQWidget.h +++ b/src/GuiQt/WuQWidget.h @@ -39,7 +39,7 @@ namespace caret { virtual QWidget* getWidget() = 0; - void setToolTip(const QString& tooltip); + virtual void setToolTip(const QString& tooltip); void setFixedWidth(int w); -- GitLab From 1e0e766c8ca70d4115c394ec8fcb28d85e5e43ff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 31 Aug 2017 14:17:27 -0500 Subject: [PATCH 368/755] Add separator between off and on items in Annotations Mode pop-up menu. --- src/GuiQt/UserInputModeAnnotationsContextMenu.cxx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index fcec0b043..298eb7669 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -229,10 +229,19 @@ m_newAnnotationCreatedByContextMenu(NULL) addSeparator(); /* - * Turn on/off display in tabs + * Turn off display in tabs */ QAction* turnOffTabDisplayAction = addAction("Turn Off Chart/Stereotaxic/Surface Annotation Display in Other Tabs", this, SLOT(turnOffDisplayInOtherTabs())); + + /* + * Separator + */ + addSeparator(); + + /* + * Turn on display in tabs + */ QAction* turnOnTabDisplayAction = addAction("Turn On Chart/Stereotaxic/Surface Annotation Display in All Tabs", this, SLOT(turnOnDisplayInAllTabs())); turnOffTabDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); -- GitLab From b72ea5e08becc1250e15813a21a76c16fb461cd7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 31 Aug 2017 14:18:32 -0500 Subject: [PATCH 369/755] In Features Toolbox : Annotations, default the Display Group to 'Tab'. --- src/Brain/DisplayPropertiesAnnotation.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index fd7a5f1fa..ff0f1fed6 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -135,7 +135,7 @@ DisplayPropertiesAnnotation::resetPrivate() m_displayWindowAnnotationsInSingleTabViews[i] = true; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { - m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); + m_displayGroup[i] = DisplayGroupEnum::DISPLAY_GROUP_TAB; } } -- GitLab From 60a0560bdd5856cba079c2eab20a257d298c55ec Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Sep 2017 11:51:44 -0500 Subject: [PATCH 370/755] Split up tab yoking into two groups: (1) 'Yoking' contains Montage, Volume, All, and Surface; (2) 'Chart Yoking' contains Chart and Chart Old. 'Yoking' Defaults to 'Group A' and 'Chart Yoking' defaults to 'Off'. --- src/Brain/BrowserTabContent.cxx | 301 +++++++++++++----- src/Brain/BrowserTabContent.h | 25 +- src/Brain/ChartTwoOverlaySet.cxx | 28 +- .../EventChartTwoAttributesChanged.cxx | 41 ++- src/Charting/EventChartTwoAttributesChanged.h | 14 +- src/Common/EventManager.cxx | 1 - src/Common/EventTypeEnum.cxx | 4 - src/Common/EventTypeEnum.h | 2 - src/GuiQt/BrainBrowserWindowToolBar.cxx | 64 ++-- src/GuiQt/BrainBrowserWindowToolBar.h | 2 + ...BrowserWindowToolBarChartTwoAttributes.cxx | 2 +- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 2 +- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 40 ++- .../BrainBrowserWindowToolBarChartTwoTitle.h | 4 +- src/GuiQt/BrainBrowserWindowToolBarTab.cxx | 62 +++- src/GuiQt/BrainBrowserWindowToolBarTab.h | 3 + src/GuiQt/CMakeLists.txt | 2 - src/GuiQt/EventUpdateYokedWindows.cxx | 93 ------ src/GuiQt/EventUpdateYokedWindows.h | 69 ---- src/GuiQt/UserInputModeView.cxx | 29 +- 20 files changed, 452 insertions(+), 336 deletions(-) delete mode 100644 src/GuiQt/EventUpdateYokedWindows.cxx delete mode 100644 src/GuiQt/EventUpdateYokedWindows.h diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 2eee77f44..05b2bae2f 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -119,7 +119,8 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_guiName = ""; m_userName = ""; m_volumeSurfaceOutlineSetModel = new VolumeSurfaceOutlineSetModel(); - m_yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; m_identificationUpdatesVolumeSlices = prefs->isVolumeIdentificationDefaultedOn(); m_aspectRatio = 1.0; @@ -199,8 +200,10 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_sceneClassAssistant->add("m_aspectRatioLocked", &m_aspectRatioLocked); - m_sceneClassAssistant->add("m_yokingGroup", - &m_yokingGroup); + m_sceneClassAssistant->add("m_brainModelYokingGroup", + &m_brainModelYokingGroup); + m_sceneClassAssistant->add("m_chartModelYokingGroup", + &m_chartModelYokingGroup); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET); EventManager::get()->addEventListener(this, @@ -215,7 +218,8 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) * Need to be done from here */ if (prefs->isYokingDefaultedOn()) { - setYokingGroup(YokingGroupEnum::YOKING_GROUP_A); + setBrainModelYokingGroup(YokingGroupEnum::YOKING_GROUP_A); + setChartModelYokingGroup(YokingGroupEnum::YOKING_GROUP_OFF); } } @@ -281,7 +285,8 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) *m_clippingPlaneGroup = *tabToClone->m_clippingPlaneGroup; - m_yokingGroup = tabToClone->m_yokingGroup; + m_brainModelYokingGroup = tabToClone->m_brainModelYokingGroup; + m_chartModelYokingGroup = tabToClone->m_chartModelYokingGroup; m_aspectRatio = tabToClone->m_aspectRatio; m_aspectRatioLocked = tabToClone->m_aspectRatioLocked; @@ -2079,7 +2084,7 @@ void BrowserTabContent::setTranslation( const float translation[3]) { getViewingTransformation()->setTranslation(translation); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -2100,7 +2105,7 @@ BrowserTabContent::setTranslation(const float translationX, getViewingTransformation()->setTranslation(translationX, translationY, translationZ); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2121,7 +2126,7 @@ void BrowserTabContent::setScaling(const float scaling) { return getViewingTransformation()->setScaling(scaling); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2143,7 +2148,7 @@ void BrowserTabContent::setRotationMatrix(const Matrix4x4& rotationMatrix) { getViewingTransformation()->setRotationMatrix(rotationMatrix); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2166,7 +2171,7 @@ BrowserTabContent::setObliqueVolumeRotationMatrix(const Matrix4x4& obliqueRotati { *m_obliqueVolumeRotationMatrix = obliqueRotationMatrix; - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -2197,7 +2202,7 @@ BrowserTabContent::setRightCortexFlatMapOffset(const float offsetX, const float offsetY) { getViewingTransformation()->setRightCortexFlatMapOffset(offsetX, offsetY); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -2231,7 +2236,7 @@ BrowserTabContent::resetView() if (isVolumeSlicesDisplayed()) { m_obliqueVolumeRotationMatrix->identity(); } - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2244,7 +2249,7 @@ BrowserTabContent::rightView() return; } getViewingTransformation()->rightView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2257,7 +2262,7 @@ BrowserTabContent::leftView() return; } getViewingTransformation()->leftView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2270,7 +2275,7 @@ BrowserTabContent::anteriorView() return; } getViewingTransformation()->anteriorView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2283,7 +2288,7 @@ BrowserTabContent::posteriorView() return; } getViewingTransformation()->posteriorView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2296,7 +2301,7 @@ BrowserTabContent::dorsalView() return; } getViewingTransformation()->dorsalView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2309,7 +2314,7 @@ BrowserTabContent::ventralView() return; } getViewingTransformation()->ventralView(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2656,7 +2661,7 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten viewingTransform->setRotationMatrix(rotationMatrix); } } - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -2719,7 +2724,7 @@ BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, } getViewingTransformation()->setScaling(scaling); } - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -3002,7 +3007,7 @@ BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportCon getViewingTransformation()->setTranslation(translation); } } - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -3208,7 +3213,7 @@ BrowserTabContent::setTransformationsFromModelTransform(const ModelTransform& mo const float rightFlatZoom = modelTransform.getRightCortexFlatMapZoomFactor(); setRightCortexFlatMapZoomFactor(rightFlatZoom); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } @@ -3268,9 +3273,28 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_A; + m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + m_sceneClassAssistant->restoreMembers(sceneAttributes, sceneClass); + /* + * With charting version two, yoking was split into chart and non-chart yoking + * If old yoking group is found, apply it to the brain model yoking group + */ + const AString oldYokingGroupName = sceneClass->getEnumeratedTypeValueAsString("m_yokingGroup", + "XXXXXX"); + if ( ! oldYokingGroupName.isEmpty()) { + bool validFlag = false; + const YokingGroupEnum::Enum oldYokeGroup = YokingGroupEnum::fromName(oldYokingGroupName, + &validFlag); + if (validFlag) { + m_brainModelYokingGroup = oldYokeGroup; + m_chartModelYokingGroup = oldYokeGroup; + } + } + m_obliqueVolumeRotationMatrix->identity(); float obliqueMatrix[16]; const int32_t numInObliqueArray = sceneClass->getFloatArrayValue("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); @@ -3506,6 +3530,7 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, } } } + } /** @@ -3577,7 +3602,7 @@ BrowserTabContent::setClippingPlaneEnabled(const bool xEnabled, m_clippingPlaneGroup->setVolumeSelected(volumeEnabled); m_clippingPlaneGroup->setFeaturesSelected(featuresEnabled); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -3625,7 +3650,7 @@ BrowserTabContent::setClippingPlaneTransformation(const float panning[3], m_clippingPlaneGroup->setDisplayClippingBoxSelected(displayClippingBox); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -3648,7 +3673,7 @@ void BrowserTabContent::resetClippingPlaneTransformation() { m_clippingPlaneGroup->resetTransformation(); - updateYokedBrowserTabs(); + updateYokedModelBrowserTabs(); } /** @@ -3702,7 +3727,7 @@ void BrowserTabContent::setSliceViewPlane(const VolumeSliceViewPlaneEnum::Enum slicePlane) { m_volumeSliceSettings->setSliceViewPlane(slicePlane); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3724,7 +3749,7 @@ void BrowserTabContent::setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout) { m_volumeSliceSettings->setSlicePlanesAllViewLayout(slicePlanesAllViewLayout); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3746,7 +3771,7 @@ void BrowserTabContent::setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType) { m_volumeSliceSettings->setSliceDrawingType(sliceDrawingType); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3768,7 +3793,7 @@ void BrowserTabContent::setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType) { m_volumeSliceSettings->setSliceProjectionType(sliceProjectionType); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3789,7 +3814,7 @@ void BrowserTabContent::setMontageNumberOfColumns(const int32_t montageNumberOfColumns) { m_volumeSliceSettings->setMontageNumberOfColumns(montageNumberOfColumns); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3810,7 +3835,7 @@ void BrowserTabContent::setMontageNumberOfRows(const int32_t montageNumberOfRows) { m_volumeSliceSettings->setMontageNumberOfRows(montageNumberOfRows); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3831,7 +3856,7 @@ void BrowserTabContent::setMontageSliceSpacing(const int32_t montageSliceSpacing) { m_volumeSliceSettings->setMontageSliceSpacing(montageSliceSpacing); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3841,7 +3866,7 @@ void BrowserTabContent::setSlicesToOrigin() { selectSlicesAtOrigin(); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3855,7 +3880,7 @@ BrowserTabContent::reset() m_volumeSliceSettings->reset(); m_obliqueVolumeRotationMatrix->identity(); } - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3877,7 +3902,7 @@ void BrowserTabContent::selectSlicesAtOrigin() { m_volumeSliceSettings->selectSlicesAtOrigin(); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3889,7 +3914,7 @@ void BrowserTabContent::selectSlicesAtCoordinate(const float xyz[3]) { m_volumeSliceSettings->selectSlicesAtCoordinate(xyz); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3913,7 +3938,7 @@ void BrowserTabContent::setIdentificationUpdatesVolumeSlices(const bool status) { m_identificationUpdatesVolumeSlices = status; - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3937,7 +3962,7 @@ BrowserTabContent::setSliceIndexAxial(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexAxial) { m_volumeSliceSettings->setSliceIndexAxial(volumeFile, sliceIndexAxial); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3962,7 +3987,7 @@ BrowserTabContent::setSliceIndexCoronal(const VolumeMappableInterface* volumeFil const int64_t sliceIndexCoronal) { m_volumeSliceSettings->setSliceIndexCoronal(volumeFile, sliceIndexCoronal); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -3987,7 +4012,7 @@ BrowserTabContent::setSliceIndexParasagittal(const VolumeMappableInterface* volu { m_volumeSliceSettings->setSliceIndexParasagittal(volumeFile, sliceIndexParasagittal); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4008,7 +4033,7 @@ void BrowserTabContent::setSliceCoordinateAxial(const float z) { m_volumeSliceSettings->setSliceCoordinateAxial(z); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4029,7 +4054,7 @@ void BrowserTabContent::setSliceCoordinateCoronal(const float y) { m_volumeSliceSettings->setSliceCoordinateCoronal(y); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4050,7 +4075,7 @@ void BrowserTabContent::setSliceCoordinateParasagittal(const float x) { m_volumeSliceSettings->setSliceCoordinateParasagittal(x); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4073,7 +4098,7 @@ void BrowserTabContent::setSliceParasagittalEnabled(const bool sliceEnabledParasagittal) { m_volumeSliceSettings->setSliceParasagittalEnabled(sliceEnabledParasagittal); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4096,7 +4121,7 @@ void BrowserTabContent::setSliceCoronalEnabled(const bool sliceEnabledCoronal) { m_volumeSliceSettings->setSliceCoronalEnabled(sliceEnabledCoronal); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4119,7 +4144,7 @@ void BrowserTabContent::setSliceAxialEnabled(const bool sliceEnabledAxial) { m_volumeSliceSettings->setSliceAxialEnabled(sliceEnabledAxial); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } @@ -4144,7 +4169,7 @@ void BrowserTabContent::setWholeBrainLeftEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setLeftEnabled(enabled); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4165,7 +4190,7 @@ void BrowserTabContent::setWholeBrainRightEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setRightEnabled(enabled); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4186,7 +4211,7 @@ void BrowserTabContent::setWholeBrainCerebellumEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setCerebellumEnabled(enabled); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4207,7 +4232,7 @@ void BrowserTabContent::setWholeBrainLeftRightSeparation(const float separation) { m_wholeBrainSurfaceSettings->setLeftRightSeparation(separation); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** @@ -4228,30 +4253,30 @@ void BrowserTabContent::setWholeBrainCerebellumSeparation(const float separation) { m_wholeBrainSurfaceSettings->setCerebellumSeparation(separation); - updateYokedBrowserTabs(); + updateBrainModelYokedBrowserTabs(); } /** - * @return Selected yoking group. + * @return Selected yoking group for charts */ YokingGroupEnum::Enum -BrowserTabContent::getYokingGroup() const +BrowserTabContent::getChartModelYokingGroup() const { - return m_yokingGroup; + return m_chartModelYokingGroup; } /** - * Set the selected yoking group. + * Set the selected yoking group for charts. * - * @param yokingGroup + * @param chartModelYokingType * New value for yoking group. */ void -BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) +BrowserTabContent::setChartModelYokingGroup(const YokingGroupEnum::Enum chartModelYokingType) { - m_yokingGroup = yokingGroup; + m_chartModelYokingGroup = chartModelYokingType; - if (m_yokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } @@ -4266,21 +4291,13 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) iter++) { BrowserTabContent* btc = *iter; if (btc != this) { - if (btc->getYokingGroup() == m_yokingGroup) { + if (btc->getChartModelYokingGroup() == m_chartModelYokingGroup) { copyFromTabIndex = btc->getTabNumber(); /* * If anything is added, also need to update updateYokedBrowserTabs() */ - *m_viewingTransformation = *btc->m_viewingTransformation; - *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; - *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; - *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; *m_chartTwoMatrixViewingTranformation = *btc->m_chartTwoMatrixViewingTranformation; *m_chartTwoMatrixDisplayProperties = *btc->m_chartTwoMatrixDisplayProperties; - *m_volumeSliceSettings = *btc->m_volumeSliceSettings; - *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; - *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; - m_identificationUpdatesVolumeSlices = btc->m_identificationUpdatesVolumeSlices; break; } } @@ -4298,26 +4315,125 @@ BrowserTabContent::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) } /** - * @return Is this browser tab yoked? + * @return Selected yoking group for brain models (surface or volumes) + */ +YokingGroupEnum::Enum +BrowserTabContent::getBrainModelYokingGroup() const +{ + return m_brainModelYokingGroup; +} + +/** + * Set the selected yoking group for brain models (surface or volumes) + * + * @param brainModelYokingType + * New value for yoking group. + */ +void +BrowserTabContent::setBrainModelYokingGroup(const YokingGroupEnum::Enum brainModelYokingType) +{ + m_brainModelYokingGroup = brainModelYokingType; + + if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + return; + } + + int32_t copyFromTabIndex = -1; + + /* + * Find another browser tab using the same yoking as 'me' and copy + * yoked data from the other browser tab. + */ + for (std::set::iterator iter = s_allBrowserTabContent.begin(); + iter != s_allBrowserTabContent.end(); + iter++) { + BrowserTabContent* btc = *iter; + if (btc != this) { + if (btc->getBrainModelYokingGroup() == m_brainModelYokingGroup) { + copyFromTabIndex = btc->getTabNumber(); + /* + * If anything is added, also need to update updateYokedBrowserTabs() + */ + *m_viewingTransformation = *btc->m_viewingTransformation; + *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; + *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; + *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; + *m_volumeSliceSettings = *btc->m_volumeSliceSettings; + *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; + *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; + m_identificationUpdatesVolumeSlices = btc->m_identificationUpdatesVolumeSlices; + break; + } + } + } +} + +/** + * @return Is this browser tab brain model yoked? */ bool -BrowserTabContent::isYoked() const +BrowserTabContent::isBrainModelYoked() const { - const bool yoked = (m_yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF); + const bool yoked = (m_brainModelYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF); return yoked; } /** - * Update other browser tabs with yoked data. + * @return Is this browser tab chart model yoked? + */ +bool +BrowserTabContent::isChartModelYoked() const +{ + const bool yoked = (m_chartModelYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF); + return yoked; +} + +/** + * Update other browser tabs with brain or chart yoked data dependent upon active model + */ +void +BrowserTabContent::updateYokedModelBrowserTabs() +{ + bool chartFlag = false; + + switch (getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + break; + } + + if (chartFlag) { + updateChartModelYokedBrowserTabs(); + } + else { + updateBrainModelYokedBrowserTabs(); + } +} + +/** + * Update other browser tabs with brain model yoked data. */ void -BrowserTabContent::updateYokedBrowserTabs() +BrowserTabContent::updateBrainModelYokedBrowserTabs() { if (isExecutingConstructor) { return; } - if (m_yokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } @@ -4332,13 +4448,11 @@ BrowserTabContent::updateYokedBrowserTabs() /* * If anything is added, also need to update setYokingGroup() */ - if (btc->getYokingGroup() == m_yokingGroup) { + if (btc->getBrainModelYokingGroup() == m_brainModelYokingGroup) { *btc->m_viewingTransformation = *m_viewingTransformation; *btc->m_flatSurfaceViewingTransformation = *m_flatSurfaceViewingTransformation; *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; - *btc->m_chartTwoMatrixViewingTranformation = *m_chartTwoMatrixViewingTranformation; - *btc->m_chartTwoMatrixDisplayProperties = *m_chartTwoMatrixDisplayProperties; *btc->m_volumeSliceSettings = *m_volumeSliceSettings; *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; @@ -4348,6 +4462,39 @@ BrowserTabContent::updateYokedBrowserTabs() } } +/** + * Update other browser tabs with brain model yoked data. + */ +void +BrowserTabContent::updateChartModelYokedBrowserTabs() +{ + if (isExecutingConstructor) { + return; + } + + if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + return; + } + + /* + * Copy yoked data from 'me' to all other yoked browser tabs + */ + for (std::set::iterator iter = s_allBrowserTabContent.begin(); + iter != s_allBrowserTabContent.end(); + iter++) { + BrowserTabContent* btc = *iter; + if (btc != this) { + /* + * If anything is added, also need to update setYokingGroup() + */ + if (btc->getChartModelYokingGroup() == m_chartModelYokingGroup) { + *btc->m_chartTwoMatrixViewingTranformation = *m_chartTwoMatrixViewingTranformation; + *btc->m_chartTwoMatrixDisplayProperties = *m_chartTwoMatrixDisplayProperties; + } + } + } +} + diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 2722636a7..f2a9135cb 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -371,13 +371,19 @@ namespace caret { void reset(); - void updateYokedBrowserTabs(); + void updateChartModelYokedBrowserTabs(); - bool isYoked() const; + bool isBrainModelYoked() const; - YokingGroupEnum::Enum getYokingGroup() const; + bool isChartModelYoked() const; - void setYokingGroup(const YokingGroupEnum::Enum yokingType); + YokingGroupEnum::Enum getBrainModelYokingGroup() const; + + void setBrainModelYokingGroup(const YokingGroupEnum::Enum brainModelYokingType); + + YokingGroupEnum::Enum getChartModelYokingGroup() const; + + void setChartModelYokingGroup(const YokingGroupEnum::Enum chartModelYokingType); bool isWholeBrainLeftEnabled() const; @@ -434,6 +440,10 @@ namespace caret { const ViewingTransformations* getViewingTransformation() const; + void updateBrainModelYokedBrowserTabs(); + + void updateYokedModelBrowserTabs(); + AString getDefaultName() const; /** Number of this tab */ @@ -484,8 +494,11 @@ namespace caret { */ Matrix4x4* m_obliqueVolumeRotationMatrix; - /** Yoking group */ - YokingGroupEnum::Enum m_yokingGroup; + /** Brain Model Yoking group */ + YokingGroupEnum::Enum m_brainModelYokingGroup; + + /** Chart Model Yoking group */ + YokingGroupEnum::Enum m_chartModelYokingGroup; /** Volume Surface Outlines */ VolumeSurfaceOutlineSetModel* m_volumeSurfaceOutlineSetModel; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 94fc19869..da2476a4f 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -594,7 +594,7 @@ ChartTwoOverlaySet::receiveEvent(Event* event) EventManager::get()->sendEvent(tabEvent.getPointer()); const BrowserTabContent* btc = tabEvent.getBrowserTab(); if (btc != NULL) { - const YokingGroupEnum::Enum tabYoking = btc->getYokingGroup(); + const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) && (yokingGroup == tabYoking) @@ -617,6 +617,32 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } } break; + case EventChartTwoAttributesChanged::Mode::TITLE: + { + YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + ChartTwoTitle* chartTitle = NULL; + attributeEvent->getTitleChanged(yokingGroup, + chartTwoDataType, + chartTitle); + + /* + * Only tabs in the windows are valid + */ + EventBrowserTabGet tabEvent(m_tabIndex); + EventManager::get()->sendEvent(tabEvent.getPointer()); + const BrowserTabContent* btc = tabEvent.getBrowserTab(); + if (btc != NULL) { + const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); + + if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) + && (yokingGroup == tabYoking) + && (m_chartDataType == chartTwoDataType)) { + *m_title = *chartTitle; + } + } + } + break; } attributeEvent->setEventProcessed(); diff --git a/src/Charting/EventChartTwoAttributesChanged.cxx b/src/Charting/EventChartTwoAttributesChanged.cxx index 325021a5e..dc439e913 100644 --- a/src/Charting/EventChartTwoAttributesChanged.cxx +++ b/src/Charting/EventChartTwoAttributesChanged.cxx @@ -76,6 +76,7 @@ EventChartTwoAttributesChanged::setCartesianAxisChanged(const YokingGroupEnum::E const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoCartesianAxis* cartesianAxis) { + CaretAssert(cartesianAxis); m_mode = Mode::CARTESIAN_AXIS; m_yokingGroup = yokingGroup; m_chartTwoDataType = chartTwoDataType; @@ -95,7 +96,7 @@ EventChartTwoAttributesChanged::setCartesianAxisChanged(const YokingGroupEnum::E void EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, - ChartTwoCartesianAxis* &cartesianAxisOut) + ChartTwoCartesianAxis* &cartesianAxisOut) const { CaretAssert(m_mode == Mode::CARTESIAN_AXIS); yokingGroupOut = m_yokingGroup; @@ -103,4 +104,42 @@ EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &y cartesianAxisOut = m_cartesianAxis; } +/** + * Set for a change in a title. + * + * @param yokingGroup + * Selected yoking group. + * @param chartTwoDataType + * Type of chart. + */ +void +EventChartTwoAttributesChanged::setTitleChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const ChartTwoTitle* chartTitle) +{ + CaretAssert(chartTitle); + m_mode = Mode::TITLE; + m_yokingGroup = yokingGroup; + m_chartTwoDataType = chartTwoDataType; + m_chartTitle = const_cast(chartTitle); +} + +/** + * Get for a change in title. + * + * @param yokingGroupOut + * Selected yoking group. + * @param chartTwoDataTypeOut + * Type of chart. + */ +void +EventChartTwoAttributesChanged::getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + ChartTwoTitle* &chartTitleOut) const +{ + CaretAssert(m_mode == Mode::TITLE); + yokingGroupOut = m_yokingGroup; + chartTwoDataTypeOut = m_chartTwoDataType; + chartTitleOut = m_chartTitle; +} diff --git a/src/Charting/EventChartTwoAttributesChanged.h b/src/Charting/EventChartTwoAttributesChanged.h index 799e8426f..07c558b76 100644 --- a/src/Charting/EventChartTwoAttributesChanged.h +++ b/src/Charting/EventChartTwoAttributesChanged.h @@ -33,12 +33,14 @@ namespace caret { class ChartTwoCartesianAxis; + class ChartTwoTitle; class EventChartTwoAttributesChanged : public Event { public: enum class Mode { INVALID, - CARTESIAN_AXIS + CARTESIAN_AXIS, + TITLE }; EventChartTwoAttributesChanged(); @@ -53,9 +55,15 @@ namespace caret { void getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, - ChartTwoCartesianAxis* &cartesianAxisOut); + ChartTwoCartesianAxis* &cartesianAxisOut) const; + void setTitleChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const ChartTwoTitle* chartTitle); + void getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + ChartTwoTitle* &chartTitleOut) const; // ADD_NEW_METHODS_HERE @@ -72,6 +80,8 @@ namespace caret { ChartTwoCartesianAxis* m_cartesianAxis = NULL; + ChartTwoTitle* m_chartTitle = NULL; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 0a708cd92..d5db2d190 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -538,7 +538,6 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_USER_INTERFACE_UPDATE: case EventTypeEnum::EVENT_PROGRESS_UPDATE: case EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS: - case EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS: case EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR: { const AString msg(EventTypeEnum::toName(eventType) diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 1b0aef70d..4870565ef 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -354,10 +354,6 @@ EventTypeEnum::initialize() "EVENT_UPDATE_INFORMATION_WINDOWS", "Update the information windows")); - enumData.push_back(EventTypeEnum(EVENT_UPDATE_YOKED_WINDOWS, - "EVENT_UPDATE_YOKED_WINDOWS", - "Update yoked windows graphics and toolbar")); - enumData.push_back(EventTypeEnum(EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, "EVENT_UPDATE_VOLUME_EDITING_TOOLBAR", "Update the volume editing toolbar")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 56527e8bb..9ead53ca2 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -184,8 +184,6 @@ public: EVENT_PROGRESS_UPDATE, /** Update the information windows */ EVENT_UPDATE_INFORMATION_WINDOWS, - /** Event to update yoked windows (graphics and toolbar) */ - EVENT_UPDATE_YOKED_WINDOWS, /** Update the volume editing toolbar */ EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, /* THIS MUST ALWAYS BE LAST - NOT an event type but is number of event types */ diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 996d7cace..28e25169d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -91,7 +91,6 @@ #include "EventManager.h" #include "EventModelGetAll.h" #include "EventSurfaceColoringInvalidate.h" -#include "EventUpdateYokedWindows.h" #include "GuiManager.h" #include "Model.h" #include "ModelChart.h" @@ -440,7 +439,6 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } @@ -1384,6 +1382,14 @@ BrainBrowserWindowToolBar::updateToolBar() if (this->isDestructionInProgress) { return; } + + if (m_performingUpdateFlag) { + const AString msg("During an update of the toolbar, a signal was issued and needs to be blocked.\n" + "Set a break on this line and go through the call stack to find where the\n" + "signal was emitted."); + CaretLogSevere(msg); + } + m_performingUpdateFlag = true; /* * If there are no models, close all but the first tab. @@ -1583,6 +1589,8 @@ BrainBrowserWindowToolBar::updateToolBar() } } } + + m_performingUpdateFlag = false; } /** @@ -3355,7 +3363,6 @@ BrainBrowserWindowToolBar::orientationLeftOrLateralToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3369,7 +3376,6 @@ BrainBrowserWindowToolBar::orientationRightOrMedialToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->rightView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3383,7 +3389,6 @@ BrainBrowserWindowToolBar::orientationAnteriorToolButtonTriggered(bool /*checked { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3397,7 +3402,6 @@ BrainBrowserWindowToolBar::orientationPosteriorToolButtonTriggered(bool /*checke { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->posteriorView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3411,7 +3415,6 @@ BrainBrowserWindowToolBar::orientationDorsalToolButtonTriggered(bool /*checked*/ { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3425,7 +3428,6 @@ BrainBrowserWindowToolBar::orientationVentralToolButtonTriggered(bool /*checked* { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->ventralView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3443,7 +3445,6 @@ BrainBrowserWindowToolBar::orientationResetToolButtonTriggered(bool /*checked*/) Model* mdc = btc->getModelForDisplay(); if (mdc != NULL) { this->updateVolumeIndicesWidget(btc); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3458,7 +3459,6 @@ BrainBrowserWindowToolBar::orientationLateralMedialToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3472,7 +3472,6 @@ BrainBrowserWindowToolBar::orientationDorsalVentralToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3486,7 +3485,6 @@ BrainBrowserWindowToolBar::orientationAnteriorPosteriorToolButtonTriggered(bool { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); this->checkUpdateCounter(); @@ -3530,7 +3528,6 @@ BrainBrowserWindowToolBar::customViewActionTriggered() if (prefs->getCustomView(customViewName, modelTransform)) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setTransformationsFromModelTransform(modelTransform); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } } @@ -3562,7 +3559,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx* if (isValid) { wholeBrainModel->setSelectedSurfaceType(tabIndex, surfaceType); this->updateVolumeIndicesWidget(btc); /* slices may get deselected */ - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } } @@ -3585,7 +3581,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state } btc->setWholeBrainLeftEnabled(this->wholeBrainSurfaceLeftCheckBox->isChecked()); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3636,7 +3631,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*check wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_LEFT, tabIndex, surfaces[i]); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); break; } @@ -3695,7 +3689,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*chec wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_RIGHT, tabIndex, surfaces[i]); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); break; } @@ -3754,7 +3747,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool / wholeBrainModel->setSelectedSurface(StructureEnum::CEREBELLUM, tabIndex, surfaces[i]); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); break; } @@ -3781,7 +3773,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightCheckBoxStateChanged(int /*stat } btc->setWholeBrainRightEnabled(this->wholeBrainSurfaceRightCheckBox->isChecked()); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3802,7 +3793,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumCheckBoxStateChanged(int / } btc->setWholeBrainCerebellumEnabled(this->wholeBrainSurfaceCerebellumCheckBox->isChecked()); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3823,7 +3813,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationLeftRightSpinBoxValueChang } btc->setWholeBrainLeftRightSeparation(this->wholeBrainSurfaceSeparationLeftRightSpinBox->value()); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3844,7 +3833,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationCerebellumSpinBoxSelected( } btc->setWholeBrainCerebellumSeparation(this->wholeBrainSurfaceSeparationCerebellumSpinBox->value()); - this->updateGraphicsWindow(); this->updateOtherYokedWindows(); } @@ -3976,21 +3964,6 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) } tabEvent->setEventProcessed(); } - else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS) { - EventUpdateYokedWindows* yokeUpdateEvent = - dynamic_cast(event); - CaretAssert(yokeUpdateEvent); - - BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); - if (browserTabContent != NULL) { - if (this->browserWindowIndex != yokeUpdateEvent->getBrowserWindowIndexThatIssuedEvent()) { - if (browserTabContent->getYokingGroup() == yokeUpdateEvent->getYokingGroup()) { - this->updateToolBar(); - this->updateGraphicsWindow(); - } - } - } - } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED) { EventBrowserTabGetAllViewed* viewedTabsEvent = dynamic_cast(event); CaretAssert(viewedTabsEvent); @@ -4031,13 +4004,16 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) void BrainBrowserWindowToolBar::updateOtherYokedWindows() { - BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); - if (browserTabContent != NULL) { - if (browserTabContent->isYoked()) { - EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, - browserTabContent->getYokingGroup()).getPointer()); - } - } + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + +// BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); +// if (browserTabContent != NULL) { +// if (browserTabContent->isYoked()) { +// EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, +// browserTabContent->getBrainModelYokingGroup()).getPointer()); +// } +// } } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 3156c9f0e..5414c5d4b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -438,6 +438,8 @@ namespace caret { bool isContructorFinished; bool isDestructionInProgress; + + bool m_performingUpdateFlag = false; }; } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx index 86fa695ab..5c19c11bb 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx @@ -363,7 +363,7 @@ MatrixChartTwoAttributesWidget::valueChanged() BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); CaretAssert(tabContent); - tabContent->updateYokedBrowserTabs(); + tabContent->updateChartModelYokedBrowserTabs(); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index adcbb1846..1caa8226d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -588,7 +588,7 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); CaretAssert(tabContent); - const YokingGroupEnum::Enum yokingGroup = tabContent->getYokingGroup(); + const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); CaretAssert(modelChartTwo); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 2b7878af9..f3d790b0c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -36,6 +36,8 @@ #include "CaretAssert.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoTitle.h" +#include "EventChartTwoAttributesChanged.h" +#include "EventManager.h" #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" @@ -59,8 +61,8 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B { m_showTitleCheckBox = new QCheckBox("Show Title"); m_showTitleCheckBox->setToolTip("Show the title at the top of the chart"); - QObject::connect(m_showTitleCheckBox, &QCheckBox::toggled, - this, &BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxToggled); + QObject::connect(m_showTitleCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxClicked); QAction* editTitleAction = new QAction("Edit Title..."); editTitleAction->setToolTip("Edit the chart title in a dialog"); @@ -146,19 +148,18 @@ BrainBrowserWindowToolBarChartTwoTitle::updateContent(BrowserTabContent* browser } /** - * Called when show title checkbox is toggled. + * Called when show title checkbox is clicked. * * @param checked * Status of checkbox. */ void -BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxToggled(bool checked) +BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxClicked(bool checked) { if (m_chartOverlaySet != NULL) { ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); chartTitle->setDisplayed(checked); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->performUpdating(); } } @@ -172,8 +173,7 @@ BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged(double) ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); chartTitle->setTextSize(m_titleSizeSpinBox->value()); chartTitle->setPaddingSize(m_paddingSizeSpinBox->value()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->performUpdating(); } } @@ -191,9 +191,29 @@ BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered() if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); m_chartOverlaySet->getChartTitle()->setText(name); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->performUpdating(); } } } +void +BrainBrowserWindowToolBarChartTwoTitle::performUpdating() +{ + const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); + CaretAssert(tabContent); + + const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); + if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { + const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); + CaretAssert(modelChartTwo); + const int32_t tabIndex = tabContent->getTabNumber(); + + EventChartTwoAttributesChanged attributesEvent; + attributesEvent.setTitleChanged(yokingGroup, + modelChartTwo->getSelectedChartTwoDataType(tabIndex), + m_chartOverlaySet->getChartTitle()); + EventManager::get()->sendEvent(attributesEvent.getPointer()); + } + + this->updateOtherYokedWindows(); +} diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h index 9bd0379c5..cf803400f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h @@ -46,7 +46,7 @@ namespace caret { private slots: void editTitleActionTriggered(); - void showTitleCheckBoxToggled(bool); + void showTitleCheckBoxClicked(bool); void sizeSpinBoxValueChanged(double); @@ -55,6 +55,8 @@ namespace caret { BrainBrowserWindowToolBarChartTwoTitle& operator=(const BrainBrowserWindowToolBarChartTwoTitle&); + void performUpdating(); + QCheckBox* m_showTitleCheckBox; WuQDoubleSpinBox* m_titleSizeSpinBox; diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx index c8e3ff31d..3e2794e10 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx @@ -77,7 +77,7 @@ m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) "Surface Yoking is applied to Surface, Surface Montage\n" "and Whole Brain. Volume Yoking is applied to Volumes.")); - QLabel* yokeToLabel = new QLabel("Yoking:"); + m_yokeToLabel = new QLabel("Yoking:"); QObject::connect(m_yokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokeToGroupComboBoxIndexChanged())); @@ -91,13 +91,13 @@ m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); - layout->addWidget(yokeToLabel); + layout->addWidget(m_yokeToLabel); layout->addWidget(m_yokingGroupComboBox->getWidget()); layout->addSpacing(15); layout->addWidget(windowAspectRatioLockedToolButton); layout->addWidget(tabAspectRatioLockedToolButton); - addToWidgetGroup(yokeToLabel); + addToWidgetGroup(m_yokeToLabel); addToWidgetGroup(m_yokingGroupComboBox->getWidget()); } @@ -119,7 +119,34 @@ BrainBrowserWindowToolBarTab::updateContent(BrowserTabContent* browserTabContent { blockAllSignals(true); - m_yokingGroupComboBox->setSelectedItem(browserTabContent->getYokingGroup()); + bool chartFlag = false; + switch (browserTabContent->getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + break; + } + + if (chartFlag) { + m_yokeToLabel->setText("Chart Yoking:"); + m_yokingGroupComboBox->setSelectedItem(browserTabContent->getChartModelYokingGroup()); + } + else { + m_yokeToLabel->setText("Yoking:"); + m_yokingGroupComboBox->setSelectedItem(browserTabContent->getBrainModelYokingGroup()); + } m_tabAspectRatioLockedAction->blockSignals(true); m_tabAspectRatioLockedAction->setChecked(browserTabContent->isAspectRatioLocked()); m_tabAspectRatioLockedAction->blockSignals(false); @@ -138,8 +165,33 @@ BrainBrowserWindowToolBarTab::yokeToGroupComboBoxIndexChanged() return; } + bool chartFlag = false; + switch (browserTabContent->getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + chartFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + break; + } + YokingGroupEnum::Enum yokingGroup = m_yokingGroupComboBox->getSelectedItem(); - browserTabContent->setYokingGroup(yokingGroup); + if (chartFlag) { + browserTabContent->setChartModelYokingGroup(yokingGroup); + } + else { + browserTabContent->setBrainModelYokingGroup(yokingGroup); + } m_parentToolBar->updateToolBarComponents(browserTabContent); diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.h b/src/GuiQt/BrainBrowserWindowToolBarTab.h index 0c11823a9..aefac6a99 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.h +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.h @@ -25,6 +25,7 @@ #include "BrainBrowserWindowToolBarComponent.h" +class QLabel; class QToolButton; namespace caret { @@ -55,6 +56,8 @@ namespace caret { BrainBrowserWindowToolBarTab& operator=(const BrainBrowserWindowToolBarTab&); + QLabel* m_yokeToLabel; + EnumComboBoxTemplate* m_yokingGroupComboBox; const int32_t m_browserWindowIndex; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 19ac8ffbf..f5883b3ec 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -326,7 +326,6 @@ EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h -EventUpdateYokedWindows.h EventUserInterfaceUpdate.h FiberOrientationSelectionViewController.h FiberSamplesOpenGLWidget.h @@ -539,7 +538,6 @@ EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx -EventUpdateYokedWindows.cxx EventUserInterfaceUpdate.cxx FiberOrientationSelectionViewController.cxx FiberSamplesOpenGLWidget.cxx diff --git a/src/GuiQt/EventUpdateYokedWindows.cxx b/src/GuiQt/EventUpdateYokedWindows.cxx deleted file mode 100644 index 5b6985a23..000000000 --- a/src/GuiQt/EventUpdateYokedWindows.cxx +++ /dev/null @@ -1,93 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ -#include "EventUpdateYokedWindows.h" -#undef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ - -#include "EventTypeEnum.h" - -using namespace caret; - - - -/** - * \class caret::EventUpdateYokedWindows - * \brief Updates windows that are yoked. - * \ingroup GuiQt - */ - -/** - * Constructor for a window. This given window will NOT be updated. - * - * @param browserWindowIndexThatIssuedEvent - * Index of browser window that issued event. - * @param yokingGroup - * Yoking group that is selected. - */ -EventUpdateYokedWindows::EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, - const YokingGroupEnum::Enum yokingGroup) -: Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), -m_browserWindowIndexThatIssuedEvent(browserWindowIndexThatIssuedEvent), -m_yokingGroup(yokingGroup) -{ -} - -/** - * Constructor for updating all windows. - * - * @param browserWindowIndexThatIssuedEvent - * Index of browser window that issued event. - * @param yokingGroup - * Yoking group that is selected. - */ -EventUpdateYokedWindows::EventUpdateYokedWindows(const YokingGroupEnum::Enum yokingGroup) -: Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), -m_browserWindowIndexThatIssuedEvent(-1), -m_yokingGroup(yokingGroup) -{ -} - -/** - * Destructor. - */ -EventUpdateYokedWindows::~EventUpdateYokedWindows() -{ - -} - -/** - * @return Index of browser window that issued the event. - */ -int32_t -EventUpdateYokedWindows::getBrowserWindowIndexThatIssuedEvent() const -{ - return m_browserWindowIndexThatIssuedEvent; -} - -/** - * @return The yoking group that should be updated. - */ -YokingGroupEnum::Enum -EventUpdateYokedWindows::getYokingGroup() const -{ - return m_yokingGroup; -} diff --git a/src/GuiQt/EventUpdateYokedWindows.h b/src/GuiQt/EventUpdateYokedWindows.h deleted file mode 100644 index fb3f207e5..000000000 --- a/src/GuiQt/EventUpdateYokedWindows.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __EVENT_UPDATE_YOKED_WINDOWS_H__ -#define __EVENT_UPDATE_YOKED_WINDOWS_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include "Event.h" -#include "YokingGroupEnum.h" - -namespace caret { - - class EventUpdateYokedWindows : public Event { - - public: - EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, - const YokingGroupEnum::Enum yokingGroup); - - EventUpdateYokedWindows(const YokingGroupEnum::Enum yokingGroup); - - virtual ~EventUpdateYokedWindows(); - - int32_t getBrowserWindowIndexThatIssuedEvent() const; - - YokingGroupEnum::Enum getYokingGroup() const; - - private: - EventUpdateYokedWindows(const EventUpdateYokedWindows&); - - EventUpdateYokedWindows& operator=(const EventUpdateYokedWindows&); - - public: - - // ADD_NEW_METHODS_HERE - - private: - - const int32_t m_browserWindowIndexThatIssuedEvent; - - const YokingGroupEnum::Enum m_yokingGroup; - - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ - // -#endif // __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ - -} // namespace -#endif //__EVENT_UPDATE_YOKED_WINDOWS_H__ diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index 94f88d5f3..c7af5e51a 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -33,7 +33,8 @@ #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EventGraphicsUpdateOneWindow.h" -#include "EventUpdateYokedWindows.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "MouseEvent.h" @@ -388,35 +389,31 @@ UserInputModeView::showContextMenu(const MouseEvent& mouseEvent, contextMenu.exec(menuPosition); } - - /** - * If this windows is yoked, issue an event to update other - * windows that are using the same yoking. + * Updated graphics. */ void UserInputModeView::updateGraphics(const MouseEvent& mouseEvent) { - bool issuedYokeEvent = false; if (mouseEvent.getViewportContent() != NULL) { BrowserTabContent* browserTabContent = mouseEvent.getViewportContent()->getBrowserTabContent(); - const int32_t browserWindowIndex = mouseEvent.getBrowserWindowIndex(); - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(browserWindowIndex).getPointer()); - if (browserTabContent != NULL) { - if (browserTabContent->isYoked()) { - issuedYokeEvent = true; - EventManager::get()->sendEvent(EventUpdateYokedWindows(browserTabContent->getYokingGroup()).getPointer()); + if (browserTabContent->isChartModelYoked() + || browserTabContent->isBrainModelYoked()) { + /* + * When yoked, need to update GUI and all windows + */ + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(mouseEvent.getBrowserWindowIndex()).getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + return; } } } /* - * If not yoked, just need to update graphics. + * Not yoked, just update graphics in this window */ - if (issuedYokeEvent == false) { - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(mouseEvent.getBrowserWindowIndex()).getPointer()); - } + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(mouseEvent.getBrowserWindowIndex()).getPointer()); } -- GitLab From 0272ae76fcbadea67a0c5ca332a22a43ab820836 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Sep 2017 12:01:46 -0500 Subject: [PATCH 371/755] Cleaned up code in toolbar that detects an improperly emitted signal when the toolbar is being updated. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 115 ++---------------------- src/GuiQt/BrainBrowserWindowToolBar.h | 16 +--- 2 files changed, 8 insertions(+), 123 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 28e25169d..5e560148c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -153,7 +153,6 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow : QToolBar(parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; - this->updateCounter = 0; m_tabIndexForTileTabsHighlighting = -1; this->isContructorFinished = false; @@ -1383,10 +1382,14 @@ BrainBrowserWindowToolBar::updateToolBar() return; } + /* + * If this is true, it indicates that one of the 'update' methods has mistakenly emitted a signal + * or an update. + */ if (m_performingUpdateFlag) { const AString msg("During an update of the toolbar, a signal was issued and needs to be blocked.\n" "Set a break on this line and go through the call stack to find where the\n" - "signal was emitted."); + "signal was emitted and block it."); CaretLogSevere(msg); } m_performingUpdateFlag = true; @@ -1402,8 +1405,6 @@ BrainBrowserWindowToolBar::updateToolBar() } } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); const ModelTypeEnum::Enum viewModel = this->updateViewWidget(browserTabContent); @@ -1558,12 +1559,6 @@ BrainBrowserWindowToolBar::updateToolBar() updateToolBarComponents(browserTabContent); - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); - - if (this->updateCounter != 0) { - CaretLogSevere("Update counter is non-zero at end of updateToolBar()"); - } - this->updateAllTabNames(); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); @@ -1694,8 +1689,6 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent modelType = browserTabContent->getSelectedModelType(); } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - this->viewWidgetGroup->blockAllSignals(true); /* @@ -1743,8 +1736,6 @@ BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent this->viewWidgetGroup->blockAllSignals(false); - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); - return modelType; } @@ -1966,8 +1957,6 @@ BrainBrowserWindowToolBar::updateOrientationWidget(BrowserTabContent* browserTab return; } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - const int32_t tabIndex = browserTabContent->getTabNumber(); this->orientationWidgetGroup->blockAllSignals(true); @@ -2111,8 +2100,6 @@ BrainBrowserWindowToolBar::updateOrientationWidget(BrowserTabContent* browserTab this->orientationPosteriorToolButton->setVisible(showSingleViewOrientationButtons); } this->orientationWidgetGroup->blockAllSignals(false); - - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); } /** @@ -2285,7 +2272,6 @@ BrainBrowserWindowToolBar::updateWholeBrainSurfaceOptionsWidget(BrowserTabConten if (this->wholeBrainSurfaceOptionsWidget->isHidden()) { return; } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); ModelWholeBrain* wholeBrainModel = browserTabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { @@ -2324,9 +2310,6 @@ BrainBrowserWindowToolBar::updateWholeBrainSurfaceOptionsWidget(BrowserTabConten this->wholeBrainSurfaceOptionsWidgetGroup->blockAllSignals(false); } - - - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); } /** @@ -2585,8 +2568,6 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte return; } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - this->modeWidgetGroup->blockAllSignals(true); EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); @@ -2619,8 +2600,6 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte this->modeWidgetGroup->blockAllSignals(false); this->updateDisplayedModeUserInputWidget(); - - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); } void @@ -3060,15 +3039,11 @@ BrainBrowserWindowToolBar::updateSingleSurfaceOptionsWidget(BrowserTabContent* b return; } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - this->singleSurfaceSelectionWidgetGroup->blockAllSignals(true); this->surfaceSurfaceSelectionControl->updateControl(browserTabContent->getSurfaceModelSelector()); this->singleSurfaceSelectionWidgetGroup->blockAllSignals(false); - - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); } /** @@ -3169,11 +3144,7 @@ BrainBrowserWindowToolBar::updateVolumeMontageWidget(BrowserTabContent* browserT return; } - this->incrementUpdateCounter(__CARET_FUNCTION_NAME__); - m_volumeMontageComponent->updateContent(browserTabContent); - - this->decrementUpdateCounter(__CARET_FUNCTION_NAME__); } /** @@ -3319,7 +3290,6 @@ BrainBrowserWindowToolBar::updateToolBox() void BrainBrowserWindowToolBar::viewModeRadioButtonClicked(QAbstractButton*) { - CaretLogEntering(); BrowserTabContent* btc = this->getTabContentFromSelectedTab(); if (btc == NULL) { return; @@ -3347,7 +3317,6 @@ BrainBrowserWindowToolBar::viewModeRadioButtonClicked(QAbstractButton*) btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_INVALID); } - this->checkUpdateCounter(); this->updateToolBar(); this->updateTabName(-1); this->updateToolBox(); @@ -3364,8 +3333,6 @@ BrainBrowserWindowToolBar::orientationLeftOrLateralToolButtonTriggered(bool /*ch BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3377,8 +3344,6 @@ BrainBrowserWindowToolBar::orientationRightOrMedialToolButtonTriggered(bool /*ch BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->rightView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3390,8 +3355,6 @@ BrainBrowserWindowToolBar::orientationAnteriorToolButtonTriggered(bool /*checked BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3403,8 +3366,6 @@ BrainBrowserWindowToolBar::orientationPosteriorToolButtonTriggered(bool /*checke BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->posteriorView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3416,8 +3377,6 @@ BrainBrowserWindowToolBar::orientationDorsalToolButtonTriggered(bool /*checked*/ BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3429,8 +3388,6 @@ BrainBrowserWindowToolBar::orientationVentralToolButtonTriggered(bool /*checked* BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->ventralView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3447,8 +3404,6 @@ BrainBrowserWindowToolBar::orientationResetToolButtonTriggered(bool /*checked*/) this->updateVolumeIndicesWidget(btc); this->updateOtherYokedWindows(); } - - this->checkUpdateCounter(); } /** @@ -3460,8 +3415,6 @@ BrainBrowserWindowToolBar::orientationLateralMedialToolButtonTriggered(bool /*ch BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3473,8 +3426,6 @@ BrainBrowserWindowToolBar::orientationDorsalVentralToolButtonTriggered(bool /*ch BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3486,8 +3437,6 @@ BrainBrowserWindowToolBar::orientationAnteriorPosteriorToolButtonTriggered(bool BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); this->updateOtherYokedWindows(); - - this->checkUpdateCounter(); } /** @@ -3540,9 +3489,6 @@ BrainBrowserWindowToolBar::customViewActionTriggered() void BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); @@ -3570,9 +3516,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx* void BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); @@ -3590,9 +3533,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state void BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*checked*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { @@ -3646,11 +3586,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*check void BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*checked*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { @@ -3704,11 +3639,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*chec void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool /*checked*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { @@ -3762,9 +3692,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool / void BrainBrowserWindowToolBar::wholeBrainSurfaceRightCheckBoxStateChanged(int /*state*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); @@ -3782,9 +3709,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightCheckBoxStateChanged(int /*stat void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumCheckBoxStateChanged(int /*state*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); @@ -3802,9 +3726,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumCheckBoxStateChanged(int / void BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationLeftRightSpinBoxValueChanged(double /*d*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); @@ -3822,9 +3743,6 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationLeftRightSpinBoxValueChang void BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationCerebellumSpinBoxSelected(double /*d*/) { - CaretLogEntering(); - this->checkUpdateCounter(); - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); @@ -3859,29 +3777,6 @@ BrainBrowserWindowToolBar::surfaceSelectionControlChanged( } this->updateTabName(-1); - - this->checkUpdateCounter(); -} - -void -BrainBrowserWindowToolBar::checkUpdateCounter() -{ - if (this->updateCounter != 0) { - CaretLogWarning(AString("Update counter is non-zero, this indicates that signal needs to be blocked during update, value=") - + AString::number(updateCounter)); - } -} - -void -BrainBrowserWindowToolBar::incrementUpdateCounter(const char* /*methodName*/) -{ - this->updateCounter++; -} - -void -BrainBrowserWindowToolBar::decrementUpdateCounter(const char* /*methodName*/) -{ - this->updateCounter--; } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 5414c5d4b..60754f926 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -226,19 +226,6 @@ namespace caret { /** Is set to the user input widget provided by the user input processor */ QWidget* userInputControlsWidgetActiveInputWidget; - /** - * When updating, no signals should be emitted. This variable - * is incremented at the beginning of an update method and - * decremented at the end of the update method. If it is - * non-zero in a slot method, then a signal was emitted during - * the update and the widget that emitted the signal should - * have its signal blocked. - */ - void incrementUpdateCounter(const char* methodName); - void decrementUpdateCounter(const char* methodName); - void checkUpdateCounter(); - int updateCounter; - void removeAndReturnAllTabs(std::vector& allTabContent); void getAllTabContent(std::vector& allTabContent) const; @@ -439,6 +426,9 @@ namespace caret { bool isContructorFinished; bool isDestructionInProgress; + /** + * Tracks when update is performed to catch incorrectly emitted signals. + */ bool m_performingUpdateFlag = false; }; } -- GitLab From 58cfaab90c7dc87b41c8bc512a2725c6f47a6b57 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Sep 2017 16:38:24 -0500 Subject: [PATCH 372/755] Added percentage line width to line drawing of Histogram Envelope. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 8 +++-- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 1 + src/Files/ChartableTwoFileHistogramChart.cxx | 11 +++++-- src/Files/ChartableTwoFileHistogramChart.h | 9 +++++- .../MapSettingsPaletteColorMappingWidget.cxx | 16 ++++++++-- .../MapSettingsPaletteColorMappingWidget.h | 3 ++ src/Palette/PaletteColorMapping.cxx | 30 +++++++++++++++++++ src/Palette/PaletteColorMapping.h | 6 ++++ src/Palette/PaletteColorMappingSaxReader.cxx | 4 +++ src/Palette/PaletteColorMappingXmlElements.h | 1 + 10 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index f9e2018bf..f1f15f8e7 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -818,7 +818,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawInfo->m_allMapsSelected); if (histogramPrimitives != NULL) { - const float ENVELOPE_LINE_WIDTH = 1.0; + const float lineWidthPercentage = histogramPrimitives->getEnvelopeLineWidthPercentage(); + const float envelopeLineWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, + tabViewportHeight); if (m_identificationModeFlag) { int32_t primitiveIndex = -1; @@ -844,7 +846,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Increase line width for identification */ - BrainOpenGL::setLineWidth(ENVELOPE_LINE_WIDTH * 3.0f); + BrainOpenGL::setLineWidth(envelopeLineWidth * 3.0f); GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, @@ -868,7 +870,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { - BrainOpenGL::setLineWidth(ENVELOPE_LINE_WIDTH); + BrainOpenGL::setLineWidth(envelopeLineWidth); m_fixedPipelineDrawing->enableLineAntiAliasing(); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index cf8cd80e7..f9cb2bef2 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include #include "BrainOpenGLChartTwoDrawingInterface.h" #include "CaretColorEnum.h" diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 89d2ccf04..df22b05bb 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -610,7 +610,8 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m HistogramPrimitives* histogramPrimitives = new HistogramPrimitives(thresholdPrimitive, barsPrimitive, - envelopePrimitive); + envelopePrimitive, + paletteColorMapping->getHistogramEnvelopeLineWidthPercentage()); m_mapHistogramPrimitives.insert(std::make_pair(mapIndex, std::unique_ptr(histogramPrimitives))); @@ -678,14 +679,18 @@ ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives() * Graphics Primitive for drawing histogram bars. * @param envelopePrimitive * Graphics Primitive for drawing histogram envelope. + * @param envelopeLineWidthPercentage + * Line width percentage for drawing envelope. */ ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, - GraphicsPrimitiveV3fC4f* barsPrimitive, - GraphicsPrimitiveV3fC4f* envelopePrimitive) + GraphicsPrimitiveV3fC4f* barsPrimitive, + GraphicsPrimitiveV3fC4f* envelopePrimitive, + const float envelopeLineWidthPercentage) { m_thresholdPrimitive.reset(thresholdPrimitive); m_barsPrimitive.reset(barsPrimitive); m_envelopePrimitive.reset(envelopePrimitive); + m_envelopeLineWidthPercentage = envelopeLineWidthPercentage; } /* diff --git a/src/Files/ChartableTwoFileHistogramChart.h b/src/Files/ChartableTwoFileHistogramChart.h index 066ddd160..9e28bb43f 100644 --- a/src/Files/ChartableTwoFileHistogramChart.h +++ b/src/Files/ChartableTwoFileHistogramChart.h @@ -44,7 +44,8 @@ namespace caret { HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, GraphicsPrimitiveV3fC4f* barsPrimitive, - GraphicsPrimitiveV3fC4f* envelopePrimitive); + GraphicsPrimitiveV3fC4f* envelopePrimitive, + const float envelopeLineWidthPercentage); ~HistogramPrimitives(); @@ -66,10 +67,16 @@ namespace caret { */ GraphicsPrimitiveV3fC4f* getEnvelopePrimitive() { return m_envelopePrimitive.get(); } + /** + * @return Line width percentage for drawing envelope + */ + float getEnvelopeLineWidthPercentage() const { return m_envelopeLineWidthPercentage; } + private: std::unique_ptr m_thresholdPrimitive; std::unique_ptr m_barsPrimitive; std::unique_ptr m_envelopePrimitive; + float m_envelopeLineWidthPercentage = 1.0f; }; ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 8ec3d04c8..4f3ca3bb4 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -64,6 +64,7 @@ #include "WuQDataEntryDialog.h" #include "WuQWidgetObjectGroup.h" #include "WuQDoubleSlider.h" +#include "WuQDoubleSpinBox.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -766,7 +767,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() QObject::connect(m_histogramBarsColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); - QLabel* envelopeColorLabel = new QLabel("Envelope Color"); + QLabel* envelopeColorLabel = new QLabel("Envelope");// Color"); if (colorBarIconValid) { m_histogramEnvelopeColorComboBox = new CaretColorEnumComboBox("Palette", colorBarIcon, @@ -781,6 +782,12 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() QObject::connect(m_histogramEnvelopeColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); + QLabel* envelopeLineWidthLabel = new QLabel("Envelope Width"); + m_histogramEnvelopeLineWidthPercentageSpinBox = new WuQDoubleSpinBox(this); + m_histogramEnvelopeLineWidthPercentageSpinBox->setupRangePercentage(0.0, 100.0); + QObject::connect(m_histogramEnvelopeLineWidthPercentageSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), + [=](double) { this->applyAndUpdate(); }); + const int32_t maxBuckets = 100000; QLabel* bucketsLabel = new QLabel("Buckets"); m_histogramBucketsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, maxBuckets, 1); @@ -800,6 +807,9 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() controlLayout->addWidget(envelopeColorLabel, rowIndex, 0); controlLayout->addWidget(m_histogramEnvelopeColorComboBox->getWidget(), rowIndex, 1); rowIndex++; + controlLayout->addWidget(envelopeLineWidthLabel, rowIndex, 0); + controlLayout->addWidget(m_histogramEnvelopeLineWidthPercentageSpinBox->getWidget(), rowIndex, 1); + rowIndex++; controlLayout->addWidget(horizRangeLabel, rowIndex, 0); controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), rowIndex, 1); rowIndex++; @@ -836,6 +846,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() statisticsLayout->addWidget(new QLabel("Min"), 3, 0); statisticsLayout->addWidget(this->statisticsMinimumValueLabel, 3, 1); //statisticsWidget->setFixedHeight(statisticsWidget->sizeHint().height()); + statisticsLayout->setRowStretch(statisticsLayout->rowCount(), 100); QGroupBox* groupBox = new QGroupBox("Histogram"); @@ -1752,7 +1763,7 @@ MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile m_histogramBarsColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramBarsColor()); m_histogramEnvelopeColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramEnvelopeColor()); - + m_histogramEnvelopeLineWidthPercentageSpinBox->setValue(this->paletteColorMapping->getHistogramEnvelopeLineWidthPercentage()); m_histogramBarsVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramBarsVisible()); m_histogramEnvelopeVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramEnvelopeVisible()); @@ -2408,6 +2419,7 @@ void MapSettingsPaletteColorMappingWidget::applySelections() this->paletteColorMapping->setHistogramBarsColor(m_histogramBarsColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramEnvelopeColor(m_histogramEnvelopeColorComboBox->getSelectedColor()); + this->paletteColorMapping->setHistogramEnvelopeLineWidthPercentage(m_histogramEnvelopeLineWidthPercentageSpinBox->value()); this->paletteColorMapping->setHistogramBarsVisible(m_histogramBarsVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramEnvelopeVisible(m_histogramEnvelopeVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h index a23b47f55..f850b1e4a 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.h +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.h @@ -46,6 +46,7 @@ namespace caret { class Histogram; class PaletteColorMapping; class WuQDoubleSlider; + class WuQDoubleSpinBox; class WuQWidgetObjectGroup; class WuQwtPlot; @@ -203,6 +204,8 @@ namespace caret { CaretColorEnumComboBox* m_histogramEnvelopeColorComboBox; + WuQDoubleSpinBox* m_histogramEnvelopeLineWidthPercentageSpinBox; + QCheckBox* m_histogramBarsVisibleCheckBox; QCheckBox* m_histogramEnvelopeVisibleCheckBox; diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 62b2969ad..63825483e 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -152,6 +152,7 @@ PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm, this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; this->histogramBarsColor = pcm.histogramBarsColor; this->histogramEnvelopeColor = pcm.histogramEnvelopeColor; + this->histogramEnvelopeLineWidthPercentage = pcm.histogramEnvelopeLineWidthPercentage; this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; } this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; @@ -218,6 +219,7 @@ PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) && (this->histogramBarsColor == pcm.histogramBarsColor) && (this->histogramEnvelopeColor == pcm.histogramEnvelopeColor) + && (this->histogramEnvelopeLineWidthPercentage == pcm.histogramEnvelopeLineWidthPercentage) && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets)) { allMatchFlag = true; } @@ -268,6 +270,7 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->histogramEnvelopeVisible = false; this->histogramBarsColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->histogramEnvelopeColor = CaretColorEnum::RED; + this->histogramEnvelopeLineWidthPercentage = 1.0f; this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; this->colorBarPrecisionDigits = 2; @@ -395,6 +398,8 @@ PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) CaretColorEnum::toName(this->histogramBarsColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_COLOR, CaretColorEnum::toName(this->histogramEnvelopeColor)); + xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE, + this->histogramEnvelopeLineWidthPercentage); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS, this->histogramNumberOfBuckets); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, @@ -2888,6 +2893,31 @@ PaletteColorMapping::setHistogramEnvelopeColor(const CaretColorEnum::Enum histog } } +/** + * @return The line width percentage for drawing histogram as envelope. + */ +float +PaletteColorMapping::getHistogramEnvelopeLineWidthPercentage() const +{ + return histogramEnvelopeLineWidthPercentage; +} + +/** + * Set line width percentage for drawing histogram as envelope. + * + * @param lineWidthPercentage + * New value for line width percentage. + */ +void +PaletteColorMapping::setHistogramEnvelopeLineWidthPercentage(const float lineWidthPercentage) +{ + if (lineWidthPercentage != this->histogramEnvelopeLineWidthPercentage) { + this->histogramEnvelopeLineWidthPercentage = lineWidthPercentage; + setModified(); + } +} + + /** * @return Histogram number of buckets. */ diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 8d8860090..5207b6952 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -230,6 +230,10 @@ namespace caret { void setHistogramEnvelopeColor(const CaretColorEnum::Enum histogramEnvelopeColor); + float getHistogramEnvelopeLineWidthPercentage() const; + + void setHistogramEnvelopeLineWidthPercentage(const float lineWidthPercentage); + int32_t getHistogramNumberOfBuckets() const; void setHistogramNumberOfBuckets(const int32_t histogramNumberOfBuckets); @@ -344,6 +348,8 @@ namespace caret { CaretColorEnum::Enum histogramEnvelopeColor; + float histogramEnvelopeLineWidthPercentage; + int32_t histogramNumberOfBuckets; NumericFormatModeEnum::Enum colorBarNumericFormatMode; diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 42e92e537..54905dcc6 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -343,6 +343,10 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, + this->elementText); } } + else + if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE) { + this->paletteColorMapping->setHistogramEnvelopeLineWidthPercentage(this->elementText.toFloat()); + } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS) { this->paletteColorMapping->setHistogramNumberOfBuckets(this->elementText.toInt()); } diff --git a/src/Palette/PaletteColorMappingXmlElements.h b/src/Palette/PaletteColorMappingXmlElements.h index 1243a368d..3c5ad103e 100644 --- a/src/Palette/PaletteColorMappingXmlElements.h +++ b/src/Palette/PaletteColorMappingXmlElements.h @@ -50,6 +50,7 @@ namespace PaletteColorMappingXmlElements { static const AString XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE = "HistogramEnvelopeVisible"; static const AString XML_TAG_HISTOGRAM_BARS_COLOR = "HistogramBarsColor"; static const AString XML_TAG_HISTOGRAM_ENVELOPE_COLOR = "HistogramEnvelopeColor"; + static const AString XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE = "HistogramEnvelopeLineWidthPercentage"; static const AString XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; -- GitLab From d23509df332865c9ad5f0c5a5ab4ed20151caac2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 10:04:15 -0500 Subject: [PATCH 373/755] Restored EventUpdateYokedWIndows and added support for the recently added chart yoking that is separate from brain model yoking. This was necessary to minimize update or otherwise, graphics updates became very slow. --- src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 35 ++++-- src/GuiQt/CMakeLists.txt | 2 + src/GuiQt/EventUpdateYokedWindows.cxx | 142 ++++++++++++++++++++++++ src/GuiQt/EventUpdateYokedWindows.h | 78 +++++++++++++ src/GuiQt/UserInputModeView.cxx | 37 ++++-- 8 files changed, 280 insertions(+), 21 deletions(-) create mode 100644 src/GuiQt/EventUpdateYokedWindows.cxx create mode 100644 src/GuiQt/EventUpdateYokedWindows.h diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index d5db2d190..7e1a3e4c6 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -539,6 +539,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_PROGRESS_UPDATE: case EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS: case EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR: + case EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS: { const AString msg(EventTypeEnum::toName(eventType) + " has an special subclass of class Event and should never be sent as an event."); diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 4870565ef..a29c33be7 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -354,6 +354,10 @@ EventTypeEnum::initialize() "EVENT_UPDATE_INFORMATION_WINDOWS", "Update the information windows")); + enumData.push_back(EventTypeEnum(EVENT_UPDATE_YOKED_WINDOWS, + "EVENT_UPDATE_YOKED_WINDOWS", + "Update yoked windows")); + enumData.push_back(EventTypeEnum(EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, "EVENT_UPDATE_VOLUME_EDITING_TOOLBAR", "Update the volume editing toolbar")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 9ead53ca2..290ed57c7 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -186,6 +186,8 @@ public: EVENT_UPDATE_INFORMATION_WINDOWS, /** Update the volume editing toolbar */ EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, + /** Update yoked windows */ + EVENT_UPDATE_YOKED_WINDOWS, /* THIS MUST ALWAYS BE LAST - NOT an event type but is number of event types */ EVENT_COUNT }; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 5e560148c..fec6875e0 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -91,6 +91,7 @@ #include "EventManager.h" #include "EventModelGetAll.h" #include "EventSurfaceColoringInvalidate.h" +#include "EventUpdateYokedWindows.h" #include "GuiManager.h" #include "Model.h" #include "ModelChart.h" @@ -3859,6 +3860,22 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) } tabEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS) { + EventUpdateYokedWindows* yokeUpdateEvent = + dynamic_cast(event); + CaretAssert(yokeUpdateEvent); + + BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); + if (browserTabContent != NULL) { + if (this->browserWindowIndex != yokeUpdateEvent->getBrowserWindowIndexThatIssuedEvent()) { + if (yokeUpdateEvent->isBrainOrChartModelYoking(browserTabContent->getBrainModelYokingGroup(), + browserTabContent->getChartModelYokingGroup())) { + this->updateToolBar(); + this->updateGraphicsWindow(); + } + } + } + } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED) { EventBrowserTabGetAllViewed* viewedTabsEvent = dynamic_cast(event); CaretAssert(viewedTabsEvent); @@ -3899,16 +3916,14 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) void BrainBrowserWindowToolBar::updateOtherYokedWindows() { - EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - -// BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); -// if (browserTabContent != NULL) { -// if (browserTabContent->isYoked()) { -// EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, -// browserTabContent->getBrainModelYokingGroup()).getPointer()); -// } -// } + BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); + if (browserTabContent != NULL) { + if (browserTabContent->isBrainModelYoked()) { + EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, + browserTabContent->getBrainModelYokingGroup(), + browserTabContent->getChartModelYokingGroup()).getPointer()); + } + } } /** diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index f5883b3ec..19ac8ffbf 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -326,6 +326,7 @@ EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h +EventUpdateYokedWindows.h EventUserInterfaceUpdate.h FiberOrientationSelectionViewController.h FiberSamplesOpenGLWidget.h @@ -538,6 +539,7 @@ EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx +EventUpdateYokedWindows.cxx EventUserInterfaceUpdate.cxx FiberOrientationSelectionViewController.cxx FiberSamplesOpenGLWidget.cxx diff --git a/src/GuiQt/EventUpdateYokedWindows.cxx b/src/GuiQt/EventUpdateYokedWindows.cxx new file mode 100644 index 000000000..ab714be3d --- /dev/null +++ b/src/GuiQt/EventUpdateYokedWindows.cxx @@ -0,0 +1,142 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ +#include "EventUpdateYokedWindows.h" +#undef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ + +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventUpdateYokedWindows + * \brief Updates windows that are yoked. + * \ingroup GuiQt + */ + +/** + * Constructor for a window. This given window will NOT be updated. + * + * @param browserWindowIndexThatIssuedEvent + * Index of browser window that issued event. + * @param brainModelYokingGroup + * brain model yoking group that is selected. + * @param chartModelYokingGroup + * chart model yoking group that is selected. + */ +EventUpdateYokedWindows::EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, + const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup) +: Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), +m_browserWindowIndexThatIssuedEvent(browserWindowIndexThatIssuedEvent), +m_brainModelYokingGroup(brainModelYokingGroup), +m_chartModelYokingGroup(chartModelYokingGroup) +{ +} + +/** + * Constructor for updating all windows. + * + * @param browserWindowIndexThatIssuedEvent + * Index of browser window that issued event. + * @param brainModelYokingGroup + * brain model yoking group that is selected. + * @param chartModelYokingGroup + * chart model yoking group that is selected. + */ +EventUpdateYokedWindows::EventUpdateYokedWindows(const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup) +: Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), +m_browserWindowIndexThatIssuedEvent(-1), +m_brainModelYokingGroup(brainModelYokingGroup), +m_chartModelYokingGroup(chartModelYokingGroup) +{ +} + +/** + * Destructor. + */ +EventUpdateYokedWindows::~EventUpdateYokedWindows() +{ + +} + +/** + * @return Index of browser window that issued the event. + */ +int32_t +EventUpdateYokedWindows::getBrowserWindowIndexThatIssuedEvent() const +{ + return m_browserWindowIndexThatIssuedEvent; +} + +/** + * @return Is the given brain model yoking group needing an update? + * + * @param brainModelYokingGroup + * The brain model yoking group. + */ +bool +EventUpdateYokedWindows::isBrainModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup) const +{ + if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + return false; + } + + return (m_brainModelYokingGroup == brainModelYokingGroup); +} + +/** + * @return Is the given chart model yoking group needing an update? + * + * @param chartModelYokingGroup + * The chart model yoking group. + */ +bool +EventUpdateYokedWindows::isChartModelYoking(const YokingGroupEnum::Enum chartModelYokingGroup) const +{ + if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { + return false; + } + + return (m_chartModelYokingGroup == chartModelYokingGroup); +} + + +/** + * @return Is the given brain OR chart model yoking group needing an update? + * + * @param brainModelYokingGroup + * The brain model yoking group. + * @param chartModelYokingGroup + * The chart model yoking group. + */ +bool +EventUpdateYokedWindows::isBrainOrChartModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup) const +{ + return (isBrainModelYoking(brainModelYokingGroup) + || isChartModelYoking(chartModelYokingGroup)); +} + diff --git a/src/GuiQt/EventUpdateYokedWindows.h b/src/GuiQt/EventUpdateYokedWindows.h new file mode 100644 index 000000000..8dee39263 --- /dev/null +++ b/src/GuiQt/EventUpdateYokedWindows.h @@ -0,0 +1,78 @@ +#ifndef __EVENT_UPDATE_YOKED_WINDOWS_H__ +#define __EVENT_UPDATE_YOKED_WINDOWS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "Event.h" +#include "YokingGroupEnum.h" + +namespace caret { + + class EventUpdateYokedWindows : public Event { + + public: + EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, + const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup); + + EventUpdateYokedWindows(const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup); + + virtual ~EventUpdateYokedWindows(); + + int32_t getBrowserWindowIndexThatIssuedEvent() const; + + bool isBrainModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup) const; + + bool isChartModelYoking(const YokingGroupEnum::Enum chartModelYokingGroup) const; + + bool isBrainOrChartModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup, + const YokingGroupEnum::Enum chartModelYokingGroup) const; + + private: + EventUpdateYokedWindows(const EventUpdateYokedWindows&); + + EventUpdateYokedWindows& operator=(const EventUpdateYokedWindows&); + + public: + + // ADD_NEW_METHODS_HERE + + private: + + const int32_t m_browserWindowIndexThatIssuedEvent; + + const YokingGroupEnum::Enum m_brainModelYokingGroup; + + const YokingGroupEnum::Enum m_chartModelYokingGroup; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ + // +#endif // __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ + +} // namespace +#endif //__EVENT_UPDATE_YOKED_WINDOWS_H__ diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index c7af5e51a..b223b6694 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -34,6 +34,7 @@ #include "ChartTwoOverlaySet.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" +#include "EventUpdateYokedWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" @@ -390,30 +391,44 @@ UserInputModeView::showContextMenu(const MouseEvent& mouseEvent, } /** - * Updated graphics. + * If this windows is yoked, issue an event to update other + * windows that are using the same yoking. */ void UserInputModeView::updateGraphics(const MouseEvent& mouseEvent) { + bool issuedYokeEvent = false; if (mouseEvent.getViewportContent() != NULL) { BrowserTabContent* browserTabContent = mouseEvent.getViewportContent()->getBrowserTabContent(); + const int32_t browserWindowIndex = mouseEvent.getBrowserWindowIndex(); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(browserWindowIndex).getPointer()); + + YokingGroupEnum::Enum brainYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + YokingGroupEnum::Enum chartYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + if (browserTabContent != NULL) { - if (browserTabContent->isChartModelYoked() - || browserTabContent->isBrainModelYoked()) { - /* - * When yoked, need to update GUI and all windows - */ - EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(mouseEvent.getBrowserWindowIndex()).getPointer()); + if (browserTabContent->isBrainModelYoked()) { + brainYokingGroup = browserTabContent->getBrainModelYokingGroup(); + issuedYokeEvent = true; + } + if (browserTabContent->isChartModelYoked()) { + chartYokingGroup = browserTabContent->getChartModelYokingGroup(); + issuedYokeEvent = true; + } + + if (issuedYokeEvent) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - return; + EventManager::get()->sendEvent(EventUpdateYokedWindows(brainYokingGroup, + chartYokingGroup).getPointer()); } } } /* - * Not yoked, just update graphics in this window + * If not yoked, just need to update graphics. */ - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(mouseEvent.getBrowserWindowIndex()).getPointer()); + if ( ! issuedYokeEvent) { + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(mouseEvent.getBrowserWindowIndex()).getPointer()); + } } - -- GitLab From 4303f5095b7c277f052d04b6a011f3f158b4072f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 12:13:41 -0500 Subject: [PATCH 374/755] Fixed bug: If a tab space annotation was created and the previously selected annotation was a chart space annotation, the new tab annotation's Y-coordinate was at the bottom of the screen. This was caused by a call to QDoubleSpinBox::setDecimals() that resulted in the emitting of a valueChanged() signal. --- src/GuiQt/AnnotationCoordinateWidget.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 775e9f9a5..b7befba5e 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -355,8 +355,8 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_xCoordSpinBox->setSingleStep(xyzStep); m_xCoordSpinBox->setSuffix(suffix); m_xCoordSpinBox->setValue(xyz[0]); - m_xCoordSpinBox->blockSignals(false); m_xCoordSpinBox->setDecimals(digitsRightOfDecimal); + m_xCoordSpinBox->blockSignals(false); m_yCoordSpinBox->blockSignals(true); m_yCoordSpinBox->setRange(yMin, @@ -364,8 +364,8 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_yCoordSpinBox->setSingleStep(xyzStep); m_yCoordSpinBox->setSuffix(suffix); m_yCoordSpinBox->setValue(xyz[1]); - m_yCoordSpinBox->blockSignals(false); m_yCoordSpinBox->setDecimals(digitsRightOfDecimal); + m_yCoordSpinBox->blockSignals(false); m_zCoordSpinBox->blockSignals(true); m_zCoordSpinBox->setRange(zMin, @@ -373,8 +373,8 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_zCoordSpinBox->setSingleStep(xyzStep); m_zCoordSpinBox->setSuffix(suffix); m_zCoordSpinBox->setValue(xyz[2]); - m_zCoordSpinBox->blockSignals(false); m_zCoordSpinBox->setDecimals(digitsRightOfDecimal); + m_zCoordSpinBox->blockSignals(false); if (surfaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; -- GitLab From 25a8cb66a2fb701e9ba0f702a3ea39a539614cfd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 12:53:23 -0500 Subject: [PATCH 375/755] If user edits a chart title so that it is non-empty, turn on display of the title. --- src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index f3d790b0c..26d7345bc 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -191,6 +191,10 @@ BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered() if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); m_chartOverlaySet->getChartTitle()->setText(name); + if ( ! name.isEmpty()) { + m_chartOverlaySet->getChartTitle()->setDisplayed(true); + m_showTitleCheckBox->setChecked(true); + } this->performUpdating(); } } @@ -216,4 +220,5 @@ BrainBrowserWindowToolBarChartTwoTitle::performUpdating() } this->updateOtherYokedWindows(); + this->updateGraphicsWindow(); } -- GitLab From 766c654c4747933dae464213ce39d934c8fe0b62 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 13:07:19 -0500 Subject: [PATCH 376/755] Rename QDoubleSpinBox method for setting a range percentage and correct maximum percentage. --- src/GuiQt/AnnotationFontWidget.cxx | 2 +- src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx | 8 ++++---- src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx | 4 ++-- src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx | 2 +- src/GuiQt/WuQDoubleSpinBox.cxx | 4 ++-- src/GuiQt/WuQDoubleSpinBox.h | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 3b984e9eb..bd56e2932 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -94,7 +94,7 @@ m_browserWindowIndex(browserWindowIndex) * Combo box for font size */ m_fontSizeSpinBox = new WuQDoubleSpinBox(this); - m_fontSizeSpinBox->setupRangePercentage(0.0, 100.0); + m_fontSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_fontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(fontSizeChanged())); WuQtUtilities::setToolTipAndStatusTip(m_fontSizeSpinBox->getWidget(), diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 1caa8226d..2d616d1a6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -181,25 +181,25 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra * Size spin boxes */ m_labelSizeSpinBox = new WuQDoubleSpinBox(this); - m_labelSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_labelSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_labelSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); m_numericsSizeSpinBox = new WuQDoubleSpinBox(this); - m_numericsSizeSpinBox->setupRangePercentage(0.0, 99.0); + m_numericsSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_numericsSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); - m_linesTicksSizeSpinBox->setupRangePercentage(0.0, 99.0); + m_linesTicksSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); - m_paddingSizeSpinBox->setupRangePercentage(0.0, 99.0); + m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 26d7345bc..816ee0f43 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -74,13 +74,13 @@ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(B editTitleToolButton->setDefaultAction(editTitleAction); m_titleSizeSpinBox = new WuQDoubleSpinBox(this); - m_titleSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_titleSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_titleSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); - m_paddingSizeSpinBox->setupRangePercentage(0.0, 99.0); // 99 instead of 100 results in narrower width + m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 4f3ca3bb4..4eed07a9b 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -784,7 +784,7 @@ MapSettingsPaletteColorMappingWidget::createHistogramControlSection() QLabel* envelopeLineWidthLabel = new QLabel("Envelope Width"); m_histogramEnvelopeLineWidthPercentageSpinBox = new WuQDoubleSpinBox(this); - m_histogramEnvelopeLineWidthPercentageSpinBox->setupRangePercentage(0.0, 100.0); + m_histogramEnvelopeLineWidthPercentageSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_histogramEnvelopeLineWidthPercentageSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), [=](double) { this->applyAndUpdate(); }); diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx index 57f9fefc6..d3f98f2ea 100644 --- a/src/GuiQt/WuQDoubleSpinBox.cxx +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -514,8 +514,8 @@ WuQDoubleSpinBox::setRangeExceedable(double minimum, * Maximum percentage (must be in range [0.0, 100.0] */ void -WuQDoubleSpinBox::setupRangePercentage(const double minimumPercentage, - const double maximumPercentage) +WuQDoubleSpinBox::setRangePercentage(const double minimumPercentage, + const double maximumPercentage) { setRange(minimumPercentage, maximumPercentage); diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h index 18c5a56c7..d50b7e6fe 100644 --- a/src/GuiQt/WuQDoubleSpinBox.h +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -115,8 +115,8 @@ namespace caret { void setRangeExceedable(double minimum, double maximum); - void setupRangePercentage(const double minimumPercentage, - const double maximumPercentage); + void setRangePercentage(const double minimumPercentage, + const double maximumPercentage); void setSingleStep(double value); -- GitLab From 2ac1878bee3679dec4e31473970e4d2d0eb3f400 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 14:57:11 -0500 Subject: [PATCH 377/755] Log time to load a scene at the INFO level. --- src/GuiQt/SceneDialog.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index a140c786e..9bc4928cc 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2372,10 +2372,18 @@ SceneDialog::displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, { AString errorMessage; + ElapsedTimer et; + et.start(); + const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, scene, showWaitCursor, errorMessage); + AString msg = (AString::number(et.getElapsedTimeSeconds()) + + " seconds to read Scene " + + scene->getName()); + CaretLogInfo(msg); + if ( ! successFlag) { WuQMessageBox::errorOk(this, errorMessage); -- GitLab From b3117096ae59274ff4a2acf9f393300d7185c83a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Sep 2017 15:29:26 -0500 Subject: [PATCH 378/755] Removed maximum pixel size used when converting from a percentage of viewport height to pixels. The maximum pixel size prevents proper padding and is not needed for lines since the Graphics code will limit the line width to OpenGL's maximum value. --- src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index f1f15f8e7..53713379b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1420,12 +1420,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToPixels(con } float pixelsWidthOrHeight = ((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight); - if (pixelsWidthOrHeight < s_minimumLineWidthOpenGL) { - pixelsWidthOrHeight = s_minimumLineWidthOpenGL; - } - if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { - pixelsWidthOrHeight = s_maximumLineWidthOpenGL; - } return pixelsWidthOrHeight; } -- GitLab From f337173b7d42efe6b24bc103ade4db0f845191d7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 09:00:22 -0500 Subject: [PATCH 379/755] Fixed drawing of box around the chart graphics region when lock tab or window aspect is selected. --- src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 53713379b..0f8819bfd 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1480,10 +1480,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons /* * For box, set coordinates for the middle of the line */ - const float boxLeft = vpX + leftAxisWidth + halfGridLineWidth; - const float boxRight = vpX + vpWidth - rightAxisWidth - halfGridLineWidth; - const float boxBottom = vpY + bottomAxisHeight + halfGridLineWidth; - const float boxTop = vpY + vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; + const float boxLeft = leftAxisWidth + halfGridLineWidth; + const float boxRight = vpWidth - rightAxisWidth - halfGridLineWidth; + const float boxBottom = bottomAxisHeight + halfGridLineWidth; + const float boxTop = vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; /* * We adjust the horizontal lines by half the line width. -- GitLab From 8f239ac3386a6d5ca7c460b0ac8a7cd21e9f3bad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 10:27:24 -0500 Subject: [PATCH 380/755] Corrected problems with line thickness limitation in OpenGL when drawing chart graphics box and ticks. Added yoking for chart line thickness. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 44 +++++++++++++++--- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 3 ++ src/Brain/ChartTwoOverlaySet.cxx | 26 +++++++++++ .../EventChartTwoAttributesChanged.cxx | 46 +++++++++++++++++++ src/Charting/EventChartTwoAttributesChanged.h | 13 +++++- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 34 +++++++++++++- .../BrainBrowserWindowToolBarChartTwoAxes.h | 2 + 7 files changed, 159 insertions(+), 9 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0f8819bfd..7fa6973a1 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -646,7 +646,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch 1.0f }; - const float graphicsBoxLineThickness = convertPercentageOfViewportToPixels(m_chartOverlaySet->getAxisLineThickness(), + const float graphicsBoxLineThickness = convertPercentageOfViewportToOpenGLLineWidth(m_chartOverlaySet->getAxisLineThickness(), tabViewportHeight); leftAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); @@ -819,7 +819,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if (histogramPrimitives != NULL) { const float lineWidthPercentage = histogramPrimitives->getEnvelopeLineWidthPercentage(); - const float envelopeLineWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, + const float envelopeLineWidth = convertPercentageOfViewportToOpenGLLineWidth(lineWidthPercentage, tabViewportHeight); if (m_identificationModeFlag) { @@ -1399,6 +1399,38 @@ BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() } +/** + * Convert a percentage of viewport width or height to an OpenGL Line Width. + * When percentage width or height is zero, zero will be returned. + * Otherwise the returned value will ALWAYS be at least one. + * + * + * @param percentageWidthOrHeight + * The percentage of width or height (ranges 0.0 to 100.0). + * @param viewportWidthOrHeight + * The viewport width or height. + * @return + * Pixels size value. + */ +float +BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToOpenGLLineWidth(const float percentageWidthOrHeight, + const float viewportWidthOrHeight) +{ + if (percentageWidthOrHeight <= 0.0f) { + return 0.0f; + } + + float pixelsWidthOrHeight = ((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight); + + if (pixelsWidthOrHeight < s_minimumLineWidthOpenGL) { + pixelsWidthOrHeight = s_minimumLineWidthOpenGL; + } + if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { + pixelsWidthOrHeight = s_maximumLineWidthOpenGL; + } + return pixelsWidthOrHeight; +} + /** * Convert a percentage of viewport width or height to pixels. * When percentage width or height is zero, zero will be returned. @@ -1467,8 +1499,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]) { - const float lineThicknessPixels = convertPercentageOfViewportToPixels(lineThicknessPercentage, - vpHeight); + const float lineThicknessPixels = convertPercentageOfViewportToOpenGLLineWidth(lineThicknessPercentage, + vpHeight); const float halfGridLineWidth = lineThicknessPixels / 2.0; glViewport(vpX, @@ -1709,12 +1741,12 @@ m_tabViewportHeight(tabViewport[3]) break; } - m_lineDrawingWidth = convertPercentageOfViewportToPixels(lineWidthPercentage, + m_lineDrawingWidth = convertPercentageOfViewportToOpenGLLineWidth(lineWidthPercentage, m_tabViewportHeight); m_tickLength = 0.0f; if (m_axis->isShowTickmarks()) { const float tickLengthPercentage = 1.0f; - m_tickLength = convertPercentageOfViewportToPixels(tickLengthPercentage, m_tabViewportHeight); + m_tickLength = convertPercentageOfViewportToOpenGLLineWidth(tickLengthPercentage, m_tabViewportHeight); //m_tickLength = m_lineDrawingWidth; // * 2.0f; } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index f9cb2bef2..a970c78eb 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -243,6 +243,9 @@ namespace caret { static float convertPercentageOfViewportToPixels(const float percentageWidthOrHeight, const float viewportWidthOrHeight); + static float convertPercentageOfViewportToOpenGLLineWidth(const float percentageWidthOrHeight, + const float viewportWidthOrHeight); + Brain* m_brain; BrainOpenGLViewportContent* m_viewportContent; diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index da2476a4f..a88f6a407 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -617,6 +617,32 @@ ChartTwoOverlaySet::receiveEvent(Event* event) } } break; + case EventChartTwoAttributesChanged::Mode::LINE_THICKESS: + { + YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; + float lineThickness = 0.0f; + attributeEvent->getLineThicknessChanged(yokingGroup, + chartTwoDataType, + lineThickness); + + /* + * Only tabs in the windows are valid + */ + EventBrowserTabGet tabEvent(m_tabIndex); + EventManager::get()->sendEvent(tabEvent.getPointer()); + const BrowserTabContent* btc = tabEvent.getBrowserTab(); + if (btc != NULL) { + const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); + + if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) + && (yokingGroup == tabYoking) + && (m_chartDataType == chartTwoDataType)) { + m_axisLineThickness = lineThickness; + } + } + } + break; case EventChartTwoAttributesChanged::Mode::TITLE: { YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; diff --git a/src/Charting/EventChartTwoAttributesChanged.cxx b/src/Charting/EventChartTwoAttributesChanged.cxx index dc439e913..639e1c097 100644 --- a/src/Charting/EventChartTwoAttributesChanged.cxx +++ b/src/Charting/EventChartTwoAttributesChanged.cxx @@ -104,6 +104,48 @@ EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &y cartesianAxisOut = m_cartesianAxis; } +/** + * Set for a change in line thickness. + * + * @param yokingGroup + * Selected yoking group. + * @param chartTwoDataType + * Type of chart. + * @param lineThickness + * New line thickness + */ +void +EventChartTwoAttributesChanged::setLineThicknessChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const float lineThickness) +{ + m_mode = Mode::LINE_THICKESS; + m_yokingGroup = yokingGroup; + m_chartTwoDataType = chartTwoDataType; + m_lineThickness = lineThickness; +} + +/** + * Get for a change in line thickness + * + * @param yokingGroupOut + * Selected yoking group. + * @param chartTwoDataTypeOut + * Type of chart. + * @param lineThicknessOut + * Output line thickness + */ +void +EventChartTwoAttributesChanged::getLineThicknessChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + float& lineThicknessOut) const +{ + CaretAssert(m_mode == Mode::LINE_THICKESS); + yokingGroupOut = m_yokingGroup; + chartTwoDataTypeOut = m_chartTwoDataType; + lineThicknessOut = m_lineThickness; +} + /** * Set for a change in a title. * @@ -111,6 +153,8 @@ EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &y * Selected yoking group. * @param chartTwoDataType * Type of chart. + * @parm chartTitle + * Chart title. */ void EventChartTwoAttributesChanged::setTitleChanged(const YokingGroupEnum::Enum yokingGroup, @@ -131,6 +175,8 @@ EventChartTwoAttributesChanged::setTitleChanged(const YokingGroupEnum::Enum yoki * Selected yoking group. * @param chartTwoDataTypeOut * Type of chart. + * @parm chartTitleOut + * Chart title. */ void EventChartTwoAttributesChanged::getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, diff --git a/src/Charting/EventChartTwoAttributesChanged.h b/src/Charting/EventChartTwoAttributesChanged.h index 07c558b76..993094619 100644 --- a/src/Charting/EventChartTwoAttributesChanged.h +++ b/src/Charting/EventChartTwoAttributesChanged.h @@ -40,6 +40,7 @@ namespace caret { enum class Mode { INVALID, CARTESIAN_AXIS, + LINE_THICKESS, TITLE }; @@ -57,6 +58,14 @@ namespace caret { ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoCartesianAxis* &cartesianAxisOut) const; + void setLineThicknessChanged(const YokingGroupEnum::Enum yokingGroup, + const ChartTwoDataTypeEnum::Enum chartTwoDataType, + const float lineThickness); + + void getLineThicknessChanged(YokingGroupEnum::Enum &yokingGroupOut, + ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, + float& lineThicknessOut) const; + void setTitleChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoTitle* chartTitle); @@ -64,7 +73,7 @@ namespace caret { void getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoTitle* &chartTitleOut) const; - + // ADD_NEW_METHODS_HERE private: @@ -82,6 +91,8 @@ namespace caret { ChartTwoTitle* m_chartTitle = NULL; + float m_lineThickness = 1.0f; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 2d616d1a6..a007a83a3 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -195,7 +195,7 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); m_linesTicksSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), - this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); + this, &BrainBrowserWindowToolBarChartTwoAxes::axisLineThicknessChanged); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); @@ -560,6 +560,37 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_widgetGroup->blockAllSignals(false); } +/** + * Called when the axis line thickness changes. + */ +void +BrainBrowserWindowToolBarChartTwoAxes::axisLineThicknessChanged(double) +{ + if (m_chartOverlaySet != NULL) { + m_chartOverlaySet->setAxisLineThickness(m_linesTicksSizeSpinBox->value()); + + const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); + CaretAssert(tabContent); + + const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); + if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { + const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); + CaretAssert(modelChartTwo); + const int32_t tabIndex = tabContent->getTabNumber(); + EventChartTwoAttributesChanged attributesEvent; + attributesEvent.setLineThicknessChanged(yokingGroup, + modelChartTwo->getSelectedChartTwoDataType(tabIndex), + m_linesTicksSizeSpinBox->value()); + EventManager::get()->sendEvent(attributesEvent.getPointer()); + } + } + + updateGraphics(); + + updateContent(getTabContentFromSelectedTab()); +} + + /** * Called when a widget is changed by the user. */ @@ -581,7 +612,6 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); m_chartAxis->setLabelTextSize(m_labelSizeSpinBox->value()); - m_chartOverlaySet->setAxisLineThickness(m_linesTicksSizeSpinBox->value()); m_chartAxis->setNumericsTextSize(m_numericsSizeSpinBox->value()); m_chartAxis->setPaddingSize(m_paddingSizeSpinBox->value()); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index d74533be9..85b353f9b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -73,6 +73,8 @@ namespace caret { void axisLabelToolButtonClicked(bool); + void axisLineThicknessChanged(double); + private: BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); -- GitLab From d81d4cc7715ee4699ac3696bfe5cca1633226264 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 11:44:29 -0500 Subject: [PATCH 381/755] Add percentage suffix to line width spin boxes in Chart Two History Dialog. --- src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 21 ++++++++----------- src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 6 +++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx index 6793e6793..128db8579 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx @@ -24,7 +24,6 @@ #undef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ #include -#include #include #include #include @@ -45,6 +44,7 @@ #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "MapFileDataSelector.h" +#include "WuQDoubleSpinBox.h" #include "WuQImageLabel.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -86,13 +86,11 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent this, &ChartTwoLineSeriesHistoryDialog::defaultColorSelected); QLabel* defaultLineWidthLabel = new QLabel("Default Line Width: "); - m_defaultLineWidthSpinBox = new QDoubleSpinBox(); - m_defaultLineWidthSpinBox->setRange(0.0, 100000.0); - m_defaultLineWidthSpinBox->setDecimals(2); - m_defaultLineWidthSpinBox->setSingleStep(0.1); + m_defaultLineWidthSpinBox = new WuQDoubleSpinBox(this); + m_defaultLineWidthSpinBox->setRangePercentage(0.0, 100.0); m_defaultLineWidthSpinBox->setToolTip("Default width of new chart lines"); - defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->toolTip()); - QObject::connect(m_defaultLineWidthSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->getWidget()->toolTip()); + QObject::connect(m_defaultLineWidthSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &ChartTwoLineSeriesHistoryDialog::defaultLineWidthChanged); QToolButton* removeAllHistoryToolButton = new QToolButton(); @@ -136,7 +134,7 @@ ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent topLayout->addWidget(m_filenameLabel, gridRow, 0, 1, 5, Qt::AlignLeft); gridRow++; topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); - topLayout->addWidget(m_defaultLineWidthSpinBox, gridRow, 1); + topLayout->addWidget(m_defaultLineWidthSpinBox->getWidget(), gridRow, 1); topLayout->addWidget(defaultColorLabel, gridRow, 2); topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 3); gridRow++; @@ -357,15 +355,14 @@ ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHi m_colorComboBoxes.push_back(caretColorComboBox); } else if (j == COLUMN_LINE_WIDTH) { - QDoubleSpinBox* lineWidthSpinBox = new QDoubleSpinBox(); - lineWidthSpinBox->setRange(1.0, 10.0); - lineWidthSpinBox->setSingleStep(1.0); + WuQDoubleSpinBox* lineWidthSpinBox = new WuQDoubleSpinBox(this); + lineWidthSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(lineWidthSpinBox, SIGNAL(valueChanged(double)), m_lineWidthItemSignalMapper, SLOT(map())); m_lineWidthItemSignalMapper->setMapping(lineWidthSpinBox, iRow); m_tableWidget->setCellWidget(iRow, COLUMN_LINE_WIDTH, - lineWidthSpinBox); + lineWidthSpinBox->getWidget()); m_lineWidthSpinBoxes.push_back(lineWidthSpinBox); } else if (j == COLUMN_DESCRIPTION) { diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h index 9392a8d0e..60ecbe57c 100644 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h +++ b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h @@ -28,7 +28,6 @@ #include "CaretColorEnum.h" #include "WuQDialogNonModal.h" -class QDoubleSpinBox; class QLabel; class QIcon; class QSignalMapper; @@ -41,6 +40,7 @@ namespace caret { class CaretMappableDataFile; class ChartTwoLineSeriesHistory; class ChartTwoOverlay; + class WuQDoubleSpinBox; class ChartTwoLineSeriesHistoryDialog : public WuQDialogNonModal { @@ -106,13 +106,13 @@ namespace caret { std::vector m_colorComboBoxes; - std::vector m_lineWidthSpinBoxes; + std::vector m_lineWidthSpinBoxes; QLabel* m_filenameLabel; CaretColorEnumComboBox* m_defaultColorComboBox; - QDoubleSpinBox* m_defaultLineWidthSpinBox; + WuQDoubleSpinBox* m_defaultLineWidthSpinBox; QSpinBox* m_viewedMaximumCountSpinBox; -- GitLab From f74333f6464f3cdc1dcc559cda2d7c7450c62a32 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 12:55:21 -0500 Subject: [PATCH 382/755] Reduce the default "percentage sizes" for chart labels, numerics, and line width. Reduced default line width for line charts. Some previously created scenes may override these new defaults. --- src/Brain/ChartTwoOverlaySet.cxx | 2 -- src/Brain/ChartTwoOverlaySet.h | 2 +- src/Charting/ChartTwoCartesianAxis.h | 4 ++-- src/Charting/ChartTwoDataCartesian.cxx | 2 +- src/Charting/ChartTwoDataCartesian.h | 6 +++++- src/Charting/ChartTwoLineSeriesHistory.cxx | 2 +- src/Charting/ChartTwoLineSeriesHistory.h | 2 +- src/Palette/PaletteColorMapping.cxx | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index a88f6a407..10f1cc6d8 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -122,8 +122,6 @@ m_tabIndex(tabIndex) m_title = std::unique_ptr(new ChartTwoTitle()); - m_axisLineThickness = 1.0f; - m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartAxisLeft", "ChartTwoCartesianAxis", diff --git a/src/Brain/ChartTwoOverlaySet.h b/src/Brain/ChartTwoOverlaySet.h index c3af52762..c4e8dfec9 100644 --- a/src/Brain/ChartTwoOverlaySet.h +++ b/src/Brain/ChartTwoOverlaySet.h @@ -166,7 +166,7 @@ namespace caret { bool m_inFirstOverlayChangedMethodFlag = false; /** Thickness of box around chart and tick marks on axes*/ - float m_axisLineThickness = 1.0; + float m_axisLineThickness = 0.5; // ADD_NEW_MEMBERS_HERE diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 453a0e931..2218d389a 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -190,10 +190,10 @@ namespace caret { int32_t m_userNumberOfSubdivisions = 2; /** size of label text*/ - float m_labelTextSize = 5.0f; + float m_labelTextSize = 2.5f; /** size of numerics text*/ - float m_numericsTextSize = 5.0f; + float m_numericsTextSize = 2.5f; /** size of padding*/ float m_paddingSize = 0.0f; diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index dd2b5d58a..1831c33f2 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -102,7 +102,7 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() m_selectionStatus = true; m_color = CaretColorEnum::RED; - m_lineWidth = 1.0; + m_lineWidth = getDefaultLineWidth(); m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; diff --git a/src/Charting/ChartTwoDataCartesian.h b/src/Charting/ChartTwoDataCartesian.h index 8460d3876..fe93f530a 100644 --- a/src/Charting/ChartTwoDataCartesian.h +++ b/src/Charting/ChartTwoDataCartesian.h @@ -91,6 +91,11 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); + /** + * @return The default line width for cartesian charts. + */ + static float getDefaultLineWidth() { return 0.5f; } + protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass); @@ -134,7 +139,6 @@ namespace caret { SceneClassAssistant* m_sceneAssistant; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 18ae26753..6ee3bb019 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -175,7 +175,7 @@ ChartTwoLineSeriesHistory::initializeInstance() m_defaultColor = ChartTwoLineSeriesHistory::generateDefaultColor(); validateDefaultColor(); - m_defaultLineWidth = 1.0f; + m_defaultLineWidth = ChartTwoDataCartesian::getDefaultLineWidth(); const int32_t defaultHistoryCount = 1; m_loadingEnabled = false; diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 85dae1813..4ea54c062 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -124,7 +124,7 @@ namespace caret { CaretColorEnum::Enum m_defaultColor = CaretColorEnum::BLUE; - float m_defaultLineWidth = 1.0f; + float m_defaultLineWidth; int32_t m_displayCount; diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 63825483e..eafe3f1ae 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -270,7 +270,7 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->histogramEnvelopeVisible = false; this->histogramBarsColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->histogramEnvelopeColor = CaretColorEnum::RED; - this->histogramEnvelopeLineWidthPercentage = 1.0f; + this->histogramEnvelopeLineWidthPercentage = 0.5f; this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; this->colorBarPrecisionDigits = 2; -- GitLab From 22de451c393adeed836991e283c5ccc42afea546 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 15:37:49 -0500 Subject: [PATCH 383/755] Resolve WB-728: Image capture message: The message is now non-modal and does not block access to the user-interface. --- src/GuiQt/ImageCaptureDialog.cxx | 6 +-- src/GuiQt/UserInputModeImage.cxx | 10 ++--- src/GuiQt/WuQTimedMessageDisplay.cxx | 65 +++++++++++++++++++++------- src/GuiQt/WuQTimedMessageDisplay.h | 25 ++++++----- 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/GuiQt/ImageCaptureDialog.cxx b/src/GuiQt/ImageCaptureDialog.cxx index 2977dbdc5..722ce44d2 100644 --- a/src/GuiQt/ImageCaptureDialog.cxx +++ b/src/GuiQt/ImageCaptureDialog.cxx @@ -1205,9 +1205,9 @@ ImageCaptureDialog::applyButtonClicked() QWidget* parent = getDialogButtonBox()->button(QDialogButtonBox::Apply); CaretAssert(parent); - WuQTimedMessageDisplay::show(parent, - 0.5, - "Image captured"); + WuQTimedMessageDisplay::showNonModal(parent, + 3.0, + "Image captured"); } EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(browserWindowIndex).getPointer()); diff --git a/src/GuiQt/UserInputModeImage.cxx b/src/GuiQt/UserInputModeImage.cxx index 3d4ec5f3e..1af2a6a91 100644 --- a/src/GuiQt/UserInputModeImage.cxx +++ b/src/GuiQt/UserInputModeImage.cxx @@ -225,11 +225,11 @@ UserInputModeImage::mouseLeftClick(const MouseEvent& mouseEvent) updateAfterControlPointsChanged(); if ( ! toolTipMessage.isEmpty()) { - WuQTimedMessageDisplay::show(openGLWidget, - mouseEvent.getX(), - mouseEvent.getY(), - 2, - toolTipMessage); + WuQTimedMessageDisplay::showModal(openGLWidget, + mouseEvent.getX(), + mouseEvent.getY(), + 2, + toolTipMessage); } } diff --git a/src/GuiQt/WuQTimedMessageDisplay.cxx b/src/GuiQt/WuQTimedMessageDisplay.cxx index b9cdd9531..b9b6754c6 100644 --- a/src/GuiQt/WuQTimedMessageDisplay.cxx +++ b/src/GuiQt/WuQTimedMessageDisplay.cxx @@ -55,10 +55,13 @@ using namespace caret; * Message is displayed for this amount of time, in milliseconds. * @param message * Message that is displayed. + * @param modalFlag + * If true dialog is modal. */ WuQTimedMessageDisplay::WuQTimedMessageDisplay(QWidget* parent, const float displayForSeconds, - const QString& message) + const QString& message, + const bool modalFlag) : QDialog(parent, Qt::FramelessWindowHint) { @@ -68,7 +71,7 @@ WuQTimedMessageDisplay::WuQTimedMessageDisplay(QWidget* parent, /* * Modal so it blocks until done. */ - setModal(true); + setModal(modalFlag); /* * Delete self when done. @@ -94,8 +97,14 @@ WuQTimedMessageDisplay::WuQTimedMessageDisplay(QWidget* parent, */ QTimer* timer = new QTimer(this); timer->setSingleShot(true); - QObject::connect(timer, SIGNAL(timeout()), - this, SLOT(accept())); + if (modalFlag) { + QObject::connect(timer, SIGNAL(timeout()), + this, SLOT(accept())); + } + else { + QObject::connect(timer, SIGNAL(timeout()), + this, SLOT(close())); + } timer->start(displayForSeconds * 1000.0); /* @@ -117,16 +126,42 @@ WuQTimedMessageDisplay::WuQTimedMessageDisplay(QWidget* parent, * Message that is displayed. */ void -WuQTimedMessageDisplay::show(QWidget* parent, - const float displayForSeconds, - const QString& message) +WuQTimedMessageDisplay::showModal(QWidget* parent, + const float displayForSeconds, + const QString& message) { WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, displayForSeconds, - message); + message, + true); md->exec(); } +/** + * Display a message containing the given message for the given amount + * of time. This method will return IMMEDIATELY and the message will + * delete its self when closed. + * + * @param parent + * Parent on which message is displayed. + * @param displayForSeconds + * Message is displayed for this amount of time, in milliseconds. + * @param message + * Message that is displayed. + */ +void +WuQTimedMessageDisplay::showNonModal(QWidget* parent, + const float displayForSeconds, + const QString& message) +{ + WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, + displayForSeconds, + message, + false); + md->show(); + md->raise(); +} + /** * Display a message containing the given message for the given amount * of time. This method will not return until the message window closes. @@ -143,15 +178,16 @@ WuQTimedMessageDisplay::show(QWidget* parent, * Message that is displayed. */ void -WuQTimedMessageDisplay::show(QWidget* parent, - const int32_t x, - const int32_t y, - const float displayForSeconds, - const QString& message) +WuQTimedMessageDisplay::showModal(QWidget* parent, + const int32_t x, + const int32_t y, + const float displayForSeconds, + const QString& message) { WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, displayForSeconds, - message); + message, + true); const int32_t originAtTopWindowY = parent->height() - y; QPoint globalXY = parent->mapToGlobal(QPoint(x, originAtTopWindowY)); @@ -164,6 +200,5 @@ WuQTimedMessageDisplay::show(QWidget* parent, */ WuQTimedMessageDisplay::~WuQTimedMessageDisplay() { - } diff --git a/src/GuiQt/WuQTimedMessageDisplay.h b/src/GuiQt/WuQTimedMessageDisplay.h index 13c1f0576..2813763cf 100644 --- a/src/GuiQt/WuQTimedMessageDisplay.h +++ b/src/GuiQt/WuQTimedMessageDisplay.h @@ -34,18 +34,23 @@ namespace caret { private: WuQTimedMessageDisplay(QWidget* parent, const float displayForSeconds, - const QString& message); + const QString& message, + const bool modalFlag); public: - static void show(QWidget* parent, - const float displayForSeconds, - const QString& message); + static void showModal(QWidget* parent, + const float displayForSeconds, + const QString& message); - static void show(QWidget* parent, - const int32_t x, - const int32_t y, - const float displayForSeconds, - const QString& message); + static void showNonModal(QWidget* parent, + const float displayForSeconds, + const QString& message); + + static void showModal(QWidget* parent, + const int32_t x, + const int32_t y, + const float displayForSeconds, + const QString& message); virtual ~WuQTimedMessageDisplay(); @@ -59,7 +64,7 @@ namespace caret { // ADD_NEW_METHODS_HERE private: - + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 8824bf28c7378257d90cb142b0e5788b6cef5de7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Sep 2017 15:39:15 -0500 Subject: [PATCH 384/755] Call to set the normalization mode in the copy constructor of CaretMappableDataFile was removed. It is not necessary since the the normalization mode is stored in the metadata (which is copied) and it may cause a crash since the function is virtual and called in a constructor. --- src/Files/CaretMappableDataFile.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Files/CaretMappableDataFile.cxx b/src/Files/CaretMappableDataFile.cxx index 126906ad7..507c006b1 100644 --- a/src/Files/CaretMappableDataFile.cxx +++ b/src/Files/CaretMappableDataFile.cxx @@ -115,7 +115,6 @@ CaretMappableDataFile::initializeCaretMappableDataFileInstance() void CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& cmdf) { - setPaletteNormalizationMode(cmdf.getPaletteNormalizationMode()); *m_labelDrawingProperties = *cmdf.m_labelDrawingProperties; } -- GitLab From 7fb57b46a9819bbacd43fabb969be23e4769ec3f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Sep 2017 12:37:09 -0500 Subject: [PATCH 385/755] Resolve WB-740: Y-range of histogram changes when Y-axis is turned on and off: Logic that determined the correct range for an axis was not performed when the axis was off and has been corrected. --- .../BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 7fa6973a1..2ebbe1e86 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1710,6 +1710,22 @@ m_tabViewportHeight(tabViewport[3]) break; } + /* + * This is necessary so that the correct axis minimum and + * maximum values (m_axisMinimumValue and m_axisMaximumValue). + */ + if (m_axis != NULL) { + std::vector scaleValuePositions; + std::vector scaleValuesText; + m_axis->getScaleValuesAndOffsets(dataMinimumValue, + dataMaximumValue, + 1.0, + m_axisMinimumValue, + m_axisMaximumValue, + scaleValuePositions, + scaleValuesText); + } + return; } -- GitLab From ed09aa46d33629a151c4a871be03f598c5f48f28 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Sep 2017 15:16:44 -0500 Subject: [PATCH 386/755] Resolve WB-70-9 OpenGL buffer may not be getting released in wb_command: Fixing this will require restructuring wb_command that will make the command slower (scene will need to be loaded for each window) when there is more than one window. So, for wb_command do not print these messages. --- .../EventGraphicsOpenGLDeleteBufferObject.cxx | 34 ++++++++++++++----- src/Palette/PaletteColorMappingSaxReader.cxx | 3 +- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx index 26d11ed6f..a28ae6c2f 100644 --- a/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx +++ b/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx @@ -23,6 +23,7 @@ #include "EventGraphicsOpenGLDeleteBufferObject.h" #undef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ +#include "ApplicationInformation.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" @@ -58,14 +59,31 @@ m_openglBufferObject(openglBufferObject) */ EventGraphicsOpenGLDeleteBufferObject::~EventGraphicsOpenGLDeleteBufferObject() { - if (this->getEventProcessCount() <= 0) { - CaretLogSevere("Deletion of OpenGL Buffer Object Name=" - + AString::number(m_openglBufferObject->getBufferObjectName()) - + ", context pointer=" - + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer()) - + " appears to have failed. The events processed count is zero and that " - "indicates that the event was not received in any listener or the " - "listener failed to set the event as processed."); + switch (ApplicationInformation::getApplicationType()) { + case ApplicationTypeEnum::APPLICATION_TYPE_COMMAND_LINE: + /* + * Do not test for deletion of OpenGL buffers with + * the command line program as will require redesign + * of the -show-scene command and would likely require + * loading of the scene for each window. + */ + break; + case ApplicationTypeEnum::APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE: + /* + * Only perform this test for the GUI application. + */ + if (this->getEventProcessCount() <= 0) { + CaretLogSevere("Deletion of OpenGL Buffer Object Name=" + + AString::number(m_openglBufferObject->getBufferObjectName()) + + ", context pointer=" + + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer()) + + " appears to have failed. The events processed count is zero and that " + "indicates that the event was not received in any listener or the " + "listener failed to set the event as processed."); + } + break; + case ApplicationTypeEnum::APPLICATION_TYPE_INVALID: + break; } } diff --git a/src/Palette/PaletteColorMappingSaxReader.cxx b/src/Palette/PaletteColorMappingSaxReader.cxx index 54905dcc6..0c3e39ae6 100644 --- a/src/Palette/PaletteColorMappingSaxReader.cxx +++ b/src/Palette/PaletteColorMappingSaxReader.cxx @@ -343,8 +343,7 @@ PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, + this->elementText); } } - else - if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE) { + else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE) { this->paletteColorMapping->setHistogramEnvelopeLineWidthPercentage(this->elementText.toFloat()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS) { -- GitLab From d7b15c5b8dc2b9a142347270c5f55e04b08bfb54 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Sep 2017 17:22:22 -0500 Subject: [PATCH 387/755] In an attempt to improve WB-729: When a tab is selected with Tile Tabs on, a box is drawn around the selected tab. The time has been increased from 3/4 second to 5 seconds to that redraw events are not issued while the user is dragging a tab to move it. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index fec6875e0..d37bacf73 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1276,7 +1276,7 @@ BrainBrowserWindowToolBar::selectedTabChanged(int indx) * Note: There is no need to 'stop' the timer if it is running * as the start() method will stop and restart the timer */ - const int timeInMilliseconds = 750; + const int timeInMilliseconds = 5000; m_tileTabsHighlightingTimer->setSingleShot(true); m_tileTabsHighlightingTimer->start(timeInMilliseconds); } -- GitLab From 9574a74e035a3afbdae5bafcd517b420f725697d Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 7 Sep 2017 17:51:04 -0500 Subject: [PATCH 388/755] setting tab highlight box display time back to previous value, as it had no noticeable effect --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index d37bacf73..fec6875e0 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1276,7 +1276,7 @@ BrainBrowserWindowToolBar::selectedTabChanged(int indx) * Note: There is no need to 'stop' the timer if it is running * as the start() method will stop and restart the timer */ - const int timeInMilliseconds = 5000; + const int timeInMilliseconds = 750; m_tileTabsHighlightingTimer->setSingleShot(true); m_tileTabsHighlightingTimer->start(timeInMilliseconds); } -- GitLab From 93037be397650dfeffc1a8a63cdbacacf356586d Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 8 Sep 2017 14:58:39 -0500 Subject: [PATCH 389/755] add -parallel-help to completions --- src/Commands/CommandOperationManager.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 658f7bdb2..72d173e61 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -719,7 +719,7 @@ AString CommandOperationManager::doCompletion(ProgramParameters& parameters, con const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); if (!parameters.hasNext()) {//suggest all commands, including deprecated and informational (order doesn't matter, bash sorts them before displaying) - ret += "\\ -help\\ -arguments-help\\ -cifti-help\\ -gifti-help\\ -version\\ -list-commands\\ -list-deprecated-commands\\ -all-commands-help"; + ret += "\\ -help\\ -arguments-help\\ -cifti-help\\ -gifti-help\\ -parallel-help\\ -version\\ -list-commands\\ -list-deprecated-commands\\ -all-commands-help"; for (uint64_t i = 0; i < numberOfCommands; i++) { ret += "\\ " + commandOperations[i]->getCommandLineSwitch(); -- GitLab From b83f9b8bca3d27a127f349a4da1f0bf2b6ece80a Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 18 Sep 2017 15:50:21 -0500 Subject: [PATCH 390/755] fix repetitiveness of repeatable option in arguments help --- src/Commands/CommandOperationManager.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Commands/CommandOperationManager.cxx b/src/Commands/CommandOperationManager.cxx index 72d173e61..10f2a4bf7 100644 --- a/src/Commands/CommandOperationManager.cxx +++ b/src/Commands/CommandOperationManager.cxx @@ -1002,7 +1002,7 @@ void CommandOperationManager::printArgumentsHelp(const AString& programName) cout << " [-fixnan] - replace NaN results with a value" << endl; cout << " - value to replace NaN with" << endl; cout << endl;//guide for wrap, assuming 80 columns: | - cout << " [-var] (repeatable) - repeatable - a volume file to use as a variable" << endl; + cout << " [-var] - repeatable - a volume file to use as a variable" << endl; cout << " - the name of the variable, as used in the expression" << endl; cout << " - the volume file to use as this variable" << endl; cout << endl;//guide for wrap, assuming 80 columns: | @@ -1014,7 +1014,7 @@ void CommandOperationManager::printArgumentsHelp(const AString& programName) cout << endl;//guide for wrap, assuming 80 columns: | cout << " '' and '' denote mandatory parameters. '[-fixnan]'" << endl; cout << " denotes an option taking one mandatory parameter '', and" << endl; - cout << " '[-var] (repeatable)' denotes a repeatable option with mandatory parameters" << endl; + cout << " '[-var] - repeatable' denotes a repeatable option with mandatory parameters" << endl; cout << " '' and '', and two suboptions: '[-subvolume]', which has a" << endl; cout << " mandatory parameter '', and '[-repeat]', which takes no parameters." << endl; cout << " Commands also provide additional help info below the section in the example." << endl; -- GitLab From 29e1dae799611e4daa632c76e0b5312f5e8591d1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 11 Sep 2017 09:21:58 -0500 Subject: [PATCH 391/755] Resolve WB-736: In new matrix charting, clicking wrench button may crash wb_view --- src/Brain/Brain.cxx | 26 ++++++++++++++++++++ src/Brain/Brain.h | 2 ++ src/Files/ChartableTwoFileMatrixChart.cxx | 30 +++++++++++++++++++++++ src/Files/ChartableTwoFileMatrixChart.h | 2 ++ 4 files changed, 60 insertions(+) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 28b08087e..cc5a1181b 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -39,6 +39,7 @@ #include "CaretPreferences.h" #include "ChartingDataManager.h" #include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileMatrixChart.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiBrainordinateLabelFile.h" @@ -5223,6 +5224,8 @@ Brain::addReadOrReloadDataFile(const FileModeAddReadReload fileMode, throw dfe; } + loadMatrixChartingFileDefaultRowOrColumn(caretDataFileRead); + updateAfterFilesAddedOrRemoved(); return caretDataFileRead; @@ -7187,6 +7190,8 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, caretDataFile->restoreFromScene(sceneAttributes, bestMatchingSceneClass); } + + loadMatrixChartingFileDefaultRowOrColumn(caretDataFile); } } @@ -7311,6 +7316,27 @@ Brain::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAnnotationFile->clearModified(); } +/** + * Load the default row/column for a matrix charting file. + * If the file is not matrix chartable, no action is taken. + * + * @param caretDataFile + * The Caret Data File. + */ +void +Brain::loadMatrixChartingFileDefaultRowOrColumn(CaretDataFile* caretDataFile) +{ + if (caretDataFile == NULL) { + return; + } + + CaretMappableDataFile* cmdf = dynamic_cast(caretDataFile); + if (cmdf != NULL) { + cmdf->getChartingDelegate()->getMatrixCharting()->loadDefaultRowOrColumn(); + } +} + + /** * If model one charts are in scene but not * model two charts, attempt to restore model diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index adb191341..b3af92374 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -409,6 +409,8 @@ namespace caret { void restoreModelChartOneToModelChartTwo(); + void loadMatrixChartingFileDefaultRowOrColumn(CaretDataFile* caretDataFile); + IdentificationManager* getIdentificationManager(); SelectionManager* getSelectionManager(); diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 38df3c679..43f2f8fbc 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -699,6 +699,36 @@ ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, } } +/** + * Load a row or column if none are loaded. + * + */ +void +ChartableTwoFileMatrixChart::loadDefaultRowOrColumn() +{ + if (getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { + return; + } + if (m_matrixDataFileType == MatrixDataFileType::INVALID) { + return; + } + + const int32_t tabIndex = BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS - 1; + ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension = getSelectedRowColumnDimension(); + std::vector selectedRowIndices; + std::vector selectedColumnIndices; + + getSelectedRowColumnIndices(tabIndex, + rowColumnDimension, + selectedRowIndices, + selectedColumnIndices); + + if (selectedRowIndices.empty() + && selectedRowIndices.empty()) { + setSelectedRowColumnIndex(tabIndex, 0); + } +} + /** * @return True if the file supports row selection. */ diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index 0596efcf5..bcec3c116 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -84,6 +84,8 @@ namespace caret { bool hasColumnSelection() const; + void loadDefaultRowOrColumn(); + AString getRowNumberAndName(const int32_t rowIndex) const; AString getColumnNumberAndName(const int32_t columnIndex) const; -- GitLab From 7a147378c916f80f0496cd7e52dfc2049798a7c7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 11 Sep 2017 15:44:30 -0500 Subject: [PATCH 392/755] Resolve WB-737: Selecting a dynamic connectivity file as histogram may crash wb_view if no data: If a histogram is not valid (no data has been loaded form dynamic file), wb_view will not crash. --- ...BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 6 +++++- src/Brain/BrowserTabContent.cxx | 16 +++++++++++----- src/Brain/ChartTwoOverlay.cxx | 18 ++++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 2ebbe1e86..648851359 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -399,7 +399,11 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, (chartOverlay->isAllMapsSupported() && chartOverlay->isAllMapsSelected())); - CaretAssert(histogram); + if (histogram == NULL) { + histogramDrawingInfo.pop_back(); + continue; + } + float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); if (histogramMaxX > histogramMinX) { diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 05b2bae2f..bbcf1f8e7 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -1562,11 +1562,17 @@ BrowserTabContent::getAnnotationColorBars(std::vector& colo break; } - paletteColorMapping->setupAnnotationColorBar(statistics, - info.m_colorBar); - - info.m_colorBar->setTabIndex(m_tabNumber); - colorBarsOut.push_back(info.m_colorBar); + /* + * Statistics may be NULL for some instances of histograms + * from dynamically loaded files (dynconn) + */ + if (statistics != NULL) { + paletteColorMapping->setupAnnotationColorBar(statistics, + info.m_colorBar); + + info.m_colorBar->setTabIndex(m_tabNumber); + colorBarsOut.push_back(info.m_colorBar); + } } } } diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index c1fa00a2f..4722bd658 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -550,14 +550,16 @@ ChartTwoOverlay::getBounds(BoundingBox& boundingBoxOut) const const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, (isAllMapsSupported() && isAllMapsSelected())); - CaretAssert(histogram); - float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; - histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); - if (histogramMaxX > histogramMinX) { - boundingBoxOut.set(histogramMinX, histogramMaxX, - 0.0f, histogramMaxY, - 0.0f, 0.0f); - validFlag = true; + //CaretAssert(histogram); + if (histogram != NULL) { + float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; + histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); + if (histogramMaxX > histogramMinX) { + boundingBoxOut.set(histogramMinX, histogramMaxX, + 0.0f, histogramMaxY, + 0.0f, 0.0f); + validFlag = true; + } } } break; -- GitLab From 398e71501260a00a9162e6cba11758c3d83b8877 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 12 Sep 2017 15:21:40 -0500 Subject: [PATCH 393/755] Resolve WB-695: Need to be able to set base directory when creating ZIP in scene GUI AND WB-732 No intuitive way to set base dir when zipping scene: Add user-interface components so that the user is able to set the base directory by entering its name, browsing using a file selection dialog or by pressing the new 'Find' button. The 'Find' button will examine files within all scenes in a scene file to find the base directory. Note that in a scene, files in the spec file use the 'ScenePathName' object type are use the object name 'fileName' (not used anywhere else). In addition, the name of the Spec File is examined when finding the base directory. The AString class was modified to find the common prefix for a vector of strings. --- src/Common/AString.cxx | 75 +++++++++ src/Common/AString.h | 3 + src/Files/SceneFile.cxx | 53 ++++++ src/Files/SceneFile.h | 2 + src/GuiQt/ZipSceneFileDialog.cxx | 268 +++++++++++++++++++++++++++++-- src/GuiQt/ZipSceneFileDialog.h | 37 ++++- 6 files changed, 424 insertions(+), 14 deletions(-) diff --git a/src/Common/AString.cxx b/src/Common/AString.cxx index c28ea0dbf..e1d844330 100644 --- a/src/Common/AString.cxx +++ b/src/Common/AString.cxx @@ -21,6 +21,7 @@ #include #include "AString.h" +#include "CaretAssert.h" #include "CaretLogger.h" #include @@ -913,4 +914,78 @@ AString::countMatchingCharactersFromEnd(const AString& rhs) const return matchCount; } +/** + * Find the longest common prefix in the given vector of strings. + * + * @param v + * A vector of strings + * @return + * Longest common prefix found (may be an empty string). + */ +AString +AString::findLongestCommonPrefix(const std::vector& stringVector) +{ + AString longestPrefix; + + const int32_t numStrings = static_cast(stringVector.size()); + if (numStrings == 1) { + CaretAssertVectorIndex(stringVector, 0); + longestPrefix = stringVector[0]; + } + else if (numStrings > 1) { + /* + * Find string with shortest name + */ + CaretAssertVectorIndex(stringVector, 0); + AString shortestString = stringVector[0]; + for (const auto name : stringVector) { + if (name.length() < shortestString.length()) { + shortestString = name; + } + } + + /* + * Loop through each character in the shortest string + * until a character does not match in any strings + */ + const int32_t numChars = static_cast(shortestString.length()); + for (int32_t ich = 0; ich < numChars; ich++) { + const QChar character = shortestString.at(ich); + + bool allMatchFlag = true; + for (const auto name : stringVector) { + CaretAssert(ich < name.length()); + if (name.at(ich) != character) { + allMatchFlag = false; + } + } + + if (allMatchFlag) { + longestPrefix.append(character); + } + else { + break; + } + } + } + + /* + * If the last character is a '/', remove it + */ + if (longestPrefix.length() > 1) { + if (longestPrefix.endsWith('/')) { + longestPrefix.resize(longestPrefix.length() - 1); + } + } + + const bool debugFlag = false; + if (debugFlag) { + std::cout << "Longest prefix: " << longestPrefix << std::endl; + for (const auto name : stringVector) { + std::cout << " " << name << std::endl; + } + } + + return longestPrefix; +} diff --git a/src/Common/AString.h b/src/Common/AString.h index 2b532fb33..3be009fdd 100644 --- a/src/Common/AString.h +++ b/src/Common/AString.h @@ -131,6 +131,9 @@ namespace caret { AString replaceHtmlSpecialCharactersWithEscapeCharacters() const; AString fixUnicodeHyphens(bool* hyphenReplaced = NULL, bool* hadOtherNonAscii = NULL, const bool& quiet = false) const; + + static AString findLongestCommonPrefix(const std::vector& v); + }; } diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index f7dd23d9e..8bfb9d91e 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -24,6 +24,7 @@ #include #include +#include #define __SCENE_FILE_DECLARE__ #include "SceneFile.h" @@ -42,6 +43,7 @@ #include "SceneClassArray.h" #include "SceneFileSaxReader.h" #include "SceneInfo.h" +#include "ScenePathName.h" #include "SceneXmlElements.h" #include "SceneWriterXml.h" #include "SpecFile.h" @@ -804,6 +806,57 @@ SceneFile::setBalsaExtractToDirectoryName(const AString& extractToDirectoryName) } } +/** + * return Base directory for data files. + * The base directory is a directory that is parent to all loaded data files. + */ +AString +SceneFile::findBaseDirectoryForDataFiles() const +{ + std::set directoryNames; + + /** + * Find all 'path name' elements from ALL scenes + */ + for (Scene* scene: m_scenes) { + CaretAssert(scene); + std::vector children = scene->getDescendants(); + for (SceneObject* sceneObject : children) { + CaretAssert(sceneObject); + if (sceneObject->getDataType() == SceneObjectDataTypeEnum::SCENE_PATH_NAME) { + const ScenePathName* scenePathName = dynamic_cast(sceneObject); + /* + * Will be NULL for 'path name arrays' which we ignore + */ + if (scenePathName != NULL) { + /* + * files in spec file are named "fileName" in the scene + * specFile is named "specFileName" + * and these names are unique to name of files in the spec file + */ + if ((sceneObject->getName() == "fileName") + || (sceneObject->getName() == "specFileName")) { + const AString pathName = scenePathName->stringValue().trimmed(); + if ( ! pathName.isEmpty()) { + FileInformation fileInfo(pathName); + const AString dirName = fileInfo.getAbsolutePath().trimmed(); + if ( ! dirName.isEmpty()) { + directoryNames.insert(dirName); + } + } + } + } + } + } + } + + const std::vector stringVector(directoryNames.begin(), + directoryNames.end()); + const AString baseDirectoryName = AString::findLongestCommonPrefix(stringVector); + + return baseDirectoryName; +} + /** * @return Default name for a ZIP file containing the scene file and its data files. */ diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 05da4495d..dedb396c1 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -95,6 +95,8 @@ namespace caret { void setBalsaBaseDirectory(const AString& balsaBaseDirectory); + AString findBaseDirectoryForDataFiles() const; + void reorderScenes(std::vector& orderedScenes); int32_t getSceneIndexFromNumberOrName(const AString& numberOrName); diff --git a/src/GuiQt/ZipSceneFileDialog.cxx b/src/GuiQt/ZipSceneFileDialog.cxx index 675baf500..973f16136 100644 --- a/src/GuiQt/ZipSceneFileDialog.cxx +++ b/src/GuiQt/ZipSceneFileDialog.cxx @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "BalsaDatabaseManager.h" #include "Brain.h" @@ -34,6 +36,7 @@ #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CursorDisplayScoped.h" +#include "DataFileException.h" #include "FileInformation.h" #include "GuiManager.h" #include "SceneFile.h" @@ -56,7 +59,7 @@ using namespace caret; * @param parent * Parent of this dialog. */ -ZipSceneFileDialog::ZipSceneFileDialog(const SceneFile* sceneFile, +ZipSceneFileDialog::ZipSceneFileDialog(SceneFile* sceneFile, QWidget* parent) : WuQDialogModal("Zip Scene File", parent), @@ -65,7 +68,7 @@ m_sceneFile(sceneFile) const int minimumLineEditWidth = 400; - AString extractToDirectoryName("ext_dir"); + AString defaultExtractToDirectoryName("ext_dir"); AString zipFileName("file.zip"); FileInformation fileInfo(sceneFile->getFileName()); AString sceneFileDirectory = fileInfo.getAbsolutePath(); @@ -75,7 +78,7 @@ m_sceneFile(sceneFile) const AString dirName = dir.dirName(); if ( ! dirName.isEmpty()) { if (dirName != ".") { - extractToDirectoryName = dirName; + defaultExtractToDirectoryName = dirName; } } } @@ -90,19 +93,61 @@ m_sceneFile(sceneFile) "zip"); } - QLabel* zipFileNameLabel = new QLabel("Zip File Name"); + /* + * ZIP file + */ + m_zipFileNameLabel = new QLabel("Zip File Name"); m_zipFileNameLineEdit = new QLineEdit; + m_zipFileNameLineEdit->setToolTip("Name of the ZIP file"); m_zipFileNameLineEdit->setMinimumWidth(minimumLineEditWidth); m_zipFileNameLineEdit->setText(zipFileName); + m_zipFileNameLineEdit->setValidator(createValidator(LabelName::ZIP_FILE)); + QObject::connect(m_zipFileNameLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); + /* + * Zip file button + */ QPushButton* chooseZipFileButton = new QPushButton("Choose..."); QObject::connect(chooseZipFileButton, SIGNAL(clicked()), this, SLOT(chooseZipFileButtonClicked())); - QLabel* extractDirectoryLabel = new QLabel("Extract to Directory"); + /* + * Extract to directory + */ + m_extractDirectoryLabel = new QLabel("Extract to Directory"); m_extractDirectoryNameLineEdit = new QLineEdit(); + m_extractDirectoryNameLineEdit->setToolTip("Directory that is created when user unzips the ZIP file"); m_extractDirectoryNameLineEdit->setMinimumWidth(minimumLineEditWidth); - m_extractDirectoryNameLineEdit->setText(extractToDirectoryName); + m_extractDirectoryNameLineEdit->setValidator(createValidator(LabelName::EXTRACT_DIRECTORY)); + QObject::connect(m_extractDirectoryNameLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); + + /* + * Base Directory + */ + m_baseDirectoryLabel = new QLabel("Base Directory"); + m_baseDirectoryLineEdit = new QLineEdit(); + m_baseDirectoryLineEdit->setToolTip("Directory that contains all data files"); + m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::BASE_DIRECTORY)); + QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, + this, [=] { this->validateData(); }); + + /* + * Browse for base directory + */ + m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); + m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); + QObject::connect(m_browseBaseDirectoryPushButton, &QPushButton::clicked, + this, &ZipSceneFileDialog::browseBaseDirectoryPushButtonClicked); + + /* + * Browse for base directory + */ + m_findBaseDirectoryPushButton = new QPushButton("Find"); + m_findBaseDirectoryPushButton->setToolTip("Find the base directory by examining files in all scenes"); + QObject::connect(m_findBaseDirectoryPushButton, &QPushButton::clicked, + this, &ZipSceneFileDialog::findBaseDirectoryPushButtonClicked); QWidget* dialogWidget = new QWidget(); @@ -110,18 +155,38 @@ m_sceneFile(sceneFile) gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); + gridLayout->setColumnStretch(3, 0); int row = 0; - gridLayout->addWidget(zipFileNameLabel, row, 0); + gridLayout->addWidget(m_zipFileNameLabel, row, 0); gridLayout->addWidget(m_zipFileNameLineEdit, row, 1); gridLayout->addWidget(chooseZipFileButton, row, 2); row++; - gridLayout->addWidget(extractDirectoryLabel, row, 0); + gridLayout->addWidget(m_extractDirectoryLabel, row, 0); gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1); row++; + gridLayout->addWidget(m_baseDirectoryLabel, row, 0); + gridLayout->addWidget(m_baseDirectoryLineEdit, row, 1); + gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, 2); + gridLayout->addWidget(m_findBaseDirectoryPushButton, row, 3); + row++; + AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); + if (baseDirectory.isEmpty()) { + FileInformation fileInfo(m_sceneFile->getFileName()); + baseDirectory = fileInfo.getPathName(); + } + m_baseDirectoryLineEdit->setText(baseDirectory); + + AString extractDirectory = m_sceneFile->getBalsaExtractToDirectoryName(); + if (extractDirectory.isEmpty()) { + extractDirectory = m_sceneFile->getDefaultExtractToDirectoryName(); + } + m_extractDirectoryNameLineEdit->setText(extractDirectory); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); + + validateData(); } /** @@ -131,6 +196,14 @@ ZipSceneFileDialog::~ZipSceneFileDialog() { } +void +ZipSceneFileDialog::validateData() +{ + setLabelText(LabelName::BASE_DIRECTORY); + setLabelText(LabelName::EXTRACT_DIRECTORY); + setLabelText(LabelName::ZIP_FILE); +} + /** * Choose the zip file name with a file browser dialog. */ @@ -168,11 +241,36 @@ ZipSceneFileDialog::okButtonClicked() if (zipFileName.isEmpty()) { errorMessage.appendWithNewLine("Zip file name is missing"); } - if (extractToDirectoryName.isEmpty()) { - errorMessage.appendWithNewLine("Extract to directory is missing."); + if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { + errorMessage.appendWithNewLine("Extract to Directory is invalid.

"); + } + if ( ! m_baseDirectoryLineEdit->hasAcceptableInput()) { + errorMessage.appendWithNewLine("Base Directory is invalid.

"); } if (errorMessage.isEmpty()) { + m_sceneFile->setBalsaBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); + m_sceneFile->setBalsaExtractToDirectoryName(extractToDirectoryName); + + if (m_sceneFile->isModified()) { + const QString msg("The scene file is modified and must be saved before continuing. Would you like " + "to save the scene file using its current name and continue?"); + if (WuQMessageBox::warningYesNo(this, msg)) { + try { + Brain* brain = GuiManager::get()->getBrain(); + brain->writeDataFile(m_sceneFile); + } + catch (const DataFileException& e) { + WuQMessageBox::errorOk(this, e.whatString()); + return; + } + } + else { + return; + } + } + + CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -202,3 +300,153 @@ ZipSceneFileDialog::okButtonClicked() WuQDialogModal::okButtonClicked(); } +/** + * Called when find base directory push button is clicked. + */ +void +ZipSceneFileDialog::findBaseDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + const AString baseDirectoryName = m_sceneFile->findBaseDirectoryForDataFiles(); + + if (baseDirectoryName.isEmpty()) { + return; + } + + /* + * Set name for base directory + */ + m_baseDirectoryLineEdit->setText(baseDirectoryName); + validateData(); +} + + +/** + * Called when browse base directory push button is clicked. + */ +void +ZipSceneFileDialog::browseBaseDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + /* + * Let user choose directory path + */ + QString directoryName; + FileInformation fileInfo(m_baseDirectoryLineEdit->text().trimmed()); + if (fileInfo.exists()) { + if (fileInfo.isDirectory()) { + directoryName = fileInfo.getAbsoluteFilePath(); + } + } + AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, + "Choose Base Directory", + directoryName); + /* + * If user cancels, return + */ + if (newDirectoryName.isEmpty()) { + return; + } + + /* + * Set name of base directory + */ + m_baseDirectoryLineEdit->setText(newDirectoryName); + validateData(); +} + +/** + * Create a regular expression validatory for the give label/data. + * + * @param labelName + * 'Name' of label. + */ +QRegularExpressionValidator* +ZipSceneFileDialog::createValidator(const LabelName labelName) +{ + QRegularExpression regEx; + + switch (labelName) { + case LabelName::BASE_DIRECTORY: + regEx.setPattern(".+"); + break; + case LabelName::EXTRACT_DIRECTORY: + regEx.setPattern(".+"); + break; + case LabelName::ZIP_FILE: + regEx.setPattern(".+\\.zip$"); + break; + } + CaretAssert(regEx.isValid()); + + QRegularExpressionValidator* validator = new QRegularExpressionValidator(regEx, + this); + return validator; +} + +/** + * Set the label's text. + * + * @param label + * The label + * @param labelName + * 'Name' of the label + */ +void +ZipSceneFileDialog::setLabelText(const LabelName labelName) +{ + QLabel* label = NULL; + AString labelText; + bool validFlag = false; + switch (labelName) { + case LabelName::BASE_DIRECTORY: + label = m_baseDirectoryLabel; + labelText = "Base Directory"; + validFlag = m_baseDirectoryLineEdit->hasAcceptableInput(); + break; + case LabelName::EXTRACT_DIRECTORY: + label = m_extractDirectoryLabel; + labelText = "Extract to Directory"; + validFlag = m_extractDirectoryNameLineEdit->hasAcceptableInput(); + break; + case LabelName::ZIP_FILE: + label = m_zipFileNameLabel; + labelText = "Zip File"; + validFlag = m_zipFileNameLineEdit->hasAcceptableInput(); + break; + } + + const bool textRedIfInvalid = true; + + AString coloredText; + if (validFlag) { + if (textRedIfInvalid) { + coloredText = (labelText + + ": "); + } + else { + coloredText = (" " + + labelText + + ": "); + } + } + else { + if (textRedIfInvalid) { + coloredText = ("" + + labelText + + ": "); + } + else { + coloredText = ("" + + labelText + + "*" + ": "); + } + } + + CaretAssert(label); + label->setText(coloredText); +} + diff --git a/src/GuiQt/ZipSceneFileDialog.h b/src/GuiQt/ZipSceneFileDialog.h index 5615f196d..6f302c838 100644 --- a/src/GuiQt/ZipSceneFileDialog.h +++ b/src/GuiQt/ZipSceneFileDialog.h @@ -24,9 +24,10 @@ #include "WuQDialogModal.h" +class QLabel; class QLineEdit; - - +class QPushButton; +class QRegularExpressionValidator; namespace caret { @@ -37,7 +38,7 @@ namespace caret { Q_OBJECT public: - ZipSceneFileDialog(const SceneFile* sceneFile, + ZipSceneFileDialog(SceneFile* sceneFile, QWidget* parent); virtual ~ZipSceneFileDialog(); @@ -50,19 +51,47 @@ namespace caret { virtual void okButtonClicked(); private slots: + void browseBaseDirectoryPushButtonClicked(); + void chooseZipFileButtonClicked(); + void findBaseDirectoryPushButtonClicked(); + + void validateData(); + private: + enum class LabelName { + BASE_DIRECTORY, + EXTRACT_DIRECTORY, + ZIP_FILE + }; + ZipSceneFileDialog(const ZipSceneFileDialog&); ZipSceneFileDialog& operator=(const ZipSceneFileDialog&); - const SceneFile* m_sceneFile; + QRegularExpressionValidator* createValidator(const LabelName labelName); + + void setLabelText(const LabelName labelName); + + SceneFile* m_sceneFile; + + QLabel* m_zipFileNameLabel; QLineEdit* m_zipFileNameLineEdit; + QLabel* m_extractDirectoryLabel; + QLineEdit* m_extractDirectoryNameLineEdit; + QLabel* m_baseDirectoryLabel; + + QLineEdit* m_baseDirectoryLineEdit; + + QPushButton* m_findBaseDirectoryPushButton; + + QPushButton* m_browseBaseDirectoryPushButton; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From bcaeb06512f86a844ea1c40c069f1fa15188b565 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 12 Sep 2017 15:30:42 -0500 Subject: [PATCH 394/755] Added a "Find" button to the Upload Scene File to BALSA Dialog. The "Find" button is the same functionality as on the Zip Scene File Dialog that examines files in the scene to determine the "Base Directory". --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 38 +++++++++++++++++-- .../BalsaDatabaseUploadSceneFileDialog.h | 3 ++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 4ed33f315..1e47e5b73 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -273,8 +273,16 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() */ m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); - QObject::connect(m_browseBaseDirectoryPushButton, SIGNAL(clicked()), - this, SLOT(browseBaseDirectoryPushButtonClicked())); + QObject::connect(m_browseBaseDirectoryPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked); + + /* + * Browse for base directory + */ + m_findBaseDirectoryPushButton = new QPushButton("Find"); + m_findBaseDirectoryPushButton->setToolTip("Find the base directory by examining files in all scenes"); + QObject::connect(m_findBaseDirectoryPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked); int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; @@ -307,7 +315,8 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; gridLayout->addWidget(m_baseDirectoryLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_baseDirectoryLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, COLUMN_BUTTON_ONE, 1, 2); + gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, COLUMN_BUTTON_ONE); + gridLayout->addWidget(m_findBaseDirectoryPushButton, row, COLUMN_BUTTON_TWO); row++; gridLayout->addWidget(m_balsaStudyTitleLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, COLUMN_DATA_WIDGET); @@ -711,7 +720,7 @@ BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicke directoryName = fileInfo.getAbsoluteFilePath(); } } - AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, + AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_zipFileCustomDirectoryRadioButton, "Choose Custom Zip File Directory", directoryName); /* @@ -926,4 +935,25 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) label->setText(coloredText); } +/** + * Called when find base directory push button is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked() +{ + CaretAssert(m_sceneFile); + + const AString baseDirectoryName = m_sceneFile->findBaseDirectoryForDataFiles(); + + if (baseDirectoryName.isEmpty()) { + return; + } + + /* + * Set name for base directory + */ + m_baseDirectoryLineEdit->setText(baseDirectoryName); + validateData(); +} + diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 9e7badc38..c032ab173 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -68,6 +68,8 @@ namespace caret { void browseZipFileCustomDirectoryPushButtonClicked(); + void findBaseDirectoryPushButtonClicked(); + protected: virtual void okButtonClicked(); @@ -135,6 +137,7 @@ namespace caret { QPushButton* m_selectStudyTitlePushButton; QPushButton* m_browseBaseDirectoryPushButton; + QPushButton* m_findBaseDirectoryPushButton; QLabel* m_baseDirectoryLabel; QLineEdit* m_baseDirectoryLineEdit; -- GitLab From 386fb1bde1f7e96ebde57f6dd29bf3c0a070ea90 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Sep 2017 09:09:23 -0500 Subject: [PATCH 395/755] Resolve WB-702 - Move line chart history from its own dialog to map settings dialog: Added chart two line series history to the Overlay and Map Settings Dialog. --- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/ChartTwoOverlayViewController.cxx | 1 - src/GuiQt/GuiManager.cxx | 21 +- .../MapSettingsChartTwoLineHistoryWidget.cxx | 577 ++++++++++++++++++ .../MapSettingsChartTwoLineHistoryWidget.h | 134 ++++ src/GuiQt/OverlaySettingsEditorDialog.cxx | 175 ++++-- src/GuiQt/OverlaySettingsEditorDialog.h | 7 + 7 files changed, 838 insertions(+), 80 deletions(-) create mode 100644 src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx create mode 100644 src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 19ac8ffbf..a96ed9fa4 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -135,6 +135,7 @@ ELSE() LabelSelectionViewController.h MacApplication.h MacDockMenu.h + MapSettingsChartTwoLineHistoryWidget.h MapSettingsColorBarWidget.h MapSettingsFiberTrajectoryWidget.h MapSettingsLabelsWidget.h @@ -351,6 +352,7 @@ KeyEvent.h LabelSelectionViewController.h MacApplication.h MacDockMenu.h +MapSettingsChartTwoLineHistoryWidget.h MapSettingsColorBarWidget.h MapSettingsFiberTrajectoryWidget.h MapSettingsLabelsWidget.h @@ -564,6 +566,7 @@ KeyEvent.cxx LabelSelectionViewController.cxx MacApplication.cxx MacDockMenu.cxx +MapSettingsChartTwoLineHistoryWidget.cxx MapSettingsColorBarWidget.cxx MapSettingsFiberTrajectoryWidget.cxx MapSettingsLabelsWidget.cxx diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 64bc19f70..26c357112 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -792,7 +792,6 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - enableSettingsActionFlag = false; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index a6bf2c2ca..ceeca7072 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -118,7 +118,6 @@ #include "TileTabsConfigurationDialog.h" #include "VolumeMappableInterface.h" #include "WuQMessageBox.h" -//#include "WuQWebView.h" #include "WuQtUtilities.h" #include "CaretAssert.h" @@ -383,22 +382,6 @@ GuiManager::getBrain() const return SessionManager::get()->getBrain(0); } -/** - * Get the Brain OpenGL for drawing with OpenGL. - * - * @return - * Point to the brain. - */ -//BrainOpenGL* -//GuiManager::getBrainOpenGL() -//{ -// if (this->brainOpenGL == NULL) { -// this->brainOpenGL = BrainOpenGL::getBrainOpenGL(); -// } -// -// return this->brainOpenGL; -//} - /** * See if a brain browser window can be closed. If there is only * one brain browser window, the user will be warned that any @@ -1341,6 +1324,10 @@ GuiManager::receiveEvent(Event* event) if (m_chartTwoLineSeriesHistoryDialog != NULL) { m_chartTwoLineSeriesHistoryDialog->updateDialog(); } + + for (auto overlayEditor : m_overlaySettingsEditors) { + overlayEditor->updateChartLinesInDialog(); + } } else if (event->getEventType() == EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE) { EventMacDockMenuUpdate* macDockMenuEvent = dynamic_cast(event); diff --git a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx new file mode 100644 index 000000000..10629684e --- /dev/null +++ b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx @@ -0,0 +1,577 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ +#include "MapSettingsChartTwoLineHistoryWidget.h" +#undef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretColorEnumComboBox.h" +#include "CaretMappableDataFile.h" +#include "ChartTwoDataCartesian.h" +#include "ChartableTwoFileDelegate.h" +#include "ChartableTwoFileLineSeriesChart.h" +#include "ChartTwoLineSeriesHistory.h" +#include "ChartTwoOverlay.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "MapFileDataSelector.h" +#include "WuQDoubleSpinBox.h" +#include "WuQImageLabel.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::MapSettingsChartTwoLineHistoryWidget + * \brief Dialog for controlling the display of line series chart data. + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +MapSettingsChartTwoLineHistoryWidget::MapSettingsChartTwoLineHistoryWidget(QWidget* parent) +: QWidget(parent) +{ + const AString maxHistoryString(AString::number(ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount())); + const AString defaultColorToolTip("Color assigned to newly added line-series items"); + const AString displayMaximumToolTip("Maximum number of line-series items enabled for viewing\n" + "As new items are added, older items are disabled for viewing\n" + "The number of history items retained (including those not\n" + "displayed) is limited to this value or " + maxHistoryString + ", whichever is larger."); + + m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); + + m_filenameLabel = new QLabel(""); + + QLabel* defaultColorLabel = new QLabel("Default Color: "); + defaultColorLabel->setToolTip(defaultColorToolTip); + m_defaultColorComboBox = new CaretColorEnumComboBox(this); + m_defaultColorComboBox->getWidget()->setToolTip(defaultColorToolTip); + m_defaultColorComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + QObject::connect(m_defaultColorComboBox, &CaretColorEnumComboBox::colorSelected, + this, &MapSettingsChartTwoLineHistoryWidget::defaultColorSelected); + + QLabel* defaultLineWidthLabel = new QLabel("Default Line Width: "); + m_defaultLineWidthSpinBox = new WuQDoubleSpinBox(this); + m_defaultLineWidthSpinBox->setRangePercentage(0.0, 100.0); + m_defaultLineWidthSpinBox->setToolTip("Default width of new chart lines"); + defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->getWidget()->toolTip()); + QObject::connect(m_defaultLineWidthSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), + this, &MapSettingsChartTwoLineHistoryWidget::defaultLineWidthChanged); + + QToolButton* removeAllHistoryToolButton = new QToolButton(); + removeAllHistoryToolButton->setText("Remove All History..."); + QObject::connect(removeAllHistoryToolButton, &QToolButton::clicked, + this, &MapSettingsChartTwoLineHistoryWidget::removeAllHistoryButtonClicked); + + QLabel* viewedMaximumLabel = new QLabel("Viewed Maximum: "); + viewedMaximumLabel->setToolTip(displayMaximumToolTip); + m_viewedMaximumCountSpinBox = new QSpinBox(); + m_viewedMaximumCountSpinBox->setToolTip(displayMaximumToolTip); + m_viewedMaximumCountSpinBox->setRange(1, 10000); + QObject::connect(m_viewedMaximumCountSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(viewedMaximumSpinBoxValueChanged(int))); + + m_removeHistoryItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_removeHistoryItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(removeHistoryItemSelected(int))); + + m_colorItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_colorItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(colorItemSelected(int))); + + m_lineWidthItemSignalMapper = new QSignalMapper(this); + QObject::connect(m_lineWidthItemSignalMapper, SIGNAL(mapped(int)), + this, SLOT(lineWidthItemSelected(int))); + + m_tableWidget = new QTableWidget(); + m_tableWidget->setSelectionBehavior(QTableWidget::SelectItems); + m_tableWidget->setSelectionMode(QTableWidget::SingleSelection); + QObject::connect(m_tableWidget, &QTableWidget::cellChanged, + this, &MapSettingsChartTwoLineHistoryWidget::tableWidgetCellChanged); + + QGridLayout* topLayout = new QGridLayout(); + topLayout->setColumnStretch(0, 0); + topLayout->setColumnStretch(1, 0); + topLayout->setColumnStretch(2, 0); + topLayout->setColumnStretch(3, 0); + topLayout->setColumnStretch(4, 100); + int gridRow = 0; + topLayout->addWidget(m_filenameLabel, gridRow, 0, 1, 5, Qt::AlignLeft); + gridRow++; + topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); + topLayout->addWidget(m_defaultLineWidthSpinBox->getWidget(), gridRow, 1); + topLayout->addWidget(defaultColorLabel, gridRow, 2); + topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 3); + gridRow++; + topLayout->addWidget(viewedMaximumLabel, gridRow, 0); + topLayout->addWidget(m_viewedMaximumCountSpinBox, gridRow, 1); + topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2, 1, 2, Qt::AlignLeft); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addLayout(topLayout); + layout->addWidget(m_tableWidget); +} + +/** + * Destructor. + */ +MapSettingsChartTwoLineHistoryWidget::~MapSettingsChartTwoLineHistoryWidget() +{ +} + +/** + * @return The chart overlay in this dialog (May be NULL !) + */ +ChartTwoOverlay* +MapSettingsChartTwoLineHistoryWidget::getChartOverlay() +{ + ChartTwoOverlay* chartOverlay = NULL; + if (m_chartOverlayWeakPointer.expired()) { + m_chartOverlayWeakPointer.reset(); + } + else { + chartOverlay = m_chartOverlayWeakPointer.lock().get(); + } + + return chartOverlay; +} + + +/** + * Update dialog if the given chart overlay is in the dialog. + * This may occur when the user changes the file in the chart overlay. + * + * @param chartOverlay + * Chart overlay for history display. + */ +void +MapSettingsChartTwoLineHistoryWidget::updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay) +{ + ChartTwoOverlay* currentChartOverlay = getChartOverlay(); + + if (currentChartOverlay != NULL) { + if (chartOverlay != currentChartOverlay) { + return; + } + } + + updateDialogContentPrivate(); +} + +/** + * Update the content of the widget. + * + * @param chartOverlay + * Chart overlay for history display. + */ +void +MapSettingsChartTwoLineHistoryWidget::updateContent(ChartTwoOverlay* chartOverlay) +{ + CaretAssert(chartOverlay); + m_chartOverlayWeakPointer = chartOverlay->getWeakPointerToSelf(); + updateDialogContentPrivate(); +} + +void +MapSettingsChartTwoLineHistoryWidget::updateDialogContentPrivate() +{ + ChartTwoOverlay* chartOverlay = getChartOverlay(); + if (chartOverlay == NULL) { + close(); + return; + } + + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + + if (lineSeriesHistory != NULL) { + const CaretMappableDataFile* mapFile = getMapFile(); + if (mapFile != NULL) { + m_filenameLabel->setText("Filename: " + mapFile->getFileNameNoPath()); + m_filenameLabel->setToolTip(mapFile->getFileName()); + } + m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); + m_defaultLineWidthSpinBox->blockSignals(true); + m_defaultLineWidthSpinBox->setValue(lineSeriesHistory->getDefaultLineWidth()); + m_defaultLineWidthSpinBox->blockSignals(false); + + m_viewedMaximumCountSpinBox->blockSignals(true); + m_viewedMaximumCountSpinBox->setValue(lineSeriesHistory->getDisplayCount()); + m_viewedMaximumCountSpinBox->blockSignals(false); + + loadHistoryIntoTableWidget(lineSeriesHistory); + } + else { + close(); + } +} + + +/** + * @return Map file in the dialog. + */ +CaretMappableDataFile* +MapSettingsChartTwoLineHistoryWidget::getMapFile() +{ + CaretMappableDataFile* mapFile = NULL; + ChartTwoOverlay* chartOverlay = getChartOverlay(); + if (chartOverlay != NULL) { + if (chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { + ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; + int32_t mapIndex = -1; + chartOverlay->getSelectionData(mapFile, indexType, mapIndex); + } + } + + return mapFile; +} + +/** + * @return The line series history for the current chart overlay + */ +ChartTwoLineSeriesHistory* +MapSettingsChartTwoLineHistoryWidget::getLineSeriesHistory() +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; + + CaretMappableDataFile* mapFile = getMapFile(); + if (mapFile != NULL) { + ChartableTwoFileLineSeriesChart* chartTwoLineSeries = mapFile->getChartingDelegate()->getLineSeriesCharting(); + lineSeriesHistory = chartTwoLineSeries->getHistory(); + } + + return lineSeriesHistory; +} + + +/** + * Load the line-series history into the table widget. + * + * @param lineSeriesHistory + * The line series history. + */ +void +MapSettingsChartTwoLineHistoryWidget::loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory) +{ + CaretAssert(lineSeriesHistory); + + /* + * NOTE: We never remove items from a table due to issues + * with widget ownership (and destruction) and the signal mappers. + * + * When new rows are needed, they are added. + * When there are two many rows, they are hidden. + */ + + const QSignalBlocker tableSignalBlocker(m_tableWidget); + + const int32_t oldRowCount = m_tableWidget->rowCount(); + const int32_t numHistory = lineSeriesHistory->getHistoryCount(); + + /* + * Setup table dimensions + */ + m_tableWidget->setRowCount(std::max(numHistory, oldRowCount)); + m_tableWidget->setColumnCount(COLUMN_COUNT); + + /* + * If needed, add cells + */ + for (int32_t iRow = oldRowCount; iRow < numHistory; iRow++) { + for (int32_t j = 0; j < COLUMN_COUNT; j++) { + if (j == COLUMN_VIEW) { + QTableWidgetItem* item = new QTableWidgetItem(""); + item->setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable + | Qt::ItemIsUserCheckable); + m_tableWidget->setItem(iRow, j, item); + } + else if (j == COLUMN_REMOVE) { + WuQImageLabel* removeHistoryLabel = new WuQImageLabel(m_removeAllHistoryIcon, + "Remove"); + QObject::connect(removeHistoryLabel, SIGNAL(clicked()), + m_removeHistoryItemSignalMapper, SLOT(map())); + m_removeHistoryItemSignalMapper->setMapping(removeHistoryLabel, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_REMOVE, + removeHistoryLabel); + } + else if (j == COLUMN_COLOR) { + CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); + QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), + m_colorItemSignalMapper, SLOT(map())); + m_colorItemSignalMapper->setMapping(caretColorComboBox, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_COLOR, + caretColorComboBox->getWidget()); + m_colorComboBoxes.push_back(caretColorComboBox); + } + else if (j == COLUMN_LINE_WIDTH) { + WuQDoubleSpinBox* lineWidthSpinBox = new WuQDoubleSpinBox(this); + lineWidthSpinBox->setRangePercentage(0.0, 100.0); + QObject::connect(lineWidthSpinBox, SIGNAL(valueChanged(double)), + m_lineWidthItemSignalMapper, SLOT(map())); + m_lineWidthItemSignalMapper->setMapping(lineWidthSpinBox, iRow); + m_tableWidget->setCellWidget(iRow, + COLUMN_LINE_WIDTH, + lineWidthSpinBox->getWidget()); + m_lineWidthSpinBoxes.push_back(lineWidthSpinBox); + } + else if (j == COLUMN_DESCRIPTION) { + QTableWidgetItem* item = new QTableWidgetItem(""); + item->setFlags(Qt::ItemIsEnabled + | Qt::ItemIsSelectable); + m_tableWidget->setItem(iRow, j, item); + } + else { + CaretAssert(0); + } + } + } + + CaretAssert(m_lineWidthSpinBoxes.size() == m_colorComboBoxes.size()); + + /* + * Hide rows not needed + */ + for (int32_t iRow = numHistory; iRow < oldRowCount; iRow++) { + m_tableWidget->setRowHidden(iRow, true); + } + + /* + * Load cells + */ + CaretAssert(numHistory <= m_tableWidget->rowCount()); + for (int32_t iRow = 0; iRow < numHistory; iRow++) { + ChartTwoDataCartesian* historyData = lineSeriesHistory->getHistoryItem(iRow); + const MapFileDataSelector* mapFileDataSelector = historyData->getMapFileDataSelector(); + + m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(historyData->isSelected() + ? Qt::Checked + : Qt::Unchecked); + + CaretAssertVectorIndex(m_colorComboBoxes, iRow); + m_colorComboBoxes[iRow]->setSelectedColor(historyData->getColor()); + + CaretAssertVectorIndex(m_lineWidthSpinBoxes, iRow); + m_lineWidthSpinBoxes[iRow]->setValue(historyData->getLineWidth()); + + QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); + item->setText(mapFileDataSelector->toString()); + + m_tableWidget->setRowHidden(iRow, false); + } + + /* + * If table was empty, add column titles + * and adjust column widths + */ + if ((oldRowCount == 0) + && (numHistory > 0)) { + m_tableWidget->setHorizontalHeaderItem(COLUMN_VIEW, + new QTableWidgetItem("View")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_REMOVE, + new QTableWidgetItem("Remove")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, + new QTableWidgetItem("Color")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_LINE_WIDTH, + new QTableWidgetItem("Line Width")); + m_tableWidget->setHorizontalHeaderItem(COLUMN_DESCRIPTION, + new QTableWidgetItem("Description")); + + m_tableWidget->resizeColumnToContents(COLUMN_VIEW); + m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); + m_tableWidget->resizeColumnToContents(COLUMN_COLOR); + m_tableWidget->resizeColumnToContents(COLUMN_LINE_WIDTH); + m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, + 350); + + QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_tableWidget); + + WuQtUtilities::resizeWindow(this, + tableSize.width() + 30, + sizeHint().height()); + } +} + +/** + * Called when the content of a cell changes. + * Update corresponding item in the spec file. + * + * @param rowIndex + * The row of the cell that was clicked. + * @param columnIndex + * The columnof the cell that was clicked. + */ +void +MapSettingsChartTwoLineHistoryWidget::tableWidgetCellChanged(int rowIndex, int columnIndex) +{ + QTableWidgetItem* item = m_tableWidget->item(rowIndex, columnIndex); + if (item != NULL) { + if (columnIndex == COLUMN_VIEW) { + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setSelected(WuQtUtilities::checkStateToBool(item->checkState())); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } + } + } +} + +/** + * Remove a history item selected + * + * @param rowIndex + * Row index of item. + */ +void +MapSettingsChartTwoLineHistoryWidget::removeHistoryItemSelected(int rowIndex) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->removeHistoryItem(rowIndex); + updateDialogContentPrivate(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Color item selected + * + * @param rowIndex + * Row index of item. + */ +void +MapSettingsChartTwoLineHistoryWidget::colorItemSelected(int rowIndex) +{ + CaretAssertVectorIndex(m_colorComboBoxes, rowIndex); + CaretAssert(m_colorComboBoxes[rowIndex]); + + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setColor(m_colorComboBoxes[rowIndex]->getSelectedColor()); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + +/** + * line width item selected + * + * @param rowIndex + * Row index of item. + */ +void +MapSettingsChartTwoLineHistoryWidget::lineWidthItemSelected(int rowIndex) +{ + CaretAssertVectorIndex(m_lineWidthSpinBoxes, rowIndex); + CaretAssert(m_lineWidthSpinBoxes[rowIndex]); + + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); + CaretAssert(data); + data->setLineWidth(m_lineWidthSpinBoxes[rowIndex]->value()); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + +/** + * Called when the "Remove All History" button is clicked. + */ +void +MapSettingsChartTwoLineHistoryWidget::removeAllHistoryButtonClicked() +{ + if (WuQMessageBox::warningOkCancel(this, + ("Remove all line series history from the file " + + getMapFile()->getFileNameNoPath()))) { + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + lineSeriesHistory->clearHistory(); + updateDialogContentPrivate(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + +/** + * Called when the default color is changed. + * + * @param color + * New default color. + */ +void +MapSettingsChartTwoLineHistoryWidget::defaultColorSelected(const CaretColorEnum::Enum color) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDefaultColor(color); + } +} + +/** + * Called when line width is changed + * + * @param defaultLineWidth + * New default line width. + */ +void +MapSettingsChartTwoLineHistoryWidget::defaultLineWidthChanged(double defaultLineWidth) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDefaultLineWidth(defaultLineWidth); + } +} + +/** + * Gets called when display last count is changed. + * + * @param num + * Number of history items to display. + */ +void +MapSettingsChartTwoLineHistoryWidget::viewedMaximumSpinBoxValueChanged(int num) +{ + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); + if (lineSeriesHistory != NULL) { + lineSeriesHistory->setDisplayCount(num); + updateDialogContentPrivate(); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} \ No newline at end of file diff --git a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h new file mode 100644 index 000000000..2594fa802 --- /dev/null +++ b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h @@ -0,0 +1,134 @@ +#ifndef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ +#define __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "CaretColorEnum.h" + +class QLabel; +class QIcon; +class QSignalMapper; +class QSpinBox; +class QTableWidget; + +namespace caret { + + class CaretColorEnumComboBox; + class CaretMappableDataFile; + class ChartTwoLineSeriesHistory; + class ChartTwoOverlay; + class WuQDoubleSpinBox; + + class MapSettingsChartTwoLineHistoryWidget : public QWidget { + + Q_OBJECT + + public: + MapSettingsChartTwoLineHistoryWidget(QWidget* parent = 0); + + virtual ~MapSettingsChartTwoLineHistoryWidget(); + + void updateContent(ChartTwoOverlay* chartOverlay); + + void updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay); + + // ADD_NEW_METHODS_HERE + + private slots: + void tableWidgetCellChanged(int rowIndex, int columnIndex); + + void removeHistoryItemSelected(int rowIndex); + + void colorItemSelected(int rowIndex); + + void lineWidthItemSelected(int rowIndex); + + void removeAllHistoryButtonClicked(); + + void defaultColorSelected(const CaretColorEnum::Enum color); + + void defaultLineWidthChanged(double); + + void viewedMaximumSpinBoxValueChanged(int); + + private: + + MapSettingsChartTwoLineHistoryWidget(const MapSettingsChartTwoLineHistoryWidget&); + + MapSettingsChartTwoLineHistoryWidget& operator=(const MapSettingsChartTwoLineHistoryWidget&); + + void updateDialogContentPrivate(); + + void loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory); + + ChartTwoOverlay* getChartOverlay(); + + ChartTwoLineSeriesHistory* getLineSeriesHistory(); + + CaretMappableDataFile* getMapFile(); + + std::weak_ptr m_chartOverlayWeakPointer; + + QTableWidget* m_tableWidget; + + QIcon* m_removeAllHistoryIcon; + + QSignalMapper* m_removeHistoryItemSignalMapper; + + QSignalMapper* m_colorItemSignalMapper; + + QSignalMapper* m_lineWidthItemSignalMapper; + + std::vector m_colorComboBoxes; + + std::vector m_lineWidthSpinBoxes; + + QLabel* m_filenameLabel; + + CaretColorEnumComboBox* m_defaultColorComboBox; + + WuQDoubleSpinBox* m_defaultLineWidthSpinBox; + + QSpinBox* m_viewedMaximumCountSpinBox; + + static const int32_t COLUMN_VIEW = 0; + static const int32_t COLUMN_REMOVE = 1; + static const int32_t COLUMN_COLOR = 2; + static const int32_t COLUMN_LINE_WIDTH = 3; + static const int32_t COLUMN_DESCRIPTION = 4; + static const int32_t COLUMN_COUNT = 5; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ + // +#endif // __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ + +} // namespace +#endif //__MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ diff --git a/src/GuiQt/OverlaySettingsEditorDialog.cxx b/src/GuiQt/OverlaySettingsEditorDialog.cxx index 757b74a9e..4f32903a6 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.cxx +++ b/src/GuiQt/OverlaySettingsEditorDialog.cxx @@ -43,6 +43,7 @@ #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabelTableEditor.h" +#include "MapSettingsChartTwoLineHistoryWidget.h" #include "MapSettingsColorBarWidget.h" #include "MapSettingsFiberTrajectoryWidget.h" #include "MapSettingsLabelsWidget.h" @@ -105,6 +106,8 @@ OverlaySettingsEditorDialog::OverlaySettingsEditorDialog(QWidget* parent) m_labelsWidget = new MapSettingsLabelsWidget(); + m_lineHistoryWidget = new MapSettingsChartTwoLineHistoryWidget(); + m_tabWidget = new QTabWidget(); m_colorBarWidgetTabIndex = m_tabWidget->addTab(m_colorBarWidget, @@ -117,6 +120,8 @@ OverlaySettingsEditorDialog::OverlaySettingsEditorDialog(QWidget* parent) m_layersWidgetTabIndex = m_tabWidget->addTab(m_layerWidget, "Layer"); + m_lineHistoryWidgetTabIndex = m_tabWidget->addTab(m_lineHistoryWidget, + "Lines"); m_metadataWidgetTabIndex = m_tabWidget->addTab(new QWidget(), "Metadata"); m_tabWidget->setTabEnabled(m_tabWidget->count() - 1, false); @@ -303,6 +308,7 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv bool isParcelsValid = false; bool isFiberTrajectoryValid = false; bool isVolumeLayer = false; + bool isLinesValid = false; QString mapFileName = ""; QString mapName = ""; @@ -395,79 +401,101 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv } } else if (m_chartOverlay != NULL) { - int32_t selectedMapIndex = -1; - bool mapTypeFlag = false; - switch (m_chartOverlaySelectedIndexType) { - case ChartTwoOverlay::SelectedIndexType::INVALID: - CaretAssert(0); + bool hasMapsFlag = false; + bool hasHistoryFlag = false; + switch (m_chartOverlay->getChartTwoDataType()) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; - case ChartTwoOverlay::SelectedIndexType::MAP: - if ((m_selectedMapFileIndex >= 0) - && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { - selectedMapIndex = m_selectedMapFileIndex; - mapTypeFlag = true; - } + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + hasMapsFlag = true; break; - case ChartTwoOverlay::SelectedIndexType::COLUMN: - case ChartTwoOverlay::SelectedIndexType::ROW: - if (m_selectedMapFileIndex >= 0) { - if (m_caretMappableDataFile->getNumberOfMaps() == 1) { - m_selectedMapFileIndex = 0; - } - selectedMapIndex = m_selectedMapFileIndex; - } + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + hasHistoryFlag = true; + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + hasMapsFlag = true; break; } - if ((selectedMapIndex >= 0) - && (selectedMapIndex < m_caretMappableDataFile->getNumberOfMaps())) { - /* - * Get name of file and map - */ - mapFileName = m_caretMappableDataFile->getFileNameNoPath(); - if (m_selectedMapFileIndex >= 0) { - mapName = m_caretMappableDataFile->getMapName(selectedMapIndex); - } - - if (mapTypeFlag) { - metadata = m_caretMappableDataFile->getMapMetaData(selectedMapIndex); - if (metadata != NULL) { - /* - * TODO: Update metadata widget - */ - //isMetadataValid = true; - } - } - - if (m_caretMappableDataFile->isMappedWithPalette()) { - PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(selectedMapIndex); - if (paletteColorMapping != NULL) { - /* - * Update palette settings - */ - isPaletteValid = true; - m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, - selectedMapIndex); - AnnotationColorBar* colorBar = NULL; - if (m_brainordinateOverlay != NULL) { - colorBar = m_brainordinateOverlay->getColorBar(); + + int32_t selectedMapIndex = -1; + bool mapTypeFlag = false; + if (hasMapsFlag) { + switch (m_chartOverlaySelectedIndexType) { + case ChartTwoOverlay::SelectedIndexType::INVALID: + CaretAssert(0); + break; + case ChartTwoOverlay::SelectedIndexType::MAP: + if ((m_selectedMapFileIndex >= 0) + && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { + selectedMapIndex = m_selectedMapFileIndex; + mapTypeFlag = true; } - else if (m_chartOverlay != NULL) { - colorBar = m_chartOverlay->getColorBar(); + break; + case ChartTwoOverlay::SelectedIndexType::COLUMN: + case ChartTwoOverlay::SelectedIndexType::ROW: + if (m_selectedMapFileIndex >= 0) { + if (m_caretMappableDataFile->getNumberOfMaps() == 1) { + m_selectedMapFileIndex = 0; + } + selectedMapIndex = m_selectedMapFileIndex; } - m_colorBarWidget->updateContent(colorBar, - paletteColorMapping); - } + break; } - - CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); - if (parcelsFile != NULL) { + if ((selectedMapIndex >= 0) + && (selectedMapIndex < m_caretMappableDataFile->getNumberOfMaps())) { /* - * Update parcels + * Get name of file and map */ - isParcelsValid = true; - m_parcelsWidget->updateEditor(parcelsFile); + mapFileName = m_caretMappableDataFile->getFileNameNoPath(); + if (m_selectedMapFileIndex >= 0) { + mapName = m_caretMappableDataFile->getMapName(selectedMapIndex); + } + + if (mapTypeFlag) { + metadata = m_caretMappableDataFile->getMapMetaData(selectedMapIndex); + if (metadata != NULL) { + /* + * TODO: Update metadata widget + */ + //isMetadataValid = true; + } + } + + if (m_caretMappableDataFile->isMappedWithPalette()) { + PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(selectedMapIndex); + if (paletteColorMapping != NULL) { + /* + * Update palette settings + */ + isPaletteValid = true; + m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, + selectedMapIndex); + AnnotationColorBar* colorBar = NULL; + if (m_brainordinateOverlay != NULL) { + colorBar = m_brainordinateOverlay->getColorBar(); + } + else if (m_chartOverlay != NULL) { + colorBar = m_chartOverlay->getColorBar(); + } + m_colorBarWidget->updateContent(colorBar, + paletteColorMapping); + } + } + + CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); + if (parcelsFile != NULL) { + /* + * Update parcels + */ + isParcelsValid = true; + m_parcelsWidget->updateEditor(parcelsFile); + } } } + else if (hasHistoryFlag) { + isLinesValid = true; + m_lineHistoryWidget->updateContent(m_chartOverlay); + } } else { CaretAssert(0); @@ -492,6 +520,8 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv isParcelsValid); m_tabWidget->setTabEnabled(m_trajectoryWidgetTabIndex, isFiberTrajectoryValid); + m_tabWidget->setTabEnabled(m_lineHistoryWidgetTabIndex, + isLinesValid); /* * When the selected tab is invalid, we want to select the @@ -500,6 +530,7 @@ OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOv */ std::vector priorityTabIndices; priorityTabIndices.push_back(m_paletteWidgetTabIndex); + priorityTabIndices.push_back(m_lineHistoryWidgetTabIndex); priorityTabIndices.push_back(m_colorBarWidgetTabIndex); priorityTabIndices.push_back(m_labelsWidgetTabIndex); priorityTabIndices.push_back(m_parcelsWidgetTabIndex); @@ -566,6 +597,26 @@ OverlaySettingsEditorDialog::updateDialog() } } +/** + * Update chart lines in the dialog + */ +void +OverlaySettingsEditorDialog::updateChartLinesInDialog() +{ + if (m_chartOverlay != NULL) { + EventChartOverlayValidate validateChartOverlayEvent(m_chartOverlay); + EventManager::get()->sendEvent(validateChartOverlayEvent.getPointer()); + if ( ! validateChartOverlayEvent.isValidChartOverlay()) { + m_chartOverlay = NULL; + } + + if (m_chartOverlay != NULL) { + updateDialogContentPrivate(NULL, + m_chartOverlay); + } + } +} + /** * Called when close button pressed. diff --git a/src/GuiQt/OverlaySettingsEditorDialog.h b/src/GuiQt/OverlaySettingsEditorDialog.h index 7d60ab254..955f74b9a 100644 --- a/src/GuiQt/OverlaySettingsEditorDialog.h +++ b/src/GuiQt/OverlaySettingsEditorDialog.h @@ -36,6 +36,7 @@ namespace caret { class CaretMappableDataFile; class ChartTwoOverlay; class LabelTableEditorWidget; + class MapSettingsChartTwoLineHistoryWidget; class MapSettingsColorBarWidget; class MapSettingsFiberTrajectoryWidget; class MapSettingsLabelsWidget; @@ -58,6 +59,8 @@ namespace caret { void updateDialog(); + void updateChartLinesInDialog(); + virtual ~OverlaySettingsEditorDialog(); bool isDoNotReplaceSelected() const; @@ -119,6 +122,8 @@ namespace caret { MapSettingsLabelsWidget* m_labelsWidget; + MapSettingsChartTwoLineHistoryWidget* m_lineHistoryWidget; + QPushButton* m_editLabelTablePushButton; QLabel* m_selectedMapFileNameLabel; @@ -139,6 +144,8 @@ namespace caret { int32_t m_trajectoryWidgetTabIndex; + int32_t m_lineHistoryWidgetTabIndex; + }; #ifdef __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ -- GitLab From b34ff814c5c1bb21928ef29eb7f4dfbdc52dcaf4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Sep 2017 09:49:53 -0500 Subject: [PATCH 396/755] Resolve WB-737: Selecting a dynamic connectivity file as histogram may crash wb_view if no data: Removed history dialog and launching of dialog from chart overlay in overlay toolbox. --- src/Common/EventManager.cxx | 1 - src/Common/EventTypeEnum.cxx | 4 - src/Common/EventTypeEnum.h | 2 - src/GuiQt/CMakeLists.txt | 5 - src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx | 592 ------------------ src/GuiQt/ChartTwoLineSeriesHistoryDialog.h | 135 ---- .../ChartTwoOverlaySetViewController.cxx | 38 +- src/GuiQt/ChartTwoOverlayViewController.cxx | 107 ---- src/GuiQt/ChartTwoOverlayViewController.h | 8 - ...entChartTwoShowLineSeriesHistoryDialog.cxx | 92 --- ...EventChartTwoShowLineSeriesHistoryDialog.h | 78 --- src/GuiQt/GuiManager.cxx | 53 -- 12 files changed, 15 insertions(+), 1100 deletions(-) delete mode 100644 src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx delete mode 100644 src/GuiQt/ChartTwoLineSeriesHistoryDialog.h delete mode 100644 src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx delete mode 100644 src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 7e1a3e4c6..98fc09332 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -495,7 +495,6 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED: case EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE: case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: - case EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG: case EventTypeEnum::EVENT_DATA_FILE_ADD: case EventTypeEnum::EVENT_DATA_FILE_DELETE: case EventTypeEnum::EVENT_DATA_FILE_READ: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index a29c33be7..a0daef603 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -198,10 +198,6 @@ EventTypeEnum::initialize() "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", "Load line series data for chart two implementation")); - enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG, - "EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG", - "Show the Chart Two Line Series History Dialog")); - enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_ADD, "EVENT_DATA_FILE_ADD", "Add a data file to the Brain")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 290ed57c7..e5e611e0f 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -98,8 +98,6 @@ public: EVENT_CHART_TWO_AXIS_GET_DATA_RANGE, /** Load chart two line series data */ EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, - /** Show the chart two line series history dialog */ - EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG, /** Add a data file into the Brain*/ EVENT_DATA_FILE_ADD, /** Delete a data file from the brain */ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index a96ed9fa4..e682c804f 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -100,7 +100,6 @@ ELSE() ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h - ChartTwoLineSeriesHistoryDialog.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h @@ -290,7 +289,6 @@ ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h -ChartTwoLineSeriesHistoryDialog.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h @@ -314,7 +312,6 @@ EventBrowserWindowContentGet.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h -EventChartTwoShowLineSeriesHistoryDialog.h EventGetOrSetUserInputModeProcessor.h EventGraphicsUpdateAllWindows.h EventGraphicsUpdateOneWindow.h @@ -505,7 +502,6 @@ ChartHistoryViewController.cxx ChartLinesSelectionViewController.cxx ChartMatrixParcelSelectionViewController.cxx ChartMatrixSeriesSelectionViewController.cxx -ChartTwoLineSeriesHistoryDialog.cxx ChartTwoOverlaySetViewController.cxx ChartTwoOverlayViewController.cxx ChartSelectionViewController.cxx @@ -528,7 +524,6 @@ EventBrowserWindowContentGet.cxx EventBrowserWindowCreateTabs.cxx EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx -EventChartTwoShowLineSeriesHistoryDialog.cxx EventGetOrSetUserInputModeProcessor.cxx EventGraphicsUpdateAllWindows.cxx EventGraphicsUpdateOneWindow.cxx diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx deleted file mode 100644 index 128db8579..000000000 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.cxx +++ /dev/null @@ -1,592 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ -#include "ChartTwoLineSeriesHistoryDialog.h" -#undef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CaretAssert.h" -#include "CaretColorEnumComboBox.h" -#include "CaretMappableDataFile.h" -#include "ChartTwoDataCartesian.h" -#include "ChartableTwoFileDelegate.h" -#include "ChartableTwoFileLineSeriesChart.h" -#include "ChartTwoLineSeriesHistory.h" -#include "ChartTwoOverlay.h" -#include "EventGraphicsUpdateAllWindows.h" -#include "EventManager.h" -#include "MapFileDataSelector.h" -#include "WuQDoubleSpinBox.h" -#include "WuQImageLabel.h" -#include "WuQMessageBox.h" -#include "WuQtUtilities.h" - -using namespace caret; - - - -/** - * \class caret::ChartTwoLineSeriesHistoryDialog - * \brief Dialog for controlling the display of line series chart data. - * \ingroup GuiQt - */ - -/** - * Constructor. - */ -ChartTwoLineSeriesHistoryDialog::ChartTwoLineSeriesHistoryDialog(QWidget* parent) -: WuQDialogNonModal("Line-Series History", - parent) -{ - const AString maxHistoryString(AString::number(ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount())); - const AString defaultColorToolTip("Color assigned to newly added line-series items"); - const AString displayMaximumToolTip("Maximum number of line-series items enabled for viewing\n" - "As new items are added, older items are disabled for viewing\n" - "The number of history items retained (including those not\n" - "displayed) is limited to this value or " + maxHistoryString + ", whichever is larger."); - - m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); - - m_filenameLabel = new QLabel(""); - - QLabel* defaultColorLabel = new QLabel("Default Color: "); - defaultColorLabel->setToolTip(defaultColorToolTip); - m_defaultColorComboBox = new CaretColorEnumComboBox(this); - m_defaultColorComboBox->getWidget()->setToolTip(defaultColorToolTip); - m_defaultColorComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); - QObject::connect(m_defaultColorComboBox, &CaretColorEnumComboBox::colorSelected, - this, &ChartTwoLineSeriesHistoryDialog::defaultColorSelected); - - QLabel* defaultLineWidthLabel = new QLabel("Default Line Width: "); - m_defaultLineWidthSpinBox = new WuQDoubleSpinBox(this); - m_defaultLineWidthSpinBox->setRangePercentage(0.0, 100.0); - m_defaultLineWidthSpinBox->setToolTip("Default width of new chart lines"); - defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->getWidget()->toolTip()); - QObject::connect(m_defaultLineWidthSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), - this, &ChartTwoLineSeriesHistoryDialog::defaultLineWidthChanged); - - QToolButton* removeAllHistoryToolButton = new QToolButton(); - removeAllHistoryToolButton->setText("Remove All History..."); - QObject::connect(removeAllHistoryToolButton, &QToolButton::clicked, - this, &ChartTwoLineSeriesHistoryDialog::removeAllHistoryButtonClicked); - - QLabel* viewedMaximumLabel = new QLabel("Viewed Maximum: "); - viewedMaximumLabel->setToolTip(displayMaximumToolTip); - m_viewedMaximumCountSpinBox = new QSpinBox(); - m_viewedMaximumCountSpinBox->setToolTip(displayMaximumToolTip); - m_viewedMaximumCountSpinBox->setRange(1, 10000); - QObject::connect(m_viewedMaximumCountSpinBox, SIGNAL(valueChanged(int)), - this, SLOT(viewedMaximumSpinBoxValueChanged(int))); - - m_removeHistoryItemSignalMapper = new QSignalMapper(this); - QObject::connect(m_removeHistoryItemSignalMapper, SIGNAL(mapped(int)), - this, SLOT(removeHistoryItemSelected(int))); - - m_colorItemSignalMapper = new QSignalMapper(this); - QObject::connect(m_colorItemSignalMapper, SIGNAL(mapped(int)), - this, SLOT(colorItemSelected(int))); - - m_lineWidthItemSignalMapper = new QSignalMapper(this); - QObject::connect(m_lineWidthItemSignalMapper, SIGNAL(mapped(int)), - this, SLOT(lineWidthItemSelected(int))); - - m_tableWidget = new QTableWidget(); - m_tableWidget->setSelectionBehavior(QTableWidget::SelectItems); - m_tableWidget->setSelectionMode(QTableWidget::SingleSelection); - QObject::connect(m_tableWidget, &QTableWidget::cellChanged, - this, &ChartTwoLineSeriesHistoryDialog::tableWidgetCellChanged); - - QGridLayout* topLayout = new QGridLayout(); - topLayout->setColumnStretch(0, 0); - topLayout->setColumnStretch(1, 0); - topLayout->setColumnStretch(2, 0); - topLayout->setColumnStretch(3, 0); - topLayout->setColumnStretch(4, 100); - int gridRow = 0; - topLayout->addWidget(m_filenameLabel, gridRow, 0, 1, 5, Qt::AlignLeft); - gridRow++; - topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); - topLayout->addWidget(m_defaultLineWidthSpinBox->getWidget(), gridRow, 1); - topLayout->addWidget(defaultColorLabel, gridRow, 2); - topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 3); - gridRow++; - topLayout->addWidget(viewedMaximumLabel, gridRow, 0); - topLayout->addWidget(m_viewedMaximumCountSpinBox, gridRow, 1); - topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2, 1, 2, Qt::AlignLeft); - - QWidget* dialogWidget = new QWidget; - QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); - dialogLayout->addLayout(topLayout); - dialogLayout->addWidget(m_tableWidget); - - setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); - - setApplyButtonText(""); -} - -/** - * Destructor. - */ -ChartTwoLineSeriesHistoryDialog::~ChartTwoLineSeriesHistoryDialog() -{ -} - -/** - * Update the dialog. - */ -void -ChartTwoLineSeriesHistoryDialog::updateDialog() -{ - updateDialogContentPrivate(); -} - -/** - * @return The chart overlay in this dialog (May be NULL !) - */ -ChartTwoOverlay* -ChartTwoLineSeriesHistoryDialog::getChartOverlay() -{ - ChartTwoOverlay* chartOverlay = NULL; - if (m_chartOverlayWeakPointer.expired()) { - m_chartOverlayWeakPointer.reset(); - } - else { - chartOverlay = m_chartOverlayWeakPointer.lock().get(); - } - - return chartOverlay; -} - - -/** - * Update dialog if the given chart overlay is in the dialog. - * This may occur when the user changes the file in the chart overlay. - * - * @param chartOverlay - * Chart overlay for history display. - */ -void -ChartTwoLineSeriesHistoryDialog::updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay) -{ - ChartTwoOverlay* currentChartOverlay = getChartOverlay(); - - if (currentChartOverlay != NULL) { - if (chartOverlay != currentChartOverlay) { - return; - } - } - - updateDialogContentPrivate(); -} - -/** - * Update the content of the dialog. - * - * @param chartOverlay - * Chart overlay for history display. - */ -void -ChartTwoLineSeriesHistoryDialog::updateDialogContent(ChartTwoOverlay* chartOverlay) -{ - CaretAssert(chartOverlay); - m_chartOverlayWeakPointer = chartOverlay->getWeakPointerToSelf(); - updateDialogContentPrivate(); -} - -void -ChartTwoLineSeriesHistoryDialog::updateDialogContentPrivate() -{ - ChartTwoOverlay* chartOverlay = getChartOverlay(); - if (chartOverlay == NULL) { - close(); - return; - } - - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - - if (lineSeriesHistory != NULL) { - const CaretMappableDataFile* mapFile = getMapFile(); - if (mapFile != NULL) { - m_filenameLabel->setText("Filename: " + mapFile->getFileNameNoPath()); - m_filenameLabel->setToolTip(mapFile->getFileName()); - } - m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); - m_defaultLineWidthSpinBox->blockSignals(true); - m_defaultLineWidthSpinBox->setValue(lineSeriesHistory->getDefaultLineWidth()); - m_defaultLineWidthSpinBox->blockSignals(false); - - m_viewedMaximumCountSpinBox->blockSignals(true); - m_viewedMaximumCountSpinBox->setValue(lineSeriesHistory->getDisplayCount()); - m_viewedMaximumCountSpinBox->blockSignals(false); - - loadHistoryIntoTableWidget(lineSeriesHistory); - } - else { - close(); - } -} - - -/** - * @return Map file in the dialog. - */ -CaretMappableDataFile* -ChartTwoLineSeriesHistoryDialog::getMapFile() -{ - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay* chartOverlay = getChartOverlay(); - if (chartOverlay != NULL) { - if (chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { - ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; - int32_t mapIndex = -1; - chartOverlay->getSelectionData(mapFile, indexType, mapIndex); - } - } - - return mapFile; -} - -/** - * @return The line series history for the current chart overlay - */ -ChartTwoLineSeriesHistory* -ChartTwoLineSeriesHistoryDialog::getLineSeriesHistory() -{ - ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; - - CaretMappableDataFile* mapFile = getMapFile(); - if (mapFile != NULL) { - ChartableTwoFileLineSeriesChart* chartTwoLineSeries = mapFile->getChartingDelegate()->getLineSeriesCharting(); - lineSeriesHistory = chartTwoLineSeries->getHistory(); - } - - return lineSeriesHistory; -} - - -/** - * Load the line-series history into the table widget. - * - * @param lineSeriesHistory - * The line series history. - */ -void -ChartTwoLineSeriesHistoryDialog::loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory) -{ - CaretAssert(lineSeriesHistory); - - /* - * NOTE: We never remove items from a table due to issues - * with widget ownership (and destruction) and the signal mappers. - * - * When new rows are needed, they are added. - * When there are two many rows, they are hidden. - */ - - const QSignalBlocker tableSignalBlocker(m_tableWidget); - - const int32_t oldRowCount = m_tableWidget->rowCount(); - const int32_t numHistory = lineSeriesHistory->getHistoryCount(); - - /* - * Setup table dimensions - */ - m_tableWidget->setRowCount(std::max(numHistory, oldRowCount)); - m_tableWidget->setColumnCount(COLUMN_COUNT); - - /* - * If needed, add cells - */ - for (int32_t iRow = oldRowCount; iRow < numHistory; iRow++) { - for (int32_t j = 0; j < COLUMN_COUNT; j++) { - if (j == COLUMN_VIEW) { - QTableWidgetItem* item = new QTableWidgetItem(""); - item->setFlags(Qt::ItemIsEnabled - | Qt::ItemIsSelectable - | Qt::ItemIsUserCheckable); - m_tableWidget->setItem(iRow, j, item); - } - else if (j == COLUMN_REMOVE) { - WuQImageLabel* removeHistoryLabel = new WuQImageLabel(m_removeAllHistoryIcon, - "Remove"); - QObject::connect(removeHistoryLabel, SIGNAL(clicked()), - m_removeHistoryItemSignalMapper, SLOT(map())); - m_removeHistoryItemSignalMapper->setMapping(removeHistoryLabel, iRow); - m_tableWidget->setCellWidget(iRow, - COLUMN_REMOVE, - removeHistoryLabel); - } - else if (j == COLUMN_COLOR) { - CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); - QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), - m_colorItemSignalMapper, SLOT(map())); - m_colorItemSignalMapper->setMapping(caretColorComboBox, iRow); - m_tableWidget->setCellWidget(iRow, - COLUMN_COLOR, - caretColorComboBox->getWidget()); - m_colorComboBoxes.push_back(caretColorComboBox); - } - else if (j == COLUMN_LINE_WIDTH) { - WuQDoubleSpinBox* lineWidthSpinBox = new WuQDoubleSpinBox(this); - lineWidthSpinBox->setRangePercentage(0.0, 100.0); - QObject::connect(lineWidthSpinBox, SIGNAL(valueChanged(double)), - m_lineWidthItemSignalMapper, SLOT(map())); - m_lineWidthItemSignalMapper->setMapping(lineWidthSpinBox, iRow); - m_tableWidget->setCellWidget(iRow, - COLUMN_LINE_WIDTH, - lineWidthSpinBox->getWidget()); - m_lineWidthSpinBoxes.push_back(lineWidthSpinBox); - } - else if (j == COLUMN_DESCRIPTION) { - QTableWidgetItem* item = new QTableWidgetItem(""); - item->setFlags(Qt::ItemIsEnabled - | Qt::ItemIsSelectable); - m_tableWidget->setItem(iRow, j, item); - } - else { - CaretAssert(0); - } - } - } - - CaretAssert(m_lineWidthSpinBoxes.size() == m_colorComboBoxes.size()); - - /* - * Hide rows not needed - */ - for (int32_t iRow = numHistory; iRow < oldRowCount; iRow++) { - m_tableWidget->setRowHidden(iRow, true); - } - - /* - * Load cells - */ - CaretAssert(numHistory <= m_tableWidget->rowCount()); - for (int32_t iRow = 0; iRow < numHistory; iRow++) { - ChartTwoDataCartesian* historyData = lineSeriesHistory->getHistoryItem(iRow); - const MapFileDataSelector* mapFileDataSelector = historyData->getMapFileDataSelector(); - - m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(historyData->isSelected() - ? Qt::Checked - : Qt::Unchecked); - - CaretAssertVectorIndex(m_colorComboBoxes, iRow); - m_colorComboBoxes[iRow]->setSelectedColor(historyData->getColor()); - - CaretAssertVectorIndex(m_lineWidthSpinBoxes, iRow); - m_lineWidthSpinBoxes[iRow]->setValue(historyData->getLineWidth()); - - QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); - item->setText(mapFileDataSelector->toString()); - - m_tableWidget->setRowHidden(iRow, false); - } - - /* - * If table was empty, add column titles - * and adjust column widths - */ - if ((oldRowCount == 0) - && (numHistory > 0)) { - m_tableWidget->setHorizontalHeaderItem(COLUMN_VIEW, - new QTableWidgetItem("View")); - m_tableWidget->setHorizontalHeaderItem(COLUMN_REMOVE, - new QTableWidgetItem("Remove")); - m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, - new QTableWidgetItem("Color")); - m_tableWidget->setHorizontalHeaderItem(COLUMN_LINE_WIDTH, - new QTableWidgetItem("Line Width")); - m_tableWidget->setHorizontalHeaderItem(COLUMN_DESCRIPTION, - new QTableWidgetItem("Description")); - - m_tableWidget->resizeColumnToContents(COLUMN_VIEW); - m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); - m_tableWidget->resizeColumnToContents(COLUMN_COLOR); - m_tableWidget->resizeColumnToContents(COLUMN_LINE_WIDTH); - m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, - 350); - - QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_tableWidget); - - WuQtUtilities::resizeWindow(this, - tableSize.width() + 30, - sizeHint().height()); - } -} - -/** - * Called when the content of a cell changes. - * Update corresponding item in the spec file. - * - * @param rowIndex - * The row of the cell that was clicked. - * @param columnIndex - * The columnof the cell that was clicked. - */ -void -ChartTwoLineSeriesHistoryDialog::tableWidgetCellChanged(int rowIndex, int columnIndex) -{ - QTableWidgetItem* item = m_tableWidget->item(rowIndex, columnIndex); - if (item != NULL) { - if (columnIndex == COLUMN_VIEW) { - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); - CaretAssert(data); - data->setSelected(WuQtUtilities::checkStateToBool(item->checkState())); - - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } - } - } -} - -/** - * Remove a history item selected - * - * @param rowIndex - * Row index of item. - */ -void -ChartTwoLineSeriesHistoryDialog::removeHistoryItemSelected(int rowIndex) -{ - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - lineSeriesHistory->removeHistoryItem(rowIndex); - updateDialog(); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); -} - -/** - * Color item selected - * - * @param rowIndex - * Row index of item. - */ -void -ChartTwoLineSeriesHistoryDialog::colorItemSelected(int rowIndex) -{ - CaretAssertVectorIndex(m_colorComboBoxes, rowIndex); - CaretAssert(m_colorComboBoxes[rowIndex]); - - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); - CaretAssert(data); - data->setColor(m_colorComboBoxes[rowIndex]->getSelectedColor()); - - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } -} - -/** - * line width item selected - * - * @param rowIndex - * Row index of item. - */ -void -ChartTwoLineSeriesHistoryDialog::lineWidthItemSelected(int rowIndex) -{ - CaretAssertVectorIndex(m_lineWidthSpinBoxes, rowIndex); - CaretAssert(m_lineWidthSpinBoxes[rowIndex]); - - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); - CaretAssert(data); - data->setLineWidth(m_lineWidthSpinBoxes[rowIndex]->value()); - - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } -} - -/** - * Called when the "Remove All History" button is clicked. - */ -void -ChartTwoLineSeriesHistoryDialog::removeAllHistoryButtonClicked() -{ - if (WuQMessageBox::warningOkCancel(this, - ("Remove all line series history from the file " - + getMapFile()->getFileNameNoPath()))) { - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - lineSeriesHistory->clearHistory(); - updateDialog(); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } -} - -/** - * Called when the default color is changed. - * - * @param color - * New default color. - */ -void -ChartTwoLineSeriesHistoryDialog::defaultColorSelected(const CaretColorEnum::Enum color) -{ - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - lineSeriesHistory->setDefaultColor(color); - } -} - -/** - * Called when line width is changed - * - * @param defaultLineWidth - * New default line width. - */ -void -ChartTwoLineSeriesHistoryDialog::defaultLineWidthChanged(double defaultLineWidth) -{ - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - lineSeriesHistory->setDefaultLineWidth(defaultLineWidth); - } -} - -/** - * Gets called when display last count is changed. - * - * @param num - * Number of history items to display. - */ -void -ChartTwoLineSeriesHistoryDialog::viewedMaximumSpinBoxValueChanged(int num) -{ - ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); - if (lineSeriesHistory != NULL) { - lineSeriesHistory->setDisplayCount(num); - updateDialog(); - EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); - } -} \ No newline at end of file diff --git a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h b/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h deleted file mode 100644 index 60ecbe57c..000000000 --- a/src/GuiQt/ChartTwoLineSeriesHistoryDialog.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ -#define __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "CaretColorEnum.h" -#include "WuQDialogNonModal.h" - -class QLabel; -class QIcon; -class QSignalMapper; -class QSpinBox; -class QTableWidget; - -namespace caret { - - class CaretColorEnumComboBox; - class CaretMappableDataFile; - class ChartTwoLineSeriesHistory; - class ChartTwoOverlay; - class WuQDoubleSpinBox; - - class ChartTwoLineSeriesHistoryDialog : public WuQDialogNonModal { - - Q_OBJECT - - public: - ChartTwoLineSeriesHistoryDialog(QWidget* parent); - - virtual ~ChartTwoLineSeriesHistoryDialog(); - - void updateDialogContent(ChartTwoOverlay* chartOverlay); - - virtual void updateDialog() override; - - void updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay); - - // ADD_NEW_METHODS_HERE - - private slots: - void tableWidgetCellChanged(int rowIndex, int columnIndex); - - void removeHistoryItemSelected(int rowIndex); - - void colorItemSelected(int rowIndex); - - void lineWidthItemSelected(int rowIndex); - - void removeAllHistoryButtonClicked(); - - void defaultColorSelected(const CaretColorEnum::Enum color); - - void defaultLineWidthChanged(double); - - void viewedMaximumSpinBoxValueChanged(int); - - private: - - ChartTwoLineSeriesHistoryDialog(const ChartTwoLineSeriesHistoryDialog&); - - ChartTwoLineSeriesHistoryDialog& operator=(const ChartTwoLineSeriesHistoryDialog&); - - void updateDialogContentPrivate(); - - void loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory); - - ChartTwoOverlay* getChartOverlay(); - - ChartTwoLineSeriesHistory* getLineSeriesHistory(); - - CaretMappableDataFile* getMapFile(); - - std::weak_ptr m_chartOverlayWeakPointer; - - QTableWidget* m_tableWidget; - - QIcon* m_removeAllHistoryIcon; - - QSignalMapper* m_removeHistoryItemSignalMapper; - - QSignalMapper* m_colorItemSignalMapper; - - QSignalMapper* m_lineWidthItemSignalMapper; - - std::vector m_colorComboBoxes; - - std::vector m_lineWidthSpinBoxes; - - QLabel* m_filenameLabel; - - CaretColorEnumComboBox* m_defaultColorComboBox; - - WuQDoubleSpinBox* m_defaultLineWidthSpinBox; - - QSpinBox* m_viewedMaximumCountSpinBox; - - static const int32_t COLUMN_VIEW = 0; - static const int32_t COLUMN_REMOVE = 1; - static const int32_t COLUMN_COLOR = 2; - static const int32_t COLUMN_LINE_WIDTH = 3; - static const int32_t COLUMN_DESCRIPTION = 4; - static const int32_t COLUMN_COUNT = 5; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - // -#endif // __CHART_TWO_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - -} // namespace -#endif //__CHART_TWO_LINE_SERIES_HISTORY_DIALOG_H__ diff --git a/src/GuiQt/ChartTwoOverlaySetViewController.cxx b/src/GuiQt/ChartTwoOverlaySetViewController.cxx index 72d7d70ed..687430db7 100644 --- a/src/GuiQt/ChartTwoOverlaySetViewController.cxx +++ b/src/GuiQt/ChartTwoOverlaySetViewController.cxx @@ -103,21 +103,19 @@ m_browserWindowIndex(browserWindowIndex) static const int COLUMN_SETTINGS_EDIT = 2; static const int COLUMN_SETTINGS_COLOR_BAR = 3; static const int COLUMN_SETTINGS_CONSTRUCTION = 4; - static const int COLUMN_HISTORY = 5; - static const int COLUMN_MATRIX_VIEW = 6; - static const int COLUMN_AXIS = 7; - static const int COLUMN_FILE = 8; - static const int COLUMN_YOKE = 9; - static const int COLUMN_MAP_INDEX = 10; - static const int COLUMN_ALL_MAPS = 11; - static const int COLUMN_MAP_NAME = 12; + static const int COLUMN_MATRIX_VIEW = 5; + static const int COLUMN_AXIS = 6; + static const int COLUMN_FILE = 7; + static const int COLUMN_YOKE = 8; + static const int COLUMN_MAP_INDEX = 9; + static const int COLUMN_ALL_MAPS = 10; + static const int COLUMN_MAP_NAME = 11; gridLayout->setColumnStretch(COLUMN_ON, 0); gridLayout->setColumnStretch(COLUMN_LOAD, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_COLOR_BAR, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); - gridLayout->setColumnStretch(COLUMN_HISTORY, 0); gridLayout->setColumnStretch(COLUMN_MATRIX_VIEW, 0); gridLayout->setColumnStretch(COLUMN_AXIS, 0); gridLayout->setColumnStretch(COLUMN_FILE, 100); @@ -129,7 +127,6 @@ m_browserWindowIndex(browserWindowIndex) QLabel* onLabel = new QLabel("On"); QLabel* loadLabel = new QLabel("Load"); QLabel* settingsLabel = new QLabel("Settings"); - //QLabel* historyLabel = new QLabel("History"); QLabel* fileLabel = new QLabel("File"); QLabel* yokeLabel = new QLabel("Yoke"); QLabel* allMapsLabel = new QLabel("All"); @@ -140,7 +137,6 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); gridLayout->addWidget(loadLabel, row, COLUMN_LOAD, Qt::AlignHCenter); gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 5, Qt::AlignHCenter); - //gridLayout->addWidget(historyLabel, row, COLUMN_HISTORY, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, row, COLUMN_YOKE, Qt::AlignHCenter); gridLayout->addWidget(allMapsLabel, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); @@ -157,7 +153,6 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_settingsToolButton, row, COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); - glg->addWidget(covc->m_historyToolButton, row, COLUMN_HISTORY, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, COLUMN_MATRIX_VIEW, Qt::AlignHCenter); glg->addWidget(covc->m_axisLocationToolButton, row, COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); @@ -172,17 +167,16 @@ m_browserWindowIndex(browserWindowIndex) static const int ROW_ONE_COLUMN_SETTINGS_EDIT = 1; static const int ROW_ONE_COLUMN_SETTINGS_COLOR_BAR = 2; static const int ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION = 3; - static const int ROW_ONE_COLUMN_HISTORY = 4; - static const int ROW_ONE_COLUMN_MATRIX_VIEW = 5; - static const int ROW_ONE_COLUMN_AXIS = 6; - static const int ROW_ONE_COLUMN_FILE_LABEL = 7; - static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 8; + static const int ROW_ONE_COLUMN_MATRIX_VIEW = 4; + static const int ROW_ONE_COLUMN_AXIS = 5; + static const int ROW_ONE_COLUMN_FILE_LABEL = 6; + static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 7; static const int ROW_TWO_COLUMN_LOAD = 0; static const int ROW_TWO_COLUMN_YOKE = 2; static const int ROW_TWO_COLUMN_ALL_MAPS = 4; - static const int ROW_TWO_COLUMN_MAP_INDEX = 7; - static const int ROW_TWO_COLUMN_MAP_NAME = 8; + static const int ROW_TWO_COLUMN_MAP_INDEX = 6; + static const int ROW_TWO_COLUMN_MAP_NAME = 7; gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); @@ -191,8 +185,7 @@ m_browserWindowIndex(browserWindowIndex) gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); gridLayout->setColumnStretch(6, 0); - gridLayout->setColumnStretch(7, 0); - gridLayout->setColumnStretch(8, 100); + gridLayout->setColumnStretch(7, 100); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; @@ -215,7 +208,6 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_settingsToolButton, row, ROW_ONE_COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, ROW_ONE_COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); - glg->addWidget(covc->m_historyToolButton, row, ROW_ONE_COLUMN_HISTORY, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, ROW_ONE_COLUMN_MATRIX_VIEW, Qt::AlignHCenter); glg->addWidget(covc->m_axisLocationToolButton, row, ROW_ONE_COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL, Qt::AlignHCenter); @@ -224,7 +216,7 @@ m_browserWindowIndex(browserWindowIndex) glg->addWidget(covc->m_lineSeriesLoadingEnabledCheckBox, row, ROW_TWO_COLUMN_LOAD, Qt::AlignLeft); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); - glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 3, Qt::AlignRight); + glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 2, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); } diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 26c357112..84d03ea32 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -45,7 +45,6 @@ using namespace caret; #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" -#include "EventChartTwoShowLineSeriesHistoryDialog.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" @@ -170,19 +169,6 @@ m_chartOverlay(NULL) m_constructionToolButton->setDefaultAction(m_constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); - /* - * History button - */ - m_historyToolButton = new QToolButton(); - m_historyAction = WuQtUtilities::createAction("H", - "Show history of line charts loaded from selected file", - this, - this, - SLOT(historyActionTriggered(bool))); - QPixmap historyPixmap = createHistoryPixmap(m_historyToolButton); - m_historyAction->setIcon(historyPixmap); - m_historyToolButton->setDefaultAction(m_historyAction); - /* * Matrix triangular view mode button */ @@ -307,15 +293,6 @@ ChartTwoOverlayViewController::updateOverlaySettingsEditor() selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } - - if (mapFile != NULL) { - if (m_chartOverlay->isHistorySupported()) { - EventChartTwoShowLineSeriesHistoryDialog lshd(EventChartTwoShowLineSeriesHistoryDialog::Mode::CHART_OVERLAY_CHANGED, - m_browserWindowIndex, - m_chartOverlay); - EventManager::get()->sendEvent(lshd.getPointer()); - } - } } /** @@ -586,32 +563,6 @@ ChartTwoOverlayViewController::settingsActionTriggered() } } -/** - * Called when the history action is selected. - */ -void -ChartTwoOverlayViewController::historyActionTriggered(bool) -{ - if (m_chartOverlay == NULL) { - return; - } - - CaretMappableDataFile* mapFile = NULL; - ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; - int32_t selectedIndex = -1; - m_chartOverlay->getSelectionData(mapFile, - selectedIndexType, - selectedIndex); - - if (mapFile != NULL) { - EventChartTwoShowLineSeriesHistoryDialog lshd(EventChartTwoShowLineSeriesHistoryDialog::Mode::SHOW_DIALOG, - m_browserWindowIndex, - m_chartOverlay); - EventManager::get()->sendEvent(lshd.getPointer()); - } -} - - /** * Update this view controller using the given overlay. * @param overlay @@ -818,14 +769,6 @@ ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverla */ m_constructionAction->setEnabled(true); - /* - * Update history button - */ - m_historyAction->setEnabled(false); - if (validOverlayAndFileFlag) { - m_historyAction->setEnabled(m_chartOverlay->isHistorySupported()); - } - /* * Update matrix triangular view mode */ @@ -1442,53 +1385,3 @@ ChartTwoOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* wid return pixmap; } - -/** - * Create a history pixmap. - * - * @param widget - * To color the pixmap with backround and foreground, - * the palette from the given widget is used. - * @return - * Pixmap for history. - */ -QPixmap -ChartTwoOverlayViewController::createHistoryPixmap(QWidget* widget) -{ - CaretAssert(widget); - - /* - * Create a small, square pixmap that will contain - * the foreground color around the pixmap's perimeter. - */ - const qreal iconSize = 24.0; - const qreal centerX = iconSize / 2.0; - const qreal centerY = iconSize / 2.0; - - QPixmap pixmap(static_cast(iconSize), - static_cast(iconSize)); - QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, - pixmap); - - QPen pen = painter->pen(); - pen.setWidthF(2.0); - painter->setPen(pen); - - const QPointF circleCenterXY(centerX, centerY); - const qreal circleRadius = iconSize * 0.45; - - painter->drawEllipse(circleCenterXY, - circleRadius, circleRadius); - - const qreal nineOClockX = circleRadius * 0.5; //0.25 * iconSize; - const qreal twelveOClockY = 0.15 * iconSize; - painter->drawLine(QPointF(centerX, centerY), - QPointF(nineOClockX, centerY)); - painter->drawLine(QPointF(centerX, centerY), - QPointF(centerY, twelveOClockY)); - - return pixmap; -} - - - diff --git a/src/GuiQt/ChartTwoOverlayViewController.h b/src/GuiQt/ChartTwoOverlayViewController.h index ec44605f9..0be90da06 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.h +++ b/src/GuiQt/ChartTwoOverlayViewController.h @@ -84,8 +84,6 @@ namespace caret { void yokingGroupActivated(); - void historyActionTriggered(bool); - void allMapsCheckBoxClicked(bool); void menuAddOverlayAboveTriggered(); @@ -131,8 +129,6 @@ namespace caret { void updateOverlaySettingsEditor(); - QPixmap createHistoryPixmap(QWidget* widget); - QPixmap createMatrixTriangularViewModePixmap(QWidget* widget, const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); @@ -163,10 +159,6 @@ namespace caret { QAction* m_constructionAction; - QToolButton* m_historyToolButton; - - QAction* m_historyAction; - QToolButton* m_matrixTriangularViewModeToolButton; QAction* m_matrixTriangularViewModeAction; diff --git a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx deleted file mode 100644 index b16e211b3..000000000 --- a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.cxx +++ /dev/null @@ -1,92 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ -#include "EventChartTwoShowLineSeriesHistoryDialog.h" -#undef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - -#include "CaretAssert.h" -#include "EventTypeEnum.h" - -using namespace caret; - - - -/** - * \class caret::EventChartTwoShowLineSeriesHistoryDialog - * \brief Event to show the chart two line series history dialog - * \ingroup GuiQt - */ - -/** - * Constructor. - * - * @param mode - * Mode for the dialog. - * @param browserWindowIndex - * Index of the browser window. - * @param chartOverlay - * The chart overlay. - */ -EventChartTwoShowLineSeriesHistoryDialog::EventChartTwoShowLineSeriesHistoryDialog(const Mode mode, - const int32_t browserWindowIndex, - ChartTwoOverlay* chartOverlay) -: Event(EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG), -m_mode(mode), -m_browserWindowIndex(browserWindowIndex), -m_chartOverlay(chartOverlay) -{ - -} - -/** - * Destructor. - */ -EventChartTwoShowLineSeriesHistoryDialog::~EventChartTwoShowLineSeriesHistoryDialog() -{ -} - -/** - * @return The mode. - */ -EventChartTwoShowLineSeriesHistoryDialog::Mode -EventChartTwoShowLineSeriesHistoryDialog::getMode() const -{ - return m_mode; -} - -/** - * Index of the browser window. - */ -int32_t -EventChartTwoShowLineSeriesHistoryDialog::getBrowserWindowIndex() const -{ - return m_browserWindowIndex; -} - -/** - * @return The chart overlay. - */ -ChartTwoOverlay* -EventChartTwoShowLineSeriesHistoryDialog::getChartOverlay() const -{ - return m_chartOverlay; -} diff --git a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h b/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h deleted file mode 100644 index 43f2fa8e3..000000000 --- a/src/GuiQt/EventChartTwoShowLineSeriesHistoryDialog.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ -#define __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "Event.h" - - - -namespace caret { - - class CaretMappableDataFile; - class ChartTwoOverlay; - - class EventChartTwoShowLineSeriesHistoryDialog : public Event { - - public: - enum class Mode { - CHART_OVERLAY_CHANGED, - SHOW_DIALOG - }; - EventChartTwoShowLineSeriesHistoryDialog(const Mode mode, - const int32_t browserWindowIndex, - ChartTwoOverlay* chartOverlay); - - virtual ~EventChartTwoShowLineSeriesHistoryDialog(); - - Mode getMode() const; - - int32_t getBrowserWindowIndex() const; - - ChartTwoOverlay* getChartOverlay() const; - - // ADD_NEW_METHODS_HERE - - private: - EventChartTwoShowLineSeriesHistoryDialog(const EventChartTwoShowLineSeriesHistoryDialog&); - - EventChartTwoShowLineSeriesHistoryDialog& operator=(const EventChartTwoShowLineSeriesHistoryDialog&); - - const Mode m_mode; - - const int32_t m_browserWindowIndex; - - ChartTwoOverlay* m_chartOverlay; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - // -#endif // __EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_DECLARE__ - -} // namespace -#endif //__EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG_H__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index ceeca7072..8d8b8f4ce 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -46,7 +46,6 @@ #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartingDataManager.h" -#include "ChartTwoLineSeriesHistoryDialog.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiConnectivityMatrixDataFileManager.h" @@ -64,7 +63,6 @@ #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserWindowNew.h" -#include "EventChartTwoShowLineSeriesHistoryDialog.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" @@ -288,7 +286,6 @@ GuiManager::initializeGuiManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ALERT_USER); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_NEW); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY); @@ -1273,58 +1270,8 @@ GuiManager::receiveEvent(Event* event) EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); } - else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_SHOW_LINE_SERIES_HISTORY_DIALOG) { - EventChartTwoShowLineSeriesHistoryDialog* historyDialogEvent = dynamic_cast(event); - CaretAssert(historyDialogEvent); - - const EventChartTwoShowLineSeriesHistoryDialog::Mode mode = historyDialogEvent->getMode(); - const int32_t browserWindowIndex = historyDialogEvent->getBrowserWindowIndex(); - ChartTwoOverlay* chartOverlay = historyDialogEvent->getChartOverlay(); - - CaretAssertVectorIndex(m_brainBrowserWindows, browserWindowIndex); - BrainBrowserWindow* browserWindow = m_brainBrowserWindows[browserWindowIndex]; - CaretAssert(browserWindow); - - switch (mode) { - case EventChartTwoShowLineSeriesHistoryDialog::Mode::CHART_OVERLAY_CHANGED: - if (m_chartTwoLineSeriesHistoryDialog != NULL) { - m_chartTwoLineSeriesHistoryDialog->updateIfThisChartOverlayIsInDialog(chartOverlay); - } - break; - case EventChartTwoShowLineSeriesHistoryDialog::Mode::SHOW_DIALOG: - { - bool placeInDefaultLocation = false; - if (m_chartTwoLineSeriesHistoryDialog == NULL) { - m_chartTwoLineSeriesHistoryDialog = new ChartTwoLineSeriesHistoryDialog(browserWindow); - addNonModalDialog(m_chartTwoLineSeriesHistoryDialog); - placeInDefaultLocation = true; - } - else if (m_chartTwoLineSeriesHistoryDialog->isHidden()) { - placeInDefaultLocation = true; - } - - m_chartTwoLineSeriesHistoryDialog->updateDialogContent(chartOverlay); - - m_chartTwoLineSeriesHistoryDialog->show(); - m_chartTwoLineSeriesHistoryDialog->raise(); - m_chartTwoLineSeriesHistoryDialog->activateWindow(); - if (placeInDefaultLocation) { - WuQtUtilities::moveWindowToSideOfParent(browserWindow, - m_chartTwoLineSeriesHistoryDialog); - } - - } - break; - } - - historyDialogEvent->setEventProcessed(); - } else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW)) { - if (m_chartTwoLineSeriesHistoryDialog != NULL) { - m_chartTwoLineSeriesHistoryDialog->updateDialog(); - } - for (auto overlayEditor : m_overlaySettingsEditors) { overlayEditor->updateChartLinesInDialog(); } -- GitLab From e825903eda715620cbadb64968e5fd69c863ca7e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Sep 2017 09:57:54 -0500 Subject: [PATCH 397/755] Changed logging level in CIFTI matrix file for dynamic brainordinate loading from INFO to FINE. --- src/Files/CiftiMappableConnectivityMatrixDataFile.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx index 739acee73..fee8cbc5f 100644 --- a/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx +++ b/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx @@ -885,7 +885,7 @@ CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t + " was " + AString::number(timer.getElapsedTimeSeconds()) + " seconds."); - CaretLogInfo(msg); + CaretLogFine(msg); } -- GitLab From d66b8206682adaf08dfb87949f4ba978bbff5fc0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Sep 2017 12:39:25 -0500 Subject: [PATCH 398/755] Fixed memory leak in graphics primitive when the color of a chart two line was changed. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 35 ++++++++++++----------- src/Graphics/GraphicsEngineDataOpenGL.h | 10 +++---- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 3cac8ca3c..cf31cdaa7 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -90,17 +90,17 @@ GraphicsEngineDataOpenGL::deleteBufferObjectHelper(GraphicsOpenGLBufferObject* & void GraphicsEngineDataOpenGL::deleteBuffers() { - deleteBufferObjectHelper(m_coordinateBufferObject); + //deleteBufferObjectHelper(m_coordinateBufferObject); - deleteBufferObjectHelper(m_normalVectorBufferObject); + //deleteBufferObjectHelper(m_normalVectorBufferObject); - deleteBufferObjectHelper(m_colorBufferObject); + //deleteBufferObjectHelper(m_colorBufferObject); - deleteBufferObjectHelper(m_textureCoordinatesBufferObject); + //deleteBufferObjectHelper(m_textureCoordinatesBufferObject); - for (auto mapBuff: m_alternativeColorBufferObjectMap) { - deleteBufferObjectHelper(mapBuff.second); - } +// for (auto& mapBuff: m_alternativeColorBufferObjectMap) { +// deleteBufferObjectHelper(mapBuff.second); +// } m_alternativeColorBufferObjectMap.clear(); if (m_textureImageDataName != NULL) { @@ -188,7 +188,7 @@ GraphicsEngineDataOpenGL::loadCoordinateBuffer(GraphicsPrimitive* primitive) if (m_coordinateBufferObject == NULL) { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); - m_coordinateBufferObject = createEvent.getOpenGLBufferObject(); + m_coordinateBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_coordinateBufferObject); } @@ -239,7 +239,7 @@ GraphicsEngineDataOpenGL::loadNormalVectorBuffer(GraphicsPrimitive* primitive) EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); - m_normalVectorBufferObject = createEvent.getOpenGLBufferObject(); + m_normalVectorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_normalVectorBufferObject->getBufferObjectName()); glBindBuffer(GL_ARRAY_BUFFER, @@ -265,7 +265,6 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) GLenum usageHint = getOpeGLBufferUsageHint(primitive); - switch (primitive->m_colorType) { case GraphicsPrimitive::ColorType::NONE: break; @@ -273,7 +272,7 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); - m_colorBufferObject = createEvent.getOpenGLBufferObject(); + m_colorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_colorBufferObject->getBufferObjectName()); m_componentsPerColor = 4; @@ -295,7 +294,7 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); - m_colorBufferObject = createEvent.getOpenGLBufferObject(); + m_colorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_colorBufferObject->getBufferObjectName()); m_componentsPerColor = 4; @@ -335,7 +334,7 @@ GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primiti { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); - m_textureCoordinatesBufferObject = createEvent.getOpenGLBufferObject(); + m_textureCoordinatesBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_textureCoordinatesBufferObject->getBufferObjectName()); m_textureCoordinatesDataType = GL_FLOAT; @@ -503,9 +502,9 @@ GraphicsOpenGLBufferObject* GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitive, const int32_t alternativeColorIdentifier) { - std::map::iterator iter = m_alternativeColorBufferObjectMap.find(alternativeColorIdentifier); + const auto& iter = m_alternativeColorBufferObjectMap.find(alternativeColorIdentifier); if (iter != m_alternativeColorBufferObjectMap.end()) { - return iter->second; + return iter->second.get(); } GraphicsOpenGLBufferObject* outputOpenGLBufferObject = NULL; @@ -548,8 +547,9 @@ GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitiv colorDataPointer, usageHint); + std::shared_ptr bufferObjectPtr(bufferObject); m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, - bufferObject)); + bufferObjectPtr)); outputOpenGLBufferObject = bufferObject; } break; @@ -585,8 +585,9 @@ GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitiv colorDataPointer, usageHint); + std::shared_ptr bufferObjectPtr(bufferObject); m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, - bufferObject)); + bufferObjectPtr)); outputOpenGLBufferObject = bufferObject; } break; diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 9f08d1873..f2d40dc72 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -111,7 +111,7 @@ namespace caret { GLsizei m_arrayIndicesCount = 0; - GraphicsOpenGLBufferObject* m_coordinateBufferObject = NULL; + std::unique_ptr m_coordinateBufferObject; GLenum m_coordinateDataType = GL_FLOAT; @@ -121,19 +121,19 @@ namespace caret { bool m_reloadColorsFlag = false; - GraphicsOpenGLBufferObject* m_normalVectorBufferObject = NULL; + std::unique_ptr m_normalVectorBufferObject; GLenum m_normalVectorDataType = GL_FLOAT; - GraphicsOpenGLBufferObject* m_colorBufferObject = NULL; + std::unique_ptr m_colorBufferObject; - std::map m_alternativeColorBufferObjectMap; + std::map> m_alternativeColorBufferObjectMap; GLenum m_colorDataType = GL_FLOAT; GLint m_componentsPerColor = 0; - GraphicsOpenGLBufferObject* m_textureCoordinatesBufferObject = NULL; + std::unique_ptr m_textureCoordinatesBufferObject; GLenum m_textureCoordinatesDataType = GL_FLOAT; -- GitLab From 07c6cdd49c188172423af37287ad5db4c795a941 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Sep 2017 12:21:08 -0500 Subject: [PATCH 399/755] Resolve WB-727 - New tab may not appear: If the user tries to create a new tab and tile tabs in on and there is no space available in the tile tab configuration, allow the user to cancel tab creation. The dialog asking the user to continue creating the tab provides a 'do not show this dialog again' checkbox. --- src/GuiQt/BrainBrowserWindow.cxx | 83 +++++++- src/GuiQt/BrainBrowserWindow.h | 2 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 9 + src/GuiQt/BrainBrowserWindowToolBar.h | 1 + src/GuiQt/WuQMessageBox.cxx | 251 ++++++++++++++++++++++++ src/GuiQt/WuQMessageBox.h | 42 +++- 6 files changed, 383 insertions(+), 5 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index dc257ccdc..a94de9fdd 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -3508,13 +3508,86 @@ BrainBrowserWindow::saveWindowComponentStatus(WindowComponentStatus& wcs) m_featuresToolBoxAction->setEnabled(false); } +/** + * When adding a new tab or duplicating a tab, the tab + * may not be visible when Tile Tabs is enabled and there + * is no available space in the tile tabs configuration. + * + * @param newTabTypeMessage + * Message for type of new tab. + * @return + * True if new tab should be created, else false. + */ +bool +BrainBrowserWindow::allowAddingNewTab(const AString& newTabTypeMessage) +{ + static bool m_doNotShowDialogAgainFlag = false; + + if (m_doNotShowDialogAgainFlag) { + return true; + } + + /* + * Is tile tabs off? + */ + if ( ! m_viewTileTabsSelected) { + return true; + } + + const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); + if (tileTabs == NULL) { + return true; + } + + /* + * Default configuration always shows all tabs + */ + if (tileTabs->isDefaultConfiguration()) { + return true; + } + + /* + * Is there space in the current configuration? + */ + const int32_t tileTabsCount = tileTabs->getNumberOfColumns() * tileTabs->getNumberOfRows(); + if (m_toolbar->getNumberOfTabs() < tileTabsCount) { + return true; + } + + /* + * Selected configuration is full, all user to continue/cancel + */ + const AString doNotShowAgainMsg("Remember my choice and do not show this dialog again"); + + const AString msg("" + "Tile tabs is enabled and there is no space in the selected tile " + "tabs configuration for the new tab. If you choose to continue, " + "either the new tab will not be visible or an existing tab will " + "become invisible until the tile tabs configuration is changed." + "

" + "Do you want to create the new tab?" + "
" + ""); + + + if (WuQMessageBox::warningYesNoWithDoNotShowAgain(this, + "NewTabNotDisplayedDueToTileTabs", + msg)) { + return true; + } + + return false; +} + /** * Adds a new tab to the window. */ -void +void BrainBrowserWindow::processNewTab() { - m_toolbar->addNewTab(); + if (allowAddingNewTab("create")) { + m_toolbar->addNewTab(); + } } /** @@ -3523,8 +3596,10 @@ BrainBrowserWindow::processNewTab() void BrainBrowserWindow::processDuplicateTab() { - BrowserTabContent* previousTabContent = getBrowserTabContent(); - m_toolbar->addNewTabCloneContent(previousTabContent); + if (allowAddingNewTab("duplicate")) { + BrowserTabContent* previousTabContent = getBrowserTabContent(); + m_toolbar->addNewTabCloneContent(previousTabContent); + } } /** diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 3fe64d89e..dd6f3b3c8 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -298,6 +298,8 @@ namespace caret { bool isMacOptionKeyDown() const; + bool allowAddingNewTab(const AString& newTabTypeMessage); + /** Index of this window */ int32_t m_browserWindowIndex; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index fec6875e0..a9322e51a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -4140,3 +4140,12 @@ BrainBrowserWindowToolBar::restoreFromScene(const SceneAttributes* sceneAttribut showHideToolBar(showToolBar); } +/** + * @return Number of tabs in the tab bar. + */ +int32_t +BrainBrowserWindowToolBar::getNumberOfTabs() const +{ + return this->tabBar->count(); +} + diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 60754f926..65580e8c8 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -101,6 +101,7 @@ namespace caret { void receiveEvent(Event* event); + int32_t getNumberOfTabs() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); diff --git a/src/GuiQt/WuQMessageBox.cxx b/src/GuiQt/WuQMessageBox.cxx index 62881afa0..820a140dd 100644 --- a/src/GuiQt/WuQMessageBox.cxx +++ b/src/GuiQt/WuQMessageBox.cxx @@ -19,9 +19,14 @@ */ /*LICENSE_END*/ +#include + #include "CaretAssert.h" +#include "CaretLogger.h" +#define __WU_QMESSAGE_DEFINE__ #include "WuQMessageBox.h" +#undef __WU_QMESSAGE_DEFINE__ using namespace caret; @@ -290,6 +295,252 @@ WuQMessageBox::warningOkCancel(QWidget* parent, return WuQMessageBox::warningOkCancel(parent, text, ""); } +/** + * Display a warning message box with Ok and Cancel + * buttons and a checkbox. Pressing the enter key is + * the equivalent of pressing the Ok button. + * + * @param parent + * Parent on which message box is displayed. + * @param text + * Message that is displayed. + * @param checkBoxText + * Text for display in the checkbox. + * @param checkBoxStatusInOut + * Default status for checkbox and status of + * checkbox upon exit + * @return + * true if the Ok button was pressed else false + * if the cancel button was pressed. + */ +bool +WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text) +{ + return WuQMessageBox::warningYesNoWithDoNotShowAgain(parent, + uniqueIdentifier, + text, + ""); +} + +/** + * Display a warning message box with Yes and No + * buttons and a checkbox with the text + * "Remember my choice and do not show this dialog". + * + * If the user closes the dialog with the "Do not show + * again" box checked, the next time this function is + * called with the same "uniqueIdentifier" the dialog + * will not be displayed and return the selection made + * when the user last closed the dialog. + * + * @param parent + * Parent on which message box is displayed. + * @param uniqueIdentifier + * Unique identifier used for associating of + * "do not show" status + * @param text + * Message that is displayed. + * @param informativeText + * Displayed below 'text' if this is not empty. + * @return + * true if the Yes button was pressed false if + * the NO button was pressed. + */ +bool +WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text, + const QString& informativeText) +{ + /* + * See if user previously selected "do not show again". + * If so, return the button that the user last clicked. + */ + QMessageBox::StandardButton doNotShowAgainButton = QMessageBox::NoButton; + auto doNotShowStatus = s_doNotShowAgainButtonSelection.find(uniqueIdentifier); + if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { + doNotShowAgainButton = doNotShowStatus->second; + + bool yesPressedFlag = false; + switch (doNotShowAgainButton) { + case QMessageBox::Yes: + yesPressedFlag = true; + break; + case QMessageBox::No: + yesPressedFlag = false; + break; + default: + CaretAssert(0); + break; + + } + + return yesPressedFlag; + } + + /* + * Display a message box dialog to the user + */ + QMessageBox msgBox(parent); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(""); + msgBox.setText(text); + if (informativeText.isEmpty() == false) { + msgBox.setInformativeText(informativeText); + } + msgBox.addButton(QMessageBox::Yes); + msgBox.addButton(QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + msgBox.setEscapeButton(QMessageBox::No); + QCheckBox* checkBox = new QCheckBox("Remember my choice and do not show this dialog again"); + msgBox.setCheckBox(checkBox); + checkBox->setToolTip("Do not show is for this session (until wb_view is exited"); + + const QMessageBox::StandardButton buttonClicked = + static_cast(msgBox.exec()); + + bool yesPressedFlag = false; + + switch (buttonClicked) { + case QMessageBox::Yes: + yesPressedFlag = true; + break; + case QMessageBox::No: + break; + default: + CaretAssert(0); + break; + } + + /* + * If the "do not show again" checkbox was checked, + * save the button that the user clicked. + */ + const bool doNotShowAgainFlag = msgBox.checkBox()->isChecked(); + if (doNotShowAgainFlag) { + if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { + doNotShowStatus->second = buttonClicked; + } + else { + s_doNotShowAgainButtonSelection.insert(std::make_pair(uniqueIdentifier, + buttonClicked)); + } + } + + return yesPressedFlag; +} + +/** + * Display a Yes to All, Yes, No, button dialog. + * + * @param parent + * Parent on which message box is displayed. + * @param yesToAllButtonText + * Text for Yes to All button. If empty, + * "Yes to All" is displayed in button. + * @param yesButtonText + * Text for Yes button. If empty, + * "Yes" is displayed in button. + * @param noButtonText + * Text for No button. If empty, + * "No" is displayed in button. + * @param text + * Message that is displayed. + * @param informativeText + * Displayed below 'text' if this is not empty. + * @return + * One of QMessageBox::YesToAll + * QMessageBox::Yes + * QMessageBox::No + */ +WuQMessageBox::YesToAllYesNoResult +WuQMessageBox::warningYesToAllYesNo(QWidget* parent, + const QString& yesToAllButtonText, + const QString& yesButtonText, + const QString& noButtonText, + const QString& text, + const QString& informativeText) +{ + QMessageBox msgBox(parent); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(""); + msgBox.setText(text); + if (informativeText.isEmpty() == false) { + msgBox.setInformativeText(informativeText); + } + msgBox.addButton(QMessageBox::YesToAll); + msgBox.addButton(QMessageBox::Yes); + msgBox.addButton(QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + msgBox.setEscapeButton(QMessageBox::No); + + WuQMessageBox::updateButtonText(msgBox, + QMessageBox::YesToAll, + yesToAllButtonText); + WuQMessageBox::updateButtonText(msgBox, + QMessageBox::Yes, + yesButtonText); + WuQMessageBox::updateButtonText(msgBox, + QMessageBox::No, + noButtonText); + + + QMessageBox::StandardButton buttonPressed = + static_cast(msgBox.exec()); + + + YesToAllYesNoResult result = YesToAllYesNoResult::NO; + switch (buttonPressed) { + case QMessageBox::YesToAll: + result = YesToAllYesNoResult::YES_TO_ALL; + break; + case QMessageBox::Yes: + result = YesToAllYesNoResult::YES; + break; + case QMessageBox::No: + result = YesToAllYesNoResult::NO; + break; + default: + CaretAssert(0); + break; + } + + return result; +} + +/** + * Update the text for the standard button in the given message box. + * + * @param messageBox + * The message box. + * @param standardButton + * The standard button type. + * @param text + * Text for the standard button. If empty, no action is taken. + */ + +void +WuQMessageBox::updateButtonText(QMessageBox& messageBox, + const QMessageBox::StandardButton standardButton, + const QString& text) +{ + if (text.isEmpty()) { + return; + } + + QAbstractButton* button = messageBox.button(standardButton); + CaretAssert(button); + if (button == NULL) { + CaretLogSevere("Invalid QMessageBox::StandardButton integer value: " + + QString::number(static_cast(standardButton))); + return; + } + + button->setText(text); +} + /** * Display a warning message box with Yes and No * buttons. Pressing the enter key is the equivalent diff --git a/src/GuiQt/WuQMessageBox.h b/src/GuiQt/WuQMessageBox.h index 2498f39dc..8385592f6 100644 --- a/src/GuiQt/WuQMessageBox.h +++ b/src/GuiQt/WuQMessageBox.h @@ -22,6 +22,8 @@ */ /*LICENSE_END*/ +#include + #include namespace caret { @@ -36,6 +38,12 @@ namespace caret { RESULT_CANCEL }; + enum class YesToAllYesNoResult { + YES_TO_ALL, + YES, + NO + }; + static void errorOk(QWidget* parent, const QString& text); @@ -48,13 +56,22 @@ namespace caret { static bool warningOkCancel(QWidget* parent, const QString& text); + static bool warningYesNoWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text); + static bool warningYesNo(QWidget* parent, - const QString& text); + const QString& text); static bool warningOkCancel(QWidget* parent, const QString& text, const QString& informativeText); + static bool warningYesNoWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text, + const QString& informativeText); + static bool warningYesNo(QWidget* parent, const QString& text, const QString& informativeText); @@ -71,6 +88,12 @@ namespace caret { const QString& text, const QString& informativeText); + static YesToAllYesNoResult warningYesToAllYesNo(QWidget* parent, + const QString& yesToAllButtonText, + const QString& yesButtonText, + const QString& noButtonText, + const QString& text, + const QString& informativeText); private: WuQMessageBox(QWidget* parent = 0); ~WuQMessageBox(); @@ -78,7 +101,24 @@ namespace caret { WuQMessageBox(const WuQMessageBox&); WuQMessageBox& operator=(const WuQMessageBox&); + static void updateButtonText(QMessageBox& messageBox, + const QMessageBox::StandardButton standardButton, + const QString& text); + + /* + * Maintains "do not show again selections. + * Key is unique identifier supplied by caller to a dialog. + * Value is the button that was clicked. + */ + static std::map s_doNotShowAgainButtonSelection; + }; + +#ifdef __WU_QMESSAGE_DEFINE__ + std::map WuQMessageBox::s_doNotShowAgainButtonSelection; +#endif // __WU_QMESSAGE_DEFINE__ + } + #endif // __WU_QMESSAGE_DIALOG_H__ -- GitLab From 82a952d665af852c54d52fd1e527cd814caf357b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Sep 2017 14:55:02 -0500 Subject: [PATCH 400/755] When drawing charts with tile tabs enabled, the drawing size of an axis may be greater than the viewport for drawing the chart and this was causing OpenGL errors. When this occurs, do not draw any axes and only draw the chart's data plot. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 178 +++++++++++++++++- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 12 ++ 2 files changed, 183 insertions(+), 7 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 648851359..9c4d1cd45 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -661,12 +661,19 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch topAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); - /* - * Ensure that there is sufficient space for the axes data display. - */ - if ((tabViewportWidth > (leftAxisWidth + rightAxisWidth)) - && (tabViewportHeight > (bottomAxisHeight + topAxisHeight + topTitleHeight))) { - + const bool drawAxesFlag = createChartDrawingViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + m_chartOverlaySet->getAxisLineThickness(), + topTitleHeight, + bottomAxisHeight, + topAxisHeight, + leftAxisWidth, + rightAxisWidth, + chartGraphicsDrawingViewport); + + if (drawAxesFlag) { titleInfo.drawTitle(foregroundRGBA); leftAxisInfo.drawAxis(this, m_chartOverlaySet, @@ -701,7 +708,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch xMinBottom, xMaxBottom); - drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, @@ -715,6 +721,75 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch true, /* draw the box */ chartGraphicsDrawingViewport); } + else { + drawChartGraphicsBoxAndSetViewport(tabViewportX, + tabViewportY, + tabViewportWidth, + tabViewportHeight, + m_chartOverlaySet->getAxisLineThickness(), + topTitleHeight, + 0.0f, // bottomAxisHeight, + 0.0f, //topAxisHeight, + 0.0f, //leftAxisWidth, + 0.0f, //rightAxisWidth, + true, /* draw the box */ + chartGraphicsDrawingViewport); + } + +// /* +// * Ensure that there is sufficient space for the axes data display. +// */ +// if ((tabViewportWidth > (leftAxisWidth + rightAxisWidth)) +// && (tabViewportHeight > (bottomAxisHeight + topAxisHeight + topTitleHeight))) { +// +// titleInfo.drawTitle(foregroundRGBA); +// leftAxisInfo.drawAxis(this, +// m_chartOverlaySet, +// m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// foregroundRGBA, +// yMinLeft, +// yMaxLeft); +// rightAxisInfo.drawAxis(this, +// m_chartOverlaySet, +// m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// foregroundRGBA, +// yMinRight, +// yMaxRight); +// topAxisInfo.drawAxis(this, +// m_chartOverlaySet, +// m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// foregroundRGBA, +// xMinTop, +// xMaxTop); +// bottomAxisInfo.drawAxis(this, +// m_chartOverlaySet, +// m_fixedPipelineDrawing->getContextSharingGroupPointer(), +// m_fixedPipelineDrawing->mouseX, +// m_fixedPipelineDrawing->mouseY, +// foregroundRGBA, +// xMinBottom, +// xMaxBottom); +// +// +// drawChartGraphicsBoxAndSetViewport(tabViewportX, +// tabViewportY, +// tabViewportWidth, +// tabViewportHeight, +// m_chartOverlaySet->getAxisLineThickness(), +// topTitleHeight, +// bottomAxisHeight, +// topAxisHeight, +// leftAxisWidth, +// rightAxisWidth, +// true, /* draw the box */ +// chartGraphicsDrawingViewport); +// } /* * When the user is editing an axis minimum or maximum value, @@ -1558,6 +1633,92 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons chartGraphicsDrawingViewportOut[1] = graphicsBottom; chartGraphicsDrawingViewportOut[2] = graphicsWidth; chartGraphicsDrawingViewportOut[3] = graphicsHeight; + + CaretAssert(graphicsWidth > 0); + CaretAssert(graphicsHeight > 0); +} + +/** + * Create the graphics viewport. + * + * @param vpX + * Viewport X + * @param vpY + * Viewport Y + * @param vpWidth + * Viewport width + * @param vpHeight + * Viewport height + * @param lineThicknessPercentage + * Thickness of lines in percentage of viewport height + * @param titleHeight + * Height of the title + * @param bottomAxisHeight + * Height of bottom axis + * @param topAxisHeight + * Height of top axis + * @param leftAxisWidth + * Width of left axis + * @param rightAxisWidth + * Width of right axis + * @param chartGraphicsDrawingViewportOut + * Output containing viewport for drawing chart graphics within + * the box/grid that is adjusted for the box's line thickness. + * @return + * True if axes should be drawn, otherwise false. When chart + * gets too small, axes are not drawn. + */ +bool +BrainOpenGLChartTwoDrawingFixedPipeline::createChartDrawingViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const float lineThicknessPercentage, + const float titleHeight, + const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth, + int32_t chartGraphicsDrawingViewportOut[4]) +{ + const float lineThicknessPixels = convertPercentageOfViewportToOpenGLLineWidth(lineThicknessPercentage, + vpHeight); + /* + * Region INSIDE the grid's box so that any data plots + * are WITHIN the box + */ + float graphicsLeft = vpX + leftAxisWidth + lineThicknessPixels; + float graphicsRight = vpX + vpWidth - rightAxisWidth - lineThicknessPixels; + float graphicsBottom = vpY + bottomAxisHeight + lineThicknessPixels; + float graphicsTop = vpY + vpHeight - topAxisHeight - titleHeight - lineThicknessPixels; + + int32_t graphicsWidth = graphicsRight - graphicsLeft; + int32_t graphicsHeight = graphicsTop - graphicsBottom; + + bool drawAxesFlag = true; + + const int32_t minViewportSize = 20; + if ((graphicsWidth < minViewportSize) + || (graphicsHeight < minViewportSize)) { + graphicsLeft = vpX; + graphicsRight = vpX + vpWidth; + graphicsBottom = vpY; + graphicsTop = vpY + vpHeight; + + graphicsWidth = graphicsRight - graphicsLeft; + graphicsHeight = graphicsTop - graphicsBottom; + drawAxesFlag = false; + } + + chartGraphicsDrawingViewportOut[0] = graphicsLeft; + chartGraphicsDrawingViewportOut[1] = graphicsBottom; + chartGraphicsDrawingViewportOut[2] = graphicsWidth; + chartGraphicsDrawingViewportOut[3] = graphicsHeight; + + CaretAssert(graphicsWidth > 0); + CaretAssert(graphicsHeight > 0); + + return drawAxesFlag; } /** @@ -1569,6 +1730,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons void BrainOpenGLChartTwoDrawingFixedPipeline::updateViewportContentForCharting(const int32_t viewport[4]) { + CaretAssert(viewport[2] > 0); + CaretAssert(viewport[3] > 0); + GLfloat modelviewArray[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelviewArray); GLfloat projectionArray[16]; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index a970c78eb..3208c60b1 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -236,6 +236,18 @@ namespace caret { const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]); + bool createChartDrawingViewport(const float vpX, + const float vpY, + const float vpWidth, + const float vpHeight, + const float lineThicknessPercentage, + const float titleHeight, + const float bottomAxisHeight, + const float topAxisHeight, + const float leftAxisWidth, + const float rightAxisWidth, + int32_t chartGraphicsDrawingViewportOut[4]); + void drawPrimitivePrivate(GraphicsPrimitive* primitive); void updateViewportContentForCharting(const int32_t viewport[4]); -- GitLab From 43a487c1ec1a5ab450fbd4d79cec479a3800bfbc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Sep 2017 15:38:13 -0500 Subject: [PATCH 401/755] Remove unused method parameter from recent addition to warn user if tile tabs is full and user tries to add a tab. --- src/GuiQt/BrainBrowserWindow.cxx | 8 +++----- src/GuiQt/BrainBrowserWindow.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index a94de9fdd..2e76bf116 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -3513,13 +3513,11 @@ BrainBrowserWindow::saveWindowComponentStatus(WindowComponentStatus& wcs) * may not be visible when Tile Tabs is enabled and there * is no available space in the tile tabs configuration. * - * @param newTabTypeMessage - * Message for type of new tab. * @return * True if new tab should be created, else false. */ bool -BrainBrowserWindow::allowAddingNewTab(const AString& newTabTypeMessage) +BrainBrowserWindow::allowAddingNewTab() { static bool m_doNotShowDialogAgainFlag = false; @@ -3585,7 +3583,7 @@ BrainBrowserWindow::allowAddingNewTab(const AString& newTabTypeMessage) void BrainBrowserWindow::processNewTab() { - if (allowAddingNewTab("create")) { + if (allowAddingNewTab()) { m_toolbar->addNewTab(); } } @@ -3596,7 +3594,7 @@ BrainBrowserWindow::processNewTab() void BrainBrowserWindow::processDuplicateTab() { - if (allowAddingNewTab("duplicate")) { + if (allowAddingNewTab()) { BrowserTabContent* previousTabContent = getBrowserTabContent(); m_toolbar->addNewTabCloneContent(previousTabContent); } diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index dd6f3b3c8..4a02e5e57 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -298,7 +298,7 @@ namespace caret { bool isMacOptionKeyDown() const; - bool allowAddingNewTab(const AString& newTabTypeMessage); + bool allowAddingNewTab(); /** Index of this window */ int32_t m_browserWindowIndex; -- GitLab From 61a202f17dba0d266ed6c9fc8fd3e329274ea0e6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Sep 2017 16:43:30 -0500 Subject: [PATCH 402/755] Resolve WB-731 Ask users if they want to lock windows and tabs when first entering annotation: If user presses Annotation Mode button and neither Tab nor Window Aspect locking is selected, pop-up a warning message to the user. The warning message contains a "do not show again" checkbox to avoid future pop-ups. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 61 +++++++++++++------ src/GuiQt/BrainBrowserWindowToolBar.h | 3 + src/GuiQt/WuQMessageBox.cxx | 80 +++++++++++++++++++++++-- src/GuiQt/WuQMessageBox.h | 8 +++ 4 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index a9322e51a..81c88bd7f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -156,6 +156,9 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; + m_windowAspectRatioLockedAction = windowAspectRatioLockedAction; + m_tabAspectRatioLockedAction = tabAspectRatioLockedAction; + this->isContructorFinished = false; this->isDestructionInProgress = false; @@ -344,8 +347,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); this->volumeIndicesWidget = this->createVolumeIndicesWidget(); this->modeWidget = this->createModeWidget(); - this->windowWidget = this->createTabOptionsWidget(windowAspectRatioLockedAction, - tabAspectRatioLockedAction); + this->windowWidget = this->createTabOptionsWidget(m_windowAspectRatioLockedAction, + m_tabAspectRatioLockedAction); this->singleSurfaceSelectionWidget = this->createSingleSurfaceOptionsWidget(); this->surfaceMontageSelectionWidget = this->createSurfaceMontageOptionsWidget(); m_clippingOptionsWidget = createClippingOptionsWidget(); @@ -667,27 +670,33 @@ BrainBrowserWindowToolBar::addOrInsertNewTab(BrowserTabContent* browserTabConten "NewTab"); } else { - const int32_t tabContentIndex = browserTabContent->getTabNumber(); - - const int32_t numTabs = this->tabBar->count(); - if (numTabs <= 0) { - newTabIndex = this->tabBar->addTab("NewTab"); - } - else { - int insertIndex = 0; - for (int32_t i = 0; i < numTabs; i++) { - if (tabContentIndex > this->getTabContentFromTab(i)->getTabNumber()) { - insertIndex = i + 1; - } - } - if (insertIndex >= numTabs) { + const bool putTabInTabOrderFlag = false; + if (putTabInTabOrderFlag) { + const int32_t tabContentIndex = browserTabContent->getTabNumber(); + + const int32_t numTabs = this->tabBar->count(); + if (numTabs <= 0) { newTabIndex = this->tabBar->addTab("NewTab"); } else { - this->tabBar->insertTab(insertIndex, "NewTab"); - newTabIndex = insertIndex; + int insertIndex = 0; + for (int32_t i = 0; i < numTabs; i++) { + if (tabContentIndex > this->getTabContentFromTab(i)->getTabNumber()) { + insertIndex = i + 1; + } + } + if (insertIndex >= numTabs) { + newTabIndex = this->tabBar->addTab("NewTab"); + } + else { + this->tabBar->insertTab(insertIndex, "NewTab"); + newTabIndex = insertIndex; + } } } + else { + newTabIndex = this->tabBar->addTab("NewTab"); + } } this->tabBar->setTabData(newTabIndex, @@ -2512,7 +2521,21 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) UserInputModeAbstract::UserInputMode inputMode = UserInputModeAbstract::INVALID; if (action == this->modeInputModeAnnotationsAction) { - inputMode = UserInputModeAbstract::ANNOTATIONS; + if ( ( ! m_windowAspectRatioLockedAction->isChecked()) + && ( ! m_tabAspectRatioLockedAction->isChecked()) ) { + const QString msg("" + "Neither Lock Window Aspect nor Lock Tab Aspect " + "are selected. Tab and Window annotations are displayed " + "in percentage coordinates of the tab/window " + "width and height. Locking tab/window aspect ensures that " + "the shape of the tab/window maintains its aspect ratio so " + "that tab/window annotations remain in the correct location. " + ""); + WuQMessageBox::warningOkWithDoNotShowAgain(this, + "lockAspectDoNotShowAgainIdentifier", + msg); + } + inputMode = UserInputModeAbstract::ANNOTATIONS; } else if (action == this->modeInputModeBordersAction) { inputMode = UserInputModeAbstract::BORDERS; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 65580e8c8..a87432c7c 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -227,6 +227,9 @@ namespace caret { /** Is set to the user input widget provided by the user input processor */ QWidget* userInputControlsWidgetActiveInputWidget; + QAction* m_windowAspectRatioLockedAction; + QAction* m_tabAspectRatioLockedAction; + void removeAndReturnAllTabs(std::vector& allTabContent); void getAllTabContent(std::vector& allTabContent) const; diff --git a/src/GuiQt/WuQMessageBox.cxx b/src/GuiQt/WuQMessageBox.cxx index 820a140dd..7d8b6e7c6 100644 --- a/src/GuiQt/WuQMessageBox.cxx +++ b/src/GuiQt/WuQMessageBox.cxx @@ -275,6 +275,79 @@ WuQMessageBox::warningOk(QWidget* parent, msgBox.exec(); } +/** + * Display an error message box with the + * given text and an OK button and a checkbox with + * the text "Remember my choice and do not show this dialog". + * + * If the user closes the dialog with the "Do not show + * again" box checked, the next time this function is + * called with the dialog will not be displayed. + * + * @param parent + * Parent on which message box is displayed. + * @param uniqueIdentifier + * Unique identifier used for associating of + * "do not show" status + * @param text + * Message that is displayed. + */ +void +WuQMessageBox::warningOkWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text) +{ + /* + * See if user previously selected "do not show again". + * If so, do not display dialog and return. + */ + auto doNotShowStatus = s_doNotShowAgainButtonSelection.find(uniqueIdentifier); + if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { + return; + } + + QMessageBox msgBox(parent); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(""); + msgBox.setText(text); + msgBox.addButton(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setEscapeButton(QMessageBox::Ok); + + QCheckBox* checkBox = addDoNotShowAgainCheckBox(msgBox); + + msgBox.exec(); + + /* + * If the "do not show again" checkbox was checked, + * save to do not show status. + */ + const bool doNotShowAgainFlag = checkBox->isChecked(); + if (doNotShowAgainFlag) { + s_doNotShowAgainButtonSelection.insert(std::make_pair(uniqueIdentifier, + QMessageBox::NoButton)); + } +} + +/** + * Add a "do not show again" checkbox to the given message checkbox. + * + * @param messageBox + * Message box to which "do not show again" checkbox is added. + * @return + * Pointer to the checkbox (do not destroy as dialog closing + * will handle checkbox destruction). + */ +QCheckBox* +WuQMessageBox::addDoNotShowAgainCheckBox(QMessageBox& messageBox) +{ + QCheckBox* checkBox = new QCheckBox("Remember my choice and do not show this dialog again"); + messageBox.setCheckBox(checkBox); + checkBox->setToolTip("Do not show again for this session (until wb_view is exited)"); + return checkBox; +} + + /** * Display a warning message box with Ok and Cancel * buttons. Pressing the enter key is the equivalent @@ -394,9 +467,8 @@ WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, msgBox.addButton(QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.setEscapeButton(QMessageBox::No); - QCheckBox* checkBox = new QCheckBox("Remember my choice and do not show this dialog again"); - msgBox.setCheckBox(checkBox); - checkBox->setToolTip("Do not show is for this session (until wb_view is exited"); + + QCheckBox* checkBox = addDoNotShowAgainCheckBox(msgBox); const QMessageBox::StandardButton buttonClicked = static_cast(msgBox.exec()); @@ -418,7 +490,7 @@ WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, * If the "do not show again" checkbox was checked, * save the button that the user clicked. */ - const bool doNotShowAgainFlag = msgBox.checkBox()->isChecked(); + const bool doNotShowAgainFlag = checkBox->isChecked(); if (doNotShowAgainFlag) { if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { doNotShowStatus->second = buttonClicked; diff --git a/src/GuiQt/WuQMessageBox.h b/src/GuiQt/WuQMessageBox.h index 8385592f6..a433ef317 100644 --- a/src/GuiQt/WuQMessageBox.h +++ b/src/GuiQt/WuQMessageBox.h @@ -26,6 +26,8 @@ #include +class QCheckBox; + namespace caret { class WuQMessageBox : public QMessageBox { @@ -53,6 +55,10 @@ namespace caret { static void warningOk(QWidget* parent, const QString& text); + static void warningOkWithDoNotShowAgain(QWidget* parent, + const QString& uniqueIdentifier, + const QString& text); + static bool warningOkCancel(QWidget* parent, const QString& text); @@ -101,6 +107,8 @@ namespace caret { WuQMessageBox(const WuQMessageBox&); WuQMessageBox& operator=(const WuQMessageBox&); + static QCheckBox* addDoNotShowAgainCheckBox(QMessageBox& messageBox); + static void updateButtonText(QMessageBox& messageBox, const QMessageBox::StandardButton standardButton, const QString& text); -- GitLab From 5cf53598bf3ec490f82bd5e2fdf809dcacd1e9c2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 15 Sep 2017 16:29:44 -0500 Subject: [PATCH 403/755] Added pop-up dialog (right click) on Lock Tab and Lock Window Aspect Ratio buttons so that user can manually set the numerical value for the aspect ratio. --- src/GuiQt/BrainBrowserWindow.cxx | 145 ++++++++++++++++++--- src/GuiQt/BrainBrowserWindow.h | 8 ++ src/GuiQt/BrainBrowserWindowToolBarTab.cxx | 100 ++++++++++++-- src/GuiQt/BrainBrowserWindowToolBarTab.h | 12 ++ 4 files changed, 235 insertions(+), 30 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 2e76bf116..b12272b94 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,7 @@ #include "SurfaceSelectionViewController.h" #include "TileTabsConfiguration.h" #include "WuQDataEntryDialog.h" +#include "WuQDoubleSpinBox.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "VtkFileExporter.h" @@ -728,11 +730,18 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_featuresToolBoxAction->setIconText("LT"); } + const QString aspectButtonToolTipText("" + "Right-Click (Command-Click on Mac) to display a dialog " + "for manual entry of the aspect ratio. The value displayed " + "is the value from the last time aspect was locked. If a " + "value is entered, the lock status is set to ON." + ""); + m_windowAspectRatioLockedAction = new QAction(this); m_windowAspectRatioLockedAction->setCheckable(true); m_windowAspectRatioLockedAction->setChecked(false); m_windowAspectRatioLockedAction->setText("Lock Window Aspect"); - m_windowAspectRatioLockedAction->setToolTip("Lock aspect ratio of window"); + m_windowAspectRatioLockedAction->setToolTip(aspectButtonToolTipText); m_windowAspectRatioLockedAction->setShortcut(Qt::SHIFT + Qt::CTRL+Qt::Key_K); QObject::connect(m_windowAspectRatioLockedAction, SIGNAL(toggled(bool)), this, SLOT(processWindowAspectRatioLockedToggled(bool))); @@ -740,7 +749,7 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_tabAspectRatioLockedAction = new QAction(this); m_tabAspectRatioLockedAction->setCheckable(true); m_tabAspectRatioLockedAction->setText("Lock Tab Aspect"); - m_tabAspectRatioLockedAction->setToolTip("Lock aspect ratio of selected tab"); + m_tabAspectRatioLockedAction->setToolTip(aspectButtonToolTipText); m_tabAspectRatioLockedAction->setShortcut(Qt::CTRL+Qt::Key_K); QObject::connect(m_tabAspectRatioLockedAction, SIGNAL(toggled(bool)), this, SLOT(processTabAspectRatioLockedToggled(bool))); @@ -756,6 +765,15 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_unlockAllTabsAspectRatioAction->setToolTip("Unlock aspect ratio of all tabs in this window"); QObject::connect(m_unlockAllTabsAspectRatioAction, SIGNAL(triggered(bool)), this, SLOT(processUnlockAllTabsAspectRatioTriggered())); + + const bool showEditAspectDialogFlag = false; + if (showEditAspectDialogFlag) { + m_editTabAndWindowAspectRatiosAction = new QAction(this); + m_editTabAndWindowAspectRatiosAction->setText("Edit Locked Aspect Ratios..."); + m_editTabAndWindowAspectRatiosAction->setToolTip("Edit the aspect ratio for locked window and locked tabs"); + QObject::connect(m_editTabAndWindowAspectRatiosAction, &QAction::triggered, + this, &BrainBrowserWindow::processEditTabAndWindowAspectRatiosTriggered); + } } /** @@ -855,6 +873,15 @@ BrainBrowserWindow::processUnlockAllTabsAspectRatioTriggered() m_toolbar->updateToolBar(); } +/** + * Called when the Edit Tab and Window Lock Aspect Ratios is called. + */ +void +BrainBrowserWindow::processEditTabAndWindowAspectRatiosTriggered() +{ + CaretAssertMessage(0, "Source for dialog is in \"saved_source\" directory"); +} + /** * Called when the Tab aspect ratio action it toggled. * @@ -862,56 +889,128 @@ BrainBrowserWindow::processUnlockAllTabsAspectRatioTriggered() */ void BrainBrowserWindow::processTabAspectRatioLockedToggled(bool checked) +{ + BrowserTabContent* selectedTab = m_toolbar->getTabContentFromSelectedTab(); + if (selectedTab != NULL) { + std::vector vpContent = m_openGLWidget->getViewportContent(); + for (std::vector::iterator vpIter = vpContent.begin(); + vpIter != vpContent.end(); + vpIter++) { + const BrainOpenGLViewportContent* vp = *vpIter; + CaretAssert(vp); + + BrowserTabContent* tabContent = vp->getBrowserTabContent(); + if (selectedTab == tabContent) { + int32_t tabViewport[4]; + vp->getTabViewportBeforeApplyingMargins(tabViewport); + + float aspectRatio = tabContent->getAspectRatio(); + + if (checked) { + const float width = tabViewport[2]; + if (width > 0.0) { + aspectRatio = tabViewport[3] / width; + } + } + + setLockTabAspectStatusAndRatio(checked, aspectRatio); + } + } + } + + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); +} + +/** + * Set the tab aspect ratio lock status and the ratio. Note the ratio + * is only set if the lock status is true. + * + * @param lockStatus + * New status for lock window aspect. + * @param aspectRatio + * New value for aspect ratio. + */ +void +BrainBrowserWindow::setLockTabAspectStatusAndRatio(const bool lockStatus, + const float aspectRatio) { BrowserTabContent* selectedTab = m_toolbar->getTabContentFromSelectedTab(); if (selectedTab != NULL) { std::vector vpContent = m_openGLWidget->getViewportContent(); - for (std::vector::iterator vpIter = vpContent.begin(); - vpIter != vpContent.end(); - vpIter++) { - const BrainOpenGLViewportContent* vp = *vpIter; + for (auto vp : vpContent) { CaretAssert(vp); BrowserTabContent* tabContent = vp->getBrowserTabContent(); if (selectedTab == tabContent) { - int32_t tabViewport[4]; - vp->getTabViewportBeforeApplyingMargins(tabViewport); - - const float width = tabViewport[2]; - if (width > 0.0) { - const float aspectRatio = tabViewport[3] / width; - - tabContent->setAspectRatioLocked(checked); - if (checked) { + tabContent->setAspectRatioLocked(lockStatus); + if (lockStatus) { + if (aspectRatio > 0.0) { tabContent->setAspectRatio(aspectRatio); } + else { + CaretLogSevere("Invalid tab aspect ratio " + AString::number(aspectRatio)); + } } } } } + m_tabAspectRatioLockedAction->blockSignals(true); + m_tabAspectRatioLockedAction->setChecked(lockStatus); + m_tabAspectRatioLockedAction->blockSignals(false); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } + /** - * Called when the Window aspect ratio action it toggled. + * Set the window aspect ratio lock status and the ratio. Note the ratio + * is only set if the lock status is true. * - * @param new tab locked status + * @param lockStatus + * New status for lock window aspect. + * @param aspectRatio + * New value for aspect ratio. */ void -BrainBrowserWindow::processWindowAspectRatioLockedToggled(bool checked) +BrainBrowserWindow::setLockWindowAspectStatusAndRatio(const bool lockStatus, + const float aspectRatio) { - setAspectRatioLocked(checked); - if (checked) { - const float aspectRatio = getOpenGLWidgetAspectRatio(); + setAspectRatioLocked(lockStatus); + if (lockStatus) { if (aspectRatio > 0) { setAspectRatio(aspectRatio); } + else { + CaretLogSevere("Invalid window aspect ratio " + AString::number(aspectRatio)); + } } EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } + +/** + * Called when the Window aspect ratio action it toggled. + * + * @param new tab locked status + */ +void +BrainBrowserWindow::processWindowAspectRatioLockedToggled(bool checked) +{ + setLockWindowAspectStatusAndRatio(checked, getOpenGLWidgetAspectRatio()); + +// setAspectRatioLocked(checked); +// if (checked) { +// const float aspectRatio = getOpenGLWidgetAspectRatio(); +// if (aspectRatio > 0) { +// setAspectRatio(aspectRatio); +// } +// } +// +// EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); +} + /** * @return Is the aspect ratio locked? */ @@ -2459,6 +2558,10 @@ BrainBrowserWindow::createMenuWindow() menu->addAction(m_tabAspectRatioLockedAction); menu->addAction(m_lockAllTabsAspectRatioAction); menu->addAction(m_unlockAllTabsAspectRatioAction); + const bool showEditAspectRatiosFlag = false; + if (showEditAspectRatiosFlag) { + menu->addAction(m_editTabAndWindowAspectRatiosAction); + } menu->addSeparator(); menu->addAction(m_nextTabAction); diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 4a02e5e57..3d17003ae 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -145,6 +145,12 @@ namespace caret { void setAspectRatio(const float aspectRatio); + void setLockTabAspectStatusAndRatio(const bool lockStatus, + const float aspectRatio); + + void setLockWindowAspectStatusAndRatio(const bool lockStatus, + const float aspectRatio); + bool hasValidOpenGL(); bool isOpenGLContextSharingValid() const; @@ -230,6 +236,7 @@ namespace caret { void processWindowAspectRatioLockedToggled(bool checked); void processLockAllTabsAspectRatioTriggered(); void processUnlockAllTabsAspectRatioTriggered(); + void processEditTabAndWindowAspectRatiosTriggered(); void processEditMenuItemTriggered(QAction* action); void processEditMenuAboutToShow(); @@ -385,6 +392,7 @@ namespace caret { QAction* m_unlockAllTabsAspectRatioAction; QAction* m_tabAspectRatioLockedAction; QAction* m_windowAspectRatioLockedAction; + QAction* m_editTabAndWindowAspectRatiosAction; QAction* m_featuresToolBoxAction; diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx index 3e2794e10..def4b5912 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx @@ -24,8 +24,9 @@ #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_DECLARE__ #include -#include #include +#include +#include #include #include @@ -39,6 +40,7 @@ #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" #include "YokingGroupEnum.h" +#include "WuQDataEntryDialog.h" using namespace caret; @@ -81,21 +83,27 @@ m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) QObject::connect(m_yokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokeToGroupComboBoxIndexChanged())); - QToolButton* windowAspectRatioLockedToolButton = new QToolButton(); - windowAspectRatioLockedToolButton->setDefaultAction(windowAspectRatioLockedAction); - WuQtUtilities::setToolButtonStyleForQt5Mac(windowAspectRatioLockedToolButton); + m_windowAspectRatioLockedToolButton = new QToolButton(); + m_windowAspectRatioLockedToolButton->setDefaultAction(windowAspectRatioLockedAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_windowAspectRatioLockedToolButton); + QObject::connect(m_windowAspectRatioLockedToolButton, &QToolButton::customContextMenuRequested, + this, &BrainBrowserWindowToolBarTab::windowAspectCustomContextMenuRequested); + m_windowAspectRatioLockedToolButton->setContextMenuPolicy(Qt::CustomContextMenu); - QToolButton* tabAspectRatioLockedToolButton = new QToolButton(); - tabAspectRatioLockedToolButton->setDefaultAction(tabAspectRatioLockedAction); - WuQtUtilities::setToolButtonStyleForQt5Mac(tabAspectRatioLockedToolButton); + m_tabAspectRatioLockedToolButton = new QToolButton(); + m_tabAspectRatioLockedToolButton->setDefaultAction(tabAspectRatioLockedAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_tabAspectRatioLockedToolButton); + QObject::connect(m_tabAspectRatioLockedToolButton, &QToolButton::customContextMenuRequested, + this, &BrainBrowserWindowToolBarTab::tabAspectCustomContextMenuRequested); + m_tabAspectRatioLockedToolButton->setContextMenuPolicy(Qt::CustomContextMenu); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); layout->addWidget(m_yokeToLabel); layout->addWidget(m_yokingGroupComboBox->getWidget()); layout->addSpacing(15); - layout->addWidget(windowAspectRatioLockedToolButton); - layout->addWidget(tabAspectRatioLockedToolButton); + layout->addWidget(m_windowAspectRatioLockedToolButton); + layout->addWidget(m_tabAspectRatioLockedToolButton); addToWidgetGroup(m_yokeToLabel); addToWidgetGroup(m_yokingGroupComboBox->getWidget()); @@ -108,6 +116,80 @@ BrainBrowserWindowToolBarTab::~BrainBrowserWindowToolBarTab() { } +/** + * Called when context menu requested for window lock aspect button. + * + * @param pos + * Postion of mouse in parent widget. + */ +void +BrainBrowserWindowToolBarTab::tabAspectCustomContextMenuRequested(const QPoint& /*pos*/) +{ + BrowserTabContent* tabContent = m_parentToolBar->getTabContentFromSelectedTab(); + if (tabContent != NULL) { + BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(window); + + float aspectRatio = getAspectRatioFromDialog("Set Tab Aspect Ratio", + tabContent->getAspectRatio(), + m_tabAspectRatioLockedToolButton); + if (aspectRatio > 0.0) { + window->setLockTabAspectStatusAndRatio(true, aspectRatio); + } + } +} + +/** + * Called when context menu requested for window lock aspect button. + * + * @param pos + * Postion of mouse in parent widget. + */ +void +BrainBrowserWindowToolBarTab::windowAspectCustomContextMenuRequested(const QPoint& /*pos*/) +{ + BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(window); + + float aspectRatio = getAspectRatioFromDialog("Set Window Aspect Ratio", + window->getAspectRatio(), + m_windowAspectRatioLockedToolButton); + if (aspectRatio > 0.0) { + window->setLockWindowAspectStatusAndRatio(true, aspectRatio); + } +} + +/** + * Get the new aspect ratio using a dialog. + * + * @param title + * Title for dialog. + * @param aspectRatio + * Default value for aspect ratio + * @param parent + * Parent for the dialog. + */ +float +BrainBrowserWindowToolBarTab::getAspectRatioFromDialog(const QString& title, + const float aspectRatio, + QWidget* parent) const +{ + float aspectRatioOut = -1.0; + + WuQDataEntryDialog ded(title, + parent); + QDoubleSpinBox* ratioSpinBox = ded.addDoubleSpinBox("Aspect Ratio", aspectRatio); + ratioSpinBox->setSingleStep(0.01); + ratioSpinBox->setRange(ratioSpinBox->singleStep(), 100.0); + ratioSpinBox->setDecimals(3); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + aspectRatioOut = ratioSpinBox->value(); + } + + return aspectRatioOut; +} + + /** * Update the surface montage options widget. * diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.h b/src/GuiQt/BrainBrowserWindowToolBarTab.h index aefac6a99..6e1dcee65 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.h +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.h @@ -51,11 +51,19 @@ namespace caret { private slots: void yokeToGroupComboBoxIndexChanged(); + void tabAspectCustomContextMenuRequested(const QPoint& pos); + + void windowAspectCustomContextMenuRequested(const QPoint& pos); + private: BrainBrowserWindowToolBarTab(const BrainBrowserWindowToolBarTab&); BrainBrowserWindowToolBarTab& operator=(const BrainBrowserWindowToolBarTab&); + float getAspectRatioFromDialog(const QString& title, + const float aspectRatio, + QWidget* parent) const; + QLabel* m_yokeToLabel; EnumComboBoxTemplate* m_yokingGroupComboBox; @@ -66,6 +74,10 @@ namespace caret { QAction* m_tabAspectRatioLockedAction; + QToolButton* m_tabAspectRatioLockedToolButton; + + QToolButton* m_windowAspectRatioLockedToolButton; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 9fb87c5e092300deb6f7423e6df17e9fae8f0953 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 18 Sep 2017 15:27:57 -0500 Subject: [PATCH 404/755] Resolve WB-726 - Create new tab insertion location: Rather than changing the functionality of the Menu Bar items for adding and duplicating tabs, a right-click menu has been added to the tab bar. When the a right-click is performed over a tab in the tab bar, a menu is displayed and provides selection for adding a new tab to the right of the selected tab, duplicating the selected tab and adding it to the right of the selected tab, and an item to close the selected tab. If a right-click is made over an empty region in the tab bar, a menu pos up that allows the user to add a new tab. --- src/GuiQt/BrainBrowserWindow.cxx | 79 +----- src/GuiQt/BrainBrowserWindow.h | 2 - src/GuiQt/BrainBrowserWindowToolBar.cxx | 327 +++++++++++++++++++----- src/GuiQt/BrainBrowserWindowToolBar.h | 23 +- 4 files changed, 280 insertions(+), 151 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index b12272b94..38a745c5d 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -3611,84 +3611,13 @@ BrainBrowserWindow::saveWindowComponentStatus(WindowComponentStatus& wcs) m_featuresToolBoxAction->setEnabled(false); } -/** - * When adding a new tab or duplicating a tab, the tab - * may not be visible when Tile Tabs is enabled and there - * is no available space in the tile tabs configuration. - * - * @return - * True if new tab should be created, else false. - */ -bool -BrainBrowserWindow::allowAddingNewTab() -{ - static bool m_doNotShowDialogAgainFlag = false; - - if (m_doNotShowDialogAgainFlag) { - return true; - } - - /* - * Is tile tabs off? - */ - if ( ! m_viewTileTabsSelected) { - return true; - } - - const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); - if (tileTabs == NULL) { - return true; - } - - /* - * Default configuration always shows all tabs - */ - if (tileTabs->isDefaultConfiguration()) { - return true; - } - - /* - * Is there space in the current configuration? - */ - const int32_t tileTabsCount = tileTabs->getNumberOfColumns() * tileTabs->getNumberOfRows(); - if (m_toolbar->getNumberOfTabs() < tileTabsCount) { - return true; - } - - /* - * Selected configuration is full, all user to continue/cancel - */ - const AString doNotShowAgainMsg("Remember my choice and do not show this dialog again"); - - const AString msg("" - "Tile tabs is enabled and there is no space in the selected tile " - "tabs configuration for the new tab. If you choose to continue, " - "either the new tab will not be visible or an existing tab will " - "become invisible until the tile tabs configuration is changed." - "

" - "Do you want to create the new tab?" - "
" - ""); - - - if (WuQMessageBox::warningYesNoWithDoNotShowAgain(this, - "NewTabNotDisplayedDueToTileTabs", - msg)) { - return true; - } - - return false; -} - /** * Adds a new tab to the window. */ void BrainBrowserWindow::processNewTab() { - if (allowAddingNewTab()) { - m_toolbar->addNewTab(); - } + m_toolbar->addNewTab(); } /** @@ -3697,10 +3626,8 @@ BrainBrowserWindow::processNewTab() void BrainBrowserWindow::processDuplicateTab() { - if (allowAddingNewTab()) { - BrowserTabContent* previousTabContent = getBrowserTabContent(); - m_toolbar->addNewTabCloneContent(previousTabContent); - } + BrowserTabContent* previousTabContent = getBrowserTabContent(); + m_toolbar->addNewDuplicatedTab(previousTabContent); } /** diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 3d17003ae..2477b9b47 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -305,8 +305,6 @@ namespace caret { bool isMacOptionKeyDown() const; - bool allowAddingNewTab(); - /** Index of this window */ int32_t m_browserWindowIndex; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 81c88bd7f..2aa3db3dd 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -112,6 +112,7 @@ #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "StructureSurfaceSelectionControl.h" +#include "TileTabsConfiguration.h" #include "UserInputModeAbstract.h" #include "VolumeFile.h" #include "VolumeSliceViewPlaneEnum.h" @@ -234,6 +235,17 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QObject::connect(this->tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); + + /* + * Add context menu + * From the position, use QTabBar::tabAt(const QPoint& position) to get the + * tab that the user has clicked and if over a tab, pop-up a menu + * for the tab with Create New Tab and Place Right, Duplicate and Place on Right + */ + QObject::connect(this->tabBar, &QTabBar::customContextMenuRequested, + this, &BrainBrowserWindowToolBar::showTabMenu); + this->tabBar->setContextMenuPolicy(Qt::CustomContextMenu); + /* * Custom view action */ @@ -428,11 +440,18 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->addWidget(w); if (initialBrowserTabContent != NULL) { - this->addNewTabWithContent(initialBrowserTabContent); + insertTabContentPrivate(InsertTabMode::APPEND, + initialBrowserTabContent, + -1); } else { AString errorMessage; - this->createNewTab(errorMessage); + BrowserTabContent* tabContent = this->createNewTab(errorMessage); + if (tabContent != NULL) { + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); + } } this->updateToolBar(); @@ -517,7 +536,8 @@ BrainBrowserWindowToolBar::~BrainBrowserWindowToolBar() } /** - * Create a new tab. + * Create a new tab. NOTE: This method only creates + * a new tab, it DOES NOT add the tab to the toolbar. * @param errorMessage * If fails to create new tab, it will contain a message * describing the error. @@ -542,7 +562,6 @@ BrainBrowserWindowToolBar::createNewTab(AString& errorMessage) Brain* brain = GuiManager::get()->getBrain(); tabContent->getVolumeSurfaceOutlineSet()->selectSurfacesAfterSpecFileLoaded(brain, false); - this->addNewTabWithContent(tabContent); return tabContent; } @@ -554,8 +573,28 @@ BrainBrowserWindowToolBar::createNewTab(AString& errorMessage) * Tab Content that is to be cloned into the new tab. */ void -BrainBrowserWindowToolBar::addNewTabCloneContent(BrowserTabContent* browserTabContentToBeCloned) +BrainBrowserWindowToolBar::addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned) +{ + insertClonedTabContentAtTabBarIndex(browserTabContentToBeCloned, + -1); +} + +/** + * Clone and insert the cloned tab at the given index in the tab bar. + * + * @param browserTabContentToBeCloned + * Tab Content that is to be cloned into the new tab. + * @param tabBarIndex + * Index in the tab bar. If invalid, tab is appended to the end of the toolbar. + */ +void +BrainBrowserWindowToolBar::insertClonedTabContentAtTabBarIndex(const BrowserTabContent* browserTabContentToBeCloned, + const int32_t tabBarIndex) { + if ( ! allowAddingNewTab()) { + return; + } + /* * Wait cursor */ @@ -572,11 +611,22 @@ BrainBrowserWindowToolBar::addNewTabCloneContent(BrowserTabContent* browserTabCo return; } + if (tabBarIndex >= 0){ + insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, + tabContent, + tabBarIndex); + } + else { + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); + } + if (browserTabContentToBeCloned != NULL) { /* * New tab is clone of tab that was displayed when the new tab was created. */ - tabContent->cloneBrowserTabContent(browserTabContentToBeCloned); + tabContent->cloneBrowserTabContent(const_cast(browserTabContentToBeCloned)); } this->updateToolBar(); @@ -594,8 +644,9 @@ BrainBrowserWindowToolBar::addNewTabCloneContent(BrowserTabContent* browserTabCo void BrainBrowserWindowToolBar::addNewTabWithContent(BrowserTabContent* tabContent) { - addOrInsertNewTab(tabContent, - -1); + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); } /** @@ -604,6 +655,22 @@ BrainBrowserWindowToolBar::addNewTabWithContent(BrowserTabContent* tabContent) void BrainBrowserWindowToolBar::addNewTab() { + insertNewTabAtTabBarIndex(-1); +} + +/** + * Insert a new tab at the given index in the tab bar. + * + * @param tabBarIndex + * Index in the tab bar. If invalid, tab is appended to the end of the toolbar. + */ +void +BrainBrowserWindowToolBar::insertNewTabAtTabBarIndex(const int32_t tabBarIndex) +{ + if ( ! allowAddingNewTab()) { + return; + } + /* * Wait cursor */ @@ -619,7 +686,18 @@ BrainBrowserWindowToolBar::addNewTab() errorMessage); return; } - + + if (tabBarIndex >= 0){ + insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, + tabContent, + tabBarIndex); + } + else { + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); + } + this->updateToolBar(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); @@ -629,49 +707,36 @@ BrainBrowserWindowToolBar::addNewTab() /** - * Insert the tab content at the given index. - * - * @param browserTabContent - * Content of the tab. - * @param insertAtIndex - * Insert the tab at the given index in the tab bar. Must be greater than or - * equal to zero. - */ -void -BrainBrowserWindowToolBar::insertTabAtIndex(BrowserTabContent* browserTabContent, - const int32_t insertAtIndex) -{ - CaretAssert(insertAtIndex >= 0); - - addOrInsertNewTab(browserTabContent, - insertAtIndex); -} - -/** - * Add or Insert the tab content at the given index. + * Insert tab content into a tab in the toolbar. * + * @param insertTabMode + * Mode for inserting the tab. * @param browserTabContent - * Content of the tab. - * @param insertAtIndex - * If greater than or equal to zero, insert the tab at this index. - * Otherwise, use the index from the tab content or just append. + * The tab content. + * @param tabBarIndex + * Index of tab bar of where tab is inserted for mode AT_TAB_BAR_INDEX */ void -BrainBrowserWindowToolBar::addOrInsertNewTab(BrowserTabContent* browserTabContent, - const int32_t insertAtIndex) +BrainBrowserWindowToolBar::insertTabContentPrivate(const InsertTabMode insertTabMode, + BrowserTabContent* browserTabContent, + const int32_t tabBarIndex) { CaretAssert(browserTabContent); - + this->tabBar->blockSignals(true); - + int32_t newTabIndex = -1; - if (insertAtIndex >= 0) { - newTabIndex = this->tabBar->insertTab(insertAtIndex, - "NewTab"); - } - else { - const bool putTabInTabOrderFlag = false; - if (putTabInTabOrderFlag) { + + switch (insertTabMode) { + case InsertTabMode::APPEND: + newTabIndex = this->tabBar->addTab("NewTab"); + break; + case InsertTabMode::AT_TAB_BAR_INDEX: + newTabIndex = this->tabBar->insertTab(tabBarIndex, + "NewTab"); + break; + case InsertTabMode::AT_TAB_CONTENTS_INDEX: + { const int32_t tabContentIndex = browserTabContent->getTabNumber(); const int32_t numTabs = this->tabBar->count(); @@ -694,17 +759,15 @@ BrainBrowserWindowToolBar::addOrInsertNewTab(BrowserTabContent* browserTabConten } } } - else { - newTabIndex = this->tabBar->addTab("NewTab"); - } + break; } - + this->tabBar->setTabData(newTabIndex, qVariantFromValue((void*)browserTabContent)); - + const int32_t numOpenTabs = this->tabBar->count(); this->tabBar->setTabsClosable(numOpenTabs > 1); - + this->updateTabName(newTabIndex); this->tabBar->setCurrentIndex(newTabIndex); @@ -712,6 +775,78 @@ BrainBrowserWindowToolBar::addOrInsertNewTab(BrowserTabContent* browserTabConten this->tabBar->blockSignals(false); } +/** + * When adding a new tab or duplicating a tab, the tab + * may not be visible when Tile Tabs is enabled and there + * is no available space in the tile tabs configuration. + * + * @return + * True if new tab should be created, else false. + */ +bool +BrainBrowserWindowToolBar::allowAddingNewTab() +{ + static bool m_doNotShowDialogAgainFlag = false; + + if (m_doNotShowDialogAgainFlag) { + return true; + } + + BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); + CaretAssert(browserWindow); + + /* + * Is tile tabs off? + */ + if ( ! browserWindow->isTileTabsSelected()) { + return true; + } + + const TileTabsConfiguration* tileTabs = browserWindow->getSelectedTileTabsConfiguration(); + if (tileTabs == NULL) { + return true; + } + + /* + * Default configuration always shows all tabs + */ + if (tileTabs->isDefaultConfiguration()) { + return true; + } + + /* + * Is there space in the current configuration? + */ + const int32_t tileTabsCount = tileTabs->getNumberOfColumns() * tileTabs->getNumberOfRows(); + if (getNumberOfTabs() < tileTabsCount) { + return true; + } + + /* + * Selected configuration is full, all user to continue/cancel + */ + const AString doNotShowAgainMsg("Remember my choice and do not show this dialog again"); + + const AString msg("" + "Tile tabs is enabled and there is no space in the selected tile " + "tabs configuration for the new tab. If you choose to continue, " + "either the new tab will not be visible or an existing tab will " + "become invisible until the tile tabs configuration is changed." + "

" + "Do you want to create the new tab?" + "
" + ""); + + + if (WuQMessageBox::warningYesNoWithDoNotShowAgain(this, + "NewTabNotDisplayedDueToTileTabs", + msg)) { + return true; + } + + return false; +} + /** * Shows/hides the toolbar. @@ -889,7 +1024,12 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() const int32_t numberOfTabsToAdd = numberOfTabsNeeded - this->tabBar->count(); for (int32_t i = 0; i < numberOfTabsToAdd; i++) { AString errorMessage; - this->createNewTab(errorMessage); + BrowserTabContent* tabContent = this->createNewTab(errorMessage); + if (tabContent != NULL) { + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); + } } int32_t tabIndex = 0; @@ -1008,9 +1148,13 @@ BrainBrowserWindowToolBar::loadIntoTab(const int32_t tabIndexIn, if (controller != NULL) { if (tabIndex >= this->tabBar->count()) { AString errorMessage; - if (this->createNewTab(errorMessage) == NULL) { + BrowserTabContent* tabContent = this->createNewTab(errorMessage); + if (tabContent == NULL) { return -1; } + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); tabIndex = this->tabBar->count() - 1; } @@ -1252,6 +1396,59 @@ BrainBrowserWindowToolBar::closeSelectedTab() tabCloseSelected(this->tabBar->currentIndex()); } +/** + * Called when context menu requested for the tab bar. + * + * @param pos + * Postion of mouse in parent widget. + */ +void +BrainBrowserWindowToolBar::showTabMenu(const QPoint& pos) +{ + const int tabUnderMouseIndex = this->tabBar->tabAt(pos); + + if (tabUnderMouseIndex >= 0) { + const int32_t insertAtTabIndex = tabUnderMouseIndex + 1; + QMenu menu(this->tabBar); + menu.move(mapToGlobal(pos)); + QAction* addAction = menu.addAction("Add New Tab to Right"); + QAction* duplicateAction = menu.addAction("Duplicate This Tab to Right"); + menu.addSeparator(); + QAction* closeAction = menu.addAction("Close This Tab"); + closeAction->setEnabled(this->tabBar->count() > 1); + + const QAction* selectedAction = menu.exec(); + if (selectedAction == addAction) { + insertNewTabAtTabBarIndex(insertAtTabIndex); + } + else if (selectedAction == duplicateAction) { + BrowserTabContent* tabContent = getTabContentFromTab(tabUnderMouseIndex); + CaretAssert(tabContent); + insertClonedTabContentAtTabBarIndex(tabContent, + insertAtTabIndex); + } + else if (selectedAction == closeAction) { + closeSelectedTab(); + } + else if (selectedAction != NULL) { + CaretAssertMessage(0, "Has a new action been added to the menu"); + } + } + else { + QMenu menu(this->tabBar); + menu.move(mapToGlobal(pos)); + QAction* addAction = menu.addAction("Add New Tab"); + + const QAction* selectedAction = menu.exec(); + if (selectedAction == addAction) { + addNewTab(); + } + else if (selectedAction != NULL) { + CaretAssertMessage(0, "Has a new action been added to the menu"); + } + } +} + /** * Called when the selected tab is changed. * @param index @@ -1644,8 +1841,6 @@ BrainBrowserWindowToolBar::createViewWidget() this->viewModeVolumeRadioButton = new QRadioButton("Volume"); this->viewModeWholeBrainRadioButton = new QRadioButton("All"); -// this->viewModeChartOneRadioButton->setVisible(false); - QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); @@ -2445,18 +2640,12 @@ BrainBrowserWindowToolBar::createModeWidget() WuQtUtilities::matchWidgetWidths(inputModeAnnotationsToolButton, inputModeBordersToolButton, - //inputModeFociToolButton, - //inputModeImageToolButton, inputModeViewToolButton, inputModeVolumeEditButton); -// inputModeFociToolButton->setContentsMargins(0, 0, 0, 0); -// inputModeImageToolButton->setContentsMargins(0, 0, 0, 0); inputModeFociToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeFociToolButton->sizePolicy().verticalPolicy()); inputModeImageToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeImageToolButton->sizePolicy().verticalPolicy()); -// inputModeFociToolButton->setFixedWidth(inputModeFociToolButton->sizeHint().width()); -// inputModeImageToolButton->setFixedWidth(inputModeImageToolButton->sizeHint().width()); /* * Layout for input modes @@ -3870,10 +4059,15 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) case EventBrowserWindowCreateTabs::MODE_LOADED_DATA_FILE: if (tabBar->count() == 0) { AString errorMessage; - createNewTab(errorMessage); + BrowserTabContent* tabContent = createNewTab(errorMessage); if (errorMessage.isEmpty() == false) { CaretLogSevere(errorMessage); } + if (tabContent != NULL) { + insertTabContentPrivate(InsertTabMode::APPEND, + tabContent, + -1); + } } break; case EventBrowserWindowCreateTabs::MODE_LOADED_SPEC_FILE: @@ -3925,11 +4119,6 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) else { } - -// CaretLogFinest("Toolbar width/height: " -// + AString::number(width()) -// + "/" -// + AString::number(height())); } /** @@ -4135,8 +4324,10 @@ BrainBrowserWindowToolBar::restoreFromScene(const SceneAttributes* sceneAttribut if (tabContent->getTabNumber() == selectedTabIndex) { defaultTabBarIndex = iTab; } - this->insertTabAtIndex(tabContent, - iTab); + CaretAssert(iTab >= 0); + insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, + tabContent, + iTab); } else { sceneAttributes->addToErrorMessage("Toolbar in window " diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index a87432c7c..e310cd2c2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -93,7 +93,7 @@ namespace caret { void addNewTab(); - void addNewTabCloneContent(BrowserTabContent* browserTabContentToBeCloned); + void addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned); void addNewTabWithContent(BrowserTabContent* browserTabContent); @@ -257,17 +257,28 @@ namespace caret { void selectedTabChanged(int indx); void tabMoved(int, int); void tabCloseSelected(int); + void showTabMenu(const QPoint& pos); private: - void insertTabAtIndex(BrowserTabContent* browserTabContent, - const int32_t insertAtIndex); + enum class InsertTabMode { + APPEND, + AT_TAB_BAR_INDEX, + AT_TAB_CONTENTS_INDEX + }; + + bool allowAddingNewTab(); - void addOrInsertNewTab(BrowserTabContent* browserTabContent, - const int32_t insertAtIndex); + void insertTabContentPrivate(const InsertTabMode insertTabMode, + BrowserTabContent* browserTabContent, + const int32_t tabBarIndex); void removeTab(int index); void tabClosed(int index); + void insertNewTabAtTabBarIndex(int32_t tabBarIndex); + void insertClonedTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, + const int32_t tabBarIndex); + BrowserTabContent* createNewTab(AString& errorMessage); QRadioButton* viewModeSurfaceRadioButton; @@ -434,6 +445,8 @@ namespace caret { * Tracks when update is performed to catch incorrectly emitted signals. */ bool m_performingUpdateFlag = false; + + const int32_t TAB_INDEX_APPEND_TO_TOOLBAR = 10000; }; } -- GitLab From 96e715566df241421d190d80d9cfc111b2ed9a13 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 21 Sep 2017 15:38:39 -0500 Subject: [PATCH 405/755] Added support for using GLEW on Windows. At this time wb_view compiles and runs. wb_command compiles but fails when linking. --- src/Brain/BrainOpenGL.cxx | 7 ++++++ src/Brain/CMakeLists.txt | 2 ++ src/CMakeLists.txt | 30 ++++++++++++++++++++++ src/CommandLine/CMakeLists.txt | 5 ++-- src/Desktop/CMakeLists.txt | 1 + src/Desktop/desktop.cxx | 31 +++++++++++++++++++++++ src/Graphics/CaretOpenGLInclude.h | 37 +++++++++++++++++++++++----- src/GuiQt/BrainOpenGLWidget.cxx | 8 +++--- src/GuiQt/BrainOpenGLWidget.h | 5 ++++ src/GuiQt/FiberSamplesOpenGLWidget.h | 7 ++++++ src/GuiQt/QGLWidgetTextRenderer.cxx | 7 ++++++ src/Tests/CMakeLists.txt | 2 ++ 12 files changed, 130 insertions(+), 12 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 30c192bf7..e0d91a714 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -967,6 +967,13 @@ BrainOpenGL::getOpenGLInformation() + "\nOpenGL Vendor: " + AString(vendorStr) + "\nOpenGL Renderer: " + AString(renderStr)); + AString glewVersionName("No GLEW in this version of Workbench"); +#ifdef HAVE_GLEW + glewVersionName = AString(reinterpret_cast(glewGetString(GLEW_VERSION))); +#endif /* HAVE_GLEW */ + lineInfo += "\n"; + lineInfo += ("\nGLEW Version: " + glewVersionName); + lineInfo += "\n"; lineInfo += ("\nFont Renderer: " + m_textRenderer->getName()); lineInfo += "\n"; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index ee1f469c8..2faa09e9d 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -42,6 +42,8 @@ IF (OPENGL_FOUND) # OpenGL Include Directory # INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) + MESSAGE("OpenGL Include Directory: ${OPENGL_INCLUDE_DIR}") + MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") ELSE (OPENGL_FOUND) MESSAGE(SEND_ERROR "OpenGL Libraries were not found") ENDIF (OPENGL_FOUND) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32fb803e6..2511db7ce 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -244,6 +244,35 @@ ELSE (Qwt_FOUND) SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) +########################################################################################## +# +# Look for GLEW +# +SET(GLEW_RESULT "No") +FIND_PACKAGE(GLEW) + +IF (GLEW_FOUND) + SET(GLEW_RESULT "${GLEW_INCLUDE_DIRS} ${GLEW_LIBRARIES}") + MESSAGE("GLEW Include Dirs: ${GLEW_INCLUDE_DIRS}") + MESSAGE("GLEW Libraries: ${GLEW_LIBRARIES}") + STRING(FIND ${GLEW_LIBRARIES} "glew32s.lib" GLEW_STATIC_LIB_NAME_INDEX) + ADD_DEFINITIONS(-DHAVE_GLEW) + IF (GLEW_STATIC_LIB_NAME_INDEX GREATER -1) + ADD_DEFINITIONS(-DHAVE_GLEW_STATIC_LIB) + MESSAGE("GLEW Static Library Found") + ENDIF() + INCLUDE_DIRECTORIES(${GLEW_INCLUDE_DIRS}) +ELSE() + SET(GLEW_LIBRARIES "") + SET(GLEW_INCLUDE_DIRS "") + IF (WIN32) + MESSAGE(SEND_ERROR "GLEW not found and is required on Windows for finding OpenGL functions.\n" + " Setting CMAKE_PREFIX_PATH to the GLEW installation directory when\n" + " running CMAKE may help find GLEW.\n" + " -DCMAKE_PREFIX_PATH=C:\some-path\glew-2.1.0") + ENDIF() +ENDIF() + ########################################################################################## # # The Find OpenMP package may not work on all systems and the user may @@ -527,6 +556,7 @@ IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) MESSAGE(${MSG_MODE} "PACKAGES:") MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLEW: " ${GLEW_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index 75a7126ca..dbc50c4ec 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -70,8 +70,8 @@ endif() # # Libraries that are linked -# Note: OSMESA library variables will be empty and have no effect -# if OSMESA is not available +# Note: GLEW_LIBRARIES and OSMESA library variables will be empty and +# have no effect if not available # TARGET_LINK_LIBRARIES(${EXE_NAME} Commands @@ -96,6 +96,7 @@ ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} ${QT5_LINK_LIBS} +${GLEW_LIBRARIES} ${OSMESA_OFFSCREEN_LIBRARY} ${OSMESA_GL_LIBRARY} ${OSMESA_GLU_LIBRARY} diff --git a/src/Desktop/CMakeLists.txt b/src/Desktop/CMakeLists.txt index f28af31be..e7ed93ad9 100644 --- a/src/Desktop/CMakeLists.txt +++ b/src/Desktop/CMakeLists.txt @@ -138,6 +138,7 @@ FilesBase Scenes Xml Common +${GLEW_LIBRARIES} ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index 4d7ff5c8b..a15b22251 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -18,6 +18,12 @@ */ /*LICENSE_END*/ +/* + * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". + * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by + * some Qt classes so, we must include CaretOpenGL.h first. + */ +#include "CaretOpenGLInclude.h" #include #include @@ -497,6 +503,31 @@ main(int argc, char* argv[]) return -1; } + /* + * Initialize GLEW if it is being used + */ + AString glewErrorMessage; +#ifdef HAVE_GLEW + GLenum err = glewInit(); + if (GLEW_OK != err) { + /* Problem: glewInit failed, something is seriously wrong. */ + + glewErrorMessage = ("GLEW failed to initialize.\n" + + AString(reinterpret_cast(glewGetErrorString(err)))); + CaretLogSevere(glewErrorMessage); + } + CaretLogInfo("Status: Using GLEW version " + + AString(reinterpret_cast(glewGetString(GLEW_VERSION)))); +#endif /* HAVE_GLEW */ + if ( ! glewErrorMessage.isEmpty()) { + app.processEvents(); + WuQMessageBox::errorOk(NULL, + glewErrorMessage); + app.processEvents(); + + return -1; + } + if ((myState.windowSizeXY[0] > 0) && (myState.windowSizeXY[1] > 0)) { if (myState.windowPosXY[0] > 0 && myState.windowPosXY[1] > 0) diff --git a/src/Graphics/CaretOpenGLInclude.h b/src/Graphics/CaretOpenGLInclude.h index d90329cdb..4a35db9f2 100644 --- a/src/Graphics/CaretOpenGLInclude.h +++ b/src/Graphics/CaretOpenGLInclude.h @@ -27,16 +27,41 @@ * \ingroup Brain */ +/* + * When using GLEW, GL/glew.h MUST be included before Gl/gl.h. + * Note: Windows.h includes Gl/gl.h. + * + * Must define GLEW_STATIC when GLEW is in a static library + * or linking errors will occur with GLEW functions + */ +#ifdef HAVE_GLEW + #ifdef HAVE_GLEW_STATIC_LIB + #define GLEW_STATIC + #endif + + #include +#endif + #ifdef CARET_OS_WINDOWS -#include + #include #endif + #ifdef CARET_OS_MACOSX -#include -#include + #include + #include #else -#define GL_GLEXT_PROTOTYPES -#include -#include + #ifndef HAVE_GLEW + #ifdef CARET_OS_LINUX + /* + * On linux, adds support for newer OpenGL + * as described at https://www.khronos.org/registry/OpenGL/ABI/ + */ + #define GL_GLEXT_PROTOTYPES + #endif + #endif + + #include + #include #endif #endif //__CARET_OPEN_GL_INCLUDE_H__ diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index af2ee9b1c..4bf2a35c5 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -18,6 +18,10 @@ */ /*LICENSE_END*/ +#define __BRAIN_OPENGL_WIDGET_DEFINE__ +#include "BrainOpenGLWidget.h" +#undef __BRAIN_OPENGL_WIDGET_DEFINE__ + #include #include @@ -30,10 +34,6 @@ #include #include -#define __BRAIN_OPENGL_WIDGET_DEFINE__ -#include "BrainOpenGLWidget.h" -#undef __BRAIN_OPENGL_WIDGET_DEFINE__ - #include "Border.h" #include "Brain.h" #include "BrainBrowserWindow.h" diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 2c9c8a39e..bf16ed3f1 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -24,6 +24,11 @@ #include +/* + * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". + * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by + * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. + */ #include "CaretOpenGLInclude.h" #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET diff --git a/src/GuiQt/FiberSamplesOpenGLWidget.h b/src/GuiQt/FiberSamplesOpenGLWidget.h index 51e880465..84c0b8641 100644 --- a/src/GuiQt/FiberSamplesOpenGLWidget.h +++ b/src/GuiQt/FiberSamplesOpenGLWidget.h @@ -21,6 +21,13 @@ */ /*LICENSE_END*/ +/* + * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". + * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by + * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. + */ +#include "CaretOpenGLInclude.h" + #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else diff --git a/src/GuiQt/QGLWidgetTextRenderer.cxx b/src/GuiQt/QGLWidgetTextRenderer.cxx index 1cc6a2959..0afbab00f 100644 --- a/src/GuiQt/QGLWidgetTextRenderer.cxx +++ b/src/GuiQt/QGLWidgetTextRenderer.cxx @@ -29,6 +29,13 @@ #include "QGLWidgetTextRenderer.h" #undef __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ +/* + * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". + * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by + * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. + */ +#include "CaretOpenGLInclude.h" + #include #include diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index da2e4d97d..38e051e5f 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -117,6 +117,7 @@ Xml Common ${QT5_LINK_LIBS} ${QT_LIBRARIES} +${GLEW_LIBRARIES} ${OSMESA_OFFSCREEN_LIBRARY} ${OSMESA_GL_LIBRARY} ${OSMESA_GLU_LIBRARY} @@ -126,6 +127,7 @@ ${ZLIB_LIBRARIES} IF(WIN32) TARGET_LINK_LIBRARIES(test_driver + ${GLEW_LIBRARIES} opengl32 glu32 ) -- GitLab From 8faba604d1f00c245292eb51dd0341dc15b7d132 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Sep 2017 10:14:08 -0500 Subject: [PATCH 406/755] Added a warning dialog to WuQMessageBox that accepts text for the accept and reject buttons. --- src/GuiQt/WuQMessageBox.cxx | 55 +++++++++++++++++++++++++++++++++++++ src/GuiQt/WuQMessageBox.h | 6 ++++ 2 files changed, 61 insertions(+) diff --git a/src/GuiQt/WuQMessageBox.cxx b/src/GuiQt/WuQMessageBox.cxx index 7d8b6e7c6..e69890356 100644 --- a/src/GuiQt/WuQMessageBox.cxx +++ b/src/GuiQt/WuQMessageBox.cxx @@ -582,6 +582,61 @@ WuQMessageBox::warningYesToAllYesNo(QWidget* parent, return result; } +/** + * Display a warning message box with the given + * text and content for accept/reject buttons. + * Pressing the enter key is the equivalent of + * pressing the Ok button. + * + * @param parent + * Parent on which message box is displayed. + * @param text + * Message that is displayed. + * @param acceptButtonText + * Text for "accept" button. + * @param rejectButtonText + * Text for "reject" button. + * @return + * true if the "accept" button was pressed or false + * if the "reject" button was pressed. + */ +bool +WuQMessageBox::warningAcceptReject(QWidget* parent, + const QString& text, + const QString& acceptButtonText, + const QString& rejectButtonText) +{ + QMessageBox msgBox(parent); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(""); + msgBox.setText(text); + msgBox.addButton(QMessageBox::Ok); + msgBox.addButton(QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setEscapeButton(QMessageBox::Cancel); + + updateButtonText(msgBox, QMessageBox::Ok, acceptButtonText); + updateButtonText(msgBox, QMessageBox::Cancel, rejectButtonText); + + QMessageBox::StandardButton buttonPressed = + static_cast(msgBox.exec()); + + bool acceptPressed = false; + + switch (buttonPressed) { + case QMessageBox::Ok: + acceptPressed = true; + break; + case QMessageBox::Cancel: + break; + default: + CaretAssert(0); + break; + } + + return acceptPressed; +} + /** * Update the text for the standard button in the given message box. * diff --git a/src/GuiQt/WuQMessageBox.h b/src/GuiQt/WuQMessageBox.h index a433ef317..2db2364c0 100644 --- a/src/GuiQt/WuQMessageBox.h +++ b/src/GuiQt/WuQMessageBox.h @@ -100,6 +100,12 @@ namespace caret { const QString& noButtonText, const QString& text, const QString& informativeText); + static bool warningAcceptReject(QWidget* parent, + const QString& text, + const QString& acceptButtonText, + const QString& rejectButtonText); + + private: WuQMessageBox(QWidget* parent = 0); ~WuQMessageBox(); -- GitLab From 9ce08c5bb40f0521ed9ae32aadd4aba083edad13 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Sep 2017 10:15:44 -0500 Subject: [PATCH 407/755] Removed duplicated logic for finding OpenGL in the CMakeLists.txt files in the Brain, FtglFont, and Graphics directories. Finding OpenGL was moved to the src/CMakeLists.txt file. --- src/Brain/CMakeLists.txt | 27 --------------------------- src/CMakeLists.txt | 26 ++++++++++++++++++++++++++ src/FtglFont/CMakeLists.txt | 26 -------------------------- src/Graphics/CMakeLists.txt | 25 ------------------------- 4 files changed, 26 insertions(+), 78 deletions(-) diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 2faa09e9d..56758b471 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -21,33 +21,6 @@ IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () -# -# Need OpenGL -# -FIND_PACKAGE(OpenGL REQUIRED) -IF (OPENGL_FOUND) - # - # Need help finding includes on Apple - # - IF (APPLE) - # When searching for the include directory, find the location - # for the OpenGL framework rather than an individual header file. - FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework - /System/Library/Frameworks - /Library/Frameworks - ~/Library/Frameworks - ) - ENDIF (APPLE) - # - # OpenGL Include Directory - # - INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) - MESSAGE("OpenGL Include Directory: ${OPENGL_INCLUDE_DIR}") - MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") -ELSE (OPENGL_FOUND) - MESSAGE(SEND_ERROR "OpenGL Libraries were not found") -ENDIF (OPENGL_FOUND) - # # Create the brain library # diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2511db7ce..9724b04b2 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -244,6 +244,32 @@ ELSE (Qwt_FOUND) SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) +# +# Need OpenGL +# +FIND_PACKAGE(OpenGL REQUIRED) +IF (OPENGL_FOUND) + # + # Need help finding includes on Apple + # + IF (APPLE) + # When searching for the include directory, find the location + # for the OpenGL framework rather than an individual header file. + FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework + /System/Library/Frameworks + /Library/Frameworks + ~/Library/Frameworks) + ENDIF (APPLE) + # + # OpenGL Include Directory + # + INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) + MESSAGE("OpenGL Include Directory: ${OPENGL_INCLUDE_DIR}") + MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") +ELSE (OPENGL_FOUND) + MESSAGE(SEND_ERROR "OpenGL Libraries were not found") +ENDIF (OPENGL_FOUND) + ########################################################################################## # # Look for GLEW diff --git a/src/FtglFont/CMakeLists.txt b/src/FtglFont/CMakeLists.txt index e6dad49fd..2ab7ff102 100644 --- a/src/FtglFont/CMakeLists.txt +++ b/src/FtglFont/CMakeLists.txt @@ -11,32 +11,6 @@ IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () - -# -# Need OpenGL -# -FIND_PACKAGE(OpenGL REQUIRED) -IF (OPENGL_FOUND) - # - # Need help finding includes on Apple - # - IF (APPLE) - # When searching for the include directory, find the location - # for the OpenGL framework rather than an individual header file. - FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework - /System/Library/Frameworks - /Library/Frameworks - ~/Library/Frameworks - ) - ENDIF (APPLE) - # - # OpenGL Include Directory - # - INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) -ELSE (OPENGL_FOUND) - MESSAGE(SEND_ERROR "OpenGL Libraries were not found") -ENDIF (OPENGL_FOUND) - # # Create the brain library # diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index aad89faa0..ff1474e8e 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -3,31 +3,6 @@ # PROJECT (Graphics) -# -# Need OpenGL -# -FIND_PACKAGE(OpenGL REQUIRED) -IF (OPENGL_FOUND) - # - # Need help finding includes on Apple - # - IF (APPLE) - # When searching for the include directory, find the location - # for the OpenGL framework rather than an individual header file. - FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework - /System/Library/Frameworks - /Library/Frameworks - ~/Library/Frameworks - ) - ENDIF (APPLE) - # - # OpenGL Include Directory - # - INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) -ELSE (OPENGL_FOUND) - MESSAGE(SEND_ERROR "OpenGL Libraries were not found") -ENDIF (OPENGL_FOUND) - # # Create a Library # -- GitLab From 19184be88920c1ef1b630ab0eed923c17252074d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Sep 2017 10:18:43 -0500 Subject: [PATCH 408/755] If wb_view is launched and the version of OpenGL is less than 1.5, display a warning that wb_view may crash. --- src/Brain/BrainOpenGL.cxx | 36 ++++++++++++++++++++++++++++++++++++ src/Brain/BrainOpenGL.h | 4 ++++ src/Desktop/desktop.cxx | 16 ++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index e0d91a714..b9bd7682e 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -551,6 +551,42 @@ BrainOpenGL::testForVersionOfOpenGLSupported(const AString& versionOfOpenGL) return false; } +/** + * Test for the required version of OpenGL Workbench needs. + * + * @param errorMessageOut + * Output with error message if required version is not available. + * @return + * True if required version available, else false. + */ +bool +BrainOpenGL::testForRequiredOpenGLVersion(AString& errorMessageOut) +{ + const AString minimumOpenGLVersion("1.5"); + if ( ! BrainOpenGL::testForVersionOfOpenGLSupported(minimumOpenGLVersion)) { + const AString msg("OpenGL Version " + + minimumOpenGLVersion + + " or later is required. This computer has version " + + BrainOpenGL::getOpenGLVersion() + + "\nYou may continue but the software may crash."); + errorMessageOut = msg; + return false; + } + + return true; +} + + +/** + * @return The OpenGL version. + */ +AString +BrainOpenGL::getOpenGLVersion() +{ + return QLatin1String(reinterpret_cast(glGetString(GL_VERSION))); +} + + /** * Extract the major and minor versions from an OpenGL version string. * @param versionString diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 52b80e412..3df77103b 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -143,8 +143,12 @@ namespace caret { static void getMinMaxLineWidth(float& minLineWidthOut, float& maxLineWidthOut); + static bool testForRequiredOpenGLVersion(AString& errorMessageOut); + static bool testForVersionOfOpenGLSupported(const AString& versionOfOpenGL); + static AString getOpenGLVersion(); + static void testForOpenGLError(const AString& message); static void testForOpenGLError(const AString& message, diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index a15b22251..d94ae3dbe 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -41,6 +41,7 @@ #include "ApplicationInformation.h" #include "BrainBrowserWindow.h" +#include "BrainOpenGL.h" #include "BrainOpenGLWidget.h" #include "CaretAssert.h" #include "CaretCommandLine.h" @@ -396,6 +397,7 @@ main(int argc, char* argv[]) * Log debug status */ CaretLogConfig(applicationInformation.getCompiledWithDebugStatus()); + /* * Enabled the desired splash screen based upon user preferences @@ -503,6 +505,20 @@ main(int argc, char* argv[]) return -1; } + /** + * Test for the required OpenGL version is available. + */ + AString requiredOpenGLMessage; + if ( ! BrainOpenGL::testForRequiredOpenGLVersion(requiredOpenGLMessage)) { + app.processEvents(); + if ( ! WuQMessageBox::warningAcceptReject(NULL, + requiredOpenGLMessage, + "Continue", + "Exit")) { + return -1; + } + } + /* * Initialize GLEW if it is being used */ -- GitLab From 6b6cd08b585b3612372d8d9709a46ecc81941bc9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 25 Sep 2017 11:36:05 -0500 Subject: [PATCH 409/755] Resolve WB-699: Added GLEW to the Windows build system. This allows wb_view to use OpenGL functions after OpenGL 1.1. While attempts were made to build Mesa OpenGL for wb_command's "-show-scene" command, building Mesa OpenGL was not successful. Building Mesa on Windows requires "scons", python, some sort of bison, and the instructions are not clear. For wb_view on all operating system, warn the user that wb_view may crash if OpenGL is less than version 1.5 but allow the user to continue. --- src/CMakeLists.txt | 10 +++++++--- src/CommandLine/CMakeLists.txt | 16 +++++++++++++--- src/Operations/OperationShowScene.cxx | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9724b04b2..c23f6e7ac 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -244,9 +244,11 @@ ELSE (Qwt_FOUND) SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) +########################################################################################## # # Need OpenGL # +SET(OPENGL_RESULT "") FIND_PACKAGE(OpenGL REQUIRED) IF (OPENGL_FOUND) # @@ -266,6 +268,7 @@ IF (OPENGL_FOUND) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) MESSAGE("OpenGL Include Directory: ${OPENGL_INCLUDE_DIR}") MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") + SET(OPENGL_RESULT ${OPENGL_LIBRARIES}) ELSE (OPENGL_FOUND) MESSAGE(SEND_ERROR "OpenGL Libraries were not found") ENDIF (OPENGL_FOUND) @@ -464,13 +467,13 @@ SET(OSMESA_RESULT "Not found") IF (EXISTS ${WORKBENCH_MESA_DIR}) IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) FIND_LIBRARY(OSMESA_LIBRARY_FOUND - NAMES OSMesa + NAMES OSMesa OSMESA32 HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GL_LIBRARY_FOUND - NAMES GL + NAMES GL OPENGL32 HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GLU_LIBRARY_FOUND - NAMES GLU + NAMES GLU GLU32 HINTS ${WORKBENCH_MESA_DIR}/lib) IF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_DEFINITION -DHAVE_OSMESA) @@ -583,6 +586,7 @@ IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLEW: " ${GLEW_RESULT}) + MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenGL: " ${OPENGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index dbc50c4ec..dc7e05b6b 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -97,12 +97,22 @@ ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} ${QT5_LINK_LIBS} ${GLEW_LIBRARIES} -${OSMESA_OFFSCREEN_LIBRARY} -${OSMESA_GL_LIBRARY} -${OSMESA_GLU_LIBRARY} ${ZLIB_LIBRARIES} ${LIBS}) +IF (WIN32) + IF (HAVE_OSMESA) + TARGET_LINK_LIBRARIES(${EXE_NAME} + ${OSMESA_OFFSCREEN_LIBRARY} + ${OSMESA_GL_LIBRARY} + ${OSMESA_GLU_LIBRARY}) + ELSE() + TARGET_LINK_LIBRARIES(${EXE_NAME} + opengl32 + glu32) + ENDIF() +ENDIF() + INCLUDE(GNUInstallDirs) INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 0cf4ab365..4a61c9863 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -22,6 +22,10 @@ #include #include +#ifdef HAVE_GLEW +#include +#endif + #ifdef HAVE_OSMESA #include #endif // HAVE_OSMESA -- GitLab From e01592d26456c442f1214845cd81420863ecd803 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 25 Sep 2017 14:15:16 -0500 Subject: [PATCH 410/755] Fixed configuration and compiling issues found on Linux systems from recent update WB-699: Added GLEW to the Windows build system. --- src/CommandLine/CMakeLists.txt | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/CommandLine/CMakeLists.txt b/src/CommandLine/CMakeLists.txt index dc7e05b6b..2dd29f634 100644 --- a/src/CommandLine/CMakeLists.txt +++ b/src/CommandLine/CMakeLists.txt @@ -68,6 +68,20 @@ if(Qt5_FOUND) Qt5::Xml) endif() +SET (MESA_OR_OPENGL_LIBRARIES "") +IF (OSMESA_FOUND) + SET(MESA_OR_OPENGL_LIBRARIES + ${OSMESA_OFFSCREEN_LIBRARY} + ${OSMESA_GL_LIBRARY} + ${OSMESA_GLU_LIBRARY}) +ELSE() + IF (OPENGL_FOUND) + SET(MESA_OR_OPENGL_LIBRARIES ${OPENGL_LIBRARIES}) + ELSE() + MESSAGE(SEND_ERROR "Must have either OpenGL or Mesa3D for command line") + ENDIF() +ENDIF() + # # Libraries that are linked # Note: GLEW_LIBRARIES and OSMESA library variables will be empty and @@ -97,22 +111,10 @@ ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} ${QT5_LINK_LIBS} ${GLEW_LIBRARIES} +${MESA_OR_OPENGL_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBS}) -IF (WIN32) - IF (HAVE_OSMESA) - TARGET_LINK_LIBRARIES(${EXE_NAME} - ${OSMESA_OFFSCREEN_LIBRARY} - ${OSMESA_GL_LIBRARY} - ${OSMESA_GLU_LIBRARY}) - ELSE() - TARGET_LINK_LIBRARIES(${EXE_NAME} - opengl32 - glu32) - ENDIF() -ENDIF() - INCLUDE(GNUInstallDirs) INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) -- GitLab From d4e53f1aeea175147040019c5e318283a85cadd4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 26 Sep 2017 09:43:05 -0500 Subject: [PATCH 411/755] Resolve WB-745 Incorrect warning message on upload to BALSA dialog and most of WB-749 Workbench BALSA Updates (except for items requiring communication with BALSA). --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 139 ++---------------- .../BalsaDatabaseUploadSceneFileDialog.h | 15 -- src/GuiQt/BalsaStudySelectionDialog.cxx | 41 +++++- src/GuiQt/BalsaStudySelectionDialog.h | 5 + 4 files changed, 59 insertions(+), 141 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 1e47e5b73..2684ad7e5 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -81,14 +81,6 @@ m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); - /* - * Icons - */ - m_lockClosedIconValid = WuQtUtilities::loadIcon(":/BalsaUploadDialog/lock-closed.png", - m_lockClosedIcon); - m_lockOpenIconValid = WuQtUtilities::loadIcon(":/BalsaUploadDialog/lock-open.png", - m_lockOpenIcon); - QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(createUploadTab(), "Upload"); tabWidget->addTab(createAdvancedTab(), "Advanced"); @@ -96,7 +88,6 @@ m_sceneFile(sceneFile) setCentralWidget(tabWidget, WuQDialogModal::SCROLL_AREA_NEVER); - updateBalsaStudyIDLockButtonIcon(); validateData(); setSizePolicy(sizePolicy().horizontalPolicy(), @@ -213,33 +204,10 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyIDLineEdit->setReadOnly(true); m_balsaStudyIDLineEdit->setToolTip("The Study ID is available from the BALSA Database; click the Get button to get a Study ID"); m_balsaStudyIDLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_ID)); + m_balsaStudyIDLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyIDLineEdit, &QLineEdit::textEdited, this, [=] { this->validateData(); }); - /* - * Get BALSA Study ID button - */ - const bool showGetStudyIdButtonFlag = false; - m_getBalsaStudyIDPushButton = NULL; - if (showGetStudyIdButtonFlag) { - m_getBalsaStudyIDPushButton = new QPushButton("Get..."); - m_getBalsaStudyIDPushButton->setToolTip("Get the BALSA Study ID by sending Study Title to BALSA"); - QObject::connect(m_getBalsaStudyIDPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked); - } - - /* - * BALSA Study ID Lock button - */ - m_balsaStudyIDLockPushButton = new QPushButton("Lock"); - m_balsaStudyIDLockPushButton->setToolTip("Unlock to allow manual editing of the Study ID."); - QObject::connect(m_balsaStudyIDLockPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::balsaStudyIDLockPushButtonClicked); - if (m_lockClosedIconValid - && m_lockOpenIconValid) { - m_balsaStudyIDLockPushButton->setText(""); - } - /* * Scene BALSA Study Title */ @@ -247,14 +215,15 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyTitleLineEdit = new QLineEdit(); m_balsaStudyTitleLineEdit->setToolTip("Title for the study"); m_balsaStudyTitleLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_TITLE)); + m_balsaStudyTitleLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyTitleLineEdit, &QLineEdit::textEdited, this, [=] { this->validateData(); }); /** * Select Study Push Button */ - m_selectStudyTitlePushButton = new QPushButton("Add/Choose..."); - m_selectStudyTitlePushButton->setToolTip("Add new study or choose from user's studies in BALSA Database"); + m_selectStudyTitlePushButton = new QPushButton("Add/Choose/Rename..."); + m_selectStudyTitlePushButton->setToolTip("Add new study, choose a study, or edit a study's title in BALSA Database"); QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); @@ -324,11 +293,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(m_balsaStudyIDLockPushButton, row, COLUMN_BUTTON_ONE); - if (m_getBalsaStudyIDPushButton != NULL) { - gridLayout->addWidget(m_getBalsaStudyIDPushButton, row, COLUMN_BUTTON_TWO); - } - m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); @@ -504,13 +468,17 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() if ( ! m_baseDirectoryLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Base Directory is invalid.

"); } + bool invalidStudyFlag = false; if ( ! m_balsaStudyTitleLineEdit->hasAcceptableInput()) { - msg.appendWithNewLine("Study Title is invalid.

"); + invalidStudyFlag = true; } if ( ! m_balsaStudyIDLineEdit->hasAcceptableInput()) { - msg.appendWithNewLine("Study ID is invalid. To get a Study ID, press the \"Get\" button which " - "sends the Study Title to the Database and returns a Study ID. You may " - "also go to https://balsa.wustl.edu to get a Study ID

"); + invalidStudyFlag = true; + } + if (invalidStudyFlag) { + msg.appendWithNewLine("Study ID and/or Title is invalid. Press the \"" + + m_selectStudyTitlePushButton->text() + + "\" button to choose or create a BALSA Study ID and Title."); } if ( ! msg.isEmpty()) { @@ -528,7 +496,7 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() if (m_sceneFile->isModified()) { const QString msg("The scene file is modified and must be saved before continuing. Would you like " "to save the scene file using its current name and continue?"); - if (WuQMessageBox::warningYesNo(this, msg)) { + if (WuQMessageBox::warningOkCancel(this, msg)) { try { Brain* brain = GuiManager::get()->getBrain(); brain->writeDataFile(m_sceneFile); @@ -626,82 +594,6 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() } } -/** - * Update the Icon in the BALSA Study ID Lock Button - */ -void -BalsaDatabaseUploadSceneFileDialog::updateBalsaStudyIDLockButtonIcon() -{ - - if (m_lockClosedIconValid - && m_lockOpenIconValid) { - if (m_balsaStudyIDLineEdit->isReadOnly()) { - m_balsaStudyIDLockPushButton->setIcon(m_lockClosedIcon); - } - else { - m_balsaStudyIDLockPushButton->setIcon(m_lockOpenIcon); - } - } -} - -/** - * Called when BALSA Study ID Lock Button is clicked - */ -void -BalsaDatabaseUploadSceneFileDialog::balsaStudyIDLockPushButtonClicked() -{ - /* - * Toggle the 'read only' status of the Study ID's Line Edit - */ - m_balsaStudyIDLineEdit->setReadOnly( ! m_balsaStudyIDLineEdit->isReadOnly()); - - updateBalsaStudyIDLockButtonIcon(); -} - - -/** - * Called when get BALSA study ID push button is clicked. - */ -void -BalsaDatabaseUploadSceneFileDialog::getBalsaStudyIDPushButtonClicked() -{ - CaretAssert(m_getBalsaStudyIDPushButton); - - const AString title = m_balsaStudyTitleLineEdit->text().trimmed(); - if (title.isEmpty()) { - WuQMessageBox::errorOk(m_getBalsaStudyIDPushButton, - "The Study Title is required to get a Study ID"); - return; - } - - CursorDisplayScoped cursor; - cursor.showWaitCursor(); - - const AString username = m_usernameLineEdit->text().trimmed(); - const AString password = m_passwordLineEdit->text().trimmed(); - - AString studyID; - AString errorMessage; - CaretPointer balsaDatabaseManager(new BalsaDatabaseManager()); - const bool successFlag = balsaDatabaseManager->getStudyIDFromStudyTitle(getDataBaseURL(), - username, - password, - title, - studyID, - errorMessage); - - cursor.restoreCursor(); - - if (successFlag) { - m_balsaStudyIDLineEdit->setText(studyID); - validateData(); - } - else { - WuQMessageBox::errorOk(this, - errorMessage); - } -} - /** * Choose the custom directory */ @@ -830,9 +722,8 @@ void BalsaDatabaseUploadSceneFileDialog::validateData() { updateAllLabels(); - if (m_getBalsaStudyIDPushButton != NULL) { - m_getBalsaStudyIDPushButton->setEnabled(m_balsaStudyTitleLineEdit->hasAcceptableInput()); - } + m_selectStudyTitlePushButton->setEnabled(m_usernameLineEdit->hasAcceptableInput() + && (m_passwordLineEdit->hasAcceptableInput())); } /** diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index c032ab173..7a319a9b0 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -56,10 +56,6 @@ namespace caret { void browseBaseDirectoryPushButtonClicked(); - void getBalsaStudyIDPushButtonClicked(); - - void balsaStudyIDLockPushButtonClicked(); - void validateData(); void selectStudyTitleButtonClicked(); @@ -96,8 +92,6 @@ namespace caret { AString getDataBaseURL() const; - void updateBalsaStudyIDLockButtonIcon(); - QRegularExpressionValidator* createValidator(const LabelName labelName); AString getZipFileNameWithPath(AString& errorMessageOut) const; @@ -126,9 +120,6 @@ namespace caret { QLabel* m_extractDirectoryNameLabel; QLineEdit* m_extractDirectoryNameLineEdit; - QPushButton* m_getBalsaStudyIDPushButton; - QPushButton* m_balsaStudyIDLockPushButton; - QLabel* m_balsaStudyIDLabel; QLineEdit* m_balsaStudyIDLineEdit; @@ -142,12 +133,6 @@ namespace caret { QLabel* m_baseDirectoryLabel; QLineEdit* m_baseDirectoryLineEdit; - QIcon m_lockClosedIcon; - bool m_lockClosedIconValid = false; - - QIcon m_lockOpenIcon; - bool m_lockOpenIconValid = false; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BalsaStudySelectionDialog.cxx b/src/GuiQt/BalsaStudySelectionDialog.cxx index 1e0bc4ce7..e8f12582a 100644 --- a/src/GuiQt/BalsaStudySelectionDialog.cxx +++ b/src/GuiQt/BalsaStudySelectionDialog.cxx @@ -83,14 +83,25 @@ m_balsaPassword(balsaPassword) QPushButton* newStudyTitlePushButton = new QPushButton("Create New Study..."); newStudyTitlePushButton->setSizePolicy(QSizePolicy::Fixed, newStudyTitlePushButton->sizePolicy().verticalPolicy()); - QObject::connect(newStudyTitlePushButton, &QPushButton::clicked, this, &BalsaStudySelectionDialog::newStudyButtonClicked); + m_editSelectedStudyPushButton = new QPushButton("Edit Selected Study Title..."); + m_editSelectedStudyPushButton->setSizePolicy(QSizePolicy::Fixed, + m_editSelectedStudyPushButton->sizePolicy().verticalPolicy()); + QObject::connect(m_editSelectedStudyPushButton, &QPushButton::clicked, + this, &BalsaStudySelectionDialog::editSelectedStudyButtonClicked); + + + QHBoxLayout* studyButtonLayout = new QHBoxLayout(); + studyButtonLayout->addWidget(newStudyTitlePushButton); + studyButtonLayout->addStretch(); + studyButtonLayout->addWidget(m_editSelectedStudyPushButton); + QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(m_studyTableWidget, 100); - dialogLayout->addWidget(newStudyTitlePushButton, 0); + dialogLayout->addLayout(studyButtonLayout, 0); setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); @@ -245,6 +256,32 @@ BalsaStudySelectionDialog::newStudyButtonClicked() } } +/** + * Called when edit selected study title button is clicked + */ +void +BalsaStudySelectionDialog::editSelectedStudyButtonClicked() +{ + const int32_t selectedRow = m_studyTableWidget->currentRow(); + if (selectedRow < 0) { + WuQMessageBox::errorOk(this, "No Study Title is selected"); + return; + } + + CaretAssertVectorIndex(m_studyInformation, selectedRow); + AString title = m_studyInformation[selectedRow].getStudyTitle(); + + title = QInputDialog::getText(this, + "Edit study title", + "Title", + QLineEdit::Normal, + title); + if ( ! title.isNull()) { + m_studyInformation[selectedRow].setStudyTitle(title); + loadStudyTitleTableWidget(title); + } +} + /** * Called when the OK button is clicked. */ diff --git a/src/GuiQt/BalsaStudySelectionDialog.h b/src/GuiQt/BalsaStudySelectionDialog.h index dd9db2354..900004d17 100644 --- a/src/GuiQt/BalsaStudySelectionDialog.h +++ b/src/GuiQt/BalsaStudySelectionDialog.h @@ -28,6 +28,7 @@ #include "BalsaStudyInformation.h" #include "WuQDialogModal.h" +class QPushButton; class QTableWidget; @@ -58,6 +59,8 @@ namespace caret { private slots: void newStudyButtonClicked(); + void editSelectedStudyButtonClicked(); + private: const int32_t COLUMN_TITLE = 0; @@ -83,6 +86,8 @@ namespace caret { QTableWidget* m_studyTableWidget; + QPushButton* m_editSelectedStudyPushButton; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From f564d674aea52869b594c11271f451fdea5555c2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 26 Sep 2017 09:56:20 -0500 Subject: [PATCH 412/755] Resolve WB-742 Surface orientation reset button does't work: Redraw requests were missing after addition of chart yoking --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 2aa3db3dd..f6a885cd7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -4131,10 +4131,14 @@ BrainBrowserWindowToolBar::updateOtherYokedWindows() BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { if (browserTabContent->isBrainModelYoked()) { + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, browserTabContent->getBrainModelYokingGroup(), browserTabContent->getChartModelYokingGroup()).getPointer()); } + else { + updateGraphicsWindow(); + } } } -- GitLab From 5d9234ff8c51510d90ba3f86bb070a23b5ba67bd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 26 Sep 2017 12:28:19 -0500 Subject: [PATCH 413/755] In code that attempts to restore a version one chart to version two chart from a scene, test validity of chart two (not NULL) to fix crash. --- src/Brain/Brain.cxx | 41 ++++++++++++++++++++++++++++------------- src/Brain/Brain.h | 2 ++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index cc5a1181b..69ac360e8 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -4742,13 +4742,7 @@ Brain::updateChartModel() if (haveChartableFileFlag) { if (m_modelChartTwo == NULL) { - m_modelChartTwo = new ModelChartTwo(this); - EventModelAdd eventAddModel(m_modelChartTwo); - EventManager::get()->sendEvent(eventAddModel.getPointer()); - - if (m_isSpecFileBeingRead == false) { - m_modelChartTwo->initializeOverlays(); - } + createModelChartTwo(); } } else { @@ -4761,10 +4755,25 @@ Brain::updateChartModel() } } +/** + * Create the model chart two. + */ +void +Brain::createModelChartTwo() +{ + m_modelChartTwo = new ModelChartTwo(this); + EventModelAdd eventAddModel(m_modelChartTwo); + EventManager::get()->sendEvent(eventAddModel.getPointer()); + + if (m_isSpecFileBeingRead == false) { + m_modelChartTwo->initializeOverlays(); + } +} + /** * Update the volume slice model. */ -void +void Brain::updateVolumeSliceModel() { bool isValid = false; @@ -7348,12 +7357,18 @@ Brain::loadMatrixChartingFileDefaultRowOrColumn(CaretDataFile* caretDataFile) void Brain::restoreModelChartOneToModelChartTwo() { - CaretAssert(m_modelChartTwo); - if ( ! m_modelChartTwo->isRestoredFromScene()) { - if (m_modelChart != NULL) { - if (m_modelChart->isRestoredFromScene()) { - m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); + if (m_modelChartTwo != NULL) { + if (m_modelChartTwo->isRestoredFromScene()) { + return; + } + } + + if (m_modelChart != NULL) { + if (m_modelChart->isRestoredFromScene()) { + if (m_modelChartTwo == NULL) { + createModelChartTwo(); } + m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); } } } diff --git a/src/Brain/Brain.h b/src/Brain/Brain.h index b3af92374..3edcee462 100644 --- a/src/Brain/Brain.h +++ b/src/Brain/Brain.h @@ -487,6 +487,8 @@ namespace caret { const AString& dataFileName, const bool markDataFileAsModified); + void createModelChartTwo(); + /** * Is the data file with the given name already loaded? * -- GitLab From 8da965f59abec9ded840edc40e9d7d145ebb9dff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 27 Sep 2017 10:06:04 -0500 Subject: [PATCH 414/755] Resolve WB-694 Duplicate annotation in tab: Duplicate has been added to Annotation Mode's pop-up menu. --- src/Annotations/AnnotationRedoUndoCommand.cxx | 62 +++++++++++++ src/Annotations/AnnotationRedoUndoCommand.h | 3 + .../AnnotationRedoUndoCommandModeEnum.cxx | 4 + .../AnnotationRedoUndoCommandModeEnum.h | 2 + .../EventAnnotationAddToRemoveFromFile.h | 2 + src/Files/AnnotationFile.cxx | 13 +++ .../UserInputModeAnnotationsContextMenu.cxx | 91 +++++++++++++++++++ .../UserInputModeAnnotationsContextMenu.h | 4 + 8 files changed, 181 insertions(+) diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index f63a2b902..df16def5d 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -188,6 +188,11 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; + case AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION: + CaretAssertMessage(0, ("This mode " + + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + + " is handle in the redo() and undo() functions.")); + break; case AnnotationRedoUndoCommandModeEnum::GROUPING_GROUP: CaretAssert(0); case AnnotationRedoUndoCommandModeEnum::GROUPING_REGROUP: @@ -547,6 +552,17 @@ AnnotationRedoUndoCommand::redo(AString& errorMessageOut) validFlag = false; } } + else if (m_mode == AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION) { + EventAnnotationAddToRemoveFromFile duplicateEvent(EventAnnotationAddToRemoveFromFile::MODE_DUPLICATE, + annMem->m_annotationFile, + annMem->m_annotation); + EventManager::get()->sendEvent(duplicateEvent.getPointer()); + + if (duplicateEvent.isError()) { + errorMessageOut.appendWithNewLine(duplicateEvent.getErrorMessage()); + validFlag = false; + } + } else if (m_mode == AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION) { EventAnnotationAddToRemoveFromFile pasteEvent(EventAnnotationAddToRemoveFromFile::MODE_PASTE, annMem->m_annotationFile, @@ -670,6 +686,17 @@ AnnotationRedoUndoCommand::undo(AString& errorMessageOut) validFlag = false; } } + else if (m_mode == AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION) { + EventAnnotationAddToRemoveFromFile duplicateEvent(EventAnnotationAddToRemoveFromFile::MODE_UNDUPLICATE, + annMem->m_annotationFile, + annMem->m_annotation); + EventManager::get()->sendEvent(duplicateEvent.getPointer()); + + if (duplicateEvent.isError()) { + errorMessageOut.appendWithNewLine(duplicateEvent.getErrorMessage()); + validFlag = false; + } + } else if (m_mode == AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION) { EventAnnotationAddToRemoveFromFile pasteEvent(EventAnnotationAddToRemoveFromFile::MODE_UNPASTE, annMem->m_annotationFile, @@ -1317,6 +1344,41 @@ AnnotationRedoUndoCommand::setModePasteAnnotation(AnnotationFile* annotationFile m_annotationMementos.push_back(am); } +/** + * Set the mode to duplicate annotations and create the undo/redo instances. + * + * @param annotationFile + * File to which annotation is pasted. + * @param annotations + * The new anntotation duplicated from existing annotation. + */ +void +AnnotationRedoUndoCommand::setModeDuplicateAnnotation(AnnotationFile* annotationFile, + Annotation* annotation) +{ + m_mode = AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION; + setDescription("Duplicate Annotation"); + + CaretAssert(annotationFile); + CaretAssert(annotation); + + /* + * NOTE: We only need the pointer since the file containing + * the annotation will handle delete/undelete of the + * annotation. If we don't use NULL for the redo and + * undo annotations, copies of the annotation would be + * needed since the AnnotationMemento will delete + * the redo and undo annotations when it is deleted. + */ + AnnotationMemento* am = new AnnotationMemento(annotationFile, + annotation, + NULL, + NULL); + + m_annotationMementos.push_back(am); +} + + /** * Set the mode to rotation angle and create the undo/redo instances * diff --git a/src/Annotations/AnnotationRedoUndoCommand.h b/src/Annotations/AnnotationRedoUndoCommand.h index ec99acd5c..c15773d46 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.h +++ b/src/Annotations/AnnotationRedoUndoCommand.h @@ -96,6 +96,9 @@ namespace caret { void setModePasteAnnotation(AnnotationFile* annotationFile, Annotation* annotation); + void setModeDuplicateAnnotation(AnnotationFile* annotationFile, + Annotation* annotation); + void setModeRotationAngle(const float newRotationAngle, const std::vector& annotations); diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx index 63884b8bc..8ec48ec93 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx @@ -138,6 +138,10 @@ AnnotationRedoUndoCommandModeEnum::initialize() "DELETE_ANNOTATIONS", "Delete Annotations")); + enumData.push_back(AnnotationRedoUndoCommandModeEnum(DUPLICATE_ANNOTATION, + "DUPLICATE_ANNOTATION", + "Duplicate Annotation")); + enumData.push_back(AnnotationRedoUndoCommandModeEnum(GROUPING_GROUP, "GROUPING_GROUP", "Group Annotations")); diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h index b9c0caf76..3b8d2c84f 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h @@ -53,6 +53,8 @@ public: CUT_ANNOTATION, /** Delete Annotations */ DELETE_ANNOTATIONS, + /** Duplicate Annotation */ + DUPLICATE_ANNOTATION, /** Group Annotations */ GROUPING_GROUP, /** Regroup Annotations */ diff --git a/src/Annotations/EventAnnotationAddToRemoveFromFile.h b/src/Annotations/EventAnnotationAddToRemoveFromFile.h index 8219e1bc5..d03719a14 100644 --- a/src/Annotations/EventAnnotationAddToRemoveFromFile.h +++ b/src/Annotations/EventAnnotationAddToRemoveFromFile.h @@ -38,10 +38,12 @@ namespace caret { MODE_CREATE, MODE_CUT, MODE_DELETE, + MODE_DUPLICATE, MODE_PASTE, MODE_UNCREATE, MODE_UNCUT, MODE_UNDELETE, + MODE_UNDUPLICATE, MODE_UNPASTE }; diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index e2257a707..222cc0bcb 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -354,6 +354,13 @@ AnnotationFile::receiveEvent(Event* event) annEvent->setSuccessful(true); } break; + case EventAnnotationAddToRemoveFromFile::MODE_DUPLICATE: + if (annotationFile == this) { + if (restoreAnnotationAddIfNotFound(annotation)) { + annEvent->setSuccessful(true); + } + } + break; case EventAnnotationAddToRemoveFromFile::MODE_PASTE: if (annotationFile == this) { if (restoreAnnotationAddIfNotFound(annotation)) { @@ -378,6 +385,12 @@ AnnotationFile::receiveEvent(Event* event) annEvent->setSuccessful(true); } break; + case EventAnnotationAddToRemoveFromFile::MODE_UNDUPLICATE: + if (annotationFile == this) { + if (removeAnnotation(annotation)) { + annEvent->setSuccessful(true); + } + } case EventAnnotationAddToRemoveFromFile::MODE_UNPASTE: if (annotationFile == this) { if (removeAnnotation(annotation)) { diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 298eb7669..e5f1a72ea 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -39,6 +39,8 @@ #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "CaretAssert.h" +#include "DisplayPropertiesAnnotation.h" +#include "EventBrowserTabGetAll.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" @@ -185,6 +187,14 @@ m_newAnnotationCreatedByContextMenu(NULL) this, SLOT(deleteAnnotations())); deleteAction->setEnabled(allSelectedAnnotationsDeletableFlag); + /* + * Duplicate tab space annotation + */ + QMenu* duplicateMenu = createDuplicateTabSpaceAnnotationMenu(); + if (duplicateMenu != NULL) { + addMenu(duplicateMenu); + } + /* * Paste */ @@ -479,6 +489,9 @@ UserInputModeAnnotationsContextMenu::turnOnDisplayInGroup(QAction* action) EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } +/** + * @return New menu for turning on in display group + */ QMenu* UserInputModeAnnotationsContextMenu::createTurnOnInDisplayGroupMenu() { @@ -500,6 +513,84 @@ UserInputModeAnnotationsContextMenu::createTurnOnInDisplayGroupMenu() return menu; } +/** + * @return New menu for duplicating a tab annotation. + * NULL is returned if no other tabs. + */ +QMenu* +UserInputModeAnnotationsContextMenu::createDuplicateTabSpaceAnnotationMenu() +{ + EventBrowserTabGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + const std::vector allTabs = tabIndicesEvent.getAllBrowserTabs(); + + bool menuValidFlag = false; + if (m_annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { + if (allTabs.size() > 1) { + menuValidFlag = true; + } + } + + QMenu* menu = new QMenu("Duplicate to Tab"); + QObject::connect(menu, SIGNAL(triggered(QAction*)), + this, SLOT(duplicateAnnotationSelected(QAction*))); + + if (menuValidFlag) { + for (BrowserTabContent* tabContent : allTabs) { + if (tabContent->getTabNumber() != m_annotation->getTabIndex()) { + QAction* action = menu->addAction(tabContent->getName()); + action->setData((int)tabContent->getTabNumber()); + } + } + } + else { + menu->setEnabled(false); + } + + return menu; +} + +/** + * Gets called when a selection is made from Duplicate Tab Annotation menu + * + * @param action + * Action selected from Duplicate menu + */ +void +UserInputModeAnnotationsContextMenu::duplicateAnnotationSelected(QAction* action) +{ + CaretAssert(action); + CaretAssert(m_annotationFile); + CaretAssert(m_annotation); + + AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); + + const int32_t tabIndex = action->data().toInt(); + + Annotation* annCopy = m_annotation->clone(); + annCopy->setTabIndex(tabIndex); + + DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); + dpa->updateForNewAnnotation(annCopy); + + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + undoCommand->setModeDuplicateAnnotation(m_annotationFile, + annCopy); + AString errorMessage; + if ( ! annotationManager->applyCommand(undoCommand, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + } + annotationManager->selectAnnotationForEditing(m_mouseEvent.getBrowserWindowIndex(), + AnnotationManager::SELECTION_MODE_SINGLE, + false, + annCopy); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} + /** * Group annotations. */ diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.h b/src/GuiQt/UserInputModeAnnotationsContextMenu.h index 33e6e663b..61d582c55 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.h +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.h @@ -83,6 +83,8 @@ namespace caret { void applyGroupingUngroup(); + void duplicateAnnotationSelected(QAction*); + private: UserInputModeAnnotationsContextMenu(const UserInputModeAnnotationsContextMenu&); @@ -92,6 +94,8 @@ namespace caret { QMenu* createTurnOnInDisplayGroupMenu(); + QMenu* createDuplicateTabSpaceAnnotationMenu(); + UserInputModeAnnotations* m_userInputModeAnnotations; /* -- GitLab From d6b3a525a1faf069e9eab724ae86051aaf567260 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 27 Sep 2017 12:38:42 -0500 Subject: [PATCH 415/755] Resolve WB-743 Transparency does not work in oblique volumes: Since oblique slice drawing works by compositing voxels from all layers into a single voxel, explicit blending of voxels between layers has been added. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 57 ++++++++++++++++--- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 8 ++- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index f9b09236f..5cc691ad3 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -1204,8 +1204,13 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan */ std::vector volumeSlices; for (int32_t i = 0; i < numVolumes; i++) { + float sliceOpacity = 1.0; + if (i > 0) { + sliceOpacity = m_volumeDrawInfo[i].opacity; + } volumeSlices.push_back(VolumeSlice(m_volumeDrawInfo[i].volumeFile, - m_volumeDrawInfo[i].mapIndex)); + m_volumeDrawInfo[i].mapIndex, + m_volumeDrawInfo[i].opacity)); } bool showFirstVoxelCoordFlag = debugFlag; @@ -1676,12 +1681,12 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan const uint8_t* rgba = volumeSlices[sliceIndex].getRgbaForValueByIndex(voxelOffset); if (rgba[3] > 0) { - voxelRGBA[0] = rgba[0]; - voxelRGBA[1] = rgba[1]; - voxelRGBA[2] = rgba[2]; - voxelRGBA[3] = rgba[3]; - if (m_identificationModeFlag) { + voxelRGBA[0] = rgba[0]; + voxelRGBA[1] = rgba[1]; + voxelRGBA[2] = rgba[2]; + voxelRGBA[3] = rgba[3]; + VolumeMappableInterface* volMap = volumeSlices[sliceIndex].m_volumeMappableInterface; int64_t voxelI, voxelJ, voxelK; volMap->enclosingVoxel(vtd->m_center[0], vtd->m_center[1], vtd->m_center[2], @@ -1699,6 +1704,40 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan voxelRGBA); } } + else { + /* + * In oblique drawing, each drawn "voxel" is composited from + * an interpolated voxel from each slice. Therefore, we must + * do our own alpha (transparency) processing. + */ + bool noAlphaFlag = true; + if (iSlice > 0) { + float alpha = volumeSlices[sliceIndex].m_opacity; + if (alpha < 1.0f) { + if ((voxelRGBA[3] > 0) + && (rgba[3] > 0)) { + const float oneMinusAlpha = 1.0f - alpha; + voxelRGBA[0] = static_cast((rgba[0] * alpha) + (voxelRGBA[0] * oneMinusAlpha)); + voxelRGBA[1] = static_cast((rgba[1] * alpha) + (voxelRGBA[1] * oneMinusAlpha)); + voxelRGBA[2] = static_cast((rgba[2] * alpha) + (voxelRGBA[2] * oneMinusAlpha)); + voxelRGBA[3] = 255; + noAlphaFlag = false; + } + } + } + + if (volumeEditingDrawAllVoxelsFlag + && (volumeSlices[sliceIndex].m_volumeFile == voxelEditingVolumeFile)) { + noAlphaFlag = true; + } + + if (noAlphaFlag) { + voxelRGBA[0] = rgba[0]; + voxelRGBA[1] = rgba[1]; + voxelRGBA[2] = rgba[2]; + voxelRGBA[3] = rgba[3]; + } + } } } @@ -5192,7 +5231,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::getVolumeDrawingViewDependentCulling(const * Index of selected map. */ BrainOpenGLVolumeObliqueSliceDrawing::VolumeSlice::VolumeSlice(VolumeMappableInterface* volumeMappableInterface, - const int32_t mapIndex) + const int32_t mapIndex, + const float opacity) { m_volumeMappableInterface = volumeMappableInterface; m_volumeFile = dynamic_cast(m_volumeMappableInterface); @@ -5202,6 +5242,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::VolumeSlice::VolumeSlice(VolumeMappableInt m_mapIndex = mapIndex; CaretAssert(m_mapIndex >= 0); + m_opacity = opacity; + CaretAssert((m_opacity >= 0.0f) && (m_opacity <= 1.0f)); + const int64_t sliceDim = 300; const int64_t numVoxels = sliceDim * sliceDim; m_values.reserve(numVoxels); diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index ae5fec6f6..67a190011 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -73,7 +73,8 @@ namespace caret { * Volume that contains the data values. */ VolumeSlice(VolumeMappableInterface* volumeMappableInterface, - const int32_t mapIndex); + const int32_t mapIndex, + const float opacity); /** * Add a value and return its index. @@ -131,6 +132,11 @@ namespace caret { */ int32_t m_mapIndex; + /** + * Opacity + */ + float m_opacity; + /** * The voxel values for single scalar or red if RGBA volume */ -- GitLab From 4c3bcf3d1ca54f28f76928bdb64ff52eee020bd4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 28 Sep 2017 16:04:49 -0500 Subject: [PATCH 416/755] Resolve WB-746 Color bar annotation rotation, width, height are disabled: When a colorbar is selected, one can adjust its width and height in the annotation toolbar. --- src/GuiQt/AnnotationWidthHeightWidget.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index 98aff29d6..ac8ad91b0 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -119,12 +119,7 @@ AnnotationWidthHeightWidget::~AnnotationWidthHeightWidget() void AnnotationWidthHeightWidget::updateContent(std::vector& annotations2D) { - m_annotations2D.clear(); - for (auto a : annotations2D) { - if (a->getType() != AnnotationTypeEnum::COLOR_BAR) { - m_annotations2D.push_back(a); - } - } + m_annotations2D = annotations2D; if ( ! m_annotations2D.empty()) { float widthValue = 0.0; -- GitLab From 4972453b09061627c2093a9c0c021fee8b7ea520 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 28 Sep 2017 16:29:04 -0500 Subject: [PATCH 417/755] Resolve WB-746 Color bar annotation rotation, width, height are disabled: When a colorbar is selected, one can adjust its width and height in the annotation toolbar. UPDATE enabled rotation in the toolbar. --- src/Annotations/Annotation.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 0377eb3ed..4e9753ae8 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -1198,7 +1198,6 @@ Annotation::initializeProperties() resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); resetProperty(Property::LINE_THICKNESS); - resetProperty(Property::ROTATION); resetProperty(Property::TEXT_COLOR); resetProperty(Property::TEXT_EDIT); -- GitLab From ab25dc69c0557ba990989bd76a1a1fa28484e20e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 29 Sep 2017 12:06:37 -0500 Subject: [PATCH 418/755] As part of WB-749 - Workbench BALSA Updates - Added retrieval of the user's roles from BALSA. Until this functionality is moved to the production BALSA, roles are obtained by pressing the "Test Roles" button. --- src/GuiQt/BalsaDatabaseManager.cxx | 154 ++++++++++++ src/GuiQt/BalsaDatabaseManager.h | 10 + .../BalsaDatabaseUploadSceneFileDialog.cxx | 35 ++- .../BalsaDatabaseUploadSceneFileDialog.h | 2 + src/GuiQt/BalsaUserRoles.cxx | 221 ++++++++++++++++++ src/GuiQt/BalsaUserRoles.h | 84 +++++++ src/GuiQt/CMakeLists.txt | 2 + 7 files changed, 505 insertions(+), 3 deletions(-) create mode 100644 src/GuiQt/BalsaUserRoles.cxx create mode 100644 src/GuiQt/BalsaUserRoles.h diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index b37965174..6695f4a32 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -28,6 +28,7 @@ #include +#include "BalsaUserRoles.h" #include "CaretAssert.h" #include "CaretHttpManager.h" #include "CaretLogger.h" @@ -698,6 +699,109 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, return false; } +/** + * Request the user's roles + * + * @param databaseURL + * URL for database + * @param roleNamesOut + * Output with names of roles + * @param errorMessageOut + * Output with error message + * @return + * True if success, else false. + */ +bool +BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, + AString& roleNamesOut, + AString& errorMessageOut) +{ + const AString studyIdURL(databaseURL + + "/user/roles"); + + errorMessageOut.clear(); + + CaretHttpRequest caretRequest; + caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; + caretRequest.m_url = studyIdURL; + caretRequest.m_headers.insert(std::make_pair("Content-Type", + "application/x-www-form-urlencoded")); + caretRequest.m_headers.insert(std::make_pair("Cookie", + getJSessionIdCookie())); + caretRequest.m_arguments.push_back(std::make_pair("type", + "json")); + + CaretHttpResponse studyResponse; + CaretHttpManager::httpRequest(caretRequest, studyResponse); + + if (m_debugFlag) { + std::cout << "Request rolese response Code: " << studyResponse.m_responseCode << std::endl; + } + + if (studyResponse.m_responseCode != 200) { + errorMessageOut = ("Requesting roles failed with HTTP code=" + + AString::number(studyResponse.m_responseCode)); + return false; + } + + AString contentType = getHeaderValue(studyResponse, "Content-Type"); + //AString contentType = studyResponse.getHeaderValue("Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Requesting roles failed. Content type returned by BALSA is unknown"); + return false; + } + + if ( ! contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Requesting rolesfailed. Content type return by BALSA should be JSON format but is " + + contentType); + return false; + } + + studyResponse.m_body.push_back('\0'); + AString responseContent(&studyResponse.m_body[0]); + +// if (m_debugFlag) { + std::cout << "Request roles body:\n" << responseContent << std::endl << std::endl; +// } + + QJsonParseError jsonError; + QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), + &jsonError); + if (jsonDocument.isNull()) { + errorMessageOut = ("Requesting roles failed. Failed to parse JSON, error:" + + jsonError.errorString()); + return false; + } + + QByteArray json = jsonDocument.toJson(); + if (m_debugFlag) { + std::cout << "Array?: " << jsonDocument.isArray() << std::endl; + std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; + std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; + std::cout << "Object?: " << jsonDocument.isObject() << std::endl; + std::cout << "JSON length: " << json.size() << std::endl; + AString str(json); + std::cout << ("Formatted JSON:\n" + str) << std::endl; + } + + if ( ! jsonDocument.isArray()) { + errorMessageOut = ("Requesting roles failed. JSON content is not an array." + "JSON is displayed in terminal if logging level is warning or higher."); + CaretLogWarning("Roles JSON is not Array\n" + + AString(jsonDocument.toJson())); + return false; + } + + BalsaUserRoles bsi(jsonDocument.array()); + std::cout << bsi.toString() << std::endl; +// if ( ! bsi.getStudyID().isEmpty()) { +// studyIDOut = bsi.getStudyID(); +// return true; +// } + + return bsi.isValid(); +} + /** * Login to BALSA and request a study ID from a study title. * @@ -755,6 +859,56 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, return true; } +/** + * Login to BALSA and request a study ID from a study title. + * + * @param databaseURL + * URL of the database. + * @param username + * Username for logging in. + * @param password + * Password for logging in. + * @param studyTitle + * The study's titlee. + * @param studyIdOut + * Output containing the study ID. + * @param errorMessageOut + * Contains description of any error(s). + * @return + * True if processing was successful, else false. + */ +bool +BalsaDatabaseManager::getUserRoles(const AString& databaseURL, + const AString& username, + const AString& password, + AString& roleNamesOut, + AString& errorMessageOut) +{ + /* + * Login + */ + const AString loginURL(databaseURL + + "/j_spring_security_check"); + if ( ! login(loginURL, + username, + password, + errorMessageOut)) { + + return false; + } + + CaretLogInfo("SESSION ID from BALSA Login: " + + getJSessionIdCookie()); + + if ( ! requestUserRoles(databaseURL, + roleNamesOut, + errorMessageOut)) { + return false; + } + + return true; +} + /** * Login to BALSA and request a study ID from a study title. diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index 6ff942b44..1ebfcac06 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -42,6 +42,12 @@ namespace caret { std::vector& studyInformationOut, AString& errorMessageOut); + bool getUserRoles(const AString& databaseURL, + const AString& username, + const AString& password, + AString& roleNamesOut, + AString& errorMessageOut); + bool getStudyIDFromStudyTitle(const AString& databaseURL, const AString& username, const AString& password, @@ -96,6 +102,10 @@ namespace caret { AString& studyIDOut, AString& errorMessageOut); + bool requestUserRoles(const AString& databaseURL, + AString& roleNamesOut, + AString& errorMessageOut); + bool uploadFileWithCaretHttpManager(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 2684ad7e5..9ebd3ae34 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -253,6 +253,14 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QObject::connect(m_findBaseDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked); + /* + * Roles button + */ + QPushButton* rolesPushButton = new QPushButton("Test Roles..."); + rolesPushButton->setToolTip("Test getting the user's roles"); + QObject::connect(rolesPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); + int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_DATA_WIDGET = columnCounter++; @@ -293,6 +301,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(rolesPushButton, row, COLUMN_BUTTON_ONE, 1, 2); m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); @@ -545,6 +554,26 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() WuQDialogModal::okButtonClicked(); } +void +BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked() +{ + const AString username = m_usernameLineEdit->text().trimmed(); + const AString password = m_passwordLineEdit->text().trimmed(); + + AString roleNames; + AString errorMessage; + + if ( ! m_balsaDatabaseManager->getUserRoles(getDataBaseURL(), + username, + password, + roleNames, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + return; + } +} + /** * Select a Study Title from those user has in BALSA Database */ @@ -555,9 +584,9 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() const AString password = m_passwordLineEdit->text().trimmed(); std::vector studyInfo; - studyInfo.emplace(studyInfo.end(), "AV4H", "Study One"); - studyInfo.emplace(studyInfo.end(), "BX32", "Study Two"); - studyInfo.emplace(studyInfo.end(), "CR33", "Study Three"); +// studyInfo.emplace(studyInfo.end(), "AV4H", "Study One"); +// studyInfo.emplace(studyInfo.end(), "BX32", "Study Two"); +// studyInfo.emplace(studyInfo.end(), "CR33", "Study Three"); CursorDisplayScoped cursor; cursor.showWaitCursor(); diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 7a319a9b0..7414f6bec 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -66,6 +66,8 @@ namespace caret { void findBaseDirectoryPushButtonClicked(); + void rolesButtonClicked(); + protected: virtual void okButtonClicked(); diff --git a/src/GuiQt/BalsaUserRoles.cxx b/src/GuiQt/BalsaUserRoles.cxx new file mode 100644 index 000000000..d0576e463 --- /dev/null +++ b/src/GuiQt/BalsaUserRoles.cxx @@ -0,0 +1,221 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BALSA_USER_ROLES_DECLARE__ +#include "BalsaUserRoles.h" +#undef __BALSA_USER_ROLES_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" + +using namespace caret; + + + +/** + * \class caret::BalsaUserRoles + * \brief Information about a BALSA User's Roles + * \ingroup GuiQt + */ + +/** + * Constructor with all roles invalid; + */ +BalsaUserRoles::BalsaUserRoles() +: CaretObject() +{ + +} + +/** + * Constructor that creates BALSA user roles from a JSON array. + * + * @param jsonArray + * The JSON array. + */ +BalsaUserRoles::BalsaUserRoles(const QJsonArray& jsonArray) +{ + parseJson(jsonArray); +} + +/** + * Destructor. + */ +BalsaUserRoles::~BalsaUserRoles() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +BalsaUserRoles::BalsaUserRoles(const BalsaUserRoles& obj) +: CaretObject(obj) +{ + this->copyHelperBalsaUserRoles(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +BalsaUserRoles& +BalsaUserRoles::operator=(const BalsaUserRoles& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperBalsaUserRoles(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +BalsaUserRoles::copyHelperBalsaUserRoles(const BalsaUserRoles& obj) +{ + m_validFlag = obj.m_validFlag; + m_adminFlag = obj.m_adminFlag; + m_curatorFlag = obj.m_curatorFlag; + m_submitterFlag = obj.m_submitterFlag; + m_userFlag = obj.m_userFlag; +} + +/** + * Parse JSON to find roles. + * + * @param jsonArray + * JSON array with roles. + * @return + * True if data was parsed, else false. + */ +bool +BalsaUserRoles::parseJson(const QJsonArray& jsonArray) +{ + for (QJsonArray::const_iterator roleIter = jsonArray.begin(); + roleIter != jsonArray.end(); + roleIter++) { + QJsonValue value = *roleIter; + if (value.isString()) { + const QString roleName = value.toString(); + if (roleName == "ROLE_ADMIN") { + m_adminFlag = true; + } + else if (roleName == "ROLE_CURATOR") { + m_curatorFlag = true; + } + else if (roleName == "ROLE_SUBMITTER") { + m_submitterFlag = true; + } + else if (roleName == "ROLE_USER") { + m_userFlag = true; + } + else { + CaretLogInfo("Unrecognized BALSA role found \"" + + roleName + + "\""); + } + } + + m_validFlag = true; + } + + /* + * Some roles imply other roles + */ + if (m_curatorFlag) { + m_submitterFlag = true; + } + + return isValid(); +} + +/** + * @return True if has admin role + */ +bool +BalsaUserRoles::isAdmin() const +{ + return m_adminFlag; +} + +/** + * @return True if has admin role + */ +bool +BalsaUserRoles::isCurator() const +{ + return m_curatorFlag; +} + +/** + * @return True if has submitter role + */ +bool +BalsaUserRoles::isSubmitter() const +{ + return m_submitterFlag; +} + +/** + * @return True if has user role + */ +bool +BalsaUserRoles::isUser() const +{ + return m_userFlag; +} + +/** + * Is the data valid (has parsed successfully) + */ +bool +BalsaUserRoles::isValid() const +{ + return m_validFlag; +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +BalsaUserRoles::toString() const +{ + AString msg("BalsaUserRoles: " + + AString(m_validFlag ? "Data Valid - YES: " : "Data Valid - NO: ") + + AString(m_adminFlag ? "Admin; " : "") + + AString(m_curatorFlag ? "Curator; " : "") + + AString(m_submitterFlag ? "Submitter; " : "") + + AString(m_userFlag ? "User; " : "")); + return msg; +} + diff --git a/src/GuiQt/BalsaUserRoles.h b/src/GuiQt/BalsaUserRoles.h new file mode 100644 index 000000000..7b65be338 --- /dev/null +++ b/src/GuiQt/BalsaUserRoles.h @@ -0,0 +1,84 @@ +#ifndef __BALSA_USER_ROLES_H__ +#define __BALSA_USER_ROLES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +class QJsonArray; + +namespace caret { + + class BalsaUserRoles : public CaretObject { + + public: + BalsaUserRoles(const QJsonArray& jsonArray); + + BalsaUserRoles(); + + virtual ~BalsaUserRoles(); + + BalsaUserRoles(const BalsaUserRoles& obj); + + BalsaUserRoles& operator=(const BalsaUserRoles& obj); + + bool parseJson(const QJsonArray& jsonArray); + + bool isEmpty() const; + + bool isAdmin() const; + + bool isCurator() const; + + bool isSubmitter() const; + + bool isUser() const; + + bool isValid() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperBalsaUserRoles(const BalsaUserRoles& obj); + + bool m_adminFlag = false; + + bool m_curatorFlag = false; + + bool m_submitterFlag = false; + + bool m_userFlag = false; + + bool m_validFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BALSA_USER_ROLES_DECLARE__ + // +#endif // __BALSA_USER_ROLES_DECLARE__ + +} // namespace +#endif //__BALSA_USER_ROLES_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index e682c804f..aeceab454 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -249,6 +249,7 @@ BalsaDatabaseManager.h BalsaDatabaseUploadSceneFileDialog.h BalsaStudySelectionDialog.h BalsaStudyInformation.h +BalsaUserRoles.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h @@ -461,6 +462,7 @@ AnnotationWidthHeightWidget.cxx BalsaDatabaseManager.cxx BalsaDatabaseUploadSceneFileDialog.cxx BalsaStudyInformation.cxx +BalsaUserRoles.cxx BalsaStudySelectionDialog.cxx BorderEditingSelectionDialog.cxx BorderFileSplitDialog.cxx -- GitLab From 14c8f10c2df2e7283ca3cb2a942784240a71f1ff Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 2 Oct 2017 15:39:09 -0500 Subject: [PATCH 419/755] Add WuQWidgetDisabler. This class is used to simplify the disabling and enabling a widget. Its constructor accepts and disables a widget. Its destructor changes the widget's enabled status to the status at entry of the constructor. --- src/GuiQt/WuQWidgetDisabler.cxx | 119 ++++++++++++++++++++++++++++++++ src/GuiQt/WuQWidgetDisabler.h | 59 ++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/GuiQt/WuQWidgetDisabler.cxx create mode 100644 src/GuiQt/WuQWidgetDisabler.h diff --git a/src/GuiQt/WuQWidgetDisabler.cxx b/src/GuiQt/WuQWidgetDisabler.cxx new file mode 100644 index 000000000..a908261f4 --- /dev/null +++ b/src/GuiQt/WuQWidgetDisabler.cxx @@ -0,0 +1,119 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_WIDGET_DISABLER_DECLARE__ +#include "WuQWidgetDisabler.h" +#undef __WU_Q_WIDGET_DISABLER_DECLARE__ + +#include + +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::WuQWidgetDisabler + * \brief Simplifies disabling of QWidget instance within a scope + * \ingroup GuiQt + * + * WuQWidgetDisabler can be used whereever you would otherwise + * use a pair of calls to setEnabled(). It disables the + * QWidget in its constructor and in the destructor it resets + * the enabled state to what it was before the constructor + * ran. + * + * An example for usage of this class is in the method + * that receives a QPushButton:clicked signal. User cannot + * push the button until the method completes. + * + * The design of this class is modeled after QSignalBlocker + * so Qt license is below. + * + */ + +/**************************************************************************** + ** + ** Copyright (C) 2016 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the QtWidgets module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see https://www.qt.io/terms-conditions. For further + ** information use the contact form at https://www.qt.io/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 3 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL3 included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 3 requirements + ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 2.0 or (at your option) the GNU General + ** Public license version 3 or any later version approved by the KDE Free + ** Qt Foundation. The licenses are as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 + ** included in the packaging of this file. Please review the following + ** information to ensure the GNU General Public License requirements will + ** be met: https://www.gnu.org/licenses/gpl-2.0.html and + ** https://www.gnu.org/licenses/gpl-3.0.html. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + +/** + * Constructor. + * Calls widget->setEnabled(false) + * + * @param widget + * The QWidget + */ +WuQWidgetDisabler::WuQWidgetDisabler(QWidget* widget) +: CaretObject(), +m_widget(widget) +{ + CaretAssert(m_widget); + + m_savedEnabledState = m_widget->isEnabled(); + m_widget->setEnabled(false); +} + +/** + * Destructor. Restores enabled status of the QObject + * to what it was before the constructor rang. + */ +WuQWidgetDisabler::~WuQWidgetDisabler() +{ + m_widget->setEnabled(m_savedEnabledState); +} + diff --git a/src/GuiQt/WuQWidgetDisabler.h b/src/GuiQt/WuQWidgetDisabler.h new file mode 100644 index 000000000..e8d3d963b --- /dev/null +++ b/src/GuiQt/WuQWidgetDisabler.h @@ -0,0 +1,59 @@ +#ifndef __WU_Q_WIDGET_DISABLER_H__ +#define __WU_Q_WIDGET_DISABLER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "CaretObject.h" + +class QWidget; + +namespace caret { + + class WuQWidgetDisabler : public CaretObject { + + public: + WuQWidgetDisabler(QWidget* widget); + + virtual ~WuQWidgetDisabler(); + + + // ADD_NEW_METHODS_HERE + + private: + WuQWidgetDisabler(const WuQWidgetDisabler&); + + WuQWidgetDisabler& operator=(const WuQWidgetDisabler&); + + QWidget* m_widget; + + bool m_savedEnabledState = true; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_WIDGET_DISABLER_DECLARE__ + // +#endif // __WU_Q_WIDGET_DISABLER_DECLARE__ + +} // namespace +#endif //__WU_Q_WIDGET_DISABLER_H__ -- GitLab From a03d8eeb3c779f5cfd94fe5a2234c6ec1f55e8f1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 2 Oct 2017 15:41:50 -0500 Subject: [PATCH 420/755] Implemented part of WB-479 Workbench BALSA updates: Redesigned dialog into 'Login' and 'Upload' sections. Adding support to request 'submitter' status. --- src/GuiQt/BalsaDatabaseManager.cxx | 176 +++------- src/GuiQt/BalsaDatabaseManager.h | 39 +-- .../BalsaDatabaseUploadSceneFileDialog.cxx | 330 ++++++++++++++---- .../BalsaDatabaseUploadSceneFileDialog.h | 28 +- src/GuiQt/BalsaStudySelectionDialog.cxx | 9 +- src/GuiQt/CMakeLists.txt | 3 + 6 files changed, 351 insertions(+), 234 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 6695f4a32..cd765a09d 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -56,7 +56,8 @@ using namespace caret; BalsaDatabaseManager::BalsaDatabaseManager() : CaretObject() { - m_debugFlag = false; + m_debugFlag = true; + logout(); // EventManager::get()->addEventListener(this, EventTypeEnum::); } @@ -81,8 +82,8 @@ BalsaDatabaseManager::toString() const /** * Login to the BALSA Database. * - * @param loginURL - * URL for logging in. + * @param databaseURL + * URL of the database for login * @param username * Name for login. * @param password @@ -93,17 +94,20 @@ BalsaDatabaseManager::toString() const * True if login is successful, else false. */ bool -BalsaDatabaseManager::login(const AString& loginURL, +BalsaDatabaseManager::login(const AString& databaseURL, const AString& username, const AString& password, AString& errorMessageOut) { errorMessageOut.clear(); + m_databaseURL = databaseURL; m_username = username.trimmed(); m_password = password.trimmed(); m_jSessionIdCookie = ""; + const AString loginURL(databaseURL + "/j_spring_security_check"); + CaretHttpRequest loginRequest; loginRequest.m_method = CaretHttpManager::POST_ARGUMENTS; loginRequest.m_url = loginURL; @@ -148,6 +152,7 @@ BalsaDatabaseManager::login(const AString& loginURL, if (loginResponse.m_responseCode == 200) { if (m_jSessionIdCookie.isEmpty()) { errorMessageOut = ("Login was successful but BALSA failed to provide a Session ID."); + logout(); return false; } @@ -159,10 +164,24 @@ BalsaDatabaseManager::login(const AString& loginURL, errorMessageOut = ("Login has failed.\n" "HTTP Code: " + AString::number(loginResponse.m_responseCode) + " Content: " + responseContent); + logout(); return false; } +/** + * Logout of the database + */ +void +BalsaDatabaseManager::logout() +{ + m_databaseURL.clear(); + m_username.clear(); + m_password.clear(); + m_jSessionIdCookie.clear(); +} + + /** * Upload file to the BALSA Database. * @@ -643,7 +662,6 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, } AString contentType = getHeaderValue(studyResponse, "Content-Type"); - //AString contentType = studyResponse.getHeaderValue("Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting study ID failed. Content type returned by BALSA is unknown"); return false; @@ -745,7 +763,6 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, } AString contentType = getHeaderValue(studyResponse, "Content-Type"); - //AString contentType = studyResponse.getHeaderValue("Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting roles failed. Content type returned by BALSA is unknown"); return false; @@ -760,9 +777,9 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, studyResponse.m_body.push_back('\0'); AString responseContent(&studyResponse.m_body[0]); -// if (m_debugFlag) { + if (m_debugFlag) { std::cout << "Request roles body:\n" << responseContent << std::endl << std::endl; -// } + } QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toLatin1(), @@ -793,11 +810,9 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, } BalsaUserRoles bsi(jsonDocument.array()); - std::cout << bsi.toString() << std::endl; -// if ( ! bsi.getStudyID().isEmpty()) { -// studyIDOut = bsi.getStudyID(); -// return true; -// } + if (m_debugFlag) { + std::cout << "**** Roles: " << bsi.toString() << std::endl; + } return bsi.isValid(); } @@ -805,12 +820,6 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, /** * Login to BALSA and request a study ID from a study title. * - * @param databaseURL - * URL of the database. - * @param username - * Username for logging in. - * @param password - * Password for logging in. * @param studyTitle * The study's titlee. * @param studyIdOut @@ -821,10 +830,7 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, * True if processing was successful, else false. */ bool -BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, - const AString& username, - const AString& password, - const AString& studyTitle, +BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& studyTitle, AString& studyIdOut, AString& errorMessageOut) { @@ -833,23 +839,7 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, return false; } - /* - * Login - */ - const AString loginURL(databaseURL - + "/j_spring_security_check"); - if ( ! login(loginURL, - username, - password, - errorMessageOut)) { - - return false; - } - - CaretLogInfo("SESSION ID from BALSA Login: " - + getJSessionIdCookie()); - - if ( ! requestStudyID(databaseURL, + if ( ! requestStudyID(m_databaseURL, studyTitle, studyIdOut, errorMessageOut)) { @@ -862,14 +852,8 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, /** * Login to BALSA and request a study ID from a study title. * - * @param databaseURL - * URL of the database. - * @param username - * Username for logging in. - * @param password - * Password for logging in. * @param studyTitle - * The study's titlee. + * The study's title. * @param studyIdOut * Output containing the study ID. * @param errorMessageOut @@ -878,29 +862,10 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& databaseURL, * True if processing was successful, else false. */ bool -BalsaDatabaseManager::getUserRoles(const AString& databaseURL, - const AString& username, - const AString& password, - AString& roleNamesOut, +BalsaDatabaseManager::getUserRoles(AString& roleNamesOut, AString& errorMessageOut) { - /* - * Login - */ - const AString loginURL(databaseURL - + "/j_spring_security_check"); - if ( ! login(loginURL, - username, - password, - errorMessageOut)) { - - return false; - } - - CaretLogInfo("SESSION ID from BALSA Login: " - + getJSessionIdCookie()); - - if ( ! requestUserRoles(databaseURL, + if ( ! requestUserRoles(m_databaseURL, roleNamesOut, errorMessageOut)) { return false; @@ -911,14 +876,8 @@ BalsaDatabaseManager::getUserRoles(const AString& databaseURL, /** - * Login to BALSA and request a study ID from a study title. + * Request study information. * - * @param databaseURL - * URL of the database. - * @param username - * Username for logging in. - * @param password - * Password for logging in. * @param studyInformationOut * Output containing information for all of the user's studies. * @param errorMessageOut @@ -927,37 +886,13 @@ BalsaDatabaseManager::getUserRoles(const AString& databaseURL, * True if processing was successful, else false. */ bool -BalsaDatabaseManager::getAllStudyInformationForUser(const AString& databaseURL, - const AString& username, - const AString& password, - std::vector& studyInformationOut, - AString& errorMessageOut) +BalsaDatabaseManager::getAllStudyInformation(std::vector& studyInformationOut, + AString& errorMessageOut) { studyInformationOut.clear(); errorMessageOut = ""; - /* - * Login - */ - const AString loginURL(databaseURL - + "/j_spring_security_check"); - if ( ! login(loginURL, - username, - password, - errorMessageOut)) { - - return false; - } - - if (m_debugFlag) { - std::cout << "SESSION ID from BALSA Login: " << getJSessionIdCookie() << std::endl; - } - else { - CaretLogInfo("SESSION ID from BALSA Login: " - + getJSessionIdCookie()); - } - - const AString studyIdURL(databaseURL + const AString studyIdURL(m_databaseURL + "/study/mine"); errorMessageOut.clear(); @@ -1066,12 +1001,6 @@ BalsaDatabaseManager::getAllStudyInformationForUser(const AString& databaseURL, * Login to BALSA, zip the scene and data files, and upload the * ZIP file to BALSA. * - * @param databaseURL - * URL of the database. - * @param username - * Username for logging in. - * @param password - * Password for logging in. * @param sceneFile * Name of scene file. * @param zipFileName @@ -1084,13 +1013,10 @@ BalsaDatabaseManager::getAllStudyInformationForUser(const AString& databaseURL, * True if processing was successful, else false. */ bool -BalsaDatabaseManager::uploadZippedSceneFile(const AString& databaseURL, - const AString& username, - const AString& password, - const SceneFile* sceneFile, - const AString& zipFileName, - const AString& extractToDirectoryName, - AString& errorMessageOut) +BalsaDatabaseManager::uploadZippedSceneFile(const SceneFile* sceneFile, + const AString& zipFileName, + const AString& extractToDirectoryName, + AString& errorMessageOut) { errorMessageOut.clear(); @@ -1140,22 +1066,6 @@ BalsaDatabaseManager::uploadZippedSceneFile(const AString& databaseURL, "Logging in..."); EventManager::get()->sendEvent(progressUpdate.getPointer()); - /* - * Login - */ - const AString loginURL(databaseURL - + "/j_spring_security_check"); - if ( ! login(loginURL, - username, - password, - errorMessageOut)) { - - return false; - } - - CaretLogInfo("SESSION ID from BALSA Login: " - + getJSessionIdCookie()); - progressUpdate.setProgress(PROGRESS_ZIPPING, "Zipping Scene and Data Files"); EventManager::get()->sendEvent(progressUpdate.getPointer()); @@ -1178,7 +1088,7 @@ BalsaDatabaseManager::uploadZippedSceneFile(const AString& databaseURL, * Upload the ZIP file */ AString uploadResultText; - const AString uploadURL(databaseURL + const AString uploadURL(m_databaseURL + "/study/handleUpload/" + sceneFile->getBalsaStudyID()); const bool uploadSuccessFlag = uploadFile(uploadURL, @@ -1201,7 +1111,7 @@ BalsaDatabaseManager::uploadZippedSceneFile(const AString& databaseURL, progressUpdate.setProgress(PROGRESS_PROCESS_UPLOAD, "Processing uploaded zip file"); EventManager::get()->sendEvent(progressUpdate.getPointer()); - const AString processUploadURL(databaseURL + const AString processUploadURL(m_databaseURL + "/study/processUpload/" + sceneFile->getBalsaStudyID()); AString processUploadResultText; diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index 1ebfcac06..defe92adc 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -36,29 +36,24 @@ namespace caret { virtual ~BalsaDatabaseManager(); - bool getAllStudyInformationForUser(const AString& databaseURL, - const AString& username, - const AString& password, - std::vector& studyInformationOut, - AString& errorMessageOut); - - bool getUserRoles(const AString& databaseURL, - const AString& username, - const AString& password, - AString& roleNamesOut, + bool login(const AString& databaseURL, + const AString& username, + const AString& password, + AString& errorMessageOut); + + void logout(); + + bool getAllStudyInformation(std::vector& studyInformationOut, + AString& errorMessageOut); + + bool getUserRoles(AString& roleNamesOut, AString& errorMessageOut); - bool getStudyIDFromStudyTitle(const AString& databaseURL, - const AString& username, - const AString& password, - const AString& studyTitle, + bool getStudyIDFromStudyTitle(const AString& studyTitle, AString& studyIdOut, AString& errorMessageOut); - bool uploadZippedSceneFile(const AString& databaseURL, - const AString& username, - const AString& password, - const SceneFile* sceneFile, + bool uploadZippedSceneFile(const SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, AString& errorMessageOut); @@ -79,11 +74,6 @@ namespace caret { BalsaDatabaseManager& operator=(const BalsaDatabaseManager&); - bool login(const AString& loginURL, - const AString& username, - const AString& password, - AString& errorMessageOut); - AString getJSessionIdCookie() const; bool uploadFile(const AString& uploadURL, @@ -116,6 +106,9 @@ namespace caret { const AString& responseContent, const int32_t responseHttpCode, AString& errorMessageOut) const; + + AString m_databaseURL; + AString m_username; AString m_password; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 9ebd3ae34..ad2ae8105 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -24,6 +24,7 @@ #undef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ #include +#include #include #include #include @@ -54,6 +55,7 @@ #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" +#include "WuQWidgetDisabler.h" using namespace caret; @@ -81,17 +83,25 @@ m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); - QTabWidget* tabWidget = new QTabWidget(); - tabWidget->addTab(createUploadTab(), "Upload"); - tabWidget->addTab(createAdvancedTab(), "Advanced"); + QWidget* loginWidget = createLoginWidget(); + m_uploadWidget = createUploadWidget(); + m_uploadWidget->setEnabled(false); - setCentralWidget(tabWidget, + QWidget* dialogWidget = new QWidget(); + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addWidget(loginWidget); + dialogLayout->addWidget(m_uploadWidget); + + setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); - validateData(); + loginInformationChanged(); setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + + setOkButtonText(""); + setCancelButtonText("Close"); } /** @@ -102,10 +112,24 @@ BalsaDatabaseUploadSceneFileDialog::~BalsaDatabaseUploadSceneFileDialog() } /** - * @return New instance of the upload tab. + * Called when the Cancel button (we have changed text + * to Close) is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() +{ + /* + * Will logout of database and disable part of dialog + */ + loginInformationChanged(); +} + + +/** + * @return The login widget */ QWidget* -BalsaDatabaseUploadSceneFileDialog::createUploadTab() +BalsaDatabaseUploadSceneFileDialog::createLoginWidget() { QString defaultUserName = "balsaTest"; QString defaultPassword = "@2password"; @@ -119,7 +143,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() * Create the BALSA database manager */ m_balsaDatabaseManager = std::unique_ptr(new BalsaDatabaseManager()); - + /* * Database selection */ @@ -129,6 +153,10 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_databaseComboBox->addItem("https://balsa.wustl.edu"); m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); + QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), + this, [=] { this->loginInformationChanged(); }); + QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, + this, [=] { this->loginInformationChanged(); }); const int minimumLineEditWidth = 250; @@ -141,7 +169,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_usernameLineEdit->setText(defaultUserName); m_usernameLineEdit->setValidator(createValidator(LabelName::LABEL_USERNAME)); QObject::connect(m_usernameLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->loginInformationChanged(); }); /* * Password @@ -153,7 +181,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_passwordLineEdit->setText(defaultPassword); m_passwordLineEdit->setValidator(createValidator(LabelName::LABEL_PASSWORD)); QObject::connect(m_passwordLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->loginInformationChanged(); }); /* * Forgot username label/link @@ -182,6 +210,77 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QObject::connect(registerLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); + /* + * Login push button + */ + m_loginPushButton = new QPushButton("Login"); + QObject::connect(m_loginPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::loginButtonClicked); + + int columnCounter = 0; + const int COLUMN_LABEL = columnCounter++; + const int COLUMN_DATA_WIDGET = columnCounter++; + const int COLUMN_BUTTON_ONE = columnCounter++; + const int COLUMN_BUTTON_TWO = columnCounter++; + + QGroupBox* groupBox = new QGroupBox("Database Login"); + QGridLayout* gridLayout = new QGridLayout(groupBox); + gridLayout->setSpacing(2); + gridLayout->setColumnStretch(COLUMN_LABEL, 0); + gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); + gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); + gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); + int row = 0; + gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE, 1, 2); + row++; + gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE, 1, 2); + row++; + gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET); + gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE, 1, 2); + row++; + gridLayout->setRowMinimumHeight(row, 10); // empty row + row++; + gridLayout->addWidget(m_loginPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignLeft); + + return groupBox; +} + +/** + * Called when login information (database, username, password) is changed + */ +void +BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() +{ + m_balsaDatabaseManager->logout(); + m_uploadWidget->setEnabled(false); + updateAllLabels(); +} + +/** + * @return The upload widget + */ +QWidget* +BalsaDatabaseUploadSceneFileDialog::createUploadWidget() +{ + QTabWidget* tabWidget = new QTabWidget(); + tabWidget->addTab(createUploadTab(), "Upload"); + tabWidget->addTab(createAdvancedTab(), "Advanced"); + + return tabWidget; +} + + +/** + * @return New instance of the upload tab. + */ +QWidget* +BalsaDatabaseUploadSceneFileDialog::createUploadTab() +{ /* * Extract to directory */ @@ -193,7 +292,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_extractDirectoryNameLineEdit->setToolTip("Directory that is created when user unzips the ZIP file"); m_extractDirectoryNameLineEdit->setText(defaultExtractDirectoryName); QObject::connect(m_extractDirectoryNameLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->validateUploadData(); }); /* @@ -206,7 +305,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyIDLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_ID)); m_balsaStudyIDLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyIDLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->validateUploadData(); }); /* * Scene BALSA Study Title @@ -217,7 +316,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyTitleLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_TITLE)); m_balsaStudyTitleLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyTitleLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->validateUploadData(); }); /** * Select Study Push Button @@ -235,7 +334,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_baseDirectoryLineEdit->setToolTip("Directory that contains all data files"); m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::LABEL_BASE_DIRECTORY)); QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); + this, [=] { this->validateUploadData(); }); /* * Browse for base directory @@ -261,6 +360,22 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QObject::connect(rolesPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); + /* + * Auto-save checkbox + */ + m_autoSaveSceneFileCheckBox = new QCheckBox("Auto-Save Scene File"); + m_autoSaveSceneFileCheckBox->setChecked(true); + QObject::connect(m_autoSaveSceneFileCheckBox, &QCheckBox::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked); + + /* + * Upload push button + */ + m_uploadPushButton = new QPushButton("Upload"); + QObject::connect(m_uploadPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked); + + int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_DATA_WIDGET = columnCounter++; @@ -270,23 +385,12 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); gridLayout->setSpacing(2); + gridLayout->setColumnMinimumWidth(COLUMN_DATA_WIDGET, 300); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; - gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE, 1, 2); - row++; - gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE, 1, 2); - row++; - gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE, 1, 2); - row++; gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); row++; @@ -302,6 +406,13 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(rolesPushButton, row, COLUMN_BUTTON_ONE, 1, 2); + row++; + gridLayout->addWidget(m_autoSaveSceneFileCheckBox, row, COLUMN_DATA_WIDGET, 1, 3, Qt::AlignLeft); + row++; + gridLayout->setRowMinimumHeight(row, 10); // empty row + row++; + gridLayout->addWidget(m_uploadPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignLeft); + row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); @@ -398,7 +509,7 @@ BalsaDatabaseUploadSceneFileDialog::labelHtmlLinkClicked(const QString& linkPath void BalsaDatabaseUploadSceneFileDialog::zipFileDirectoryRadioButtonClicked(int) { - validateData(); + validateUploadData(); } /** @@ -445,10 +556,42 @@ BalsaDatabaseUploadSceneFileDialog::getZipFileNameWithPath(AString& errorMessage } /** - * Gets called when the OK button is clicked. + * Gets called when the login button is clicked. */ void -BalsaDatabaseUploadSceneFileDialog::okButtonClicked() +BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() +{ + const AString username = m_usernameLineEdit->text().trimmed(); + const AString password = m_passwordLineEdit->text().trimmed(); + + m_uploadWidget->setEnabled(false); + + CursorDisplayScoped cursor; + cursor.showWaitCursor(); + + /* + * If operation takes a while + */ + WuQWidgetDisabler blocker(m_loginPushButton); + + AString errorMessage; + if ( ! m_balsaDatabaseManager->login(getDataBaseURL(), + username, + password, + errorMessage)) { + cursor.restoreCursor(); + WuQMessageBox::errorOk(this, + errorMessage); + } + + m_uploadWidget->setEnabled(true); +} + +/** + * Gets called when the upload button is clicked. + */ +void +BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() { CaretAssert(m_sceneFile); @@ -502,27 +645,30 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); - if (m_sceneFile->isModified()) { - const QString msg("The scene file is modified and must be saved before continuing. Would you like " - "to save the scene file using its current name and continue?"); - if (WuQMessageBox::warningOkCancel(this, msg)) { - try { - Brain* brain = GuiManager::get()->getBrain(); - brain->writeDataFile(m_sceneFile); - } - catch (const DataFileException& e) { - WuQMessageBox::errorOk(this, e.whatString()); - return; - } - } - else { - return; - } + if ( ! saveSceneFile("")) { + return; } +// if (m_sceneFile->isModified()) { +// const QString msg("The scene file is modified and must be saved before continuing. Would you like " +// "to save the scene file using its current name and continue?"); +// if (WuQMessageBox::warningOkCancel(this, msg)) { +// try { +// Brain* brain = GuiManager::get()->getBrain(); +// brain->writeDataFile(m_sceneFile); +// } +// catch (const DataFileException& e) { +// WuQMessageBox::errorOk(this, e.whatString()); +// return; +// } +// } +// else { +// return; +// } +// } CursorDisplayScoped cursor; cursor.showWaitCursor(); - + ProgressReportingDialog progressDialog("Upload Scene File to BALSA", "", this); @@ -530,13 +676,10 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() progressDialog.setCancelButton((QPushButton*)0); // no cancel button AString errorMessage; - const bool successFlag = m_balsaDatabaseManager->uploadZippedSceneFile(getDataBaseURL(), - username, - password, - m_sceneFile, - zipFileName, - extractToDirectoryName, - errorMessage); + const bool successFlag = m_balsaDatabaseManager->uploadZippedSceneFile(m_sceneFile, + zipFileName, + extractToDirectoryName, + errorMessage); cursor.restoreCursor(); @@ -551,7 +694,58 @@ BalsaDatabaseUploadSceneFileDialog::okButtonClicked() return; } - WuQDialogModal::okButtonClicked(); + WuQDialogModal::okButtonClicked(); +} + +/** + * Save the scene file if it is modified. If auto-save is OFF, the user is + * prompted to confirm saving. + * + * @param message + * Message containing reason for saving scene file. If empty, the + * default "file has been modified and must be saved" message is displayed. + * @return + * True if the scene file was saved successfully, else false. + */ +bool +BalsaDatabaseUploadSceneFileDialog::saveSceneFile(const AString& saveMessage) +{ + if (m_sceneFile->isModified()) { + if ( ! m_autoSaveSceneFileCheckBox->isChecked()) { + QString msg("The scene file is modified and must be saved before continuing. Would you like " + "to save the scene file using its current name and continue?"); + if ( ! saveMessage.isEmpty()) { + msg = saveMessage; + } + + if ( ! WuQMessageBox::warningOkCancel(this, msg)) { + return false; + } + + } + try { + Brain* brain = GuiManager::get()->getBrain(); + brain->writeDataFile(m_sceneFile); + } + catch (const DataFileException& e) { + WuQMessageBox::errorOk(this, e.whatString()); + return false; + } + } + + return true; +} + +/** + * Gets called when auto save checkbox is checked. + * + * @param checked + * Check status + */ +void +BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked(bool /*checked*/) +{ + } void @@ -563,15 +757,14 @@ BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked() AString roleNames; AString errorMessage; - if ( ! m_balsaDatabaseManager->getUserRoles(getDataBaseURL(), - username, - password, - roleNames, + if ( ! m_balsaDatabaseManager->getUserRoles(roleNames, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } + + std::cout << "*** Role Names: " << roleNames << std::endl; } /** @@ -591,11 +784,8 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() CursorDisplayScoped cursor; cursor.showWaitCursor(); AString errorMessage; - if ( ! m_balsaDatabaseManager->getAllStudyInformationForUser(getDataBaseURL(), - username, - password, - studyInfo, - errorMessage)) { + if ( ! m_balsaDatabaseManager->getAllStudyInformation(studyInfo, + errorMessage)) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, errorMessage); @@ -619,7 +809,7 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() m_balsaStudyIDLineEdit->setText(bsi.getStudyID()); m_balsaStudyTitleLineEdit->setText(bsi.getStudyTitle()); } - validateData(); + validateUploadData(); } } @@ -661,7 +851,7 @@ BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicke m_zipFileCustomDirectoryRadioButton->setChecked(true); } - validateData(); + validateUploadData(); } /** @@ -696,7 +886,7 @@ BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() * Set name of new scene file and add to brain */ m_baseDirectoryLineEdit->setText(newDirectoryName); - validateData(); + validateUploadData(); } /** @@ -748,11 +938,11 @@ BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) * Called by validators. */ void -BalsaDatabaseUploadSceneFileDialog::validateData() +BalsaDatabaseUploadSceneFileDialog::validateUploadData() { updateAllLabels(); - m_selectStudyTitlePushButton->setEnabled(m_usernameLineEdit->hasAcceptableInput() - && (m_passwordLineEdit->hasAcceptableInput())); +// m_selectStudyTitlePushButton->setEnabled(m_usernameLineEdit->hasAcceptableInput() +// && (m_passwordLineEdit->hasAcceptableInput())); } /** @@ -873,7 +1063,7 @@ BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked() * Set name for base directory */ m_baseDirectoryLineEdit->setText(baseDirectoryName); - validateData(); + validateUploadData(); } diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 7414f6bec..299d167c6 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -27,6 +27,7 @@ #include "WuQDialogModal.h" +class QCheckBox; class QComboBox; class QLabel; class QLineEdit; @@ -52,11 +53,18 @@ namespace caret { // ADD_NEW_METHODS_HERE private slots: + + void loginInformationChanged(); + + void loginButtonClicked(); + + void uploadButtonClicked(); + void labelHtmlLinkClicked(const QString&); void browseBaseDirectoryPushButtonClicked(); - void validateData(); + void validateUploadData(); void selectStudyTitleButtonClicked(); @@ -68,8 +76,11 @@ namespace caret { void rolesButtonClicked(); + void autoSaveCheckBoxClicked(bool checked); + + virtual void cancelButtonClicked(); + protected: - virtual void okButtonClicked(); private: enum class LabelName { @@ -86,6 +97,10 @@ namespace caret { BalsaDatabaseUploadSceneFileDialog& operator=(const BalsaDatabaseUploadSceneFileDialog&); + QWidget* createLoginWidget(); + + QWidget* createUploadWidget(); + QWidget* createUploadTab(); QWidget* createAdvancedTab(); @@ -102,10 +117,14 @@ namespace caret { void setLabelText(const LabelName labelName); + bool saveSceneFile(const AString& saveMesage); + SceneFile* m_sceneFile; std::unique_ptr m_balsaDatabaseManager; + QWidget* m_uploadWidget; + QLabel* m_databaseLabel; QComboBox* m_databaseComboBox; @@ -115,6 +134,8 @@ namespace caret { QLabel* m_passwordLabel; QLineEdit* m_passwordLineEdit; + QPushButton* m_loginPushButton; + QRadioButton* m_zipFileTemporaryDirectoryRadioButton; QRadioButton* m_zipFileCustomDirectoryRadioButton; QLineEdit* m_zipFileCustomDirectoryLineEdit; @@ -135,6 +156,9 @@ namespace caret { QLabel* m_baseDirectoryLabel; QLineEdit* m_baseDirectoryLineEdit; + QCheckBox* m_autoSaveSceneFileCheckBox; + QPushButton* m_uploadPushButton; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BalsaStudySelectionDialog.cxx b/src/GuiQt/BalsaStudySelectionDialog.cxx index e8f12582a..a2ea71b30 100644 --- a/src/GuiQt/BalsaStudySelectionDialog.cxx +++ b/src/GuiQt/BalsaStudySelectionDialog.cxx @@ -228,12 +228,9 @@ BalsaStudySelectionDialog::newStudyButtonClicked() title = title.trimmed(); AString studyID; AString errorMessage; - const bool successFlag = m_balsaDatabaseManager->getStudyIDFromStudyTitle(m_databaseURL, - m_balsaUsername, - m_balsaPassword, - title, - studyID, - errorMessage); + const bool successFlag = m_balsaDatabaseManager->getStudyIDFromStudyTitle(title, + studyID, + errorMessage); if (successFlag) { const AString titleLower = title.toLower(); diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index aeceab454..5d2d0528c 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -202,6 +202,7 @@ ELSE() WuQTrueFalseComboBox.h #WuQWebView.h WuQWidget.h + WuQWidgetDisabler.h WuQWidgetObjectGroup.h ZipSceneFileDialog.h ) @@ -430,6 +431,7 @@ WuQTreeWidget.h WuQTrueFalseComboBox.h #WuQWebView.h WuQWidget.h +WuQWidgetDisabler.h WuQWidgetObjectGroup.h WuQtUtilities.h ZipSceneFileDialog.h @@ -643,6 +645,7 @@ WuQTreeWidget.cxx WuQTrueFalseComboBox.cxx #WuQWebView.cxx WuQWidget.cxx +WuQWidgetDisabler.cxx WuQWidgetObjectGroup.cxx WuQtUtilities.cxx ZipSceneFileDialog.cxx -- GitLab From b5ccba75d1c63c1123501456394355d98048ee84 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 2 Oct 2017 15:49:59 -0500 Subject: [PATCH 421/755] A little cleanup from last balsa related update. --- src/GuiQt/BalsaDatabaseManager.cxx | 2 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 22 ------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index cd765a09d..8d2b5c9bc 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -56,7 +56,7 @@ using namespace caret; BalsaDatabaseManager::BalsaDatabaseManager() : CaretObject() { - m_debugFlag = true; + m_debugFlag = false; logout(); // EventManager::get()->addEventListener(this, EventTypeEnum::); } diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index ad2ae8105..d19de6259 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -648,23 +648,6 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() if ( ! saveSceneFile("")) { return; } -// if (m_sceneFile->isModified()) { -// const QString msg("The scene file is modified and must be saved before continuing. Would you like " -// "to save the scene file using its current name and continue?"); -// if (WuQMessageBox::warningOkCancel(this, msg)) { -// try { -// Brain* brain = GuiManager::get()->getBrain(); -// brain->writeDataFile(m_sceneFile); -// } -// catch (const DataFileException& e) { -// WuQMessageBox::errorOk(this, e.whatString()); -// return; -// } -// } -// else { -// return; -// } -// } CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -777,9 +760,6 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() const AString password = m_passwordLineEdit->text().trimmed(); std::vector studyInfo; -// studyInfo.emplace(studyInfo.end(), "AV4H", "Study One"); -// studyInfo.emplace(studyInfo.end(), "BX32", "Study Two"); -// studyInfo.emplace(studyInfo.end(), "CR33", "Study Three"); CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -941,8 +921,6 @@ void BalsaDatabaseUploadSceneFileDialog::validateUploadData() { updateAllLabels(); -// m_selectStudyTitlePushButton->setEnabled(m_usernameLineEdit->hasAcceptableInput() -// && (m_passwordLineEdit->hasAcceptableInput())); } /** -- GitLab From 780f0ef0269b87f9484aa3a22fa1f5a4f5baad54 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 07:50:00 -0500 Subject: [PATCH 422/755] Hide button for testing of getting roles from BALSA. Fixed close button not closing the dialog. --- src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index d19de6259..5f61bf1f9 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -122,6 +122,8 @@ BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() * Will logout of database and disable part of dialog */ loginInformationChanged(); + + WuQDialogModal::cancelButtonClicked(); } @@ -359,6 +361,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() rolesPushButton->setToolTip("Test getting the user's roles"); QObject::connect(rolesPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); + rolesPushButton->setVisible(false); /* * Auto-save checkbox -- GitLab From 619784fd7652aab07e26a13fbf58e6e308e293bf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 08:24:40 -0500 Subject: [PATCH 423/755] Fixed bug in src/CMakeLists.txt for windows not finding GLEW. --- src/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c23f6e7ac..326dc8374 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -296,9 +296,8 @@ ELSE() SET(GLEW_INCLUDE_DIRS "") IF (WIN32) MESSAGE(SEND_ERROR "GLEW not found and is required on Windows for finding OpenGL functions.\n" - " Setting CMAKE_PREFIX_PATH to the GLEW installation directory when\n" - " running CMAKE may help find GLEW.\n" - " -DCMAKE_PREFIX_PATH=C:\some-path\glew-2.1.0") + " Setting CMAKE_PREFIX_PATH to the GLEW installation directory when\n" + " running CMAKE may help find GLEW.\n") ENDIF() ENDIF() -- GitLab From 1ef5bb8de16ad327a08f80b3f3d20843996e29b4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 08:24:59 -0500 Subject: [PATCH 424/755] Fixed some compilation warnings --- src/Annotations/AnnotationTwoDimensionalShape.cxx | 9 --------- src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx | 4 ---- src/Brain/BrowserTabContent.cxx | 3 --- src/Brain/SurfaceNodeColoring.cxx | 8 ++++---- src/Charting/ChartTwoCompoundDataType.cxx | 3 ++- src/Charting/ChartTwoDataCartesian.cxx | 1 + src/Charting/ChartTwoTitle.cxx | 3 ++- src/Charting/MapFileDataSelector.cxx | 3 ++- src/Files/LabelDrawingProperties.cxx | 3 ++- src/Files/SpecFile.cxx | 4 ++-- src/GuiQt/BrainBrowserWindowToolBar.h | 1 - 11 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index a014b7415..fd8ae0292 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -328,30 +328,21 @@ AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const An bool AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { - bool chartFlag = false; - bool tabWindowFlag = false; - bool stereotaxicFlag = false; - bool surfaceFlag = false; bool viewportFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: - chartFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - stereotaxicFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: - surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: - tabWindowFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: viewportFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: - tabWindowFlag = true; break; } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 5cc691ad3..81d010a0e 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -1204,10 +1204,6 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan */ std::vector volumeSlices; for (int32_t i = 0; i < numVolumes; i++) { - float sliceOpacity = 1.0; - if (i > 0) { - sliceOpacity = m_volumeDrawInfo[i].opacity; - } volumeSlices.push_back(VolumeSlice(m_volumeDrawInfo[i].volumeFile, m_volumeDrawInfo[i].mapIndex, m_volumeDrawInfo[i].opacity)); diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index bbcf1f8e7..194af8aa4 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -4344,8 +4344,6 @@ BrowserTabContent::setBrainModelYokingGroup(const YokingGroupEnum::Enum brainMod return; } - int32_t copyFromTabIndex = -1; - /* * Find another browser tab using the same yoking as 'me' and copy * yoked data from the other browser tab. @@ -4356,7 +4354,6 @@ BrowserTabContent::setBrainModelYokingGroup(const YokingGroupEnum::Enum brainMod BrowserTabContent* btc = *iter; if (btc != this) { if (btc->getBrainModelYokingGroup() == m_brainModelYokingGroup) { - copyFromTabIndex = btc->getTabNumber(); /* * If anything is added, also need to update updateYokedBrowserTabs() */ diff --git a/src/Brain/SurfaceNodeColoring.cxx b/src/Brain/SurfaceNodeColoring.cxx index 8ee163372..ece3087dc 100644 --- a/src/Brain/SurfaceNodeColoring.cxx +++ b/src/Brain/SurfaceNodeColoring.cxx @@ -251,10 +251,10 @@ SurfaceNodeColoring::showBrainordinateHighlightRegionOfInterest(const Brain* bra uint8_t foregroundColorByte[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundSurfaceView(foregroundColorByte); const float foregroundColor[4] = { - foregroundColorByte[0], - foregroundColorByte[1], - foregroundColorByte[2], - 1.0 + static_cast(foregroundColorByte[0]) / 255.0f, + static_cast(foregroundColorByte[1]) / 255.0f, + static_cast(foregroundColorByte[2]) / 255.0, + 1.0f }; const BrainordinateRegionOfInterest* roi = brain->getBrainordinateHighlightRegionOfInterest(); diff --git a/src/Charting/ChartTwoCompoundDataType.cxx b/src/Charting/ChartTwoCompoundDataType.cxx index d3eea9535..4326d4663 100644 --- a/src/Charting/ChartTwoCompoundDataType.cxx +++ b/src/Charting/ChartTwoCompoundDataType.cxx @@ -154,7 +154,8 @@ ChartTwoCompoundDataType::newInstanceForMatrix(const int32_t matrixNumberOfRows, * Object that is copied. */ ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj) -: CaretObject(obj) +: CaretObject(obj), +SceneableInterface(obj) { initializeChartTwoCompoundDataType(); this->copyHelperChartTwoCompoundDataType(obj); diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 1831c33f2..e0d74c47d 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -210,6 +210,7 @@ ChartTwoDataCartesian::clone() const */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataCartesian& obj) : CaretObjectTracksModification(obj), +SceneableInterface(obj), m_dataAxisUnitsX(obj.m_dataAxisUnitsX), m_dataAxisUnitsY(obj.m_dataAxisUnitsY), m_graphicsPrimitiveType(obj.m_graphicsPrimitiveType) diff --git a/src/Charting/ChartTwoTitle.cxx b/src/Charting/ChartTwoTitle.cxx index 67a1225f3..934bb033b 100644 --- a/src/Charting/ChartTwoTitle.cxx +++ b/src/Charting/ChartTwoTitle.cxx @@ -71,7 +71,8 @@ ChartTwoTitle::~ChartTwoTitle() * Object that is copied. */ ChartTwoTitle::ChartTwoTitle(const ChartTwoTitle& obj) -: CaretObjectTracksModification(obj) +: CaretObjectTracksModification(obj), +SceneableInterface(obj) { this->copyHelperChartTwoTitle(obj); } diff --git a/src/Charting/MapFileDataSelector.cxx b/src/Charting/MapFileDataSelector.cxx index 5f035c32f..2f3db8d52 100644 --- a/src/Charting/MapFileDataSelector.cxx +++ b/src/Charting/MapFileDataSelector.cxx @@ -77,7 +77,8 @@ MapFileDataSelector::~MapFileDataSelector() * Object that is copied. */ MapFileDataSelector::MapFileDataSelector(const MapFileDataSelector& obj) -: CaretObject(obj) +: CaretObject(obj), +SceneableInterface(obj) { this->copyHelperMapFileDataSelector(obj); } diff --git a/src/Files/LabelDrawingProperties.cxx b/src/Files/LabelDrawingProperties.cxx index 4eb4a487a..a0d06acbd 100644 --- a/src/Files/LabelDrawingProperties.cxx +++ b/src/Files/LabelDrawingProperties.cxx @@ -60,7 +60,8 @@ LabelDrawingProperties::~LabelDrawingProperties() * Object that is copied. */ LabelDrawingProperties::LabelDrawingProperties(const LabelDrawingProperties& obj) -: CaretObject(obj) +: CaretObject(obj), +SceneableInterface(obj) { initializeInstance(); copyHelper(obj); diff --git a/src/Files/SpecFile.cxx b/src/Files/SpecFile.cxx index fe170457f..e5ec85863 100644 --- a/src/Files/SpecFile.cxx +++ b/src/Files/SpecFile.cxx @@ -896,7 +896,7 @@ SpecFile::readFile(const AString& filenameIn) checkFileReadability(filename); SpecFileSaxReader saxReader(this); - std::auto_ptr parser(XmlSaxParser::createXmlParser()); + std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } @@ -943,7 +943,7 @@ void SpecFile::readFileFromString(const AString& string) { SpecFileSaxReader saxReader(this); - std::auto_ptr parser(XmlSaxParser::createXmlParser()); + std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseString(string, &saxReader); } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index e310cd2c2..a0520ed2e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -417,7 +417,6 @@ namespace caret { friend class BrainBrowserWindowToolBarChartTwoAxes; friend class BrainBrowserWindowToolBarChartTwoOrientation; friend class BrainBrowserWindowToolBarChartTwoAttributes; - friend class BrainBrowserWindowToolBarChartTwoAttributes; friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; -- GitLab From 44f119185fd6d8ada46a0b3abd8f7ff4be4c22a2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 09:30:19 -0500 Subject: [PATCH 425/755] Fix for WB-726: When "Close" was selected from the pop-up toolbar in the menu, it was closing the selected tab, not the tab under the mouse. This has been fixed. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f6a885cd7..7ce9e68a9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1428,7 +1428,7 @@ BrainBrowserWindowToolBar::showTabMenu(const QPoint& pos) insertAtTabIndex); } else if (selectedAction == closeAction) { - closeSelectedTab(); + tabCloseSelected(tabUnderMouseIndex); } else if (selectedAction != NULL) { CaretAssertMessage(0, "Has a new action been added to the menu"); -- GitLab From a00c2d53d8b137998fecf1b1a73db1183c638c50 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 12:48:49 -0500 Subject: [PATCH 426/755] Resolve WB-741 2 charting matrix view issues: Selected row lines cover full width even if triangular matrix view is used; graphics update when matrix view is changed. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 157 +++++++++++++----- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 26 ++- 2 files changed, 133 insertions(+), 50 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 9c4d1cd45..1863b61d6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1227,6 +1227,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() */ updateViewportContentForCharting(chartGraphicsDrawingViewport); + std::vector rowColumnHighlighting; + for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { @@ -1258,10 +1260,34 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() chartOverlay->getMatrixTriangularViewingMode(), cellWidth, cellHeight, - m_zooming); + m_zooming, + rowColumnHighlighting); + } + } + + /* + * Row/column highlighting must be drawn after matrices to that + * the highlights are over any and all displayed matrices + */ + const int32_t numHighlights = static_cast(rowColumnHighlighting.size()); + if (numHighlights > 0) { + for (int32_t ctr = 0; ctr < numHighlights; ctr++) { + MatrixRowColumnHighight* mrch = rowColumnHighlighting[ctr]; + CaretAssert(mrch); + + glPushMatrix(); + glLoadMatrixf(mrch->m_modelViewMatrix); + + BrainOpenGL::setLineWidth(mrch->m_lineWidth); + drawPrimitivePrivate(mrch->m_graphicsPrimitive.get()); + delete mrch; + + glPopMatrix(); } + rowColumnHighlighting.clear(); } } + /* * Draw a matrix chart content. * @@ -1281,7 +1307,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, - const float zooming) + const float zooming, + std::vector& rowColumnHighlightingOut) { GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType); if (matrixPrimitive == NULL) { @@ -1365,72 +1392,112 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT selectedRowColumnDimension, selectedRowIndices, selectedColumnIndices); + + /* + * If true, selected row highlighting will be limited + * to a upper or lower triangular cells when + * triangular display is selected + * Disabled by WB-741 + */ + const bool limitSelectionToTriangularFlag = false; + for (auto rowIndex : selectedRowIndices) { - std::unique_ptr rowOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - rowOutlineData4f->reserveForNumberOfVertices(4); +// std::unique_ptr rowOutlineData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// highlightRGBA)); +// rowOutlineData4f->reserveForNumberOfVertices(4); float minX = 0; float maxX = numberOfColumns; const float minY = numberOfRows - rowIndex - 1; const float maxY = minY + 1.0f; - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxX = rowIndex; /* matrix is symmetric */ - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minX = rowIndex + 1; /* matrix is symmetric */ - break; + if (limitSelectionToTriangularFlag) { + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxX = rowIndex; /* matrix is symmetric */ + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minX = rowIndex + 1; /* matrix is symmetric */ + break; + } } - rowOutlineData4f->addVertex(minX, minY); - rowOutlineData4f->addVertex(maxX, minY); - rowOutlineData4f->addVertex(maxX, maxY); - rowOutlineData4f->addVertex(minX, maxY); const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - BrainOpenGL::setLineWidth(highlightLineWidth); - drawPrimitivePrivate(rowOutlineData4f.get()); +// rowOutlineData4f->addVertex(minX, minY); +// rowOutlineData4f->addVertex(maxX, minY); +// rowOutlineData4f->addVertex(maxX, maxY); +// rowOutlineData4f->addVertex(minX, maxY); +// BrainOpenGL::setLineWidth(highlightLineWidth); +// //drawPrimitivePrivate(rowOutlineData4f.get()); + + GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_LOOP); + rowOutlineData->reserveForNumberOfVertices(4); + rowOutlineData->addVertex(minX, minY, highlightRGBA); + rowOutlineData->addVertex(maxX, minY, highlightRGBA); + rowOutlineData->addVertex(maxX, maxY, highlightRGBA); + rowOutlineData->addVertex(minX, maxY, highlightRGBA); + + float modelViewMatrix[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); + rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(rowOutlineData, + highlightLineWidth, + modelViewMatrix)); } for (auto columnIndex : selectedColumnIndices) { - std::unique_ptr columnOutlineData4f - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, - highlightRGBA)); - columnOutlineData4f->reserveForNumberOfVertices(4); +// std::unique_ptr columnOutlineData4f +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// highlightRGBA)); +// columnOutlineData4f->reserveForNumberOfVertices(4); const float minX = columnIndex; const float maxX = columnIndex + 1; float minY = 0; float maxY = numberOfRows; - switch (chartViewingType) { - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: - maxY = columnIndex; /* matrix is symmetric */ - break; - case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: - minY = columnIndex + 1; /* matrix is symmetric */ - break; + if (limitSelectionToTriangularFlag) { + switch (chartViewingType) { + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: + maxY = columnIndex; /* matrix is symmetric */ + break; + case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: + minY = columnIndex + 1; /* matrix is symmetric */ + break; + } } - columnOutlineData4f->addVertex(minX, minY); - columnOutlineData4f->addVertex(maxX, minY); - columnOutlineData4f->addVertex(maxX, maxY); - columnOutlineData4f->addVertex(minX, maxY); + const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - BrainOpenGL::setLineWidth(highlightLineWidth); - drawPrimitivePrivate(columnOutlineData4f.get()); +// columnOutlineData4f->addVertex(minX, minY); +// columnOutlineData4f->addVertex(maxX, minY); +// columnOutlineData4f->addVertex(maxX, maxY); +// columnOutlineData4f->addVertex(minX, maxY); +// BrainOpenGL::setLineWidth(highlightLineWidth); +// //drawPrimitivePrivate(columnOutlineData4f.get()); + + GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_LOOP); + columnOutlineData->reserveForNumberOfVertices(4); + columnOutlineData->addVertex(minX, minY, highlightRGBA); + columnOutlineData->addVertex(maxX, minY, highlightRGBA); + columnOutlineData->addVertex(maxX, maxY, highlightRGBA); + columnOutlineData->addVertex(minX, maxY, highlightRGBA); + + float modelViewMatrix[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); + rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(columnOutlineData, + highlightLineWidth, + modelViewMatrix)); } } - } + } glDisable(GL_BLEND); glPopMatrix(); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 3208c60b1..b07781640 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -28,6 +28,7 @@ #include "ChartAxisLocationEnum.h" #include "ChartTwoDataTypeEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" +#include "GraphicsPrimitive.h" namespace caret { @@ -42,7 +43,6 @@ namespace caret { class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; - class GraphicsPrimitive; class SelectionItemAnnotation; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLabel; @@ -205,6 +205,21 @@ namespace caret { }; + class MatrixRowColumnHighight { + public: + MatrixRowColumnHighight(GraphicsPrimitive* graphicsPrimitive, + const float lineWidth, + const float modelViewMatrix[16]) + : m_graphicsPrimitive(std::unique_ptr(graphicsPrimitive)), + m_lineWidth(lineWidth) { + for (int32_t i = 0; i < 16; i++) m_modelViewMatrix[i] = modelViewMatrix[i]; + } + + std::unique_ptr m_graphicsPrimitive; + float m_lineWidth; + float m_modelViewMatrix[16]; + }; + BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); BrainOpenGLChartTwoDrawingFixedPipeline& operator=(const BrainOpenGLChartTwoDrawingFixedPipeline&); @@ -216,10 +231,11 @@ namespace caret { void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, - const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, - const float cellWidth, - const float cellHeight, - const float zooming); + const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, + const float cellWidth, + const float cellHeight, + const float zooming, + std::vector& rowColumnHighlightingOut); void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); -- GitLab From b4d2dd5860fd182670aa263fcafbf301c0cdf9bf Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Oct 2017 14:59:38 -0500 Subject: [PATCH 427/755] Resolve WB-704 Yoking of map-based file to row-based file: One can now link a surface/volume overlay to a row-based chart matrix file (scalar data-series) and the selected map and row are synchronized. --- src/Brain/ChartingDataManager.cxx | 2 ++ src/Brain/ModelChartTwo.cxx | 51 +++++++++++++++++++++++++++++++ src/Brain/ModelChartTwo.h | 3 ++ 3 files changed, 56 insertions(+) diff --git a/src/Brain/ChartingDataManager.cxx b/src/Brain/ChartingDataManager.cxx index 584477ee0..18abdca96 100644 --- a/src/Brain/ChartingDataManager.cxx +++ b/src/Brain/ChartingDataManager.cxx @@ -86,6 +86,8 @@ ChartingDataManager::receiveEvent(Event* event) if (modelChartTwo != NULL) { modelChartTwo->loadChartDataForYokedScalarDataSeriesFiles(yokeMapEvent->getMapYokingGroup(), yokeMapEvent->getMapIndex()); + modelChartTwo->selectRowColumnInYokedScalarDataSeriesFileOverlay(yokeMapEvent->getMapYokingGroup(), + yokeMapEvent->getMapIndex()); } } } diff --git a/src/Brain/ModelChartTwo.cxx b/src/Brain/ModelChartTwo.cxx index 57718bed5..bfe04c4e2 100644 --- a/src/Brain/ModelChartTwo.cxx +++ b/src/Brain/ModelChartTwo.cxx @@ -308,6 +308,57 @@ ModelChartTwo::loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEn } } +/** + * Select yoked row/column in scalar data series file's overlay + * + * @param mapYokingGroup + * The map yoking group. + * @param mapIndex + * The map index. + */ +void +ModelChartTwo::selectRowColumnInYokedScalarDataSeriesFileOverlay(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex) +{ + if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { + return; + } + + EventBrowserTabIndicesGetAll tabIndicesEvent; + EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); + const std::vector tabIndices = tabIndicesEvent.getAllBrowserTabIndices(); + + /* + * Find Cifti Scalar Data Series Files in valid Chart Overlays that + * have the matching yoking group + */ + for (auto tabIndex : tabIndices) { + CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + if (m_selectedChartTwoDataType[tabIndex] == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { + ChartTwoOverlaySet* overlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); + CaretAssert(overlaySet); + + const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); + for (int32_t iOverlay = 0; iOverlay < numOverlays; iOverlay++) { + ChartTwoOverlay* overlay = overlaySet->getOverlay(iOverlay); + CaretAssert(overlay); + + if (overlay->isEnabled()) { + if (overlay->getMapYokingGroup() == mapYokingGroup) { + CaretMappableDataFile* mapFile = overlay->getSelectedMapFile(); + if (mapFile != NULL) { + if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { + overlay->setSelectionData(mapFile, mapIndex); + } + } + } + } + } + + } + } +} + /** * Receive an event. * diff --git a/src/Brain/ModelChartTwo.h b/src/Brain/ModelChartTwo.h index d8ed626cc..63f5824a3 100644 --- a/src/Brain/ModelChartTwo.h +++ b/src/Brain/ModelChartTwo.h @@ -77,6 +77,9 @@ namespace caret { void loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex); + void selectRowColumnInYokedScalarDataSeriesFileOverlay(const MapYokingGroupEnum::Enum mapYokingGroup, + const int32_t mapIndex); + virtual OverlaySet* getOverlaySet(const int tabIndex) override; virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; -- GitLab From 51fbd696b3e349c811457f1d244a77931240b630 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 4 Oct 2017 09:27:50 -0500 Subject: [PATCH 428/755] This is a bug fix for WB-731 that was recently resolved. If the Annotation Mode button is clicked and the current mode is Annotation, do not pop up warning dialog suggesting the user lock the aspect ratio. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 32 +++++++++++++++---------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 7ce9e68a9..fdd85099e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -2707,22 +2707,28 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) return; } + EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); + EventManager::get()->sendEvent(getInputModeEvent.getPointer()); + const UserInputModeAbstract::UserInputMode currentMode = getInputModeEvent.getUserInputMode(); + UserInputModeAbstract::UserInputMode inputMode = UserInputModeAbstract::INVALID; if (action == this->modeInputModeAnnotationsAction) { - if ( ( ! m_windowAspectRatioLockedAction->isChecked()) - && ( ! m_tabAspectRatioLockedAction->isChecked()) ) { - const QString msg("" - "Neither Lock Window Aspect nor Lock Tab Aspect " - "are selected. Tab and Window annotations are displayed " - "in percentage coordinates of the tab/window " - "width and height. Locking tab/window aspect ensures that " - "the shape of the tab/window maintains its aspect ratio so " - "that tab/window annotations remain in the correct location. " - ""); - WuQMessageBox::warningOkWithDoNotShowAgain(this, - "lockAspectDoNotShowAgainIdentifier", - msg); + if (currentMode != UserInputModeAbstract::ANNOTATIONS) { + if ( ( ! m_windowAspectRatioLockedAction->isChecked()) + && ( ! m_tabAspectRatioLockedAction->isChecked()) ) { + const QString msg("" + "Neither Lock Window Aspect nor Lock Tab Aspect " + "are selected. Tab and Window annotations are displayed " + "in percentage coordinates of the tab/window " + "width and height. Locking tab/window aspect ensures that " + "the shape of the tab/window maintains its aspect ratio so " + "that tab/window annotations remain in the correct location. " + ""); + WuQMessageBox::warningOkWithDoNotShowAgain(this, + "lockAspectDoNotShowAgainIdentifier", + msg); + } } inputMode = UserInputModeAbstract::ANNOTATIONS; } -- GitLab From 301cd8241a9d329992d68f5983c0a2992a1b8b23 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 4 Oct 2017 14:19:33 -0500 Subject: [PATCH 429/755] Fixed crash when a right-click is selected in annotation mode without an annotation under the cursor. --- src/GuiQt/UserInputModeAnnotationsContextMenu.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index e5f1a72ea..1f857bf35 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -520,6 +520,10 @@ UserInputModeAnnotationsContextMenu::createTurnOnInDisplayGroupMenu() QMenu* UserInputModeAnnotationsContextMenu::createDuplicateTabSpaceAnnotationMenu() { + if (m_annotation == NULL) { + return NULL; + } + EventBrowserTabGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); const std::vector allTabs = tabIndicesEvent.getAllBrowserTabs(); -- GitLab From 0151e93261ddeff5dc5b0b02d42f6a068d4f045f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 5 Oct 2017 09:54:32 -0500 Subject: [PATCH 430/755] Added verification of Submitter Status when user logs into BALSA. --- src/GuiQt/BalsaDatabaseManager.cxx | 141 +++++++++--------- src/GuiQt/BalsaDatabaseManager.h | 7 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 39 ++++- .../BalsaDatabaseUploadSceneFileDialog.h | 3 + src/GuiQt/BalsaUserRoles.cxx | 30 +++- src/GuiQt/BalsaUserRoles.h | 2 + 6 files changed, 136 insertions(+), 86 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 8d2b5c9bc..8d4f1c735 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -718,23 +718,78 @@ BalsaDatabaseManager::requestStudyID(const AString& databaseURL, } /** - * Request the user's roles + * Login to BALSA and request a study ID from a study title. * - * @param databaseURL - * URL for database - * @param roleNamesOut - * Output with names of roles + * @param studyTitle + * The study's titlee. + * @param studyIdOut + * Output containing the study ID. * @param errorMessageOut - * Output with error message + * Contains description of any error(s). * @return - * True if success, else false. + * True if processing was successful, else false. */ bool -BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, - AString& roleNamesOut, - AString& errorMessageOut) +BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& studyTitle, + AString& studyIdOut, + AString& errorMessageOut) { - const AString studyIdURL(databaseURL + if (studyTitle.isEmpty()) { + errorMessageOut = "The study title is empty."; + return false; + } + + if ( ! requestStudyID(m_databaseURL, + studyTitle, + studyIdOut, + errorMessageOut)) { + return false; + } + + return true; +} + +///** +// * Login to BALSA and request a study ID from a study title. +// * +// * @param studyTitle +// * The study's title. +// * @param studyIdOut +// * Output containing the study ID. +// * @param errorMessageOut +// * Contains description of any error(s). +// * @return +// * True if processing was successful, else false. +// */ +//bool +//BalsaDatabaseManager::getUserRoles(AString& roleNamesOut, +// AString& errorMessageOut) +//{ +// if ( ! requestUserRoles(m_databaseURL, +// roleNamesOut, +// errorMessageOut)) { +// return false; +// } +// +// return true; +//} +/** + * Get the User's Roles. + * + * @param userRolesOut + * Output with user's roles. + * @param errorMessageOut + * Contains description of any error(s). + * @return + * True if processing was successful, else false. + */ +bool +BalsaDatabaseManager::getUserRoles(BalsaUserRoles& userRolesOut, + AString& errorMessageOut) +{ + userRolesOut.resetToAllInvalid(); + + const AString studyIdURL(m_databaseURL + "/user/roles"); errorMessageOut.clear(); @@ -809,69 +864,13 @@ BalsaDatabaseManager::requestUserRoles(const AString& databaseURL, return false; } - BalsaUserRoles bsi(jsonDocument.array()); - if (m_debugFlag) { - std::cout << "**** Roles: " << bsi.toString() << std::endl; - } + userRolesOut.parseJson(jsonDocument.array()); - return bsi.isValid(); -} - -/** - * Login to BALSA and request a study ID from a study title. - * - * @param studyTitle - * The study's titlee. - * @param studyIdOut - * Output containing the study ID. - * @param errorMessageOut - * Contains description of any error(s). - * @return - * True if processing was successful, else false. - */ -bool -BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& studyTitle, - AString& studyIdOut, - AString& errorMessageOut) -{ - if (studyTitle.isEmpty()) { - errorMessageOut = "The study title is empty."; - return false; - } - - if ( ! requestStudyID(m_databaseURL, - studyTitle, - studyIdOut, - errorMessageOut)) { - return false; - } - - return true; -} - -/** - * Login to BALSA and request a study ID from a study title. - * - * @param studyTitle - * The study's title. - * @param studyIdOut - * Output containing the study ID. - * @param errorMessageOut - * Contains description of any error(s). - * @return - * True if processing was successful, else false. - */ -bool -BalsaDatabaseManager::getUserRoles(AString& roleNamesOut, - AString& errorMessageOut) -{ - if ( ! requestUserRoles(m_databaseURL, - roleNamesOut, - errorMessageOut)) { - return false; + if (m_debugFlag) { + std::cout << "**** Roles: " << userRolesOut.toString() << std::endl; } - return true; + return userRolesOut.isValid(); } diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index defe92adc..d41f219ff 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -27,6 +27,7 @@ namespace caret { + class BalsaUserRoles; class SceneFile; class BalsaDatabaseManager : public CaretObject, public EventListenerInterface { @@ -46,7 +47,7 @@ namespace caret { bool getAllStudyInformation(std::vector& studyInformationOut, AString& errorMessageOut); - bool getUserRoles(AString& roleNamesOut, + bool getUserRoles(BalsaUserRoles& userRolesOut, AString& errorMessageOut); bool getStudyIDFromStudyTitle(const AString& studyTitle, @@ -92,10 +93,6 @@ namespace caret { AString& studyIDOut, AString& errorMessageOut); - bool requestUserRoles(const AString& databaseURL, - AString& roleNamesOut, - AString& errorMessageOut); - bool uploadFileWithCaretHttpManager(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 5f61bf1f9..19ae306bc 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -40,6 +40,7 @@ #include "BalsaDatabaseManager.h" #include "BalsaStudySelectionDialog.h" +#include "BalsaUserRoles.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" @@ -83,6 +84,8 @@ m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); + m_userRoles.reset(new BalsaUserRoles); + QWidget* loginWidget = createLoginWidget(); m_uploadWidget = createUploadWidget(); m_uploadWidget->setEnabled(false); @@ -260,6 +263,7 @@ BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() { m_balsaDatabaseManager->logout(); m_uploadWidget->setEnabled(false); + m_userRoles->resetToAllInvalid(); updateAllLabels(); } @@ -361,7 +365,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() rolesPushButton->setToolTip("Test getting the user's roles"); QObject::connect(rolesPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); - rolesPushButton->setVisible(false); + //rolesPushButton->setVisible(false); /* * Auto-save checkbox @@ -585,6 +589,34 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() cursor.restoreCursor(); WuQMessageBox::errorOk(this, errorMessage); + return; + } + + if (m_balsaDatabaseManager->getUserRoles(*m_userRoles, + errorMessage)) { + if ( ! m_userRoles->isSubmitter()) { + cursor.restoreCursor(); + const AString msg("Login to BALSA was successful. However, your have not agreed " + "to the BALSA Submission Terms and Conditions that are required " + "to upload data to BALSA. You will need to login to BALSA " + "using your web browser and complete this agreement."); + const bool okPressedFlag = WuQMessageBox::warningAcceptReject(this, + msg, + "OK", + "OK, Go to BALSA in Web Browser"); + if ( ! okPressedFlag) { + labelHtmlLinkClicked("/"); + } + return; + } + } + else { + cursor.restoreCursor(); + const AString msg("Unable to verify that you have agreed to the BALSA " + "Submission Terms and Conditions. If you have not " + "agreed to terms and conditions, uploading will fail.\n\n" + + errorMessage); + WuQMessageBox::warningOk(this, msg); } m_uploadWidget->setEnabled(true); @@ -743,14 +775,15 @@ BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked() AString roleNames; AString errorMessage; - if ( ! m_balsaDatabaseManager->getUserRoles(roleNames, + BalsaUserRoles balsaUserRoles; + if ( ! m_balsaDatabaseManager->getUserRoles(balsaUserRoles, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } - std::cout << "*** Role Names: " << roleNames << std::endl; + std::cout << "*** Role Names: " << balsaUserRoles.toString() << std::endl; } /** diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 299d167c6..510285399 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -37,6 +37,7 @@ class QRegularExpressionValidator; namespace caret { class BalsaDatabaseManager; + class BalsaUserRoles; class SceneFile; class BalsaDatabaseUploadSceneFileDialog : public WuQDialogModal { @@ -136,6 +137,8 @@ namespace caret { QPushButton* m_loginPushButton; + std::unique_ptr m_userRoles; + QRadioButton* m_zipFileTemporaryDirectoryRadioButton; QRadioButton* m_zipFileCustomDirectoryRadioButton; QLineEdit* m_zipFileCustomDirectoryLineEdit; diff --git a/src/GuiQt/BalsaUserRoles.cxx b/src/GuiQt/BalsaUserRoles.cxx index d0576e463..e400a4dfc 100644 --- a/src/GuiQt/BalsaUserRoles.cxx +++ b/src/GuiQt/BalsaUserRoles.cxx @@ -44,7 +44,7 @@ using namespace caret; BalsaUserRoles::BalsaUserRoles() : CaretObject() { - + resetToAllInvalid(); } /** @@ -55,6 +55,7 @@ BalsaUserRoles::BalsaUserRoles() */ BalsaUserRoles::BalsaUserRoles(const QJsonArray& jsonArray) { + resetToAllInvalid(); parseJson(jsonArray); } @@ -108,6 +109,19 @@ BalsaUserRoles::copyHelperBalsaUserRoles(const BalsaUserRoles& obj) m_userFlag = obj.m_userFlag; } +/** + * Reset the instance to all invalid roles. + */ +void +BalsaUserRoles::resetToAllInvalid() +{ + m_validFlag = false; + m_adminFlag = false; + m_curatorFlag = false; + m_submitterFlag = false; + m_userFlag = false; +} + /** * Parse JSON to find roles. * @@ -119,12 +133,14 @@ BalsaUserRoles::copyHelperBalsaUserRoles(const BalsaUserRoles& obj) bool BalsaUserRoles::parseJson(const QJsonArray& jsonArray) { + resetToAllInvalid(); + for (QJsonArray::const_iterator roleIter = jsonArray.begin(); roleIter != jsonArray.end(); roleIter++) { QJsonValue value = *roleIter; if (value.isString()) { - const QString roleName = value.toString(); + const QString roleName = value.toString().trimmed(); if (roleName == "ROLE_ADMIN") { m_adminFlag = true; } @@ -211,11 +227,11 @@ AString BalsaUserRoles::toString() const { AString msg("BalsaUserRoles: " - + AString(m_validFlag ? "Data Valid - YES: " : "Data Valid - NO: ") - + AString(m_adminFlag ? "Admin; " : "") - + AString(m_curatorFlag ? "Curator; " : "") - + AString(m_submitterFlag ? "Submitter; " : "") - + AString(m_userFlag ? "User; " : "")); + + AString("Data Valid - " + AString(m_validFlag ? "YES: " : "NO: ")) + + AString("Admin - " + AString(m_adminFlag ? "YES: " : "NO: ")) + + AString("Curator - " + AString(m_curatorFlag ? "YES: " : "NO: ")) + + AString("Submitter - " + AString(m_submitterFlag ? "YES: " : "NO: ")) + + AString("User - " + AString(m_userFlag ? "YES: " : "NO: "))); return msg; } diff --git a/src/GuiQt/BalsaUserRoles.h b/src/GuiQt/BalsaUserRoles.h index 7b65be338..7ce63ea9e 100644 --- a/src/GuiQt/BalsaUserRoles.h +++ b/src/GuiQt/BalsaUserRoles.h @@ -41,6 +41,8 @@ namespace caret { BalsaUserRoles& operator=(const BalsaUserRoles& obj); + void resetToAllInvalid(); + bool parseJson(const QJsonArray& jsonArray); bool isEmpty() const; -- GitLab From 358398706ae37df40246d4a622d3a1dbcfbb8b9e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 5 Oct 2017 12:15:11 -0500 Subject: [PATCH 431/755] Update for WB-710 Deleting all chart lines from chart history is causing a segfault: Still cannot reproduce crash. It is possible the remove code' could be called a second time before the previous removal finishes. Logic has been added to prevent this. --- src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx index 10629684e..a416b961d 100644 --- a/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx +++ b/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx @@ -142,8 +142,8 @@ MapSettingsChartTwoLineHistoryWidget::MapSettingsChartTwoLineHistoryWidget(QWidg topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2, 1, 2, Qt::AlignLeft); QVBoxLayout* layout = new QVBoxLayout(this); - layout->addLayout(topLayout); - layout->addWidget(m_tableWidget); + layout->addLayout(topLayout, 0); + layout->addWidget(m_tableWidget, 100); } /** @@ -463,6 +463,12 @@ MapSettingsChartTwoLineHistoryWidget::tableWidgetCellChanged(int rowIndex, int c void MapSettingsChartTwoLineHistoryWidget::removeHistoryItemSelected(int rowIndex) { + /* + * May be possible for user to press another remove button + * before this one is finished + */ + const QSignalBlocker removeSignalBlocker(m_removeHistoryItemSignalMapper); + ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); lineSeriesHistory->removeHistoryItem(rowIndex); updateDialogContentPrivate(); -- GitLab From 61a4057a3276eeaf8312829714af133630f7bf5e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 6 Oct 2017 13:04:32 -0500 Subject: [PATCH 432/755] WBN-695 - Base Directory - If the base directory is empty when BALSA upload dialog is displayed, fill it with the result of the 'find base directory'. --- src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 19ae306bc..8a97243d9 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -365,7 +365,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() rolesPushButton->setToolTip("Test getting the user's roles"); QObject::connect(rolesPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); - //rolesPushButton->setVisible(false); + rolesPushButton->setVisible(false); /* * Auto-save checkbox @@ -424,8 +424,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); if (baseDirectory.isEmpty()) { - FileInformation fileInfo(m_sceneFile->getFileName()); - baseDirectory = fileInfo.getPathName(); + baseDirectory = m_sceneFile->findBaseDirectoryForDataFiles(); } m_baseDirectoryLineEdit->setText(baseDirectory); m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); -- GitLab From 9bcf2d2824745a6adb5ea91e5031b564c5cb517b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 6 Oct 2017 14:35:34 -0500 Subject: [PATCH 433/755] On my Mac, I have noticed that non-modal do not always display when the dialog is active, but behind other windows. So, the various display (show) methods were combined into a single method in WuQDialogNonModal::showDialog() and now this method is used. It seems to have corrected this problem. --- src/GuiQt/GuiManager.cxx | 46 ++++++++++----------------------- src/GuiQt/WuQDialogNonModal.cxx | 24 +++++++++++++++-- src/GuiQt/WuQDialogNonModal.h | 2 ++ 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 8d8b8f4ce..70f76389b 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -1603,9 +1603,7 @@ GuiManager::processShowSurfacePropertiesEditorDialog(BrainBrowserWindow* browser m_surfacePropertiesEditorDialog->setSaveWindowPositionForNextTime(true); wasCreatedFlag = true; } - m_surfacePropertiesEditorDialog->setVisible(true); - m_surfacePropertiesEditorDialog->show(); - m_surfacePropertiesEditorDialog->activateWindow(); + m_surfacePropertiesEditorDialog->showDialog(); if (wasCreatedFlag) { WuQtUtilities::moveWindowToSideOfParent(browserWindow, @@ -1692,8 +1690,7 @@ GuiManager::showHideSceneDialog(const bool status, } } - this->sceneDialog->show(); - this->sceneDialog->activateWindow(); + this->sceneDialog->showDialog(); this->sceneDialog->createDefaultSceneFile(); } @@ -1773,9 +1770,7 @@ GuiManager::processShowBugReportDialog(BrainBrowserWindow* browserWindow, this->addNonModalDialog(m_bugReportDialog); } - m_bugReportDialog->setVisible(true); - m_bugReportDialog->show(); - m_bugReportDialog->activateWindow(); + m_bugReportDialog->showDialog(); } /** @@ -1831,8 +1826,7 @@ GuiManager::showHideHelpDialog(const bool status, } } - m_helpViewerDialog->show(); - m_helpViewerDialog->activateWindow(); + m_helpViewerDialog->showDialog(); } else { m_helpViewerDialog->close(); @@ -1953,9 +1947,7 @@ GuiManager::processShowInformationDisplayDialog(const bool forceDisplayOfDialog) if (forceDisplayOfDialog || m_informationDisplayDialogEnabledAction->isChecked()) { if (m_informationDisplayDialog != NULL) { - m_informationDisplayDialog->setVisible(true); - m_informationDisplayDialog->show(); - m_informationDisplayDialog->activateWindow(); + m_informationDisplayDialog->showDialog(); } } } @@ -2018,8 +2010,7 @@ GuiManager::showHideIdentfyBrainordinateDialog(const bool status, } } - m_identifyBrainordinateDialog->show(); - m_identifyBrainordinateDialog->activateWindow(); + m_identifyBrainordinateDialog->showDialog(); } else { m_identifyBrainordinateDialog->close(); @@ -2091,9 +2082,7 @@ GuiManager::processShowClippingPlanesDialog(BrainBrowserWindow* browserWindow) const int32_t browserWindowIndex = browserWindow->getBrowserWindowIndex(); m_clippingPlanesDialog->updateContent(browserWindowIndex); - m_clippingPlanesDialog->setVisible(true); - m_clippingPlanesDialog->show(); - m_clippingPlanesDialog->activateWindow(); + m_clippingPlanesDialog->showDialog(); } @@ -2112,9 +2101,7 @@ GuiManager::processShowCustomViewDialog(BrainBrowserWindow* browserWindow) const int32_t browserWindowIndex = browserWindow->getBrowserWindowIndex(); m_customViewDialog->updateContent(browserWindowIndex); - m_customViewDialog->setVisible(true); - m_customViewDialog->show(); - m_customViewDialog->activateWindow(); + m_customViewDialog->showDialog(); } @@ -2132,9 +2119,7 @@ GuiManager::processShowTileTabsConfigurationDialog(caret::BrainBrowserWindow *br } m_tileTabsConfigurationDialog->updateDialogWithSelectedTileTabsFromWindow(browserWindow); - m_tileTabsConfigurationDialog->setVisible(true); - m_tileTabsConfigurationDialog->show(); - m_tileTabsConfigurationDialog->activateWindow(); + m_tileTabsConfigurationDialog->showDialog(); } /** @@ -2151,9 +2136,7 @@ GuiManager::processShowImageCaptureDialog(BrainBrowserWindow* browserWindow) } this->imageCaptureDialog->updateDialog(); this->imageCaptureDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); - this->imageCaptureDialog->setVisible(true); - this->imageCaptureDialog->show(); - this->imageCaptureDialog->activateWindow(); + this->imageCaptureDialog->showDialog(); } /** @@ -2170,9 +2153,7 @@ GuiManager::processShowGapsAndMarginsDialog(BrainBrowserWindow* browserWindow) } m_gapsAndMarginsDialog->updateDialog(); //m_tabMarginsDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); - m_gapsAndMarginsDialog->setVisible(true); - m_gapsAndMarginsDialog->show(); - m_gapsAndMarginsDialog->activateWindow(); + m_gapsAndMarginsDialog->showDialog(); } /** @@ -2192,6 +2173,7 @@ GuiManager::processShowMovieDialog(BrainBrowserWindow* browserWindow) this->movieDialog->setVisible(true); this->movieDialog->show(); this->movieDialog->activateWindow(); + this->movieDialog->raise(); } @@ -2209,9 +2191,7 @@ GuiManager::processShowPreferencesDialog(BrainBrowserWindow* browserWindow) this->addNonModalDialog(this->preferencesDialog); } this->preferencesDialog->updateDialog(); - this->preferencesDialog->setVisible(true); - this->preferencesDialog->show(); - this->preferencesDialog->activateWindow(); + this->preferencesDialog->showDialog(); } /** diff --git a/src/GuiQt/WuQDialogNonModal.cxx b/src/GuiQt/WuQDialogNonModal.cxx index fc1b8b648..d86fc2768 100644 --- a/src/GuiQt/WuQDialogNonModal.cxx +++ b/src/GuiQt/WuQDialogNonModal.cxx @@ -79,8 +79,28 @@ WuQDialogNonModal::~WuQDialogNonModal() } -/** - * May be called requesting the dialog to update its content +/** + * Show the dialog. + * + * There are a number of methods for 'showing' a Qt dialog. + * Some of them will show the dialog for the first time. + * If the dialog is 'behind' the main window, not all + * of the methods put the dialog in front of the window. + * This methods uses several of the Qt methods to ensure + * that the dialog is moved in front of a main window. + */ +void +WuQDialogNonModal::showDialog() +{ + this->setVisible(true); + this->show(); + this->activateWindow(); + this->raise(); +} + + +/** + * May be called requesting the dialog to update its content * Subclasses should override. */ void diff --git a/src/GuiQt/WuQDialogNonModal.h b/src/GuiQt/WuQDialogNonModal.h index 55548bcac..247f963e0 100644 --- a/src/GuiQt/WuQDialogNonModal.h +++ b/src/GuiQt/WuQDialogNonModal.h @@ -39,6 +39,8 @@ namespace caret { void setCloseButtonText(const AString& text); + void showDialog(); + virtual void updateDialog(); //virtual void updateDialog() = 0; -- GitLab From 59ee407c78c059a2fbedee28e346ab1284a66b6e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 6 Oct 2017 14:37:28 -0500 Subject: [PATCH 434/755] Removed an unused developer flag that was no longer used for enabling new charting. --- src/Common/DeveloperFlagsEnum.cxx | 8 -------- src/Common/DeveloperFlagsEnum.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 1acb5d130..2da2da524 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -95,9 +95,6 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, case DEVELOPER_FLAG_UNUSED: this->flagStatus = false; break; - case DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1: - this->flagStatus = true; - break; } } @@ -122,11 +119,6 @@ DeveloperFlagsEnum::initialize() enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, "DEVELOPER_FLAG_UNUSED", "Developer flag unused")); - - - enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1, - "DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1", - "Draw with New Charting in Window 1")); } /** diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index abcff15da..bb21cda89 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -36,7 +36,6 @@ public: */ enum Enum { DEVELOPER_FLAG_UNUSED, - DEVELOPER_FLAG_NEW_CHARTING_WINDOW_1 }; ~DeveloperFlagsEnum(); -- GitLab From cfa34037035fe42391141c55a71f5340ed48ecb6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Oct 2017 14:52:43 -0500 Subject: [PATCH 435/755] WB-726: Updated pop-up menu to Tim's design. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 37 +-- src/GuiQt/BrainBrowserWindowToolBar.h | 4 +- .../BrainBrowserWindowToolBarTabPopUpMenu.cxx | 298 ++++++++++++++++++ .../BrainBrowserWindowToolBarTabPopUpMenu.h | 91 ++++++ src/GuiQt/CMakeLists.txt | 3 + 5 files changed, 403 insertions(+), 30 deletions(-) create mode 100644 src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx create mode 100644 src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index fdd85099e..59edb0cc2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -66,6 +66,7 @@ #include "BrainBrowserWindowToolBarSliceSelection.h" #include "BrainBrowserWindowToolBarSurfaceMontage.h" #include "BrainBrowserWindowToolBarTab.h" +#include "BrainBrowserWindowToolBarTabPopUpMenu.h" #include "BrainBrowserWindowToolBarVolumeMontage.h" #include "BrainStructure.h" #include "BrowserTabContent.h" @@ -575,7 +576,7 @@ BrainBrowserWindowToolBar::createNewTab(AString& errorMessage) void BrainBrowserWindowToolBar::addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned) { - insertClonedTabContentAtTabBarIndex(browserTabContentToBeCloned, + insertAndCloneTabContentAtTabBarIndex(browserTabContentToBeCloned, -1); } @@ -588,7 +589,7 @@ BrainBrowserWindowToolBar::addNewDuplicatedTab(BrowserTabContent* browserTabCont * Index in the tab bar. If invalid, tab is appended to the end of the toolbar. */ void -BrainBrowserWindowToolBar::insertClonedTabContentAtTabBarIndex(const BrowserTabContent* browserTabContentToBeCloned, +BrainBrowserWindowToolBar::insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* browserTabContentToBeCloned, const int32_t tabBarIndex) { if ( ! allowAddingNewTab()) { @@ -1405,34 +1406,12 @@ BrainBrowserWindowToolBar::closeSelectedTab() void BrainBrowserWindowToolBar::showTabMenu(const QPoint& pos) { - const int tabUnderMouseIndex = this->tabBar->tabAt(pos); + const int tabIndexUnderMouseIndex = this->tabBar->tabAt(pos); - if (tabUnderMouseIndex >= 0) { - const int32_t insertAtTabIndex = tabUnderMouseIndex + 1; - QMenu menu(this->tabBar); - menu.move(mapToGlobal(pos)); - QAction* addAction = menu.addAction("Add New Tab to Right"); - QAction* duplicateAction = menu.addAction("Duplicate This Tab to Right"); - menu.addSeparator(); - QAction* closeAction = menu.addAction("Close This Tab"); - closeAction->setEnabled(this->tabBar->count() > 1); - - const QAction* selectedAction = menu.exec(); - if (selectedAction == addAction) { - insertNewTabAtTabBarIndex(insertAtTabIndex); - } - else if (selectedAction == duplicateAction) { - BrowserTabContent* tabContent = getTabContentFromTab(tabUnderMouseIndex); - CaretAssert(tabContent); - insertClonedTabContentAtTabBarIndex(tabContent, - insertAtTabIndex); - } - else if (selectedAction == closeAction) { - tabCloseSelected(tabUnderMouseIndex); - } - else if (selectedAction != NULL) { - CaretAssertMessage(0, "Has a new action been added to the menu"); - } + if (tabIndexUnderMouseIndex >= 0) { + BrainBrowserWindowToolBarTabPopUpMenu menu(this, + tabIndexUnderMouseIndex); + menu.exec(mapToGlobal(pos)); } else { QMenu menu(this->tabBar); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index a0520ed2e..7d3da91a6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -276,7 +276,7 @@ namespace caret { void tabClosed(int index); void insertNewTabAtTabBarIndex(int32_t tabBarIndex); - void insertClonedTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, + void insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, const int32_t tabBarIndex); BrowserTabContent* createNewTab(AString& errorMessage); @@ -446,6 +446,8 @@ namespace caret { bool m_performingUpdateFlag = false; const int32_t TAB_INDEX_APPEND_TO_TOOLBAR = 10000; + + friend class BrainBrowserWindowToolBarTabPopUpMenu; }; } diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx new file mode 100644 index 000000000..5b00344d5 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx @@ -0,0 +1,298 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ +#include "BrainBrowserWindowToolBarTabPopUpMenu.h" +#undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ + +#include "BrainBrowserWindowToolBar.h" +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::BrainBrowserWindowToolBarTabPopUpMenu + * \brief Pop up (context-sensitive) menu for tab in toolbar to add new tabs + * \ingroup GuiQt + * + * This menu is displayed when the user performs a right-click + * with the mouse over a tab in the brain browswer window toolbar. + * The menu allows users to add/duplicate/remove tabs. + */ + +/** + * Constructor. + * + * @param toolBar + * The toolbar. + * @param tabIndexUnderMouse + * Index of tab over which mouse was clicked + * @param parent + * Optional parent widget. + */ +BrainBrowserWindowToolBarTabPopUpMenu::BrainBrowserWindowToolBarTabPopUpMenu(BrainBrowserWindowToolBar* toolBar, + const int32_t tabIndexUnderMouse, + QWidget* parent) +: QMenu(parent), +m_toolBar(toolBar), +m_tabIndexUnderMouse(tabIndexUnderMouse) +{ + CaretAssert(m_toolBar); + CaretAssert(m_toolBar->tabBar); + + m_numberOfTabs = m_toolBar->tabBar->count(); + m_activeTabIndex = m_toolBar->tabBar->currentIndex(); + + addItem(MenuItem::CREATE_NEW_TAB_BEFORE); + addItem(MenuItem::CREATE_NEW_TAB_AFTER); + addSeparator(); + addItem(MenuItem::DUPLICATE_TAB_AT_BEGINNING); + addItem(MenuItem::DUPLICATE_TAB_BEFORE); + addItem(MenuItem::DUPLICATE_TAB_AFTER); + addItem(MenuItem::DUPLICATE_TAB_AT_END); + addSeparator(); + addItem(MenuItem::MOVE_TAB_TO_BEGINNING); + addItem(MenuItem::MOVE_TAB_BEFORE); + addItem(MenuItem::MOVE_TAB_AFTER); + addItem(MenuItem::MOVE_TAB_TO_END); + addSeparator(); + addItem(MenuItem::DELETE_TAB); + + QObject::connect(this, &QMenu::triggered, + this, &BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected); +} + +/** + * Destructor. + */ +BrainBrowserWindowToolBarTabPopUpMenu::~BrainBrowserWindowToolBarTabPopUpMenu() +{ +} + +/** + * Add an item to the menu. + * + * @param menuItem + * Item to be added to menu. + */ +void +BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem) +{ + + QString thisTabName = "This Tab"; + QString activeTabName = "Active Tab"; + + const bool includeNamesInMenuFlag = false; + if (includeNamesInMenuFlag) { + if (m_tabIndexUnderMouse >= 0) { + thisTabName = ("Tab \"" + m_toolBar->tabBar->tabText(m_tabIndexUnderMouse) + "\""); + } + const int32_t activeTabIndex = m_toolBar->tabBar->currentIndex(); + if (activeTabIndex >= 0) { + activeTabName = ("Tab \"" + m_toolBar->tabBar->tabText(activeTabIndex) + "\""); + } + } + + QString text; + switch (menuItem) { + case MenuItem::NONE: + CaretAssert(0); + break; + case MenuItem::CREATE_NEW_TAB_BEFORE: + text = "Create New Tab Before " + thisTabName; + break; + case MenuItem::CREATE_NEW_TAB_AFTER: + text = "Create New Tab After " + thisTabName; + break; + case MenuItem::DUPLICATE_TAB_AT_BEGINNING: + text = "Duplicate " + thisTabName + " at Beginning"; + break; + case MenuItem::DUPLICATE_TAB_BEFORE: + text = "Duplicate " + thisTabName + " Before " + activeTabName; + break; + case MenuItem::DUPLICATE_TAB_AFTER: + text = "Duplicate " + thisTabName + " After " + activeTabName; + break; + case MenuItem::DUPLICATE_TAB_AT_END: + text = "Duplicate " + thisTabName + " at End"; + break; + case MenuItem::MOVE_TAB_TO_BEGINNING: + text = "Move " + thisTabName + " to Beginning"; + break; + case MenuItem::MOVE_TAB_BEFORE: + text = "Move " + thisTabName + " to Before " + activeTabName; + break; + case MenuItem::MOVE_TAB_AFTER: + text = "Move " + thisTabName + " to After " + activeTabName; + break; + case MenuItem::MOVE_TAB_TO_END: + text = "Move " + thisTabName + " to End"; + break; + case MenuItem::DELETE_TAB: + text = "Delete " + thisTabName; + break; + } + + QAction* action = addAction(text); + action->setData(static_cast(menuItem)); + action->setEnabled(isEnabled(menuItem)); +} + +/** + * Called when a menu item is selected. + * + * @param action + * Action for item in menu that was selected. + */ +void +BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) +{ + if (action != NULL) { + MenuItem menuItem = static_cast(action->data().toInt()); + + CaretAssert(isEnabled(menuItem)); + + int32_t createNewIndex = -1; + int32_t deleteIndex = -1; + int32_t duplicateToIndex = -1; + int32_t moveToIndex = -1; + + switch (menuItem) { + case MenuItem::NONE: + CaretAssert(0); + break; + case MenuItem::CREATE_NEW_TAB_BEFORE: + createNewIndex = m_tabIndexUnderMouse; + break; + case MenuItem::CREATE_NEW_TAB_AFTER: + createNewIndex = m_tabIndexUnderMouse + 1; + break; + case MenuItem::DUPLICATE_TAB_AT_BEGINNING: + duplicateToIndex = 0; + break; + case MenuItem::DUPLICATE_TAB_BEFORE: + duplicateToIndex = m_activeTabIndex; + break; + case MenuItem::DUPLICATE_TAB_AFTER: + duplicateToIndex = m_activeTabIndex + 1; + break; + case MenuItem::DUPLICATE_TAB_AT_END: + duplicateToIndex = m_numberOfTabs; + break; + case MenuItem::MOVE_TAB_TO_BEGINNING: + moveToIndex = 0; + break; + case MenuItem::MOVE_TAB_BEFORE: + moveToIndex = m_activeTabIndex; + break; + case MenuItem::MOVE_TAB_AFTER: + moveToIndex = m_activeTabIndex + 1; + break; + case MenuItem::MOVE_TAB_TO_END: + moveToIndex = m_numberOfTabs; + break; + case MenuItem::DELETE_TAB: + deleteIndex = m_tabIndexUnderMouse; + break; + } + + if (createNewIndex >= 0) { + m_toolBar->insertNewTabAtTabBarIndex(createNewIndex); + } + else if (deleteIndex >= 0) { + m_toolBar->tabCloseSelected(deleteIndex); + } + else if (duplicateToIndex >= 0) { + BrowserTabContent* tabContent = m_toolBar->getTabContentFromTab(m_tabIndexUnderMouse); + CaretAssert(tabContent); + m_toolBar->insertAndCloneTabContentAtTabBarIndex(tabContent, duplicateToIndex); + } + else if (moveToIndex >= 0) { + if (moveToIndex != m_tabIndexUnderMouse) { + m_toolBar->tabBar->moveTab(m_tabIndexUnderMouse, moveToIndex); + } + } + } +} + +/** + * @return True if the menu item is enabled. + * Items are enabled if action would do nothing such as + * moving a tab to itself. + * + * @param item + * Item for testing enabled. + */ +bool +BrainBrowserWindowToolBarTabPopUpMenu::isEnabled(const MenuItem menuItem) const +{ + bool enabledFlag = false; + + BrowserTabContent* tabContent = m_toolBar->getTabContentFromTab(m_tabIndexUnderMouse); + + switch (menuItem) { + case MenuItem::NONE: + CaretAssert(0); + break; + case MenuItem::CREATE_NEW_TAB_BEFORE: + enabledFlag = true; + break; + case MenuItem::CREATE_NEW_TAB_AFTER: + enabledFlag = true; + break; + case MenuItem::DUPLICATE_TAB_AT_BEGINNING: + case MenuItem::DUPLICATE_TAB_BEFORE: + case MenuItem::DUPLICATE_TAB_AFTER: + case MenuItem::DUPLICATE_TAB_AT_END: + if (tabContent != NULL) { + enabledFlag = true; + } + break; + case MenuItem::MOVE_TAB_TO_BEGINNING: + if (m_tabIndexUnderMouse > 0) { + enabledFlag = true; + } + break; + case MenuItem::MOVE_TAB_BEFORE: + if (m_tabIndexUnderMouse != (m_activeTabIndex - 1)) { + enabledFlag = true; + } + break; + case MenuItem::MOVE_TAB_AFTER: + if (m_tabIndexUnderMouse != (m_activeTabIndex + 1)) { + enabledFlag = true; + } + break; + case MenuItem::MOVE_TAB_TO_END: + if (m_tabIndexUnderMouse != (m_numberOfTabs - 1)) { + enabledFlag = true; + } + break; + case MenuItem::DELETE_TAB: + enabledFlag = true; + break; + } + + return enabledFlag; +} + + diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h new file mode 100644 index 000000000..60ed6a911 --- /dev/null +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h @@ -0,0 +1,91 @@ +#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ +#define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include + + + +namespace caret { + + class BrainBrowserWindowToolBar; + + class BrainBrowserWindowToolBarTabPopUpMenu : public QMenu { + Q_OBJECT + + public: + BrainBrowserWindowToolBarTabPopUpMenu(BrainBrowserWindowToolBar* toolBar, + const int32_t tabIndexUnderMouse, + QWidget* parent = 0); + + virtual ~BrainBrowserWindowToolBarTabPopUpMenu(); + + + // ADD_NEW_METHODS_HERE + + private slots: + void menuItemSelected(QAction* action); + + private: + enum class MenuItem { + NONE, + CREATE_NEW_TAB_BEFORE, + CREATE_NEW_TAB_AFTER, + DUPLICATE_TAB_AT_BEGINNING, + DUPLICATE_TAB_BEFORE, + DUPLICATE_TAB_AFTER, + DUPLICATE_TAB_AT_END, + MOVE_TAB_TO_BEGINNING, + MOVE_TAB_BEFORE, + MOVE_TAB_AFTER, + MOVE_TAB_TO_END, + DELETE_TAB + }; + + BrainBrowserWindowToolBarTabPopUpMenu(const BrainBrowserWindowToolBarTabPopUpMenu&); + + BrainBrowserWindowToolBarTabPopUpMenu& operator=(const BrainBrowserWindowToolBarTabPopUpMenu&); + + void addItem(const MenuItem menuItem); + + bool isEnabled(const MenuItem menuItem) const; + + BrainBrowserWindowToolBar* m_toolBar; + + int32_t m_tabIndexUnderMouse; + + int32_t m_numberOfTabs; + + int32_t m_activeTabIndex; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ + // +#endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ + +} // namespace +#endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 5d2d0528c..812069611 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -85,6 +85,7 @@ ELSE() BrainBrowserWindowToolBarSliceSelection.h BrainBrowserWindowToolBarSurfaceMontage.h BrainBrowserWindowToolBarTab.h + BrainBrowserWindowToolBarTabPopUpMenu.h BrainBrowserWindowToolBarVolumeMontage.h BrainOpenGLWidget.h BugReportDialog.h @@ -276,6 +277,7 @@ BrainBrowserWindowToolBarSlicePlane.h BrainBrowserWindowToolBarSliceSelection.h BrainBrowserWindowToolBarSurfaceMontage.h BrainBrowserWindowToolBarTab.h +BrainBrowserWindowToolBarTabPopUpMenu.h BrainBrowserWindowToolBarVolumeMontage.h BrainOpenGLWidget.h BugReportDialog.h @@ -491,6 +493,7 @@ BrainBrowserWindowToolBarSlicePlane.cxx BrainBrowserWindowToolBarSliceSelection.cxx BrainBrowserWindowToolBarSurfaceMontage.cxx BrainBrowserWindowToolBarTab.cxx +BrainBrowserWindowToolBarTabPopUpMenu.cxx BrainBrowserWindowToolBarVolumeMontage.cxx BrainOpenGLWidget.cxx BugReportDialog.cxx -- GitLab From d1a2a8eef566ced31a82e66ea923f4bea0b575c8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Oct 2017 16:14:10 -0500 Subject: [PATCH 436/755] Improvement with WB-748: Corrects display of '-0.0/0.0' in the color bar for the 'zero' value. --- src/Palette/PaletteColorMapping.cxx | 32 ++++++++++++++++++++++++++++- src/Palette/PaletteColorMapping.h | 2 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index eafe3f1ae..4a967f204 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -2196,7 +2196,7 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic if (negativeDataDisplayedFlag && positiveDataDisplayedFlag) { CaretAssert(negativeValuesText.size() > 0); - const AString negMinText = negativeValuesText.back(); + AString negMinText = negativeValuesText.back(); CaretAssert(positiveValuesText.size() > 0); const AString posMinText = positiveValuesText.front(); @@ -2207,6 +2207,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ zeroValueText = negMinText; } + else if (isZeroNumericText(negMinText) + && (isZeroNumericText(posMinText))) { + zeroValueText = "0"; + } else { /* * When the negative min and positive min values are the @@ -2615,6 +2619,10 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ zeroValueText = negMinText; } + else if (isZeroNumericText(negMinText) + && (isZeroNumericText(posMinText))) { + zeroValueText = "0"; + } else { /* * When the negative min and positive min values are the @@ -2739,6 +2747,28 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic } } +/** + * Is the numeric value of the text zero? + * + * @param numericText + * The text with a numeric value + * @return + * True if the text represents zero, else false + */ +bool +PaletteColorMapping::isZeroNumericText(const AString& numericText) const +{ + if ((numericText == "0") + || (numericText == "0.0") + || (numericText == "-0") + || (numericText == "-0.0")) { + return true; + } + + return false; +} + + /** * @return True if thresholding is linked meaning * that the high threshold is restricted to a positive value diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 5207b6952..1c297a87b 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -282,6 +282,8 @@ namespace caret { static const float SMALL_NEGATIVE; private: + bool isZeroNumericText(const AString& numericText) const; + PaletteScaleModeEnum::Enum scaleMode; float autoScalePercentageNegativeMaximum; -- GitLab From b626ff32446bc6ef0429bcaf5709c1ebee863381 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 10:26:03 -0500 Subject: [PATCH 437/755] Clean up commented out code in palette color mapping. --- src/Palette/PaletteColorMapping.cxx | 612 +--------------------------- src/Palette/PaletteColorMapping.h | 7 +- 2 files changed, 4 insertions(+), 615 deletions(-) diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 4a967f204..abc0916bb 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -262,7 +262,6 @@ PaletteColorMapping::initializeMembersPaletteColorMapping() this->thresholdMappedAverageAreaMaximum = 1.0f; this->thresholdDataName = ""; this->thresholdShowFailureInGreen = false; - //this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP; this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; @@ -546,9 +545,6 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, float rightSideRGBA[4]; rightSideScalarColor->getColor(rightSideRGBA); - //addXyRgba(quadsXYZ, quadsRGBA, rightSideScalar, -halfHeight, rightSideRGBA); - //addXyRgba(quadsXYZ, quadsRGBA, rightSideScalar, halfHeight, rightSideRGBA); - /* * Default left side of palette subsection to far left side * and same color as right side of palette subsection @@ -696,241 +692,6 @@ PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, colorBar); } -///** -// * Setup an annotation color bar with its color sections. -// * -// * @param statistics -// * Statistics of data for colorbar. -// * @param colorBar -// * The annotation colorbar that has its color sections set. -// */ -//void -//PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, -// AnnotationColorBar* colorBar) -//{ -// CaretAssert(statistics); -// CaretAssert(colorBar); -// -// colorBar->clearSections(); -// -// const AString paletteName = getSelectedPaletteName(); -// EventPaletteGetByName paletteEvent(paletteName); -// EventManager::get()->sendEvent(paletteEvent.getPointer()); -// const Palette* palette = paletteEvent.getPalette(); -// if (palette == NULL) { -// CaretLogSevere("Unable to find palette named \"" -// + paletteName -// + "\""); -// return; -// } -// -// -// /* -// * Types of values for display -// */ -// const bool isPositiveOnly = (this->displayPositiveDataFlag && ( ! this->displayNegativeDataFlag)); -// const bool isNegativeOnly = (( ! this->displayPositiveDataFlag) && this->displayNegativeDataFlag); -// -// float xMinimum = -1.0; -// float xMaximum = 1.0; -// if (isPositiveOnly) { -// xMinimum = 0.0; -// } -// else if (isNegativeOnly) { -// xMaximum = 0.0; -// } -// -// /* -// * Always interpolate if the palette has only two colors -// */ -// bool interpolateColor = this->interpolatePaletteFlag; -// if (palette->getNumberOfScalarsAndColors() <= 2) { -// interpolateColor = true; -// } -// -// /* -// * Draw the colorbar starting with the color assigned -// * to the negative end of the palette. -// * Colorbar scalars range from -1 to 1. -// */ -// const int iStart = palette->getNumberOfScalarsAndColors() - 1; -// const int iEnd = 1; -// const int iStep = -1; -// for (int i = iStart; i >= iEnd; i += iStep) { -// /* -// * palette data for 'left' side of a color in the palette. -// */ -// const PaletteScalarAndColor* sc = palette->getScalarAndColor(i); -// float scalar = sc->getScalar(); -// float rgba[4]; -// sc->getColor(rgba); -// -// /* -// * palette data for 'right' side of a color in the palette. -// */ -// const PaletteScalarAndColor* nextSC = palette->getScalarAndColor(i - 1); -// float nextScalar = nextSC->getScalar(); -// float nextRGBA[4]; -// nextSC->getColor(nextRGBA); -// const bool isNoneColorFlag = nextSC->isNoneColor(); -// -// /* -// * Exclude negative regions if not displayed. -// */ -// if ( ! this->displayNegativeDataFlag) { -// if (nextScalar < 0.0) { -// continue; -// } -// else if (scalar < 0.0) { -// scalar = 0.0; -// } -// } -// -// /* -// * Exclude positive regions if not displayed. -// */ -// if ( ! this->displayPositiveDataFlag) { -// if (scalar > 0.0) { -// continue; -// } -// else if (nextScalar > 0.0) { -// nextScalar = 0.0; -// } -// } -// -// /* -// * Normally, the first entry has a scalar value of -1. -// * If it does not, use the first color draw from -// * -1 to the first scalar value. -// */ -// if (i == iStart) { -// if ( ! sc->isNoneColor()) { -// if (scalar > -1.0) { -// const float xStart = -1.0; -// const float xEnd = scalar; -// -// colorBar->addSection(xStart, -// xEnd, -// rgba, -// rgba); -// } -// } -// } -// -// /* -// * If the 'next' color is none, drawing -// * is skipped to let the background show -// * throw the 'none' region of the palette. -// */ -// if ( ! isNoneColorFlag) { -// /* -// * left and right region of an entry in the palette -// */ -// const float xStart = scalar; -// const float xEnd = nextScalar; -// -// /* -// * Unless interpolating, use the 'next' color. -// */ -// float* startRGBA = nextRGBA; -// float* endRGBA = nextRGBA; -// if (interpolateColor) { -// startRGBA = rgba; -// } -// -// /* -// * Draw the region in the palette. -// */ -// colorBar->addSection(xStart, -// xEnd, -// startRGBA, -// endRGBA); -// -// /* -// * The last scalar value is normally 1.0. If the last -// * scalar is less than 1.0, then fill in the rest of -// * the palette from the last scalar to 1.0. -// */ -// if (i == iEnd) { -// if (nextScalar < 1.0) { -// const float xStart = nextScalar; -// const float xEnd = 1.0; -// colorBar->addSection(xStart, -// xEnd, -// nextRGBA, -// nextRGBA); -// } -// } -// } -// } -// -// float backgroundRGBA[4]; -// colorBar->getBackgroundColorRGBA(backgroundRGBA); -// -// /* -// * Draw over thresholded regions with background color -// */ -// if (this->thresholdType != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { -// const float minMaxThresholds[2] = { -// getThresholdMinimum(thresholdType), -// getThresholdMaximum(thresholdType) -// }; -// float normalizedThresholds[2]; -// -// mapDataToPaletteNormalizedValues(statistics, -// minMaxThresholds, -// normalizedThresholds, -// 2); -// -// switch (this->thresholdTest) { -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: -// if (normalizedThresholds[0] >= xMinimum) { -// colorBar->addSection(xMinimum, -// normalizedThresholds[0], -// backgroundRGBA, -// backgroundRGBA); -// } -// if (normalizedThresholds[1] < xMaximum) { -// colorBar->addSection(normalizedThresholds[1], -// xMaximum, -// backgroundRGBA, -// backgroundRGBA); -// } -// break; -// case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: -// { -// const float xMin = MathFunctions::limitRange(normalizedThresholds[0], -// xMinimum, -// xMaximum); -// const float xMax = MathFunctions::limitRange(normalizedThresholds[1], -// xMinimum, -// xMaximum); -// if (xMin < xMax) { -// colorBar->addSection(normalizedThresholds[0], -// normalizedThresholds[1], -// backgroundRGBA, -// backgroundRGBA); -// } -// } -// break; -// } -// } -// -// /* -// * If zeros are not displayed, draw a line in the -// * background color at zero in the palette. -// */ -// if ( ! this->displayZeroDataFlag) { -// colorBar->addSection(0.0, 0.0, backgroundRGBA, backgroundRGBA); -// } -// -// /** -// * Add numeric text to the color bar. -// */ -// setupAnnotationColorBarNumericText(statistics, -// colorBar); -//} - /** * Get auto scale percentage negative maximum. * @return Its value. @@ -1942,9 +1703,6 @@ PaletteColorMapping::setupAnnotationColorBarNumericText(const FastStatistics* st getPaletteColorBarScaleText(statistics, colorBarNumericText); -// std::vector > normalizedPositionAndText; -// getPaletteColorBarScaleText(statistics, -// normalizedPositionAndText); for (std::vector::iterator iter = colorBarNumericText.begin(); iter != colorBarNumericText.end(); @@ -1987,9 +1745,9 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic { const int emDash = 0x2014; - const AString positive("(+)"); //"POS"); + const AString positive("(+)"); const AString zero("0"); - const AString negative("(" + QString(QChar(emDash)) + ")"); //"NEG"); + const AString negative("(" + QString(QChar(emDash)) + ")"); if (isDisplayPositiveDataFlag() && isDisplayNegativeDataFlag()) { @@ -2005,9 +1763,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic positive, AnnotationTextAlignHorizontalEnum::RIGHT, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.0, negative)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.5, zero)); -// normalizedPositionAndTextOut.push_back(std::make_pair(1.0, positive)); } else if (isDisplayPositiveDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, @@ -2018,8 +1773,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic positive, AnnotationTextAlignHorizontalEnum::RIGHT, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.0, zero)); -// normalizedPositionAndTextOut.push_back(std::make_pair(1.0, positive)); } else if (isDisplayNegativeDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, @@ -2030,15 +1783,12 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic zero, AnnotationTextAlignHorizontalEnum::CENTER, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.0, negative)); -// normalizedPositionAndTextOut.push_back(std::make_pair(1.0, zero)); } else if (isDisplayZeroDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, zero, AnnotationTextAlignHorizontalEnum::CENTER, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.5, zero)); } return; @@ -2151,7 +1901,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic * Decimal mode integers for percentile */ numericFormatModeForTextFormatting = NumericFormatModeEnum::DECIMAL; - //precisionDigitsForTextFormatting = 0; break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: CaretAssertMessage(0, "Should never get here. Sign only handled above"); @@ -2291,8 +2040,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic negativeValuesText[i], alignment, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(value, -// negativeValuesText[i])); } } @@ -2305,8 +2052,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic zeroValueText, AnnotationTextAlignHorizontalEnum::CENTER, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(0.5, -// zeroValueText)); } /* @@ -2353,8 +2098,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic positiveValuesText[i], alignment, true)); -// normalizedPositionAndTextOut.push_back(std::make_pair(value, -// positiveValuesText[i])); } } @@ -2371,11 +2114,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic AnnotationColorBarNumericText* nt = *iter; nt->setNumericText(nt->getNumericText() + "%"); } -// for (std::vector >::iterator iter = normalizedPositionAndTextOut.begin(); -// iter != normalizedPositionAndTextOut.end(); -// iter++) { -// iter->second.append("%"); -// } break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: break; @@ -2402,351 +2140,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic } } - -/** - * Get the text characters for drawing the scale above the palette - * color bar. - * - * @param statistics - * Statistics for the data. - * @param normalizedPositionAndTextOut, - * Horizontal position ranging 0.0 to 1.0 - * and text values. - */ -void -PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistics, - std::vector >& normalizedPositionAndTextOut) const -{ - normalizedPositionAndTextOut.clear(); - - /* - * Processing for Sign Only Mode - */ - switch (this->colorBarValuesMode) { - case PaletteColorBarValuesModeEnum::DATA: - break; - case PaletteColorBarValuesModeEnum::PERCENTILE: - break; - case PaletteColorBarValuesModeEnum::SIGN_ONLY: - { - const int emDash = 0x2014; - - const AString positive("(+)"); //"POS"); - const AString zero("0"); - const AString negative("(" + QString(QChar(emDash)) + ")"); //"NEG"); - - if (isDisplayPositiveDataFlag() - && isDisplayNegativeDataFlag()) { - normalizedPositionAndTextOut.push_back(std::make_pair(0.0, negative)); - normalizedPositionAndTextOut.push_back(std::make_pair(0.5, zero)); - normalizedPositionAndTextOut.push_back(std::make_pair(1.0, positive)); - } - else if (isDisplayPositiveDataFlag()) { - normalizedPositionAndTextOut.push_back(std::make_pair(0.0, zero)); - normalizedPositionAndTextOut.push_back(std::make_pair(1.0, positive)); - } - else if (isDisplayNegativeDataFlag()) { - normalizedPositionAndTextOut.push_back(std::make_pair(0.0, negative)); - normalizedPositionAndTextOut.push_back(std::make_pair(1.0, zero)); - } - else if (isDisplayZeroDataFlag()) { - normalizedPositionAndTextOut.push_back(std::make_pair(0.5, zero)); - } - - return; - } - break; - } - - - float negMax = -1.0; - float negMin = 0.0; - float posMin = 0.0; - float posMax = 1.0; - switch (getScaleMode()) { - case PaletteScaleModeEnum::MODE_AUTO_SCALE: - { - float dummy; - statistics->getNonzeroRanges(negMax, dummy, dummy, posMax); - } - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: - { - const float maxPct = getAutoScaleAbsolutePercentageMaximum(); - const float minPct = getAutoScaleAbsolutePercentageMinimum(); - - negMax = -statistics->getApproxAbsolutePercentile(maxPct); - negMin = -statistics->getApproxAbsolutePercentile(minPct); - posMin = statistics->getApproxAbsolutePercentile(minPct); - posMax = statistics->getApproxAbsolutePercentile(maxPct); - } - break; - case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: - { - const float negMaxPct = getAutoScalePercentageNegativeMaximum(); - const float negMinPct = getAutoScalePercentageNegativeMinimum(); - const float posMinPct = getAutoScalePercentagePositiveMinimum(); - const float posMaxPct = getAutoScalePercentagePositiveMaximum(); - - negMax = statistics->getApproxNegativePercentile(negMaxPct); - negMin = statistics->getApproxNegativePercentile(negMinPct); - posMin = statistics->getApproxPositivePercentile(posMinPct); - posMax = statistics->getApproxPositivePercentile(posMaxPct); - } - break; - case PaletteScaleModeEnum::MODE_USER_SCALE: - negMax = getUserScaleNegativeMaximum(); - negMin = getUserScaleNegativeMinimum(); - posMin = getUserScalePositiveMinimum(); - posMax = getUserScalePositiveMaximum(); - break; - } - - /* - * numeric values displayed for negative data - */ - std::vector negativeValues; - negativeValues.push_back(negMax); - if (this->colorBarNumericSubdivisionCount > 0) { - const float range = negMin - negMax; - const float interval = range / (this->colorBarNumericSubdivisionCount + 1); - for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { - negativeValues.push_back(negMax - + (interval * (i + 1))); - } - } - negativeValues.push_back(negMin); - - /* - * numeric values displayed for positive data - */ - std::vector positiveValues; - positiveValues.push_back(posMin); - if (this->colorBarNumericSubdivisionCount > 0) { - const float range = posMax - posMin; - const float interval = range / (this->colorBarNumericSubdivisionCount + 1); - for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { - positiveValues.push_back(posMin - + (interval * (i + 1))); - } - } - positiveValues.push_back(posMax); - - /* - * Wil need to override these values when percentile - */ - NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->colorBarNumericFormatMode; - int32_t precisionDigitsForTextFormatting = this->colorBarPrecisionDigits; - - /* - * Processing for percentile mode - * Convert numeric values to percentiles - */ - switch (this->colorBarValuesMode) { - case PaletteColorBarValuesModeEnum::DATA: - break; - case PaletteColorBarValuesModeEnum::PERCENTILE: - for (std::vector::iterator iter = positiveValues.begin(); - iter != positiveValues.end(); - iter++) { - const float percentile = statistics->getPositiveValuePercentile(*iter); - *iter = percentile; - } - for (std::vector::iterator iter = negativeValues.begin(); - iter != negativeValues.end(); - iter++) { - const float percentile = statistics->getNegativeValuePercentile(*iter); - *iter = percentile; - } - - /* - * Decimal mode integers for percentile - */ - numericFormatModeForTextFormatting = NumericFormatModeEnum::DECIMAL; - precisionDigitsForTextFormatting = 0; - break; - case PaletteColorBarValuesModeEnum::SIGN_ONLY: - CaretAssertMessage(0, "Should never get here. Sign only handled above"); - break; - } - - /* - * Create text representations for negative values - */ - const int32_t numberOfNegValues = static_cast(negativeValues.size()); - std::vector negativeValuesText(numberOfNegValues); - NumericTextFormatting::formatValueRange(numericFormatModeForTextFormatting, - precisionDigitsForTextFormatting, - &negativeValues[0], - &negativeValuesText[0], - numberOfNegValues); - - /* - * Create text representations for positive values - */ - const int32_t numberOfPosValues = static_cast(positiveValues.size()); - std::vector positiveValuesText(numberOfPosValues); - NumericTextFormatting::formatValueRange(numericFormatModeForTextFormatting, - precisionDigitsForTextFormatting, - &positiveValues[0], - &positiveValuesText[0], - numberOfPosValues); - - CaretAssert(negativeValues.size() == negativeValuesText.size()); - CaretAssert(positiveValues.size() == positiveValuesText.size()); - - /* - * Types of values for display - */ - const bool positiveDataDisplayedFlag = isDisplayPositiveDataFlag(); - const bool negativeDataDisplayedFlag = isDisplayNegativeDataFlag(); - - /* - * Are both negative and positive values displayed? - */ - AString zeroValueText; - if (negativeDataDisplayedFlag - && positiveDataDisplayedFlag) { - CaretAssert(negativeValuesText.size() > 0); - const AString negMinText = negativeValuesText.back(); - CaretAssert(positiveValuesText.size() > 0); - const AString posMinText = positiveValuesText.front(); - - if (negMinText == posMinText) { - /* - * When the negative min and positive min values are the - * same, there is no need to display both of them. - */ - zeroValueText = negMinText; - } - else if (isZeroNumericText(negMinText) - && (isZeroNumericText(posMinText))) { - zeroValueText = "0"; - } - else { - /* - * When the negative min and positive min values are the - * different, display both an separate with a slash - */ - zeroValueText = negMinText + "/" + posMinText; - } - - /* - * Since the negative min and positive min text values - * are dislayed together by above code, remove these - * values from their respective text values. - */ - negativeValuesText.resize(negativeValuesText.size() - 1); - negativeValues.resize(negativeValues.size() - 1); - CaretAssert(negativeValues.size() == negativeValuesText.size()); - positiveValuesText.erase(positiveValuesText.begin()); - positiveValues.erase(positiveValues.begin()); - CaretAssert(positiveValues.size() == positiveValuesText.size()); - } - - /* - * The positions of the text are normalized in the range zero - * to one where zero is at the left side of the color bar - * and one is at the right side of the color bar. - */ - float negPositionStart = 0.0; - float negPositionInterval = 0.0; - float posPositionStart = 0.0; - float posPositionInterval = 0.0; - if (negativeDataDisplayedFlag - && positiveDataDisplayedFlag) { - negPositionStart = 0.0; - CaretAssert(negativeValuesText.size() > 0); - negPositionInterval = (0.5 / negativeValuesText.size()); - - CaretAssert(positiveValuesText.size() > 0); - posPositionInterval = (0.5 / positiveValuesText.size()); - posPositionStart = 0.5 + posPositionInterval; - } - else if (negativeDataDisplayedFlag) { - negPositionStart = 0.0; - negPositionInterval = 1.0; - if (negativeValuesText.size() > 1) { - CaretAssert(negativeValuesText.size() > 0); - negPositionInterval = (1.0 / (negativeValuesText.size() - 1)); - } - } - else if (positiveDataDisplayedFlag) { - posPositionStart = 0.0; - posPositionInterval = 1.0; - if (positiveValuesText.size() > 1) { - CaretAssert(positiveValuesText.size() > 0); - posPositionInterval = (1.0 / (positiveValuesText.size() - 1)); - } - } - - /* - * Output the negative values text - */ - if (negativeDataDisplayedFlag) { - const int32_t numValues = static_cast(negativeValuesText.size()); - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(negativeValuesText, i); - const float value = (negPositionStart - + (i * negPositionInterval)); - normalizedPositionAndTextOut.push_back(std::make_pair(value, - negativeValuesText[i])); - } - } - - /* - * Add the zero value text - */ - if (negativeDataDisplayedFlag - && positiveDataDisplayedFlag) { - normalizedPositionAndTextOut.push_back(std::make_pair(0.5, - zeroValueText)); - } - - /* - * Add the positive values text - */ - if (positiveDataDisplayedFlag) { - const int32_t numValues = static_cast(positiveValuesText.size()); - for (int32_t i = 0; i < numValues; i++) { - CaretAssertVectorIndex(positiveValuesText, i); - const float value = (posPositionStart - + (i * posPositionInterval)); - normalizedPositionAndTextOut.push_back(std::make_pair(value, - positiveValuesText[i])); - } - } - - /* - * Add percentage signs when percentile is selected - */ - switch (this->colorBarValuesMode) { - case PaletteColorBarValuesModeEnum::DATA: - break; - case PaletteColorBarValuesModeEnum::PERCENTILE: - for (std::vector >::iterator iter = normalizedPositionAndTextOut.begin(); - iter != normalizedPositionAndTextOut.end(); - iter++) { - iter->second.append("%"); - } - break; - case PaletteColorBarValuesModeEnum::SIGN_ONLY: - break; - } - - const bool debugFlag = false; - if (debugFlag) { - const int numItems = static_cast(normalizedPositionAndTextOut.size()); - std::cout << "Colorbar: " << std::endl; - for (int32_t i = 0; i < numItems; i++) { - std::cout << " " << qPrintable(QString::number(normalizedPositionAndTextOut[i].first) - + ": " - + normalizedPositionAndTextOut[i].second) << std::endl; - } - std::cout << std::endl; - } -} - /** * Is the numeric value of the text zero? * @@ -2767,7 +2160,6 @@ PaletteColorMapping::isZeroNumericText(const AString& numericText) const return false; } - /** * @return True if thresholding is linked meaning diff --git a/src/Palette/PaletteColorMapping.h b/src/Palette/PaletteColorMapping.h index 1c297a87b..008b2a066 100644 --- a/src/Palette/PaletteColorMapping.h +++ b/src/Palette/PaletteColorMapping.h @@ -269,9 +269,6 @@ namespace caret { float* normalizedValuesOut, const int64_t numberOfData) const; - void getPaletteColorBarScaleText(const FastStatistics* statistics, - std::vector >& normalizedPositionAndTextOut) const; - void getPaletteColorBarScaleText(const FastStatistics* statistics, std::vector& colorBarNumericTextOut) const; @@ -370,8 +367,8 @@ namespace caret { }; #ifdef __PALETTE_COLOR_MAPPING_DECLARE__ - const float PaletteColorMapping::SMALL_POSITIVE = 0.0; // JWH 24 April 2015 0.00001; - const float PaletteColorMapping::SMALL_NEGATIVE = 0.0; // JWH 24 April 2015 -0.00001; + const float PaletteColorMapping::SMALL_POSITIVE = 0.0; + const float PaletteColorMapping::SMALL_NEGATIVE = 0.0; #endif // __PALETTE_COLOR_MAPPING_DECLARE__ } // namespace -- GitLab From 1b75298c02a4ff5a5fd91d084c32a4d28af203c3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 10:54:38 -0500 Subject: [PATCH 438/755] Corrections for WB-726 New tab insertion: (1) "Move to Before Active" is fixed for when tab being moved is left of active tab; (2) "Move to After Active" is fixed for when tab being moved is to the left of the active tab; (3) "Move to End" is fixed; (4) The active tab remains the active tab after any operation. --- .../BrainBrowserWindowToolBarTabPopUpMenu.cxx | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx index 5b00344d5..5433697d3 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx @@ -167,6 +167,8 @@ void BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) { if (action != NULL) { + const BrowserTabContent* activeTabContent = m_toolBar->getTabContentFromTab(m_activeTabIndex); + MenuItem menuItem = static_cast(action->data().toInt()); CaretAssert(isEnabled(menuItem)); @@ -202,13 +204,23 @@ BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) moveToIndex = 0; break; case MenuItem::MOVE_TAB_BEFORE: - moveToIndex = m_activeTabIndex; + if (m_tabIndexUnderMouse < m_activeTabIndex) { + moveToIndex = m_activeTabIndex - 1; + } + else { + moveToIndex = m_activeTabIndex; + } break; case MenuItem::MOVE_TAB_AFTER: - moveToIndex = m_activeTabIndex + 1; + if (m_tabIndexUnderMouse < m_activeTabIndex) { + moveToIndex = m_activeTabIndex; + } + else { + moveToIndex = m_activeTabIndex + 1; + } break; case MenuItem::MOVE_TAB_TO_END: - moveToIndex = m_numberOfTabs; + moveToIndex = m_numberOfTabs - 1; break; case MenuItem::DELETE_TAB: deleteIndex = m_tabIndexUnderMouse; @@ -231,6 +243,21 @@ BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) m_toolBar->tabBar->moveTab(m_tabIndexUnderMouse, moveToIndex); } } + + /* + * Ensure active tab remains active. Note that number of tabs may have changed. + */ + int32_t updatedActiveTabIndex = -1; + const int32_t numTabs = m_toolBar->tabBar->count(); + for (int32_t iTab = 0; iTab < numTabs; iTab++) { + if (activeTabContent == m_toolBar->getTabContentFromTab(iTab)) { + updatedActiveTabIndex = iTab; + break; + } + } + if (updatedActiveTabIndex >= 0) { + m_toolBar->tabBar->setCurrentIndex(updatedActiveTabIndex); + } } } @@ -273,12 +300,14 @@ BrainBrowserWindowToolBarTabPopUpMenu::isEnabled(const MenuItem menuItem) const } break; case MenuItem::MOVE_TAB_BEFORE: - if (m_tabIndexUnderMouse != (m_activeTabIndex - 1)) { + if ((m_tabIndexUnderMouse != m_activeTabIndex) + && (m_tabIndexUnderMouse != (m_activeTabIndex - 1))) { enabledFlag = true; } break; case MenuItem::MOVE_TAB_AFTER: - if (m_tabIndexUnderMouse != (m_activeTabIndex + 1)) { + if ((m_tabIndexUnderMouse != m_activeTabIndex) + && (m_tabIndexUnderMouse != (m_activeTabIndex + 1))) { enabledFlag = true; } break; -- GitLab From 8674cac46f376d5089f8d0432d263ef3ae6c28bd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 12:15:54 -0500 Subject: [PATCH 439/755] Correction for WB-726 New tab insertion: When a tab is deleted, delete all annotations in tab space that are associated with the tab being deleted. Otherwise, if a new tab is created, it may contain annotations that were for the previously deleted tab. --- src/Brain/CMakeLists.txt | 2 - src/Common/CMakeLists.txt | 2 + .../EventBrowserTabDelete.cxx | 10 +- src/{Brain => Common}/EventBrowserTabDelete.h | 5 +- src/Files/AnnotationFile.cxx | 136 ++++++++++++++---- src/Files/AnnotationFile.h | 7 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 3 +- 7 files changed, 127 insertions(+), 38 deletions(-) rename src/{Brain => Common}/EventBrowserTabDelete.cxx (89%) rename src/{Brain => Common}/EventBrowserTabDelete.h (90%) diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 56758b471..8da1ff6d4 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -77,7 +77,6 @@ DummyFontTextRenderer.h EventAnnotationColorBarGet.h EventBrainReset.h EventBrainStructureGetAll.h -EventBrowserTabDelete.h EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h @@ -224,7 +223,6 @@ DummyFontTextRenderer.cxx EventAnnotationColorBarGet.cxx EventBrainReset.cxx EventBrainStructureGetAll.cxx -EventBrowserTabDelete.cxx EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index dec3db174..8552c39b9 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -97,6 +97,7 @@ DisplayGroupEnum.h ElapsedTimer.h Event.h EventAlertUser.h +EventBrowserTabDelete.h EventBrowserTabIndicesGetAll.h EventCaretPreferencesGet.h EventGetViewportSize.h @@ -195,6 +196,7 @@ DisplayGroupEnum.cxx ElapsedTimer.cxx Event.cxx EventAlertUser.cxx +EventBrowserTabDelete.cxx EventBrowserTabIndicesGetAll.cxx EventCaretPreferencesGet.cxx EventGetViewportSize.cxx diff --git a/src/Brain/EventBrowserTabDelete.cxx b/src/Common/EventBrowserTabDelete.cxx similarity index 89% rename from src/Brain/EventBrowserTabDelete.cxx rename to src/Common/EventBrowserTabDelete.cxx index 2b4f8d148..c341e5f4d 100644 --- a/src/Brain/EventBrowserTabDelete.cxx +++ b/src/Common/EventBrowserTabDelete.cxx @@ -19,7 +19,6 @@ /*LICENSE_END*/ #include "CaretAssert.h" -#include "BrowserTabContent.h" #include "EventBrowserTabDelete.h" using namespace caret; @@ -27,12 +26,13 @@ using namespace caret; /** * Constructor. */ -EventBrowserTabDelete::EventBrowserTabDelete(BrowserTabContent* browserTab) -: Event(EventTypeEnum::EVENT_BROWSER_TAB_DELETE) +EventBrowserTabDelete::EventBrowserTabDelete(BrowserTabContent* browserTab, + const int32_t browserTabIndex) +: Event(EventTypeEnum::EVENT_BROWSER_TAB_DELETE), +m_browserTab(browserTab), +m_browserTabIndex(browserTabIndex) { CaretAssert(browserTab); - m_browserTab = browserTab; - m_browserTabIndex = browserTab->getTabNumber(); } /** diff --git a/src/Brain/EventBrowserTabDelete.h b/src/Common/EventBrowserTabDelete.h similarity index 90% rename from src/Brain/EventBrowserTabDelete.h rename to src/Common/EventBrowserTabDelete.h index 678aac926..d2f717f28 100644 --- a/src/Brain/EventBrowserTabDelete.h +++ b/src/Common/EventBrowserTabDelete.h @@ -33,7 +33,8 @@ namespace caret { class EventBrowserTabDelete : public Event { public: - EventBrowserTabDelete(BrowserTabContent* browserTab); + EventBrowserTabDelete(BrowserTabContent* browserTab, + const int32_t browserTabIndex); virtual ~EventBrowserTabDelete(); @@ -48,7 +49,7 @@ namespace caret { BrowserTabContent* m_browserTab; - int32_t m_browserTabIndex; + const int32_t m_browserTabIndex; }; } // namespace diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index 222cc0bcb..d5e0728c3 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -42,6 +42,7 @@ #include "EventAnnotationAddToRemoveFromFile.h" #include "EventAnnotationGroupGetWithKey.h" #include "EventAnnotationGrouping.h" +#include "EventBrowserTabDelete.h" #include "EventManager.h" #include "GiftiMetaData.h" #include "SceneClass.h" @@ -218,6 +219,7 @@ AnnotationFile::initializeAnnotationFile() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUPING); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); } /** @@ -345,12 +347,12 @@ AnnotationFile::receiveEvent(Event* event) } break; case EventAnnotationAddToRemoveFromFile::MODE_CUT: - if (removeAnnotation(annotation)) { + if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } break; case EventAnnotationAddToRemoveFromFile::MODE_DELETE: - if (removeAnnotation(annotation)) { + if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } break; @@ -370,7 +372,7 @@ AnnotationFile::receiveEvent(Event* event) break; case EventAnnotationAddToRemoveFromFile::MODE_UNCREATE: if (annotationFile == this) { - if (removeAnnotation(annotation)) { + if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } @@ -387,13 +389,13 @@ AnnotationFile::receiveEvent(Event* event) break; case EventAnnotationAddToRemoveFromFile::MODE_UNDUPLICATE: if (annotationFile == this) { - if (removeAnnotation(annotation)) { + if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } case EventAnnotationAddToRemoveFromFile::MODE_UNPASTE: if (annotationFile == this) { - if (removeAnnotation(annotation)) { + if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } @@ -436,6 +438,15 @@ AnnotationFile::receiveEvent(Event* event) } } } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { + EventBrowserTabDelete* deleteEvent = dynamic_cast(event); + CaretAssert(deleteEvent); + + const int32_t tabIndex = deleteEvent->getBrowserTabIndex(); + if (removeAnnotationsInTab(tabIndex)) { + deleteEvent->setEventProcessed(); + } + } } /** @@ -782,9 +793,9 @@ AnnotationFile::restoreAnnotation(Annotation* annotation) } /** - * Remove the annotation. NOTE: The annotation is NOT deleted - * but instead it is saved so that it can be 'undeleted' - * or 're-pasted'. + * Remove the annotation for use with REDO/UNDO. + * NOTE: The annotation is NOT deleted but instead + * it is saved so that it can be 'undeleted' or 're-pasted'. * * @param annotation * Annotation that is removed. @@ -792,9 +803,56 @@ AnnotationFile::restoreAnnotation(Annotation* annotation) * True if the annotation was removed, otherwise false. */ bool -AnnotationFile::removeAnnotation(Annotation* annotation) +AnnotationFile::removeAnnotationWithUndoRedo(Annotation* annotation) { + return removeAnnotationPrivate(annotation, true); + +// for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); +// groupIter != m_annotationGroups.end(); +// groupIter++) { +// QSharedPointer group = *groupIter; +// QSharedPointer removedAnnotationPointer; +// if (group->removeAnnotation(annotation, +// removedAnnotationPointer)) { +// +// removedAnnotationPointer->invalidateAnnotationGroupKey(); +// +// m_removedAnnotations.insert(removedAnnotationPointer); +// +// /* +// * Remove group if it is empty. +// */ +// if (group->isEmpty()) { +// m_annotationGroups.erase(groupIter); +// } +// +// setModified(); +// return true; +// } +// } +// +// /* +// * Annotation not in this file +// */ +// return false; +} + +/** + * Remove the + * + * @param annotation + * Annotation that is removed. + * @param keepAnnotationForUndoRedoFlag + * If true, keep the annotation available for any + * undo or redo operation. + * @return + * True if the annotation was removed, otherwise false. + */ +bool +AnnotationFile::removeAnnotationPrivate(Annotation* annotation, + const bool keepAnnotationForUndoRedoFlag) +{ for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { @@ -805,7 +863,9 @@ AnnotationFile::removeAnnotation(Annotation* annotation) removedAnnotationPointer->invalidateAnnotationGroupKey(); - m_removedAnnotations.insert(removedAnnotationPointer); + if (keepAnnotationForUndoRedoFlag) { + m_removedAnnotations.insert(removedAnnotationPointer); + } /* * Remove group if it is empty. @@ -818,23 +878,6 @@ AnnotationFile::removeAnnotation(Annotation* annotation) return true; } } -// for (AnnotationIterator iter = m_annotations.begin(); -// iter != m_annotations.end(); -// iter++) { -// QSharedPointer& annotationPointer = *iter; -// if (annotationPointer == annotation) { -// m_removedAnnotations.insert(annotationPointer); -// -// m_annotations.erase(iter); -// -// setModified(); -// -// /* -// * Successfully removed -// */ -// return true; -// } -// } /* * Annotation not in this file @@ -842,6 +885,45 @@ AnnotationFile::removeAnnotation(Annotation* annotation) return false; } +/** + * Remove all annotations in tab space in the given tab. + * + * @param tabIndex + * Index of the tab. + * @return + * True if any annotations were removed. + */ +bool +AnnotationFile::removeAnnotationsInTab(const int32_t tabIndex) +{ + std::vector groupsToRemove; + + /* + * Find annotation group(s) in tab space + * with the given tab index. + */ + for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); + groupIter != m_annotationGroups.end(); + groupIter++) { + QSharedPointer& group = *groupIter; + if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { + if (group->getTabOrWindowIndex() == tabIndex) { + groupsToRemove.push_back(groupIter); + } + } + } + + /* + * Remove the groups (shared pointers will do all deleting) + */ + for (auto annGroup : groupsToRemove) { + m_annotationGroups.erase(annGroup); + } + + return ( ! groupsToRemove.empty()); +} + + /** * Get all annotations in this file. * diff --git a/src/Files/AnnotationFile.h b/src/Files/AnnotationFile.h index ecc6f54f0..a4b985972 100644 --- a/src/Files/AnnotationFile.h +++ b/src/Files/AnnotationFile.h @@ -195,7 +195,12 @@ namespace caret { bool restoreAnnotationAddIfNotFound(Annotation* annotation); - bool removeAnnotation(Annotation* annotation); + bool removeAnnotationWithUndoRedo(Annotation* annotation); + + bool removeAnnotationPrivate(Annotation* annotation, + const bool keepAnnotationForUndoRedoFlag); + + bool removeAnnotationsInTab(const int32_t tabIndex); int32_t generateUniqueKey(); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 59edb0cc2..8306e8593 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1546,7 +1546,8 @@ BrainBrowserWindowToolBar::removeTab(int tabIndex) if (p != NULL) { BrowserTabContent* btc = (BrowserTabContent*)p; - EventBrowserTabDelete deleteTabEvent(btc); + EventBrowserTabDelete deleteTabEvent(btc, + btc->getTabNumber()); EventManager::get()->sendEvent(deleteTabEvent.getPointer()); } -- GitLab From 2a1062eae51fb16f7d2f0ae1a9d8433f4aea4e5d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 14:33:32 -0500 Subject: [PATCH 440/755] From comments in WB-726 Create new tab insertion location: Whenever the tile tabs configuration is edited, if the number of rows or columns increases, default their stretch factors to 1.0. --- src/Common/TileTabsConfiguration.cxx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Common/TileTabsConfiguration.cxx b/src/Common/TileTabsConfiguration.cxx index 9bc3a5b32..73f2095f5 100644 --- a/src/Common/TileTabsConfiguration.cxx +++ b/src/Common/TileTabsConfiguration.cxx @@ -117,7 +117,9 @@ TileTabsConfiguration::initialize() 1.0); m_columnStretchFactors.resize(getMaximumNumberOfColumns(), 1.0); - + m_numberOfColumns = 0; + m_numberOfRows = 0; + setNumberOfRows(2); setNumberOfColumns(2); @@ -329,8 +331,9 @@ TileTabsConfiguration::getNumberOfRows() const void TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) { - CaretAssert(numberOfRows >= 1); + const int32_t oldNumerOfRows = m_numberOfRows; + CaretAssert(numberOfRows >= 1); m_numberOfRows = numberOfRows; if (m_numberOfRows > getMaximumNumberOfRows()) { CaretLogSevere("Requested number of rows is " @@ -339,6 +342,14 @@ TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) + getMaximumNumberOfRows()); m_numberOfRows = getMaximumNumberOfRows(); } + + /* + * Stretch factors default to 1.0 + */ + for (int32_t iRow = oldNumerOfRows; iRow < m_numberOfRows; iRow++) { + CaretAssertVectorIndex(m_rowStretchFactors, iRow); + m_rowStretchFactors[iRow] = 1.0; + } } /** @@ -359,6 +370,8 @@ TileTabsConfiguration::getNumberOfColumns() const void TileTabsConfiguration::setNumberOfColumns(const int32_t numberOfColumns) { + const int32_t oldNumberOfColumns = m_numberOfColumns; + CaretAssert(numberOfColumns >= 1); m_numberOfColumns = numberOfColumns; @@ -369,6 +382,14 @@ TileTabsConfiguration::setNumberOfColumns(const int32_t numberOfColumns) + getMaximumNumberOfColumns()); m_numberOfColumns = getMaximumNumberOfColumns(); } + + /* + * Stretch factors default to 1.0 + */ + for (int32_t iCol = oldNumberOfColumns; iCol < m_numberOfColumns; iCol++) { + CaretAssertVectorIndex(m_columnStretchFactors, iCol); + m_columnStretchFactors[iCol] = 1.0; + } } /** -- GitLab From 52c0da8f6c227fd329a9ff6e15f6e8b7be440573 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 14:53:09 -0500 Subject: [PATCH 441/755] From comments in WB-726 Create new tab insertion location: When a new tab is created, default its Tab Margins to zeros. --- src/Brain/GapsAndMargins.cxx | 38 ++++++++++++++++++++++++++++++++++++ src/Brain/GapsAndMargins.h | 5 ++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Brain/GapsAndMargins.cxx b/src/Brain/GapsAndMargins.cxx index 6fc16ab14..b40a7d916 100644 --- a/src/Brain/GapsAndMargins.cxx +++ b/src/Brain/GapsAndMargins.cxx @@ -23,7 +23,10 @@ #include "GapsAndMargins.h" #undef __GAPS_AND_MARGINS_DECLARE__ +#include "BrowserTabContent.h" #include "CaretAssert.h" +#include "EventBrowserTabNew.h" +#include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -84,6 +87,12 @@ GapsAndMargins::GapsAndMargins() m_volumeMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, 0.0); + + /* + * Use processed event listener because we need to know the index + * of the tab that was created + */ + EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); } /** @@ -94,6 +103,35 @@ GapsAndMargins::~GapsAndMargins() delete m_sceneAssistant; } +/** + * Receive an event. + * + * @param event + * The event that the receive can respond to. + */ +void +GapsAndMargins::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW) { + EventBrowserTabNew* newTabEvent = dynamic_cast(event); + CaretAssert(newTabEvent); + + const BrowserTabContent* tab = newTabEvent->getBrowserTab(); + CaretAssert(tab); + if (tab != NULL) { + const int32_t tabIndex = tab->getTabNumber(); + CaretAssertArrayIndex(m_tabMarginsLeft, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + CaretAssertArrayIndex(m_tabMarginsRight, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + CaretAssertArrayIndex(m_tabMarginsBottom, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + CaretAssertArrayIndex(m_tabMarginsTop, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); + m_tabMarginsLeft[tabIndex] = 0.0; + m_tabMarginsRight[tabIndex] = 0.0; + m_tabMarginsBottom[tabIndex] = 0.0; + m_tabMarginsTop[tabIndex] = 0.0; + } + } +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Brain/GapsAndMargins.h b/src/Brain/GapsAndMargins.h index 03b440ffa..577b04f8e 100644 --- a/src/Brain/GapsAndMargins.h +++ b/src/Brain/GapsAndMargins.h @@ -23,18 +23,21 @@ #include "BrainConstants.h" #include "CaretObject.h" +#include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; - class GapsAndMargins : public CaretObject, public SceneableInterface { + class GapsAndMargins : public CaretObject, public EventListenerInterface, public SceneableInterface { public: GapsAndMargins(); virtual ~GapsAndMargins(); + virtual void receiveEvent(Event* event) override; + float getMarginLeftForTab(const int32_t tabIndex) const; float getMarginRightForTab(const int32_t tabIndex) const; -- GitLab From b7295bcd7556823e3f9c4139613ba4a8b35a32fd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 15:13:56 -0500 Subject: [PATCH 442/755] From comments in WB-726 Create new tab insertion location: When a new window is created, default its surface and volume montage gaps to zero percent. --- src/GuiQt/BrainBrowserWindow.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 38a745c5d..6948c90f3 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -75,6 +75,7 @@ #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FociProjectionDialog.h" +#include "GapsAndMargins.h" #include "GuiManager.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" @@ -274,6 +275,12 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, } #endif s_brainBrowserWindows.insert(this); + + GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); + gapsAndMargins->setSurfaceMontageHorizontalGapForWindow(m_browserWindowIndex, 0.0f); + gapsAndMargins->setSurfaceMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); + gapsAndMargins->setVolumeMontageHorizontalGapForWindow(m_browserWindowIndex, 0.0f); + gapsAndMargins->setVolumeMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); } /** -- GitLab From 8690450d5eeeb4a862b60fb5c30ed2b320e89e6a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Oct 2017 16:16:57 -0500 Subject: [PATCH 443/755] Forgot to remove event listeners in GapsAndMargins causing wb_command to print message and breaking HTML command help generation. --- src/Brain/GapsAndMargins.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Brain/GapsAndMargins.cxx b/src/Brain/GapsAndMargins.cxx index b40a7d916..f2d9322fe 100644 --- a/src/Brain/GapsAndMargins.cxx +++ b/src/Brain/GapsAndMargins.cxx @@ -100,6 +100,8 @@ GapsAndMargins::GapsAndMargins() */ GapsAndMargins::~GapsAndMargins() { + EventManager::get()->removeAllEventsFromListener(this); + delete m_sceneAssistant; } -- GitLab From b4cedacc9c8106f08ec271a280498ef95cdd83f4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 11 Oct 2017 10:47:53 -0500 Subject: [PATCH 444/755] added a button "M" to Slice Indices/Coords section of Toolbar to get feedback on its acceptability for selection of oblique volume masking. --- ...rainBrowserWindowToolBarSliceSelection.cxx | 37 ++++++++++++++++++- .../BrainBrowserWindowToolBarSliceSelection.h | 2 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 8d48b6cd9..877ae259b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,25 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setToolTipAndStatusTip(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), "Chooses viewing orientation (oblique or orthogonal)"); +// QMenu* obliqueMaskingMenu = new QMenu("Oblique Sampling"); +// obliqueMaskingMenu->addAction("Oblique Masking - OFF"); +// obliqueMaskingMenu->addAction("Oblique Masking - ENCLOSING"); +// obliqueMaskingMenu->addAction("Oblique Masking - TRILINEAR"); +// QAction* obliqueMaskingAction = new QAction("M"); +// obliqueMaskingAction->setMenu(obliqueMaskingMenu); +// QToolButton* obliqueMaskingToolButton = new QToolButton(); +// obliqueMaskingToolButton->setDefaultAction(obliqueMaskingAction); +// WuQtUtilities::setToolButtonStyleForQt5Mac(obliqueMaskingToolButton); + + const AString maskToolTip("Masking for oblique slice viewing"); + m_obliqueMaskingAction = new QAction("M"); + m_obliqueMaskingAction->setToolTip(maskToolTip); + QObject::connect(m_obliqueMaskingAction, &QAction::triggered, + this, &BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered); + QToolButton* obliqueMaskingToolButton = new QToolButton(); + obliqueMaskingToolButton->setDefaultAction(m_obliqueMaskingAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(obliqueMaskingToolButton); + QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->addWidget(m_volumeIndicesParasagittalCheckBox, 0, 0); @@ -196,7 +216,9 @@ m_parentToolBar(parentToolBar) gridLayout->addWidget(m_volumeIndicesZcoordSpinBox, 2, 3); gridLayout->addWidget(volumeIDToolButton, 3, 0, 1, 2, Qt::AlignLeft); - gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 3, Qt::AlignRight); + gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 2, Qt::AlignCenter); + //gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 3, Qt::AlignRight); + gridLayout->addWidget(obliqueMaskingToolButton, 3, 4); gridLayout->addWidget(volumeIndicesOriginToolButton, 0, 4, 3, 1); @@ -716,4 +738,17 @@ BrainBrowserWindowToolBarSliceSelection::volumeIdentificationToggled(bool value) browserTabContent->setIdentificationUpdatesVolumeSlices(value); } +/** + * Called when the oblique masking action is triggered. + */ +void +BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) +{ + QMenu obliqueMaskingMenu("Oblique Sampling"); + obliqueMaskingMenu.addAction("Oblique Masking - OFF"); + obliqueMaskingMenu.addAction("Oblique Masking - ENCLOSING"); + obliqueMaskingMenu.addAction("Oblique Masking - TRILINEAR"); + /*QAction* selectedAction =*/ obliqueMaskingMenu.exec(QCursor::pos()); + +} diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h index 9d436bba3..8ab841974 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h @@ -61,6 +61,7 @@ namespace caret { void volumeIndicesZcoordSpinBoxValueChanged(double d); void volumeSliceProjectionTypeEnumComboBoxItemActivated(); void volumeIdentificationToggled(bool value); + void obliqueMaskingActionTriggered(bool); private: BrainBrowserWindowToolBarSliceSelection(const BrainBrowserWindowToolBarSliceSelection&); @@ -86,6 +87,7 @@ namespace caret { QDoubleSpinBox* m_volumeIndicesXcoordSpinBox; QDoubleSpinBox* m_volumeIndicesYcoordSpinBox; QDoubleSpinBox* m_volumeIndicesZcoordSpinBox; + QAction* m_obliqueMaskingAction; EnumComboBoxTemplate* m_volumeSliceProjectionTypeEnumComboBox; // ADD_NEW_MEMBERS_HERE -- GitLab From 64ab32057d53ff04442d743064027cc2168bde67 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 12 Oct 2017 11:08:52 -0500 Subject: [PATCH 445/755] Initial implementation of WB-750 Strange oblique volume drawing - Added an "M" button ("M" for masking) to the Slice Indices/Coords section of the toolbar. The "M" button is enabled only when Oblique viewing is selected. Pressing the "M" button displays a menu with selections for the type of oblique masking (off, enclosing voxel, trilinear). The "M" button has a selection status that is "on" (highlighted) when enclosing voxel or trilinear is selected. The "M" button has a tooltip that describes its functionality. When using the scene that was created for this issue, there are differences between enclosing voxel and trilinear masking, though not drastic. Please review the text in "M" button's tooltip and the menus. The default masking is enclosing voxel. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 13 +- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 42 +- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 5 +- src/Brain/BrowserTabContent.cxx | 22 + src/Brain/BrowserTabContent.h | 5 + src/Brain/CMakeLists.txt | 2 + .../VolumeSliceObliqueDrawingMaskEnum.cxx | 376 ++++++++++++++++++ src/Brain/VolumeSliceObliqueDrawingMaskEnum.h | 105 +++++ src/Brain/VolumeSliceSettings.cxx | 33 +- src/Brain/VolumeSliceSettings.h | 8 + ...rainBrowserWindowToolBarSliceSelection.cxx | 99 ++++- .../BrainBrowserWindowToolBarSliceSelection.h | 2 + 12 files changed, 685 insertions(+), 27 deletions(-) create mode 100644 src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx create mode 100644 src/Brain/VolumeSliceObliqueDrawingMaskEnum.h diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 9084dee0e..45b6cbf3f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -3552,7 +3552,7 @@ BrainOpenGLFixedPipeline::drawVolumeModel(BrowserTabContent* browserTabContent, VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); - + VolumeSliceObliqueDrawingMaskEnum::Enum obliqueMaskType = browserTabContent->getObliqueSliceDrawingMaskingType(); /* * There is/was a flaw in volume drawing in that it does not "center" @@ -3582,11 +3582,12 @@ BrainOpenGLFixedPipeline::drawVolumeModel(BrowserTabContent* browserTabContent, else { BrainOpenGLVolumeObliqueSliceDrawing obliqueVolumeSliceDrawing; obliqueVolumeSliceDrawing.draw(this, - browserTabContent, - volumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - viewport); + browserTabContent, + volumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); } } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 81d010a0e..a991da8a2 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -105,6 +105,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::~BrainOpenGLVolumeObliqueSliceDrawing() * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) + * @param obliqueSliceMaskingType + * Masking for oblique slice drawing * @param viewport * The viewport (region of graphics area) for drawing slices. */ @@ -114,6 +116,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceObliqueDrawingMaskEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]) { CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); @@ -126,7 +129,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli CaretAssert(browserTabContent); m_browserTabContent = browserTabContent; m_fixedPipelineDrawing = fixedPipelineDrawing; - + m_obliqueSliceMaskingType = obliqueSliceMaskingType; /* * No lighting for drawing slices */ @@ -1445,6 +1448,43 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan VolumeFile::CUBIC, &valueValidFlag, vdi.mapIndex); + + if (valueValidFlag + && (values[0] != 0.0f)) { + /* + * Apply masking to oblique voxels (WB-750). + * In some instances, CUBIC interpolation may result in a voxel + * receiving a very small value (0.000000000000000210882405) and + * this will cause the slice drawing to look very unusual. Masking + * is used to prevent this from occurring. + * + */ + bool maskValidFlag = false; + float maskValue = 0.0f; + switch (m_obliqueSliceMaskingType) { + case VolumeSliceObliqueDrawingMaskEnum::OFF: + maskValidFlag = false; + break; + case VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL: + maskValue = volumeFile->interpolateValue(voxelCenter, + VolumeFile::ENCLOSING_VOXEL, + &maskValidFlag, + vdi.mapIndex); + break; + case VolumeSliceObliqueDrawingMaskEnum::TRILINEAR_INTERPOLATION: + maskValue = volumeFile->interpolateValue(voxelCenter, + VolumeFile::TRILINEAR, + &maskValidFlag, + vdi.mapIndex); + break; + } + + if (maskValidFlag + && (maskValue == 0.0f)) { + values[0] = 0.0f; + valueValidFlag = false; + } + } } else if (ciftiMappableFile != NULL) { const int64_t voxelOffset = ciftiMappableFile->getMapDataOffsetForVoxelAtCoordinate(voxelCenter, diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index 67a190011..c27411d1b 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -24,12 +24,12 @@ #include "BrainOpenGLFixedPipeline.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" +#include "VolumeSliceObliqueDrawingMaskEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" - namespace caret { class Brain; @@ -54,6 +54,7 @@ namespace caret { std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, + const VolumeSliceObliqueDrawingMaskEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]); // ADD_NEW_METHODS_HERE @@ -370,6 +371,8 @@ namespace caret { double m_orthographicBounds[6]; + VolumeSliceObliqueDrawingMaskEnum::Enum m_obliqueSliceMaskingType = VolumeSliceObliqueDrawingMaskEnum::OFF; + std::vector m_identificationIndices; bool m_identificationModeFlag; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 194af8aa4..67ba5c36f 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -3802,6 +3802,28 @@ BrowserTabContent::setSliceProjectionType(const VolumeSliceProjectionTypeEnum::E updateBrainModelYokedBrowserTabs(); } +/** + * @return The masking used when drawing an oblique volume slice + */ +VolumeSliceObliqueDrawingMaskEnum::Enum +BrowserTabContent::getObliqueSliceDrawingMaskingType() const +{ + return m_volumeSliceSettings->getObliqueSliceDrawingMaskingType(); +} + +/** + * Set the masking used when drawing an oblique volume slice. + * + * @param maskingType + * Type of masking. + */ +void +BrowserTabContent::setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType) +{ + m_volumeSliceSettings->setObliqueSliceDrawingMaskingType(maskingType); + updateBrainModelYokedBrowserTabs(); +} + /** * @return the montage number of columns for the given window tab. */ diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index f2a9135cb..99b304f47 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -32,6 +32,7 @@ #include "SceneableInterface.h" #include "StructureEnum.h" #include "VolumeSliceDrawingTypeEnum.h" +#include "VolumeSliceObliqueDrawingMaskEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" @@ -306,6 +307,10 @@ namespace caret { void setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); + VolumeSliceObliqueDrawingMaskEnum::Enum getObliqueSliceDrawingMaskingType() const; + + void setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType); + int32_t getMontageNumberOfColumns() const; void setMontageNumberOfColumns(const int32_t montageNumberOfColumns); diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 8da1ff6d4..7658fb97e 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -166,6 +166,7 @@ ViewingTransformations.h ViewingTransformationsCerebellum.h ViewingTransformationsVolume.h VolumeSliceDrawingTypeEnum.h +VolumeSliceObliqueDrawingMaskEnum.h VolumeSliceSettings.h VolumeSliceViewAllPlanesLayoutEnum.h VolumeSurfaceOutlineColorOrTabModel.h @@ -311,6 +312,7 @@ ViewingTransformations.cxx ViewingTransformationsCerebellum.cxx ViewingTransformationsVolume.cxx VolumeSliceDrawingTypeEnum.cxx +VolumeSliceObliqueDrawingMaskEnum.cxx VolumeSliceSettings.cxx VolumeSliceViewAllPlanesLayoutEnum.cxx VolumeSurfaceOutlineColorOrTabModel.cxx diff --git a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx b/src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx new file mode 100644 index 000000000..41ff6218c --- /dev/null +++ b/src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx @@ -0,0 +1,376 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ +#include "VolumeSliceObliqueDrawingMaskEnum.h" +#undef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::VolumeSliceObliqueDrawingMaskEnum + * \brief Enumerated type for oblique slice drawing masking + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_volumeSliceObliqueDrawingMaskEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void volumeSliceObliqueDrawingMaskEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "VolumeSliceObliqueDrawingMaskEnum.h" + * + * Instatiate: + * m_volumeSliceObliqueDrawingMaskEnumComboBox = new EnumComboBoxTemplate(this); + * m_volumeSliceObliqueDrawingMaskEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_volumeSliceObliqueDrawingMaskEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(volumeSliceObliqueDrawingMaskEnumComboBoxItemActivated())); + * + * Update the selection: + * m_volumeSliceObliqueDrawingMaskEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const VolumeSliceObliqueDrawingMaskEnum::Enum VARIABLE = m_volumeSliceObliqueDrawingMaskEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +VolumeSliceObliqueDrawingMaskEnum::VolumeSliceObliqueDrawingMaskEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +VolumeSliceObliqueDrawingMaskEnum::~VolumeSliceObliqueDrawingMaskEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +VolumeSliceObliqueDrawingMaskEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(OFF, + "OFF", + "Oblique Masking OFF")); + + enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(ENCLOSING_VOXEL, + "ENCLOSING_VOXEL", + "Oblique Masking ENCLOSING VOXEL")); + + enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(TRILINEAR_INTERPOLATION, + "TRILINEAR_INTERPOLATION", + "Oblique Masking TRILINEAR INTERPOLATION")); +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const VolumeSliceObliqueDrawingMaskEnum* +VolumeSliceObliqueDrawingMaskEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const VolumeSliceObliqueDrawingMaskEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +VolumeSliceObliqueDrawingMaskEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +VolumeSliceObliqueDrawingMaskEnum::Enum +VolumeSliceObliqueDrawingMaskEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceObliqueDrawingMaskEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +VolumeSliceObliqueDrawingMaskEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +VolumeSliceObliqueDrawingMaskEnum::Enum +VolumeSliceObliqueDrawingMaskEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceObliqueDrawingMaskEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +VolumeSliceObliqueDrawingMaskEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +VolumeSliceObliqueDrawingMaskEnum::Enum +VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const VolumeSliceObliqueDrawingMaskEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +VolumeSliceObliqueDrawingMaskEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +VolumeSliceObliqueDrawingMaskEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(VolumeSliceObliqueDrawingMaskEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +VolumeSliceObliqueDrawingMaskEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(VolumeSliceObliqueDrawingMaskEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.h b/src/Brain/VolumeSliceObliqueDrawingMaskEnum.h new file mode 100644 index 000000000..b1fe00a52 --- /dev/null +++ b/src/Brain/VolumeSliceObliqueDrawingMaskEnum.h @@ -0,0 +1,105 @@ +#ifndef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ +#define __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class VolumeSliceObliqueDrawingMaskEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Masking Off */ + OFF, + /** Mask with enclosing voxel */ + ENCLOSING_VOXEL, + /** Mask with trilinear interpolation */ + TRILINEAR_INTERPOLATION + }; + + ~VolumeSliceObliqueDrawingMaskEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + VolumeSliceObliqueDrawingMaskEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const VolumeSliceObliqueDrawingMaskEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ +std::vector VolumeSliceObliqueDrawingMaskEnum::enumData; +bool VolumeSliceObliqueDrawingMaskEnum::initializedFlag = false; +int32_t VolumeSliceObliqueDrawingMaskEnum::integerCodeCounter = 0; +#endif // __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ + +} // namespace +#endif //__VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index 5e3e509c9..b3ba53a85 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -50,6 +50,8 @@ VolumeSliceSettings::VolumeSliceSettings() m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; + m_obliqueSliceDrawingMaskingType = VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL; + m_montageNumberOfColumns = 6; // was 3; m_montageNumberOfRows = 4; m_montageSliceSpacing = 5; @@ -72,6 +74,8 @@ VolumeSliceSettings::VolumeSliceSettings() &m_sliceDrawingType); m_sceneAssistant->add("m_sliceProjectionType", &m_sliceProjectionType); + m_sceneAssistant->add("m_obliqueSliceDrawingMaskingType", + &m_obliqueSliceDrawingMaskingType); m_sceneAssistant->add("m_montageNumberOfColumns", &m_montageNumberOfColumns); m_sceneAssistant->add("m_montageNumberOfRows", @@ -135,6 +139,7 @@ VolumeSliceSettings::copyHelperVolumeSliceSettings(const VolumeSliceSettings& ob m_slicePlanesAllViewLayout = obj.m_slicePlanesAllViewLayout; m_sliceDrawingType = obj.m_sliceDrawingType; m_sliceProjectionType = obj.m_sliceProjectionType; + m_obliqueSliceDrawingMaskingType = obj.m_obliqueSliceDrawingMaskingType; m_montageNumberOfColumns = obj.m_montageNumberOfColumns; m_montageNumberOfRows = obj.m_montageNumberOfRows; @@ -304,8 +309,29 @@ VolumeSliceSettings::setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum m_sliceDrawingType = sliceDrawingType; } -/** - * @return Type of slice projection (oblique/orthogonal) +/** + * @return The masking used when drawing an oblique volume slice + */ +VolumeSliceObliqueDrawingMaskEnum::Enum +VolumeSliceSettings::getObliqueSliceDrawingMaskingType() const +{ + return m_obliqueSliceDrawingMaskingType; +} + +/** + * Set the masking used when drawing an oblique volume slice. + * + * @param maskingType + * Type of masking. + */ +void +VolumeSliceSettings::setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType) +{ + m_obliqueSliceDrawingMaskingType = maskingType; +} + +/** + * @return Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum VolumeSliceSettings::getSliceProjectionType() const @@ -804,10 +830,11 @@ VolumeSliceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, } /* - * Added in scene version 2 + * Added in scene version 2 or later */ m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; + m_obliqueSliceDrawingMaskingType = VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Brain/VolumeSliceSettings.h b/src/Brain/VolumeSliceSettings.h index 59fe3d391..c112ae3eb 100644 --- a/src/Brain/VolumeSliceSettings.h +++ b/src/Brain/VolumeSliceSettings.h @@ -26,6 +26,7 @@ #include "ModelTypeEnum.h" #include "SceneableInterface.h" #include "VolumeSliceDrawingTypeEnum.h" +#include "VolumeSliceObliqueDrawingMaskEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" @@ -60,6 +61,10 @@ namespace caret { void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); + VolumeSliceObliqueDrawingMaskEnum::Enum getObliqueSliceDrawingMaskingType() const; + + void setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType); + VolumeSliceProjectionTypeEnum::Enum getSliceProjectionType() const; void setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); @@ -156,6 +161,9 @@ namespace caret { /** Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum m_sliceDrawingType; + /** Type of masking for oblique slice drawing */ + VolumeSliceObliqueDrawingMaskEnum::Enum m_obliqueSliceDrawingMaskingType; + /** Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum m_sliceProjectionType; diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 877ae259b..5cae76331 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -44,6 +44,7 @@ #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "VolumeFile.h" +#include "VolumeSliceObliqueDrawingMaskEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "WuQFactory.h" #include "WuQWidgetObjectGroup.h" @@ -179,19 +180,14 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setToolTipAndStatusTip(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), "Chooses viewing orientation (oblique or orthogonal)"); -// QMenu* obliqueMaskingMenu = new QMenu("Oblique Sampling"); -// obliqueMaskingMenu->addAction("Oblique Masking - OFF"); -// obliqueMaskingMenu->addAction("Oblique Masking - ENCLOSING"); -// obliqueMaskingMenu->addAction("Oblique Masking - TRILINEAR"); -// QAction* obliqueMaskingAction = new QAction("M"); -// obliqueMaskingAction->setMenu(obliqueMaskingMenu); -// QToolButton* obliqueMaskingToolButton = new QToolButton(); -// obliqueMaskingToolButton->setDefaultAction(obliqueMaskingAction); -// WuQtUtilities::setToolButtonStyleForQt5Mac(obliqueMaskingToolButton); - - const AString maskToolTip("Masking for oblique slice viewing"); + const AString maskToolTip("Masking for oblique slice viewing is used to remove " + "artifacts due to cubic interpolation. In extreme " + "instance, the artifacts result in blocky and/or " + "striped patterns."); m_obliqueMaskingAction = new QAction("M"); - m_obliqueMaskingAction->setToolTip(maskToolTip); + WuQtUtilities::setWordWrappedToolTip(m_obliqueMaskingAction, + maskToolTip); + m_obliqueMaskingAction->setCheckable(true); QObject::connect(m_obliqueMaskingAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered); QToolButton* obliqueMaskingToolButton = new QToolButton(); @@ -318,6 +314,8 @@ BrainBrowserWindowToolBarSliceSelection::updateContent(BrowserTabContent* browse m_volumeIndicesParasagittalCheckBox->setChecked(browserTabContent->isSliceParasagittalEnabled()); } + updateObliqueMaskingButton(); + m_volumeSliceProjectionTypeEnumComboBox->setSelectedItem(browserTabContent->getSliceProjectionType()); m_volumeIdentificationUpdatesSlicesAction->setChecked(browserTabContent->isIdentificationUpdatesVolumeSlices()); @@ -719,6 +717,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeSliceProjectionTypeEnumComboBoxIt btc->setSliceProjectionType(sliceProjectionType); this->updateGraphicsWindow(); this->updateOtherYokedWindows(); + updateObliqueMaskingButton(); EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); } @@ -744,11 +743,79 @@ BrainBrowserWindowToolBarSliceSelection::volumeIdentificationToggled(bool value) void BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) { + BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); + if (browserTabContent == NULL) { + return; + } + std::vector allMaskEnums; + VolumeSliceObliqueDrawingMaskEnum::getAllEnums(allMaskEnums); + QMenu obliqueMaskingMenu("Oblique Sampling"); - obliqueMaskingMenu.addAction("Oblique Masking - OFF"); - obliqueMaskingMenu.addAction("Oblique Masking - ENCLOSING"); - obliqueMaskingMenu.addAction("Oblique Masking - TRILINEAR"); - /*QAction* selectedAction =*/ obliqueMaskingMenu.exec(QCursor::pos()); + QActionGroup* maskActionGroup = new QActionGroup(this); + maskActionGroup->setExclusive(true); + QAction* selectedAction = NULL; + for (auto maskEnum : allMaskEnums) { + QAction* action = maskActionGroup->addAction(VolumeSliceObliqueDrawingMaskEnum::toGuiName(maskEnum)); + action->setCheckable(true); + action->setData(VolumeSliceObliqueDrawingMaskEnum::toIntegerCode(maskEnum)); + if (maskEnum == browserTabContent->getObliqueSliceDrawingMaskingType()) { + selectedAction = action; + } + obliqueMaskingMenu.addAction(action); + } + if (selectedAction != NULL) { + selectedAction->setChecked(true); + } + selectedAction = obliqueMaskingMenu.exec(QCursor::pos()); + if (selectedAction != NULL) { + const int32_t intValue = selectedAction->data().toInt(); + bool validFlag = false; + VolumeSliceObliqueDrawingMaskEnum::Enum maskType = VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(intValue, + &validFlag); + CaretAssert(validFlag); + browserTabContent->setObliqueSliceDrawingMaskingType(maskType); + + this->updateGraphicsWindow(); + this->updateOtherYokedWindows(); + EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); + } + + updateObliqueMaskingButton(); } +/** + * Update the oblique masking button so that it enabled only + * when oblique slice drawing is selected and it is "checked" + * when a masking is applied. + */ +void +BrainBrowserWindowToolBarSliceSelection::updateObliqueMaskingButton() +{ + BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); + if (browserTabContent == NULL) { + return; + } + + QSignalBlocker obliqueBlocker(m_obliqueMaskingAction); + switch (browserTabContent->getObliqueSliceDrawingMaskingType()) { + case VolumeSliceObliqueDrawingMaskEnum::OFF: + m_obliqueMaskingAction->setChecked(false); + break; + case VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL: + case VolumeSliceObliqueDrawingMaskEnum::TRILINEAR_INTERPOLATION: + m_obliqueMaskingAction->setChecked(true); + break; + } + + switch (browserTabContent->getSliceProjectionType()) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + m_obliqueMaskingAction->setEnabled(true); + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + m_obliqueMaskingAction->setEnabled(false); + break; + } +} + + diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h index 8ab841974..a1c7b966f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h @@ -73,6 +73,8 @@ namespace caret { const int64_t sliceIndex); void updateSliceIndicesAndCoordinatesRanges(); + void updateObliqueMaskingButton(); + BrainBrowserWindowToolBar* m_parentToolBar; WuQWidgetObjectGroup* m_volumeIndicesWidgetGroup; -- GitLab From 9253ac2f0b24a76da31d0a6fdea82b903c5ea34c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 12 Oct 2017 11:09:42 -0500 Subject: [PATCH 446/755] Added an overloaded method for setting a word wrapped tooltip that sets the tooltip for a QAction (existing method set tooltip for a Widget). --- src/GuiQt/WuQtUtilities.cxx | 21 +++++++++++++++++++++ src/GuiQt/WuQtUtilities.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index f6c3a95cf..1332b5dd3 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1163,6 +1163,27 @@ WuQtUtilities::setWordWrappedToolTip(QWidget* widget, widget->setToolTip(createWordWrappedToolTipText(tooltipText)); } +/** + * Set the text for a tooltip so that long lines are + * wrapped and the tooltip is not one giant line + * that is the width of the display. + * + * This is accomplished by placing the text into a + * QTextDocument and then retrieving the text with + * HTML formatting. + * + * @param action + * Action on which tooltip is set. + * @param tooltipText + * Text for the widget's tooltip. + */ +void +WuQtUtilities::setWordWrappedToolTip(QAction* action, + const QString& tooltipText) +{ + action->setToolTip(createWordWrappedToolTipText(tooltipText)); +} + /** * Convert a Qt::CheckState to a boolean value. * diff --git a/src/GuiQt/WuQtUtilities.h b/src/GuiQt/WuQtUtilities.h index df4ad438d..e5024125c 100644 --- a/src/GuiQt/WuQtUtilities.h +++ b/src/GuiQt/WuQtUtilities.h @@ -193,6 +193,9 @@ namespace caret { static void setWordWrappedToolTip(QWidget* widget, const QString& tooltipText); + static void setWordWrappedToolTip(QAction* action, + const QString& tooltipText); + static bool checkStateToBool(const Qt::CheckState checkState); static Qt::CheckState boolToCheckState(const bool value); -- GitLab From a3e7efdebb2affb12c49dbcd1a3c8fad9241286d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 13 Oct 2017 15:30:17 -0500 Subject: [PATCH 447/755] Added an experimental "Tab" menu that is at the beginning of the View Mode pop-up menu that allows one to selected the tab under the mouse, add a new tab before, and add a new tab after. --- src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 6 +- src/Common/EventTypeEnum.h | 2 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 97 ++++++++++--- src/GuiQt/BrainBrowserWindowToolBar.h | 3 + src/GuiQt/CMakeLists.txt | 5 + .../EventBrowserWindowTileTabOperation.cxx | 131 +++++++++++++++++ .../EventBrowserWindowTileTabOperation.h | 83 +++++++++++ src/GuiQt/UserInputModeView.cxx | 4 +- src/GuiQt/UserInputModeViewContextMenu.cxx | 55 ++++++- src/GuiQt/UserInputModeViewContextMenu.h | 10 +- src/GuiQt/UserInputTileTabsContextMenu.cxx | 135 ++++++++++++++++++ src/GuiQt/UserInputTileTabsContextMenu.h | 79 ++++++++++ 13 files changed, 580 insertions(+), 31 deletions(-) create mode 100644 src/GuiQt/EventBrowserWindowTileTabOperation.cxx create mode 100644 src/GuiQt/EventBrowserWindowTileTabOperation.h create mode 100644 src/GuiQt/UserInputTileTabsContextMenu.cxx create mode 100644 src/GuiQt/UserInputTileTabsContextMenu.h diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 98fc09332..a4d754699 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -487,6 +487,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS: case EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN: case EventTypeEnum::EVENT_BROWSER_WINDOW_NEW: + case EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS: case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index a0daef603..ba7581906 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -154,7 +154,11 @@ EventTypeEnum::initialize() "EVENT_BROWSER_WINDOW_NEW", "Create a new browser window")); - enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILES_GET, + enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION, + "EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION", + "Browser Window Tile Tab Operation")); + + enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILES_GET, "EVENT_CARET_MAPPABLE_DATA_FILES_GET", "Get all Caret Mappable data files")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index e5e611e0f..ea319b502 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -82,6 +82,8 @@ public: EVENT_BROWSER_WINDOW_MENUS_UPDATE, /** Create a new browser window */ EVENT_BROWSER_WINDOW_NEW, + /** Browser tile tab operations */ + EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION, /** Get CaretMappable data files */ EVENT_CARET_MAPPABLE_DATA_FILES_GET, /** Get CaretMappableDataFiles and their maps viewed as overlays */ diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 8306e8593..5860b67c1 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -85,6 +85,7 @@ #include "EventBrowserWindowContentGet.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowNew.h" +#include "EventBrowserWindowTileTabOperation.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" @@ -458,10 +459,12 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->updateToolBar(); this->isContructorFinished = true; + m_tileTabsHighlightingTimerEnabledFlag = true; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } @@ -733,8 +736,10 @@ BrainBrowserWindowToolBar::insertTabContentPrivate(const InsertTabMode insertTab newTabIndex = this->tabBar->addTab("NewTab"); break; case InsertTabMode::AT_TAB_BAR_INDEX: - newTabIndex = this->tabBar->insertTab(tabBarIndex, - "NewTab"); + if ((tabBarIndex >= 0) && (tabBarIndex <= this->tabBar->count())) { + newTabIndex = this->tabBar->insertTab(tabBarIndex, + "NewTab"); + } break; case InsertTabMode::AT_TAB_CONTENTS_INDEX: { @@ -1446,24 +1451,26 @@ BrainBrowserWindowToolBar::selectedTabChanged(int indx) if (browserWindow->isTileTabsSelected()) { const BrowserTabContent* btc = getTabContentFromSelectedTab(); if (btc != NULL) { - m_tabIndexForTileTabsHighlighting = btc->getTabNumber(); - - /* - * Short timer that will reset the tab highlighting - */ - if (m_tileTabsHighlightingTimer == NULL) { - m_tileTabsHighlightingTimer = new QTimer(this); - QObject::connect(m_tileTabsHighlightingTimer, &QTimer::timeout, - this, &BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting); + if (m_tileTabsHighlightingTimerEnabledFlag) { + m_tabIndexForTileTabsHighlighting = btc->getTabNumber(); + + /* + * Short timer that will reset the tab highlighting + */ + if (m_tileTabsHighlightingTimer == NULL) { + m_tileTabsHighlightingTimer = new QTimer(this); + QObject::connect(m_tileTabsHighlightingTimer, &QTimer::timeout, + this, &BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting); + } + + /* + * Note: There is no need to 'stop' the timer if it is running + * as the start() method will stop and restart the timer + */ + const int timeInMilliseconds = 750; + m_tileTabsHighlightingTimer->setSingleShot(true); + m_tileTabsHighlightingTimer->start(timeInMilliseconds); } - - /* - * Note: There is no need to 'stop' the timer if it is running - * as the start() method will stop and restart the timer - */ - const int timeInMilliseconds = 750; - m_tileTabsHighlightingTimer->setSingleShot(true); - m_tileTabsHighlightingTimer->start(timeInMilliseconds); } } } @@ -4063,6 +4070,34 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) } tabEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION) { + EventBrowserWindowTileTabOperation* tileTabsEvent = + dynamic_cast(event); + CaretAssert(tileTabsEvent); + + if (tileTabsEvent->getWindowIndex() == this->browserWindowIndex) { + const int32_t browserTabIndex = tileTabsEvent->getBrowserTabIndex(); + int32_t tabBarIndex = getTabBarIndexWithBrowserTabIndex(browserTabIndex); + if (tabBarIndex >= 0) { + const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); + switch (operation) { + case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER: + insertNewTabAtTabBarIndex(tabBarIndex + 1); + break; + case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE: + insertNewTabAtTabBarIndex(tabBarIndex); + break; + case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: + m_tileTabsHighlightingTimerEnabledFlag = false; + this->tabBar->setCurrentIndex(tabBarIndex); + m_tileTabsHighlightingTimerEnabledFlag = true; + break; + } + } + + tileTabsEvent->setEventProcessed(); + } + } else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS) { EventUpdateYokedWindows* yokeUpdateEvent = dynamic_cast(event); @@ -4107,6 +4142,30 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) } } +/** + * Get the tab bar index containing the browser tab index. + * + * @param browserTabIndex + * Index of the browser tab. + * @return + * Index in tab bar containing the browser tab index or -1 if not found. + */ +int32_t +BrainBrowserWindowToolBar::getTabBarIndexWithBrowserTabIndex(const int32_t browserTabIndex) +{ + const int numTabs = this->tabBar->count(); + if (numTabs > 0) { + for (int32_t i = 0; i < numTabs; i++) { + const BrowserTabContent* btc = getTabContentFromTab(i); + if (btc->getTabNumber() == browserTabIndex){ + return i; + } + } + } + + return -1; +} + /** * If this windows is yoked, issue an event to update other * windows that are using the same yoking. diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 7d3da91a6..7b5882538 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -126,6 +126,8 @@ namespace caret { BrowserTabContent* getTabContentFromSelectedTab(); BrowserTabContent* getTabContentFromTab(const int tabIndex); + int32_t getTabBarIndexWithBrowserTabIndex(const int32_t browserTabIndex); + Model* getDisplayedModel(); int32_t loadIntoTab(const int32_t tabIndex, @@ -436,6 +438,7 @@ namespace caret { */ int32_t m_tabIndexForTileTabsHighlighting; QTimer* m_tileTabsHighlightingTimer = NULL; + bool m_tileTabsHighlightingTimerEnabledFlag = true; bool isContructorFinished; bool isDestructionInProgress; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 812069611..df0d13132 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -175,6 +175,7 @@ ELSE() UserInputModeImageWidget.h UserInputModeViewContextMenu.h UserInputModeVolumeEditWidget.h + UserInputTileTabsContextMenu.h UsernamePasswordWidget.h VolumeFileCreateDialog.h VolumeSurfaceOutlineColorOrTabViewController.h @@ -316,6 +317,7 @@ EventBrowserWindowContentGet.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h +EventBrowserWindowTileTabOperation.h EventGetOrSetUserInputModeProcessor.h EventGraphicsUpdateAllWindows.h EventGraphicsUpdateOneWindow.h @@ -403,6 +405,7 @@ UserInputModeView.h UserInputModeViewContextMenu.h UserInputModeVolumeEdit.h UserInputModeVolumeEditWidget.h +UserInputTileTabsContextMenu.h UsernamePasswordWidget.h ViewModeEnum.h VolumeFileCreateDialog.h @@ -531,6 +534,7 @@ EventBrowserWindowContentGet.cxx EventBrowserWindowCreateTabs.cxx EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx +EventBrowserWindowTileTabOperation.cxx EventGetOrSetUserInputModeProcessor.cxx EventGraphicsUpdateAllWindows.cxx EventGraphicsUpdateOneWindow.cxx @@ -618,6 +622,7 @@ UserInputModeView.cxx UserInputModeViewContextMenu.cxx UserInputModeVolumeEdit.cxx UserInputModeVolumeEditWidget.cxx +UserInputTileTabsContextMenu.cxx UsernamePasswordWidget.cxx ViewModeEnum.cxx VolumeFileCreateDialog.cxx diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.cxx b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx new file mode 100644 index 000000000..52a52281a --- /dev/null +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx @@ -0,0 +1,131 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ +#include "EventBrowserWindowTileTabOperation.h" +#undef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "EventManager.h" +#include "EventTypeEnum.h" +#include "WuQMessageBox.h" +using namespace caret; + + + +/** + * \class caret::EventBrowserWindowTileTabOperation + * \brief Operations for tab changes + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param operation + * The operation + * @param parentWidget + * Parent widget for error dialogs. + * @param windowIndex + * Index of the window. + * @param browserTabIndex + * Index of the browser tab. + */ +EventBrowserWindowTileTabOperation::EventBrowserWindowTileTabOperation(const Operation operation, + QWidget* parentWidget, + const int32_t windowIndex, + const int32_t browserTabIndex) +: Event(EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION), +m_operation(operation), +m_parentWidget(parentWidget), +m_windowIndex(windowIndex), +m_browserTabIndex(browserTabIndex) +{ + CaretAssert(m_parentWidget); + CaretAssert(m_windowIndex >= 0); + CaretAssert(m_browserTabIndex >= 0); +} + +/** + * Destructor. + */ +EventBrowserWindowTileTabOperation::~EventBrowserWindowTileTabOperation() +{ +} + +/** + * Operation that selects the given tab in the given window. + * + * @param parentWidget + * Parent widget for error dialogs. + * @param windowIndex + * Index of the window. + * @param browserTabIndex + * Index of the browser tab. + */ +void +EventBrowserWindowTileTabOperation::selectTabInWindow(QWidget* parentWidget, + const int32_t windowIndex, + const int32_t browserTabIndex) +{ + EventBrowserWindowTileTabOperation tabOperation(Operation::OPERATION_SELECT_TAB, + parentWidget, + windowIndex, + browserTabIndex); + + EventManager::get()->sendEvent(tabOperation.getPointer()); + + if (tabOperation.getEventProcessCount() <= 0) { + WuQMessageBox::errorOk(parentWidget, + "Tab not created, invalid window or tab index"); + } +} + +/** + * @return The mode + */ +EventBrowserWindowTileTabOperation::Operation +EventBrowserWindowTileTabOperation::getOperation() const +{ + return m_operation; +} + +/** + * @return The window index. + */ +int32_t +EventBrowserWindowTileTabOperation::getWindowIndex() const +{ + return m_windowIndex; +} + +/** + * @return The browser tab index. + */ +int32_t +EventBrowserWindowTileTabOperation::getBrowserTabIndex() const +{ + return m_browserTabIndex; +} + + diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.h b/src/GuiQt/EventBrowserWindowTileTabOperation.h new file mode 100644 index 000000000..39540e96e --- /dev/null +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.h @@ -0,0 +1,83 @@ +#ifndef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ +#define __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + +class QWidget; + +namespace caret { + + class EventBrowserWindowTileTabOperation : public Event { + + public: + static void selectTabInWindow(QWidget* parentWidget, + const int32_t windowIndex, + const int32_t browserTabIndex); + enum Operation { + OPERATION_NEW_TAB_AFTER, + OPERATION_NEW_TAB_BEFORE, + OPERATION_SELECT_TAB + }; + + EventBrowserWindowTileTabOperation(const Operation operation, + QWidget* parentWidget, + const int32_t windowIndex, + const int32_t browserTabIndex); + + virtual ~EventBrowserWindowTileTabOperation(); + + Operation getOperation() const; + + int32_t getWindowIndex() const; + + int32_t getBrowserTabIndex() const; + + // ADD_NEW_METHODS_HERE + + private: + EventBrowserWindowTileTabOperation(const EventBrowserWindowTileTabOperation&); + + EventBrowserWindowTileTabOperation& operator=(const EventBrowserWindowTileTabOperation&); + + const Operation m_operation; + + QWidget* m_parentWidget; + + const int32_t m_windowIndex; + + const int32_t m_browserTabIndex; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ + // +#endif // __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ + +} // namespace +#endif //__EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index b223b6694..158453e5e 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -384,8 +384,8 @@ UserInputModeView::showContextMenu(const MouseEvent& mouseEvent, mouseY, false); - UserInputModeViewContextMenu contextMenu(idManager, - tabContent, + UserInputModeViewContextMenu contextMenu(viewportContent, + idManager, openGLWidget); contextMenu.exec(menuPosition); } diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index fc78fa938..cb9dc8392 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -30,6 +30,8 @@ #include "AlgorithmNodesInsideBorder.h" #include "Border.h" #include "Brain.h" +#include "BrainBrowserWindow.h" +#include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" @@ -70,6 +72,7 @@ #include "SessionManager.h" #include "Surface.h" #include "UserInputModeFociWidget.h" +#include "UserInputTileTabsContextMenu.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" @@ -88,22 +91,36 @@ using namespace caret; */ /** * Constructor. + * + * @param viewportContent + * Content of the viewport. * @param selectionManager * The selection manager, provides data under the cursor. - * @param browserTabContent - * Content of browser tab. * @param parentOpenGLWidget * Parent OpenGL Widget on which the menu is displayed. */ -UserInputModeViewContextMenu::UserInputModeViewContextMenu(SelectionManager* selectionManager, - BrowserTabContent* browserTabContent, +UserInputModeViewContextMenu::UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, + SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget) : QMenu(parentOpenGLWidget) { + this->viewportContent = viewportContent; + CaretAssert(this->viewportContent); this->parentOpenGLWidget = parentOpenGLWidget; this->selectionManager = selectionManager; - this->browserTabContent = browserTabContent; - + this->browserTabContent = viewportContent->getBrowserTabContent(); + CaretAssert(this->browserTabContent); + + UserInputTileTabsContextMenu* tabMenu = new UserInputTileTabsContextMenu(this->parentOpenGLWidget, + this->viewportContent); + if (tabMenu->isValid()) { + addSubMenuToMenu(tabMenu, + true); + } + else { + delete tabMenu; + tabMenu = NULL; + } /* * Add the identification actions. */ @@ -191,7 +208,7 @@ UserInputModeViewContextMenu::~UserInputModeViewContextMenu() * Add the actions to this context menu. * * @param actionsToAdd - * Actions to add to the menum. + * Actions to add to the menu. * @param addSeparatorBeforeActions * If true and there are actions presently in the menu, a separator * (horizontal bar) is added prior to adding the given actions. @@ -211,6 +228,30 @@ UserInputModeViewContextMenu::addActionsToMenu(QList& actionsToAdd, } } +/** + * Add a submenu to this menu. + * + * @param menu + * Menu that is added. + * @param addSeparatorBeforeMenu + * If true and the menu is not empty, add a separator before + * adding the sub menu. + */ +void +UserInputModeViewContextMenu::addSubMenuToMenu(QMenu* menu, + const bool addSeparatorBeforeMenu) +{ + CaretAssert(menu); + + if (addSeparatorBeforeMenu) { + if (actions().isEmpty() == false) { + addSeparator(); + } + + addMenu(menu); + } + +} /** * Add the identification actions to the menu. diff --git a/src/GuiQt/UserInputModeViewContextMenu.h b/src/GuiQt/UserInputModeViewContextMenu.h index d92c209f6..7879cc992 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.h +++ b/src/GuiQt/UserInputModeViewContextMenu.h @@ -34,6 +34,7 @@ class QAction; namespace caret { class Brain; + class BrainOpenGLViewportContent; class BrainOpenGLWidget; class BrowserTabContent; class CaretMappableDataFile; @@ -49,8 +50,8 @@ namespace caret { Q_OBJECT public: - UserInputModeViewContextMenu(SelectionManager* selectionManager, - BrowserTabContent* browserTabContent, + UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, + SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget); virtual ~UserInputModeViewContextMenu(); @@ -152,6 +153,9 @@ namespace caret { void addLabelRegionOfInterestActions(); + void addSubMenuToMenu(QMenu* menu, + const bool addSeparatorBeforeMenu); + void addActionsToMenu(QList& actionsToAdd, const bool addSeparatorBeforeActions); @@ -159,6 +163,8 @@ namespace caret { std::vector parcelConnectivities; + BrainOpenGLViewportContent* viewportContent; + SelectionManager* selectionManager; BrowserTabContent* browserTabContent; diff --git a/src/GuiQt/UserInputTileTabsContextMenu.cxx b/src/GuiQt/UserInputTileTabsContextMenu.cxx new file mode 100644 index 000000000..a1699c66a --- /dev/null +++ b/src/GuiQt/UserInputTileTabsContextMenu.cxx @@ -0,0 +1,135 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ +#include "UserInputTileTabsContextMenu.h" +#undef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ + +#include "BrainBrowserWindow.h" +#include "BrainOpenGLViewportContent.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventBrowserTabGet.h" +#include "EventBrowserWindowTileTabOperation.h" +#include "EventManager.h" +#include "GuiManager.h" + +using namespace caret; + + + +/** + * \class caret::UserInputTileTabsContextMenu + * \brief Menu for tile tabs operations in a window context menu + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param parentWidget + * Parent widget on which error message dialogs are displayed + * @param viewportContent + * Content of the viewport under the mouse. + */ +UserInputTileTabsContextMenu::UserInputTileTabsContextMenu(QWidget* parentWidget, + BrainOpenGLViewportContent* viewportContent) +: QMenu("Tabs"), +m_parentWidget(parentWidget), +m_windowIndex(viewportContent->getWindowIndex()), +m_tabIndex(viewportContent->getTabIndex()) +{ + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_windowIndex); + CaretAssert(bbw); + CaretAssert(m_windowIndex >= 0); + CaretAssert(m_tabIndex >= 0); + + EventBrowserTabGet tabContentEvent(m_tabIndex); + EventManager::get()->sendEvent(tabContentEvent.getPointer()); + BrowserTabContent* tabContent = tabContentEvent.getBrowserTab(); + if (tabContent != NULL) { + const AString tabNumberText(AString::number(m_tabIndex + 1)); + + if (bbw->isTileTabsSelected()) { + m_createNewTabBeforeAction = addAction("Create New Tab Before This Tab"); + m_createNewTabAfterAction = addAction("Create New Tab After This Tab"); + m_selectTabAction = addAction("Select Tab " + tabContent->getName()); + } + + QObject::connect(this, &QMenu::triggered, + this, &UserInputTileTabsContextMenu::actionTriggered); + } +} + +/** + * Destructor. + */ +UserInputTileTabsContextMenu::~UserInputTileTabsContextMenu() +{ +} + +/** + * @return Is this menu valid? + */ +bool +UserInputTileTabsContextMenu::isValid() const +{ + return (actions().size() > 0); +} + + +/** + * Gets called when an action is selected from the menu. + * + * @param action + * Action selected by user. + */ +void +UserInputTileTabsContextMenu::actionTriggered(QAction* action) +{ + EventBrowserWindowTileTabOperation::Operation operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; + bool validOperationFlag = false; + + if (action == m_createNewTabBeforeAction) { + operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE; + validOperationFlag = true; + } + else if (action == m_createNewTabAfterAction) { + operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER; + validOperationFlag = true; + } + else if (action == m_selectTabAction) { + operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; + validOperationFlag = true; + } + else if (action != NULL) { + CaretAssertMessage(0, "Invalid menu action. Has a new menu action been added?"); + } + + if (validOperationFlag) { + EventBrowserWindowTileTabOperation tileTabOperation(operation, + m_parentWidget, + m_windowIndex, + m_tabIndex); + EventManager::get()->sendEvent(tileTabOperation.getPointer()); + } +} + diff --git a/src/GuiQt/UserInputTileTabsContextMenu.h b/src/GuiQt/UserInputTileTabsContextMenu.h new file mode 100644 index 000000000..bcb533891 --- /dev/null +++ b/src/GuiQt/UserInputTileTabsContextMenu.h @@ -0,0 +1,79 @@ +#ifndef __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ +#define __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QWidget; + +namespace caret { + + class BrainOpenGLViewportContent; + + class UserInputTileTabsContextMenu : public QMenu { + + Q_OBJECT + + public: + UserInputTileTabsContextMenu(QWidget* parentWidget, + BrainOpenGLViewportContent* viewportContent); + + virtual ~UserInputTileTabsContextMenu(); + + bool isValid() const; + + // ADD_NEW_METHODS_HERE + + private slots: + void actionTriggered(QAction* action); + + private: + UserInputTileTabsContextMenu(const UserInputTileTabsContextMenu&); + + UserInputTileTabsContextMenu& operator=(const UserInputTileTabsContextMenu&); + + QWidget* m_parentWidget; + + const int32_t m_windowIndex; + + const int32_t m_tabIndex; + + QAction* m_createNewTabBeforeAction = nullptr; + + QAction* m_createNewTabAfterAction = nullptr; + + QAction* m_selectTabAction = nullptr; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ + // +#endif // __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ + +} // namespace +#endif //__USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ -- GitLab From c5d96b8b5af44276e15208de71ae8cb6f85fbbe3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 13 Oct 2017 15:49:43 -0500 Subject: [PATCH 448/755] Fix label on tabs submenu. --- src/GuiQt/UserInputTileTabsContextMenu.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/UserInputTileTabsContextMenu.cxx b/src/GuiQt/UserInputTileTabsContextMenu.cxx index a1699c66a..051dfd164 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.cxx +++ b/src/GuiQt/UserInputTileTabsContextMenu.cxx @@ -71,7 +71,7 @@ m_tabIndex(viewportContent->getTabIndex()) if (bbw->isTileTabsSelected()) { m_createNewTabBeforeAction = addAction("Create New Tab Before This Tab"); m_createNewTabAfterAction = addAction("Create New Tab After This Tab"); - m_selectTabAction = addAction("Select Tab " + tabContent->getName()); + m_selectTabAction = addAction("Select This Tab"); } QObject::connect(this, &QMenu::triggered, -- GitLab From 22ced9bfa12142e32dc01796acd586e19bb8ad42 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 16 Oct 2017 15:50:33 -0500 Subject: [PATCH 449/755] Partial implementation of converting OpenGL lines to rectangles to avoid the limited line width range. --- src/Graphics/CMakeLists.txt | 3 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 152 +++++++++++++++++++++ src/Graphics/GraphicsOpenGLLineDrawing.h | 73 ++++++++++ src/Graphics/GraphicsPrimitive.h | 1 + 4 files changed, 229 insertions(+) create mode 100644 src/Graphics/GraphicsOpenGLLineDrawing.cxx create mode 100644 src/Graphics/GraphicsOpenGLLineDrawing.h diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index ff1474e8e..3dead4581 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -15,6 +15,7 @@ EventGraphicsOpenGLDeleteTextureName.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h +GraphicsOpenGLLineDrawing.h GraphicsOpenGLTextureName.h GraphicsPrimitive.h GraphicsPrimitiveSelectionHelper.h @@ -30,6 +31,7 @@ EventGraphicsOpenGLDeleteTextureName.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx +GraphicsOpenGLLineDrawing.cxx GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx GraphicsPrimitiveSelectionHelper.cxx @@ -45,6 +47,7 @@ GraphicsPrimitiveV3fT3f.cxx INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Graphics +${CMAKE_SOURCE_DIR}/Nifti ) TARGET_LINK_LIBRARIES(Graphics ${CARET_QT5_LINK}) diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx new file mode 100644 index 000000000..ef1396eec --- /dev/null +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -0,0 +1,152 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ +#include "GraphicsOpenGLLineDrawing.h" +#undef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ + +#include "CaretAssert.h" +#include "CaretOpenGLInclude.h" +#include "GraphicsPrimitive.h" +#include "MathFunctions.h" +#include "Matrix4x4.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLLineDrawing + * \brief Converts lines to rectangles + * \ingroup Graphics + * + * Convert lines to rectangles. + * OpenGL lines have a limited width whose maximum is often exceeded. + * Convert the lines to rectangles. All drawing is done in + * two dimensional windows coordinates. + */ + +/** + * Constructor. + * + * @param primitive + * Line primitive converted to rectangles. + * @param lineThicknessPixels + * Thickness of line in pixels. + */ +GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, + const float lineThicknessPixels) +: CaretObject(), +m_inputPrimitive(primitive), +m_lineThicknessPixels(lineThicknessPixels) +{ + +} + +/** + * Destructor. + */ +GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() +{ +} + +/** + * Run to convert the lines to rectangles. + * + * @param errorMessageOut + * Upon exit contains error information. + * @return + * True if successful, otherwise false. + */ +bool +GraphicsOpenGLLineDrawing::run(AString& errorMessageOut) +{ + errorMessageOut.clear(); + + GLfloat projectionArray[16]; + glGetFloatv(GL_PROJECTION_MATRIX, + projectionArray); + + GLfloat modelviewArray[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, + modelviewArray); + + GLint viewportArray[4]; + glGetIntegerv(GL_VIEWPORT, + viewportArray); + + Matrix4x4 matrixToViewport; + + + const std::vector& xyz = m_inputPrimitive->getFloatXYZ(); + + const int32_t numPointsMinusOne = static_cast(xyz.size() - 1); + for (int32_t i = 0; i < numPointsMinusOne; i++) { + const int32_t i3 = i * 3; + convertLineToRectangle(&xyz[i3], + &xyz[i3 + 3]); + + } + return false; +} + +void +GraphicsOpenGLLineDrawing::convertLineToRectangle(const float* startXYZ, + const float* endXYZ) +{ + float x1 = startXYZ[0]; + float y1 = startXYZ[1]; + float x2 = endXYZ[0]; + float y2 = endXYZ[1]; + + float perpendicularVector[3] = { + y2 - y1, + x2 - x1, + 0.0f + }; + + const float halfThickness = m_lineThicknessPixels / 2.0f; + MathFunctions::normalizeVector(perpendicularVector); + const float halfX = perpendicularVector[0] * halfThickness; + const float halfY = perpendicularVector[1] * halfThickness; + + float rectangleXY[8] = { + x1 - halfX, + y1 - halfY, + x1 + halfX, + y1 + halfY, + x2 + halfX, + y2 + halfY, + x2 - halfX, + x2 - halfY + }; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsOpenGLLineDrawing::toString() const +{ + return "GraphicsOpenGLLineDrawing"; +} + diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h new file mode 100644 index 000000000..107d98d57 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -0,0 +1,73 @@ +#ifndef __GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ +#define __GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class GraphicsPrimitive; + + class GraphicsOpenGLLineDrawing : public CaretObject { + + public: + GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, + const float lineThicknessPixels); + + virtual ~GraphicsOpenGLLineDrawing(); + + bool run(AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + GraphicsOpenGLLineDrawing(const GraphicsOpenGLLineDrawing& obj); + + GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj); + + void convertLineToRectangle(const float* startXYZ, + const float* endXYZ); + + const GraphicsPrimitive* m_inputPrimitive; + + const float m_lineThicknessPixels; + + GraphicsPrimitive* m_outputPrimitive = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ + // +#endif // __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index e58dc2f7d..427d24dfd 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -323,6 +323,7 @@ namespace caret { void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); friend class GraphicsEngineDataOpenGL; + friend class GraphicsOpenGLLineDrawing; friend class GraphicsPrimitiveSelectionHelper; std::vector m_dummyFloatRGBAVector; -- GitLab From e8c19d1befed688e29d5a69101387d5418ebf49d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 17 Oct 2017 16:39:01 -0500 Subject: [PATCH 450/755] Scene File Base Path Updates (WB-695): There is now a 'base path mode'. When a scene file is zipped, if the mode is automatic, Workbench will determine the base path and provide it to the ZIP scene file command. The other base path mode is CUSTOM that requires the user to provide the base path used when zipping a scene file. A widget containing these base path controls has been created and is used by the BALSA upload dialog. These base patch controls are now on the 'Advanced' tab in the BALSA dialog. The base path is stored in the scene file only when the mode is CUSTOM and the base path is in the scene file as a relative path in relation to the scene file. --- src/Files/SceneFile.cxx | 66 ++- src/Files/SceneFile.h | 8 + src/Files/SceneFileSaxReader.cxx | 71 +++- src/Files/SceneFileSaxReader.h | 10 +- src/GuiQt/BalsaDatabaseManager.cxx | 30 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 144 ++----- .../BalsaDatabaseUploadSceneFileDialog.h | 14 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/SceneBasePathWidget.cxx | 190 +++++++++ src/GuiQt/SceneBasePathWidget.h | 78 ++++ src/Scenes/CMakeLists.txt | 2 + src/Scenes/SceneFileBasePathTypeEnum.cxx | 376 ++++++++++++++++++ src/Scenes/SceneFileBasePathTypeEnum.h | 104 +++++ src/Scenes/SceneXmlElements.h | 7 +- 14 files changed, 971 insertions(+), 132 deletions(-) create mode 100644 src/GuiQt/SceneBasePathWidget.cxx create mode 100644 src/GuiQt/SceneBasePathWidget.h create mode 100644 src/Scenes/SceneFileBasePathTypeEnum.cxx create mode 100644 src/Scenes/SceneFileBasePathTypeEnum.h diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 8bfb9d91e..1e5f6756a 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -47,6 +47,7 @@ #include "SceneXmlElements.h" #include "SceneWriterXml.h" #include "SpecFile.h" +#include "SystemUtilities.h" #include "XmlSaxParser.h" #include "XmlWriter.h" @@ -69,6 +70,7 @@ SceneFile::SceneFile() m_balsaStudyTitle = ""; m_balsaBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; + m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; m_metadata = new GiftiMetaData(); } @@ -101,6 +103,7 @@ SceneFile::clear() m_balsaStudyTitle = ""; m_balsaBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; + m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; for (std::vector::iterator iter = m_scenes.begin(); iter != m_scenes.end(); @@ -544,6 +547,29 @@ SceneFile::setBalsaBaseDirectory(const AString& balsaBaseDirectory) } } +/** + * @return The base path type. + */ +SceneFileBasePathTypeEnum::Enum +SceneFile::getBasePathType() const +{ + return m_basePathType; +} + +/** + * Set the base path type. + * + * @param basePathType + * New type for base path. + */ +void SceneFile::setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathType) +{ + if (basePathType != m_basePathType) { + m_basePathType = basePathType; + setModified(); + } +} + /** * Read the scene file. @@ -565,7 +591,8 @@ SceneFile::readFile(const AString& filenameIn) checkFileReadability(filename); this->setFileName(filename); - SceneFileSaxReader saxReader(this); + SceneFileSaxReader saxReader(this, + filename); std::auto_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); @@ -679,10 +706,43 @@ SceneFile::writeFile(const AString& filename) getBalsaStudyID()); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG, getBalsaStudyTitle()); - xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, - getBalsaBaseDirectory()); + switch (getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, + ""); + break; + case SceneFileBasePathTypeEnum::CUSTOM: + { + /* + * Write base path as a path RELATIVE to the scene file + * but only when base path type is CUSTOM + * Note: we do not use FileInformation::getCanonicalFilePath() + * because it returns an empty string if the file DOES NOT exist + * and this may occur since the file may be new and has not + * been closed. + */ + if ( ! getBalsaBaseDirectory().isEmpty()) { + const AString baseDirAbsPath = FileInformation(getBalsaBaseDirectory()).getAbsoluteFilePath(); + const AString sceneFileAbsPath = FileInformation(filename).getAbsoluteFilePath(); + ScenePathName basePathName("basePathName", + baseDirAbsPath); + + const AString relativeBasePath = basePathName.getRelativePathToSceneFile(sceneFileAbsPath); + + //std::cout << "baseDirAbsPath: " << baseDirAbsPath << std::endl; + //std::cout << "sceneFileAbsPath: " << sceneFileAbsPath << std::endl; + //std::cout << "relativeTempFileName: " << relativeBasePath << std::endl; + + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, + relativeBasePath); + } + } + break; + } xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG, getBalsaExtractToDirectoryName()); + xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BASE_PATH_TYPE, + SceneFileBasePathTypeEnum::toName(getBasePathType())); for (int32_t i = 0; i < numScenes; i++) { m_scenes[i]->getSceneInfo()->writeSceneInfo(xmlWriter, diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index dedb396c1..60e38b625 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -23,6 +23,7 @@ #include "CaretDataFile.h" +#include "SceneFileBasePathTypeEnum.h" namespace caret { @@ -91,6 +92,10 @@ namespace caret { void setBalsaStudyTitle(const AString& balsaStudyTitle); + SceneFileBasePathTypeEnum::Enum getBasePathType() const; + + void setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathType); + AString getBalsaBaseDirectory() const; void setBalsaBaseDirectory(const AString& balsaBaseDirectory); @@ -141,6 +146,9 @@ namespace caret { /** the BALSA Study Title */ AString m_balsaStudyTitle; + /** the Base Path Type */ + SceneFileBasePathTypeEnum::Enum m_basePathType; + /** the Base Directory */ AString m_balsaBaseDirectory; diff --git a/src/Files/SceneFileSaxReader.cxx b/src/Files/SceneFileSaxReader.cxx index 6a41ceedf..0630c03ae 100644 --- a/src/Files/SceneFileSaxReader.cxx +++ b/src/Files/SceneFileSaxReader.cxx @@ -22,6 +22,7 @@ #include "CaretAssert.h" #include "CaretLogger.h" +#include "FileInformation.h" #include "GiftiMetaDataSaxReader.h" #include "GiftiXmlElements.h" #include "Scene.h" @@ -29,6 +30,7 @@ #include "SceneFileSaxReader.h" #include "SceneInfo.h" #include "SceneInfoSaxReader.h" +#include "ScenePathName.h" #include "SceneXmlElements.h" #include "XmlAttributes.h" @@ -45,10 +47,12 @@ using namespace caret; /** * constructor. */ -SceneFileSaxReader::SceneFileSaxReader(SceneFile* sceneFile) +SceneFileSaxReader::SceneFileSaxReader(SceneFile* sceneFile, + const AString& sceneFileName) { CaretAssert(sceneFile); m_sceneFile = sceneFile; + m_sceneFileName = sceneFileName; m_state = STATE_NONE; m_stateStack.push(m_state); m_elementText = ""; @@ -56,6 +60,7 @@ SceneFileSaxReader::SceneFileSaxReader(SceneFile* sceneFile) m_sceneSaxReader = NULL; m_sceneInfoSaxReader = NULL; m_scene = NULL; + m_baseBathTypeWasFoundFlag = false; } /** @@ -138,6 +143,9 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, else if (qName == SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG) { m_state = STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY; } + else if (qName == SceneXmlElements::SCENE_INFO_BASE_PATH_TYPE) { + m_state = STATE_SCENE_INFO_BASE_PATH_TYPE; + } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(SceneXmlElements::SCENE_INFO_TAG, qName); @@ -155,6 +163,8 @@ SceneFileSaxReader::startElement(const AString& namespaceURI, break; case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: break; + case STATE_SCENE_INFO_BASE_PATH_TYPE: + break; case STATE_SCENE_INFO: m_sceneInfoSaxReader->startElement(namespaceURI, localName, qName, attributes); break; @@ -248,6 +258,24 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: m_sceneFile->setBalsaExtractToDirectoryName(m_elementText); break; + case STATE_SCENE_INFO_BASE_PATH_TYPE: + { + SceneFileBasePathTypeEnum::Enum basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; + bool validFlag = false; + basePathType = SceneFileBasePathTypeEnum::fromName(m_elementText, &validFlag); + if (validFlag) { + m_baseBathTypeWasFoundFlag = true; + } + else { + basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; + + AString msg("Invalid BasePathType name: " + m_elementText); + XmlSaxParserException e(msg); + warning(e); + } + m_sceneFile->setBasePathType(basePathType); + } + break; case STATE_SCENE_INFO: CaretAssert(m_sceneInfo); CaretAssert(m_sceneInfoSaxReader); @@ -282,6 +310,47 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, CaretLogSevere(msg); } } + + if (m_baseBathTypeWasFoundFlag) { + switch (m_sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + m_sceneFile->setBalsaBaseDirectory(""); + break; + case SceneFileBasePathTypeEnum::CUSTOM: + { + AString basePath = m_sceneFile->getBalsaBaseDirectory(); + if ( ! basePath.isEmpty()) { + FileInformation basePathInfo(basePath); + if (basePathInfo.isRelative()) { +// FileInformation tempBaseFile(basePath, +// "temp.txt"); + ScenePathName basePathName("basePathName", + ""); + basePathName.setValueToAbsolutePath(m_sceneFileName, + (basePath)); // + "/temp.txt")); + basePath = basePathName.stringValue(); + } + } + m_sceneFile->setBalsaBaseDirectory(basePath); + } + break; + } + } + else { + /* + * Base path type was added by WB- in Oct 2017. + * If it is not found, the file was created prior to adding the + * base path type. If there is no base path, the go ahead and + * use AUTOMATIC mode. If there is a base path assume it is valid + * and use CUSTOM mode. + */ + if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { + m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); + } + else { + m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); + } + } } break; case STATE_METADATA: diff --git a/src/Files/SceneFileSaxReader.h b/src/Files/SceneFileSaxReader.h index f4a45f29c..531e1f5f9 100644 --- a/src/Files/SceneFileSaxReader.h +++ b/src/Files/SceneFileSaxReader.h @@ -44,7 +44,8 @@ namespace caret { class SceneFileSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: - SceneFileSaxReader(SceneFile* sceneFile); + SceneFileSaxReader(SceneFile* sceneFile, + const AString& sceneFileName); virtual ~SceneFileSaxReader(); @@ -89,6 +90,8 @@ namespace caret { STATE_SCENE_INFO_BALSA_BASE_DIRECTORY, /// processing scene info Balsa Extract to Directory STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY, + /// processing base path type + STATE_SCENE_INFO_BASE_PATH_TYPE, /// processing SceneInfo tag STATE_SCENE_INFO, /// processing Scene tag @@ -110,6 +113,9 @@ namespace caret { /// scene that is being read Scene* m_scene; + /// name of scene file being read + AString m_sceneFileName; + /// scene info that is being read SceneInfo* m_sceneInfo; @@ -130,6 +136,8 @@ namespace caret { /// map that stores scene info by index std::map m_sceneInfoMap; + + bool m_baseBathTypeWasFoundFlag = false; }; } // namespace diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 8d4f1c735..235f54f95 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -457,10 +457,30 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, return false; } - AString baseDirectoryName; - if ( ! sceneFile->getBalsaBaseDirectory().isEmpty()) { - /* validate ? */ - baseDirectoryName = sceneFile->getBalsaBaseDirectory(); + AString basePathName = sceneFile->getBalsaBaseDirectory(); + + switch (sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + basePathName = sceneFile->findBaseDirectoryForDataFiles(); + if ( ! FileInformation(basePathName).exists()) { + errorMessageOut = ("AUTOMATIC base path mode produced an invalid base path (directory does not exist): \"" + + basePathName + + "\""); + return false; + } + break; + case SceneFileBasePathTypeEnum::CUSTOM: + if (basePathName.isEmpty()) { + errorMessageOut = ("CUSTOM base path is empty"); + return false; + } + if ( ! FileInformation(basePathName).exists()) { + errorMessageOut = ("CUSTOM base path is invalid (directory does not exist): \"" + + basePathName + + "\""); + return false; + } + break; } bool successFlag = false; @@ -468,7 +488,7 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, OperationZipSceneFile::createZipFile(sceneFileName, extractToDirectoryName, zipFileName, - baseDirectoryName, + basePathName, OperationZipSceneFile::PROGRESS_GUI_EVENT, NULL); successFlag = true; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 8a97243d9..55acf807c 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -51,6 +51,7 @@ #include "FileInformation.h" #include "GuiManager.h" #include "ProgressReportingDialog.h" +#include "SceneBasePathWidget.h" #include "SceneFile.h" #include "SystemUtilities.h" #include "WuQDataEntryDialog.h" @@ -88,7 +89,7 @@ m_sceneFile(sceneFile) QWidget* loginWidget = createLoginWidget(); m_uploadWidget = createUploadWidget(); - m_uploadWidget->setEnabled(false); + m_uploadPushButton->setEnabled(false); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); @@ -105,6 +106,8 @@ m_sceneFile(sceneFile) setOkButtonText(""); setCancelButtonText("Close"); + + m_basePathWidget->updateSceneFile(m_sceneFile); } /** @@ -262,7 +265,7 @@ void BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() { m_balsaDatabaseManager->logout(); - m_uploadWidget->setEnabled(false); + m_uploadPushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateAllLabels(); } @@ -332,32 +335,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); - /* - * Base Directory - */ - m_baseDirectoryLabel = new QLabel(""); - m_baseDirectoryLineEdit = new QLineEdit(); - m_baseDirectoryLineEdit->setToolTip("Directory that contains all data files"); - m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::LABEL_BASE_DIRECTORY)); - QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateUploadData(); }); - - /* - * Browse for base directory - */ - m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); - m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); - QObject::connect(m_browseBaseDirectoryPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked); - - /* - * Browse for base directory - */ - m_findBaseDirectoryPushButton = new QPushButton("Find"); - m_findBaseDirectoryPushButton->setToolTip("Find the base directory by examining files in all scenes"); - QObject::connect(m_findBaseDirectoryPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked); - /* * Roles button */ @@ -401,11 +378,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); row++; - gridLayout->addWidget(m_baseDirectoryLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_baseDirectoryLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, COLUMN_BUTTON_ONE); - gridLayout->addWidget(m_findBaseDirectoryPushButton, row, COLUMN_BUTTON_TWO); - row++; gridLayout->addWidget(m_balsaStudyTitleLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(m_selectStudyTitlePushButton, row, COLUMN_BUTTON_ONE, 1, 2); @@ -422,11 +394,10 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); - AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); - if (baseDirectory.isEmpty()) { - baseDirectory = m_sceneFile->findBaseDirectoryForDataFiles(); - } - m_baseDirectoryLineEdit->setText(baseDirectory); +// AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); +// if (baseDirectory.isEmpty()) { +// baseDirectory = m_sceneFile->findBaseDirectoryForDataFiles(); +// } m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); m_extractDirectoryNameLineEdit->setText(m_sceneFile->getBalsaExtractToDirectoryName()); @@ -472,9 +443,13 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() gridLayout->addWidget(browseCustomDirectoryPushButton, 1, 2); row++; + m_basePathWidget = new SceneBasePathWidget(); + QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(zipDirectoryGroupBox); + //layout->addWidget(m_basePathWidget, 0, Qt::AlignLeft); + layout->addWidget(m_basePathWidget); layout->addStretch(); return widget; @@ -570,7 +545,7 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); - m_uploadWidget->setEnabled(false); + m_uploadPushButton->setEnabled(false); CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -618,7 +593,7 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() WuQMessageBox::warningOk(this, msg); } - m_uploadWidget->setEnabled(true); + m_uploadPushButton->setEnabled(true); } /** @@ -631,7 +606,6 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() m_sceneFile->setBalsaStudyID(m_balsaStudyIDLineEdit->text().trimmed()); m_sceneFile->setBalsaStudyTitle(m_balsaStudyTitleLineEdit->text().trimmed()); - m_sceneFile->setBalsaBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); AString zipFileErrorMessage; const AString zipFileName = getZipFileNameWithPath(zipFileErrorMessage); @@ -651,9 +625,26 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Extract to Directory is invalid.

"); } - if ( ! m_baseDirectoryLineEdit->hasAcceptableInput()) { - msg.appendWithNewLine("Base Directory is invalid.

"); + + switch (m_sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + break; + case SceneFileBasePathTypeEnum::CUSTOM: + { + if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { + msg.appendWithNewLine("CUSTOM Base Path (on Advanced Tab) is invalid. " + "Select Base Path or use AUTOMATIC.

"); + } + else { + if ( ! FileInformation(m_sceneFile->getBalsaBaseDirectory()).exists()) { + msg.appendWithNewLine("CUSTOM Base Directory (on Advanced Tab) is not a valid directory on this computer. " + "Select a valid Base Path or use AUTOMATIC.

"); + } + } + } + break; } + bool invalidStudyFlag = false; if ( ! m_balsaStudyTitleLineEdit->hasAcceptableInput()) { invalidStudyFlag = true; @@ -869,41 +860,6 @@ BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicke validateUploadData(); } -/** - * Called when upload scene file is selected. - */ -void -BalsaDatabaseUploadSceneFileDialog::browseBaseDirectoryPushButtonClicked() -{ - CaretAssert(m_sceneFile); - - /* - * Let user choose directory path - */ - QString directoryName; - FileInformation fileInfo(m_baseDirectoryLineEdit->text().trimmed()); - if (fileInfo.exists()) { - if (fileInfo.isDirectory()) { - directoryName = fileInfo.getAbsoluteFilePath(); - } - } - AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, - "Choose Base Directory", - directoryName); - /* - * If user cancels, return - */ - if (newDirectoryName.isEmpty()) { - return; - } - - /* - * Set name of new scene file and add to brain - */ - m_baseDirectoryLineEdit->setText(newDirectoryName); - validateUploadData(); -} - /** * Create a regular expression validatory for the give label/data. * @@ -916,9 +872,6 @@ BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) QRegularExpression regEx; switch (labelName) { - case LabelName::LABEL_BASE_DIRECTORY: - regEx.setPattern(".+"); - break; case LabelName::LABEL_DATABASE: regEx.setPattern(".+"); break; @@ -964,7 +917,6 @@ BalsaDatabaseUploadSceneFileDialog::validateUploadData() void BalsaDatabaseUploadSceneFileDialog::updateAllLabels() { - setLabelText(LabelName::LABEL_BASE_DIRECTORY); setLabelText(LabelName::LABEL_DATABASE); setLabelText(LabelName::LABEL_EXTRACT_DIRECTORY); setLabelText(LabelName::LABEL_PASSWORD); @@ -989,11 +941,6 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) AString labelText; bool validFlag = false; switch (labelName) { - case LabelName::LABEL_BASE_DIRECTORY: - label = m_baseDirectoryLabel; - labelText = "Base Directory"; - validFlag = m_baseDirectoryLineEdit->hasAcceptableInput(); - break; case LabelName::LABEL_DATABASE: label = m_databaseLabel; labelText = "Database"; @@ -1057,26 +1004,3 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) CaretAssert(label); label->setText(coloredText); } - -/** - * Called when find base directory push button is clicked. - */ -void -BalsaDatabaseUploadSceneFileDialog::findBaseDirectoryPushButtonClicked() -{ - CaretAssert(m_sceneFile); - - const AString baseDirectoryName = m_sceneFile->findBaseDirectoryForDataFiles(); - - if (baseDirectoryName.isEmpty()) { - return; - } - - /* - * Set name for base directory - */ - m_baseDirectoryLineEdit->setText(baseDirectoryName); - validateUploadData(); -} - - diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 510285399..66890b27e 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -38,6 +38,7 @@ class QRegularExpressionValidator; namespace caret { class BalsaDatabaseManager; class BalsaUserRoles; + class SceneBasePathWidget; class SceneFile; class BalsaDatabaseUploadSceneFileDialog : public WuQDialogModal { @@ -63,8 +64,6 @@ namespace caret { void labelHtmlLinkClicked(const QString&); - void browseBaseDirectoryPushButtonClicked(); - void validateUploadData(); void selectStudyTitleButtonClicked(); @@ -73,8 +72,6 @@ namespace caret { void browseZipFileCustomDirectoryPushButtonClicked(); - void findBaseDirectoryPushButtonClicked(); - void rolesButtonClicked(); void autoSaveCheckBoxClicked(bool checked); @@ -85,7 +82,6 @@ namespace caret { private: enum class LabelName { - LABEL_BASE_DIRECTORY, LABEL_DATABASE, LABEL_EXTRACT_DIRECTORY, LABEL_PASSWORD, @@ -153,15 +149,11 @@ namespace caret { QLineEdit* m_balsaStudyTitleLineEdit; QPushButton* m_selectStudyTitlePushButton; - QPushButton* m_browseBaseDirectoryPushButton; - QPushButton* m_findBaseDirectoryPushButton; - - QLabel* m_baseDirectoryLabel; - QLineEdit* m_baseDirectoryLineEdit; - QCheckBox* m_autoSaveSceneFileCheckBox; QPushButton* m_uploadPushButton; + SceneBasePathWidget* m_basePathWidget; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index df0d13132..1855e451a 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -157,6 +157,7 @@ ELSE() ProgressReportingFromEvent.h ProgressReportingWithSlots.h RegionOfInterestCreateFromBorderDialog.h + SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h @@ -379,6 +380,7 @@ ProgressReportingFromEvent.h ProgressReportingWithSlots.h QGLWidgetTextRenderer.h RegionOfInterestCreateFromBorderDialog.h +SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h ScenePreviewDialog.h @@ -596,6 +598,7 @@ ProgressReportingFromEvent.cxx ProgressReportingWithSlots.cxx QGLWidgetTextRenderer.cxx RegionOfInterestCreateFromBorderDialog.cxx +SceneBasePathWidget.cxx SceneCreateReplaceDialog.cxx SceneDialog.cxx ScenePreviewDialog.cxx diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx new file mode 100644 index 000000000..db5f73b83 --- /dev/null +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -0,0 +1,190 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#include +#include +#include +#include +#include +#include + +#define __SCENE_BASE_PATH_WIDGET_DECLARE__ +#include "SceneBasePathWidget.h" +#undef __SCENE_BASE_PATH_WIDGET_DECLARE__ + +#include "CaretAssert.h" +#include "CaretFileDialog.h" +#include "FileInformation.h" +#include "SceneFile.h" + +using namespace caret; + + + +/** + * \class caret::SceneBasePathWidget + * \brief Widget for setting scene file base path. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param widget + * Optional parent. + */ +SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) +: QWidget(widget) +{ + m_automaticRadioButton = new QRadioButton("Automatic"); + m_customRadioButton = new QRadioButton("Custom"); + + QButtonGroup* buttGroup = new QButtonGroup(this); + buttGroup->addButton(m_automaticRadioButton); + buttGroup->addButton(m_customRadioButton); + QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), + this, [=](QAbstractButton* button){ this->basePathTypeButtonGroupClicked(button); }); + + m_basePathLineEdit = new QLineEdit; + m_basePathLineEdit->setReadOnly(true); + + QPushButton* browsePushButton = new QPushButton("Browse..."); + QObject::connect(browsePushButton, &QPushButton::clicked, + this, &SceneBasePathWidget::browseButtonClicked); + + QGroupBox* groupBox = new QGroupBox("Base Path"); + QGridLayout* gridLayout = new QGridLayout(groupBox); + gridLayout->setSpacing(2); + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 100); + gridLayout->setColumnStretch(2, 0); + int row = 0; + gridLayout->addWidget(m_automaticRadioButton, + row, 0, 1, 2, Qt::AlignLeft); + row++; + gridLayout->addWidget(m_customRadioButton, + row, 0); + gridLayout->addWidget(m_basePathLineEdit, + row, 1); + gridLayout->addWidget(browsePushButton, + row, 2); + + QVBoxLayout* widgetLayout = new QVBoxLayout(this); + widgetLayout->setContentsMargins(0, 0, 0, 0); + widgetLayout->addWidget(groupBox); + +// setSizePolicy(sizePolicy().horizontalPolicy(), +// QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +SceneBasePathWidget::~SceneBasePathWidget() +{ +} + +/** + * Update the widget with the given scene file. + * + * @param sceneFile + * The scene file. + */ +void +SceneBasePathWidget::updateSceneFile(SceneFile* sceneFile) +{ + m_sceneFile = sceneFile; + + if (m_sceneFile != NULL) { + m_basePathLineEdit->setText(m_sceneFile->getBalsaBaseDirectory()); + switch (m_sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + m_automaticRadioButton->setChecked(true); + m_basePathLineEdit->setEnabled(false); + break; + case SceneFileBasePathTypeEnum::CUSTOM: + m_customRadioButton->setChecked(true); + m_basePathLineEdit->setEnabled(true); + break; + } + setEnabled(true); + } + else { + m_basePathLineEdit->setText(""); + setEnabled(false); + } +} + +/** + * Gets called when the browse button is clicked. + */ +void +SceneBasePathWidget::browseButtonClicked() +{ + CaretAssert(m_sceneFile); + + /* + * Let user choose directory path + */ + QString directoryName; + FileInformation fileInfo(m_basePathLineEdit->text().trimmed()); + if (fileInfo.exists()) { + if (fileInfo.isDirectory()) { + directoryName = fileInfo.getAbsoluteFilePath(); + } + } + AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(this, + "Choose Base Path", + directoryName); + /* + * If user cancels, return + */ + if (newDirectoryName.isEmpty()) { + return; + } + + m_sceneFile->setBalsaBaseDirectory(newDirectoryName); + m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); + updateSceneFile(m_sceneFile); +} + +/** + * Gets called when on of the radio buttons is clicked. + * + * @param button + * Button that was clicked. + */ +void +SceneBasePathWidget::basePathTypeButtonGroupClicked(QAbstractButton* button) +{ + if (button == m_automaticRadioButton) { + m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); + } + else if (button == m_customRadioButton) { + m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); + } + else { + CaretAssertMessage(0, "Has a new SceneFileBasePathTypeEnum::Enum been added?"); + } + + updateSceneFile(m_sceneFile); +} diff --git a/src/GuiQt/SceneBasePathWidget.h b/src/GuiQt/SceneBasePathWidget.h new file mode 100644 index 000000000..c7171640f --- /dev/null +++ b/src/GuiQt/SceneBasePathWidget.h @@ -0,0 +1,78 @@ +#ifndef __SCENE_BASE_PATH_WIDGET_H__ +#define __SCENE_BASE_PATH_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QAbstractButton; +class QLineEdit; +class QRadioButton; + +namespace caret { + + class SceneFile; + + class SceneBasePathWidget : public QWidget { + + Q_OBJECT + + public: + SceneBasePathWidget(QWidget* parent = 0); + + virtual ~SceneBasePathWidget(); + + void updateSceneFile(SceneFile* sceneFile); + + // ADD_NEW_METHODS_HERE + + private slots: + void browseButtonClicked(); + + void basePathTypeButtonGroupClicked(QAbstractButton* button); + + private: + SceneBasePathWidget(const SceneBasePathWidget&); + + SceneBasePathWidget& operator=(const SceneBasePathWidget&); + + SceneFile* m_sceneFile = NULL; + + QLineEdit* m_basePathLineEdit; + + QRadioButton* m_automaticRadioButton; + + QRadioButton* m_customRadioButton; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SCENE_BASE_PATH_WIDGET_DECLARE__ + // +#endif // __SCENE_BASE_PATH_WIDGET_DECLARE__ + +} // namespace +#endif //__SCENE_BASE_PATH_WIDGET_H__ diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index d0cbcad38..ae9c80404 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -44,6 +44,7 @@ SceneClassArray.h SceneClassAssistant.h SceneEnumeratedTypeArray.h SceneEnumeratedType.h +SceneFileBasePathTypeEnum.h SceneFloat.h SceneFloatArray.h SceneInfo.h @@ -80,6 +81,7 @@ SceneClassArray.cxx SceneClassAssistant.cxx SceneEnumeratedTypeArray.cxx SceneEnumeratedType.cxx +SceneFileBasePathTypeEnum.cxx SceneFloat.cxx SceneFloatArray.cxx SceneInfo.cxx diff --git a/src/Scenes/SceneFileBasePathTypeEnum.cxx b/src/Scenes/SceneFileBasePathTypeEnum.cxx new file mode 100644 index 000000000..e64535c40 --- /dev/null +++ b/src/Scenes/SceneFileBasePathTypeEnum.cxx @@ -0,0 +1,376 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __SCENE_FILE_BASE_PATH_TYPE_ENUM_DECLARE__ +#include "SceneFileBasePathTypeEnum.h" +#undef __SCENE_FILE_BASE_PATH_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::SceneFileBasePathTypeEnum + * \brief Type of base path for the scene file. + * + * When Automatic, Workbench determines scene file at time of zipping + * When Custom, user chooses the base path + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_sceneFileBasePathTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void sceneFileBasePathTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "SceneFileBasePathTypeEnum.h" + * + * Instatiate: + * m_sceneFileBasePathTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_sceneFileBasePathTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_sceneFileBasePathTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(sceneFileBasePathTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_sceneFileBasePathTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const SceneFileBasePathTypeEnum::Enum VARIABLE = m_sceneFileBasePathTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +SceneFileBasePathTypeEnum::SceneFileBasePathTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +SceneFileBasePathTypeEnum::~SceneFileBasePathTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +SceneFileBasePathTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(SceneFileBasePathTypeEnum(AUTOMATIC, + "AUTOMATIC", + "Automatic")); + + enumData.push_back(SceneFileBasePathTypeEnum(CUSTOM, + "CUSTOM", + "Custom")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const SceneFileBasePathTypeEnum* +SceneFileBasePathTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const SceneFileBasePathTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +SceneFileBasePathTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const SceneFileBasePathTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +SceneFileBasePathTypeEnum::Enum +SceneFileBasePathTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneFileBasePathTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneFileBasePathTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SceneFileBasePathTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +SceneFileBasePathTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const SceneFileBasePathTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +SceneFileBasePathTypeEnum::Enum +SceneFileBasePathTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneFileBasePathTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneFileBasePathTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SceneFileBasePathTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +SceneFileBasePathTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const SceneFileBasePathTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +SceneFileBasePathTypeEnum::Enum +SceneFileBasePathTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = SceneFileBasePathTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const SceneFileBasePathTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SceneFileBasePathTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +SceneFileBasePathTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +SceneFileBasePathTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(SceneFileBasePathTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +SceneFileBasePathTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(SceneFileBasePathTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Scenes/SceneFileBasePathTypeEnum.h b/src/Scenes/SceneFileBasePathTypeEnum.h new file mode 100644 index 000000000..4079f01d7 --- /dev/null +++ b/src/Scenes/SceneFileBasePathTypeEnum.h @@ -0,0 +1,104 @@ +#ifndef __SCENE_FILE_BASE_PATH_TYPE_ENUM_H__ +#define __SCENE_FILE_BASE_PATH_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class SceneFileBasePathTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Automatic */ + AUTOMATIC, + /** Custom */ + CUSTOM + }; + + + ~SceneFileBasePathTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + SceneFileBasePathTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const SceneFileBasePathTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __SCENE_FILE_BASE_PATH_TYPE_ENUM_DECLARE__ +std::vector SceneFileBasePathTypeEnum::enumData; +bool SceneFileBasePathTypeEnum::initializedFlag = false; +int32_t SceneFileBasePathTypeEnum::integerCodeCounter = 0; +#endif // __SCENE_FILE_BASE_PATH_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__SCENE_FILE_BASE_PATH_TYPE_ENUM_H__ diff --git a/src/Scenes/SceneXmlElements.h b/src/Scenes/SceneXmlElements.h index 42370c80b..5ea4d3423 100644 --- a/src/Scenes/SceneXmlElements.h +++ b/src/Scenes/SceneXmlElements.h @@ -168,10 +168,15 @@ namespace caret { static const AString SCENE_INFO_BALSA_BASE_DIRECTORY_TAG_OLD = "BaseDirectory"; /** - * XML Tag for Base Directory ID element. + * XML Tag for Extract Directory ID element. */ static const AString SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG = "BalsaExtractToDirectory"; + /** + * XML Tag for Base Path Type + */ + static const AString SCENE_INFO_BASE_PATH_TYPE = "BasePathType"; + } // namespace SceneXmlElements } // namespace caret -- GitLab From adef39f04e86593136919d3ebe589452b3865e76 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 18 Oct 2017 08:21:40 -0500 Subject: [PATCH 451/755] Updates for login --- src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 55acf807c..351addb49 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -139,13 +139,8 @@ BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() QWidget* BalsaDatabaseUploadSceneFileDialog::createLoginWidget() { - QString defaultUserName = "balsaTest"; - QString defaultPassword = "@2password"; - -#ifdef NDEBUG - defaultUserName = ""; - defaultPassword = ""; -#endif + AString defaultUserName; + AString defaultPassword; /* * Create the BALSA database manager -- GitLab From ff5e9eeba80a71dfc1c73997b24998d5636a208f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 18 Oct 2017 10:37:30 -0500 Subject: [PATCH 452/755] Scene File Base Path Updates (WB-695): Updates to BALSA Upload and Zip Scene File dialogs have been completed. --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 69 +++++---- .../BalsaDatabaseUploadSceneFileDialog.h | 8 +- src/GuiQt/SceneBasePathWidget.cxx | 46 +++++- src/GuiQt/SceneBasePathWidget.h | 6 +- src/GuiQt/ZipSceneFileDialog.cxx | 143 ++++-------------- src/GuiQt/ZipSceneFileDialog.h | 14 +- 6 files changed, 121 insertions(+), 165 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 351addb49..95911eda7 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -88,7 +88,7 @@ m_sceneFile(sceneFile) m_userRoles.reset(new BalsaUserRoles); QWidget* loginWidget = createLoginWidget(); - m_uploadWidget = createUploadWidget(); + m_uploadWidget = createTabWidget(); m_uploadPushButton->setEnabled(false); QWidget* dialogWidget = new QWidget(); @@ -107,7 +107,7 @@ m_sceneFile(sceneFile) setOkButtonText(""); setCancelButtonText("Close"); - m_basePathWidget->updateSceneFile(m_sceneFile); + m_basePathWidget->updateWithSceneFile(m_sceneFile); } /** @@ -124,6 +124,9 @@ BalsaDatabaseUploadSceneFileDialog::~BalsaDatabaseUploadSceneFileDialog() void BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() { + s_username = m_usernameLineEdit->text(); + s_password = m_passwordLineEdit->text(); + /* * Will logout of database and disable part of dialog */ @@ -139,9 +142,6 @@ BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() QWidget* BalsaDatabaseUploadSceneFileDialog::createLoginWidget() { - AString defaultUserName; - AString defaultPassword; - /* * Create the BALSA database manager */ @@ -169,7 +169,7 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() m_usernameLabel = new QLabel(""); m_usernameLineEdit = new QLineEdit(); m_usernameLineEdit->setMinimumWidth(minimumLineEditWidth); - m_usernameLineEdit->setText(defaultUserName); + m_usernameLineEdit->setText(s_username); m_usernameLineEdit->setValidator(createValidator(LabelName::LABEL_USERNAME)); QObject::connect(m_usernameLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); @@ -181,7 +181,7 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() m_passwordLineEdit = new QLineEdit(); m_passwordLineEdit->setMinimumWidth(minimumLineEditWidth); m_passwordLineEdit->setEchoMode(QLineEdit::Password); - m_passwordLineEdit->setText(defaultPassword); + m_passwordLineEdit->setText(s_password); m_passwordLineEdit->setValidator(createValidator(LabelName::LABEL_PASSWORD)); QObject::connect(m_passwordLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); @@ -228,7 +228,7 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() QGroupBox* groupBox = new QGroupBox("Database Login"); QGridLayout* gridLayout = new QGridLayout(groupBox); - gridLayout->setSpacing(2); + gridLayout->setSpacing(5); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); @@ -269,7 +269,7 @@ BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() * @return The upload widget */ QWidget* -BalsaDatabaseUploadSceneFileDialog::createUploadWidget() +BalsaDatabaseUploadSceneFileDialog::createTabWidget() { QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(createUploadTab(), "Upload"); @@ -361,9 +361,8 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() const int COLUMN_BUTTON_ONE = columnCounter++; const int COLUMN_BUTTON_TWO = columnCounter++; - QWidget* widget = new QWidget(); - QGridLayout* gridLayout = new QGridLayout(widget); - gridLayout->setSpacing(2); + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->setSpacing(5); gridLayout->setColumnMinimumWidth(COLUMN_DATA_WIDGET, 300); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); @@ -389,10 +388,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); -// AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); -// if (baseDirectory.isEmpty()) { -// baseDirectory = m_sceneFile->findBaseDirectoryForDataFiles(); -// } m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); m_extractDirectoryNameLineEdit->setText(m_sceneFile->getBalsaExtractToDirectoryName()); @@ -400,6 +395,10 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_extractDirectoryNameLineEdit->setText(m_sceneFile->getDefaultExtractToDirectoryName()); } + QWidget* widget = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addLayout(gridLayout); + layout->addStretch(); return widget; } @@ -443,7 +442,6 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(zipDirectoryGroupBox); - //layout->addWidget(m_basePathWidget, 0, Qt::AlignLeft); layout->addWidget(m_basePathWidget); layout->addStretch(); @@ -606,6 +604,9 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() m_sceneFile->setBalsaExtractToDirectoryName(m_extractDirectoryNameLineEdit->text().trimmed()); + s_username = m_usernameLineEdit->text(); + s_password = m_passwordLineEdit->text(); + AString msg; if ( ! m_usernameLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Username is missing. If you do not have an account, press the \"Register\" link. " @@ -621,23 +622,29 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() msg.appendWithNewLine("Extract to Directory is invalid.

"); } - switch (m_sceneFile->getBasePathType()) { - case SceneFileBasePathTypeEnum::AUTOMATIC: - break; - case SceneFileBasePathTypeEnum::CUSTOM: - { - if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { - msg.appendWithNewLine("CUSTOM Base Path (on Advanced Tab) is invalid. " - "Select Base Path or use AUTOMATIC.

"); - } - else { - if ( ! FileInformation(m_sceneFile->getBalsaBaseDirectory()).exists()) { - msg.appendWithNewLine("CUSTOM Base Directory (on Advanced Tab) is not a valid directory on this computer. " - "Select a valid Base Path or use AUTOMATIC.

"); + AString basePathErrorMessage; + if ( ! m_basePathWidget->isValid(basePathErrorMessage)) { + msg.appendWithNewLine(basePathErrorMessage); + } + else { + switch (m_sceneFile->getBasePathType()) { + case SceneFileBasePathTypeEnum::AUTOMATIC: + break; + case SceneFileBasePathTypeEnum::CUSTOM: + { + if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { + msg.appendWithNewLine("CUSTOM Base Path (on Advanced Tab) is invalid. " + "Select Base Path or use AUTOMATIC.

"); + } + else { + if ( ! FileInformation(m_sceneFile->getBalsaBaseDirectory()).exists()) { + msg.appendWithNewLine("CUSTOM Base Directory (on Advanced Tab) is not a valid directory on this computer. " + "Select a valid Base Path or use AUTOMATIC.

"); + } } } + break; } - break; } bool invalidStudyFlag = false; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 66890b27e..3b9a11b44 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -96,7 +96,7 @@ namespace caret { QWidget* createLoginWidget(); - QWidget* createUploadWidget(); + QWidget* createTabWidget(); QWidget* createUploadTab(); @@ -154,12 +154,16 @@ namespace caret { SceneBasePathWidget* m_basePathWidget; + static AString s_username; + static AString s_password; + // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ - // + AString BalsaDatabaseUploadSceneFileDialog::s_username; + AString BalsaDatabaseUploadSceneFileDialog::s_password; #endif // __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ } // namespace diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index db5f73b83..491fe2d90 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -110,7 +110,7 @@ SceneBasePathWidget::~SceneBasePathWidget() * The scene file. */ void -SceneBasePathWidget::updateSceneFile(SceneFile* sceneFile) +SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) { m_sceneFile = sceneFile; @@ -164,7 +164,7 @@ SceneBasePathWidget::browseButtonClicked() m_sceneFile->setBalsaBaseDirectory(newDirectoryName); m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); - updateSceneFile(m_sceneFile); + updateWithSceneFile(m_sceneFile); } /** @@ -186,5 +186,45 @@ SceneBasePathWidget::basePathTypeButtonGroupClicked(QAbstractButton* button) CaretAssertMessage(0, "Has a new SceneFileBasePathTypeEnum::Enum been added?"); } - updateSceneFile(m_sceneFile); + updateWithSceneFile(m_sceneFile); } + +/** + * @return True if the selections in the widget are valid, else false. + * + * @param errorMessageOut + * Output contains error information if false returned. + */ +bool +SceneBasePathWidget::isValid(AString& errorMessageOut) const +{ + errorMessageOut.clear(); + + if (m_automaticRadioButton->isChecked()) { + /* valid */ + } + else if (m_customRadioButton->isChecked()) { + const AString basePath = m_basePathLineEdit->text().trimmed(); + if (basePath.isEmpty()) { + errorMessageOut = "CUSTOM base path is empty."; + } + else { + FileInformation fileInfo(basePath); + if (fileInfo.exists() + && fileInfo.isDirectory()) { + /* Valid directory */ + } + else { + errorMessageOut = "CUSTOM base path is not a valid directory"; + } + } + } + else { + CaretAssert(0); + errorMessageOut = "Neither AUTOMATIC nor CUSTOM is selected."; + } + + return (errorMessageOut.isEmpty()); +} + + diff --git a/src/GuiQt/SceneBasePathWidget.h b/src/GuiQt/SceneBasePathWidget.h index c7171640f..ae641b018 100644 --- a/src/GuiQt/SceneBasePathWidget.h +++ b/src/GuiQt/SceneBasePathWidget.h @@ -31,6 +31,8 @@ class QAbstractButton; class QLineEdit; class QRadioButton; +#include "AString.h" + namespace caret { class SceneFile; @@ -44,8 +46,10 @@ namespace caret { virtual ~SceneBasePathWidget(); - void updateSceneFile(SceneFile* sceneFile); + void updateWithSceneFile(SceneFile* sceneFile); + bool isValid(AString& errorMessageOut) const; + // ADD_NEW_METHODS_HERE private slots: diff --git a/src/GuiQt/ZipSceneFileDialog.cxx b/src/GuiQt/ZipSceneFileDialog.cxx index 973f16136..c135161be 100644 --- a/src/GuiQt/ZipSceneFileDialog.cxx +++ b/src/GuiQt/ZipSceneFileDialog.cxx @@ -24,11 +24,13 @@ #undef __ZIP_SCENE_FILE_DIALOG_DECLARE__ #include +#include #include #include #include #include #include +#include #include "BalsaDatabaseManager.h" #include "Brain.h" @@ -39,6 +41,7 @@ #include "DataFileException.h" #include "FileInformation.h" #include "GuiManager.h" +#include "SceneBasePathWidget.h" #include "SceneFile.h" #include "SystemUtilities.h" #include "WuQMessageBox.h" @@ -108,7 +111,7 @@ m_sceneFile(sceneFile) /* * Zip file button */ - QPushButton* chooseZipFileButton = new QPushButton("Choose..."); + QPushButton* chooseZipFileButton = new QPushButton("Browse..."); QObject::connect(chooseZipFileButton, SIGNAL(clicked()), this, SLOT(chooseZipFileButtonClicked())); @@ -126,57 +129,29 @@ m_sceneFile(sceneFile) /* * Base Directory */ - m_baseDirectoryLabel = new QLabel("Base Directory"); - m_baseDirectoryLineEdit = new QLineEdit(); - m_baseDirectoryLineEdit->setToolTip("Directory that contains all data files"); - m_baseDirectoryLineEdit->setValidator(createValidator(LabelName::BASE_DIRECTORY)); - QObject::connect(m_baseDirectoryLineEdit, &QLineEdit::textEdited, - this, [=] { this->validateData(); }); - - /* - * Browse for base directory - */ - m_browseBaseDirectoryPushButton = new QPushButton("Browse..."); - m_browseBaseDirectoryPushButton->setToolTip("Use a file system dialog to choose the base directory"); - QObject::connect(m_browseBaseDirectoryPushButton, &QPushButton::clicked, - this, &ZipSceneFileDialog::browseBaseDirectoryPushButtonClicked); - - /* - * Browse for base directory - */ - m_findBaseDirectoryPushButton = new QPushButton("Find"); - m_findBaseDirectoryPushButton->setToolTip("Find the base directory by examining files in all scenes"); - QObject::connect(m_findBaseDirectoryPushButton, &QPushButton::clicked, - this, &ZipSceneFileDialog::findBaseDirectoryPushButtonClicked); + m_basePathWidget = new SceneBasePathWidget(); - - QWidget* dialogWidget = new QWidget(); - QGridLayout* gridLayout = new QGridLayout(dialogWidget); - gridLayout->setColumnStretch(0, 0); - gridLayout->setColumnStretch(1, 100); - gridLayout->setColumnStretch(2, 0); - gridLayout->setColumnStretch(3, 0); + QGroupBox* zipFileGroupBox = new QGroupBox("Zip File"); + QGridLayout* zipFileLayout = new QGridLayout(zipFileGroupBox); + zipFileLayout->setSpacing(2); + zipFileLayout->setColumnStretch(0, 0); + zipFileLayout->setColumnStretch(1, 100); + zipFileLayout->setColumnStretch(2, 0); int row = 0; - gridLayout->addWidget(m_zipFileNameLabel, row, 0); - gridLayout->addWidget(m_zipFileNameLineEdit, row, 1); - gridLayout->addWidget(chooseZipFileButton, row, 2); + zipFileLayout->addWidget(m_zipFileNameLabel, row, 0); + zipFileLayout->addWidget(m_zipFileNameLineEdit, row, 1); + zipFileLayout->addWidget(chooseZipFileButton, row, 2); row++; - gridLayout->addWidget(m_extractDirectoryLabel, row, 0); - gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1); + zipFileLayout->addWidget(m_extractDirectoryLabel, row, 0); + zipFileLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1); row++; - gridLayout->addWidget(m_baseDirectoryLabel, row, 0); - gridLayout->addWidget(m_baseDirectoryLineEdit, row, 1); - gridLayout->addWidget(m_browseBaseDirectoryPushButton, row, 2); - gridLayout->addWidget(m_findBaseDirectoryPushButton, row, 3); + + QWidget* dialogWidget = new QWidget(); + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addWidget(zipFileGroupBox); + dialogLayout->addWidget(m_basePathWidget); row++; - AString baseDirectory = m_sceneFile->getBalsaBaseDirectory(); - if (baseDirectory.isEmpty()) { - FileInformation fileInfo(m_sceneFile->getFileName()); - baseDirectory = fileInfo.getPathName(); - } - m_baseDirectoryLineEdit->setText(baseDirectory); - AString extractDirectory = m_sceneFile->getBalsaExtractToDirectoryName(); if (extractDirectory.isEmpty()) { extractDirectory = m_sceneFile->getDefaultExtractToDirectoryName(); @@ -186,6 +161,8 @@ m_sceneFile(sceneFile) setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); + m_basePathWidget->updateWithSceneFile(m_sceneFile); + validateData(); } @@ -199,7 +176,6 @@ ZipSceneFileDialog::~ZipSceneFileDialog() void ZipSceneFileDialog::validateData() { - setLabelText(LabelName::BASE_DIRECTORY); setLabelText(LabelName::EXTRACT_DIRECTORY); setLabelText(LabelName::ZIP_FILE); } @@ -244,12 +220,12 @@ ZipSceneFileDialog::okButtonClicked() if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { errorMessage.appendWithNewLine("Extract to Directory is invalid.

"); } - if ( ! m_baseDirectoryLineEdit->hasAcceptableInput()) { - errorMessage.appendWithNewLine("Base Directory is invalid.

"); + AString basePathErrorMessage; + if ( ! m_basePathWidget->isValid(basePathErrorMessage)) { + errorMessage.appendWithNewLine(basePathErrorMessage); } if (errorMessage.isEmpty()) { - m_sceneFile->setBalsaBaseDirectory(m_baseDirectoryLineEdit->text().trimmed()); m_sceneFile->setBalsaExtractToDirectoryName(extractToDirectoryName); if (m_sceneFile->isModified()) { @@ -300,63 +276,6 @@ ZipSceneFileDialog::okButtonClicked() WuQDialogModal::okButtonClicked(); } -/** - * Called when find base directory push button is clicked. - */ -void -ZipSceneFileDialog::findBaseDirectoryPushButtonClicked() -{ - CaretAssert(m_sceneFile); - - const AString baseDirectoryName = m_sceneFile->findBaseDirectoryForDataFiles(); - - if (baseDirectoryName.isEmpty()) { - return; - } - - /* - * Set name for base directory - */ - m_baseDirectoryLineEdit->setText(baseDirectoryName); - validateData(); -} - - -/** - * Called when browse base directory push button is clicked. - */ -void -ZipSceneFileDialog::browseBaseDirectoryPushButtonClicked() -{ - CaretAssert(m_sceneFile); - - /* - * Let user choose directory path - */ - QString directoryName; - FileInformation fileInfo(m_baseDirectoryLineEdit->text().trimmed()); - if (fileInfo.exists()) { - if (fileInfo.isDirectory()) { - directoryName = fileInfo.getAbsoluteFilePath(); - } - } - AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_browseBaseDirectoryPushButton, - "Choose Base Directory", - directoryName); - /* - * If user cancels, return - */ - if (newDirectoryName.isEmpty()) { - return; - } - - /* - * Set name of base directory - */ - m_baseDirectoryLineEdit->setText(newDirectoryName); - validateData(); -} - /** * Create a regular expression validatory for the give label/data. * @@ -369,9 +288,6 @@ ZipSceneFileDialog::createValidator(const LabelName labelName) QRegularExpression regEx; switch (labelName) { - case LabelName::BASE_DIRECTORY: - regEx.setPattern(".+"); - break; case LabelName::EXTRACT_DIRECTORY: regEx.setPattern(".+"); break; @@ -401,11 +317,6 @@ ZipSceneFileDialog::setLabelText(const LabelName labelName) AString labelText; bool validFlag = false; switch (labelName) { - case LabelName::BASE_DIRECTORY: - label = m_baseDirectoryLabel; - labelText = "Base Directory"; - validFlag = m_baseDirectoryLineEdit->hasAcceptableInput(); - break; case LabelName::EXTRACT_DIRECTORY: label = m_extractDirectoryLabel; labelText = "Extract to Directory"; @@ -413,7 +324,7 @@ ZipSceneFileDialog::setLabelText(const LabelName labelName) break; case LabelName::ZIP_FILE: label = m_zipFileNameLabel; - labelText = "Zip File"; + labelText = "Zip File Name"; validFlag = m_zipFileNameLineEdit->hasAcceptableInput(); break; } diff --git a/src/GuiQt/ZipSceneFileDialog.h b/src/GuiQt/ZipSceneFileDialog.h index 6f302c838..963458f65 100644 --- a/src/GuiQt/ZipSceneFileDialog.h +++ b/src/GuiQt/ZipSceneFileDialog.h @@ -32,6 +32,7 @@ class QRegularExpressionValidator; namespace caret { class SceneFile; + class SceneBasePathWidget; class ZipSceneFileDialog : public WuQDialogModal { @@ -51,17 +52,12 @@ namespace caret { virtual void okButtonClicked(); private slots: - void browseBaseDirectoryPushButtonClicked(); - void chooseZipFileButtonClicked(); - void findBaseDirectoryPushButtonClicked(); - void validateData(); private: enum class LabelName { - BASE_DIRECTORY, EXTRACT_DIRECTORY, ZIP_FILE }; @@ -84,13 +80,7 @@ namespace caret { QLineEdit* m_extractDirectoryNameLineEdit; - QLabel* m_baseDirectoryLabel; - - QLineEdit* m_baseDirectoryLineEdit; - - QPushButton* m_findBaseDirectoryPushButton; - - QPushButton* m_browseBaseDirectoryPushButton; + SceneBasePathWidget* m_basePathWidget; // ADD_NEW_MEMBERS_HERE -- GitLab From 5fcd1daa476c1868f8dd41d2a48cd7059e31844c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 18 Oct 2017 11:14:25 -0500 Subject: [PATCH 453/755] Completed WB-695 Need to be able to set base directory when creating Zip in scene GUI: Updated wb_command -zip-scene-file to that if the "-base-dir" option is not specified, the base directory is automatically set to the lowest level directory containing all data files. Prior to this modification, the base directory was set to the directory containing the scene file. --- src/Operations/OperationZipSceneFile.cxx | 194 +++-------------------- 1 file changed, 19 insertions(+), 175 deletions(-) diff --git a/src/Operations/OperationZipSceneFile.cxx b/src/Operations/OperationZipSceneFile.cxx index 209acbe57..54885d76d 100644 --- a/src/Operations/OperationZipSceneFile.cxx +++ b/src/Operations/OperationZipSceneFile.cxx @@ -66,7 +66,7 @@ OperationParameters* OperationZipSceneFile::getParameters() baseOpt->addStringParameter(1, "directory", "the directory"); ret->setHelpText("If zip-file already exists, it will be overwritten. " - "If -base-dir is not specified, the directory containing the scene file is used for the base directory. " + "If -base-dir is not specified, the base directory will be automatically set to the lowest level directory containing all files. " "The scene file must contain only relative paths, and no data files may be outside the base directory."); return ret; } @@ -103,39 +103,42 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, if (outputSubDirectory.isEmpty()) { throw OperationException("extract-dir must contain characters"); } + if (FileInformation(outputSubDirectory).isAbsolute()) + { + CaretLogWarning("You have specified that the zip file should extract to an absolute path, this is generally frowned on. " + "The parameter should generally be a string without '/' or '\\' in it."); + } else { + if (outputSubDirectory.indexOfAnyChar("/\\") != -1)//assume backslashes work too + { + CaretLogWarning("You have specified that the zipfile should create multiple levels of otherwise empty directories " + "before the file paths starting from the base directory, this is probably going to be inconvenient. " + "The parameter should generally be a string without '/' or '\\' in it."); + } + } + + SceneFile sceneFile; + sceneFile.readFile(sceneFileName); AString myBaseDir; if ( ! baseDirectory.isEmpty()) { myBaseDir = QDir::cleanPath(QDir(baseDirectory).absolutePath()); } else { - myBaseDir = QDir::cleanPath(sceneFileInfo.getAbsolutePath()); + myBaseDir = QDir::cleanPath(sceneFile.findBaseDirectoryForDataFiles()); } if (!myBaseDir.endsWith('/'))//root is a special case, if we didn't handle it differently it would end up looking for "//somefile" {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" myBaseDir += "/";//so, add the trailing slash to the path } + AString sceneFilePath = QDir::cleanPath(sceneFileInfo.getAbsoluteFilePath());//resolve filenames to open from the spec file's location, NOT from current directory if (!sceneFilePath.startsWith(myBaseDir)) { throw OperationException("scene file lies outside the base directory"); } - if (FileInformation(outputSubDirectory).isAbsolute()) - { - CaretLogWarning("You have specified that the zip file should extract to an absolute path, this is generally frowned on. " - "The parameter should generally be a string without '/' or '\\' in it."); - } else { - if (outputSubDirectory.indexOfAnyChar("/\\") != -1)//assume backslashes work too - { - CaretLogWarning("You have specified that the zipfile should create multiple levels of otherwise empty directories " - "before the file paths starting from the base directory, this is probably going to be inconvenient. " - "The parameter should generally be a string without '/' or '\\' in it."); - } - } + set allFiles; allFiles.insert(sceneFilePath); - SceneFile sceneFile; - sceneFile.readFile(sceneFileName); const int numScenes = sceneFile.getNumberOfScenes(); for (int i = 0; i < numScenes; ++i) { @@ -291,162 +294,3 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, break; } } - -//void OperationZipSceneFile::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) -//{ -// LevelProgress myProgress(myProgObj); -// AString sceneFileName = myParams->getString(1); -// AString outputSubDirectory = myParams->getString(2); -// AString zipFileName = myParams->getString(3); -// FileInformation sceneFileInfo(sceneFileName); -// if (outputSubDirectory.isEmpty()) { -// throw OperationException("extract-dir must contain characters"); -// } -// OptionalParameter* baseOpt = myParams->getOptionalParameter(4); -// AString myBaseDir; -// if (baseOpt->m_present) -// { -// myBaseDir = QDir::cleanPath(QDir(baseOpt->getString(1)).absolutePath()); -// } else { -// myBaseDir = QDir::cleanPath(sceneFileInfo.getAbsolutePath()); -// } -// if (!myBaseDir.endsWith('/'))//root is a special case, if we didn't handle it differently it would end up looking for "//somefile" -// {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" -// myBaseDir += "/";//so, add the trailing slash to the path -// } -// AString sceneFilePath = QDir::cleanPath(sceneFileInfo.getAbsoluteFilePath());//resolve filenames to open from the spec file's location, NOT from current directory -// if (!sceneFilePath.startsWith(myBaseDir)) -// { -// throw OperationException("scene file lies outside the base directory"); -// } -// if (FileInformation(outputSubDirectory).isAbsolute()) -// { -// CaretLogWarning("You have specified that the zip file should extract to an absolute path, this is generally frowned on. " -// "The parameter should generally be a string without '/' or '\\' in it."); -// } else { -// if (outputSubDirectory.indexOfAnyChar("/\\") != -1)//assume backslashes work too -// { -// CaretLogWarning("You have specified that the zipfile should create multiple levels of otherwise empty directories " -// "before the file paths starting from the base directory, this is probably going to be inconvenient. " -// "The parameter should generally be a string without '/' or '\\' in it."); -// } -// } -// set allFiles; -// allFiles.insert(sceneFilePath); -// SceneFile sceneFile; -// sceneFile.readFile(sceneFileName); -// const int numScenes = sceneFile.getNumberOfScenes(); -// for (int i = 0; i < numScenes; ++i) -// { -// Scene* thisScene = sceneFile.getSceneAtIndex(i); -// SceneAttributes* myAttrs = thisScene->getAttributes(); -// const SceneClass* guiMgrClass = thisScene->getClassWithName("guiManager"); -// if (guiMgrClass == NULL) -// { -// throw OperationException("scene '" + thisScene->getName() + "' is missing guiManager class"); -// } -// const SceneClass* sessMgrClass = guiMgrClass->getClass("m_sessionManager"); -// if (sessMgrClass == NULL) -// { -// throw OperationException("scene '" + thisScene->getName() + "' is missing m_sessionManager class"); -// } -// const SceneClassArray* brainArray = sessMgrClass->getClassArray("m_brains"); -// if (brainArray == NULL) -// { -// throw OperationException("scene '" + thisScene->getName() + "' is missing m_brains class array"); -// } -// const int numBrainClasses = brainArray->getNumberOfArrayElements(); -// for (int j = 0; j < numBrainClasses; ++j) -// { -// const SceneClass* brainClass = brainArray->getClassAtIndex(j); -// const SceneClass* specClass = brainClass->getClass("specFile"); -// if (specClass == NULL) -// { -// throw OperationException("scene '" + thisScene->getName() + "' is missing specFile class in m_brains element " + AString::number(j)); -// } -// SpecFile tempSpec; -// tempSpec.restoreFromScene(myAttrs, specClass); -// vector tempNames = tempSpec.getAllDataFileNamesSelectedForLoading(); -// int numNames = (int)tempNames.size(); -// for (int k = 0; k < numNames; ++k) -// { -// if (DataFile::isFileOnNetwork(tempNames[k])) -// { -// cout << "skipping network file '" << tempNames[k] << "'" << endl; -// continue; -// } -// AString thisName = QDir::cleanPath(tempNames[k]); -// if (allFiles.insert(thisName).second) -// { -// if (FileInformation(thisName).isRelative()) -// { -// throw OperationException("scene '" + thisScene->getName() + "' contains an unresolved relative path: '" + tempNames[k] + "'"); -// } -// if (!thisName.startsWith(myBaseDir)) -// { -// throw OperationException("scene '" + thisScene->getName() + "' contains a file outside the base directory: '" + thisName + "', try using -base-dir"); -// } -// } -// } -// } -// } -// QFile zipFileObject(zipFileName); -// QuaZip zipFile(&zipFileObject); -// if (!zipFile.open(QuaZip::mdCreate)) -// { -// throw OperationException("Unable to open ZIP File \"" -// + zipFileName -// + "\" for writing."); -// } -// static const char *myUnits[9] = {" B ", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"}; -// for (set::iterator iter = allFiles.begin(); iter != allFiles.end(); ++iter) -// { -// AString dataFileName = *iter; -// AString unzippedDataFileName = outputSubDirectory + "/" + dataFileName.mid(myBaseDir.size());//we know the string matches to the length of myBaseDir, and is cleaned, so we can just chop the right number of characters off -// QFile dataFileIn(dataFileName); -// if (!dataFileIn.open(QFile::ReadOnly)) { -// throw OperationException("Unable to open \"" + dataFileName + "\" for reading: " + dataFileIn.errorString()); -// } -// float fileSize = (float)dataFileIn.size(); -// int unit = 0; -// while (unit < 8 && fileSize >= 1000.0f)//don't let there be 4 digits to the left of decimal point -// { -// ++unit; -// fileSize /= 1000.0f;//use GB and friends, not GiB -// } -// if (unit > 0) -// { -// cout << AString::number(fileSize, 'f', 2); -// } else { -// cout << AString::number(fileSize); -// } -// cout << myUnits[unit] << " \t" << unzippedDataFileName; -// cout.flush();//don't endl until it finishes -// -// QuaZipNewInfo zipNewInfo(unzippedDataFileName, -// dataFileName); -// zipNewInfo.externalAttr |= (6 << 22L) | (6 << 19L) | (4 << 16L);//make permissions 664 -// -// QuaZipFile dataFileOut(&zipFile); -// if (!dataFileOut.open(QIODevice::WriteOnly, zipNewInfo)) { -// throw OperationException("Unable to open zip output for \"" + dataFileName + "\""); -// } -// -// const qint64 BUFFER_SIZE = 1024 * 1024; -// vector buffer(BUFFER_SIZE); -// -// while (dataFileIn.atEnd() == false) { -// const qint64 numRead = dataFileIn.read(buffer.data(), BUFFER_SIZE); -// if (numRead < 0) throw OperationException("Error reading from data file"); -// if (numRead > 0) { -// qint64 result = dataFileOut.write(buffer.data(), numRead); -// if (result != numRead) throw OperationException("Error writing to zip file"); -// } -// } -// -// dataFileIn.close(); -// dataFileOut.close(); -// cout << endl; -// } -// zipFile.close(); -//} -- GitLab From 8ca389de99696ab1a856a7e38aef852b1737f796 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 18 Oct 2017 12:36:36 -0500 Subject: [PATCH 454/755] Resolve WB-750 Strange Volume Drawing - Changed masking names to OFF, LOOSE, TIGHT. Default is TIGHT. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 12 +- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 6 +- src/Brain/BrowserTabContent.cxx | 10 +- src/Brain/BrowserTabContent.h | 6 +- src/Brain/CMakeLists.txt | 4 +- ...ceInterpolationEdgeEffectsMaskingEnum.cxx} | 154 +++++++++++------- ...liceInterpolationEdgeEffectsMaskingEnum.h} | 39 +++-- src/Brain/VolumeSliceSettings.cxx | 20 +-- src/Brain/VolumeSliceSettings.h | 8 +- ...rainBrowserWindowToolBarSliceSelection.cxx | 32 ++-- 11 files changed, 162 insertions(+), 131 deletions(-) rename src/Brain/{VolumeSliceObliqueDrawingMaskEnum.cxx => VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx} (52%) rename src/Brain/{VolumeSliceObliqueDrawingMaskEnum.h => VolumeSliceInterpolationEdgeEffectsMaskingEnum.h} (68%) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 45b6cbf3f..2dc29ef1b 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -3552,7 +3552,7 @@ BrainOpenGLFixedPipeline::drawVolumeModel(BrowserTabContent* browserTabContent, VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); - VolumeSliceObliqueDrawingMaskEnum::Enum obliqueMaskType = browserTabContent->getObliqueSliceDrawingMaskingType(); + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); /* * There is/was a flaw in volume drawing in that it does not "center" diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index a991da8a2..e20320543 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -116,7 +116,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceObliqueDrawingMaskEnum::Enum obliqueSliceMaskingType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]) { CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); @@ -1462,18 +1462,18 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan bool maskValidFlag = false; float maskValue = 0.0f; switch (m_obliqueSliceMaskingType) { - case VolumeSliceObliqueDrawingMaskEnum::OFF: + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF: maskValidFlag = false; break; - case VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL: + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE: maskValue = volumeFile->interpolateValue(voxelCenter, - VolumeFile::ENCLOSING_VOXEL, + VolumeFile::TRILINEAR, &maskValidFlag, vdi.mapIndex); break; - case VolumeSliceObliqueDrawingMaskEnum::TRILINEAR_INTERPOLATION: + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT: maskValue = volumeFile->interpolateValue(voxelCenter, - VolumeFile::TRILINEAR, + VolumeFile::ENCLOSING_VOXEL, &maskValidFlag, vdi.mapIndex); break; diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index c27411d1b..63a07cbbd 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -24,7 +24,7 @@ #include "BrainOpenGLFixedPipeline.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" -#include "VolumeSliceObliqueDrawingMaskEnum.h" +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" @@ -54,7 +54,7 @@ namespace caret { std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, - const VolumeSliceObliqueDrawingMaskEnum::Enum obliqueSliceMaskingType, + const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]); // ADD_NEW_METHODS_HERE @@ -371,7 +371,7 @@ namespace caret { double m_orthographicBounds[6]; - VolumeSliceObliqueDrawingMaskEnum::Enum m_obliqueSliceMaskingType = VolumeSliceObliqueDrawingMaskEnum::OFF; + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_obliqueSliceMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF; std::vector m_identificationIndices; diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 67ba5c36f..13b215ecd 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -3805,10 +3805,10 @@ BrowserTabContent::setSliceProjectionType(const VolumeSliceProjectionTypeEnum::E /** * @return The masking used when drawing an oblique volume slice */ -VolumeSliceObliqueDrawingMaskEnum::Enum -BrowserTabContent::getObliqueSliceDrawingMaskingType() const +VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum +BrowserTabContent::getVolumeSliceInterpolationEdgeEffectsMaskingType() const { - return m_volumeSliceSettings->getObliqueSliceDrawingMaskingType(); + return m_volumeSliceSettings->getVolumeSliceInterpolationEdgeEffectsMaskingType(); } /** @@ -3818,9 +3818,9 @@ BrowserTabContent::getObliqueSliceDrawingMaskingType() const * Type of masking. */ void -BrowserTabContent::setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType) +BrowserTabContent::setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType) { - m_volumeSliceSettings->setObliqueSliceDrawingMaskingType(maskingType); + m_volumeSliceSettings->setVolumeSliceInterpolationEdgeEffectsMaskingType(maskingType); updateBrainModelYokedBrowserTabs(); } diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 99b304f47..04bb70b72 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -32,7 +32,7 @@ #include "SceneableInterface.h" #include "StructureEnum.h" #include "VolumeSliceDrawingTypeEnum.h" -#include "VolumeSliceObliqueDrawingMaskEnum.h" +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" @@ -307,9 +307,9 @@ namespace caret { void setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); - VolumeSliceObliqueDrawingMaskEnum::Enum getObliqueSliceDrawingMaskingType() const; + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum getVolumeSliceInterpolationEdgeEffectsMaskingType() const; - void setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType); + void setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType); int32_t getMontageNumberOfColumns() const; diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 7658fb97e..7c94fc12e 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -166,7 +166,7 @@ ViewingTransformations.h ViewingTransformationsCerebellum.h ViewingTransformationsVolume.h VolumeSliceDrawingTypeEnum.h -VolumeSliceObliqueDrawingMaskEnum.h +VolumeSliceInterpolationEdgeEffectsMaskingEnum.h VolumeSliceSettings.h VolumeSliceViewAllPlanesLayoutEnum.h VolumeSurfaceOutlineColorOrTabModel.h @@ -312,7 +312,7 @@ ViewingTransformations.cxx ViewingTransformationsCerebellum.cxx ViewingTransformationsVolume.cxx VolumeSliceDrawingTypeEnum.cxx -VolumeSliceObliqueDrawingMaskEnum.cxx +VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx VolumeSliceSettings.cxx VolumeSliceViewAllPlanesLayoutEnum.cxx VolumeSurfaceOutlineColorOrTabModel.cxx diff --git a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx b/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx similarity index 52% rename from src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx rename to src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx index 41ff6218c..97b2ca9a2 100644 --- a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.cxx +++ b/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx @@ -20,9 +20,9 @@ /*LICENSE_END*/ #include -#define __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ -#include "VolumeSliceObliqueDrawingMaskEnum.h" -#undef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ +#define __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" +#undef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,8 +30,8 @@ using namespace caret; /** - * \class caret::VolumeSliceObliqueDrawingMaskEnum - * \brief Enumerated type for oblique slice drawing masking + * \class caret::VolumeSliceInterpolationEdgeEffectsMaskingEnum + * \brief Enumerated type for edge effects masking. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * @@ -40,30 +40,30 @@ using namespace caret; * class EnumComboBoxTemplate; * * Declare the member: - * EnumComboBoxTemplate* m_volumeSliceObliqueDrawingMaskEnumComboBox; + * EnumComboBoxTemplate* m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: - * void volumeSliceObliqueDrawingMaskEnumComboBoxItemActivated(); + * void volumeSliceInterpolationEdgeEffectsMaskingEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "VolumeSliceObliqueDrawingMaskEnum.h" + * #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" * * Instatiate: - * m_volumeSliceObliqueDrawingMaskEnumComboBox = new EnumComboBoxTemplate(this); - * m_volumeSliceObliqueDrawingMaskEnumComboBox->setup(); + * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox = new EnumComboBoxTemplate(this); + * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->setup(); * * Get notified when the user changes the selection: - * QObject::connect(m_volumeSliceObliqueDrawingMaskEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(volumeSliceObliqueDrawingMaskEnumComboBoxItemActivated())); + * QObject::connect(m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(volumeSliceInterpolationEdgeEffectsMaskingEnumComboBoxItemActivated())); * * Update the selection: - * m_volumeSliceObliqueDrawingMaskEnumComboBox->setSelectedItem(NEW_VALUE); + * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const VolumeSliceObliqueDrawingMaskEnum::Enum VARIABLE = m_volumeSliceObliqueDrawingMaskEnumComboBox->getSelectedItem(); + * const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VARIABLE = m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -VolumeSliceObliqueDrawingMaskEnum::VolumeSliceObliqueDrawingMaskEnum(const Enum enumValue, +VolumeSliceInterpolationEdgeEffectsMaskingEnum::VolumeSliceInterpolationEdgeEffectsMaskingEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,32 +91,66 @@ VolumeSliceObliqueDrawingMaskEnum::VolumeSliceObliqueDrawingMaskEnum(const Enum /** * Destructor. */ -VolumeSliceObliqueDrawingMaskEnum::~VolumeSliceObliqueDrawingMaskEnum() +VolumeSliceInterpolationEdgeEffectsMaskingEnum::~VolumeSliceInterpolationEdgeEffectsMaskingEnum() { } +AString +VolumeSliceInterpolationEdgeEffectsMaskingEnum::getToolTip() +{ + AString toolTip("" + "Masking is used to remove edge effects from cubic
" + "interpolation. In extreme instances, the artifacts
" + "result in blocky and/or striped patterns.
" + "
"); + + std::vector allEnums; + getAllEnums(allEnums); + + for (const auto enumValue : allEnums) { + AString description(toGuiName(enumValue) + " - "); + switch (enumValue) { + case OFF: + description.append("No masking"); + break; + case LOOSE: + description.append("Mask with Trilinear Interpolation"); + break; + case TIGHT: + description.append("Mask with Enclosing Voxel"); + break; + } + toolTip.append(description + "
"); + } + + toolTip.append(""); + + return toolTip; +} + /** * Initialize the enumerated metadata. */ void -VolumeSliceObliqueDrawingMaskEnum::initialize() +VolumeSliceInterpolationEdgeEffectsMaskingEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(OFF, + enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(OFF, "OFF", - "Oblique Masking OFF")); + "Masking Off")); + + enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(LOOSE, + "LOOSE", + "Masking Loose")); - enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(ENCLOSING_VOXEL, - "ENCLOSING_VOXEL", - "Oblique Masking ENCLOSING VOXEL")); + enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(TIGHT, + "TIGHT", + "Masking Tight")); - enumData.push_back(VolumeSliceObliqueDrawingMaskEnum(TRILINEAR_INTERPOLATION, - "TRILINEAR_INTERPOLATION", - "Oblique Masking TRILINEAR INTERPOLATION")); } /** @@ -126,14 +160,14 @@ VolumeSliceObliqueDrawingMaskEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const VolumeSliceObliqueDrawingMaskEnum* -VolumeSliceObliqueDrawingMaskEnum::findData(const Enum enumValue) +const VolumeSliceInterpolationEdgeEffectsMaskingEnum* +VolumeSliceInterpolationEdgeEffectsMaskingEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const VolumeSliceObliqueDrawingMaskEnum* d = &enumData[i]; + const VolumeSliceInterpolationEdgeEffectsMaskingEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -150,10 +184,10 @@ VolumeSliceObliqueDrawingMaskEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -VolumeSliceObliqueDrawingMaskEnum::toName(Enum enumValue) { +VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -167,18 +201,18 @@ VolumeSliceObliqueDrawingMaskEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -VolumeSliceObliqueDrawingMaskEnum::Enum -VolumeSliceObliqueDrawingMaskEnum::fromName(const AString& name, bool* isValidOut) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum +VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const VolumeSliceObliqueDrawingMaskEnum& d = *iter; + const VolumeSliceInterpolationEdgeEffectsMaskingEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -190,7 +224,7 @@ VolumeSliceObliqueDrawingMaskEnum::fromName(const AString& name, bool* isValidOu *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } @@ -203,10 +237,10 @@ VolumeSliceObliqueDrawingMaskEnum::fromName(const AString& name, bool* isValidOu * String representing enumerated value. */ AString -VolumeSliceObliqueDrawingMaskEnum::toGuiName(Enum enumValue) { +VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -220,18 +254,18 @@ VolumeSliceObliqueDrawingMaskEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -VolumeSliceObliqueDrawingMaskEnum::Enum -VolumeSliceObliqueDrawingMaskEnum::fromGuiName(const AString& guiName, bool* isValidOut) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum +VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const VolumeSliceObliqueDrawingMaskEnum& d = *iter; + const VolumeSliceInterpolationEdgeEffectsMaskingEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -243,7 +277,7 @@ VolumeSliceObliqueDrawingMaskEnum::fromGuiName(const AString& guiName, bool* isV *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } @@ -255,10 +289,10 @@ VolumeSliceObliqueDrawingMaskEnum::fromGuiName(const AString& guiName, bool* isV * Integer code for data type. */ int32_t -VolumeSliceObliqueDrawingMaskEnum::toIntegerCode(Enum enumValue) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const VolumeSliceObliqueDrawingMaskEnum* enumInstance = findData(enumValue); + const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -273,18 +307,18 @@ VolumeSliceObliqueDrawingMaskEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -VolumeSliceObliqueDrawingMaskEnum::Enum -VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum +VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = VolumeSliceObliqueDrawingMaskEnum::enumData[0].enumValue; + Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const VolumeSliceObliqueDrawingMaskEnum& enumInstance = *iter; + const VolumeSliceInterpolationEdgeEffectsMaskingEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -296,7 +330,7 @@ VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(const int32_t integerCode, bo *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceObliqueDrawingMaskEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } @@ -309,13 +343,13 @@ VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(const int32_t integerCode, bo * A vector that is OUTPUT containing all of the enumerated values. */ void -VolumeSliceObliqueDrawingMaskEnum::getAllEnums(std::vector& allEnums) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -331,16 +365,16 @@ VolumeSliceObliqueDrawingMaskEnum::getAllEnums(std::vector& allNames, const bool isSorted) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(VolumeSliceObliqueDrawingMaskEnum::toName(iter->enumValue)); + allNames.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(iter->enumValue)); } if (isSorted) { @@ -357,16 +391,16 @@ VolumeSliceObliqueDrawingMaskEnum::getAllNames(std::vector& allNames, c * If true, the names are sorted in alphabetical order. */ void -VolumeSliceObliqueDrawingMaskEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(VolumeSliceObliqueDrawingMaskEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.h b/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.h similarity index 68% rename from src/Brain/VolumeSliceObliqueDrawingMaskEnum.h rename to src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.h index b1fe00a52..bb1f06fcc 100644 --- a/src/Brain/VolumeSliceObliqueDrawingMaskEnum.h +++ b/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.h @@ -1,5 +1,5 @@ -#ifndef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ -#define __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ +#ifndef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ +#define __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ /*LICENSE_START*/ /* @@ -28,22 +28,23 @@ namespace caret { -class VolumeSliceObliqueDrawingMaskEnum { +class VolumeSliceInterpolationEdgeEffectsMaskingEnum { public: /** * Enumerated values. */ enum Enum { - /** Masking Off */ + /** Off */ OFF, - /** Mask with enclosing voxel */ - ENCLOSING_VOXEL, - /** Mask with trilinear interpolation */ - TRILINEAR_INTERPOLATION + /** Loose - Trilinear */ + LOOSE, + /** Tight - Enclosing Voxel */ + TIGHT }; - ~VolumeSliceObliqueDrawingMaskEnum(); + + ~VolumeSliceInterpolationEdgeEffectsMaskingEnum(); static AString toName(Enum enumValue); @@ -63,15 +64,17 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + static AString getToolTip(); + private: - VolumeSliceObliqueDrawingMaskEnum(const Enum enumValue, + VolumeSliceInterpolationEdgeEffectsMaskingEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const VolumeSliceObliqueDrawingMaskEnum* findData(const Enum enumValue); + static const VolumeSliceInterpolationEdgeEffectsMaskingEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -95,11 +98,11 @@ private: AString guiName; }; -#ifdef __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ -std::vector VolumeSliceObliqueDrawingMaskEnum::enumData; -bool VolumeSliceObliqueDrawingMaskEnum::initializedFlag = false; -int32_t VolumeSliceObliqueDrawingMaskEnum::integerCodeCounter = 0; -#endif // __VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_DECLARE__ +#ifdef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ +std::vector VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData; +bool VolumeSliceInterpolationEdgeEffectsMaskingEnum::initializedFlag = false; +int32_t VolumeSliceInterpolationEdgeEffectsMaskingEnum::integerCodeCounter = 0; +#endif // __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ } // namespace -#endif //__VOLUME_SLICE_OBLIQUE_DRAWING_MASK_ENUM_H__ +#endif //__VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index b3ba53a85..27393af1e 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -50,7 +50,7 @@ VolumeSliceSettings::VolumeSliceSettings() m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; - m_obliqueSliceDrawingMaskingType = VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL; + m_volumeSliceInterpolationEdgeEffectsMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT; m_montageNumberOfColumns = 6; // was 3; m_montageNumberOfRows = 4; @@ -74,8 +74,8 @@ VolumeSliceSettings::VolumeSliceSettings() &m_sliceDrawingType); m_sceneAssistant->add("m_sliceProjectionType", &m_sliceProjectionType); - m_sceneAssistant->add("m_obliqueSliceDrawingMaskingType", - &m_obliqueSliceDrawingMaskingType); + m_sceneAssistant->add("m_volumeSliceInterpolationEdgeEffectsMaskingType", + &m_volumeSliceInterpolationEdgeEffectsMaskingType); m_sceneAssistant->add("m_montageNumberOfColumns", &m_montageNumberOfColumns); m_sceneAssistant->add("m_montageNumberOfRows", @@ -139,7 +139,7 @@ VolumeSliceSettings::copyHelperVolumeSliceSettings(const VolumeSliceSettings& ob m_slicePlanesAllViewLayout = obj.m_slicePlanesAllViewLayout; m_sliceDrawingType = obj.m_sliceDrawingType; m_sliceProjectionType = obj.m_sliceProjectionType; - m_obliqueSliceDrawingMaskingType = obj.m_obliqueSliceDrawingMaskingType; + m_volumeSliceInterpolationEdgeEffectsMaskingType = obj.m_volumeSliceInterpolationEdgeEffectsMaskingType; m_montageNumberOfColumns = obj.m_montageNumberOfColumns; m_montageNumberOfRows = obj.m_montageNumberOfRows; @@ -312,10 +312,10 @@ VolumeSliceSettings::setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum /** * @return The masking used when drawing an oblique volume slice */ -VolumeSliceObliqueDrawingMaskEnum::Enum -VolumeSliceSettings::getObliqueSliceDrawingMaskingType() const +VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum +VolumeSliceSettings::getVolumeSliceInterpolationEdgeEffectsMaskingType() const { - return m_obliqueSliceDrawingMaskingType; + return m_volumeSliceInterpolationEdgeEffectsMaskingType; } /** @@ -325,9 +325,9 @@ VolumeSliceSettings::getObliqueSliceDrawingMaskingType() const * Type of masking. */ void -VolumeSliceSettings::setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType) +VolumeSliceSettings::setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType) { - m_obliqueSliceDrawingMaskingType = maskingType; + m_volumeSliceInterpolationEdgeEffectsMaskingType = maskingType; } /** @@ -834,7 +834,7 @@ VolumeSliceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, */ m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; - m_obliqueSliceDrawingMaskingType = VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL; + m_volumeSliceInterpolationEdgeEffectsMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Brain/VolumeSliceSettings.h b/src/Brain/VolumeSliceSettings.h index c112ae3eb..9afbed1ea 100644 --- a/src/Brain/VolumeSliceSettings.h +++ b/src/Brain/VolumeSliceSettings.h @@ -26,7 +26,7 @@ #include "ModelTypeEnum.h" #include "SceneableInterface.h" #include "VolumeSliceDrawingTypeEnum.h" -#include "VolumeSliceObliqueDrawingMaskEnum.h" +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" @@ -61,9 +61,9 @@ namespace caret { void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); - VolumeSliceObliqueDrawingMaskEnum::Enum getObliqueSliceDrawingMaskingType() const; + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum getVolumeSliceInterpolationEdgeEffectsMaskingType() const; - void setObliqueSliceDrawingMaskingType(const VolumeSliceObliqueDrawingMaskEnum::Enum maskingType); + void setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType); VolumeSliceProjectionTypeEnum::Enum getSliceProjectionType() const; @@ -162,7 +162,7 @@ namespace caret { VolumeSliceDrawingTypeEnum::Enum m_sliceDrawingType; /** Type of masking for oblique slice drawing */ - VolumeSliceObliqueDrawingMaskEnum::Enum m_obliqueSliceDrawingMaskingType; + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_volumeSliceInterpolationEdgeEffectsMaskingType; /** Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum m_sliceProjectionType; diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 5cae76331..979a88b27 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -44,7 +44,7 @@ #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "VolumeFile.h" -#include "VolumeSliceObliqueDrawingMaskEnum.h" +#include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "WuQFactory.h" #include "WuQWidgetObjectGroup.h" @@ -180,13 +180,8 @@ m_parentToolBar(parentToolBar) WuQtUtilities::setToolTipAndStatusTip(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), "Chooses viewing orientation (oblique or orthogonal)"); - const AString maskToolTip("Masking for oblique slice viewing is used to remove " - "artifacts due to cubic interpolation. In extreme " - "instance, the artifacts result in blocky and/or " - "striped patterns."); m_obliqueMaskingAction = new QAction("M"); - WuQtUtilities::setWordWrappedToolTip(m_obliqueMaskingAction, - maskToolTip); + m_obliqueMaskingAction->setToolTip(VolumeSliceInterpolationEdgeEffectsMaskingEnum::getToolTip()); m_obliqueMaskingAction->setCheckable(true); QObject::connect(m_obliqueMaskingAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered); @@ -213,7 +208,6 @@ m_parentToolBar(parentToolBar) gridLayout->addWidget(volumeIDToolButton, 3, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 2, Qt::AlignCenter); - //gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 3, Qt::AlignRight); gridLayout->addWidget(obliqueMaskingToolButton, 3, 4); gridLayout->addWidget(volumeIndicesOriginToolButton, 0, 4, 3, 1); @@ -747,18 +741,18 @@ BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) if (browserTabContent == NULL) { return; } - std::vector allMaskEnums; - VolumeSliceObliqueDrawingMaskEnum::getAllEnums(allMaskEnums); + std::vector allMaskEnums; + VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllEnums(allMaskEnums); QMenu obliqueMaskingMenu("Oblique Sampling"); QActionGroup* maskActionGroup = new QActionGroup(this); maskActionGroup->setExclusive(true); QAction* selectedAction = NULL; for (auto maskEnum : allMaskEnums) { - QAction* action = maskActionGroup->addAction(VolumeSliceObliqueDrawingMaskEnum::toGuiName(maskEnum)); + QAction* action = maskActionGroup->addAction(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(maskEnum)); action->setCheckable(true); - action->setData(VolumeSliceObliqueDrawingMaskEnum::toIntegerCode(maskEnum)); - if (maskEnum == browserTabContent->getObliqueSliceDrawingMaskingType()) { + action->setData(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toIntegerCode(maskEnum)); + if (maskEnum == browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType()) { selectedAction = action; } obliqueMaskingMenu.addAction(action); @@ -771,10 +765,10 @@ BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) if (selectedAction != NULL) { const int32_t intValue = selectedAction->data().toInt(); bool validFlag = false; - VolumeSliceObliqueDrawingMaskEnum::Enum maskType = VolumeSliceObliqueDrawingMaskEnum::fromIntegerCode(intValue, + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromIntegerCode(intValue, &validFlag); CaretAssert(validFlag); - browserTabContent->setObliqueSliceDrawingMaskingType(maskType); + browserTabContent->setVolumeSliceInterpolationEdgeEffectsMaskingType(maskType); this->updateGraphicsWindow(); this->updateOtherYokedWindows(); @@ -798,12 +792,12 @@ BrainBrowserWindowToolBarSliceSelection::updateObliqueMaskingButton() } QSignalBlocker obliqueBlocker(m_obliqueMaskingAction); - switch (browserTabContent->getObliqueSliceDrawingMaskingType()) { - case VolumeSliceObliqueDrawingMaskEnum::OFF: + switch (browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType()) { + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF: m_obliqueMaskingAction->setChecked(false); break; - case VolumeSliceObliqueDrawingMaskEnum::ENCLOSING_VOXEL: - case VolumeSliceObliqueDrawingMaskEnum::TRILINEAR_INTERPOLATION: + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE: + case VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT: m_obliqueMaskingAction->setChecked(true); break; } -- GitLab From a305e39be0896b0277ebbb27f520215ef34b12cb Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 19 Oct 2017 19:34:29 -0500 Subject: [PATCH 455/755] add ability to accept somewhat-incorrect nifti-1 files --- src/Nifti/NiftiHeader.cxx | 92 ++++++++++++++++++++++++--------------- src/Nifti/NiftiHeader.h | 9 +++- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index f492a34c6..80d157213 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -622,6 +622,7 @@ void NiftiHeader::read(CaretBinaryFile& inFile) inFile.read(&buffer1, sizeof(nifti_1_header)); int version = NIFTI2_VERSION(buffer1); bool swapped = false; + Quirks myquirks; try { if (version == 2) @@ -633,14 +634,14 @@ void NiftiHeader::read(CaretBinaryFile& inFile) swapped = true; swapHeaderBytes(buffer2); } - setupFrom(buffer2); + myquirks = setupFrom(buffer2); } else if (version == 1) { if (NIFTI2_NEEDS_SWAP(buffer1))//yes, this works on nifti-1 also { swapped = true; swapHeaderBytes(buffer1); } - setupFrom(buffer1); + myquirks = setupFrom(buffer1); } else { throw DataFileException(inFile.getFilename() + " is not a valid NIfTI file"); } @@ -648,47 +649,56 @@ void NiftiHeader::read(CaretBinaryFile& inFile) throw DataFileException("error reading NIfTI file " + inFile.getFilename() + ": " + e.whatString()); } m_extensions.clear(); - char extender[4]; - inFile.read(extender, 4); - int extensions = 0;//if it has extensions in a format we don't know about, don't try to read them - if (version == 1 && extender[0] != 0) extensions = 1;//sadly, this is the only thing nifti-1 says about the extender bytes - if (version == 2 && extender[0] == 1 && extender[1] == 0 && extender[2] == 0 && extender[3] == 0) extensions = 1;//from http://nifti.nimh.nih.gov/nifti-2 as of 4/4/2014: - if (extensions == 1)//"extentions match those of NIfTI-1.1 when the extender bytes are 1 0 0 0" - { - int64_t extStart; - if (version == 1) - { - extStart = 352; - } else { - CaretAssert(version == 2); - extStart = 544; - } - CaretAssert(inFile.pos() == extStart); - while(extStart + 2 * sizeof(int32_t) <= (size_t)m_header.vox_offset) + if (myquirks.no_extender) + { + int min_offset = 352; + if (version == 2) min_offset = 544; + CaretLogWarning("in file '" + inFile.getFilename() + "', vox_offset is " + AString::number(m_header.vox_offset) + + ", nifti standard specifies that it should be at least " + AString::number(min_offset) + ", assuming malformed file with no extender"); + } else { + char extender[4]; + inFile.read(extender, 4); + int extensions = 0;//if it has extensions in a format we don't know about, don't try to read them + if (version == 1 && extender[0] != 0) extensions = 1;//sadly, this is the only thing nifti-1 says about the extender bytes + if (version == 2 && extender[0] == 1 && extender[1] == 0 && extender[2] == 0 && extender[3] == 0) extensions = 1;//from http://nifti.nimh.nih.gov/nifti-2 as of 4/4/2014: + if (extensions == 1)//"extentions match those of NIfTI-1.1 when the extender bytes are 1 0 0 0" { - int32_t esize, ecode; - inFile.read(&esize, sizeof(int32_t)); - if (swapped) ByteSwapping::swap(esize); - inFile.read(&ecode, sizeof(int32_t)); - if (swapped) ByteSwapping::swap(ecode); - if (esize < 8 || esize + extStart > m_header.vox_offset) break; - CaretPointer tempExtension(new NiftiExtension()); - if ((size_t)esize > 2 * sizeof(int32_t))//don't try to read 0 bytes + int64_t extStart; + if (version == 1) + { + extStart = 352; + } else { + CaretAssert(version == 2); + extStart = 544; + } + CaretAssert(inFile.pos() == extStart); + while(extStart + 2 * sizeof(int32_t) <= (size_t)m_header.vox_offset) { - tempExtension->m_bytes.resize(esize - 2 * sizeof(int32_t)); - inFile.read(tempExtension->m_bytes.data(), esize - 2 * sizeof(int32_t)); + int32_t esize, ecode; + inFile.read(&esize, sizeof(int32_t)); + if (swapped) ByteSwapping::swap(esize); + inFile.read(&ecode, sizeof(int32_t)); + if (swapped) ByteSwapping::swap(ecode); + if (esize < 8 || esize + extStart > m_header.vox_offset) break; + CaretPointer tempExtension(new NiftiExtension()); + if ((size_t)esize > 2 * sizeof(int32_t))//don't try to read 0 bytes + { + tempExtension->m_bytes.resize(esize - 2 * sizeof(int32_t)); + inFile.read(tempExtension->m_bytes.data(), esize - 2 * sizeof(int32_t)); + } + tempExtension->m_ecode = ecode; + m_extensions.push_back(tempExtension); + extStart += esize;//esize includes the two int32_ts } - tempExtension->m_ecode = ecode; - m_extensions.push_back(tempExtension); - extStart += esize;//esize includes the two int32_ts } } m_isSwapped = swapped;//now that we know there were no errors (because they throw), complete the internal state m_version = version; } -void NiftiHeader::setupFrom(const nifti_1_header& header) +NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_1_header& header) { + Quirks ret; if (header.sizeof_hdr != sizeof(nifti_1_header)) throw DataFileException("incorrect sizeof_hdr"); const char magic[] = "n+1\0";//only support single-file nifti if (strncmp(header.magic, magic, 4) != 0) throw DataFileException("incorrect magic"); @@ -697,7 +707,14 @@ void NiftiHeader::setupFrom(const nifti_1_header& header) { if (header.dim[i + 1] < 1) throw DataFileException("dim[" + QString::number(i + 1) + "] < 1"); } - if (header.vox_offset < 352) throw DataFileException("incorrect vox_offset"); + if (header.vox_offset < 352) + { + if (header.vox_offset < 348) + { + throw DataFileException("invalid vox_offset: " + AString::number(header.vox_offset)); + } + ret.no_extender = true; + } int numBits = typeToNumBits(header.datatype); if (header.bitpix != numBits) CaretLogWarning("datatype disagrees with bitpix"); m_header.sizeof_hdr = header.sizeof_hdr;//copy in everything, so we don't have to fake anything to print the header as read @@ -742,10 +759,12 @@ void NiftiHeader::setupFrom(const nifti_1_header& header) m_header.intent_code = header.intent_code; for (int i = 0; i < 16; ++i) m_header.intent_name[i] = header.intent_name[i]; m_header.dim_info = header.dim_info; + return ret; } -void NiftiHeader::setupFrom(const nifti_2_header& header) +NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_2_header& header) { + Quirks ret; if (header.sizeof_hdr != sizeof(nifti_2_header)) throw DataFileException("incorrect sizeof_hdr"); const char magic[] = "n+2\0\r\n\032\n";//only support single-file nifti for (int i = 0; i < 8; ++i) @@ -757,9 +776,10 @@ void NiftiHeader::setupFrom(const nifti_2_header& header) { if (header.dim[i + 1] < 1) throw DataFileException("dim[" + QString::number(i + 1) + "] < 1"); } - if (header.vox_offset < 352) throw DataFileException("incorrect vox_offset"); + if (header.vox_offset < 544) throw DataFileException("incorrect vox_offset");//haven't noticed any nifti-2 with bad vox_offset yet, and all cifti files have a big extension, so they have to have used it correctly if (header.bitpix != typeToNumBits(header.datatype)) CaretLogWarning("datatype disagrees with bitpix"); memcpy(&m_header, &header, sizeof(nifti_2_header)); + return ret; } int NiftiHeader::typeToNumBits(const int64_t& type) diff --git a/src/Nifti/NiftiHeader.h b/src/Nifti/NiftiHeader.h index 1ddb17bc4..c00f26720 100644 --- a/src/Nifti/NiftiHeader.h +++ b/src/Nifti/NiftiHeader.h @@ -78,6 +78,11 @@ namespace caret bool operator==(const NiftiHeader& rhs) const;//for testing purposes bool operator!=(const NiftiHeader& rhs) const { return !((*this) == rhs); } private: + struct Quirks + { + bool no_extender; + Quirks() { no_extender = false; } + }; nifti_2_header m_header;//storage for header values regardless of version int m_version; bool m_isSwapped; @@ -85,8 +90,8 @@ namespace caret static void swapHeaderBytes(nifti_2_header &header); void prepareHeader(nifti_1_header& header) const;//transform internal state into ready to write header struct void prepareHeader(nifti_2_header& header) const; - void setupFrom(const nifti_1_header& header);//error check provided header, and populate members from it - void setupFrom(const nifti_2_header& header); + Quirks setupFrom(const nifti_1_header& header);//error check provided header, and populate members from it + Quirks setupFrom(const nifti_2_header& header); static int typeToNumBits(const int64_t& type); int64_t computeVoxOffset(const int& version) const; }; -- GitLab From 650c5aa6045c039e7178ba2532a6f7beecb1b6f8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 20 Oct 2017 11:50:54 -0500 Subject: [PATCH 456/755] Did more work on drawing lines as rectangles but need to move on to higher priority items. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 44 ++- src/Graphics/GraphicsOpenGLLineDrawing.cxx | 271 +++++++++++++++--- src/Graphics/GraphicsOpenGLLineDrawing.h | 13 +- 3 files changed, 281 insertions(+), 47 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 286da285e..ceaaa33fe 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -54,7 +54,9 @@ #include "EventBrowserTabGet.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" +#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsPrimitiveV3f.h" +#include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fT3f.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" @@ -360,12 +362,17 @@ BrainOpenGLAnnotationDrawingFixedPipeline::convertModelToWindowCoordinate(const windowXYZOut[1] = windowY - m_modelSpaceViewport[1]; /* - * From OpenGL Programming Guide 3rd Ed, p 133: + * From OpenGL Programming Guide 3rd Ed, p 133, + * or 6th Ed, p 142 * - * If the near value is 1.0 and the far value is 3.0, - * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. - * So, negate the Z-value to be negative. - */ + * Remember that with the projection commands, the near and far coordinates measure + * distance from the viewpoint and that (by default) you're looking down the negative + * z axis. Thus, if the near value is 1.0 and the far 3.0, objects must have z coordinates + * between -1.0 and -3.0 in order to be visible. To ensure that you haven't clipped + * everything out of your scene, temporarily set the near and far clipping planes to + * some absurdly inclusive values, such as 0.001 and 1000000.0. This alters appearance + * for operations such as depth-buffering and fog, but it might uncover inadvertently + * clipped objects. */ windowXYZOut[2] = -windowZ; if ((m_modelSpaceProjectionMatrix[0] != 0.0) @@ -2762,6 +2769,33 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi foregroundRGBA, lineWidth); drawnFlag = true; + + /* + * For testing new line drawing + */ + const bool testLineDrawingFlag = false; + if (testLineDrawingFlag) { + std::unique_ptr primitive; + primitive.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES)); + const int32_t numXYZ = static_cast(coords.size() / 3); + const float rgba[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; + for (int32_t i = 0; i < numXYZ; i++) { + primitive->addVertex(&coords[i*3], rgba); + } + + /* + * Width not limited to OpenGL min/max + */ + float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + + GraphicsOpenGLLineDrawing lineDraw(primitive.get(), + widthPixels); + AString errorMessage; + const bool successFlag = lineDraw.run(errorMessage); + if ( ! successFlag) { + //CaretLogSevere("Line Drawing: " + errorMessage); + } + } } } diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index ef1396eec..ba50e1bcc 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -19,6 +19,8 @@ */ /*LICENSE_END*/ +#include + #define __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ #include "GraphicsOpenGLLineDrawing.h" #undef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ @@ -79,65 +81,254 @@ GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() bool GraphicsOpenGLLineDrawing::run(AString& errorMessageOut) { + /* + * Save OpenGL state + */ + glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + GLint savedPolygonMode[2]; // front and back + glGetIntegerv(GL_POLYGON_MODE, savedPolygonMode); + + GLint savedViewport[4]; + glGetIntegerv(GL_VIEWPORT, + savedViewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + errorMessageOut.clear(); - GLfloat projectionArray[16]; - glGetFloatv(GL_PROJECTION_MATRIX, + convertPointsToWindowCoordinates(); + + convertLineSegmentsToQuads(); + + drawQuads(); + + /* + * Restore OpenGL state + */ + glPolygonMode(GL_FRONT, savedPolygonMode[0]); + glPolygonMode(GL_BACK, savedPolygonMode[1]); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); + + glPopAttrib(); + + return false; +} + +/** + * Convert the points from model to window coordinates + */ +void +GraphicsOpenGLLineDrawing::convertPointsToWindowCoordinates() +{ + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + if (m_debugFlag) std::cout << "Depth Range: " << depthRange[0] << ", " << depthRange[1] << std::endl; + +// { +// glDepthRange(-5.0, 5.0); +// GLfloat depthRangeTest[2]; +// glGetFloatv(GL_DEPTH_RANGE, depthRangeTest); +// std::cout << "Setting depth range to -5,5 opengl uses " << depthRangeTest[0] << " " << depthRangeTest[1] << std::endl; +// } +// + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); + Matrix4x4 projectionMatrix; + projectionMatrix.setMatrixFromOpenGL(projectionArray); - GLfloat modelviewArray[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); + Matrix4x4 modelviewMatrix; + modelviewMatrix.setMatrixFromOpenGL(modelviewArray); - GLint viewportArray[4]; + GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, - viewportArray); - - Matrix4x4 matrixToViewport; + viewport); + Matrix4x4 projectionTimesModelMatrix(projectionMatrix); + projectionTimesModelMatrix.postmultiply(modelviewMatrix); const std::vector& xyz = m_inputPrimitive->getFloatXYZ(); - const int32_t numPointsMinusOne = static_cast(xyz.size() - 1); + m_windowLineSegmentsXYZ.reserve(xyz.size()); + + const int32_t numPoints = static_cast(xyz.size() / 3); + for (int32_t i = 0; i < numPoints; i++) { + const int32_t i3 = i * 3; + + /* + * Convert model coordinate to a window coordinate + * as described by the documentation from gluProject(). + */ + float xyzw[4] = { xyz[i3], xyz[i3+1], xyz[i3+2], 1.0f }; + projectionTimesModelMatrix.multiplyPoint4(xyzw); + const float windowX = viewport[0] + (viewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); + const float windowY = viewport[1] + (viewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); + float windowZ = (xyzw[2] + 1.0f) / 2.0f; + + /* + * From OpenGL Programming Guide 3rd Ed, p 133: + * + * If the near value is 1.0 and the far value is 3.0, + * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. + * So, negate the Z-value to be negative. + */ + windowZ = -windowZ; + + m_windowLineSegmentsXYZ.push_back(windowX); + m_windowLineSegmentsXYZ.push_back(windowY); + m_windowLineSegmentsXYZ.push_back(windowZ); + + if (m_debugFlag) { + GLdouble winX, winY, winZ; + gluProject(xyz[i3], xyz[i3+1], xyz[i3+2], + modelviewArray, projectionArray, viewport, + &winX, &winY, &winZ); + std::cout << "Input: " << xyz[i3] << ", " << xyz[i3+1] << ", " << xyz[i3+2] << std::endl; + std::cout << " Pt " << i << ": " + << windowX << ", " << windowY << ", " << windowZ << " w=" << xyzw[3] << std::endl; + std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; + } + } +} + +/** + * Convert each line segment into a rectangle + * using the line width. "Length" of the + * rectangle is the length of the line segment + * and "width" of the rectangle is the line width. + */ +void +GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() +{ + const int32_t numPoints = static_cast(m_windowLineSegmentsXYZ.size() / 3); + m_windowQuadsXYZ.reserve(numPoints * 6); // 2 points in line to 4 points in quad + + const int32_t numPointsMinusOne = static_cast((m_windowLineSegmentsXYZ.size() / 3) - 1); for (int32_t i = 0; i < numPointsMinusOne; i++) { const int32_t i3 = i * 3; - convertLineToRectangle(&xyz[i3], - &xyz[i3 + 3]); + float x1 = m_windowLineSegmentsXYZ[i3]; + float y1 = m_windowLineSegmentsXYZ[i3 + 1]; + float z1 = m_windowLineSegmentsXYZ[i3 + 2]; + float x2 = m_windowLineSegmentsXYZ[i3 + 3]; + float y2 = m_windowLineSegmentsXYZ[i3 + 4]; + float z2 = m_windowLineSegmentsXYZ[i3 + 5]; + + /* + * Vector from start to end on line segment in 2D coordinates + */ + float startToEndVector[3] = { + x2 - x1, + y2 - y1, + 0.0f + }; + + /* + * Create a perpendicualar vector to the line segment + */ + MathFunctions::normalizeVector(startToEndVector); + float perpendicularVector[3] = { + startToEndVector[1], + -startToEndVector[0], + 0.0f + }; + + /* + * "Width" of rectangle + */ + const float halfWidth = m_lineThicknessPixels / 2.0f; + const float halfWidthX = perpendicularVector[0] * halfWidth; + const float halfWidthY = perpendicularVector[1] * halfWidth; + + /* + * Points of the rectangle + */ + float p1[3] = { + x1 - halfWidthX, + y1 - halfWidthY, + z1 + }; + float p2[3] = { + x1 + halfWidthX, + y1 + halfWidthY, + z1 + }; + float p3[3] = { + x2 + halfWidthX, + y2 + halfWidthY, + z2 + }; + float p4[3] = { + x2 - halfWidthX, + y2 - halfWidthY, + z2 + }; + + float crossProduct[3]; + MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); + if (crossProduct[2] < 0.0) { + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); + } } - return false; + } void -GraphicsOpenGLLineDrawing::convertLineToRectangle(const float* startXYZ, - const float* endXYZ) +GraphicsOpenGLLineDrawing::drawQuads() { - float x1 = startXYZ[0]; - float y1 = startXYZ[1]; - float x2 = endXYZ[0]; - float y2 = endXYZ[1]; - - float perpendicularVector[3] = { - y2 - y1, - x2 - x1, - 0.0f - }; - - const float halfThickness = m_lineThicknessPixels / 2.0f; - MathFunctions::normalizeVector(perpendicularVector); - const float halfX = perpendicularVector[0] * halfThickness; - const float halfY = perpendicularVector[1] * halfThickness; - - float rectangleXY[8] = { - x1 - halfX, - y1 - halfY, - x1 + halfX, - y1 + halfY, - x2 + halfX, - y2 + halfY, - x2 - halfX, - x2 - halfY - }; + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(viewport[0], viewport[0] + viewport[2], + viewport[1], viewport[1] + viewport[3], + 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPolygonMode(GL_FRONT, GL_FILL); + glPolygonMode(GL_BACK, GL_LINE); + glColor3f(0.0, 1.0, 0.0); + glLineWidth(1.0); + glBegin(GL_QUADS); //GL_QUADS) + for (int32_t j = 0; j < 4; j++) { + glNormal3f(0.0, 0.0, -1.0); + glVertex3fv(&m_windowQuadsXYZ[j*3]); + } + glEnd(); + + if (m_debugFlag) { + std::cout << std::endl << "QUADS: " << AString::fromNumbers(m_windowQuadsXYZ, ",") << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; + } } /** diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index 107d98d57..9c67e1abe 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -52,8 +52,11 @@ namespace caret { GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj); - void convertLineToRectangle(const float* startXYZ, - const float* endXYZ); + void convertPointsToWindowCoordinates(); + + void convertLineSegmentsToQuads(); + + void drawQuads(); const GraphicsPrimitive* m_inputPrimitive; @@ -61,6 +64,12 @@ namespace caret { GraphicsPrimitive* m_outputPrimitive = NULL; + std::vector m_windowLineSegmentsXYZ; + + std::vector m_windowQuadsXYZ; + + bool m_debugFlag = false; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 8e56c7ef51d3162d7288fbba8e0a0137e800e760 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 14:59:51 -0500 Subject: [PATCH 457/755] Added additional 'modification tracking' to scene file and its contents (Scene, SceneInfo) so that setting Scene IDs after upload to BALSA results in saving of scene file. --- src/Files/SceneFile.cxx | 29 +++++++++++++++++++++++++++++ src/Files/SceneFile.h | 4 ++++ src/Scenes/Scene.cxx | 33 +++++++++++++++++++++++++++++++-- src/Scenes/Scene.h | 7 +++++-- src/Scenes/SceneInfo.cxx | 26 +++++++++++++++++++------- src/Scenes/SceneInfo.h | 4 ++-- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 1e5f6756a..3366dc108 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -949,4 +949,33 @@ SceneFile::getDefaultExtractToDirectoryName() const return directoryName; } +/** + * @return True if this scene is modified. + */ +bool +SceneFile::isModified() const +{ + if (CaretDataFile::isModified()) { + return true; + } + for (const auto scene : m_scenes) { + if (scene->isModified()) { + return true; + } + } + + return false; +} + +/** + * Clear the modified status of this scene. + */ +void +SceneFile::clearModified() +{ + CaretDataFile::clearModified(); + for (auto scene : m_scenes) { + scene->clearModified(); + } +} diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 60e38b625..f3b0eb7cf 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -116,6 +116,10 @@ namespace caret { AString getDefaultExtractToDirectoryName() const; + virtual bool isModified() const override; + + virtual void clearModified() override; + // ADD_NEW_METHODS_HERE /** Version of file */ diff --git a/src/Scenes/Scene.cxx b/src/Scenes/Scene.cxx index b1fcd8ec8..2c679245d 100644 --- a/src/Scenes/Scene.cxx +++ b/src/Scenes/Scene.cxx @@ -231,14 +231,15 @@ SomeClass::restoreFromScene(const SceneAttributes* sceneAttributes, * Type of scene. */ Scene::Scene(const SceneTypeEnum::Enum sceneType) -: CaretObject() +:CaretObjectTracksModification() { m_sceneAttributes = new SceneAttributes(sceneType); m_hasFilesWithRemotePaths = false; m_sceneInfo = new SceneInfo(); } -Scene::Scene(const Scene& rhs) : CaretObject() +Scene::Scene(const Scene& rhs) +:CaretObjectTracksModification() { m_sceneAttributes = new SceneAttributes(*(rhs.m_sceneAttributes)); m_hasFilesWithRemotePaths = rhs.m_hasFilesWithRemotePaths; @@ -310,6 +311,7 @@ Scene::addClass(SceneClass* sceneClass) { if (sceneClass != NULL) { m_sceneClasses.push_back(sceneClass); + setModified(); } } @@ -493,6 +495,33 @@ Scene::setSceneInfo(SceneInfo* sceneInfo) delete m_sceneInfo; } m_sceneInfo = sceneInfo; + setModified(); +} + +/** + * @return True if this scene is modified. + */ +bool +Scene::isModified() const +{ + if (CaretObjectTracksModification::isModified()) { + return true; + } + if (m_sceneInfo->isModified()) { + return true; + } + + return false; +} + +/** + * Clear the modified status of this scene. + */ +void +Scene::clearModified() +{ + CaretObjectTracksModification::clearModified(); + m_sceneInfo->clearModified(); } diff --git a/src/Scenes/Scene.h b/src/Scenes/Scene.h index 02b932c56..939edc7d2 100644 --- a/src/Scenes/Scene.h +++ b/src/Scenes/Scene.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ -#include "CaretObject.h" +#include "CaretObjectTracksModification.h" #include "SceneTypeEnum.h" namespace caret { @@ -31,7 +31,7 @@ namespace caret { class SceneInfo; class SceneObject; - class Scene : public CaretObject { + class Scene : public CaretObjectTracksModification { public: Scene(const SceneTypeEnum::Enum sceneType); @@ -81,6 +81,9 @@ namespace caret { void setHasFilesWithRemotePaths(const bool hasFilesWithRemotePaths); + virtual bool isModified() const override; + + virtual void clearModified() override; // ADD_NEW_METHODS_HERE diff --git a/src/Scenes/SceneInfo.cxx b/src/Scenes/SceneInfo.cxx index 0846d6e40..a5e3cfbe4 100644 --- a/src/Scenes/SceneInfo.cxx +++ b/src/Scenes/SceneInfo.cxx @@ -42,12 +42,12 @@ using namespace caret; * Constructor. */ SceneInfo::SceneInfo() -: CaretObject() +: CaretObjectTracksModification() { } -SceneInfo::SceneInfo(const SceneInfo& rhs) : CaretObject() +SceneInfo::SceneInfo(const SceneInfo& rhs) : CaretObjectTracksModification() { m_sceneName = rhs.m_sceneName; m_sceneDescription = rhs.m_sceneDescription; @@ -80,7 +80,10 @@ SceneInfo::getName() const void SceneInfo::setName(const AString& sceneName) { - m_sceneName = sceneName; + if (sceneName != m_sceneName) { + m_sceneName = sceneName; + setModified(); + } } /** @@ -100,7 +103,10 @@ SceneInfo::getDescription() const void SceneInfo::setDescription(const AString& sceneDescription) { - m_sceneDescription = sceneDescription; + if (sceneDescription != m_sceneDescription) { + m_sceneDescription = sceneDescription; + setModified(); + } } /** @@ -115,8 +121,11 @@ void SceneInfo::setImageBytes(const QByteArray& imageBytes, const AString& imageFormat) { - m_imageBytes = imageBytes; - m_imageFormat = imageFormat; + if ((imageBytes != m_imageBytes) + || (imageFormat != m_imageFormat)) { + m_imageBytes = imageBytes; + m_imageFormat = imageFormat; + } } /** @@ -169,7 +178,10 @@ SceneInfo::getBalsaSceneID() const void SceneInfo::setBalsaSceneID(const AString& balsaSceneID) { - m_balsaSceneID = balsaSceneID; + if (balsaSceneID != m_balsaSceneID) { + m_balsaSceneID = balsaSceneID; + setModified(); + } } /** diff --git a/src/Scenes/SceneInfo.h b/src/Scenes/SceneInfo.h index 5ccb646cb..b4358c77e 100644 --- a/src/Scenes/SceneInfo.h +++ b/src/Scenes/SceneInfo.h @@ -22,14 +22,14 @@ /*LICENSE_END*/ #include -#include "CaretObject.h" +#include "CaretObjectTracksModification.h" namespace caret { class XmlWriter; - class SceneInfo : public CaretObject { + class SceneInfo : public CaretObjectTracksModification { public: SceneInfo(); -- GitLab From ff7f152c38a0938ffdae9e5dc21598d94551829a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 15:02:03 -0500 Subject: [PATCH 458/755] Added JsonHelper class to assist with processing of JSON. --- src/Common/CMakeLists.txt | 2 + src/Common/JsonHelper.cxx | 113 ++++++++++++++++++++++++++++++++++++++ src/Common/JsonHelper.h | 61 ++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 src/Common/JsonHelper.cxx create mode 100644 src/Common/JsonHelper.h diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 8552c39b9..7a5cc299a 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -113,6 +113,7 @@ FloatMatrix.h Histogram.h HtmlStringBuilder.h ImageCaptureMethodEnum.h +JsonHelper.h Logger.h LogHandler.h LogHandlerStandardError.h @@ -211,6 +212,7 @@ FloatMatrix.cxx Histogram.cxx HtmlStringBuilder.cxx ImageCaptureMethodEnum.cxx +JsonHelper.cxx Logger.cxx LogHandler.cxx LogHandlerStandardError.cxx diff --git a/src/Common/JsonHelper.cxx b/src/Common/JsonHelper.cxx new file mode 100644 index 000000000..a49fc1bc4 --- /dev/null +++ b/src/Common/JsonHelper.cxx @@ -0,0 +1,113 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __JSON_HELPER_DECLARE__ +#include "JsonHelper.h" +#undef __JSON_HELPER_DECLARE__ + +#include +#include +#include +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::JsonHelper + * \brief Helper class for JSON processing. + * \ingroup Common + */ + +/** + * Constructor. + */ +JsonHelper::JsonHelper() +{ + +} + +/** + * Destructor. + */ +JsonHelper::~JsonHelper() +{ +} + +/** + * Determine type of content in the value and return its string representation + * + * @param jsonValue + * The JSON Value + * @return + * The string representation of the value. + */ +AString +JsonHelper::jsonValueToString(const QJsonValue& jsonValue) +{ + AString typeString("Invalid: "); + AString contentString; + QJsonDocument contentJson; + + switch (jsonValue.type()) { + case QJsonValue::Array: + typeString = "Array: "; + contentJson = QJsonDocument(jsonValue.toArray()); + break; + case QJsonValue::Bool: + typeString = "Bool: "; + contentString = AString::fromBool(jsonValue.toBool()); + break; + case QJsonValue::Double: + typeString = "Double: "; + contentString = AString::fromBool(jsonValue.toDouble()); + break; + case QJsonValue::Null: + typeString = "Null: "; + contentString = ""; + break; + case QJsonValue::Object: + typeString = "Object: "; + contentJson = QJsonDocument(jsonValue.toObject()); + break; + case QJsonValue::String: + typeString = "String: "; + contentString = jsonValue.toString(); + break; + case QJsonValue::Undefined: + typeString = "Undefined: "; + contentString = ""; + break; + } + + AString s(typeString); + + if (contentJson.isNull()) { + s.append(contentString); + } + else { + s.append(contentJson.toJson(QJsonDocument::Compact)); + } + + return s; +} diff --git a/src/Common/JsonHelper.h b/src/Common/JsonHelper.h new file mode 100644 index 000000000..a0ab4e74b --- /dev/null +++ b/src/Common/JsonHelper.h @@ -0,0 +1,61 @@ +#ifndef __JSON_HELPER_H__ +#define __JSON_HELPER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "AString.h" + +class QJsonValue; + + +namespace caret { + + class JsonHelper { + + public: + static AString jsonValueToString(const QJsonValue& jsonValue); + + + // ADD_NEW_METHODS_HERE + + private: + JsonHelper(); + + virtual ~JsonHelper(); + + JsonHelper(const JsonHelper&); + + JsonHelper& operator=(const JsonHelper&); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __JSON_HELPER_DECLARE__ + // +#endif // __JSON_HELPER_DECLARE__ + +} // namespace +#endif //__JSON_HELPER_H__ -- GitLab From b782d52a94717f0c01ad0ddc2333375ad195830b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 15:08:06 -0500 Subject: [PATCH 459/755] Resolve WB-728 After upload to BALSA, workbench requests scene IDs and saves in scene file and WB-749 Workbench BALSA updates: When logging in, "user roles" are evaluated to verify that the user is allowed to upload files; revised BALSA upload dialog to include auto saving and other options; after Scene File is upload update Scene IDs in the local copy of the scene file. --- src/GuiQt/BalsaDatabaseManager.cxx | 307 ++++++++++++++---- src/GuiQt/BalsaDatabaseManager.h | 38 ++- .../BalsaDatabaseUploadSceneFileDialog.cxx | 33 +- .../BalsaDatabaseUploadSceneFileDialog.h | 2 + 4 files changed, 320 insertions(+), 60 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 235f54f95..6c3f6f8b9 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -36,8 +36,10 @@ #include "EventManager.h" #include "EventProgressUpdate.h" #include "FileInformation.h" +#include "JsonHelper.h" #include "OperationZipSceneFile.h" #include "ProgramParameters.h" +#include "Scene.h" #include "SceneFile.h" using namespace caret; @@ -58,7 +60,7 @@ BalsaDatabaseManager::BalsaDatabaseManager() { m_debugFlag = false; logout(); -// EventManager::get()->addEventListener(this, EventTypeEnum::); + //EventManager::get()->addEventListener(this, EventTypeEnum::); } /** @@ -289,7 +291,7 @@ BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, responseContentOut.append(&uploadResponse.m_body[0]); - return processUploadResponse(uploadResponse.m_headers, + return verifyUploadFileResponse(uploadResponse.m_headers, responseContentOut, uploadResponse.m_responseCode, errorMessageOut); @@ -310,7 +312,7 @@ BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, * True if response shows upload was successful, else false. */ bool -BalsaDatabaseManager::processUploadResponse(const std::map& responseHeaders, +BalsaDatabaseManager::verifyUploadFileResponse(const std::map& responseHeaders, const AString& responseContent, const int32_t responseHttpCode, AString& errorMessageOut) const @@ -519,35 +521,34 @@ BalsaDatabaseManager::getJSessionIdCookie() const void BalsaDatabaseManager::receiveEvent(Event* /*event*/) { -// if (event->getEventType() == EventTypeEnum::) { -// eventName = dynamic_cast(event); -// CaretAssert(eventName); -// -// event->setEventProcessed(); -// } + // if (event->getEventType() == EventTypeEnum::) { + // eventName = dynamic_cast(event); + // CaretAssert(eventName); + // + // event->setEventProcessed(); + // } } /** * Request BALSA database process the file that was uploaded. * + * @param sceneFile + * Scene file that was uploaded. * @param processUploadURL * URL for uploading file. * @param httpContentTypeName * Type of content for upload (eg: application/zip, see http://www.freeformatter.com/mime-types-list.html) - * @param responseContentOut - * If successful, contains the response content received after successful upload. * @param errorMessageOut * Contains error information if upload failed. * @return * True if upload is successful, else false. */ bool -BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, +BalsaDatabaseManager::processUploadedFile(SceneFile* sceneFile, + const AString& processUploadURL, const AString& httpContentTypeName, - AString& responseContentOut, AString& errorMessageOut) { - responseContentOut.clear(); errorMessageOut.clear(); if (httpContentTypeName.isEmpty()) { @@ -563,6 +564,8 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, httpContentTypeName)); uploadRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); + uploadRequest.m_arguments.push_back(std::make_pair("type", + "json")); CaretHttpResponse uploadResponse; CaretHttpManager::httpRequest(uploadRequest, uploadResponse); @@ -571,6 +574,14 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, std::cout << "Process upload response Code: " << uploadResponse.m_responseCode << std::endl; } + if (uploadResponse.m_responseCode != 200) { + errorMessageOut = ("Process Upload failed code: " + + QString::number(uploadResponse.m_responseCode) + + "\n"); + + return false; + } + for (std::map::iterator mapIter = uploadResponse.m_headers.begin(); mapIter != uploadResponse.m_headers.end(); mapIter++) { @@ -581,26 +592,110 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, } uploadResponse.m_body.push_back('\0'); - responseContentOut.append(&uploadResponse.m_body[0]); - CaretLogFine("Process Upload to BALSA reply body: " - + responseContentOut); + AString responseContent(&uploadResponse.m_body[0]); + if (m_debugFlag) { + std::cout << "Process Upload to BALSA reply body: " << responseContent << std::endl; + } + else { + CaretLogFine("Process Upload to BALSA reply body: " + + responseContent); + } - if (uploadResponse.m_responseCode == 200) { - return true; + + AString contentType = getHeaderValue(uploadResponse, "Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Process Upload Content type returned by BALSA is unknown"); + return false; } - errorMessageOut = ("Process Upload failed code: " - + QString::number(uploadResponse.m_responseCode) - + "\n" - + responseContentOut); + if ( ! contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Process Upload Content type return by BALSA should be JSON format but is " + + contentType + + "Scene File was uploaded but Scene IDs will not be updated"); + return false; + } + + if ( ! updateSceneIdsFromProcessUploadResponse(sceneFile, + responseContent, + errorMessageOut)) { + return false; + } - return false; + return true; +} + +/** + * Get the Scene IDs from the JSON content returned by + * the process upload command and update the scene file. + * + * @param sceneFile + * Scene file that was uploaded. + * @param jsonContent + * The JSON content. + * @param errorMessage + * Contains error information if there is a problem. + * @return + * true if successful, else false. + */ +bool +BalsaDatabaseManager::updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFile, + const AString& jsonContent, + AString& errorMessageOut) +{ + QJsonParseError jsonError; + QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonContent.toLatin1(), + &jsonError); + if (jsonDocument.isNull()) { + errorMessageOut = ("Failed to parse JSON response from procssess upload, error:" + + jsonError.errorString()); + return false; + } + if ( ! jsonDocument.isArray()) { + errorMessageOut = ("Unrecognized format of JSON response from process upload (not an array)"); + return false; + } + const AString mySceneFileName = sceneFile->getFileNameNoPath(); + + QJsonArray jsonArray = jsonDocument.array(); + const int32_t numFileAndSceneIds = jsonArray.count(); + for (int32_t j = 0; j < numFileAndSceneIds; j++) { + SceneFileIdentifiers sceneFileIDs(m_debugFlag, + jsonArray.at(j)); + if ( ! sceneFileIDs.isValid()) { + errorMessageOut = ("Scene File IDs error: " + + sceneFileIDs.getErrorMessage()); + return false; + } + + if (sceneFileIDs.m_sceneFileName == mySceneFileName) { + for (const auto& indexAndID : sceneFileIDs.m_sceneIndexAndIDsMap) { + const int32_t sceneIndex = indexAndID.first; + const AString sceneID = indexAndID.second; + + if ((sceneIndex >= 0) + && (sceneIndex < sceneFile->getNumberOfScenes())) { + Scene* scene = sceneFile->getSceneAtIndex(sceneIndex); + CaretAssert(scene); + scene->setBalsaSceneID(sceneID); + } + else { + errorMessageOut = ("Invalid Scene Index from BALSA Scene IDs: " + + AString::number(sceneIndex)); + return false; + } + } + } + } + + return true; } /** * Get the value for the given header name using * a case-insensitive string comparison. * + * @param httpResponse + * The HTTP response. * @param headerName * The header name. * @return @@ -608,8 +703,9 @@ BalsaDatabaseManager::processUploadedFile(const AString& processUploadURL, * not found the returned string will be NULL * (test with .isNull()). */ -static AString getHeaderValue(const CaretHttpResponse& httpResponse, - const AString& headerName) +AString +BalsaDatabaseManager::getHeaderValue(const CaretHttpResponse& httpResponse, + const AString& headerName) const { /* * NULL string @@ -769,30 +865,6 @@ BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& studyTitle, return true; } -///** -// * Login to BALSA and request a study ID from a study title. -// * -// * @param studyTitle -// * The study's title. -// * @param studyIdOut -// * Output containing the study ID. -// * @param errorMessageOut -// * Contains description of any error(s). -// * @return -// * True if processing was successful, else false. -// */ -//bool -//BalsaDatabaseManager::getUserRoles(AString& roleNamesOut, -// AString& errorMessageOut) -//{ -// if ( ! requestUserRoles(m_databaseURL, -// roleNamesOut, -// errorMessageOut)) { -// return false; -// } -// -// return true; -//} /** * Get the User's Roles. * @@ -1032,7 +1104,7 @@ BalsaDatabaseManager::getAllStudyInformation(std::vector& * True if processing was successful, else false. */ bool -BalsaDatabaseManager::uploadZippedSceneFile(const SceneFile* sceneFile, +BalsaDatabaseManager::uploadZippedSceneFile(SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, AString& errorMessageOut) @@ -1098,7 +1170,7 @@ BalsaDatabaseManager::uploadZippedSceneFile(const SceneFile* sceneFile, return false; } - if (m_debugFlag) std::cout << "Zip file has been created " << std::endl; + if (m_debugFlag) std::cout << "Zip file " << zipFileName << " has been created " << std::endl; progressUpdate.setProgress(PROGRESS_UPLOAD, "Uploading zip file"); EventManager::get()->sendEvent(progressUpdate.getPointer()); @@ -1133,10 +1205,9 @@ BalsaDatabaseManager::uploadZippedSceneFile(const SceneFile* sceneFile, const AString processUploadURL(m_databaseURL + "/study/processUpload/" + sceneFile->getBalsaStudyID()); - AString processUploadResultText; - const bool processUploadSuccessFlag = processUploadedFile(processUploadURL, + const bool processUploadSuccessFlag = processUploadedFile(sceneFile, + processUploadURL, "application/x-www-form-urlencoded", - processUploadResultText, errorMessageOut); if (m_debugFlag) std::cout << "Result of processing the uploaded ZIP file" << AString::fromBool(processUploadSuccessFlag) << std::endl; @@ -1157,7 +1228,133 @@ BalsaDatabaseManager::uploadZippedSceneFile(const SceneFile* sceneFile, progressUpdate.setProgress(PROGRESS_DONE, "Finished."); EventManager::get()->sendEvent(progressUpdate.getPointer()); + return true; } +/** + * Constructor that parses JSON containing scene file name and identifiers. + * + * Example: ["FileName.scene",[[1,"55XX"],[0,"n51z"]]] + * + * @param debugFlag + * Debugging flag + * @param jsonValue + * The JSON value containing the array. + */ +BalsaDatabaseManager::SceneFileIdentifiers::SceneFileIdentifiers(const bool debugFlag, + const QJsonValue& jsonValue) +: m_debugFlag(debugFlag) +{ + if ( ! jsonValue.isArray()) { + m_errorMessage = ("Scene File Name/Identifier is not JSON array \"" + + JsonHelper::jsonValueToString(jsonValue) + + "\""); + return; + } + + if (m_debugFlag) { + std::cout << "Scene IDs Content: " << JsonHelper::jsonValueToString(jsonValue) << std::endl; + } + + + const QJsonArray jsonArray = jsonValue.toArray(); + if (jsonArray.count() != 2) { + m_errorMessage = ("Scene File Name/Identifier array should have two elements \"" + + JsonHelper::jsonValueToString(jsonValue) + + "\""); + return; + } + + const QJsonValue sceneFileNameJsonValue = jsonArray.at(0); + if ( ! sceneFileNameJsonValue.isString()) { + m_errorMessage = ("Scene File Name is not a string \"" + + JsonHelper::jsonValueToString(sceneFileNameJsonValue) + + "\""); + return; + } + m_sceneFileName = sceneFileNameJsonValue.toString(); + + const QJsonValue sceneIDsJsonValue = jsonArray.at(1); + if ( ! sceneIDsJsonValue.isArray()) { + m_errorMessage = ("Scene IDs is not an array \"" + + JsonHelper::jsonValueToString(sceneFileNameJsonValue) + + "\""); + + return; + } + + const QJsonArray sceneIDsArray = sceneIDsJsonValue.toArray(); + const int numSceneIDs = sceneIDsArray.count(); + for (int32_t i = 0; i < numSceneIDs; i++) { + const QJsonValue sceneIDJsonElementValue = sceneIDsArray.at(i); + if (m_debugFlag) { + std::cout << "Scene Index/ID: " << i << " " << JsonHelper::jsonValueToString(sceneIDJsonElementValue) << std::endl; + } + + if ( ! sceneIDJsonElementValue.isArray()) { + m_errorMessage = ("Scene Index/ID is not an array \"" + + JsonHelper::jsonValueToString(sceneIDJsonElementValue) + + "\""); + + return; + } + + const QJsonArray sceneIDJsonArray = sceneIDJsonElementValue.toArray(); + if (sceneIDJsonArray.count() != 2) { + m_errorMessage = ("Scene Index/ID array should have two elements \"" + + JsonHelper::jsonValueToString(sceneIDJsonArray) + + "\""); + return; + } + + const QJsonValue sceneIndexValue = sceneIDJsonArray.at(0); + if ( ! sceneIndexValue.isDouble()) { + m_errorMessage = ("Scene Index (first element) is not a number \"" + + JsonHelper::jsonValueToString(sceneIndexValue) + + "\""); + return; + } + + const QJsonValue sceneIDValue = sceneIDJsonArray.at(1); + if ( ! sceneIDValue.isString()) { + m_errorMessage = ("Scene ID (second element) is not a string \"" + + JsonHelper::jsonValueToString(sceneIDJsonArray) + + "\""); + return; + } + + const int32_t invalidIndex = -1; + const int32_t sceneIndex = sceneIndexValue.toInt(invalidIndex); + if (sceneIndex == invalidIndex) { + m_errorMessage = ("Scene Index (first element) is not an integer \"" + + JsonHelper::jsonValueToString(sceneIndexValue) + + "\""); + return; + } + + const AString sceneID = sceneIDValue.toString(); + + m_sceneIndexAndIDsMap.insert(std::make_pair(sceneIndex, + sceneID)); + } +} + +/** + * @return True if parsing was valid. + */ +bool +BalsaDatabaseManager::SceneFileIdentifiers::isValid() const +{ + return (m_errorMessage.isEmpty()); +} + +/** + * @return Error message describing parsing problem. + */ +AString +BalsaDatabaseManager::SceneFileIdentifiers::getErrorMessage() const +{ + return m_errorMessage; +} diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index d41f219ff..b590012f2 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -21,13 +21,18 @@ */ /*LICENSE_END*/ +#include + #include "BalsaStudyInformation.h" #include "CaretObject.h" #include "EventListenerInterface.h" +class QJsonValue; + namespace caret { class BalsaUserRoles; + struct CaretHttpResponse; class SceneFile; class BalsaDatabaseManager : public CaretObject, public EventListenerInterface { @@ -54,7 +59,7 @@ namespace caret { AString& studyIdOut, AString& errorMessageOut); - bool uploadZippedSceneFile(const SceneFile* sceneFile, + bool uploadZippedSceneFile(SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, AString& errorMessageOut); @@ -71,6 +76,24 @@ namespace caret { virtual void receiveEvent(Event* event); private: + class SceneFileIdentifiers { + public: + SceneFileIdentifiers(const bool debugFlag, + const QJsonValue& jsonValue); + + bool isValid() const; + + AString getErrorMessage() const; + + const bool m_debugFlag; + + AString m_errorMessage; + + AString m_sceneFileName; + + std::map m_sceneIndexAndIDsMap; + }; + BalsaDatabaseManager(const BalsaDatabaseManager&); BalsaDatabaseManager& operator=(const BalsaDatabaseManager&); @@ -83,9 +106,9 @@ namespace caret { AString& responseContentOut, AString& errorMessageOut); - bool processUploadedFile(const AString& processUploadURL, + bool processUploadedFile(SceneFile* sceneFile, + const AString& processUploadURL, const AString& httpContentTypeName, - AString& responseContentOut, AString& errorMessageOut); bool requestStudyID(const AString& databaseURL, @@ -99,11 +122,18 @@ namespace caret { AString& responseContentOut, AString& errorMessageOut); - bool processUploadResponse(const std::map& responseHeaders, + bool verifyUploadFileResponse(const std::map& responseHeaders, const AString& responseContent, const int32_t responseHttpCode, AString& errorMessageOut) const; + AString getHeaderValue(const CaretHttpResponse& httpResponse, + const AString& headerName) const; + + bool updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFile, + const AString& jsonContent, + AString& errorMessageOut); + AString m_databaseURL; AString m_username; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 95911eda7..9733d67c6 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -89,7 +89,6 @@ m_sceneFile(sceneFile) QWidget* loginWidget = createLoginWidget(); m_uploadWidget = createTabWidget(); - m_uploadPushButton->setEnabled(false); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); @@ -173,6 +172,8 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() m_usernameLineEdit->setValidator(createValidator(LabelName::LABEL_USERNAME)); QObject::connect(m_usernameLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); + QObject::connect(m_usernameLineEdit, &QLineEdit::returnPressed, + this, &BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword); /* * Password @@ -185,6 +186,8 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() m_passwordLineEdit->setValidator(createValidator(LabelName::LABEL_PASSWORD)); QObject::connect(m_passwordLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); + QObject::connect(m_passwordLineEdit, &QLineEdit::returnPressed, + this, &BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword); /* * Forgot username label/link @@ -261,6 +264,7 @@ BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() { m_balsaDatabaseManager->logout(); m_uploadPushButton->setEnabled(false); + m_selectStudyTitlePushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateAllLabels(); } @@ -539,6 +543,7 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() const AString password = m_passwordLineEdit->text().trimmed(); m_uploadPushButton->setEnabled(false); + m_selectStudyTitlePushButton->setEnabled(false); CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -587,8 +592,27 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() } m_uploadPushButton->setEnabled(true); + m_selectStudyTitlePushButton->setEnabled(true); +} + +/** + * Gets called when return is pressed in either username + * or password. If both contain text, try to login. + */ +void +BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword() +{ + if (m_usernameLineEdit->text().trimmed().isEmpty()) { + return; + } + if (m_passwordLineEdit->text().trimmed().isEmpty()) { + return; + } + + loginButtonClicked(); } + /** * Gets called when the upload button is clicked. */ @@ -693,6 +717,13 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() cursor.restoreCursor(); + /* + * Scene file may be modified with updated Scene IDs from BALSA. + * Allow user to save, but do not require saving + */ + saveSceneFile("Scene IDs were updated by BALSA during upload. Would you like " + "to save the scene file using its current name?"); + progressDialog.setValue(progressDialog.maximum()); if (successFlag) { diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 3b9a11b44..2706b82b8 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -60,6 +60,8 @@ namespace caret { void loginButtonClicked(); + void returnPressedUsernameOrPassword(); + void uploadButtonClicked(); void labelHtmlLinkClicked(const QString&); -- GitLab From 20176f9dcb3c1df8725ab946c13b43d51f408270 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 15:57:44 -0500 Subject: [PATCH 460/755] Add a method to JsonHelper to convert a Json Array to a string. --- src/Common/JsonHelper.cxx | 17 +++++++++++++++++ src/Common/JsonHelper.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/src/Common/JsonHelper.cxx b/src/Common/JsonHelper.cxx index a49fc1bc4..b5d05dc8b 100644 --- a/src/Common/JsonHelper.cxx +++ b/src/Common/JsonHelper.cxx @@ -54,6 +54,23 @@ JsonHelper::~JsonHelper() { } +/** + * Convert the JSON Array to a String representation + * + * @param jsonValue + * The JSON Value + * @return + * The string representation of the value. + */ +AString +JsonHelper::jsonArrayToString(const QJsonArray& jsonArray) +{ + const QJsonDocument contentJson = QJsonDocument(jsonArray); + const AString s = contentJson.toJson(QJsonDocument::Compact); + return s; +} + + /** * Determine type of content in the value and return its string representation * diff --git a/src/Common/JsonHelper.h b/src/Common/JsonHelper.h index a0ab4e74b..c307fc0a5 100644 --- a/src/Common/JsonHelper.h +++ b/src/Common/JsonHelper.h @@ -27,6 +27,7 @@ #include "AString.h" +class QJsonArray; class QJsonValue; @@ -35,6 +36,8 @@ namespace caret { class JsonHelper { public: + static AString jsonArrayToString(const QJsonArray& jsonArray); + static AString jsonValueToString(const QJsonValue& jsonValue); -- GitLab From 9fa1b97edcaca98f53e962673bd9579e9fab7463 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 15:58:42 -0500 Subject: [PATCH 461/755] Verify that the array of Scene IDs returned by BALSA is not empty. --- src/GuiQt/BalsaDatabaseManager.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 6c3f6f8b9..ff6a92f4a 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -658,6 +658,12 @@ BalsaDatabaseManager::updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFi QJsonArray jsonArray = jsonDocument.array(); const int32_t numFileAndSceneIds = jsonArray.count(); + if (numFileAndSceneIds <= 0) { + errorMessageOut = ("No Scene IDs were returned by BALSA. Content returned \"" + + JsonHelper::jsonArrayToString(jsonArray) + + "\""); + return false; + } for (int32_t j = 0; j < numFileAndSceneIds; j++) { SceneFileIdentifiers sceneFileIDs(m_debugFlag, jsonArray.at(j)); -- GitLab From 43ee7baee361b5b6f48caa333a68e0e765b21d17 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 23 Oct 2017 16:05:33 -0500 Subject: [PATCH 462/755] Resolve WB-750 Strange Oblique Volume Drawing: Default volume slice interpolation edge effects masking to LOOSE. --- src/Brain/VolumeSliceSettings.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Brain/VolumeSliceSettings.cxx b/src/Brain/VolumeSliceSettings.cxx index 27393af1e..5a5127b0b 100644 --- a/src/Brain/VolumeSliceSettings.cxx +++ b/src/Brain/VolumeSliceSettings.cxx @@ -40,6 +40,8 @@ using namespace caret; * \ingroup Brain */ +const static VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum defaultVolumeSliceInterpolationEdgeMaskType = + VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE; /** * Constructor. */ @@ -50,7 +52,7 @@ VolumeSliceSettings::VolumeSliceSettings() m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; - m_volumeSliceInterpolationEdgeEffectsMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT; + m_volumeSliceInterpolationEdgeEffectsMaskingType = defaultVolumeSliceInterpolationEdgeMaskType; m_montageNumberOfColumns = 6; // was 3; m_montageNumberOfRows = 4; @@ -834,7 +836,7 @@ VolumeSliceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, */ m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; - m_volumeSliceInterpolationEdgeEffectsMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT; + m_volumeSliceInterpolationEdgeEffectsMaskingType = defaultVolumeSliceInterpolationEdgeMaskType; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); -- GitLab From 34002bc8af48be2123cecd8ca43cbd2c5ac5c463 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 24 Oct 2017 16:39:31 -0500 Subject: [PATCH 463/755] Continued development of line drawings using rectangles but more to do so it is disabled at this time. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 33 +- src/Graphics/GraphicsOpenGLLineDrawing.cxx | 651 +++++++++++++----- src/Graphics/GraphicsOpenGLLineDrawing.h | 93 ++- 3 files changed, 571 insertions(+), 206 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index ceaaa33fe..ebb02dd9c 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1272,6 +1272,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil BrainOpenGLPrimitiveDrawing::drawRectangleOutline(bottomLeft, bottomRight, topRight, topLeft, outlineWidth, foregroundRGBA); + + /* + * For testing new line drawing + * Width not limited to OpenGL min/max + */ + const bool testLineDrawingFlag = false; + if (testLineDrawingFlag) { + float widthPixels = (box->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + GraphicsOpenGLLineDrawing::drawLineLoopSolidColor(coords, foregroundRGBA, widthPixels); + } } else { const float tempRGBA[4] = { 1.0, 1.0, 0.0, 1.0 }; @@ -2746,6 +2756,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi uint8_t foregroundRGBA[4]; line->getLineColorRGBA(foregroundRGBA); + float floatForegroundRGBA[4]; + line->getLineColorRGBA(floatForegroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); @@ -2772,29 +2784,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi /* * For testing new line drawing + * Width not limited to OpenGL min/max */ const bool testLineDrawingFlag = false; if (testLineDrawingFlag) { - std::unique_ptr primitive; - primitive.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES)); - const int32_t numXYZ = static_cast(coords.size() / 3); - const float rgba[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; - for (int32_t i = 0; i < numXYZ; i++) { - primitive->addVertex(&coords[i*3], rgba); - } - - /* - * Width not limited to OpenGL min/max - */ float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - - GraphicsOpenGLLineDrawing lineDraw(primitive.get(), - widthPixels); - AString errorMessage; - const bool successFlag = lineDraw.run(errorMessage); - if ( ! successFlag) { - //CaretLogSevere("Line Drawing: " + errorMessage); - } + GraphicsOpenGLLineDrawing::drawLinesSolidColor(coords, floatForegroundRGBA, widthPixels); } } } diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index ba50e1bcc..b13c94568 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -26,6 +26,7 @@ #undef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ #include "CaretAssert.h" +#include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "GraphicsPrimitive.h" #include "MathFunctions.h" @@ -46,124 +47,325 @@ using namespace caret; * two dimensional windows coordinates. */ +/** + * Destructor. + */ +GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() +{ +} + /** * Constructor. * - * @param primitive - * Line primitive converted to rectangles. + * @param xyz + * The XYZ vertices. + * @param rgba + * The RGBA coloring. + * @param lineThicknessPixels + * Thickness of lines in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + */ +GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +: m_inputPrimitive(NULL), +m_inputXYZ(xyz), +m_inputRGBA(rgba), +m_lineThicknessPixels(lineThicknessPixels), +m_colorType(colorType), +m_lineType(lineType) +{ + +} + + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0.0, 1.0] * @param lineThicknessPixels * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. */ -GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, - const float lineThicknessPixels) -: CaretObject(), -m_inputPrimitive(primitive), -m_lineThicknessPixels(lineThicknessPixels) +bool +GraphicsOpenGLLineDrawing::drawLinesSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels) { + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + return drawLinesPrivate(xyz, + rgbaVector, + lineThicknessPixels, + ColorType::RGBA_SOLID, + LineType::LINES); + +// const int32_t numPoints = static_cast(xyz.size() / 3); +// if (numPoints < 2) { +// CaretLogWarning("Invalid number of points=" +// + AString::number(numPoints) +// + " for line drawing. Must be at least 2."); +// return false; +// } +// +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// +// GraphicsOpenGLLineDrawing lineDrawing(xyz, +// rgbaVector, +// lineThicknessPixels, +// ColorType::RGBA_SOLID, +// LineType::LINES); +// lineDrawing.performDrawing(); +// +// return true; } /** - * Destructor. + * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). + * + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0.0, 1.0] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. */ -GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() +bool +GraphicsOpenGLLineDrawing::drawLineStripSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels) +{ + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + + return drawLinesPrivate(xyz, + rgbaVector, + lineThicknessPixels, + ColorType::RGBA_SOLID, + LineType::LINE_STRIP); + +} + +/** + * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). + * + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0.0, 1.0] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLineLoopSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels) +{ + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + + return drawLinesPrivate(xyz, + rgbaVector, + lineThicknessPixels, + ColorType::RGBA_SOLID, + LineType::LINE_LOOP); + +} + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0.0, 1.0] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLinesPrivate(const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) { + GraphicsOpenGLLineDrawing lineDrawing(xyz, + rgba, + lineThicknessPixels, + colorType, + lineType); + return lineDrawing.performDrawing(); } /** - * Run to convert the lines to rectangles. - * - * @param errorMessageOut - * Upon exit contains error information. - * @return - * True if successful, otherwise false. + * Perform the line drawinhg. + * + * @return + * True if no errors, false if errors. */ bool -GraphicsOpenGLLineDrawing::run(AString& errorMessageOut) +GraphicsOpenGLLineDrawing::performDrawing() { + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + CaretLogWarning("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return false; + } + + const int32_t numRGBA = static_cast(m_inputRGBA.size()); + switch (m_colorType) { + case ColorType::RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::RGBA_SOLID: + if (numRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numRGBA)); + return false; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + convertLineSegmentsToQuads(); + + drawQuads(); + + restoreOpenGLState(); + + return true; +} + +/** + * Save the OpenGL State. + */ +void +GraphicsOpenGLLineDrawing::saveOpenGLState() +{ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT + | GL_HINT_BIT + | GL_LIGHTING_BIT + | GL_POLYGON_BIT); + /* - * Save OpenGL state + * For anti-aliasing requires sorting polygons + * and turning of depth testing */ - glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT); + const bool drawWithAntiAliasingFlag = false; + if (drawWithAntiAliasingFlag) { + glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); + glEnable(GL_BLEND); + glHint(GL_POLYGON_SMOOTH_HINT, + GL_NICEST); + glEnable(GL_POLYGON_SMOOTH); + } + glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); - GLint savedPolygonMode[2]; // front and back - glGetIntegerv(GL_POLYGON_MODE, savedPolygonMode); + glGetIntegerv(GL_POLYGON_MODE, + m_savedPolygonMode); - GLint savedViewport[4]; glGetIntegerv(GL_VIEWPORT, - savedViewport); + m_savedViewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); - - errorMessageOut.clear(); - - convertPointsToWindowCoordinates(); - - convertLineSegmentsToQuads(); - - drawQuads(); +} - /* - * Restore OpenGL state - */ - glPolygonMode(GL_FRONT, savedPolygonMode[0]); - glPolygonMode(GL_BACK, savedPolygonMode[1]); +/** + * Restore the OpenGL State. + */ +void +GraphicsOpenGLLineDrawing::restoreOpenGLState() +{ + glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); + glPolygonMode(GL_BACK, m_savedPolygonMode[1]); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); - glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); + glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); glPopAttrib(); - - return false; } /** - * Convert the points from model to window coordinates + * Create the projection matrix. */ void -GraphicsOpenGLLineDrawing::convertPointsToWindowCoordinates() +GraphicsOpenGLLineDrawing::createProjectionMatrix() { - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - if (m_debugFlag) std::cout << "Depth Range: " << depthRange[0] << ", " << depthRange[1] << std::endl; - -// { -// glDepthRange(-5.0, 5.0); -// GLfloat depthRangeTest[2]; -// glGetFloatv(GL_DEPTH_RANGE, depthRangeTest); -// std::cout << "Setting depth range to -5,5 opengl uses " << depthRangeTest[0] << " " << depthRangeTest[1] << std::endl; -// } -// - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, - projectionArray); - Matrix4x4 projectionMatrix; - projectionMatrix.setMatrixFromOpenGL(projectionArray); - GLdouble modelviewArray[16]; glGetDoublev(GL_MODELVIEW_MATRIX, - modelviewArray); + modelviewArray); Matrix4x4 modelviewMatrix; modelviewMatrix.setMatrixFromOpenGL(modelviewArray); + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, + projectionArray); + + m_projectionMatrix.setMatrixFromOpenGL(projectionArray); + m_projectionMatrix.postmultiply(modelviewMatrix); +} + + +/** + * Create window coordinates from the input vertices. + */ +void +GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() +{ + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - Matrix4x4 projectionTimesModelMatrix(projectionMatrix); - projectionTimesModelMatrix.postmultiply(modelviewMatrix); - - const std::vector& xyz = m_inputPrimitive->getFloatXYZ(); + const int32_t numPoints = static_cast(m_inputXYZ.size() / 3); + m_vertexWindowXYZ.reserve(numPoints * 3); - m_windowLineSegmentsXYZ.reserve(xyz.size()); - - const int32_t numPoints = static_cast(xyz.size() / 3); for (int32_t i = 0; i < numPoints; i++) { const int32_t i3 = i * 3; @@ -171,133 +373,217 @@ GraphicsOpenGLLineDrawing::convertPointsToWindowCoordinates() * Convert model coordinate to a window coordinate * as described by the documentation from gluProject(). */ - float xyzw[4] = { xyz[i3], xyz[i3+1], xyz[i3+2], 1.0f }; - projectionTimesModelMatrix.multiplyPoint4(xyzw); - const float windowX = viewport[0] + (viewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); - const float windowY = viewport[1] + (viewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); - float windowZ = (xyzw[2] + 1.0f) / 2.0f; + float windowXYZ[3]; + convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); - /* - * From OpenGL Programming Guide 3rd Ed, p 133: - * - * If the near value is 1.0 and the far value is 3.0, - * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. - * So, negate the Z-value to be negative. - */ - windowZ = -windowZ; +// if (m_debugFlag) { +// GLdouble winX, winY, winZ; +// gluProject(xyz[i3], xyz[i3+1], xyz[i3+2], +// modelviewArray, projectionArray, viewport, +// &winX, &winY, &winZ); +// std::cout << "Input: " << xyz[i3] << ", " << xyz[i3+1] << ", " << xyz[i3+2] << std::endl; +// std::cout << " Pt " << i << ": " +// << windowX << ", " << windowY << ", " << windowZ << " w=" << xyzw[3] << std::endl; +// std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; +// } + } + + CaretAssert(m_inputXYZ.size() == m_vertexWindowXYZ.size()); +} - m_windowLineSegmentsXYZ.push_back(windowX); - m_windowLineSegmentsXYZ.push_back(windowY); - m_windowLineSegmentsXYZ.push_back(windowZ); - - if (m_debugFlag) { - GLdouble winX, winY, winZ; - gluProject(xyz[i3], xyz[i3+1], xyz[i3+2], - modelviewArray, projectionArray, viewport, - &winX, &winY, &winZ); - std::cout << "Input: " << xyz[i3] << ", " << xyz[i3+1] << ", " << xyz[i3+2] << std::endl; - std::cout << " Pt " << i << ": " - << windowX << ", " << windowY << ", " << windowZ << " w=" << xyzw[3] << std::endl; - std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; +/** + * Convert from a model coordinate to a window coordinate. + * + * @param modelXYZ + * The coordinate in model space. + * @param windowXYZOut + * Output with coordinate in window space. + */ +void +GraphicsOpenGLLineDrawing::convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const +{ + float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; + m_projectionMatrix.multiplyPoint4(xyzw); + windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); + windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); + windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; + + /* + * From OpenGL Programming Guide 3rd Ed, p 133: + * + * If the near value is 1.0 and the far value is 3.0, + * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. + * So, negate the Z-value to be negative. + */ + windowXYZOut[2] = -windowXYZOut[2]; +} + +/** + * Create a quad from the two window vertices + * + * @param indexOne + * Index of first vertex. + * @param indexTwo + * Index of second vertex. + */ +void +GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, + const int32_t indexTwo) +{ + const int32_t iOne3 = indexOne * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); + const int32_t iTwo3 = indexTwo * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); + float x1 = m_vertexWindowXYZ[iOne3]; + float y1 = m_vertexWindowXYZ[iOne3 + 1]; + float z1 = m_vertexWindowXYZ[iOne3 + 2]; + float x2 = m_vertexWindowXYZ[iTwo3]; + float y2 = m_vertexWindowXYZ[iTwo3 + 1]; + float z2 = m_vertexWindowXYZ[iTwo3 + 2]; + + /* + * Vector from start to end on line segment in 2D coordinates + */ + float startToEndVector[3] = { + x2 - x1, + y2 - y1, + 0.0f + }; + + /* + * Create a perpendicualar vector to the line segment + */ + MathFunctions::normalizeVector(startToEndVector); + float perpendicularVector[3] = { + startToEndVector[1], + -startToEndVector[0], + 0.0f + }; + + /* + * "Width" of rectangle + */ + const float halfWidth = m_lineThicknessPixels / 2.0f; + const float halfWidthX = perpendicularVector[0] * halfWidth; + const float halfWidthY = perpendicularVector[1] * halfWidth; + + /* + * Points of the rectangle + */ + float p1[3] = { + x1 - halfWidthX, + y1 - halfWidthY, + z1 + }; + float p2[3] = { + x1 + halfWidthX, + y1 + halfWidthY, + z1 + }; + float p3[3] = { + x2 + halfWidthX, + y2 + halfWidthY, + z2 + }; + float p4[3] = { + x2 - halfWidthX, + y2 - halfWidthY, + z2 + }; + + float crossProduct[3]; + MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); + if (crossProduct[2] < 0.0) { + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); + m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); + } + + switch (m_colorType) { + case ColorType::RGBA_PER_VERTEX: + { + CaretAssertVectorIndex(m_inputRGBA, indexOne * 4 * 3); + const float* rgbaOneOffset = &m_inputRGBA[indexOne * 4]; + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); + + CaretAssertVectorIndex(m_inputRGBA, indexTwo * 4 * 3); + const float* rgbaTwoOffset = &m_inputRGBA[indexTwo * 4]; + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaTwoOffset, rgbaTwoOffset + 4); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); } + break; + case ColorType::RGBA_SOLID: + CaretAssertVectorIndex(m_inputRGBA, 3); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); + m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); + break; } } + /** * Convert each line segment into a rectangle - * using the line width. "Length" of the + * using the line width. "Length" of the * rectangle is the length of the line segment * and "width" of the rectangle is the line width. */ void GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() { - const int32_t numPoints = static_cast(m_windowLineSegmentsXYZ.size() / 3); - m_windowQuadsXYZ.reserve(numPoints * 6); // 2 points in line to 4 points in quad + const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); + m_windowQuadsXYZ.reserve(numVertices * 6); // 2 points in line to 4 points in quad - const int32_t numPointsMinusOne = static_cast((m_windowLineSegmentsXYZ.size() / 3) - 1); - for (int32_t i = 0; i < numPointsMinusOne; i++) { - const int32_t i3 = i * 3; - - float x1 = m_windowLineSegmentsXYZ[i3]; - float y1 = m_windowLineSegmentsXYZ[i3 + 1]; - float z1 = m_windowLineSegmentsXYZ[i3 + 2]; - float x2 = m_windowLineSegmentsXYZ[i3 + 3]; - float y2 = m_windowLineSegmentsXYZ[i3 + 4]; - float z2 = m_windowLineSegmentsXYZ[i3 + 5]; - - /* - * Vector from start to end on line segment in 2D coordinates - */ - float startToEndVector[3] = { - x2 - x1, - y2 - y1, - 0.0f - }; - - /* - * Create a perpendicualar vector to the line segment - */ - MathFunctions::normalizeVector(startToEndVector); - float perpendicularVector[3] = { - startToEndVector[1], - -startToEndVector[0], - 0.0f - }; - - /* - * "Width" of rectangle - */ - const float halfWidth = m_lineThicknessPixels / 2.0f; - const float halfWidthX = perpendicularVector[0] * halfWidth; - const float halfWidthY = perpendicularVector[1] * halfWidth; - - /* - * Points of the rectangle - */ - float p1[3] = { - x1 - halfWidthX, - y1 - halfWidthY, - z1 - }; - float p2[3] = { - x1 + halfWidthX, - y1 + halfWidthY, - z1 - }; - float p3[3] = { - x2 + halfWidthX, - y2 + halfWidthY, - z2 - }; - float p4[3] = { - x2 - halfWidthX, - y2 - halfWidthY, - z2 - }; - - float crossProduct[3]; - MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); - if (crossProduct[2] < 0.0) { - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); + const int32_t numVerticesMinusOne = numVertices - 1; + + switch (m_lineType) { + case LineType::LINES: + { + const int32_t numLineSegments = (numVertices / 2); + for (int32_t i = 0; i < numLineSegments; i++) { + const int32_t i2 = i * 2; + createQuadFromWindowVertices(i2, i2 + 1); + } } + break; + case LineType::LINE_LOOP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + createQuadFromWindowVertices(i, i + 1); + } + createQuadFromWindowVertices(numVerticesMinusOne, 0); + break; + case LineType::LINE_STRIP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + createQuadFromWindowVertices(i, i + 1); + } + break; } - } +/** + * Draw the lines using quads. + */ void GraphicsOpenGLLineDrawing::drawQuads() { + const int32_t numVertices = static_cast(m_windowQuadsXYZ.size() / 3); + const int32_t numRGBA = static_cast(m_windowQuadsRGBA.size() / 4); + CaretAssert(numVertices == numRGBA); + GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); @@ -315,15 +601,22 @@ GraphicsOpenGLLineDrawing::drawQuads() glLoadIdentity(); glPolygonMode(GL_FRONT, GL_FILL); - glPolygonMode(GL_BACK, GL_LINE); - glColor3f(0.0, 1.0, 0.0); - glLineWidth(1.0); - glBegin(GL_QUADS); //GL_QUADS) - for (int32_t j = 0; j < 4; j++) { - glNormal3f(0.0, 0.0, -1.0); - glVertex3fv(&m_windowQuadsXYZ[j*3]); + //glPolygonMode(GL_BACK, GL_LINE); + + switch (m_colorType) { + case ColorType::RGBA_PER_VERTEX: + break; + case ColorType::RGBA_SOLID: + glBegin(GL_QUADS); //GL_QUADS) + for (int32_t j = 0; j < numVertices; j++) { + CaretAssertVectorIndex(m_windowQuadsRGBA, j*4 + 3); + glColor4fv(&m_windowQuadsRGBA[j*4]); + CaretAssertVectorIndex(m_windowQuadsXYZ, j*3 + 2); + glVertex3fv(&m_windowQuadsXYZ[j*3]); + } + glEnd(); + break; } - glEnd(); if (m_debugFlag) { std::cout << std::endl << "QUADS: " << AString::fromNumbers(m_windowQuadsXYZ, ",") << std::endl; diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index 9c67e1abe..75ba9964f 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -26,8 +26,7 @@ #include #include "CaretObject.h" - - +#include "Matrix4x4.h" namespace caret { @@ -36,40 +35,118 @@ namespace caret { class GraphicsOpenGLLineDrawing : public CaretObject { public: - GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, - const float lineThicknessPixels); +// GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, +// const float lineThicknessPixels); virtual ~GraphicsOpenGLLineDrawing(); - bool run(AString& errorMessageOut); + //bool run(AString& errorMessageOut); + static bool drawLinesSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidColor(const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + // ADD_NEW_METHODS_HERE virtual AString toString() const; private: + /** + * Type of line coloring + */ + enum class ColorType { + /** color at each vertex */ + RGBA_PER_VERTEX, + /** one color for all vertices */ + RGBA_SOLID + }; + + /** + * Type of line drawing + */ + enum class LineType { + /** Each pair of vertices is an independent line segment (GL_LINES) */ + LINES, + /** A connected set of lines forming a loop (last is automaticall connected to first) */ + LINE_LOOP, + /** A connected set of lines (last is not connected to first) */ + LINE_STRIP + }; + + GraphicsOpenGLLineDrawing(const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + GraphicsOpenGLLineDrawing(const GraphicsOpenGLLineDrawing& obj); - GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj); + GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj) const; + + static bool drawLinesPrivate(const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + + bool performDrawing(); + + void saveOpenGLState(); + + void restoreOpenGLState(); - void convertPointsToWindowCoordinates(); + void createProjectionMatrix(); + + void convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const; + + //void convertPointsToWindowCoordinates(); + + void createWindowCoordinatesFromVertices(); void convertLineSegmentsToQuads(); + void createQuadFromWindowVertices(const int32_t indexOne, + const int32_t indexTwo); + void drawQuads(); const GraphicsPrimitive* m_inputPrimitive; + const std::vector& m_inputXYZ; + + const std::vector& m_inputRGBA; + const float m_lineThicknessPixels; + const ColorType m_colorType; + + const LineType m_lineType; + GraphicsPrimitive* m_outputPrimitive = NULL; - std::vector m_windowLineSegmentsXYZ; + std::vector m_vertexWindowXYZ; std::vector m_windowQuadsXYZ; + std::vector m_windowQuadsRGBA; + bool m_debugFlag = false; + int m_savedPolygonMode[2]; + + int m_savedViewport[4]; + + Matrix4x4 m_projectionMatrix; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From f67d950c40a70560f4d37f37f28439a816cb751a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 25 Oct 2017 12:04:16 -0500 Subject: [PATCH 464/755] Resolve WB-738 After upload to BALSA, Workbench requests Scene IDs and saves in Scene File: Changed update of Scene IDs so that the Scene IDs are updated prior to zipping the scene file. After upload, update scenes listed in Scene File Dialog so that the displayed Scene IDs are updated. --- src/GuiQt/BalsaDatabaseManager.cxx | 233 +++++++++++++++--- src/GuiQt/BalsaDatabaseManager.h | 8 + .../BalsaDatabaseUploadSceneFileDialog.cxx | 129 +++++++--- .../BalsaDatabaseUploadSceneFileDialog.h | 5 +- src/GuiQt/BalsaUserRoles.cxx | 17 ++ src/GuiQt/BalsaUserRoles.h | 2 + src/GuiQt/SceneDialog.cxx | 8 +- 7 files changed, 323 insertions(+), 79 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index ff6a92f4a..2b1a6fa21 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -538,6 +538,8 @@ BalsaDatabaseManager::receiveEvent(Event* /*event*/) * URL for uploading file. * @param httpContentTypeName * Type of content for upload (eg: application/zip, see http://www.freeformatter.com/mime-types-list.html) + * @param updateSceneIDsFromResponseFlag + * If true, update the Scene IDs using those in the response content. * @param errorMessageOut * Contains error information if upload failed. * @return @@ -546,8 +548,9 @@ BalsaDatabaseManager::receiveEvent(Event* /*event*/) bool BalsaDatabaseManager::processUploadedFile(SceneFile* sceneFile, const AString& processUploadURL, - const AString& httpContentTypeName, - AString& errorMessageOut) + const AString& httpContentTypeName, + const bool updateSceneIDsFromResponseFlag, + AString& errorMessageOut) { errorMessageOut.clear(); @@ -582,43 +585,48 @@ BalsaDatabaseManager::processUploadedFile(SceneFile* sceneFile, return false; } - for (std::map::iterator mapIter = uploadResponse.m_headers.begin(); - mapIter != uploadResponse.m_headers.end(); - mapIter++) { + /* + * As of 24 Oct 2017, Scene IDs are updated prior to uploading scene fiel + */ + if (updateSceneIDsFromResponseFlag) { + for (std::map::iterator mapIter = uploadResponse.m_headers.begin(); + mapIter != uploadResponse.m_headers.end(); + mapIter++) { + if (m_debugFlag) { + std::cout << " Process Upload Response Header: " << qPrintable(mapIter->first) + << " -> " << qPrintable(mapIter->second) << std::endl; + } + } + + uploadResponse.m_body.push_back('\0'); + AString responseContent(&uploadResponse.m_body[0]); if (m_debugFlag) { - std::cout << " Process Upload Response Header: " << qPrintable(mapIter->first) - << " -> " << qPrintable(mapIter->second) << std::endl; + std::cout << "Process Upload to BALSA reply body: " << responseContent << std::endl; + } + else { + CaretLogFine("Process Upload to BALSA reply body: " + + responseContent); + } + + + AString contentType = getHeaderValue(uploadResponse, "Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Process Upload Content type returned by BALSA is unknown"); + return false; + } + + if ( ! contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Process Upload Content type return by BALSA should be JSON format but is " + + contentType + + "Scene File was uploaded but Scene IDs will not be updated"); + return false; + } + + if ( ! updateSceneIdsFromProcessUploadResponse(sceneFile, + responseContent, + errorMessageOut)) { + return false; } - } - - uploadResponse.m_body.push_back('\0'); - AString responseContent(&uploadResponse.m_body[0]); - if (m_debugFlag) { - std::cout << "Process Upload to BALSA reply body: " << responseContent << std::endl; - } - else { - CaretLogFine("Process Upload to BALSA reply body: " - + responseContent); - } - - - AString contentType = getHeaderValue(uploadResponse, "Content-Type"); - if (contentType.isNull()) { - errorMessageOut = ("Process Upload Content type returned by BALSA is unknown"); - return false; - } - - if ( ! contentType.toLower().startsWith("application/json")) { - errorMessageOut = ("Process Upload Content type return by BALSA should be JSON format but is " - + contentType - + "Scene File was uploaded but Scene IDs will not be updated"); - return false; - } - - if ( ! updateSceneIdsFromProcessUploadResponse(sceneFile, - responseContent, - errorMessageOut)) { - return false; } return true; @@ -732,6 +740,156 @@ BalsaDatabaseManager::getHeaderValue(const CaretHttpResponse& httpResponse, return value; } +/** + * Add Scene IDs to scenes in the given scene file that are missing Scene IDs + * + * @param sceneFile + * The scene file. + * @param errorMessageOut + * Output with error message + * @return + * True if success, else false. + */ +bool +BalsaDatabaseManager::updateSceneIDs(SceneFile* sceneFile, + AString& errorMessageOut) +{ + CaretAssert(sceneFile); + + std::vector scenesMissingID; + + const int32_t numScenes = sceneFile->getNumberOfScenes(); + for (int32_t i = 0; i < numScenes; i++) { + Scene* scene = sceneFile->getSceneAtIndex(i); + CaretAssert(scene); + if (scene->getBalsaSceneID().trimmed().isEmpty()) { + scenesMissingID.push_back(scene); + } + } + + const int32_t numberOfIDs = static_cast(scenesMissingID.size()); + if (numberOfIDs > 0) { + std::vector sceneIDs; + if ( ! getSceneIDs(numberOfIDs, + sceneIDs, + errorMessageOut)) { + return false; + } + + CaretAssert(scenesMissingID.size() == sceneIDs.size()); + + for (int32_t i = 0; i < numberOfIDs; i++) { + scenesMissingID[i]->setBalsaSceneID(sceneIDs[i]); + } + } + + return true; +} + + +/** + * Request the given number of scene IDs + * + * @param numberOfSceneIDs + * Number of scene IDs requested + * @param sceneIDsOut + * Output with requested number of Scene IDs + * @param errorMessageOut + * Output with error message + * @return + * True if success, else false. + */ +bool +BalsaDatabaseManager::getSceneIDs(const int32_t numberOfSceneIDs, + std::vector& sceneIDsOut, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + sceneIDsOut.clear(); + + if (numberOfSceneIDs <= 0) { + errorMessageOut = "Zero or fewer Study IDs requested"; + return false; + } + + const AString studyIdURL(m_databaseURL + + "/scene/newIds/" + + AString::number(numberOfSceneIDs)); + + errorMessageOut.clear(); + + CaretHttpRequest caretRequest; + caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; + caretRequest.m_url = studyIdURL; + caretRequest.m_headers.insert(std::make_pair("Content-Type", + "application/x-www-form-urlencoded")); + caretRequest.m_headers.insert(std::make_pair("Cookie", + getJSessionIdCookie())); + caretRequest.m_arguments.push_back(std::make_pair("type", + "json")); + + CaretHttpResponse response; + CaretHttpManager::httpRequest(caretRequest, response); + + if (m_debugFlag) { + std::cout << "Request Scene IDs response Code: " << response.m_responseCode << std::endl; + } + + if (response.m_responseCode != 200) { + errorMessageOut = ("Requesting Scene IDs failed with HTTP code=" + + AString::number(response.m_responseCode) + + ". This error may be caused by failure to agree to data use terms."); + return false; + } + + response.m_body.push_back('\0'); + AString responseContent(&response.m_body[0]); + + if (m_debugFlag) { + std::cout << "Request Scene IDs body:\n" << responseContent << std::endl << std::endl; + } + + AString contentType = getHeaderValue(response, "Content-Type"); + if (contentType.isNull()) { + errorMessageOut = ("Requesting Scene IDs failed. Content type returned by BALSA is unknown"); + return false; + } + + if (contentType.toLower().startsWith("text/html")) { + /* + * Response from BALSA has Scene IDs separated by '
' + * Example: vp5B
Z02A
+ */ + QStringList sl = responseContent.split("
", + QString::SkipEmptyParts, + Qt::CaseInsensitive); + const int32_t receivedCount = sl.count(); + if (receivedCount != numberOfSceneIDs) { + errorMessageOut = ("Requested " + + AString::number(numberOfSceneIDs) + + " but received " + + receivedCount + + " IDs"); + return false; + } + for (int32_t i = 0; i < receivedCount; i++) { + sceneIDsOut.push_back(sl.at(i)); + } + } + else if (contentType.toLower().startsWith("application/json")) { + errorMessageOut = ("Requesting Scene IDS failed. Content type returned by BALSA is JSON but support for JSON has not been implemented in Workbench"); + return false; + } + else { + errorMessageOut = ("Requesting Scene IDS failed. Content type returned by BALSA should be either text/html or JSON format but is " + + contentType); + return false; + } + + return true; +} + + /** * Get the study ID from a study Title * @@ -1214,6 +1372,7 @@ BalsaDatabaseManager::uploadZippedSceneFile(SceneFile* sceneFile, const bool processUploadSuccessFlag = processUploadedFile(sceneFile, processUploadURL, "application/x-www-form-urlencoded", + false, // do not look for Scene IDs in response content errorMessageOut); if (m_debugFlag) std::cout << "Result of processing the uploaded ZIP file" << AString::fromBool(processUploadSuccessFlag) << std::endl; diff --git a/src/GuiQt/BalsaDatabaseManager.h b/src/GuiQt/BalsaDatabaseManager.h index b590012f2..fd9a10cb4 100644 --- a/src/GuiQt/BalsaDatabaseManager.h +++ b/src/GuiQt/BalsaDatabaseManager.h @@ -59,6 +59,13 @@ namespace caret { AString& studyIdOut, AString& errorMessageOut); + bool getSceneIDs(const int32_t numberOfSceneIDs, + std::vector& sceneIDsOut, + AString& errorMessageOut); + + bool updateSceneIDs(SceneFile* sceneFile, + AString& errorMessageOut); + bool uploadZippedSceneFile(SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, @@ -109,6 +116,7 @@ namespace caret { bool processUploadedFile(SceneFile* sceneFile, const AString& processUploadURL, const AString& httpContentTypeName, + const bool updateSceneIDsFromResponseFlag, AString& errorMessageOut); bool requestStudyID(const AString& databaseURL, diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 9733d67c6..a859af4ab 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -107,6 +107,7 @@ m_sceneFile(sceneFile) setCancelButtonText("Close"); m_basePathWidget->updateWithSceneFile(m_sceneFile); + updateUserRolesLabel(); } /** @@ -223,35 +224,43 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() QObject::connect(m_loginPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::loginButtonClicked); + /* + * Label for User Roles + */ + m_userRolesLabel = new QLabel(" "); + int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; - const int COLUMN_DATA_WIDGET = columnCounter++; + const int COLUMN_DATA_WIDGET_ONE = columnCounter++; + const int COLUMN_DATA_WIDGET_TWO = columnCounter++; const int COLUMN_BUTTON_ONE = columnCounter++; - const int COLUMN_BUTTON_TWO = columnCounter++; + //const int COLUMN_BUTTON_TWO = columnCounter++; QGroupBox* groupBox = new QGroupBox("Database Login"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(5); gridLayout->setColumnStretch(COLUMN_LABEL, 0); - gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); + gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_ONE, 0); + gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_TWO, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); - gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); + //gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE, 1, 2); + gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET_ONE, 1, 2); + gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE); row++; gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE, 1, 2); + gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); + gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE); row++; gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE, 1, 2); + gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); + gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_ONE); row++; gridLayout->setRowMinimumHeight(row, 10); // empty row row++; - gridLayout->addWidget(m_loginPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignLeft); + gridLayout->addWidget(m_loginPushButton, row, COLUMN_DATA_WIDGET_ONE); + gridLayout->addWidget(m_userRolesLabel, row, COLUMN_DATA_WIDGET_TWO, 1, Qt::AlignLeft); return groupBox; } @@ -335,13 +344,13 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); /* - * Roles button + * Test button */ - QPushButton* rolesPushButton = new QPushButton("Test Roles..."); - rolesPushButton->setToolTip("Test getting the user's roles"); - QObject::connect(rolesPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked); - rolesPushButton->setVisible(false); + QPushButton* testPushButton = new QPushButton("Test..."); + testPushButton->setToolTip("Test some functionality"); + QObject::connect(testPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::testButtonClicked); + testPushButton->setVisible(false); /* * Auto-save checkbox @@ -382,7 +391,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); - gridLayout->addWidget(rolesPushButton, row, COLUMN_BUTTON_ONE, 1, 2); + gridLayout->addWidget(testPushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; gridLayout->addWidget(m_autoSaveSceneFileCheckBox, row, COLUMN_DATA_WIDGET, 1, 3, Qt::AlignLeft); row++; @@ -544,6 +553,8 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() m_uploadPushButton->setEnabled(false); m_selectStudyTitlePushButton->setEnabled(false); + m_userRoles->resetToAllInvalid(); + updateUserRolesLabel(); CursorDisplayScoped cursor; cursor.showWaitCursor(); @@ -583,6 +594,8 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() } } else { + m_userRoles->resetToAllInvalid(); + cursor.restoreCursor(); const AString msg("Unable to verify that you have agreed to the BALSA " "Submission Terms and Conditions. If you have not " @@ -591,12 +604,33 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() WuQMessageBox::warningOk(this, msg); } + updateUserRolesLabel(); + m_uploadPushButton->setEnabled(true); m_selectStudyTitlePushButton->setEnabled(true); } /** - * Gets called when return is pressed in either username + * Update roles label with user's valid roles + */ +void +BalsaDatabaseUploadSceneFileDialog::updateUserRolesLabel() +{ + m_userRolesLabel->setText(""); + + const bool showRolesFlag = false; + if (showRolesFlag) { + const AString rolesText = m_userRoles->getRolesForDisplayInGUI(); + if ( ! rolesText.isEmpty()) { + m_userRolesLabel->setText(" BALSA Roles: " + + rolesText); + } + } +} + + +/** + * Gets called when return is pressed in either username * or password. If both contain text, try to login. */ void @@ -696,7 +730,22 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); - if ( ! saveSceneFile("")) { + AString saveMessage("The scene file is modified and must be saved before continuing."); + AString errorMessage; + bool sceneFileModStatus = m_sceneFile->isModified(); + if (m_balsaDatabaseManager->updateSceneIDs(m_sceneFile, + errorMessage)) { + if ( ! sceneFileModStatus) { + if (m_sceneFile->isModified()) { + saveMessage = "The scene file was modified to add BALSA Scene Identifiers and must be saved before continuing."; + } + } + } + else { + return; + } + + if ( ! saveSceneFile(saveMessage)) { return; } @@ -709,21 +758,13 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() progressDialog.setCancelButton((QPushButton*)0); // no cancel button - AString errorMessage; const bool successFlag = m_balsaDatabaseManager->uploadZippedSceneFile(m_sceneFile, zipFileName, extractToDirectoryName, errorMessage); - + cursor.restoreCursor(); - /* - * Scene file may be modified with updated Scene IDs from BALSA. - * Allow user to save, but do not require saving - */ - saveSceneFile("Scene IDs were updated by BALSA during upload. Would you like " - "to save the scene file using its current name?"); - progressDialog.setValue(progressDialog.maximum()); if (successFlag) { @@ -753,12 +794,8 @@ BalsaDatabaseUploadSceneFileDialog::saveSceneFile(const AString& saveMessage) { if (m_sceneFile->isModified()) { if ( ! m_autoSaveSceneFileCheckBox->isChecked()) { - QString msg("The scene file is modified and must be saved before continuing. Would you like " - "to save the scene file using its current name and continue?"); - if ( ! saveMessage.isEmpty()) { - msg = saveMessage; - } - + AString msg(saveMessage + + " Would you like to save the scene file using its current name and continue?"); if ( ! WuQMessageBox::warningOkCancel(this, msg)) { return false; } @@ -790,8 +827,11 @@ BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked(bool /*checked*/) } void -BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked() +BalsaDatabaseUploadSceneFileDialog::testButtonClicked() { + bool testRolesFlag = false; + bool testNewIDsFlag = true; + if (testRolesFlag) { const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); @@ -807,6 +847,23 @@ BalsaDatabaseUploadSceneFileDialog::rolesButtonClicked() } std::cout << "*** Role Names: " << balsaUserRoles.toString() << std::endl; + } + + if (testNewIDsFlag) { + int32_t numberOfSceneIDs = 2; + std::vector sceneIDs; + AString errorMessage; + if ( ! m_balsaDatabaseManager->getSceneIDs(numberOfSceneIDs, + sceneIDs, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + return; + } + for (auto id : sceneIDs) { + std::cout << "Scene ID " << id << std::endl; + } + } } /** diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 2706b82b8..c401c2631 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -74,7 +74,7 @@ namespace caret { void browseZipFileCustomDirectoryPushButtonClicked(); - void rolesButtonClicked(); + void testButtonClicked(); void autoSaveCheckBoxClicked(bool checked); @@ -118,6 +118,8 @@ namespace caret { bool saveSceneFile(const AString& saveMesage); + void updateUserRolesLabel(); + SceneFile* m_sceneFile; std::unique_ptr m_balsaDatabaseManager; @@ -134,6 +136,7 @@ namespace caret { QLineEdit* m_passwordLineEdit; QPushButton* m_loginPushButton; + QLabel* m_userRolesLabel; std::unique_ptr m_userRoles; diff --git a/src/GuiQt/BalsaUserRoles.cxx b/src/GuiQt/BalsaUserRoles.cxx index e400a4dfc..1119015c6 100644 --- a/src/GuiQt/BalsaUserRoles.cxx +++ b/src/GuiQt/BalsaUserRoles.cxx @@ -218,6 +218,23 @@ BalsaUserRoles::isValid() const return m_validFlag; } +/** + * @return Roles formatted for display in GUI. + */ +AString +BalsaUserRoles::getRolesForDisplayInGUI() const +{ + AString s; + + if (m_validFlag) { + if (m_adminFlag) s.append("Admin; "); + if (m_curatorFlag) s.append("Curator; "); + if (m_submitterFlag) s.append("Submitter; "); + if (m_userFlag) s.append("User; "); + } + + return s; +} /** * Get a description of this object's content. diff --git a/src/GuiQt/BalsaUserRoles.h b/src/GuiQt/BalsaUserRoles.h index 7ce63ea9e..701a013ae 100644 --- a/src/GuiQt/BalsaUserRoles.h +++ b/src/GuiQt/BalsaUserRoles.h @@ -59,6 +59,8 @@ namespace caret { // ADD_NEW_METHODS_HERE + AString getRolesForDisplayInGUI() const; + virtual AString toString() const; private: diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 9bc4928cc..b28fade28 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -982,16 +982,14 @@ SceneDialog::uploadSceneFileButtonClicked() } SceneFile* sceneFile = getSelectedSceneFile(); -// if (sceneFile->isModified()) { -// WuQMessageBox::errorOk(m_uploadSceneFilePushButton, -// "Selected Scene File is modified and must be saved prior to uploading."); -// return; -// } BalsaDatabaseUploadSceneFileDialog uploadDialog(sceneFile, this); uploadDialog.exec(); + /* Scene ID may have been added and it is shown in info section for each scene */ + loadScenesIntoDialog(NULL); + updateSceneFileModifiedStatusLabel(); } -- GitLab From 61197908a8db710bce5afb1db22e1c226d77b118 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 31 Oct 2017 21:43:00 -0500 Subject: [PATCH 465/755] belatedly remove "temporary" option for a worse cortex layer method --- src/Algorithms/AlgorithmSurfaceCortexLayer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Algorithms/AlgorithmSurfaceCortexLayer.cxx b/src/Algorithms/AlgorithmSurfaceCortexLayer.cxx index 71ad7612a..66142b175 100644 --- a/src/Algorithms/AlgorithmSurfaceCortexLayer.cxx +++ b/src/Algorithms/AlgorithmSurfaceCortexLayer.cxx @@ -55,7 +55,7 @@ OperationParameters* AlgorithmSurfaceCortexLayer::getParameters() OptionalParameter* metricOpt = ret->createOptionalParameter(5, "-placement-out", "output the placement as a distance fraction from pial to white"); metricOpt->addMetricOutputParameter(1, "placement-metric", "output metric"); - ret->createOptionalParameter(6, "-untwist", "temporary option for comparing methods, specify to use old method"); + //ret->createOptionalParameter(6, "-untwist", "temporary option for comparing methods, specify to use old method"); ret->setHelpText( AString("The input surfaces must have vertex correspondence. ") + @@ -78,7 +78,7 @@ void AlgorithmSurfaceCortexLayer::useParameters(OperationParameters* myParams, P { myMetricOut = metricOpt->getOutputMetric(1); } - bool untwistMode = myParams->getOptionalParameter(6)->m_present; + bool untwistMode = false;//myParams->getOptionalParameter(6)->m_present; AlgorithmSurfaceCortexLayer(myProgObj, myWhiteSurf, myPialSurf, myVolFrac, myOutSurf, myMetricOut, untwistMode); } -- GitLab From 49e06730cae969b92c131b0b25498c0d2643b088 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 1 Nov 2017 15:23:47 -0500 Subject: [PATCH 466/755] Fixed bug in oblique volume slice selection. When in oblique volume viewing, if the user entered a slice index and pressed enter, the slice changed by only one slice index. Logic that limited changing the oblique slice index by more than one has been removed. --- ...rainBrowserWindowToolBarSliceSelection.cxx | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 979a88b27..fb897c3df 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -588,45 +588,21 @@ BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoo switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { - float sx(1.0), sy(1.0), sz(1.0); - underlayVolumeFile->getVoxelSpacing(sx, sy, sz); - switch (viewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: - { - const int32_t diff = sliceIndex - btc->getSliceIndexAxial(underlayVolumeFile); - if (diff > 0) { - btc->setSliceCoordinateAxial(btc->getSliceCoordinateAxial() + sz); - } - else { - btc->setSliceCoordinateAxial(btc->getSliceCoordinateAxial() - sz); - } - } + btc->setSliceIndexAxial(underlayVolumeFile, + sliceIndex); break; case VolumeSliceViewPlaneEnum::CORONAL: - { - const int32_t diff = sliceIndex - btc->getSliceIndexCoronal(underlayVolumeFile); - if (diff > 0) { - btc->setSliceCoordinateCoronal(btc->getSliceCoordinateCoronal() + sy); - } - else { - btc->setSliceCoordinateCoronal(btc->getSliceCoordinateCoronal() - sy); - } - } + btc->setSliceIndexCoronal(underlayVolumeFile, + sliceIndex); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: - { - const int32_t diff = sliceIndex - btc->getSliceIndexParasagittal(underlayVolumeFile); - if (diff > 0) { - btc->setSliceCoordinateParasagittal(btc->getSliceCoordinateParasagittal() + sx); - } - else { - btc->setSliceCoordinateParasagittal(btc->getSliceCoordinateParasagittal() - sx); - } - } + btc->setSliceIndexParasagittal(underlayVolumeFile, + sliceIndex); break; } } -- GitLab From 7a0066d6b8188dc6fb7927b8fe973a3266840b17 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Nov 2017 11:38:35 -0600 Subject: [PATCH 467/755] Changed src/CMakeLists.txt to only look for GLEW on windows. --- src/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 326dc8374..bc3ef5849 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -275,10 +275,12 @@ ENDIF (OPENGL_FOUND) ########################################################################################## # -# Look for GLEW +# Look for GLEW but only on Windows # SET(GLEW_RESULT "No") -FIND_PACKAGE(GLEW) +IF (WIN32) + FIND_PACKAGE(GLEW) +ENDIF () IF (GLEW_FOUND) SET(GLEW_RESULT "${GLEW_INCLUDE_DIRS} ${GLEW_LIBRARIES}") -- GitLab From 997894e5d0f9446be4b329ca50188b42de7f2632 Mon Sep 17 00:00:00 2001 From: Kristian Loewe Date: Wed, 15 Nov 2017 04:34:22 +0100 Subject: [PATCH 468/755] Fix if statement in CMakeLists.txt (#24) In the following piece of code in CMakeLists.txt, testing for an empty string fails (using CMake 3.5.1): SET(DEBUG_VARIABLE_PREFIX "") IF(NOT (DEBUG_VARIABLE_PREFIX STREQUAL "")) getListOfVarsStartingWith(${DEBUG_VARIABLE_PREFIX} allVars) foreach( debugVar IN LISTS allVars ). message(${MSG_TYPE} ${MSG_INDENT} "${debugVar}=${${debugVar}}" ) endforeach() ENDIF() This leads to the following error when running cmake: CMake Error at CMakeLists.txt:549 (getListOfVarsStartingWith): getListOfVarsStartingWith Function invoked with incorrect arguments for function named: getListOfVarsStartingWith --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc3ef5849..82f67adf2 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -547,7 +547,7 @@ ENABLE_TESTING() # or to "OSMESA" to print all OSMESA variables. # SET(DEBUG_VARIABLE_PREFIX "") -IF(NOT (DEBUG_VARIABLE_PREFIX STREQUAL "")) +IF(NOT ("${DEBUG_VARIABLE_PREFIX}" STREQUAL "")) getListOfVarsStartingWith(${DEBUG_VARIABLE_PREFIX} allVars) foreach( debugVar IN LISTS allVars ) message(${MSG_TYPE} ${MSG_INDENT} "${debugVar}=${${debugVar}}" ) -- GitLab From 9d0985ea7bb9ce658c2e9e2227d7e472a6e7f038 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 14 Nov 2017 21:48:13 -0600 Subject: [PATCH 469/755] try using qt 5.6 on travis --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 18823adfe..f0b4e5769 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: cpp dist: trusty -sudo: false +sudo: required notifications: email: false @@ -9,11 +9,15 @@ cache: - apt - ccache +git: + depth: 3 + addons: apt: + sources: + - sourceline: ppa:beineri/opt-qt562-trusty packages: - - qt5-default - - libqt5opengl5-dev + - qt56base - zlib1g-dev - libosmesa6-dev - libssl-dev @@ -26,6 +30,7 @@ env: - OMP_NUM_THREADS=4 before_install: + - source /opt/qt56/bin/qt56-env.sh - mkdir ../build - cd ../build -- GitLab From db9d9fc5ade9161b131daddbcc3a9a4e97f2b0c1 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 14 Nov 2017 22:44:15 -0600 Subject: [PATCH 470/755] try qt 5.7 in travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f0b4e5769..3b28e01e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ git: addons: apt: sources: - - sourceline: ppa:beineri/opt-qt562-trusty + - sourceline: ppa:beineri/opt-qt571-trusty packages: - qt56base - zlib1g-dev @@ -30,7 +30,7 @@ env: - OMP_NUM_THREADS=4 before_install: - - source /opt/qt56/bin/qt56-env.sh + - source /opt/qt57/bin/qt57-env.sh - mkdir ../build - cd ../build -- GitLab From 114e846c7d5810079f811fef8e019aa00e55b3de Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 14 Nov 2017 22:57:27 -0600 Subject: [PATCH 471/755] another try at qt 5.7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3b28e01e6..5b3a0fea7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ addons: sources: - sourceline: ppa:beineri/opt-qt571-trusty packages: - - qt56base + - qt57base - zlib1g-dev - libosmesa6-dev - libssl-dev -- GitLab From c8c53cb47af2e3a0ccae24cef8f0efaa7f9dde21 Mon Sep 17 00:00:00 2001 From: Kristian Loewe Date: Thu, 16 Nov 2017 00:07:01 +0100 Subject: [PATCH 472/755] Add AVX-512-based dot product implementation to further speed up ... (#25) * Update cpuinfo module Update src/kloewe/cpuinfo to the current version (https://github.com/kloewe/mod-cpuinfo/commit/11700cc). This enables detection of the AVX-512 instruction set extensions. * Update dot module (AVX-512) Update src/kloewe/dot to the current version (https://github.com/kloewe/mod-dot/commit/584410c). This enables AVX-512-based dot product computation providing additional speedup compared to the AVX-based implementation (on processors that support AVX-512). Note that sddot() has been renamed to dsdot() for consistency with cblas function names. --- src/Algorithms/AlgorithmCiftiCorrelation.cxx | 4 +- .../AlgorithmCiftiCorrelationGradient.cxx | 2 +- .../AlgorithmCiftiCrossCorrelation.cxx | 4 +- src/Common/dot_wrapper.h | 34 +- ...iftiConnectivityMatrixDenseDynamicFile.cxx | 4 +- src/Tests/DotTest.cxx | 30 +- src/kloewe/cpuinfo/LICENSE | 2 +- src/kloewe/cpuinfo/src/cpuinfo.c | 323 ++++++++++++++---- src/kloewe/cpuinfo/src/cpuinfo.h | 18 +- src/kloewe/dot/CMakeLists.txt | 51 ++- src/kloewe/dot/LICENSE | 2 +- src/kloewe/dot/src/dot.c | 97 ++++-- src/kloewe/dot/src/dot.h | 108 +++--- src/kloewe/dot/src/dot_avx.c | 4 +- src/kloewe/dot/src/dot_avx.h | 75 +++- src/kloewe/dot/src/dot_avx512.c | 19 ++ src/kloewe/dot/src/dot_avx512.h | 124 +++++++ src/kloewe/dot/src/dot_avxfma.c | 6 + src/kloewe/dot/src/dot_naive.c | 2 +- src/kloewe/dot/src/dot_naive.h | 6 +- src/kloewe/dot/src/dot_sse2.c | 2 +- src/kloewe/dot/src/dot_sse2.h | 25 +- 22 files changed, 723 insertions(+), 219 deletions(-) create mode 100644 src/kloewe/dot/src/dot_avx512.c create mode 100644 src/kloewe/dot/src/dot_avx512.h create mode 100644 src/kloewe/dot/src/dot_avxfma.c diff --git a/src/Algorithms/AlgorithmCiftiCorrelation.cxx b/src/Algorithms/AlgorithmCiftiCorrelation.cxx index e1d880846..7f4c27e5b 100644 --- a/src/Algorithms/AlgorithmCiftiCorrelation.cxx +++ b/src/Algorithms/AlgorithmCiftiCorrelation.cxx @@ -527,7 +527,7 @@ float AlgorithmCiftiCorrelation::correlate(const float* row1, const float& rrs1, if (m_weightedMode) { int numWeights = (int)m_weightIndexes.size();//because we compacted the data in the row to not include any zero weights - double accum = sddot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied + double accum = dsdot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied if (m_covariance) { if (m_binaryWeights) @@ -540,7 +540,7 @@ float AlgorithmCiftiCorrelation::correlate(const float* row1, const float& rrs1, r = accum / (rrs1 * rrs2);//as do these } } else { - double accum = sddot(row1, row2, m_numCols);//these have already had the row means subtracted out + double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out if (m_covariance) { r = accum / m_numCols; diff --git a/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx b/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx index 9e471435f..ec0401d7f 100644 --- a/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx +++ b/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx @@ -895,7 +895,7 @@ float AlgorithmCiftiCorrelationGradient::correlate(const float* row1, const floa { r = 1.0;//short circuit for same row } else { - double accum = sddot(row1, row2, m_numCols);//these have already had the row means subtracted out + double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out if (m_covariance) { r = accum / m_numCols; diff --git a/src/Algorithms/AlgorithmCiftiCrossCorrelation.cxx b/src/Algorithms/AlgorithmCiftiCrossCorrelation.cxx index b03aeb0bf..a9a2dfb3c 100644 --- a/src/Algorithms/AlgorithmCiftiCrossCorrelation.cxx +++ b/src/Algorithms/AlgorithmCiftiCrossCorrelation.cxx @@ -248,10 +248,10 @@ float AlgorithmCiftiCrossCorrelation::correlate(const float* row1, const float& if (m_weightedMode) { int numWeights = (int)m_weightIndexes.size();//because we compacted the data in the row to not include any zero weights - double accum = sddot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied + double accum = dsdot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied r = accum / (rrs1 * rrs2);//as do these } else { - double accum = sddot(row1, row2, m_numCols);//these have already had the row means subtracted out + double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out r = accum / (rrs1 * rrs2); } if (fisherZ) diff --git a/src/Common/dot_wrapper.h b/src/Common/dot_wrapper.h index a27198b20..d8cb9345b 100644 --- a/src/Common/dot_wrapper.h +++ b/src/Common/dot_wrapper.h @@ -16,21 +16,23 @@ extern "C" #ifdef CARET_DOTFCN #include "dot.h" #else -inline double sddot (const float *a, const float *b, int n) +inline double dsdot (const float *a, const float *b, int n) { double sum = 0; for (int k = 0; k < n; k++) sum += a[k] * b[k]; return sum; -} // sddot() +} // dsdot() //copy enum from dot.h //renamed to dot_flags in both files for less conflict chance typedef enum { - DOT_NAIVE = 1, - DOT_SSE2 = 2, - DOT_AVX = 3, - DOT_AVXFMA = 4, - DOT_AUTO = 100 + DOT_NAIVE = 1, + DOT_SSE2 = 2, + DOT_AVX = 3, + DOT_AVXFMA = 4, + DOT_AVX512 = 5, + DOT_AVX512FMA = 6, + DOT_AUTO = 100 } dot_flags; //and dummy implementation of dot_set_impl inline dot_flags dot_set_impl (dot_flags) @@ -55,7 +57,7 @@ namespace caret { public: typedef dot_flags Enum; - + static inline std::vector getAllEnums() { std::vector ret; @@ -63,10 +65,12 @@ namespace caret ret.push_back(DOT_SSE2); ret.push_back(DOT_AVX); ret.push_back(DOT_AVXFMA); + ret.push_back(DOT_AVX512); + ret.push_back(DOT_AVX512FMA); ret.push_back(DOT_AUTO); return ret; } - + static inline Enum fromName(const AString& name, bool* isValidOut = NULL) { bool valid = false; @@ -84,6 +88,12 @@ namespace caret } else if (name == "AVXFMA") { ret = DOT_AVXFMA; valid = true; + } else if (name == "AVX512") { + ret = DOT_AVX512; + valid = true; + } else if (name == "AVX512FMA") { + ret = DOT_AVX512FMA; + valid = true; } else if (name == "AUTO") { ret = DOT_AUTO; valid = true; @@ -96,7 +106,7 @@ namespace caret } return ret; } - + static inline AString toName(const Enum& value) { switch (value) @@ -109,6 +119,10 @@ namespace caret return "AVX"; case DOT_AVXFMA: return "AVXFMA"; + case DOT_AVX512: + return "AVX512"; + case DOT_AVX512FMA: + return "AVX512FMA"; case DOT_AUTO: return "AUTO"; default: diff --git a/src/Files/CiftiConnectivityMatrixDenseDynamicFile.cxx b/src/Files/CiftiConnectivityMatrixDenseDynamicFile.cxx index fd0e221cd..7a18b2cf1 100644 --- a/src/Files/CiftiConnectivityMatrixDenseDynamicFile.cxx +++ b/src/Files/CiftiConnectivityMatrixDenseDynamicFile.cxx @@ -489,12 +489,12 @@ CiftiConnectivityMatrixDenseDynamicFile::correlation(const std::vector& d const RowData& otherData = m_rowData[otherRowIndex]; if (m_cacheDataFlag) { - xySum = sddot(&data[0], &otherData.m_data[0], numberOfPoints); + xySum = dsdot(&data[0], &otherData.m_data[0], numberOfPoints); } else { std::vector otherDataVector(m_numberOfTimePoints); m_parentDataSeriesCiftiFile->getRow(&otherDataVector[0], otherRowIndex); - xySum = sddot(&data[0], &otherDataVector[0], numberOfPoints); + xySum = dsdot(&data[0], &otherDataVector[0], numberOfPoints); } const double ssxy = xySum - (numFloat * mean * otherData.m_mean); diff --git a/src/Tests/DotTest.cxx b/src/Tests/DotTest.cxx index ff3f8f806..024c7c1dd 100644 --- a/src/Tests/DotTest.cxx +++ b/src/Tests/DotTest.cxx @@ -100,7 +100,7 @@ namespace } float stdev1 = sqrt(accum1); float stdev2 = sqrt(accum2); - double dotval = sddot(vec1.data(), vec2.data(), length);//function under test + double dotval = dsdot(vec1.data(), vec2.data(), length);//function under test return dotval / (stdev1 * stdev2); } @@ -156,7 +156,7 @@ void DotTest::execute() } else { cout << "skipping AVX, not supported" << endl; } - //avx + //avx+fma impl_in_use = dot_set_impl(DOT_AVXFMA); if (impl_in_use == DOT_AVXFMA) { @@ -169,4 +169,30 @@ void DotTest::execute() } else { cout << "skipping AVXFMA, not supported" << endl; } + //avx512 + impl_in_use = dot_set_impl(DOT_AVX512); + if (impl_in_use == DOT_AVX512) + { + checkVal(self_naive, correlate(rand1, rand1), "avx512 self-correlation"); + checkVal(unrelated_naive, correlate(rand1, rand2), "avx512 unrelated correlation"); + checkVal(lowsnr_naive, correlate(lowsnrA, lowsnrB), "avx512 low snr correlation"); + checkVal(midsnr_naive, correlate(midsnrA, midsnrB), "avx512 mid snr correlation"); + checkVal(highsnr_naive, correlate(highsnrA, highsnrB), "avx512 high snr correlation"); + checkVal(cross_snr_naive, correlate(lowsnrA, highsnrB), "avx512 cross snr correlation"); + } else { + cout << "skipping AVX512, not supported" << endl; + } + //avx512+fma + impl_in_use = dot_set_impl(DOT_AVX512FMA); + if (impl_in_use == DOT_AVX512FMA) + { + checkVal(self_naive, correlate(rand1, rand1), "avx512fma self-correlation"); + checkVal(unrelated_naive, correlate(rand1, rand2), "avx512fma unrelated correlation"); + checkVal(lowsnr_naive, correlate(lowsnrA, lowsnrB), "avx512fma low snr correlation"); + checkVal(midsnr_naive, correlate(midsnrA, midsnrB), "avx512fma mid snr correlation"); + checkVal(highsnr_naive, correlate(highsnrA, highsnrB), "avx512fma high snr correlation"); + checkVal(cross_snr_naive, correlate(lowsnrA, highsnrB), "avx512fma cross snr correlation"); + } else { + cout << "skipping AVX512FMA, not supported" << endl; + } } diff --git a/src/kloewe/cpuinfo/LICENSE b/src/kloewe/cpuinfo/LICENSE index a64f28f98..fcaf12d79 100644 --- a/src/kloewe/cpuinfo/LICENSE +++ b/src/kloewe/cpuinfo/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2016 Kristian Loewe, Christian Borgelt +Copyright (c) 2013-2017 Kristian Loewe, Christian Borgelt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/kloewe/cpuinfo/src/cpuinfo.c b/src/kloewe/cpuinfo/src/cpuinfo.c index f106c06ac..b02c97c4f 100644 --- a/src/kloewe/cpuinfo/src/cpuinfo.c +++ b/src/kloewe/cpuinfo/src/cpuinfo.c @@ -28,7 +28,10 @@ #ifdef NDEBUG #define DBGMSG(...) ((void)0) #else -#define DBGMSG(...) fprintf(stderr, __VA_ARGS__) +#line __LINE__ "cpuinfo.c" +#define DBGMSG(...) do { fprintf(stderr, "%s:%d:%s()\n", \ + __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); } while(0) #endif /*---------------------------------------------------------------------------- @@ -42,23 +45,30 @@ typedef struct { /* --- processor ids --- */ /*---------------------------------------------------------------------------- Global Variables ----------------------------------------------------------------------------*/ -static int cpuinfo[5]; /* cpu information */ +static int cpuinfo[4]; /* cpu information (cpuid) */ +static int peax = -1; /* previous eax */ +static int pecx = -1; /* previous ecx */ +static int nphys = 0; /* # processors/packages/sockets */ +static int ncores = 0; /* # processor cores */ +static int nprocs = 0; /* # logical processors */ /*---------------------------------------------------------------------------- Functions ----------------------------------------------------------------------------*/ #ifdef _WIN32 /* if Microsoft Windows system */ -#define cpuid __cpuid /* map existing function */ +#define cpuid __cpuidex /* map existing function */ #else /* if Linux/Unix system */ -static void cpuid (int32_t info[4], int32_t type) +static void cpuid (int32_t info[4], int32_t eax, int32_t ecx) { /* --- get CPU information */ __asm__ __volatile__ ("cpuid" : "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3]) - : "a" (type), "c" (0)); // : "a" (type)); + : "a" (eax), "c" (ecx)); + peax = eax; + pecx = ecx; } /* cpuid() */ #endif /* #ifdef _WIN32 .. #else .. */ @@ -107,17 +117,25 @@ static int cmpids (const void *p, const void *q) /*--------------------------------------------------------------------------*/ -int corecnt (void) -{ /* --- number of processor cores */ +static int enumerate (void) +{ /* --- enumerate topology */ FILE *fp; /* file for /proc/cpuinfo */ PROCIDS *pids; /* processor ids (physical & core) */ int n; /* # log. processors found in cpuinfo */ int i, p, c, np, nc; /* loop variables */ - int nphys = 0; /* number of physical processors */ - int ncores = 0; /* number of physical cores */ - int nprocs = proccnt(); /* # log. processors (reference) */ - if (nprocs < 0) return -1; /* abort if nprocs can't be determined */ + /* determine number of logical processors (reference) */ + #ifdef _SC_NPROCESSORS_ONLN /* if glibc's sysconf is available */ + nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN); + #else + nprocs = -1; + #endif + if (nprocs < 0) { /* abort if nprocs can't be determined */ + nphys = -1; + ncores = -1; + nprocs = -1; + return -1; + } /* collect physical id and core id of each logical processor */ pids = calloc((size_t)nprocs, sizeof(PROCIDS)); @@ -133,7 +151,13 @@ int corecnt (void) while (((c = fgetc(fp)) != EOF) && (c != '\n')); } fclose(fp); - if (n != nprocs) { free(pids); return -1; } + if (n != nprocs) { /* abort if the number of log. procs */ + nphys = -1; /* found differs from the reference */ + ncores = -1; + nprocs = -1; + free(pids); + return -1; + } /* sort the array of processor ids and determine the number of cores */ qsort(pids, (size_t)nprocs, sizeof(PROCIDS), cmpids); @@ -142,7 +166,7 @@ int corecnt (void) for (i = np = nc = 0; i < n; i++) { if (pids[i].phys == p) { np += 1; if (pids[i].core == c) { nc += 1; continue; } - DBGMSG("phys %d, core %d: %d logical processor(s)\n", p, c, nc); + DBGMSG("phys %d, core %2d: %d logical processor(s)\n", p, c, nc); c = pids[i].core; nc = 1; ncores += 1; continue; } @@ -157,42 +181,59 @@ int corecnt (void) DBGMSG("number of physical processors: %d\n", nphys); DBGMSG("number of cores: %d\n", ncores); free(pids); - if ((ncores != nprocs) && (ncores != nprocs/2)) - return -1; /* check result for consistency */ - return ncores; /* return the number of cores */ -} /* corecnt() */ + if (nprocs % ncores) { /* check results for consistency */ + nphys = -1; + ncores = -1; + nprocs = -1; + return -1; } + else + return 0; +} /* enumerate() */ -#elif defined _WIN32 /* if Microsoft Windows system */ +/*--------------------------------------------------------------------------*/ -int corecnt (void) -{ /* --- number of processor cores */ - return -1; /* not yet implemented for Windows */ -} /* corecnt() */ +int physcnt (void) +{ /* --- number of physical processors */ + if (!nphys) + if (enumerate()) { return -1; } + return nphys; +} /* physcnt() */ -#elif defined __APPLE__ /* if Apple Mac OS system */ +/*--------------------------------------------------------------------------*/ int corecnt (void) { /* --- number of processor cores */ - int ncores; - size_t len = sizeof(ncores); - if (sysctlbyname("hw.physicalcpu", &ncores, &len, NULL, (size_t)0)) - return -1; + if (!ncores) + if (enumerate()) { return -1; } return ncores; } /* corecnt() */ -#endif /* #ifdef __linux__ .. #elif def. _WIN32 .. #elif def. __APPLE__ .. */ /*--------------------------------------------------------------------------*/ -#ifdef __linux__ /* if Linux system */ -#ifdef _SC_NPROCESSORS_ONLN /* if glibc's sysconf is available */ int proccnt (void) { /* --- number of logical processors */ - return (int)sysconf(_SC_NPROCESSORS_ONLN); + if (!nprocs) + if (enumerate()) { return -1; } + return nprocs; } /* proccnt() */ -#endif /* #ifdef _SC_NPROCESSORS_ONLN */ +/*--------------------------------------------------------------------------*/ #elif defined _WIN32 /* if Microsoft Windows system */ +int physcnt (void) +{ /* --- number of physical processors */ + return -1; /* not yet implemented for Windows */ +} /* physcnt() */ + +/*--------------------------------------------------------------------------*/ + +int corecnt (void) +{ /* --- number of processor cores */ + return -1; /* not yet implemented for Windows */ +} /* corecnt() */ + +/*--------------------------------------------------------------------------*/ + int proccnt (void) { /* --- number of logical processors */ SYSTEM_INFO sysinfo; /* system information structure */ @@ -200,8 +241,31 @@ int proccnt (void) return sysinfo.dwNumberOfProcessors; } /* proccnt() */ +/*--------------------------------------------------------------------------*/ #elif defined __APPLE__ /* if Apple Mac OS system */ +int physcnt (void) +{ /* --- number of physical processors */ + int nphys; + size_t len = sizeof(nphys); + if (sysctlbyname("hw.packages", &nphys, &len, NULL, (size_t)0)) + return -1; + return nphys; +} /* physcnt() */ + +/*--------------------------------------------------------------------------*/ + +int corecnt (void) +{ /* --- number of processor cores */ + int ncores; + size_t len = sizeof(ncores); + if (sysctlbyname("hw.physicalcpu", &ncores, &len, NULL, (size_t)0)) + return -1; + return ncores; +} /* corecnt() */ + +/*--------------------------------------------------------------------------*/ + int proccnt (void) { /* --- number of logical processors */ int nproc; @@ -230,7 +294,10 @@ Additional info and references (proccnt, Linux version): int proccntmax (void) { /* --- max. number of logical processors * per physical processor */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); return (cpuinfo[1] >> 16) & 0xff; /* EBX[23:16] */ } /* proccntmax() */ @@ -248,7 +315,10 @@ References (proccntmax): int hasMMX (void) { /* --- check for MMX instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); return (cpuinfo[3] & (1 << 23)) != 0; } /* hasMMX() */ @@ -256,85 +326,180 @@ int hasMMX (void) int hasSSE (void) { /* --- check for SSE instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[3] & (1 << 25)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[3] & (1 << 25)) != 0; /* EDX 25 */ } /* hasSSE() */ /*--------------------------------------------------------------------------*/ int hasSSE2 (void) { /* --- check for SSE2 instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[3] & (1 << 26)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[3] & (1 << 26)) != 0; /* EDX 26 */ } /* hasSSE2() */ /*--------------------------------------------------------------------------*/ int hasSSE3 (void) { /* --- check for SSE3 instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 0)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 0)) != 0; /* ECX 0 */ } /* hasSSE3() */ /*--------------------------------------------------------------------------*/ int hasSSSE3 (void) { /* --- check for SSSE3 instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 9)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 9)) != 0; /* ECX 9 */ } /* hasSSSE3() */ /*--------------------------------------------------------------------------*/ int hasSSE41 (void) { /* --- check for SSE4.1 instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 19)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 19)) != 0; /* ECX 19 */ } /* hasSSE41() */ /*--------------------------------------------------------------------------*/ int hasSSE42 (void) { /* --- check for SSE4.2 instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 20)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 20)) != 0; /* ECX 20 */ } /* hasSSE42() */ /*--------------------------------------------------------------------------*/ int hasPOPCNT (void) { /* --- check for popcnt instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 23)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 23)) != 0; /* ECX 23 */ } /* hasPOPCNT() */ /*--------------------------------------------------------------------------*/ int hasAVX (void) { /* --- check for AVX instructions */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 28)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 28)) != 0; /* ECX 28 */ } /* hasAVX() */ /*--------------------------------------------------------------------------*/ +int hasAVX2 (void) +{ /* --- check for AVX2 instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 5)) != 0; /* EBX 5 */ +} /* hasAVX2() */ + +/*--------------------------------------------------------------------------*/ + int hasFMA3 (void) { /* --- check for FMA3 */ - if (!cpuinfo[4]) { cpuid(cpuinfo, 1); cpuinfo[4] = -1; } - return (cpuinfo[2] & (1 << 12)) != 0; + int eax = 1; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[2] & (1 << 12)) != 0; /* ECX 12 */ } /* hasFMA3() */ /*--------------------------------------------------------------------------*/ +int hasAVX512f (void) +{ /* --- check for AVX512f instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 16)) != 0; /* EBX 16 */ +} /* hasAVX512f() */ + +/*--------------------------------------------------------------------------*/ + +int hasAVX512cd (void) +{ /* --- check for AVX512cd instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 28)) != 0; /* EBX 28 */ +} /* hasAVX512cd() */ + +/*--------------------------------------------------------------------------*/ + +int hasAVX512bw (void) +{ /* --- check for AVX512bw instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 30)) != 0; /* EBX 30 */ +} /* hasAVX512bw() */ + +/*--------------------------------------------------------------------------*/ + +int hasAVX512dq (void) +{ /* --- check for AVX512dq instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 17)) != 0; /* EBX 17 */ +} /* hasAVX512dq() */ + +/*--------------------------------------------------------------------------*/ + +int hasAVX512vl (void) +{ /* --- check for AVX512vl instructions */ + int eax = 7; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + return (cpuinfo[1] & (1 << 31)) != 0; /* EBX 31 */ +} /* hasAVX512vl() */ + +/*--------------------------------------------------------------------------*/ + void getVendorID (char *buf) { /* --- get vendor id */ /* the string is going to be exactly 12 characters long, allocate the buffer outside this function accordingly */ - int regs[4]; - cpuid(regs, 0); - ((unsigned *)buf)[0] = (unsigned)regs[1]; // EBX - ((unsigned *)buf)[1] = (unsigned)regs[3]; // EDX - ((unsigned *)buf)[2] = (unsigned)regs[2]; // ECX + int eax = 0; + int ecx = 0; + if ((eax != peax) || (ecx != pecx)) + cpuid(cpuinfo, eax, ecx); + ((unsigned *)buf)[0] = (unsigned)cpuinfo[1]; /* EBX */ + ((unsigned *)buf)[1] = (unsigned)cpuinfo[3]; /* EDX */ + ((unsigned *)buf)[2] = (unsigned)cpuinfo[2]; /* ECX */ } /* getVendorID() */ /*---------------------------------------------------------------------------- @@ -347,28 +512,36 @@ int main (int argc, char* argv[]) { char vendor[12]; getVendorID(vendor); - printf("Vendor %s\n", vendor); - #ifndef _WIN32 - printf("Processor cores %d\n", corecnt()); - #endif - printf("Logical processors %d\n", proccnt()); - printf("MMX %d\n", hasMMX()); - printf("SSE %d\n", hasSSE()); - printf("SSE2 %d\n", hasSSE2()); - printf("SSE3 %d\n", hasSSE3()); - printf("SSSE3 %d\n", hasSSSE3()); - printf("SSE41 %d\n", hasSSE41()); - printf("SSE42 %d\n", hasSSE42()); - printf("POPCNT %d\n", hasPOPCNT()); - printf("AVX %d\n", hasAVX()); - printf("FMA3 %d\n", hasFMA3()); - -/* corecnt -> number of processor cores + printf("Vendor %s\n", vendor); + printf("Physical processors %d\n", physcnt()); + printf("Processor cores %d\n", corecnt()); + printf("Logical processors %d\n", proccnt()); + printf("MMX %d\n", hasMMX()); + printf("SSE %d\n", hasSSE()); + printf("SSE2 %d\n", hasSSE2()); + printf("SSE3 %d\n", hasSSE3()); + printf("SSSE3 %d\n", hasSSSE3()); + printf("SSE41 %d\n", hasSSE41()); + printf("SSE42 %d\n", hasSSE42()); + printf("POPCNT %d\n", hasPOPCNT()); + printf("AVX %d\n", hasAVX()); + printf("AVX2 %d\n", hasAVX2()); + printf("FMA3 %d\n", hasFMA3()); + printf("AVX512f %d\n", hasAVX512f()); + printf("AVX512cd %d\n", hasAVX512cd()); + printf("AVX512bw %d\n", hasAVX512bw()); + printf("AVX512dq %d\n", hasAVX512dq()); + printf("AVX512vl %d\n", hasAVX512vl()); + +/* + physcnt -> number of physical processors/packages/sockets + corecnt -> number of processor cores proccnt -> number of logical processors proccntmax -> max. number of logical processors per core See the glossary at: software.intel.com/en-us/articles/ - intel-64-architecture-processor-topology-enumeration */ + intel-64-architecture-processor-topology-enumeration +*/ } /* main() */ diff --git a/src/kloewe/cpuinfo/src/cpuinfo.h b/src/kloewe/cpuinfo/src/cpuinfo.h index 990609128..348da9c06 100644 --- a/src/kloewe/cpuinfo/src/cpuinfo.h +++ b/src/kloewe/cpuinfo/src/cpuinfo.h @@ -9,17 +9,9 @@ /*---------------------------------------------------------------------------- Functions ----------------------------------------------------------------------------*/ -extern int proccnt (void); /* # logical processors */ - -#ifndef _WIN32 /* if Linux or Apple Mac OS system */ +extern int physcnt (void); /* # physical processors */ extern int corecnt (void); /* # processor cores */ - -#ifdef __linux__ -#ifdef HAVE_HWLOC -extern int corecntHwloc (void); /* # processor cores */ -#endif -#endif -#endif +extern int proccnt (void); /* # logical processors */ extern int hasMMX (void); extern int hasSSE (void); @@ -30,6 +22,12 @@ extern int hasSSE41 (void); extern int hasSSE42 (void); extern int hasPOPCNT (void); extern int hasAVX (void); +extern int hasAVX2 (void); extern int hasFMA3 (void); +extern int hasAVX512f (void); +extern int hasAVX512cd (void); +extern int hasAVX512bw (void); +extern int hasAVX512dq (void); +extern int hasAVX512vl (void); #endif /* #ifndef CPUINFO_H */ diff --git a/src/kloewe/dot/CMakeLists.txt b/src/kloewe/dot/CMakeLists.txt index 5e5725a10..5da60db96 100644 --- a/src/kloewe/dot/CMakeLists.txt +++ b/src/kloewe/dot/CMakeLists.txt @@ -8,42 +8,77 @@ if(CMAKE_VERSION VERSION_LESS "2.8.12") endfunction(add_compile_options) endif() +add_compile_options(-std=c99 -Wall -Wextra -Wno-unused-parameter -Wconversion -Wshadow -pedantic) + SET(DOT_USEFMA 0) +SET(DOT_USEAVX512 0) + if (CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + string(FIND ${GCC_VERSION} "." GCC_VERSION_HAS_DOT) + if (${GCC_VERSION_HAS_DOT} EQUAL -1) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpfullversion OUTPUT_VARIABLE GCC_VERSION) + endif() if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7) - message(STATUS "Version >= 4.7") + message(STATUS "GCC version >= 4.7") SET(DOT_USEFMA 1) endif() + if (GCC_VERSION VERSION_GREATER 7.1 OR GCC_VERSION VERSION_EQUAL 7.1) + message(STATUS "GCC version >= 7.1") + add_compile_options(-Wimplicit-fallthrough=0) + SET(DOT_USEAVX512 1) + endif() endif() -add_compile_options(-std=c99 -Wall -Wextra -Wno-unused-parameter -Wconversion -Wshadow -pedantic) - add_library(dot src/dot.c) add_library(dot_naive src/dot_naive.c) add_library(dot_sse2 src/dot_sse2.c) add_library(dot_avx src/dot_avx.c) -if(DOT_USEFMA) +if(DOT_USEFMA AND DOT_USEAVX512) + add_library(dot_avxfma src/dot_avx.c) + add_library(dot_avx512 src/dot_avx512.c) + add_library(dot_avx512fma src/dot_avx512.c) + target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma dot_avx512 dot_avx512fma cpuinfo ${CARET_QT5_LINK}) +elseif(DOT_USEFMA) add_library(dot_avxfma src/dot_avx.c) target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma cpuinfo ${CARET_QT5_LINK}) +elseif(DOT_USEAVX512) + add_library(dot_avx512 src/dot_avx512.c) + target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avx512 cpuinfo ${CARET_QT5_LINK}) else() target_link_libraries(dot dot_naive dot_sse2 dot_avx cpuinfo ${CARET_QT5_LINK}) endif() if(CMAKE_VERSION VERSION_LESS "2.8.12") - if(DOT_USEFMA) + if(DOT_USEFMA AND DOT_USEAVX512) set_target_properties(dot_avxfma PROPERTIES COMPILE_FLAGS "-mfma -mavx -funroll-loops") - else() + set_target_properties(dot_avx512 PROPERTIES COMPILE_FLAGS "-mavx512f -funroll-loops") + set_target_properties(dot_avx512fma PROPERTIES COMPILE_FLAGS "-mavx512f -mfma -funroll-loops") + elseif(DOT_USEFMA) + set_target_properties(dot_avxfma PROPERTIES COMPILE_FLAGS "-mfma -mavx -funroll-loops") + set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOAVX512") + elseif(DOT_USEAVX512) + set_target_properties(dot_avx512 PROPERTIES COMPILE_FLAGS "-mavx512f -funroll-loops") set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOFMA") + else() + set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOFMA -DDOT_NOAVX512") endif() set_target_properties(dot_avx PROPERTIES COMPILE_FLAGS "-mavx -funroll-loops") set_target_properties(dot_sse2 PROPERTIES COMPILE_FLAGS "-msse2") include_directories(../cpuinfo/src) else() - if(DOT_USEFMA) + if(DOT_USEFMA AND DOT_USEAVX512) target_compile_options(dot_avxfma PRIVATE -mfma -mavx -funroll-loops) - else() + target_compile_options(dot_avx512 PRIVATE -mavx512f -funroll-loops) + target_compile_options(dot_avx512fma PRIVATE -mavx512f -mfma -funroll-loops) + elseif(DOT_USEFMA) + target_compile_options(dot_avxfma PRIVATE -mfma -mavx -funroll-loops) + target_compile_definitions(dot PRIVATE "DOT_NOAVX512") + elseif(DOT_USEAVX512) + target_compile_options(dot_avx512 PRIVATE -mavx512f -funroll-loops) target_compile_definitions(dot PRIVATE "DOT_NOFMA") + else() + target_compile_definitions(dot PRIVATE "DOT_NOFMA DOT_NOAVX512") endif() target_compile_options(dot_avx PRIVATE -mavx -funroll-loops) target_compile_options(dot_sse2 PRIVATE -msse2) diff --git a/src/kloewe/dot/LICENSE b/src/kloewe/dot/LICENSE index 8b99578c0..d7cddabbf 100644 --- a/src/kloewe/dot/LICENSE +++ b/src/kloewe/dot/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2012-2016 Kristian Loewe, Christian Borgelt +Copyright (c) 2012-2017 Kristian Loewe, Christian Borgelt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/kloewe/dot/src/dot.c b/src/kloewe/dot/src/dot.c index d8130b1d2..f33853040 100644 --- a/src/kloewe/dot/src/dot.c +++ b/src/kloewe/dot/src/dot.c @@ -3,22 +3,24 @@ Contents: dot product (cpu dispatcher) Author : Kristian Loewe ----------------------------------------------------------------------------*/ -#include "cpuinfo.h" #include "dot.h" +#ifdef ARCH_IS_X86_64 +#include "cpuinfo.h" +#endif /*---------------------------------------------------------------------------- Function Prototypes ----------------------------------------------------------------------------*/ extern float sdot (const float *a, const float *b, int n); extern double ddot (const double *a, const double *b, int n); -extern double sddot (const float *a, const float *b, int n); +extern double dsdot (const float *a, const float *b, int n); /*---------------------------------------------------------------------------- Global Variables ----------------------------------------------------------------------------*/ sdot_func *sdot_ptr = &sdot_select; ddot_func *ddot_ptr = &ddot_select; -sddot_func *sddot_ptr = &sddot_select; +dsdot_func *dsdot_ptr = &dsdot_select; /*---------------------------------------------------------------------------- Functions @@ -34,37 +36,68 @@ double ddot_select (const double *a, const double *b, int n) { return (*ddot_ptr)(a,b,n); } -double sddot_select (const float *a, const float *b, int n) { +double dsdot_select (const float *a, const float *b, int n) { dot_set_impl(DOT_AUTO); - return (*sddot_ptr)(a,b,n); + return (*dsdot_ptr)(a,b,n); } -dot_flags dot_set_impl (dot_flags impl) { - #ifndef DOT_NOFMA - // the AVX-FMA implementations are currently slower than the AVX - // implementations and are thus only used if explicitly requested - if (hasFMA3() && hasAVX() && (impl == DOT_AVXFMA)) { // AVX-FMA - sdot_ptr = &sdot_avxfma; - ddot_ptr = &ddot_avxfma; - sddot_ptr = &sddot_avxfma; - return DOT_AVXFMA; } - else if (hasAVX() && (impl >= DOT_AVX)) { // AVX - #else - if (hasAVX() && (impl >= DOT_AVX)) { // AVX +dot_flags dot_set_impl (dot_flags impl) { + + #ifndef ARCH_IS_X86_64 + impl = DOT_NAIVE; #endif - sdot_ptr = &sdot_avx; - ddot_ptr = &ddot_avx; - sddot_ptr = &sddot_avx; - return DOT_AVX; } - else if (hasSSE2() && (impl >= DOT_SSE2)) { // SSE2 - sdot_ptr = &sdot_sse2; - ddot_ptr = &ddot_sse2; - sddot_ptr = &sddot_sse2; - return DOT_SSE2; } - else { // naive - sdot_ptr = &sdot_naive; - ddot_ptr = &ddot_naive; - sddot_ptr = &sddot_naive; - return DOT_NAIVE; + + switch (impl) { + case DOT_AUTO : + #ifndef DOT_NOAVX512 + #ifndef DOT_NOFMA + case DOT_AVX512FMA : + if (hasAVX512f() && hasFMA3()) { + sdot_ptr = &sdot_avx512fma; + ddot_ptr = &ddot_avx512fma; + dsdot_ptr = &dsdot_avx512fma; + return DOT_AVX512FMA; + } + #endif + case DOT_AVX512 : + if (hasAVX512f()) { + sdot_ptr = &sdot_avx512; + ddot_ptr = &ddot_avx512; + dsdot_ptr = &dsdot_avx512; + return DOT_AVX512; + } + #endif + #ifndef DOT_NOFMA + // Note: The AVX-FMA implementations seem to be slower than the AVX + // implementations and are thus only used if explicitly requested. + case DOT_AVXFMA : + if ((impl == DOT_AVXFMA) && hasAVX() && hasFMA3()) { + sdot_ptr = &sdot_avxfma; + ddot_ptr = &ddot_avxfma; + dsdot_ptr = &dsdot_avxfma; + return DOT_AVXFMA; + } + #endif + case DOT_AVX : + if (hasAVX()) { + sdot_ptr = &sdot_avx; + ddot_ptr = &ddot_avx; + dsdot_ptr = &dsdot_avx; + return DOT_AVX; + } + case DOT_SSE2 : + if (hasSSE2()) { + sdot_ptr = &sdot_sse2; + ddot_ptr = &ddot_sse2; + dsdot_ptr = &dsdot_sse2; + return DOT_SSE2; + } + case DOT_NAIVE : + sdot_ptr = &sdot_naive; + ddot_ptr = &ddot_naive; + dsdot_ptr = &dsdot_naive; + return DOT_NAIVE; + default : + return dot_set_impl(DOT_AUTO); } -} +} // dot_set_impl() diff --git a/src/kloewe/dot/src/dot.h b/src/kloewe/dot/src/dot.h index 48674c030..ced9ac2d4 100644 --- a/src/kloewe/dot/src/dot.h +++ b/src/kloewe/dot/src/dot.h @@ -11,15 +11,25 @@ extern "C" { #endif +/*---------------------------------------------------------------------------- + Preprocessor Definitions +----------------------------------------------------------------------------*/ +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) \ + || defined(__amd64__) || defined(_M_AMD64) || defined(_M_X64) +#define ARCH_IS_X86_64 +#endif + /*---------------------------------------------------------------------------- Enum to encode the sets of dot implementations ----------------------------------------------------------------------------*/ typedef enum { - DOT_NAIVE = 1, // plain C - DOT_SSE2 = 2, // SSE2 - DOT_AVX = 3, // AVX - DOT_AVXFMA = 4, // AVX+FMA3 - DOT_AUTO = 100 // automatic choice + DOT_NAIVE = 1, // plain C + DOT_SSE2 = 2, // SSE2 + DOT_AVX = 3, // AVX + DOT_AVXFMA = 4, // AVX+FMA3 + DOT_AVX512 = 5, // AVX512 + DOT_AVX512FMA = 6, // AVX512+FMA3 + DOT_AUTO = 100 // automatic choice } dot_flags; // Using dot_set_impl(), these values are used to specify the set of // implementations to be used. The values/sets are ordered chronologically wrt @@ -30,23 +40,23 @@ typedef enum { /*---------------------------------------------------------------------------- Type Definitions ----------------------------------------------------------------------------*/ -typedef float (sdot_func) (const float *a, const float *b, int n); -typedef double (ddot_func) (const double *a, const double *b, int n); -typedef double (sddot_func) (const float *a, const float *b, int n); +typedef float (sdot_func) (const float *a, const float *b, int n); +typedef double (ddot_func) (const double *a, const double *b, int n); +typedef double (dsdot_func) (const float *a, const float *b, int n); /*---------------------------------------------------------------------------- Global Variables ----------------------------------------------------------------------------*/ extern sdot_func *sdot_ptr; extern ddot_func *ddot_ptr; -extern sddot_func *sddot_ptr; +extern dsdot_func *dsdot_ptr; /*---------------------------------------------------------------------------- Function Prototypes ----------------------------------------------------------------------------*/ -inline float sdot (const float *a, const float *b, int n); -inline double ddot (const double *a, const double *b, int n); -inline double sddot (const float *a, const float *b, int n); +inline float sdot (const float *a, const float *b, int n); +inline double ddot (const double *a, const double *b, int n); +inline double dsdot (const float *a, const float *b, int n); /* dot_set_impl * ------------ @@ -57,41 +67,55 @@ inline double sddot (const float *a, const float *b, int n); * * parameters * impl indicates which set of implementations should be used - * DOT_NAIVE -> plain C implementations - * DOT_SSE2 -> SSE2 implementations - * DOT_AVX -> AVX implementations - * DOT_AVXFMA -> AVX+FMA3 implementations - * DOT_AUTO -> automatically choose the best available set + * DOT_NAIVE -> plain C implementations + * DOT_SSE2 -> SSE2 implementations + * DOT_AVX -> AVX implementations + * DOT_AVXFMA -> AVX+FMA3 implementations + * DOT_AVX512 -> AVX512 implementations + * DOT_AVX512FMA -> AVX512+FMA3 implementations + * DOT_AUTO -> automatically choose the best available set * (see also the above enum) * * returns * the enum value corresponding to the selected set of implementations */ -extern dot_flags dot_set_impl (dot_flags impl); - - -extern float sdot_select (const float *a, const float *b, int n); -extern double ddot_select (const double *a, const double *b, int n); -extern double sddot_select (const float *a, const float *b, int n); - -#ifndef DOT_NOFMA -extern float sdot_avxfma (const float *a, const float *b, int n); -extern double ddot_avxfma (const double *a, const double *b, int n); -extern double sddot_avxfma (const float *a, const float *b, int n); +extern dot_flags dot_set_impl (dot_flags impl); + + +extern float sdot_select (const float *a, const float *b, int n); +extern double ddot_select (const double *a, const double *b, int n); +extern double dsdot_select (const float *a, const float *b, int n); + +extern float sdot_naive (const float *a, const float *b, int n); +extern double ddot_naive (const double *a, const double *b, int n); +extern double dsdot_naive (const float *a, const float *b, int n); + +#ifdef ARCH_IS_X86_64 +extern float sdot_sse2 (const float *a, const float *b, int n); +extern double ddot_sse2 (const double *a, const double *b, int n); +extern double dsdot_sse2 (const float *a, const float *b, int n); + +extern float sdot_avx (const float *a, const float *b, int n); +extern double ddot_avx (const double *a, const double *b, int n); +extern double dsdot_avx (const float *a, const float *b, int n); + +# ifndef DOT_NOFMA +extern float sdot_avxfma (const float *a, const float *b, int n); +extern double ddot_avxfma (const double *a, const double *b, int n); +extern double dsdot_avxfma (const float *a, const float *b, int n); +# endif +# ifndef DOT_NOAVX512 +extern float sdot_avx512 (const float *a, const float *b, int n); +extern double ddot_avx512 (const double *a, const double *b, int n); +extern double dsdot_avx512 (const float *a, const float *b, int n); +# ifndef DOT_NOFMA +extern float sdot_avx512fma (const float *a, const float *b, int n); +extern double ddot_avx512fma (const double *a, const double *b, int n); +extern double dsdot_avx512fma (const float *a, const float *b, int n); +# endif +# endif #endif -extern float sdot_avx (const float *a, const float *b, int n); -extern double ddot_avx (const double *a, const double *b, int n); -extern double sddot_avx (const float *a, const float *b, int n); - -extern float sdot_sse2 (const float *a, const float *b, int n); -extern double ddot_sse2 (const double *a, const double *b, int n); -extern double sddot_sse2 (const float *a, const float *b, int n); - -extern float sdot_naive (const float *a, const float *b, int n); -extern double ddot_naive (const double *a, const double *b, int n); -extern double sddot_naive (const float *a, const float *b, int n); - /*---------------------------------------------------------------------------- Inline Functions ----------------------------------------------------------------------------*/ @@ -104,8 +128,8 @@ inline double ddot (const double *a, const double *b, int n) { return (*ddot_ptr)(a,b,n); } -inline double sddot (const float *a, const float *b, int n) { - return (*sddot_ptr)(a,b,n); +inline double dsdot (const float *a, const float *b, int n) { + return (*dsdot_ptr)(a,b,n); } #ifdef __cplusplus diff --git a/src/kloewe/dot/src/dot_avx.c b/src/kloewe/dot/src/dot_avx.c index 3372ac2f1..30521b7b9 100644 --- a/src/kloewe/dot/src/dot_avx.c +++ b/src/kloewe/dot/src/dot_avx.c @@ -11,9 +11,9 @@ #ifdef __FMA__ extern float sdot_avxfma (const float *a, const float *b, int n); extern double ddot_avxfma (const double *a, const double *b, int n); -extern double sddot_avxfma (const float *a, const float *b, int n); +extern double dsdot_avxfma (const float *a, const float *b, int n); #else extern float sdot_avx (const float *a, const float *b, int n); extern double ddot_avx (const double *a, const double *b, int n); -extern double sddot_avx (const float *a, const float *b, int n); +extern double dsdot_avx (const float *a, const float *b, int n); #endif diff --git a/src/kloewe/dot/src/dot_avx.h b/src/kloewe/dot/src/dot_avx.h index 32a5203cc..2cbcff936 100644 --- a/src/kloewe/dot/src/dot_avx.h +++ b/src/kloewe/dot/src/dot_avx.h @@ -11,6 +11,12 @@ #endif #include +#include + +// alignment check +#include +#define is_aligned(POINTER, BYTE_COUNT) \ + (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) /*---------------------------------------------------------------------------- Function Prototypes @@ -18,11 +24,11 @@ #ifdef __FMA__ inline float sdot_avxfma (const float *a, const float *b, int n); inline double ddot_avxfma (const double *a, const double *b, int n); -inline double sddot_avxfma (const float *a, const float *b, int n); +inline double dsdot_avxfma (const float *a, const float *b, int n); #else inline float sdot_avx (const float *a, const float *b, int n); inline double ddot_avx (const double *a, const double *b, int n); -inline double sddot_avx (const float *a, const float *b, int n); +inline double dsdot_avx (const float *a, const float *b, int n); #endif /*---------------------------------------------------------------------------- @@ -36,6 +42,23 @@ inline float sdot_avxfma (const float *a, const float *b, int n) inline float sdot_avx (const float *a, const float *b, int n) #endif { + // initialize total sum + float s = 0.0f; + + // compute and add up to 7 products without SIMD to achieve alignment + int aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (!aligned) { + int k = 0; + while (!aligned) { + s += (*a) * (*b); + n--; a++; b++; + aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (aligned || (++k > 6) || (n == 0)) + break; + } + } + assert(aligned || (n < 8)); + // initialize 8 sums __m256 s8 = _mm256_setzero_ps(); @@ -60,7 +83,7 @@ inline float sdot_avx (const float *a, const float *b, int n) __m128 sh = _mm_add_ss(_mm256_castps256_ps128(s8), _mm256_extractf128_ps(s8, 1)); #endif - float s = _mm_cvtss_f32(sh); // extract horizontal sum from 1st elem. + s += _mm_cvtss_f32(sh); // extract horizontal sum from 1st elem. // add the remaining products for (int k = 8*(n/8); k < n; k++) @@ -78,6 +101,23 @@ inline double ddot_avxfma (const double *a, const double *b, int n) inline double ddot_avx (const double *a, const double *b, int n) #endif { + // initialize total sum + double s = 0.0; + + // compute and add up to 3 products without SIMD to achieve alignment + int aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (!aligned) { + int k = 0; + while (!aligned) { + s += (*a) * (*b); + n--; a++; b++; + aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (aligned || (++k > 2) || (n == 0)) + break; + } + } + assert(aligned || (n < 4)); + // initialize 4 sums __m256d s4 = _mm256_setzero_pd(); @@ -89,11 +129,12 @@ inline double ddot_avx (const double *a, const double *b, int n) s4 = _mm256_add_pd( _mm256_mul_pd(_mm256_loadu_pd(a+k), _mm256_loadu_pd(b+k)), s4); #endif + // compute horizontal sum __m128d sh = _mm_add_pd(_mm256_extractf128_pd(s4, 0), _mm256_extractf128_pd(s4, 1)); sh = _mm_add_pd(sh, _mm_shuffle_pd(sh, sh, 1)); - double s = _mm_cvtsd_f64(sh); // extract horizontal sum from 1st elem. + s += _mm_cvtsd_f64(sh); // extract horizontal sum from 1st elem. // add the remaining products for (int k = 4*(n/4); k < n; k++) @@ -106,11 +147,28 @@ inline double ddot_avx (const double *a, const double *b, int n) // --- dot product (input: single; intermediate and output: double) #ifdef __FMA__ -inline double sddot_avxfma (const float *a, const float *b, int n) +inline double dsdot_avxfma (const float *a, const float *b, int n) #else -inline double sddot_avx (const float *a, const float *b, int n) +inline double dsdot_avx (const float *a, const float *b, int n) #endif { + // initialize total sum + double s = 0.0; + + // compute and add up to 7 products without SIMD to achieve alignment + int aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (!aligned) { + int k = 0; + while (!aligned) { + s += (*a) * (*b); + n--; a++; b++; + aligned = is_aligned(a, 32) && is_aligned(b, 32); + if (aligned || (++k > 6) || (n == 0)) + break; + } + } + assert(aligned || (n < 8)); + // initialize 4 sums __m256d s4 = _mm256_setzero_pd(); @@ -123,17 +181,18 @@ inline double sddot_avx (const float *a, const float *b, int n) s4 = _mm256_add_pd( _mm256_cvtps_pd(_mm_mul_ps(_mm_loadu_ps(a+k), _mm_loadu_ps(b+k))), s4); #endif + // compute horizontal sum __m128d sh = _mm_add_pd(_mm256_extractf128_pd(s4, 0), _mm256_extractf128_pd(s4, 1)); sh = _mm_add_pd(sh, _mm_shuffle_pd(sh, sh, 1)); - double s = _mm_cvtsd_f64(sh); // extract horizontal sum from 1st elem. + s += _mm_cvtsd_f64(sh); // extract horizontal sum from 1st elem. // add the remaining products for (int k = 4*(n/4); k < n; k++) s += a[k] * b[k]; return s; -} // sddot_avx() +} // dsdot_avx() #endif // DOT_AVX_H diff --git a/src/kloewe/dot/src/dot_avx512.c b/src/kloewe/dot/src/dot_avx512.c new file mode 100644 index 000000000..f8f5bc240 --- /dev/null +++ b/src/kloewe/dot/src/dot_avx512.c @@ -0,0 +1,19 @@ +/*---------------------------------------------------------------------------- + File : dot_avx512.c + Contents: dot product (AVX512-based implementations) + Author : Kristian Loewe +----------------------------------------------------------------------------*/ +#include "dot_avx512.h" + +/*---------------------------------------------------------------------------- + Function Prototypes +----------------------------------------------------------------------------*/ +#ifdef __FMA__ +extern float sdot_avx512fma (const float *a, const float *b, int n); +extern double ddot_avx512fma (const double *a, const double *b, int n); +extern double dsdot_avx512fma (const float *a, const float *b, int n); +#else +extern float sdot_avx512 (const float *a, const float *b, int n); +extern double ddot_avx512 (const double *a, const double *b, int n); +extern double dsdot_avx512 (const float *a, const float *b, int n); +#endif diff --git a/src/kloewe/dot/src/dot_avx512.h b/src/kloewe/dot/src/dot_avx512.h new file mode 100644 index 000000000..c7ecfa9ba --- /dev/null +++ b/src/kloewe/dot/src/dot_avx512.h @@ -0,0 +1,124 @@ +/*---------------------------------------------------------------------------- + File : dot_avx512.h + Contents: dot product (AVX512-based implementations) + Author : Kristian Loewe, Christian Borgelt +----------------------------------------------------------------------------*/ +#ifndef DOT_AVX512_H +#define DOT_AVX512_H + +#ifndef __AVX512F__ +# error "AXV512F is not enabled" +#endif + +#include + +/*---------------------------------------------------------------------------- + Function Prototypes +----------------------------------------------------------------------------*/ +#ifdef __FMA__ +inline float sdot_avx512fma (const float *a, const float *b, int n); +inline double ddot_avx512fma (const double *a, const double *b, int n); +inline double dsdot_avx512fma (const float *a, const float *b, int n); +#else +inline float sdot_avx512 (const float *a, const float *b, int n); +inline double ddot_avx512 (const double *a, const double *b, int n); +inline double dsdot_avx512 (const float *a, const float *b, int n); +#endif + +/*---------------------------------------------------------------------------- + Inline Functions +----------------------------------------------------------------------------*/ + +// --- dot product (single precision) +#ifdef __FMA__ +inline float sdot_avx512fma (const float *a, const float *b, int n) +#else +inline float sdot_avx512 (const float *a, const float *b, int n) +#endif +{ + // initialize 16 sums + __m512 s16 = _mm512_setzero_ps(); + + // in each iteration, add 1 product to each of the 16 sums in parallel + for (int k = 0, nq = 16*(n/16); k < nq; k += 16) + #ifdef __FMA__ + s16 = _mm512_fmadd_ps(_mm512_loadu_ps(a+k), _mm512_loadu_ps(b+k), s16); + #else + s16 = _mm512_add_ps( + _mm512_mul_ps(_mm512_loadu_ps(a+k), _mm512_loadu_ps(b+k)), s16); + #endif + + // compute horizontal sum + float s = _mm512_reduce_add_ps(s16); + + // add the remaining products + for (int k = 16*(n/16); k < n; k++) + s += a[k] * b[k]; + + return s; +} // sdot_avx512() + +/*--------------------------------------------------------------------------*/ + +// --- dot product (double precision) +#ifdef __FMA__ +inline double ddot_avx512fma (const double *a, const double *b, int n) +#else +inline double ddot_avx512 (const double *a, const double *b, int n) +#endif +{ + // initialize 8 sums + __m512d s8 = _mm512_setzero_pd(); + + // in each iteration, add 1 product to each of the 8 sums in parallel + for (int k = 0, nq = 8*(n/8); k < nq; k += 8) + #ifdef __FMA__ + s8 = _mm512_fmadd_pd(_mm512_loadu_pd(a+k), _mm512_loadu_pd(b+k), s8); + #else + s8 = _mm512_add_pd( + _mm512_mul_pd(_mm512_loadu_pd(a+k), _mm512_loadu_pd(b+k)), s8); + #endif + + // compute horizontal sum + double s = _mm512_reduce_add_pd(s8); + + // add the remaining products + for (int k = 8*(n/8); k < n; k++) + s += a[k] * b[k]; + + return s; +} // ddot_avx512() + +/*--------------------------------------------------------------------------*/ + +// --- dot product (input: single; intermediate and output: double) +#ifdef __FMA__ +inline double dsdot_avx512fma (const float *a, const float *b, int n) +#else +inline double dsdot_avx512 (const float *a, const float *b, int n) +#endif +{ + // initialize 8 sums + __m512d s8 = _mm512_setzero_pd(); + + // in each iteration, add 1 product to each of the 4 sums in parallel + for (int k = 0, nq = 8*(n/8); k < nq; k += 8) + #ifdef __FMA__ + s8 = _mm512_fmadd_pd(_mm512_cvtps_pd(_mm256_loadu_ps(a+k)), + _mm512_cvtps_pd(_mm256_loadu_ps(b+k)), s8); + #else + s8 = _mm512_add_pd(_mm512_cvtps_pd( + _mm256_mul_ps(_mm256_loadu_ps(a+k), _mm256_loadu_ps(b+k))), s8); + #endif + + // compute horizontal sum + double s = _mm512_reduce_add_pd(s8); + + // add the remaining products + for (int k = 8*(n/8); k < n; k++) + s += a[k] * b[k]; + + return s; +} // dsdot_avx512() + +#endif // DOT_AVX512_H diff --git a/src/kloewe/dot/src/dot_avxfma.c b/src/kloewe/dot/src/dot_avxfma.c new file mode 100644 index 000000000..5b3626752 --- /dev/null +++ b/src/kloewe/dot/src/dot_avxfma.c @@ -0,0 +1,6 @@ +/*---------------------------------------------------------------------------- + File : dot_avxfma.c + Contents: dot product (AVX-based implementations) + Author : Kristian Loewe +----------------------------------------------------------------------------*/ +#include "dot_avx.c" diff --git a/src/kloewe/dot/src/dot_naive.c b/src/kloewe/dot/src/dot_naive.c index cdab2e9a7..4506bfffc 100644 --- a/src/kloewe/dot/src/dot_naive.c +++ b/src/kloewe/dot/src/dot_naive.c @@ -10,4 +10,4 @@ ----------------------------------------------------------------------------*/ extern float sdot_naive (const float *a, const float *b, int n); extern double ddot_naive (const double *a, const double *b, int n); -extern double sddot_naive (const float *a, const float *b, int n); +extern double dsdot_naive (const float *a, const float *b, int n); diff --git a/src/kloewe/dot/src/dot_naive.h b/src/kloewe/dot/src/dot_naive.h index 00ef1ef4a..754411d6d 100644 --- a/src/kloewe/dot/src/dot_naive.h +++ b/src/kloewe/dot/src/dot_naive.h @@ -11,7 +11,7 @@ ----------------------------------------------------------------------------*/ inline float sdot_naive (const float *a, const float *b, int n); inline double ddot_naive (const double *a, const double *b, int n); -inline double sddot_naive (const float *a, const float *b, int n); +inline double dsdot_naive (const float *a, const float *b, int n); /*---------------------------------------------------------------------------- Inline Functions @@ -52,12 +52,12 @@ inline double sddot_naive (const float *a, const float *b, int n); /*--------------------------------------------------------------------------*/ // --- dot product (input: single; intermediate and output: double) -inline double sddot_naive (const float *a, const float *b, int n) +inline double dsdot_naive (const float *a, const float *b, int n) { double sum = 0; for (int k = 0; k < n; k++) sum += a[k] * b[k]; return sum; -} // sddot_naive() +} // dsdot_naive() #endif // DOT_NAIVE_H diff --git a/src/kloewe/dot/src/dot_sse2.c b/src/kloewe/dot/src/dot_sse2.c index 2c832330a..3fbc699ee 100644 --- a/src/kloewe/dot/src/dot_sse2.c +++ b/src/kloewe/dot/src/dot_sse2.c @@ -10,4 +10,4 @@ ----------------------------------------------------------------------------*/ extern float sdot_sse2 (const float *a, const float *b, int n); extern double ddot_sse2 (const double *a, const double *b, int n); -extern double sddot_sse2 (const float *a, const float *b, int n); +extern double dsdot_sse2 (const float *a, const float *b, int n); diff --git a/src/kloewe/dot/src/dot_sse2.h b/src/kloewe/dot/src/dot_sse2.h index 5b2c05959..b35ea9273 100644 --- a/src/kloewe/dot/src/dot_sse2.h +++ b/src/kloewe/dot/src/dot_sse2.h @@ -1,13 +1,6 @@ /*---------------------------------------------------------------------------- File: dot_sse2.h Contents: dot product (SSE2-based implementations) - - Notes: - On older CPU models such as the Xeon E5440, unaligned load (_mm_loadu_ps) - is significantly slower than aligned load (_mm_load_ps) which is why we - try to avoid it here if possible. On newer CPU models, the AVX version - should be used. - Authors: Kristian Loewe, Christian Borgelt ----------------------------------------------------------------------------*/ #ifndef DOT_SSE2_H @@ -38,7 +31,7 @@ ----------------------------------------------------------------------------*/ inline float sdot_sse2 (const float *a, const float *b, int n); inline double ddot_sse2 (const double *a, const double *b, int n); -inline double sddot_sse2 (const float *a, const float *b, int n); +inline double dsdot_sse2 (const float *a, const float *b, int n); /*---------------------------------------------------------------------------- Inline Functions @@ -48,9 +41,9 @@ inline double sddot_sse2 (const float *a, const float *b, int n); inline float sdot_sse2 (const float *a, const float *b, int n) { // initialize total sum - float s = 0.0; + float s = 0.0f; - // compute and add up to 3 products without SIMD, hoping for alignment + // compute and add up to 3 products without SIMD to achieve alignment int aligned = is_aligned(a, 16) && is_aligned(b, 16); if (!aligned) { int k = 0; @@ -58,7 +51,7 @@ inline float sdot_sse2 (const float *a, const float *b, int n) s += (*a) * (*b); n--; a++; b++; aligned = is_aligned(a, 16) && is_aligned(b, 16); - if (aligned || (++k > 2) || (++k > n)) + if (aligned || (++k > 2) || (n == 0)) break; } } @@ -99,7 +92,7 @@ inline double ddot_sse2 (const double *a, const double *b, int n) // initialize total sum double s = 0.0; - // compute and add up to 1 product without SIMD, hoping for alignment + // compute and add up to 1 product without SIMD to achieve alignment int aligned = is_aligned(a, 16) && is_aligned(b, 16); if (!aligned) { s += (*a) * (*b); @@ -134,12 +127,12 @@ inline double ddot_sse2 (const double *a, const double *b, int n) /*--------------------------------------------------------------------------*/ // --- dot product (input: single; intermediate and output: double) -inline double sddot_sse2 (const float *a, const float *b, int n) +inline double dsdot_sse2 (const float *a, const float *b, int n) { // initialize total sum double s = 0.0; - // compute and add up to 3 products without SIMD, hoping for alignment + // compute and add up to 3 products without SIMD to achieve alignment int aligned = is_aligned(a, 16) && is_aligned(b, 16); if (!aligned) { int k = 0; @@ -147,7 +140,7 @@ inline double sddot_sse2 (const float *a, const float *b, int n) s += (*a) * (*b); n--; a++; b++; aligned = is_aligned(a, 16) && is_aligned(b, 16); - if (aligned || (++k > 2) || (++k > n)) + if (aligned || (++k > 2) || (n == 0)) break; } } @@ -186,6 +179,6 @@ inline double sddot_sse2 (const float *a, const float *b, int n) s += a[k] * b[k]; return s; -} // sddot_sse2() +} // dsdot_sse2() #endif // DOT_SSE2_H -- GitLab From 7335c69c0e647ffe95c217ca8dbae329d60bad25 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Wed, 15 Nov 2017 18:33:14 -0600 Subject: [PATCH 473/755] a quick guess at mac compilation error with newer cmake --- src/kloewe/dot/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kloewe/dot/CMakeLists.txt b/src/kloewe/dot/CMakeLists.txt index 5da60db96..2e4a40892 100644 --- a/src/kloewe/dot/CMakeLists.txt +++ b/src/kloewe/dot/CMakeLists.txt @@ -78,7 +78,7 @@ else() target_compile_options(dot_avx512 PRIVATE -mavx512f -funroll-loops) target_compile_definitions(dot PRIVATE "DOT_NOFMA") else() - target_compile_definitions(dot PRIVATE "DOT_NOFMA DOT_NOAVX512") + target_compile_definitions(dot PRIVATE "DOT_NOFMA" "DOT_NOAVX512") endif() target_compile_options(dot_avx PRIVATE -mavx -funroll-loops) target_compile_options(dot_sse2 PRIVATE -msse2) -- GitLab From 51134b1893e831c6afbc6fddfb86842916277eca Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 16 Nov 2017 16:58:12 -0600 Subject: [PATCH 474/755] some copy paste errors in -cifti-parcellate argument handling --- src/Algorithms/AlgorithmCiftiParcellate.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Algorithms/AlgorithmCiftiParcellate.cxx b/src/Algorithms/AlgorithmCiftiParcellate.cxx index 14c6922e1..66c2eedfe 100644 --- a/src/Algorithms/AlgorithmCiftiParcellate.cxx +++ b/src/Algorithms/AlgorithmCiftiParcellate.cxx @@ -194,7 +194,7 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog thisStore = &rightStore; thisWeights = &rightWeights; thisSurfOpt = rightSurfOpt; - thisMetricOpt = cerebMetricOpt; + thisMetricOpt = rightMetricOpt; break; case 2: thisStore = &cerebStore; @@ -205,7 +205,7 @@ void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, Prog } if (thisMetricOpt->m_present) { - *thisWeights = leftMetricOpt->getMetric(1); + *thisWeights = thisMetricOpt->getMetric(1); } if (thisSurfOpt->m_present) { -- GitLab From c176ae4a3cdedc78dfc48fc62864a04a85320971 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Nov 2017 09:22:12 -0600 Subject: [PATCH 475/755] Resolve WB-758 Spec File vs Scene File when Zipping Scene File: When searching for the base directory, DO NOT include the name of the spec file. --- src/Files/SceneFile.cxx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 3366dc108..66b98865a 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -875,6 +875,8 @@ SceneFile::findBaseDirectoryForDataFiles() const { std::set directoryNames; + const bool includeSpecFileFlag = false; + /** * Find all 'path name' elements from ALL scenes */ @@ -894,8 +896,14 @@ SceneFile::findBaseDirectoryForDataFiles() const * specFile is named "specFileName" * and these names are unique to name of files in the spec file */ - if ((sceneObject->getName() == "fileName") - || (sceneObject->getName() == "specFileName")) { + bool useNameFlag = false; + if (sceneObject->getName() == "fileName") { + useNameFlag = true; + } + else if (sceneObject->getName() == "specFileName") { + useNameFlag = includeSpecFileFlag; + } + if (useNameFlag) { const AString pathName = scenePathName->stringValue().trimmed(); if ( ! pathName.isEmpty()) { FileInformation fileInfo(pathName); -- GitLab From ec676aec3894d0f2385dfc5a45007793890e77c1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Nov 2017 11:52:59 -0600 Subject: [PATCH 476/755] Resolve WB-757 BALSA Upload Dialog Items: (1) Indicate the BALSA Upload Processing Step may take a long time; (2) If user logs in successfully but has not agreed to BALSA Submitter terms, a button has been added to the error message dialog that goes to the BALSA Submitter page in the user's web browser; (3) If user fails to login, display a useful error message dialog that informs the user to use the links for register, forgot username, forgot password on the Upload dialog. --- src/GuiQt/BalsaDatabaseManager.cxx | 15 ++++- .../BalsaDatabaseUploadSceneFileDialog.cxx | 17 +++++- src/GuiQt/WuQMessageBox.cxx | 58 +++++++++++++++++++ src/GuiQt/WuQMessageBox.h | 5 ++ 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 2b1a6fa21..35390b333 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -58,7 +58,7 @@ using namespace caret; BalsaDatabaseManager::BalsaDatabaseManager() : CaretObject() { - m_debugFlag = false; + m_debugFlag = true; logout(); //EventManager::get()->addEventListener(this, EventTypeEnum::); } @@ -160,6 +160,17 @@ BalsaDatabaseManager::login(const AString& databaseURL, return true; } + else if (loginResponse.m_responseCode == 302) { + errorMessageOut = ("Login failed.

" + "If you are unable to login, helpful links are located on the right side of the username and password boxes:" + "

    " + "
  • Register: Click to create a BALSA account" + "
  • Forgot Username: Click to get your username by entering your email address" + "
  • Forgot Password: Click to reset your password by entering your username" + "
"); + logout(); + return false; + } loginResponse.m_body.push_back('\0'); const AString responseContent(&loginResponse.m_body[0]); @@ -1363,7 +1374,7 @@ BalsaDatabaseManager::uploadZippedSceneFile(SceneFile* sceneFile, /* * Process the uploaded file */ - progressUpdate.setProgress(PROGRESS_PROCESS_UPLOAD, "Processing uploaded zip file"); + progressUpdate.setProgress(PROGRESS_PROCESS_UPLOAD, "Processing uploaded zip file (this step may take a long time)"); EventManager::get()->sendEvent(progressUpdate.getPointer()); const AString processUploadURL(m_databaseURL diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index a859af4ab..1cb7fc127 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -588,7 +588,7 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() "OK", "OK, Go to BALSA in Web Browser"); if ( ! okPressedFlag) { - labelHtmlLinkClicked("/"); + labelHtmlLinkClicked("about/submission"); } return; } @@ -829,6 +829,21 @@ BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked(bool /*checked*/) void BalsaDatabaseUploadSceneFileDialog::testButtonClicked() { + const int32_t buttonIndex = WuQMessageBox::informationTwoButtons(this, + "You have not agreed to Submitter Terms", + "OK", + "OK, View Terms in Web Browser"); + switch (buttonIndex) { + case 1: + break; + case 2: + labelHtmlLinkClicked("about/submission"); + break; + default: + CaretAssert(0); + } + return; + bool testRolesFlag = false; bool testNewIDsFlag = true; if (testRolesFlag) { diff --git a/src/GuiQt/WuQMessageBox.cxx b/src/GuiQt/WuQMessageBox.cxx index e69890356..f86a06cfb 100644 --- a/src/GuiQt/WuQMessageBox.cxx +++ b/src/GuiQt/WuQMessageBox.cxx @@ -504,6 +504,64 @@ WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, return yesPressedFlag; } +/** + * Display an information dialog with two buttons, both of which + * will close the dialog. + * + * @param parent + * The parent dialog. + * @param text + * Text for the dialog. + * @param buttonOneText + * Text for the first button. + * @param buttonTwoText + * Text for the second button. + * @return + * 1 if button one clicked, 2 if button two clicked. + */ +int32_t +WuQMessageBox::informationTwoButtons(QWidget* parent, + const QString& text, + const QString& buttonOneText, + const QString& buttonTwoText) +{ + QMessageBox msgBox(parent); + msgBox.setIcon(QMessageBox::Information); + msgBox.setWindowTitle(""); + msgBox.setText(text); + msgBox.addButton(QMessageBox::YesToAll); + msgBox.addButton(QMessageBox::Yes); + msgBox.setDefaultButton(QMessageBox::Yes); + + WuQMessageBox::updateButtonText(msgBox, + QMessageBox::YesToAll, + buttonOneText); + WuQMessageBox::updateButtonText(msgBox, + QMessageBox::Yes, + buttonTwoText); + + + QMessageBox::StandardButton buttonPressed = + static_cast(msgBox.exec()); + + + int32_t buttonClicked = 0; + switch (buttonPressed) { + case QMessageBox::YesToAll: + buttonClicked = 1; + break; + case QMessageBox::Yes: + buttonClicked = 2; + break; + default: + CaretAssert(0); + break; + } + + return buttonClicked; +} + + /** * Display a Yes to All, Yes, No, button dialog. * diff --git a/src/GuiQt/WuQMessageBox.h b/src/GuiQt/WuQMessageBox.h index 2db2364c0..93033f147 100644 --- a/src/GuiQt/WuQMessageBox.h +++ b/src/GuiQt/WuQMessageBox.h @@ -52,6 +52,11 @@ namespace caret { static void informationOk(QWidget* parent, const QString& text); + static int32_t informationTwoButtons(QWidget* parent, + const QString& text, + const QString& buttonOneText, + const QString& buttonTwoText); + static void warningOk(QWidget* parent, const QString& text); -- GitLab From 2ec3d83dfc257cb8d5d2a73589a1c698d8bb3c09 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Nov 2017 14:31:19 -0600 Subject: [PATCH 477/755] WB-760: Copy/Move Annotations Dialog Bug Fixes: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This dialog is used to copy or move annotations between files and is launched from the ‘sprocket’ button on the Save/Manage Files Dialog. * For the Destination File Selection: If “New File Name†button is clicked, automatically select the corresponding radio button. * Fixed “Close Source File After Copying Data†when the Source File is the Scene Annotations. --- src/Brain/Brain.cxx | 20 ++++++++++++++++++-- src/GuiQt/DataFileContentCopyMoveDialog.cxx | 9 +++++---- src/GuiQt/DataFileContentCopyMoveDialog.h | 3 +++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 69ac360e8..7a35c9784 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -6585,7 +6585,10 @@ Brain::removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile) const bool wasRemoved = removeWithoutDeleteDataFilePrivate(caretDataFile); if (wasRemoved) { - m_specFile->removeCaretDataFile(caretDataFile); + /* Scene annotation file is NOT in the spec file */ + if (caretDataFile != m_sceneAnnotationFile) { + m_specFile->removeCaretDataFile(caretDataFile); + } updateAfterFilesAddedOrRemoved(); } @@ -6627,6 +6630,12 @@ Brain::removeWithoutDeleteDataFilePrivate(const CaretDataFile* caretDataFile) return true; } + if (caretDataFile == m_sceneAnnotationFile) { + m_sceneAnnotationFile->clear(); + m_sceneAnnotationFile->clearModified(); + return true; + } + std::vector::iterator borderIterator = std::find(m_borderFiles.begin(), m_borderFiles.end(), caretDataFile); @@ -6799,7 +6808,14 @@ bool Brain::removeAndDeleteDataFile(CaretDataFile* caretDataFile) { if (removeWithoutDeleteDataFile(caretDataFile)) { - delete caretDataFile; + /* NEVER delete scene annotation file */ + if (caretDataFile == m_sceneAnnotationFile) { + m_sceneAnnotationFile->clear(); + m_sceneAnnotationFile->clearModified(); + } + else { + delete caretDataFile; + } return true; } diff --git a/src/GuiQt/DataFileContentCopyMoveDialog.cxx b/src/GuiQt/DataFileContentCopyMoveDialog.cxx index 0fe33cbbd..b29715d71 100644 --- a/src/GuiQt/DataFileContentCopyMoveDialog.cxx +++ b/src/GuiQt/DataFileContentCopyMoveDialog.cxx @@ -135,7 +135,7 @@ DataFileContentCopyMoveDialog::createOptionsWidget() QObject::connect(m_closeSourceFileCheckBox, SIGNAL(toggled(bool)), this, SLOT(closeSourceFileCheckBoxToggled(bool))); - m_copySelectedAnnotationsOnlyCheckBox = new QCheckBox("Copy Only Selected Annotations"); + m_copySelectedAnnotationsOnlyCheckBox = new QCheckBox("Copy Only Annotations SELECTED FOR EDITING"); m_copySelectedAnnotationsOnlyCheckBox->setChecked(false); QGroupBox* groupBox = new QGroupBox("Options"); @@ -194,8 +194,8 @@ DataFileContentCopyMoveDialog::createDestinationWidget() newDestinationFileToolButton->setText("New File Name..."); m_newDestinationFileNameLabel = new QLabel(" "); m_newDestinatonFileButtonGroupIndex = m_destinationButtonGroup->buttons().size(); - QRadioButton* newFileRadioButton = new QRadioButton(""); - m_destinationButtonGroup->addButton(newFileRadioButton, + m_newDestinationFileRadioButton = new QRadioButton(""); + m_destinationButtonGroup->addButton(m_newDestinationFileRadioButton, m_newDestinatonFileButtonGroupIndex); @@ -210,7 +210,7 @@ DataFileContentCopyMoveDialog::createDestinationWidget() while (buttonIter.hasNext()) { const int row = layout->rowCount(); QAbstractButton* button = buttonIter.next(); - if (button == newFileRadioButton) { + if (button == m_newDestinationFileRadioButton) { layout->addWidget(button, row, 0); layout->addWidget(newDestinationFileToolButton, @@ -242,6 +242,7 @@ DataFileContentCopyMoveDialog::newDestinationFileToolButtonClicked() m_newDestinationFileName = fileName; FileInformation fileInfo(fileName); m_newDestinationFileNameLabel->setText(fileInfo.getFileName()); + m_newDestinationFileRadioButton->setChecked(true); } } diff --git a/src/GuiQt/DataFileContentCopyMoveDialog.h b/src/GuiQt/DataFileContentCopyMoveDialog.h index fe23492cd..a27fd3dd7 100644 --- a/src/GuiQt/DataFileContentCopyMoveDialog.h +++ b/src/GuiQt/DataFileContentCopyMoveDialog.h @@ -27,6 +27,7 @@ class QButtonGroup; class QCheckBox; class QLabel; +class QRadioButton; namespace caret { @@ -79,6 +80,8 @@ namespace caret { QString m_newDestinationFileName; + QRadioButton* m_newDestinationFileRadioButton; + QCheckBox* m_closeSourceFileCheckBox; QCheckBox* m_copySelectedAnnotationsOnlyCheckBox; -- GitLab From fd90fd460dc6db1096c896dda73b1f5e9018c09f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 17 Nov 2017 14:31:57 -0600 Subject: [PATCH 478/755] =?UTF-8?q?WB-759:=20Add=20Scene=20Number=20to=20S?= =?UTF-8?q?cene=20Dialog:=20There=20are=20many=20times=20that=20I=20want?= =?UTF-8?q?=20to=20load=20scene=20by=20number=20when=20starting=20wb=5Fvie?= =?UTF-8?q?w.=20=20Adding=20the=20scene=E2=80=99s=20number=20on=20the=20Sc?= =?UTF-8?q?ene=20File=20dialog=20will=20simplify=20identifying=20the=20sce?= =?UTF-8?q?ne=E2=80=99s=20number,=20especially=20when=20there=20are=20many?= =?UTF-8?q?=20scenes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/GuiQt/SceneDialog.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index b28fade28..d4c8d3449 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2893,8 +2893,9 @@ SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(const SceneInfo nameTextOut = ("" + indexText - + "NAME" - + ": " + + "NAME (" + + AString::number(sceneIndex + 1) + + "): " + name + ""); -- GitLab From 5f86fe421c63eeae3708ea341366328e135014be Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Dec 2017 11:09:09 -0600 Subject: [PATCH 479/755] Updating with copy from my repository that fixes this error: Resolve WB-762 wb_view New BALSA submitter upload Add/Choose/Rename button bug: When the user has no studies do not display error message, but show study dialog so that user can add a new study. --- src/GuiQt/BalsaDatabaseManager.cxx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 35390b333..f97e51f8a 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -58,7 +58,7 @@ using namespace caret; BalsaDatabaseManager::BalsaDatabaseManager() : CaretObject() { - m_debugFlag = true; + m_debugFlag = false; logout(); //EventManager::get()->addEventListener(this, EventTypeEnum::); } @@ -1250,15 +1250,12 @@ BalsaDatabaseManager::getAllStudyInformation(std::vector& } } } - - if (studyInformationOut.empty()) { - errorMessageOut = "No study information was found."; - return false; + + if ( ! studyInformationOut.empty()) { + std::sort(studyInformationOut.begin(), + studyInformationOut.end()); } - std::sort(studyInformationOut.begin(), - studyInformationOut.end()); - return true; } -- GitLab From 6c99f181359c59a90273a14680f8f58b5f6ff47e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Dec 2017 14:37:58 -0600 Subject: [PATCH 480/755] Resolve WB-763: Add information on Balsa Upload's Advance Tab: Descriptions on usage of a Custom Zip File Directory and a Custom Base Path have been added. --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 53 +++++++++++++++++-- .../BalsaDatabaseUploadSceneFileDialog.h | 4 ++ src/GuiQt/SceneBasePathWidget.cxx | 46 +++++++++++++++- src/GuiQt/SceneBasePathWidget.h | 4 ++ 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 1cb7fc127..cad27fe56 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -23,8 +23,10 @@ #include "BalsaDatabaseUploadSceneFileDialog.h" #undef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ +#include #include #include +#include #include #include #include @@ -421,7 +423,14 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QWidget* BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() { - m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("Use System Temporary Directory"); + QLabel* zipInfoLabel = new QLabel("When the Scene File is uploaded to BALSA, the Scene File and all data files that it " + "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " + "While unlikely, creation of the ZIP file in the system temporary directory could " + "fail if there is insuffient space. If this should happend, set a CUSTOM directory " + "on a disk with adequate space other than the disk containing the system temporary directory."); + zipInfoLabel->setWordWrap(true); + + m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("System Temporary"); m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); QButtonGroup* buttGroup = new QButtonGroup(this); @@ -431,8 +440,17 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), [=](int id){ this->zipFileDirectoryRadioButtonClicked(id); }); + m_zipFileAutomaticDirectoryLineEdit = new QLineEdit(); + m_zipFileAutomaticDirectoryLineEdit->setReadOnly(true); + m_zipFileAutomaticDirectoryLineEdit->setText(SystemUtilities::getTempDirectory()); + m_zipFileCustomDirectoryLineEdit = new QLineEdit(); + QPushButton* copyAutomaticDirectoryPushButton = new QPushButton("Copy"); + QObject::connect(copyAutomaticDirectoryPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked); + copyAutomaticDirectoryPushButton->setToolTip("Copy system temporary directory to clipboard"); + QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); @@ -444,16 +462,28 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; - gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, 0, 0, 1, 3); - gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, 1, 0); - gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, 1, 1); - gridLayout->addWidget(browseCustomDirectoryPushButton, 1, 2); + gridLayout->addWidget(zipInfoLabel, row, 0, 1, 3); + row++; + gridLayout->addWidget(new QLabel(" "), row, 0, 1, 3); + row++; + gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, row, 0); + gridLayout->addWidget(m_zipFileAutomaticDirectoryLineEdit, row, 1); + gridLayout->addWidget(copyAutomaticDirectoryPushButton, row, 2); + row++; + gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, row, 0); + gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, row, 1); + gridLayout->addWidget(browseCustomDirectoryPushButton, row, 2); row++; m_basePathWidget = new SceneBasePathWidget(); + QLabel* infoLabel = new QLabel("NOTE: In most instances, the default selections (System Temporary for Zip File Directory and " + "Automatic for Base Path) should be used."); + infoLabel->setWordWrap(true); + QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addWidget(infoLabel); layout->addWidget(zipDirectoryGroupBox); layout->addWidget(m_basePathWidget); layout->addStretch(); @@ -924,6 +954,19 @@ BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() } } +/** + * Copy automatic directory to clipboard + */ +void +BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked() +{ + const QString txt = m_zipFileAutomaticDirectoryLineEdit->text().trimmed(); + if ( ! txt.isEmpty()) { + QApplication::clipboard()->setText(txt, + QClipboard::Clipboard); + } +} + /** * Choose the custom directory */ diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index c401c2631..f9775f155 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -72,6 +72,8 @@ namespace caret { void zipFileDirectoryRadioButtonClicked(int); + void copyAutomaticDirectoryPushButtonClicked(); + void browseZipFileCustomDirectoryPushButtonClicked(); void testButtonClicked(); @@ -142,6 +144,8 @@ namespace caret { QRadioButton* m_zipFileTemporaryDirectoryRadioButton; QRadioButton* m_zipFileCustomDirectoryRadioButton; + + QLineEdit* m_zipFileAutomaticDirectoryLineEdit; QLineEdit* m_zipFileCustomDirectoryLineEdit; QLabel* m_extractDirectoryNameLabel; diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index 491fe2d90..b8239b080 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -19,9 +19,12 @@ */ /*LICENSE_END*/ +#include #include +#include #include #include +#include #include #include #include @@ -55,7 +58,16 @@ using namespace caret; SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) : QWidget(widget) { + QLabel* basePathInfoLabel = new QLabel("The Base Path is the \"lowest level\" path that contains the Scene File and " + "all data files referenced by the Scene File. It is typically used when creating a " + "ZIP file. A ZIP file may never reference files in a directory \"above\" the " + "ZIP file's location."); + basePathInfoLabel->setWordWrap(true); + m_automaticRadioButton = new QRadioButton("Automatic"); + m_automaticBasePathLineEdit = new QLineEdit; + m_automaticBasePathLineEdit->setReadOnly(true); + m_customRadioButton = new QRadioButton("Custom"); QButtonGroup* buttGroup = new QButtonGroup(this); @@ -67,6 +79,11 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) m_basePathLineEdit = new QLineEdit; m_basePathLineEdit->setReadOnly(true); + QPushButton* copyAutoBasePathPushButton = new QPushButton("Copy"); + copyAutoBasePathPushButton->setToolTip("Copy automatic base path to clipboard"); + QObject::connect(copyAutoBasePathPushButton, &QPushButton::clicked, + this, &SceneBasePathWidget::copyAutoBasePathToClipboard); + QPushButton* browsePushButton = new QPushButton("Browse..."); QObject::connect(browsePushButton, &QPushButton::clicked, this, &SceneBasePathWidget::browseButtonClicked); @@ -78,8 +95,18 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; + gridLayout->addWidget(basePathInfoLabel, + row, 0, 1, 3); + row++; + gridLayout->addWidget(new QLabel(" "), + row, 0); + row++; gridLayout->addWidget(m_automaticRadioButton, - row, 0, 1, 2, Qt::AlignLeft); + row, 0); + gridLayout->addWidget(m_automaticBasePathLineEdit, + row, 1); + gridLayout->addWidget(copyAutoBasePathPushButton, + row, 2); row++; gridLayout->addWidget(m_customRadioButton, row, 0); @@ -114,6 +141,8 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) { m_sceneFile = sceneFile; + m_automaticBasePathLineEdit->clear(); + if (m_sceneFile != NULL) { m_basePathLineEdit->setText(m_sceneFile->getBalsaBaseDirectory()); switch (m_sceneFile->getBasePathType()) { @@ -126,6 +155,8 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) m_basePathLineEdit->setEnabled(true); break; } + + m_automaticBasePathLineEdit->setText(m_sceneFile->findBaseDirectoryForDataFiles()); setEnabled(true); } else { @@ -134,6 +165,19 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) } } +/** + * Copy the automatic base path to the clipboard + */ +void +SceneBasePathWidget::copyAutoBasePathToClipboard() +{ + const QString txt = m_automaticBasePathLineEdit->text().trimmed(); + if ( ! txt.isEmpty()) { + QApplication::clipboard()->setText(txt, + QClipboard::Clipboard); + } +} + /** * Gets called when the browse button is clicked. */ diff --git a/src/GuiQt/SceneBasePathWidget.h b/src/GuiQt/SceneBasePathWidget.h index ae641b018..059350119 100644 --- a/src/GuiQt/SceneBasePathWidget.h +++ b/src/GuiQt/SceneBasePathWidget.h @@ -55,6 +55,8 @@ namespace caret { private slots: void browseButtonClicked(); + void copyAutoBasePathToClipboard(); + void basePathTypeButtonGroupClicked(QAbstractButton* button); private: @@ -70,6 +72,8 @@ namespace caret { QRadioButton* m_customRadioButton; + QLineEdit* m_automaticBasePathLineEdit; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 34f83ffc62cdbeae34aea4712b2bec7a099f78a5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 21 Dec 2017 14:06:27 -0600 Subject: [PATCH 481/755] Updates to BALSA Upload Dialog, primarily to the Advanced Tab of the dialog. --- src/Common/CaretPreferences.cxx | 25 ++ src/Common/CaretPreferences.h | 8 + src/GuiQt/BalsaDatabaseManager.cxx | 8 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 214 +++++++++++++++--- .../BalsaDatabaseUploadSceneFileDialog.h | 8 + src/GuiQt/SceneBasePathWidget.cxx | 38 +++- src/GuiQt/SceneBasePathWidget.h | 2 + 7 files changed, 254 insertions(+), 49 deletions(-) diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 48534171e..0038e6882 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -1068,6 +1068,29 @@ CaretPreferences::setRemoteFileUserNameAndPassword(const AString& userName, this->qSettings->sync(); } +/** + * @return The BALSA username + */ +AString +CaretPreferences::getBalsaUserName() const +{ + return this->balsaUserName; +} + +/** + * Set the BALSA username + * + * @param userName + * New value for BALSA username. + */ +void +CaretPreferences::setBalsaUserName(const AString& userName) +{ + this->balsaUserName = userName; + this->setString(NAME_BALSA_USER_NAME, + userName); +} + /** * @return Are axes crosshairs displayed? */ @@ -1497,6 +1520,8 @@ CaretPreferences::readPreferences() this->remoteFileLoginSaved = this->getBoolean(NAME_REMOTE_FILE_LOGIN_SAVED, false); + this->balsaUserName = this->getString(NAME_BALSA_USER_NAME); + this->showSurfaceIdentificationSymbols = this->getBoolean(NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS, true); this->showVolumeIdentificationSymbols = this->getBoolean(NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS, diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index 916e58594..20db3f72b 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -159,6 +159,10 @@ namespace caret { void setRemoteFileUserNameAndPassword(const AString& userName, const AString& password); + AString getBalsaUserName() const; + + void setBalsaUserName(const AString& userName); + static void byteRgbToFloatRgb(const uint8_t byteRGB[3], float floatRGB[3]); @@ -287,9 +291,12 @@ namespace caret { AString remoteFilePassword; bool remoteFileLoginSaved; + AString balsaUserName; + SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType; static const AString NAME_ANIMATION_START_TIME; + static const AString NAME_BALSA_USER_NAME; static const AString NAME_VOLUME_AXES_CROSSHAIRS; static const AString NAME_VOLUME_AXES_LABELS; static const AString NAME_VOLUME_AXES_COORDINATE; @@ -331,6 +338,7 @@ namespace caret { #ifdef __CARET_PREFERENCES_DECLARE__ const AString CaretPreferences::NAME_ANIMATION_START_TIME = "animationStartTime"; + const AString CaretPreferences::NAME_BALSA_USER_NAME = "balsaUserName"; const AString CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS = "volumeAxesCrosshairs"; const AString CaretPreferences::NAME_VOLUME_AXES_LABELS = "volumeAxesLabels"; const AString CaretPreferences::NAME_VOLUME_AXES_COORDINATE = "volumeAxesCoordinates"; diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index f97e51f8a..101a11f31 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -507,7 +507,13 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, successFlag = true; } catch (const CaretException& e) { - errorMessageOut = e.whatString(); + AString moreInfo("If there was an error creating the ZIP file, " + "it may caused by incorrect permissions or insufficient space in the " + "temporary directory used for creating the ZIP file. Use the ZIP File Directory Custom option " + "in the Advanced Tab to choose an alternative directory."); + errorMessageOut = (moreInfo + + "\n\n" + + e.whatString()); } return successFlag; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index cad27fe56..c564abf48 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -48,6 +48,7 @@ #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretPointer.h" +#include "CaretPreferences.h" #include "CursorDisplayScoped.h" #include "DataFileException.h" #include "FileInformation.h" @@ -55,6 +56,7 @@ #include "ProgressReportingDialog.h" #include "SceneBasePathWidget.h" #include "SceneFile.h" +#include "SessionManager.h" #include "SystemUtilities.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" @@ -86,6 +88,10 @@ BalsaDatabaseUploadSceneFileDialog::BalsaDatabaseUploadSceneFileDialog(SceneFile m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); + + if (s_username.isEmpty()) { + s_username = SessionManager::get()->getCaretPreferences()->getBalsaUserName(); + } m_userRoles.reset(new BalsaUserRoles); @@ -152,16 +158,16 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() /* * Database selection */ - m_databaseLabel = new QLabel(""); - m_databaseComboBox = new QComboBox(); - m_databaseComboBox->setEditable(true); - m_databaseComboBox->addItem("https://balsa.wustl.edu"); - m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); - m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); - QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), - this, [=] { this->loginInformationChanged(); }); - QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, - this, [=] { this->loginInformationChanged(); }); +// m_databaseLabel = new QLabel(""); +// m_databaseComboBox = new QComboBox(); +// m_databaseComboBox->setEditable(true); +// m_databaseComboBox->addItem("https://balsa.wustl.edu"); +// m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); +// m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); +// QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), +// this, [=] { this->loginInformationChanged(); }); +// QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, +// this, [=] { this->loginInformationChanged(); }); const int minimumLineEditWidth = 250; @@ -236,9 +242,9 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() const int COLUMN_DATA_WIDGET_ONE = columnCounter++; const int COLUMN_DATA_WIDGET_TWO = columnCounter++; const int COLUMN_BUTTON_ONE = columnCounter++; - //const int COLUMN_BUTTON_TWO = columnCounter++; + const int COLUMN_BUTTON_TWO = columnCounter++; - QGroupBox* groupBox = new QGroupBox("Database Login"); + QGroupBox* groupBox = new QGroupBox("BALSA Login"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(5); gridLayout->setColumnStretch(COLUMN_LABEL, 0); @@ -247,13 +253,12 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); //gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; - gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET_ONE, 1, 2); - gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE); - row++; +// gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); +// gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET_ONE, 1, 2); gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); - gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_ONE); + gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE); + gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_TWO); row++; gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); @@ -340,7 +345,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() /** * Select Study Push Button */ - m_selectStudyTitlePushButton = new QPushButton("Add/Choose/Rename..."); + m_selectStudyTitlePushButton = new QPushButton("Create/Select/Rename..."); m_selectStudyTitlePushButton->setToolTip("Add new study, choose a study, or edit a study's title in BALSA Database"); QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); @@ -384,9 +389,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; - gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); - gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); - row++; gridLayout->addWidget(m_balsaStudyTitleLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(m_selectStudyTitlePushButton, row, COLUMN_BUTTON_ONE, 1, 2); @@ -395,11 +397,14 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(testPushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; + gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); + row++; gridLayout->addWidget(m_autoSaveSceneFileCheckBox, row, COLUMN_DATA_WIDGET, 1, 3, Qt::AlignLeft); row++; - gridLayout->setRowMinimumHeight(row, 10); // empty row + gridLayout->setRowMinimumHeight(row, 15); // empty row row++; - gridLayout->addWidget(m_uploadPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignLeft); + gridLayout->addWidget(m_uploadPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignHCenter); row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); @@ -418,18 +423,55 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() } /** - * @return New instance of the advanced tab + * @return A new BALSA Database selection widget */ QWidget* -BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() +BalsaDatabaseUploadSceneFileDialog::createBalsaDatabaseSelectionWidget() { - QLabel* zipInfoLabel = new QLabel("When the Scene File is uploaded to BALSA, the Scene File and all data files that it " - "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " - "While unlikely, creation of the ZIP file in the system temporary directory could " - "fail if there is insuffient space. If this should happend, set a CUSTOM directory " - "on a disk with adequate space other than the disk containing the system temporary directory."); - zipInfoLabel->setWordWrap(true); + /* + * Database selection + */ + m_databaseLabel = new QLabel(""); + m_databaseComboBox = new QComboBox(); + m_databaseComboBox->setEditable(true); + m_databaseComboBox->addItem("https://balsa.wustl.edu"); + m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); + m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); + QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), + this, [=] { this->loginInformationChanged(); }); + QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, + this, [=] { this->loginInformationChanged(); }); + + QPushButton* whatsThisPushButton = new QPushButton("What's this?"); + whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); + QObject::connect(whatsThisPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::whatsThisDatabase); + + int columnCounter = 0; + const int COLUMN_LABEL = columnCounter++; + const int COLUMN_WIDGET = columnCounter++; + QGroupBox* groupBox = new QGroupBox("BALSA Database"); + QGridLayout* gridLayout = new QGridLayout(groupBox); + gridLayout->setSpacing(5); + gridLayout->setColumnStretch(COLUMN_LABEL, 0); + gridLayout->setColumnStretch(COLUMN_WIDGET, 100); + int row = 0; + gridLayout->addWidget(whatsThisPushButton, row, COLUMN_LABEL, 1, 2, Qt::AlignLeft); + row++; + gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); + gridLayout->addWidget(m_databaseComboBox, row, COLUMN_WIDGET); + row++; + + return groupBox; +} + +/** + * @return A new ZIP file directory widget + */ +QWidget* +BalsaDatabaseUploadSceneFileDialog::creatZipFileDirectoryWidget() +{ m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("System Temporary"); m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); @@ -445,7 +487,7 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() m_zipFileAutomaticDirectoryLineEdit->setText(SystemUtilities::getTempDirectory()); m_zipFileCustomDirectoryLineEdit = new QLineEdit(); - + QPushButton* copyAutomaticDirectoryPushButton = new QPushButton("Copy"); QObject::connect(copyAutomaticDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked); @@ -455,6 +497,11 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); + QPushButton* whatsThisPushButton = new QPushButton("What's this?"); + whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); + QObject::connect(whatsThisPushButton, &QPushButton::clicked, + this, &BalsaDatabaseUploadSceneFileDialog::whatsThisZipFileDirectory); + QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); gridLayout->setSpacing(2); @@ -462,9 +509,7 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; - gridLayout->addWidget(zipInfoLabel, row, 0, 1, 3); - row++; - gridLayout->addWidget(new QLabel(" "), row, 0, 1, 3); + gridLayout->addWidget(whatsThisPushButton, row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, row, 0); gridLayout->addWidget(m_zipFileAutomaticDirectoryLineEdit, row, 1); @@ -475,6 +520,69 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() gridLayout->addWidget(browseCustomDirectoryPushButton, row, 2); row++; + return zipDirectoryGroupBox; +} + +/** + * @return New instance of the advanced tab + */ +QWidget* +BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() +{ +// QLabel* zipInfoLabel = new QLabel("When the Scene File is uploaded to BALSA, the Scene File and all data files that it " +// "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " +// "While unlikely, creation of the ZIP file in the system temporary directory could " +// "fail if there is insuffient space. If this should happend, set a CUSTOM directory " +// "on a disk with adequate space other than the disk containing the system temporary directory."); +// zipInfoLabel->setWordWrap(true); +// +// m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("System Temporary"); +// m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); +// +// QButtonGroup* buttGroup = new QButtonGroup(this); +// buttGroup->addButton(m_zipFileTemporaryDirectoryRadioButton); +// buttGroup->addButton(m_zipFileCustomDirectoryRadioButton); +// m_zipFileTemporaryDirectoryRadioButton->setChecked(true); // do before signal +// QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), +// [=](int id){ this->zipFileDirectoryRadioButtonClicked(id); }); +// +// m_zipFileAutomaticDirectoryLineEdit = new QLineEdit(); +// m_zipFileAutomaticDirectoryLineEdit->setReadOnly(true); +// m_zipFileAutomaticDirectoryLineEdit->setText(SystemUtilities::getTempDirectory()); +// +// m_zipFileCustomDirectoryLineEdit = new QLineEdit(); +// +// QPushButton* copyAutomaticDirectoryPushButton = new QPushButton("Copy"); +// QObject::connect(copyAutomaticDirectoryPushButton, &QPushButton::clicked, +// this, &BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked); +// copyAutomaticDirectoryPushButton->setToolTip("Copy system temporary directory to clipboard"); +// +// QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); +// QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, +// this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); +// +// QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); +// QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); +// gridLayout->setSpacing(2); +// gridLayout->setColumnStretch(0, 0); +// gridLayout->setColumnStretch(1, 100); +// gridLayout->setColumnStretch(2, 0); +// int row = 0; +// gridLayout->addWidget(zipInfoLabel, row, 0, 1, 3); +// row++; +// gridLayout->addWidget(new QLabel(" "), row, 0, 1, 3); +// row++; +// gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, row, 0); +// gridLayout->addWidget(m_zipFileAutomaticDirectoryLineEdit, row, 1); +// gridLayout->addWidget(copyAutomaticDirectoryPushButton, row, 2); +// row++; +// gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, row, 0); +// gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, row, 1); +// gridLayout->addWidget(browseCustomDirectoryPushButton, row, 2); +// row++; + + QWidget* databaseSelectionWidget = createBalsaDatabaseSelectionWidget(); + QWidget* zipDirectoryWidget = creatZipFileDirectoryWidget(); m_basePathWidget = new SceneBasePathWidget(); QLabel* infoLabel = new QLabel("NOTE: In most instances, the default selections (System Temporary for Zip File Directory and " @@ -484,8 +592,9 @@ BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(infoLabel); - layout->addWidget(zipDirectoryGroupBox); layout->addWidget(m_basePathWidget); + layout->addWidget(zipDirectoryWidget); + layout->addWidget(databaseSelectionWidget); layout->addStretch(); return widget; @@ -638,6 +747,8 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() m_uploadPushButton->setEnabled(true); m_selectStudyTitlePushButton->setEnabled(true); + + SessionManager::get()->getCaretPreferences()->setBalsaUserName(username); } /** @@ -1096,7 +1207,7 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) break; case LabelName::LABEL_EXTRACT_DIRECTORY: label = m_extractDirectoryNameLabel; - labelText = "Extract to Directory"; + labelText = "Unzip into Directory"; validFlag = m_extractDirectoryNameLineEdit->hasAcceptableInput(); break; case LabelName::LABEL_PASSWORD: @@ -1152,3 +1263,32 @@ BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) CaretAssert(label); label->setText(coloredText); } + +/** + * Displays a dialog explaining the ZIP file directory options + */ +void +BalsaDatabaseUploadSceneFileDialog::whatsThisZipFileDirectory() +{ + const AString text("When a Scene File is uploaded to BALSA, the Scene File and all data files that it " + "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " + "While unlikely, creation of the ZIP file in the system temporary directory could fail " + "if there is insufficient space. If this should happen, set a CUSTOM directory on a disk " + "with adequate space."); + WuQMessageBox::informationOk(this, + text); +} + +/** + * Displays a dialog explaining the database selection option + */ +void +BalsaDatabaseUploadSceneFileDialog::whatsThisDatabase() +{ + const AString text("This option is provided for developers of " + "Workbench (wb_view and wb_command) and BALSA Database software. " + "It allows the selection of develpment versions of the BALSA Database."); + WuQMessageBox::informationOk(this, + text); +} + diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index f9775f155..0dbcde011 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -82,6 +82,10 @@ namespace caret { virtual void cancelButtonClicked(); + void whatsThisZipFileDirectory(); + + void whatsThisDatabase(); + protected: private: @@ -106,6 +110,10 @@ namespace caret { QWidget* createAdvancedTab(); + QWidget* createBalsaDatabaseSelectionWidget(); + + QWidget* creatZipFileDirectoryWidget(); + void loadSceneFileMetaDataWidgets(); AString getDataBaseURL() const; diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index b8239b080..4dae5dc46 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include "CaretFileDialog.h" #include "FileInformation.h" #include "SceneFile.h" +#include "WuQMessageBox.h" using namespace caret; @@ -58,12 +60,6 @@ using namespace caret; SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) : QWidget(widget) { - QLabel* basePathInfoLabel = new QLabel("The Base Path is the \"lowest level\" path that contains the Scene File and " - "all data files referenced by the Scene File. It is typically used when creating a " - "ZIP file. A ZIP file may never reference files in a directory \"above\" the " - "ZIP file's location."); - basePathInfoLabel->setWordWrap(true); - m_automaticRadioButton = new QRadioButton("Automatic"); m_automaticBasePathLineEdit = new QLineEdit; m_automaticBasePathLineEdit->setReadOnly(true); @@ -88,6 +84,11 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) QObject::connect(browsePushButton, &QPushButton::clicked, this, &SceneBasePathWidget::browseButtonClicked); + QPushButton* whatsThisPushButton = new QPushButton("What's this?"); + whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); + QObject::connect(whatsThisPushButton, &QPushButton::clicked, + this, &SceneBasePathWidget::whatsThisBasePath); + QGroupBox* groupBox = new QGroupBox("Base Path"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(2); @@ -95,11 +96,8 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; - gridLayout->addWidget(basePathInfoLabel, - row, 0, 1, 3); - row++; - gridLayout->addWidget(new QLabel(" "), - row, 0); + gridLayout->addWidget(whatsThisPushButton, + row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_automaticRadioButton, row, 0); @@ -271,4 +269,22 @@ SceneBasePathWidget::isValid(AString& errorMessageOut) const return (errorMessageOut.isEmpty()); } +/** + * Displays a dialog explaining base path options + */ +void +SceneBasePathWidget::whatsThisBasePath() +{ + const AString text("The Automatic Base Path is the \"lowest level\" path that contains the Scene File and " + "all data files referenced by the Scene File. " + "The directory structure of all files contained in the Scene File relative (at or below) " + "the Base Path will be preserved in your dataset when it is downloaded from BALSA and " + "unzipped by other users. You may set a Custom path above the Automatic Base Path, but " + "it will add additional, unnecessary path layers to the unzipped dataset."); + WuQMessageBox::informationOk(this, + text); + +} + + diff --git a/src/GuiQt/SceneBasePathWidget.h b/src/GuiQt/SceneBasePathWidget.h index 059350119..e04ceb419 100644 --- a/src/GuiQt/SceneBasePathWidget.h +++ b/src/GuiQt/SceneBasePathWidget.h @@ -59,6 +59,8 @@ namespace caret { void basePathTypeButtonGroupClicked(QAbstractButton* button); + void whatsThisBasePath(); + private: SceneBasePathWidget(const SceneBasePathWidget&); -- GitLab From 43302e52f4534436bf93fddc66d236dd68c96e8a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 21 Dec 2017 15:54:33 -0600 Subject: [PATCH 482/755] For zipping a scene file, the extract to directory now defaults to the last sub-directory in the default base path found for the scene file. Previously it was the last sub-directory in the path of the scene file. --- src/Files/SceneFile.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 66b98865a..ddd3afdb5 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -935,17 +935,17 @@ SceneFile::getDefaultZipFileName() const } /** - * @return The default extract to directory name (directory containing the scene file, EXCLUDING THE PATH) + * @return The default extract to directory name (end of default base directory) */ AString SceneFile::getDefaultExtractToDirectoryName() const { AString directoryName; - FileInformation fileInfo(getFileName()); - AString sceneFileDirectory = fileInfo.getAbsolutePath(); - if ( ! sceneFileDirectory.isEmpty()) { - QDir dir(sceneFileDirectory); + FileInformation fileInfo(findBaseDirectoryForDataFiles()); + AString baseDirectory = fileInfo.getAbsoluteFilePath(); + if ( ! baseDirectory.isEmpty()) { + QDir dir(baseDirectory); directoryName = dir.dirName(); } -- GitLab From b2d137f30014e5680cc4315498f06d33f5ee5fb0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Dec 2017 10:30:26 -0600 Subject: [PATCH 483/755] Added a method to get the fully qualified local host name to SystemUtilities. --- src/Common/SystemUtilities.cxx | 35 ++++++++++++++++++++++++++++++++++ src/Common/SystemUtilities.h | 3 +++ 2 files changed, 38 insertions(+) diff --git a/src/Common/SystemUtilities.cxx b/src/Common/SystemUtilities.cxx index a467f0afc..386baeaee 100644 --- a/src/Common/SystemUtilities.cxx +++ b/src/Common/SystemUtilities.cxx @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -653,3 +654,37 @@ SystemUtilities::getWorkbenchHome() return workbenchHomeDirectory = QDir::toNativeSeparators(workbenchHomeDirectory); } +/** + * @return The fully qualifed domain name for the local host. + * + * If failure, an empty string is returned and a message + * is sent to the logger. + * + * If the address is a "loopback" (127.0.0.1) it typically + * indicates that there is not a valid network connection + * and an empty string is returned and a message is logged. + */ +AString +SystemUtilities::getLocalHostName() +{ + QString hostName; + + QHostInfo hostInfo = QHostInfo::fromName(QHostInfo::localHostName()); + if (hostInfo.error() == QHostInfo::NoError) { + for (auto address : hostInfo.addresses()) { + if (address.isLoopback()) { + CaretLogFine("Lookup of host found loopback address (localhost). May not have valid network connection"); + return ""; + } + } + hostName = hostInfo.hostName(); + } + else { + CaretLogWarning("Lookup of local host name failed: " + + hostInfo.errorString()); + } + + return hostName; +} + + diff --git a/src/Common/SystemUtilities.h b/src/Common/SystemUtilities.h index 7a4f8e6a4..2035bff99 100644 --- a/src/Common/SystemUtilities.h +++ b/src/Common/SystemUtilities.h @@ -100,6 +100,9 @@ public: static void sleepSeconds(const float numberOfSeconds); static AString getWorkbenchHome(); + + static AString getLocalHostName(); + }; } // namespace -- GitLab From e2323f60ec3747470b862e634e09da0e5fd4267e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Dec 2017 10:33:08 -0600 Subject: [PATCH 484/755] In Upload to Balsa Database dialog's database selection combo box, list the testing versions of BALSA database only if in a WUSTL domain. --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 84 +++---------------- 1 file changed, 10 insertions(+), 74 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index c564abf48..677c70bed 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -155,20 +155,6 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() */ m_balsaDatabaseManager = std::unique_ptr(new BalsaDatabaseManager()); - /* - * Database selection - */ -// m_databaseLabel = new QLabel(""); -// m_databaseComboBox = new QComboBox(); -// m_databaseComboBox->setEditable(true); -// m_databaseComboBox->addItem("https://balsa.wustl.edu"); -// m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); -// m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); -// QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), -// this, [=] { this->loginInformationChanged(); }); -// QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, -// this, [=] { this->loginInformationChanged(); }); - const int minimumLineEditWidth = 250; /* @@ -251,10 +237,7 @@ BalsaDatabaseUploadSceneFileDialog::createLoginWidget() gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_ONE, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_TWO, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); - //gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; -// gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); -// gridLayout->addWidget(m_databaseComboBox, row, COLUMN_DATA_WIDGET_ONE, 1, 2); gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE); @@ -428,6 +411,9 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() QWidget* BalsaDatabaseUploadSceneFileDialog::createBalsaDatabaseSelectionWidget() { + QString hostName = SystemUtilities::getLocalHostName(); + const bool isWustlDomainFlag = hostName.endsWith(".wustl.edu"); + /* * Database selection */ @@ -435,8 +421,10 @@ BalsaDatabaseUploadSceneFileDialog::createBalsaDatabaseSelectionWidget() m_databaseComboBox = new QComboBox(); m_databaseComboBox->setEditable(true); m_databaseComboBox->addItem("https://balsa.wustl.edu"); - m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); - m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); + if (isWustlDomainFlag) { + m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); + m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); + } QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), this, [=] { this->loginInformationChanged(); }); QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, @@ -529,64 +517,11 @@ BalsaDatabaseUploadSceneFileDialog::creatZipFileDirectoryWidget() QWidget* BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() { -// QLabel* zipInfoLabel = new QLabel("When the Scene File is uploaded to BALSA, the Scene File and all data files that it " -// "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " -// "While unlikely, creation of the ZIP file in the system temporary directory could " -// "fail if there is insuffient space. If this should happend, set a CUSTOM directory " -// "on a disk with adequate space other than the disk containing the system temporary directory."); -// zipInfoLabel->setWordWrap(true); -// -// m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("System Temporary"); -// m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); -// -// QButtonGroup* buttGroup = new QButtonGroup(this); -// buttGroup->addButton(m_zipFileTemporaryDirectoryRadioButton); -// buttGroup->addButton(m_zipFileCustomDirectoryRadioButton); -// m_zipFileTemporaryDirectoryRadioButton->setChecked(true); // do before signal -// QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), -// [=](int id){ this->zipFileDirectoryRadioButtonClicked(id); }); -// -// m_zipFileAutomaticDirectoryLineEdit = new QLineEdit(); -// m_zipFileAutomaticDirectoryLineEdit->setReadOnly(true); -// m_zipFileAutomaticDirectoryLineEdit->setText(SystemUtilities::getTempDirectory()); -// -// m_zipFileCustomDirectoryLineEdit = new QLineEdit(); -// -// QPushButton* copyAutomaticDirectoryPushButton = new QPushButton("Copy"); -// QObject::connect(copyAutomaticDirectoryPushButton, &QPushButton::clicked, -// this, &BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked); -// copyAutomaticDirectoryPushButton->setToolTip("Copy system temporary directory to clipboard"); -// -// QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); -// QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, -// this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); -// -// QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); -// QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); -// gridLayout->setSpacing(2); -// gridLayout->setColumnStretch(0, 0); -// gridLayout->setColumnStretch(1, 100); -// gridLayout->setColumnStretch(2, 0); -// int row = 0; -// gridLayout->addWidget(zipInfoLabel, row, 0, 1, 3); -// row++; -// gridLayout->addWidget(new QLabel(" "), row, 0, 1, 3); -// row++; -// gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, row, 0); -// gridLayout->addWidget(m_zipFileAutomaticDirectoryLineEdit, row, 1); -// gridLayout->addWidget(copyAutomaticDirectoryPushButton, row, 2); -// row++; -// gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, row, 0); -// gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, row, 1); -// gridLayout->addWidget(browseCustomDirectoryPushButton, row, 2); -// row++; - QWidget* databaseSelectionWidget = createBalsaDatabaseSelectionWidget(); QWidget* zipDirectoryWidget = creatZipFileDirectoryWidget(); m_basePathWidget = new SceneBasePathWidget(); - QLabel* infoLabel = new QLabel("NOTE: In most instances, the default selections (System Temporary for Zip File Directory and " - "Automatic for Base Path) should be used."); + QLabel* infoLabel = new QLabel("NOTE: In most instances, the default selections should be used."); infoLabel->setWordWrap(true); QWidget* widget = new QWidget; @@ -1287,7 +1222,8 @@ BalsaDatabaseUploadSceneFileDialog::whatsThisDatabase() { const AString text("This option is provided for developers of " "Workbench (wb_view and wb_command) and BALSA Database software. " - "It allows the selection of develpment versions of the BALSA Database."); + "It allows the selection of develpment versions of the BALSA Database. " + "To add a database, type the new name into the combo box."); WuQMessageBox::informationOk(this, text); } -- GitLab From 11099a3dd443d54e71551fcc964033ce2f628989 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Dec 2017 14:28:54 -0600 Subject: [PATCH 485/755] Added a method to SceneFile to get the base directory and all of its ancestor directories. --- src/Files/SceneFile.cxx | 35 +++++++++++++++++++++++++++++++++++ src/Files/SceneFile.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index ddd3afdb5..cb11caacc 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -925,6 +925,41 @@ SceneFile::findBaseDirectoryForDataFiles() const return baseDirectoryName; } +/** + * @return The base directory for all data files and all of + * the base directorys ancestors (parent directory + * up to root directory). + * + * @param maximumAncestorCount + * Maximum number of ancestor directories for output + */ +std::vector +SceneFile::getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount) +{ + std::vector names; + + AString baseDirectoryName = findBaseDirectoryForDataFiles(); + if ( ! baseDirectoryName.isEmpty()) { + QDir dir(baseDirectoryName); + + for (int32_t i = 0; i < maximumAncestorCount; i++) { + names.push_back(dir.absolutePath()); + + if (dir.isRoot()) { + break; + } + else { + if ( ! dir.cdUp()) { + break; + } + } + } + } + + return names; +} + + /** * @return Default name for a ZIP file containing the scene file and its data files. */ diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index f3b0eb7cf..dc4bc2d55 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -102,6 +102,8 @@ namespace caret { AString findBaseDirectoryForDataFiles() const; + std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 15); + void reorderScenes(std::vector& orderedScenes); int32_t getSceneIndexFromNumberOrName(const AString& numberOrName); -- GitLab From d35868727299fbef931389fe97cd6fa7e59464aa Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 22 Dec 2017 14:32:51 -0600 Subject: [PATCH 486/755] Updated the BALSA Upload Dialog and the ZIP Scene File Dialogs: Changed "custom base path" to a combo box and by default it contains the base path and its ancestor directories. There is still a "browse" button the user can use to choose an alternative base path. If the "browse" button is used, the user is (1) warned that an invalid base path will cause zipping of the scene file to fail; and (2) the "browse" button should only be used in the event (which is unlikely to occur) the automatic base path search fails. --- src/GuiQt/BalsaDatabaseManager.cxx | 7 +- src/GuiQt/SceneBasePathWidget.cxx | 106 +++++++++++++++++++++++------ src/GuiQt/SceneBasePathWidget.h | 11 ++- 3 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 101a11f31..4214d3cc9 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -507,13 +507,14 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, successFlag = true; } catch (const CaretException& e) { - AString moreInfo("If there was an error creating the ZIP file, " + AString moreInfo("If there was an error opening or writing to the ZIP file, " "it may caused by incorrect permissions or insufficient space in the " "temporary directory used for creating the ZIP file. Use the ZIP File Directory Custom option " "in the Advanced Tab to choose an alternative directory."); - errorMessageOut = (moreInfo + errorMessageOut = ("Error: " + + e.whatString() + "\n\n" - + e.whatString()); + + moreInfo); } return successFlag; diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index 4dae5dc46..99a00fa34 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -39,6 +39,7 @@ #include "CaretFileDialog.h" #include "FileInformation.h" #include "SceneFile.h" +#include "WuQFactory.h" #include "WuQMessageBox.h" using namespace caret; @@ -72,17 +73,19 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](QAbstractButton* button){ this->basePathTypeButtonGroupClicked(button); }); - m_basePathLineEdit = new QLineEdit; - m_basePathLineEdit->setReadOnly(true); + m_customBasePathComboBox = WuQFactory::newComboBox(); + m_customBasePathComboBox->setEditable(false); + QObject::connect(m_customBasePathComboBox, static_cast(&QComboBox::activated), + this, [=](int index){ this->customPathComboBoxActivated(index); }); QPushButton* copyAutoBasePathPushButton = new QPushButton("Copy"); copyAutoBasePathPushButton->setToolTip("Copy automatic base path to clipboard"); QObject::connect(copyAutoBasePathPushButton, &QPushButton::clicked, this, &SceneBasePathWidget::copyAutoBasePathToClipboard); - QPushButton* browsePushButton = new QPushButton("Browse..."); - QObject::connect(browsePushButton, &QPushButton::clicked, - this, &SceneBasePathWidget::browseButtonClicked); + QPushButton* customBrowsePushButton = new QPushButton("Browse..."); + QObject::connect(customBrowsePushButton, &QPushButton::clicked, + this, &SceneBasePathWidget::customBrowseButtonClicked); QPushButton* whatsThisPushButton = new QPushButton("What's this?"); whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); @@ -108,9 +111,9 @@ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) row++; gridLayout->addWidget(m_customRadioButton, row, 0); - gridLayout->addWidget(m_basePathLineEdit, + gridLayout->addWidget(m_customBasePathComboBox, row, 1); - gridLayout->addWidget(browsePushButton, + gridLayout->addWidget(customBrowsePushButton, row, 2); QVBoxLayout* widgetLayout = new QVBoxLayout(this); @@ -141,16 +144,48 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) m_automaticBasePathLineEdit->clear(); + QSignalBlocker customPathSignalBlocker(m_customBasePathComboBox); + if (m_sceneFile != NULL) { - m_basePathLineEdit->setText(m_sceneFile->getBalsaBaseDirectory()); + AString baseDirectoryName = m_sceneFile->getBalsaBaseDirectory(); + m_customBasePathComboBox->clear(); + + const std::vector dirNames = m_sceneFile->getBaseDirectoryHierarchyForDataFiles(); + if ( ! baseDirectoryName.isEmpty()) { + /* + * If the base directory is in neither the base path hierarchy + * nor the user custom paths, add it to the user custom paths + * so that it appears in the combo box and is selected. + */ + if (std::find(dirNames.begin(), + dirNames.end(), + baseDirectoryName) == dirNames.end()) { + if (std::find(s_userCustomBasePaths.begin(), + s_userCustomBasePaths.end(), + baseDirectoryName) == s_userCustomBasePaths.end()) { + s_userCustomBasePaths.push_back(baseDirectoryName); + } + } + } + for (auto name : s_userCustomBasePaths) { + m_customBasePathComboBox->addItem(name); + } + for (auto name : dirNames) { + m_customBasePathComboBox->addItem(name); + } + + if ( ! baseDirectoryName.isEmpty()) { + m_customBasePathComboBox->setCurrentText(baseDirectoryName); + } + switch (m_sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: m_automaticRadioButton->setChecked(true); - m_basePathLineEdit->setEnabled(false); + m_customBasePathComboBox->setEnabled(false); break; case SceneFileBasePathTypeEnum::CUSTOM: m_customRadioButton->setChecked(true); - m_basePathLineEdit->setEnabled(true); + m_customBasePathComboBox->setEnabled(true); break; } @@ -158,7 +193,7 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) setEnabled(true); } else { - m_basePathLineEdit->setText(""); + m_customBasePathComboBox->clear(); setEnabled(false); } } @@ -177,35 +212,66 @@ SceneBasePathWidget::copyAutoBasePathToClipboard() } /** - * Gets called when the browse button is clicked. + * Called when the user selects and item in the custom + * path combo box. + * + * @param index + * Index of the item selected. + */ +void +SceneBasePathWidget::customPathComboBoxActivated(int index) +{ + const AString text = m_customBasePathComboBox->itemText(index); + if ( ! text.isEmpty()) { + m_sceneFile->setBalsaBaseDirectory(text); + } +} + + +/** + * Gets called when the custom browse button is clicked. */ void -SceneBasePathWidget::browseButtonClicked() +SceneBasePathWidget::customBrowseButtonClicked() { + const AString msg("The only reason to use this Browse button is when the Automatic mode fails. " + "If you select a base path that is a not a parent directory of the " + "scene file and its data files, zipping of the scene file and its " + "data files will fail.\n\n" + "Do you want to continue?"); + if ( ! WuQMessageBox::warningOkCancel(this, msg)) { + return; + } + CaretAssert(m_sceneFile); /* * Let user choose directory path */ QString directoryName; - FileInformation fileInfo(m_basePathLineEdit->text().trimmed()); + FileInformation fileInfo(m_customBasePathComboBox->currentText().trimmed()); if (fileInfo.exists()) { if (fileInfo.isDirectory()) { directoryName = fileInfo.getAbsoluteFilePath(); } } - AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(this, - "Choose Base Path", - directoryName); + const AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(this, + "Choose Base Path", + directoryName); /* * If user cancels, return */ if (newDirectoryName.isEmpty()) { return; } - - m_sceneFile->setBalsaBaseDirectory(newDirectoryName); + + if (std::find(s_userCustomBasePaths.begin(), + s_userCustomBasePaths.end(), + newDirectoryName) == s_userCustomBasePaths.end()) { + s_userCustomBasePaths.push_back(newDirectoryName); + } m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); + m_sceneFile->setBalsaBaseDirectory(newDirectoryName); updateWithSceneFile(m_sceneFile); } @@ -246,7 +312,7 @@ SceneBasePathWidget::isValid(AString& errorMessageOut) const /* valid */ } else if (m_customRadioButton->isChecked()) { - const AString basePath = m_basePathLineEdit->text().trimmed(); + const AString basePath = m_customBasePathComboBox->currentText().trimmed(); if (basePath.isEmpty()) { errorMessageOut = "CUSTOM base path is empty."; } diff --git a/src/GuiQt/SceneBasePathWidget.h b/src/GuiQt/SceneBasePathWidget.h index e04ceb419..b1f8bd5e1 100644 --- a/src/GuiQt/SceneBasePathWidget.h +++ b/src/GuiQt/SceneBasePathWidget.h @@ -28,6 +28,7 @@ #include class QAbstractButton; +class QComboBox; class QLineEdit; class QRadioButton; @@ -53,7 +54,9 @@ namespace caret { // ADD_NEW_METHODS_HERE private slots: - void browseButtonClicked(); + void customBrowseButtonClicked(); + + void customPathComboBoxActivated(int index); void copyAutoBasePathToClipboard(); @@ -68,7 +71,7 @@ namespace caret { SceneFile* m_sceneFile = NULL; - QLineEdit* m_basePathLineEdit; + QComboBox* m_customBasePathComboBox; QRadioButton* m_automaticRadioButton; @@ -76,12 +79,14 @@ namespace caret { QLineEdit* m_automaticBasePathLineEdit; + static std::vector s_userCustomBasePaths; + // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_BASE_PATH_WIDGET_DECLARE__ - // + std::vector SceneBasePathWidget::s_userCustomBasePaths; #endif // __SCENE_BASE_PATH_WIDGET_DECLARE__ } // namespace -- GitLab From 8fea6ddb1f973c77b5343adf662ddb2caa7deaee Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 28 Dec 2017 14:52:32 -0600 Subject: [PATCH 487/755] When searching for the default base path for a scene file, ignore files on the network (http://, ftp://) since they are not on the local file system. Otherwise, the default base path will be empty. In the event all files are on the network, the base path will be the directory containing the scene file. Also, minor correction to text for Base Path What's This?. --- src/Files/SceneFile.cxx | 20 +++++++++++++++----- src/GuiQt/SceneBasePathWidget.cxx | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index cb11caacc..49fde7dbc 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -906,10 +906,15 @@ SceneFile::findBaseDirectoryForDataFiles() const if (useNameFlag) { const AString pathName = scenePathName->stringValue().trimmed(); if ( ! pathName.isEmpty()) { - FileInformation fileInfo(pathName); - const AString dirName = fileInfo.getAbsolutePath().trimmed(); - if ( ! dirName.isEmpty()) { - directoryNames.insert(dirName); + /* + * Need to ignore file on the network + */ + if ( ! DataFile::isFileOnNetwork(pathName)) { + FileInformation fileInfo(pathName); + const AString dirName = fileInfo.getAbsolutePath().trimmed(); + if ( ! dirName.isEmpty()) { + directoryNames.insert(dirName); + } } } } @@ -920,7 +925,12 @@ SceneFile::findBaseDirectoryForDataFiles() const const std::vector stringVector(directoryNames.begin(), directoryNames.end()); - const AString baseDirectoryName = AString::findLongestCommonPrefix(stringVector); + AString baseDirectoryName = AString::findLongestCommonPrefix(stringVector); + + if (baseDirectoryName.isEmpty()) { + FileInformation fileInfo(getFileName()); + baseDirectoryName = fileInfo.getAbsolutePath(); + } return baseDirectoryName; } diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index 99a00fa34..4be5f0181 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -343,7 +343,7 @@ SceneBasePathWidget::whatsThisBasePath() { const AString text("The Automatic Base Path is the \"lowest level\" path that contains the Scene File and " "all data files referenced by the Scene File. " - "The directory structure of all files contained in the Scene File relative (at or below) " + "The directory structure of all files contained in the Scene File relative to (at or below) " "the Base Path will be preserved in your dataset when it is downloaded from BALSA and " "unzipped by other users. You may set a Custom path above the Automatic Base Path, but " "it will add additional, unnecessary path layers to the unzipped dataset."); -- GitLab From 9512e6bf11a9141b4e4a8e8603cdb861c5ad00f0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 26 Oct 2017 09:07:48 -0500 Subject: [PATCH 488/755] Added Graphics directory to Doxyfile --- Doxyfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Doxyfile b/Doxyfile index 1d0e24be8..632e830f7 100644 --- a/Doxyfile +++ b/Doxyfile @@ -43,6 +43,7 @@ INPUT = \ src/FilesBase \ src/FtglFont \ src/Gifti \ + src/Graphics \ src/GuiQt \ src/Nifti \ src/OSMesaDummy \ -- GitLab From 74b4f5f9184e6a9bd888742a6d4981fab6f128f6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 26 Oct 2017 14:29:18 -0500 Subject: [PATCH 489/755] Continuing development of line drawing with polygons (OpenGL lines are limited in width, typically 10 pixels) --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 83 +-- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 119 +++-- src/Common/DeveloperFlagsEnum.cxx | 8 +- src/Common/DeveloperFlagsEnum.h | 1 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 486 ++++++++++++++---- src/Graphics/GraphicsOpenGLLineDrawing.h | 89 +++- 6 files changed, 589 insertions(+), 197 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index ebb02dd9c..9df93433e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1248,9 +1248,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * select annotation that are inside of the box */ const float slightlyThicker = 2.0; - BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - selectionColorRGBA, - outlineWidth + slightlyThicker); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + /* + * For testing new line drawing + * Width not limited to OpenGL min/max + */ + float widthPixels = (box->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + coords, selectionColorRGBA, widthPixels); + } + else { + BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, + selectionColorRGBA, + outlineWidth + slightlyThicker); + } } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -1269,18 +1280,19 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil if (drawForegroundFlag) { const bool drawOutlineWithPolygonsFlag = true; if (drawOutlineWithPolygonsFlag) { - BrainOpenGLPrimitiveDrawing::drawRectangleOutline(bottomLeft, bottomRight, topRight, topLeft, - outlineWidth, - foregroundRGBA); - - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - const bool testLineDrawingFlag = false; - if (testLineDrawingFlag) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + /* + * For testing new line drawing + * Width not limited to OpenGL min/max + */ float widthPixels = (box->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLineLoopSolidColor(coords, foregroundRGBA, widthPixels); + GraphicsOpenGLLineDrawing::drawLineLoopSolidFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + coords, foregroundRGBA, widthPixels); + } + else { + BrainOpenGLPrimitiveDrawing::drawRectangleOutline(bottomLeft, bottomRight, topRight, topLeft, + outlineWidth, + foregroundRGBA); } } else { @@ -2767,9 +2779,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - BrainOpenGLPrimitiveDrawing::drawLines(coords, - selectionColorRGBA, - backgroundLineWidth); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + /* + * For testing new line drawing + * Width not limited to OpenGL min/max + */ + float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + GraphicsOpenGLLineDrawing::drawLinesSolidByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + coords, selectionColorRGBA, widthPixels); + } + else { + BrainOpenGLPrimitiveDrawing::drawLines(coords, + selectionColorRGBA, + backgroundLineWidth); + } m_selectionInfo.push_back(SelectionInfo(annotationFile, line, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, @@ -2777,20 +2800,22 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi } else { if (drawForegroundFlag) { - BrainOpenGLPrimitiveDrawing::drawLines(coords, - foregroundRGBA, - lineWidth); - drawnFlag = true; - - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - const bool testLineDrawingFlag = false; - if (testLineDrawingFlag) { + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + /* + * For testing new line drawing + * Width not limited to OpenGL min/max + */ float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLinesSolidColor(coords, floatForegroundRGBA, widthPixels); + GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + coords, floatForegroundRGBA, widthPixels); + } + else { + BrainOpenGLPrimitiveDrawing::drawLines(coords, + foregroundRGBA, + lineWidth); } + + drawnFlag = true; } } diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index e58300a4e..297a4dc9e 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -48,6 +48,7 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" +#include "GraphicsOpenGLLineDrawing.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "IdentificationWithColor.h" @@ -3597,42 +3598,100 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) glColor3fv(CaretColorEnum::toRGB(outlineColor)); m_fixedPipelineDrawing->setLineWidth(thickness); - /* - * Examine each triangle to see if it intersects the Plane - * in which the slice exists. - */ - glBegin(GL_LINES); - for (int it = 0; it < numTriangles; it++) { - const int32_t* triangleNodes = surface->getTriangle(it); - const float* c1 = surface->getCoordinate(triangleNodes[0]); - const float* c2 = surface->getCoordinate(triangleNodes[1]); - const float* c3 = surface->getCoordinate(triangleNodes[2]); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + std::vector lineXYZ; + std::vector lineRGBA; - if (plane.triangleIntersectPlane(c1, c2, c3, - intersectionPoint1, - intersectionPoint2)) { - if (surfaceColorFlag) { - /* - * Use coloring assigned to the first node in the triangle - * but only if Alpha is valid (greater than zero). - */ - const int64_t colorIndex = triangleNodes[0] * 4; - if (nodeColoringRGBA[colorIndex + 3] > 0.0) { - glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); - } - else { - continue; + /* + * Examine each triangle to see if it intersects the Plane + * in which the slice exists. + */ + for (int it = 0; it < numTriangles; it++) { + const int32_t* triangleNodes = surface->getTriangle(it); + const float* c1 = surface->getCoordinate(triangleNodes[0]); + const float* c2 = surface->getCoordinate(triangleNodes[1]); + const float* c3 = surface->getCoordinate(triangleNodes[2]); + + if (plane.triangleIntersectPlane(c1, c2, c3, + intersectionPoint1, + intersectionPoint2)) { + if (surfaceColorFlag) { + const int32_t rgbaOffset = triangleNodes[0] * 4; + /* + * Use coloring assigned to the first node in the triangle + * but only if Alpha is valid (greater than zero). + */ + if (nodeColoringRGBA[rgbaOffset + 3] <= 0.0f) { + continue; + } + lineRGBA.insert(lineRGBA.end(), &nodeColoringRGBA[rgbaOffset], &nodeColoringRGBA[rgbaOffset] + 4); + lineRGBA.insert(lineRGBA.end(), &nodeColoringRGBA[rgbaOffset], &nodeColoringRGBA[rgbaOffset] + 4); } + lineXYZ.insert(lineXYZ.end(), intersectionPoint1, intersectionPoint1 + 3); + lineXYZ.insert(lineXYZ.end(), intersectionPoint2, intersectionPoint2 + 3); } + } + + GLboolean depthTestFlag = GL_FALSE; + glGetBooleanv(GL_DEPTH_TEST, &depthTestFlag); + glDisable(GL_DEPTH_TEST); + float widthPixels = thickness; + if (surfaceColorFlag) { + GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + lineXYZ, + lineRGBA, + widthPixels); + } + else { + float rgba[4] = { 1.0, 0.0, 0.0, 1.0 }; + CaretColorEnum::toRGBAFloat(outlineColor, rgba); + GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + lineXYZ, + rgba, + widthPixels); + } + if (depthTestFlag) { + glEnable(GL_DEPTH_TEST); + } + } + else { + /* + * Examine each triangle to see if it intersects the Plane + * in which the slice exists. + */ + glBegin(GL_LINES); + for (int it = 0; it < numTriangles; it++) { + const int32_t* triangleNodes = surface->getTriangle(it); + const float* c1 = surface->getCoordinate(triangleNodes[0]); + const float* c2 = surface->getCoordinate(triangleNodes[1]); + const float* c3 = surface->getCoordinate(triangleNodes[2]); - /* - * Draw the line where the triangle intersections the slice - */ - glVertex3fv(intersectionPoint1); - glVertex3fv(intersectionPoint2); + if (plane.triangleIntersectPlane(c1, c2, c3, + intersectionPoint1, + intersectionPoint2)) { + if (surfaceColorFlag) { + /* + * Use coloring assigned to the first node in the triangle + * but only if Alpha is valid (greater than zero). + */ + const int64_t colorIndex = triangleNodes[0] * 4; + if (nodeColoringRGBA[colorIndex + 3] > 0.0) { + glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); + } + else { + continue; + } + } + + /* + * Draw the line where the triangle intersections the slice + */ + glVertex3fv(intersectionPoint1); + glVertex3fv(intersectionPoint2); + } } + glEnd(); } - glEnd(); } } } diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 2da2da524..941abeffb 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -95,6 +95,9 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, case DEVELOPER_FLAG_UNUSED: this->flagStatus = false; break; + case DEVELOPER_FLAG_NEW_LINE_DRAWING: + this->flagStatus = true; + break; } } @@ -118,7 +121,10 @@ DeveloperFlagsEnum::initialize() enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, "DEVELOPER_FLAG_UNUSED", - "Developer flag unused")); + "Developer Flag Unused")); + enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_LINE_DRAWING, + "DEVELOPER_FLAG_NEW_LINE_DRAWING", + "Developer Flag New Line Drawing")); } /** diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index bb21cda89..1263b7662 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -36,6 +36,7 @@ public: */ enum Enum { DEVELOPER_FLAG_UNUSED, + DEVELOPER_FLAG_NEW_LINE_DRAWING }; ~DeveloperFlagsEnum(); diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index b13c94568..f1f6d8ca7 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -27,8 +27,11 @@ #include "CaretAssert.h" #include "CaretLogger.h" +#include "GraphicsEngineDataOpenGL.h" #include "CaretOpenGLInclude.h" #include "GraphicsPrimitive.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -57,10 +60,14 @@ GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() /** * Constructor. * + * @param openglContextPointer + * Pointer to OpenGL context. * @param xyz * The XYZ vertices. - * @param rgba - * The RGBA coloring. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. * @param lineThicknessPixels * Thickness of lines in pixels. * @param colorType @@ -68,14 +75,17 @@ GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() * @param lineType * Type of lines drawn. */ -GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -: m_inputPrimitive(NULL), +GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +: m_openglContextPointer(openglContextPointer), m_inputXYZ(xyz), -m_inputRGBA(rgba), +m_inputFloatRGBA(floatRGBA), +m_inputByteRGBA(byteRGBA), m_lineThicknessPixels(lineThicknessPixels), m_colorType(colorType), m_lineType(lineType) @@ -83,11 +93,43 @@ m_lineType(lineType) } +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0.0, 1.0] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels) +{ + std::vector emptyByteRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, + rgba, + emptyByteRGBA, + lineThicknessPixels, + ColorType::FLOAT_RGBA_PER_VERTEX, + LineType::LINES); +} /** * Draw lines where each pair of vertices is drawn as an independent * line segment. Same as OpenGL GL_LINES mode with glBegin(). * + * @param openglContextPointer + * Pointer to OpenGL context. * @param xyz * The vertices. * @param rgba @@ -98,41 +140,28 @@ m_lineType(lineType) * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLLineDrawing::drawLinesSolidColor(const std::vector& xyz, +GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, const float rgba[4], const float lineThicknessPixels) { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - return drawLinesPrivate(xyz, + std::vector emptyByteRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, rgbaVector, + emptyByteRGBA, lineThicknessPixels, - ColorType::RGBA_SOLID, + ColorType::FLOAT_RGBA_SOLID, LineType::LINES); - -// const int32_t numPoints = static_cast(xyz.size() / 3); -// if (numPoints < 2) { -// CaretLogWarning("Invalid number of points=" -// + AString::number(numPoints) -// + " for line drawing. Must be at least 2."); -// return false; -// } -// -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// -// GraphicsOpenGLLineDrawing lineDrawing(xyz, -// rgbaVector, -// lineThicknessPixels, -// ColorType::RGBA_SOLID, -// LineType::LINES); -// lineDrawing.performDrawing(); -// -// return true; } /** * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). * + * @param openglContextPointer + * Pointer to OpenGL context. * @param xyz * The vertices. * @param rgba @@ -143,23 +172,28 @@ GraphicsOpenGLLineDrawing::drawLinesSolidColor(const std::vector& xyz, * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLLineDrawing::drawLineStripSolidColor(const std::vector& xyz, +GraphicsOpenGLLineDrawing::drawLineStripSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, const float rgba[4], const float lineThicknessPixels) { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + std::vector emptyByteRGBA; - return drawLinesPrivate(xyz, + return drawLinesPrivate(openglContextPointer, + xyz, rgbaVector, + emptyByteRGBA, lineThicknessPixels, - ColorType::RGBA_SOLID, + ColorType::FLOAT_RGBA_SOLID, LineType::LINE_STRIP); - } /** * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). * + * @param openglContextPointer + * Pointer to OpenGL context. * @param xyz * The vertices. * @param rgba @@ -170,28 +204,166 @@ GraphicsOpenGLLineDrawing::drawLineStripSolidColor(const std::vector& xyz * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLLineDrawing::drawLineLoopSolidColor(const std::vector& xyz, +GraphicsOpenGLLineDrawing::drawLineLoopSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, const float rgba[4], const float lineThicknessPixels) { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - - return drawLinesPrivate(xyz, + std::vector emptyByteRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, rgbaVector, + emptyByteRGBA, lineThicknessPixels, - ColorType::RGBA_SOLID, + ColorType::FLOAT_RGBA_SOLID, LineType::LINE_LOOP); - } + + + + /** * Draw lines where each pair of vertices is drawn as an independent * line segment. Same as OpenGL GL_LINES mode with glBegin(). * + * @param openglContextPointer + * Pointer to OpenGL context. * @param xyz * The vertices. * @param rgba - * RGBA color for the lines with values ranging [0.0, 1.0] + * RGBA color for the lines with values ranging [0, 255] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLinesPerVertexByteColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels) +{ + std::vector emptyFloatRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, + emptyFloatRGBA, + rgba, + lineThicknessPixels, + ColorType::BYTE_RGBA_PER_VERTEX, + LineType::LINES); +} + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0, 255] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLinesSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels) +{ + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + + std::vector emptyFloatRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, + emptyFloatRGBA, + rgbaVector, + lineThicknessPixels, + ColorType::BYTE_RGBA_SOLID, + LineType::LINES); +} + +/** + * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0, 255] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLineStripSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels) +{ + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + std::vector emptyFloatRGBA; + + return drawLinesPrivate(openglContextPointer, + xyz, + emptyFloatRGBA, + rgbaVector, + lineThicknessPixels, + ColorType::BYTE_RGBA_SOLID, + LineType::LINE_STRIP); +} + +/** + * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param rgba + * RGBA color for the lines with values ranging [0, 255] + * @param lineThicknessPixels + * Thickness of line in pixels. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels) +{ + std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + std::vector emptyFloatRGBA; + return drawLinesPrivate(openglContextPointer, + xyz, + emptyFloatRGBA, + rgbaVector, + lineThicknessPixels, + ColorType::BYTE_RGBA_SOLID, + LineType::LINE_LOOP); +} + + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. * @param lineThicknessPixels * Thickness of line in pixels. * @param colorType @@ -202,14 +374,18 @@ GraphicsOpenGLLineDrawing::drawLineLoopSolidColor(const std::vector& xyz, * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLLineDrawing::drawLinesPrivate(const std::vector& xyz, - const std::vector& rgba, +GraphicsOpenGLLineDrawing::drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, const float lineThicknessPixels, const ColorType colorType, const LineType lineType) { - GraphicsOpenGLLineDrawing lineDrawing(xyz, - rgba, + GraphicsOpenGLLineDrawing lineDrawing(openglContextPointer, + xyz, + floatRGBA, + byteRGBA, lineThicknessPixels, colorType, lineType); @@ -233,26 +409,48 @@ GraphicsOpenGLLineDrawing::performDrawing() return false; } - const int32_t numRGBA = static_cast(m_inputRGBA.size()); + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); switch (m_colorType) { - case ColorType::RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return false; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: { - const int32_t numRgbaVertices = numRGBA / 4; + const int32_t numRgbaVertices = numFloatRGBA / 4; if (numVertices != numRgbaVertices) { CaretLogSevere("Mismatch in vertices and coloring. There are " + AString::number(numVertices) - + " vertices but have coloring for " + + " vertices but have float coloring for " + AString::number(numRgbaVertices) + " vertices"); return false; } } break; - case ColorType::RGBA_SOLID: - if (numRGBA < 4) { + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { CaretLogSevere("Must have at last 4 color components for solid color line drawing" "Number of color components is " - + AString::number(numRGBA)); + + AString::number(numFloatRGBA)); return false; } break; @@ -345,7 +543,8 @@ GraphicsOpenGLLineDrawing::createProjectionMatrix() projectionArray); m_projectionMatrix.setMatrixFromOpenGL(projectionArray); - m_projectionMatrix.postmultiply(modelviewMatrix); + //m_projectionMatrix.postmultiply(modelviewMatrix); + m_projectionMatrix.premultiply(modelviewMatrix); } @@ -379,16 +578,20 @@ GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() m_vertexWindowXYZ.push_back(windowXYZ[1]); m_vertexWindowXYZ.push_back(windowXYZ[2]); -// if (m_debugFlag) { -// GLdouble winX, winY, winZ; -// gluProject(xyz[i3], xyz[i3+1], xyz[i3+2], -// modelviewArray, projectionArray, viewport, -// &winX, &winY, &winZ); -// std::cout << "Input: " << xyz[i3] << ", " << xyz[i3+1] << ", " << xyz[i3+2] << std::endl; -// std::cout << " Pt " << i << ": " -// << windowX << ", " << windowY << ", " << windowZ << " w=" << xyzw[3] << std::endl; -// std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; -// } + if (m_debugFlag) { + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); + GLdouble winX, winY, winZ; + gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], + modelviewArray, projectionArray, viewport, + &winX, &winY, &winZ); + std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; + std::cout << " Pt " << i << ": " + << winX << ", " << winY << ", " << winZ << std::endl; + std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; + } } CaretAssert(m_inputXYZ.size() == m_vertexWindowXYZ.size()); @@ -495,42 +698,78 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, z2 }; + + /* + * RGBA for the points P1, P2, P3, P4 + */ + int32_t rgbaOffsetP1P2 = 0; + int32_t rgbaOffsetP3P4 = 0; + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOne * 4; + rgbaOffsetP3P4 = indexTwo * 4; + break; + case ColorType::BYTE_RGBA_SOLID: + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOne * 4; + rgbaOffsetP3P4 = indexTwo * 4; + break; + case ColorType::FLOAT_RGBA_SOLID: + break; + } + float crossProduct[3]; MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); - if (crossProduct[2] < 0.0) { - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p1, p1 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p4, p4 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p3, p3 + 3); - m_windowQuadsXYZ.insert(m_windowQuadsXYZ.end(), p2, p2 + 3); - } - + switch (m_colorType) { - case ColorType::RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: { - CaretAssertVectorIndex(m_inputRGBA, indexOne * 4 * 3); - const float* rgbaOneOffset = &m_inputRGBA[indexOne * 4]; - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); + const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); + const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; - CaretAssertVectorIndex(m_inputRGBA, indexTwo * 4 * 3); - const float* rgbaTwoOffset = &m_inputRGBA[indexTwo * 4]; - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaTwoOffset, rgbaTwoOffset + 4); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), rgbaOneOffset, rgbaOneOffset + 4); + CaretAssert(m_primitiveByteColor.get()); + if (crossProduct[2] < 0.0) { + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p3, rgbaP34); + m_primitiveByteColor->addVertex(p4, rgbaP34); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p4, rgbaP34); + m_primitiveByteColor->addVertex(p3, rgbaP34); + m_primitiveByteColor->addVertex(p2, rgbaP12); + } } break; - case ColorType::RGBA_SOLID: - CaretAssertVectorIndex(m_inputRGBA, 3); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); - m_windowQuadsRGBA.insert(m_windowQuadsRGBA.end(), m_inputRGBA.begin(), m_inputRGBA.begin() + 4); + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + { + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); + const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); + const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; + + CaretAssert(m_primitiveFloatColor.get()); + if (crossProduct[2] < 0.0) { + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + m_primitiveFloatColor->addVertex(p2, rgbaP12); + } + } break; } } @@ -545,8 +784,35 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, void GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() { + const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); - m_windowQuadsXYZ.reserve(numVertices * 6); // 2 points in line to 4 points in quad + + int32_t estimatedNumberOfQuads = 0; + switch (m_lineType) { + case LineType::LINES: + estimatedNumberOfQuads = numVertices / 2; + break; + case LineType::LINE_LOOP: + estimatedNumberOfQuads = numVertices; + break; + case LineType::LINE_STRIP: + estimatedNumberOfQuads = numVertices - 1; + break; + } + + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + break; + } + const int32_t numVerticesMinusOne = numVertices - 1; @@ -580,10 +846,6 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() void GraphicsOpenGLLineDrawing::drawQuads() { - const int32_t numVertices = static_cast(m_windowQuadsXYZ.size() / 3); - const int32_t numRGBA = static_cast(m_windowQuadsRGBA.size() / 4); - CaretAssert(numVertices == numRGBA); - GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); @@ -604,24 +866,28 @@ GraphicsOpenGLLineDrawing::drawQuads() //glPolygonMode(GL_BACK, GL_LINE); switch (m_colorType) { - case ColorType::RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + CaretAssert(m_primitiveByteColor.get()); + GraphicsEngineDataOpenGL::draw(m_openglContextPointer, + m_primitiveByteColor.get()); + if (m_debugFlag) { + std::cout << std::endl << "Quad Primitive: " << m_primitiveByteColor->toString() << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; + } break; - case ColorType::RGBA_SOLID: - glBegin(GL_QUADS); //GL_QUADS) - for (int32_t j = 0; j < numVertices; j++) { - CaretAssertVectorIndex(m_windowQuadsRGBA, j*4 + 3); - glColor4fv(&m_windowQuadsRGBA[j*4]); - CaretAssertVectorIndex(m_windowQuadsXYZ, j*3 + 2); - glVertex3fv(&m_windowQuadsXYZ[j*3]); + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + CaretAssert(m_primitiveFloatColor.get()); + GraphicsEngineDataOpenGL::draw(m_openglContextPointer, + m_primitiveFloatColor.get()); + if (m_debugFlag) { + std::cout << std::endl << "Quad Primitive: " << m_primitiveFloatColor->toString() << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; } - glEnd(); break; } - if (m_debugFlag) { - std::cout << std::endl << "QUADS: " << AString::fromNumbers(m_windowQuadsXYZ, ",") << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } } /** diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index 75ba9964f..3fa568fd8 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -30,30 +30,55 @@ namespace caret { - class GraphicsPrimitive; + class GraphicsPrimitiveV3fC4f; + class GraphicsPrimitiveV3fC4ub; class GraphicsOpenGLLineDrawing : public CaretObject { public: -// GraphicsOpenGLLineDrawing(const GraphicsPrimitive* primitive, -// const float lineThicknessPixels); - virtual ~GraphicsOpenGLLineDrawing(); - //bool run(AString& errorMessageOut); - - static bool drawLinesSolidColor(const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); + static bool drawLinesPerVertexFloatColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); - static bool drawLineStripSolidColor(const std::vector& xyz, + static bool drawLinesSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, const float rgba[4], const float lineThicknessPixels); - static bool drawLineLoopSolidColor(const std::vector& xyz, + static bool drawLineStripSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, const float rgba[4], const float lineThicknessPixels); + static bool drawLineLoopSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + + static bool drawLinesPerVertexByteColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); + + static bool drawLinesSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -63,10 +88,14 @@ namespace caret { * Type of line coloring */ enum class ColorType { - /** color at each vertex */ - RGBA_PER_VERTEX, - /** one color for all vertices */ - RGBA_SOLID + /** Byte RGBA color at each vertex */ + BYTE_RGBA_PER_VERTEX, + /** One Byte RGBA color for all vertices */ + BYTE_RGBA_SOLID, + /** Float RGBA color at each vertex */ + FLOAT_RGBA_PER_VERTEX, + /** One Float RGBA color for all vertices */ + FLOAT_RGBA_SOLID }; /** @@ -81,8 +110,10 @@ namespace caret { LINE_STRIP }; - GraphicsOpenGLLineDrawing(const std::vector& xyz, - const std::vector& rgba, + GraphicsOpenGLLineDrawing(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, const float lineThicknessPixels, const ColorType colorType, const LineType lineType); @@ -91,8 +122,10 @@ namespace caret { GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj) const; - static bool drawLinesPrivate(const std::vector& xyz, - const std::vector& rgba, + static bool drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, const float lineThicknessPixels, const ColorType colorType, const LineType lineType); @@ -108,8 +141,6 @@ namespace caret { void convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const; - //void convertPointsToWindowCoordinates(); - void createWindowCoordinatesFromVertices(); void convertLineSegmentsToQuads(); @@ -119,11 +150,13 @@ namespace caret { void drawQuads(); - const GraphicsPrimitive* m_inputPrimitive; + void* m_openglContextPointer; const std::vector& m_inputXYZ; - const std::vector& m_inputRGBA; + const std::vector& m_inputFloatRGBA; + + const std::vector& m_inputByteRGBA; const float m_lineThicknessPixels; @@ -131,13 +164,11 @@ namespace caret { const LineType m_lineType; - GraphicsPrimitive* m_outputPrimitive = NULL; - std::vector m_vertexWindowXYZ; - std::vector m_windowQuadsXYZ; + //std::vector m_windowQuadsXYZ; - std::vector m_windowQuadsRGBA; + //std::vector m_windowQuadsRGBA; bool m_debugFlag = false; @@ -147,6 +178,10 @@ namespace caret { Matrix4x4 m_projectionMatrix; + std::unique_ptr m_primitiveFloatColor; + + std::unique_ptr m_primitiveByteColor; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 7c5d23e1b7c67b023c0f62c6c4410d6e1a91cafb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 1 Nov 2017 11:00:12 -0500 Subject: [PATCH 490/755] Continuing development of line drawing with polygons. Now able to draw lines with miter joins at the ends of connected line segments. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 65 ++- src/Brain/BrainOpenGLFixedPipeline.cxx | 160 +++++--- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 9 + src/Common/MathFunctions.cxx | 81 +++- src/Common/MathFunctions.h | 8 + src/Graphics/CMakeLists.txt | 2 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 381 +++++++++++++++--- src/Graphics/GraphicsOpenGLLineDrawing.h | 34 +- src/Graphics/GraphicsPrimitive.cxx | 19 + src/Graphics/GraphicsPrimitive.h | 8 + src/Graphics/GraphicsShape.cxx | 207 ++++++++++ src/Graphics/GraphicsShape.h | 74 ++++ 12 files changed, 930 insertions(+), 118 deletions(-) create mode 100644 src/Graphics/GraphicsShape.cxx create mode 100644 src/Graphics/GraphicsShape.h diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 9df93433e..0fa04fae3 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -58,6 +58,7 @@ #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fT3f.h" +#include "GraphicsShape.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -1978,9 +1979,17 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * since it is opaque and prevents "behind" annotations * from being selected */ - m_brainOpenGLFixedPipeline->drawEllipseFilled(selectionColorRGBA, - majorAxis, - minorAxis); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + selectionColorRGBA); + } + else { + m_brainOpenGLFixedPipeline->drawEllipseFilled(selectionColorRGBA, + majorAxis, + minorAxis); + } } else { /* @@ -1988,10 +1997,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * select annotation that are inside of the box */ const float slightlyThicker = 2.0; - m_brainOpenGLFixedPipeline->drawEllipseOutline(selectionColorRGBA, - majorAxis, - minorAxis, - outlineWidth + slightlyThicker); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + float widthPixels = (oval->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + selectionColorRGBA, + widthPixels + slightlyThicker); + } + else { + m_brainOpenGLFixedPipeline->drawEllipseOutline(selectionColorRGBA, + majorAxis, + minorAxis, + outlineWidth + slightlyThicker); + } } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -2001,17 +2020,35 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi } else { if (drawBackgroundFlag) { - m_brainOpenGLFixedPipeline->drawEllipseFilled(backgroundRGBA, - majorAxis, - minorAxis); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + backgroundRGBA); + } + else { + m_brainOpenGLFixedPipeline->drawEllipseFilled(backgroundRGBA, + majorAxis, + minorAxis); + } drawnFlag = true; } if (drawForegroundFlag) { - m_brainOpenGLFixedPipeline->drawEllipseOutline(foregroundRGBA, - majorAxis, - minorAxis, - outlineWidth); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + float widthPixels = (oval->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; + GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + foregroundRGBA, + widthPixels); + } + else { + m_brainOpenGLFixedPipeline->drawEllipseOutline(foregroundRGBA, + majorAxis, + minorAxis, + outlineWidth); + } drawnFlag = true; } } diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 2dc29ef1b..f0cb741ce 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -101,6 +101,7 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" +#include "GraphicsOpenGLLineDrawing.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" @@ -2873,65 +2874,130 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } else { - glColor3fv(borderDrawInfo.rgba); - - /* - * Start at one, since need two points for each line - */ - glBegin(GL_LINES); - for (int32_t i = 1; i < numPointsToDraw; i++) { - /* - * On a flat surface, do not draw a line segment if it is - * from non-consecutive border points. This occurs when - * a border point does not project to the flat surface - * due to a cut or removal of the medial wall. If helps - * prevent long border lines stretching from one edge of the - * surface to a far away edge. - */ - if (flatSurfaceDrawUnstretchedLinesFlag) { - if (pointIndex[i] != (pointIndex[i-1] + 1)) { - continue; - } - } - - const int32_t i3 = i * 3; - CaretAssertVectorIndex(pointXYZ, i3 + 2); - const float* xyz1 = &pointXYZ[i3 - 3]; - const float* xyz2 = &pointXYZ[i3]; + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - bool drawIt = true; - if (doClipping) { - if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz1) - && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz2)) ) { - /* nothing */ + std::vector linesXYZ; + for (int32_t i = 1; i < numPointsToDraw; i++) { + /* + * On a flat surface, do not draw a line segment if it is + * from non-consecutive border points. This occurs when + * a border point does not project to the flat surface + * due to a cut or removal of the medial wall. If helps + * prevent long border lines stretching from one edge of the + * surface to a far away edge. + */ + if (flatSurfaceDrawUnstretchedLinesFlag) { + if (pointIndex[i] != (pointIndex[i-1] + 1)) { + continue; + } } - else { - drawIt = false; + + const int32_t i3 = i * 3; + CaretAssertVectorIndex(pointXYZ, i3 + 2); + const float* xyz1 = &pointXYZ[i3 - 3]; + const float* xyz2 = &pointXYZ[i3]; + + bool drawIt = true; + if (doClipping) { + if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, + xyz1) + && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, + xyz2)) ) { + /* nothing */ + } + else { + drawIt = false; + } + } + + + if (drawIt) { + if (flatSurfaceDrawUnstretchedLinesFlag) { + CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); + if (unstretchedBorderLineTest(xyz1, + xyz2, + &pointAnatomicalXYZ[i3], + &pointAnatomicalXYZ[i3-3], + unstretchedLinesLength)) { + drawIt = false; + } + } + } + + if (drawIt) { + linesXYZ.insert(linesXYZ.end(), xyz1, xyz1 + 3); + linesXYZ.insert(linesXYZ.end(), xyz2, xyz2 + 3); } } + if (linesXYZ.size() >= 6) { + GraphicsOpenGLLineDrawing::drawLineStripSolidFloatColor(getContextSharingGroupPointer(), + linesXYZ, + borderDrawInfo.rgba, + lineWidth); + } + } + else { + glColor3fv(borderDrawInfo.rgba); - if (drawIt) { + /* + * Start at one, since need two points for each line + */ + glBegin(GL_LINES); + for (int32_t i = 1; i < numPointsToDraw; i++) { + /* + * On a flat surface, do not draw a line segment if it is + * from non-consecutive border points. This occurs when + * a border point does not project to the flat surface + * due to a cut or removal of the medial wall. If helps + * prevent long border lines stretching from one edge of the + * surface to a far away edge. + */ if (flatSurfaceDrawUnstretchedLinesFlag) { - CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); - if (unstretchedBorderLineTest(xyz1, - xyz2, - &pointAnatomicalXYZ[i3], - &pointAnatomicalXYZ[i3-3], - unstretchedLinesLength)) { + if (pointIndex[i] != (pointIndex[i-1] + 1)) { + continue; + } + } + + const int32_t i3 = i * 3; + CaretAssertVectorIndex(pointXYZ, i3 + 2); + const float* xyz1 = &pointXYZ[i3 - 3]; + const float* xyz2 = &pointXYZ[i3]; + + bool drawIt = true; + if (doClipping) { + if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, + xyz1) + && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, + xyz2)) ) { + /* nothing */ + } + else { drawIt = false; } } + + + if (drawIt) { + if (flatSurfaceDrawUnstretchedLinesFlag) { + CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); + if (unstretchedBorderLineTest(xyz1, + xyz2, + &pointAnatomicalXYZ[i3], + &pointAnatomicalXYZ[i3-3], + unstretchedLinesLength)) { + drawIt = false; + } + } + } + + if (drawIt) { + glVertex3fv(xyz1); + glVertex3fv(xyz2); + } } - - if (drawIt) { - glVertex3fv(xyz1); - glVertex3fv(xyz2); - } + glEnd(); } - glEnd(); } this->enableLighting(); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 297a4dc9e..5926228c7 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3637,12 +3637,21 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) glDisable(GL_DEPTH_TEST); float widthPixels = thickness; if (surfaceColorFlag) { + /* + * Note: Must draw as line segments (each consecutive two points is independent of all others). + * The reason is that the intersection algorithm picks triangles for intersection with the + * surface in no particular order. Thus, two adjacent points in the lines may be nowhere + * near each others. + */ GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), lineXYZ, lineRGBA, widthPixels); } else { + /* + * Ditto, comment above + */ float rgba[4] = { 1.0, 0.0, 0.0, 1.0 }; CaretColorEnum::toRGBAFloat(outlineColor, rgba); GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), diff --git a/src/Common/MathFunctions.cxx b/src/Common/MathFunctions.cxx index 5ee6a7603..89b7af704 100644 --- a/src/Common/MathFunctions.cxx +++ b/src/Common/MathFunctions.cxx @@ -1373,8 +1373,6 @@ MathFunctions::vtkPerpendiculars(const double x[3], double y[3], double z[3], } } - - /** * Determine if 2D line segments intersect. * Algorithm from http://mathworld.wolfram.com/Line-LineIntersection.html @@ -1388,16 +1386,17 @@ MathFunctions::vtkPerpendiculars(const double x[3], double y[3], double z[3], * parameter to 0.01. * @param intersectionOut Location of intersection. * @return true if the line segments intersect else false. - * + * The intersection MUST BE within the range of + * each of the line segments. */ bool MathFunctions::lineIntersection2D( - const float p1[2], - const float p2[2], - const float q1[2], - const float q2[2], - const float tolerance, - float intersectionOut[2]) + const float p1[2], + const float p2[2], + const float q1[2], + const float q2[2], + const float tolerance, + float intersectionOut[2]) { double tol = tolerance; double x1 = p1[0]; @@ -1439,6 +1438,70 @@ MathFunctions::lineIntersection2D( return false; } + +/** + * Determine if 2D vectors intersect. + * Algorithm from http://mathworld.wolfram.com/Line-LineIntersection.html + * + * @param p1 Vector 1 end point 1. + * @param p2 Vector 1 end point 2. + * @param q1 Vector 2 end point 1. + * @param q2 Vector 2 end point 2. + * @param tolerance Tolerance around the vertices (essentially + * lengthens lines by this quantity). Caret5 set this + * parameter to 0.01. + * @param intersectionOut Location of intersection. + * @return true if the vectors intersect. + */ +bool +MathFunctions::vectorIntersection2D( + const float p1[2], + const float p2[2], + const float q1[2], + const float q2[2], + const float tolerance, + float intersectionOut[2]) +{ + double tol = tolerance; + double x1 = p1[0]; + double y1 = p1[1]; + double x2 = p2[0]; + double y2 = p2[1]; + + double x3 = q1[0]; + double y3 = q1[1]; + double x4 = q2[0]; + double y4 = q2[1]; + + double denom = ((x1 - x2) * (y3 - y4)) - ((x3 - x4) * (y1 - y2)); + + if (denom != 0.0) { + double a = (x1 * y2) - (x2 * y1); + double c = (x3 * y4) - (x4 * y3); + double x = ((a * (x3 - x4)) - (c * (x1 - x2))) / denom; + double y = ((a * (y3 - y4)) - (c * (y1 - y2))) / denom; + +// double pxMax = std::max(x1, x2) + tol; +// double pxMin = std::min(x1, x2) - tol; +// double pyMax = std::max(y1, y2) + tol; +// double pyMin = std::min(y1, y2) - tol; +// +// double qxMax = std::max(x3, x4) + tol; +// double qxMin = std::min(x3, x4) - tol; +// double qyMax = std::max(y3, y4) + tol; +// double qyMin = std::min(y3, y4) - tol; + + intersectionOut[0] = (float)x; + intersectionOut[1] = (float)y; +// if ((x >= pxMin) && (x <= pxMax) && (x >= qxMin) && (x <= qxMax) && +// (y >= pyMin) && (y <= pyMax) && (y >= qyMin) && (y <= qyMax)) { + return true; +// } + } + + return false; +} + /** * Determine if a ray intersects a plane. * @param p1 - 1st point defining the plane diff --git a/src/Common/MathFunctions.h b/src/Common/MathFunctions.h index df7d974d6..0555612c5 100644 --- a/src/Common/MathFunctions.h +++ b/src/Common/MathFunctions.h @@ -239,6 +239,14 @@ public: const float tolerance, float intersectionOut[3]); + static bool vectorIntersection2D( + const float p1[3], + const float p2[3], + const float q1[3], + const float q2[3], + const float tolerance, + float intersectionOut[3]); + static bool rayIntersectPlane( const float p1[3], const float p2[3], diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 3dead4581..ba5c4c7d3 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -23,6 +23,7 @@ GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h GraphicsPrimitiveV3fT3f.h +GraphicsShape.h EventGraphicsOpenGLCreateBufferObject.cxx EventGraphicsOpenGLCreateTextureName.cxx @@ -39,6 +40,7 @@ GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx GraphicsPrimitiveV3fT3f.cxx +GraphicsShape.cxx ) # diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index f1f6d8ca7..7a93f0749 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -462,9 +462,17 @@ GraphicsOpenGLLineDrawing::performDrawing() createWindowCoordinatesFromVertices(); - convertLineSegmentsToQuads(); - - drawQuads(); + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToQuads(); + + joinQuads(); + + CaretAssert(m_primitive); + if (m_primitive->isValid()) { + drawQuads(); + } + } restoreOpenGLState(); @@ -554,6 +562,8 @@ GraphicsOpenGLLineDrawing::createProjectionMatrix() void GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() { + const float coincidentMaxDistSQ = (0.01f * 0.01f); + GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); @@ -562,10 +572,32 @@ GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() glGetIntegerv(GL_VIEWPORT, viewport); - const int32_t numPoints = static_cast(m_inputXYZ.size() / 3); - m_vertexWindowXYZ.reserve(numPoints * 3); + int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); + int32_t iStep = 1; + switch (m_lineType) { + case LineType::LINES: + iStep = 2; + if (MathFunctions::isOddNumber(numInputPoints)) { + CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); + --numInputPoints; + } + break; + case LineType::LINE_LOOP: + iStep = 1; + break; + case LineType::LINE_STRIP: + iStep = 1; + break; + } - for (int32_t i = 0; i < numPoints; i++) { + m_vertexWindowXYZ.reserve(numInputPoints * 3); + m_vertexWindowInputIndices.reserve(numInputPoints); + + /* + * Coincident points that result in zero length + * line segments are filtered out + */ + for (int32_t i = 0; i < numInputPoints; i += iStep) { const int32_t i3 = i * 3; /* @@ -573,10 +605,55 @@ GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() * as described by the documentation from gluProject(). */ float windowXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, i3 + 1); convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); - m_vertexWindowXYZ.push_back(windowXYZ[0]); - m_vertexWindowXYZ.push_back(windowXYZ[1]); - m_vertexWindowXYZ.push_back(windowXYZ[2]); + + if (iStep == 1) { + if (i > 0) { + const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); + CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + &m_vertexWindowXYZ[previousPointOffset]); + if (distSQ < coincidentMaxDistSQ) { + CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); + continue; + } + } + + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + } + else if (iStep == 2) { + const int32_t iNext3 = (i + 1) * 3; + float windowNextXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); + convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], + windowNextXYZ); + + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + windowNextXYZ); + if (distSQ < coincidentMaxDistSQ) { + CaretLogSevere("Filtered out line pairs conincident points " + + AString::number(i) + + " and " + + AString::number(i + 1)); + continue; + } + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + + m_vertexWindowXYZ.push_back(windowNextXYZ[0]); + m_vertexWindowXYZ.push_back(windowNextXYZ[1]); + m_vertexWindowXYZ.push_back(windowNextXYZ[2]); + m_vertexWindowInputIndices.push_back(i + 1); + } + else { + CaretAssertMessage(0, "Invalid step value"); + } if (m_debugFlag) { GLdouble modelviewArray[16]; @@ -594,7 +671,7 @@ GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() } } - CaretAssert(m_inputXYZ.size() == m_vertexWindowXYZ.size()); + CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); } /** @@ -632,10 +709,13 @@ GraphicsOpenGLLineDrawing::convertFromModelToWindowCoordinate(const float modelX * Index of first vertex. * @param indexTwo * Index of second vertex. + * @param lastVertexFlag + * Flag indicating last vertex used when joining line loop last to first */ void GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo) + const int32_t indexTwo, + const bool lastVertexFlag) { const int32_t iOne3 = indexOne * 3; CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); @@ -649,18 +729,28 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, float z2 = m_vertexWindowXYZ[iTwo3 + 2]; /* - * Vector from start to end on line segment in 2D coordinates + * Normalized vector from start to end on line segment in 2D coordinates */ float startToEndVector[3] = { x2 - x1, y2 - y1, 0.0f }; + const float lineLength = MathFunctions::normalizeVector(startToEndVector); + if (lineLength < 0.001f) { + CaretLogWarning("This should not happen: Failure to filter coincident points with indices=" + + AString::number(indexOne) + + ", " + + AString::number(indexTwo) + + " Coordinates: " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") + + " " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); + } /* * Create a perpendicualar vector to the line segment */ - MathFunctions::normalizeVector(startToEndVector); float perpendicularVector[3] = { startToEndVector[1], -startToEndVector[0], @@ -676,6 +766,7 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, /* * Points of the rectangle + * They should be counter-clockwise oriented */ float p1[3] = { x1 - halfWidthX, @@ -698,6 +789,14 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, z2 }; + /* + * Indices to input coloring. + * Note that coincident points may be removed + */ + CaretAssertVectorIndex(m_vertexWindowInputIndices, indexOne); + const int32_t indexOneRgba = m_vertexWindowInputIndices[indexOne]; + CaretAssertVectorIndex(m_vertexWindowInputIndices, indexTwo); + const int32_t indexTwoRgba = m_vertexWindowInputIndices[indexTwo]; /* * RGBA for the points P1, P2, P3, P4 @@ -706,14 +805,14 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, int32_t rgbaOffsetP3P4 = 0; switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOne * 4; - rgbaOffsetP3P4 = indexTwo * 4; + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; break; case ColorType::BYTE_RGBA_SOLID: break; case ColorType::FLOAT_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOne * 4; - rgbaOffsetP3P4 = indexTwo * 4; + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; break; case ColorType::FLOAT_RGBA_SOLID: break; @@ -721,6 +820,9 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, float crossProduct[3]; MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); + if (crossProduct[2] == 0.0f) { + /* This should get caught by vector length check above */ + } switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: @@ -732,7 +834,7 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; CaretAssert(m_primitiveByteColor.get()); - if (crossProduct[2] < 0.0) { + if (crossProduct[2] <= 0.0f) { m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p3, rgbaP34); @@ -740,10 +842,10 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, } else { std::cout << "Flipped Quad" << std::endl; + m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p4, rgbaP34); m_primitiveByteColor->addVertex(p3, rgbaP34); - m_primitiveByteColor->addVertex(p2, rgbaP12); } } break; @@ -756,7 +858,7 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; CaretAssert(m_primitiveFloatColor.get()); - if (crossProduct[2] < 0.0) { + if (crossProduct[2] <= 0.0f) { m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p3, rgbaP34); @@ -764,16 +866,189 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, } else { std::cout << "Flipped Quad" << std::endl; + m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p4, rgbaP34); m_primitiveFloatColor->addVertex(p3, rgbaP34); - m_primitiveFloatColor->addVertex(p2, rgbaP12); } } break; } + +// /* +// * Perform joins of connected lines +// */ +// switch (m_lineType) { +// case LineType::LINES: +// return; +// break; +// case LineType::LINE_LOOP: +// break; +// case LineType::LINE_STRIP: +// break; +// } +// +// if (indexTwo >= 2) { +// CaretAssert(m_primitive); +// const int32_t numQuadVertices = m_primitive->getNumberOfVertices(); +// +// switch (m_joinType) { +// case JoinType::NONE: +// return; +// break; +// case JoinType::MITER: +// if (lastVertexFlag) { +// /* Join last quad to first quad */ +// performJoin(indexOne, +// indexTwo, +// 0, +// numQuadVertices - 4, +// 0); +// } +// else { +// performJoin(indexOne - 1, +// indexOne, +// indexTwo, +// numQuadVertices - 8, +// numQuadVertices - 4); +// } +// break; +// } +// } +} + +void +GraphicsOpenGLLineDrawing::joinQuads() +{ + /* + * Perform joins of connected lines + */ + + CaretAssert(m_primitive); + const int32_t numberOfLineVertices = (m_vertexWindowXYZ.size() / 3); + const int32_t lastVertexIndex = numberOfLineVertices - 1; + int32_t numberOfLines = numberOfLineVertices; + + switch (m_lineType) { + case LineType::LINES: + numberOfLines = 0; + break; + case LineType::LINE_LOOP: + break; + case LineType::LINE_STRIP: + numberOfLines = numberOfLines - 2; + break; + } + + switch (m_joinType) { + case JoinType::NONE: + numberOfLines = 0; + break; + case JoinType::MITER: + for (int32_t indexOne = 0; indexOne < numberOfLines; indexOne++) { + const int32_t indexTwo = (((indexOne + 1) <= lastVertexIndex) ? (indexOne + 1) : 0); + const int32_t indexThree = (((indexTwo + 1) <= lastVertexIndex) ? (indexTwo + 1) : 0); + if (m_debugFlag) { + std::cout << "JOIN: " << indexOne << ", " << indexTwo << ", " << indexThree << std::endl; + } + + const int32_t quadOneVertexIndex = indexOne * 4; + const int32_t quadTwoVertexIndex = indexTwo * 4; + performJoin(indexOne, indexTwo, indexThree, quadOneVertexIndex, quadTwoVertexIndex); + } + break; + } } +/** + * Perform a join using the last two vertices in quad one + * and the first two vertices in quad two + * + * @param lineVertexIndexOne + * Index of first vertex in line segment + * @param lineVertexIndexTwo + * Index of second vertex in line segment + * @param lineVertexIndexThree + * Index of three vertex in line segment + * @param quadOneVertexIndex + * Index of first vertex in first quad + * @param quadTwoVertexIndex + * Index of first vertex in second quad + */ +void +GraphicsOpenGLLineDrawing::performJoin(const int32_t lineVertexIndexOne, + const int32_t lineVertexIndexTwo, + const int32_t lineVertexIndexThree, + const int32_t quadOneVertexIndex, + const int32_t quadTwoVertexIndex) +{ + if (m_debugFlag) std::cout << "Join: " << lineVertexIndexOne << ", " << lineVertexIndexTwo << ", " << lineVertexIndexThree << std::endl; + CaretAssert(m_primitive); + + /* + * Determine if the junction of the two consecutive + * line segments in window coordinates makes a left + * or right turn + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexOne * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexTwo * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexThree * 3) + 2); + const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[lineVertexIndexOne * 3], + &m_vertexWindowXYZ[lineVertexIndexTwo * 3], + &m_vertexWindowXYZ[lineVertexIndexThree * 3]); + + + int32_t quadOneSideBeginVertexIndex = -1; + int32_t quadOneSideEndVertexIndex = -1; + int32_t quadTwoSideBeginVertexIndex = -1; + int32_t quadTwoSideEndVertexIndex = -1; + const float smallNumber = 0.001; + if (signedArea > smallNumber) { + if (m_debugFlag) std::cout << " Left Turn" << std::endl; + /* + * Right side is vertices two and three + */ + quadOneSideBeginVertexIndex = quadOneVertexIndex + 1; + quadOneSideEndVertexIndex = quadOneVertexIndex + 2; + quadTwoSideBeginVertexIndex = quadTwoVertexIndex + 1; + quadTwoSideEndVertexIndex = quadTwoVertexIndex + 2; + } + else if (signedArea < -smallNumber) { + if (m_debugFlag) std::cout << " Right Turn" << std::endl; + /* + * Right side is vertices 1 and 4 + */ + quadOneSideBeginVertexIndex = quadOneVertexIndex; + quadOneSideEndVertexIndex = quadOneVertexIndex + 3; + quadTwoSideBeginVertexIndex = quadTwoVertexIndex; + quadTwoSideEndVertexIndex = quadTwoVertexIndex + 3; + } + else { + if (m_debugFlag) std::cout << " Parallel" << std::endl; + return; + } + + const std::vector& xyz = m_primitive->getFloatXYZ(); + CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); + const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; + const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; + const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; + const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; + + /* + * Find location of where the edges in the quads intersect + */ + float intersectionXYZ[3]; + if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { + intersectionXYZ[2] = q1v1[2]; + if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; + m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); + } +} /** * Convert each line segment into a rectangle @@ -800,19 +1075,24 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() break; } + m_primitive = NULL; switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: case ColorType::BYTE_RGBA_SOLID: m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + m_primitive = m_primitiveByteColor.get(); break; case ColorType::FLOAT_RGBA_PER_VERTEX: case ColorType::FLOAT_RGBA_SOLID: m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + m_primitive = m_primitiveFloatColor.get(); break; } - + CaretAssert(m_primitive); + + m_primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); const int32_t numVerticesMinusOne = numVertices - 1; @@ -822,19 +1102,19 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() const int32_t numLineSegments = (numVertices / 2); for (int32_t i = 0; i < numLineSegments; i++) { const int32_t i2 = i * 2; - createQuadFromWindowVertices(i2, i2 + 1); + createQuadFromWindowVertices(i2, i2 + 1, false); } } break; case LineType::LINE_LOOP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { - createQuadFromWindowVertices(i, i + 1); + createQuadFromWindowVertices(i, i + 1, false); } - createQuadFromWindowVertices(numVerticesMinusOne, 0); + createQuadFromWindowVertices(numVerticesMinusOne, 0, true); break; case LineType::LINE_STRIP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { - createQuadFromWindowVertices(i, i + 1); + createQuadFromWindowVertices(i, i + 1, false); } break; } @@ -865,29 +1145,36 @@ GraphicsOpenGLLineDrawing::drawQuads() glPolygonMode(GL_FRONT, GL_FILL); //glPolygonMode(GL_BACK, GL_LINE); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - case ColorType::BYTE_RGBA_SOLID: - CaretAssert(m_primitiveByteColor.get()); - GraphicsEngineDataOpenGL::draw(m_openglContextPointer, - m_primitiveByteColor.get()); - if (m_debugFlag) { - std::cout << std::endl << "Quad Primitive: " << m_primitiveByteColor->toString() << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - case ColorType::FLOAT_RGBA_SOLID: - CaretAssert(m_primitiveFloatColor.get()); - GraphicsEngineDataOpenGL::draw(m_openglContextPointer, - m_primitiveFloatColor.get()); - if (m_debugFlag) { - std::cout << std::endl << "Quad Primitive: " << m_primitiveFloatColor->toString() << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } - break; + CaretAssert(m_primitive); + GraphicsEngineDataOpenGL::draw(m_openglContextPointer, + m_primitive); + if (m_debugFlag) { + std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; } +// switch (m_colorType) { +// case ColorType::BYTE_RGBA_PER_VERTEX: +// case ColorType::BYTE_RGBA_SOLID: +// CaretAssert(m_primitiveByteColor.get()); +// GraphicsEngineDataOpenGL::draw(m_openglContextPointer, +// m_primitiveByteColor.get()); +// if (m_debugFlag) { +// std::cout << std::endl << "Quad Primitive: " << m_primitiveByteColor->toString() << std::endl; +// std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; +// } +// break; +// case ColorType::FLOAT_RGBA_PER_VERTEX: +// case ColorType::FLOAT_RGBA_SOLID: +// CaretAssert(m_primitiveFloatColor.get()); +// GraphicsEngineDataOpenGL::draw(m_openglContextPointer, +// m_primitiveFloatColor.get()); +// if (m_debugFlag) { +// std::cout << std::endl << "Quad Primitive: " << m_primitiveFloatColor->toString() << std::endl; +// std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; +// } +// break; +// } } /** diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index 3fa568fd8..d15a37dba 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -30,12 +30,23 @@ namespace caret { + class GraphicsPrimitive; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; class GraphicsOpenGLLineDrawing : public CaretObject { public: + /** + * Join tyupe of how connected lines are drawn to remove gaps between segments + */ + enum JoinType { + /** None */ + NONE, + /* Extends 'outsides' of lines to meet forming a pointed shape */ + MITER + }; + virtual ~GraphicsOpenGLLineDrawing(); static bool drawLinesPerVertexFloatColor(void* openglContextPointer, @@ -146,10 +157,19 @@ namespace caret { void convertLineSegmentsToQuads(); void createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo); + const int32_t indexTwo, + const bool lastVertexFlag); void drawQuads(); + void performJoin(const int32_t lineVertexIndexOne, + const int32_t lineVertexIndexTwo, + const int32_t lineVertexIndexThree, + const int32_t quadOneVertexIndex, + const int32_t quadTwoVertexIndex); + + void joinQuads(); + void* m_openglContextPointer; const std::vector& m_inputXYZ; @@ -166,10 +186,14 @@ namespace caret { std::vector m_vertexWindowXYZ; + std::vector m_vertexWindowInputIndices; + //std::vector m_windowQuadsXYZ; //std::vector m_windowQuadsRGBA; + JoinType m_joinType = JoinType::MITER; + bool m_debugFlag = false; int m_savedPolygonMode[2]; @@ -178,6 +202,14 @@ namespace caret { Matrix4x4 m_projectionMatrix; + /* + * The base class graphics primitive that points to + * either the Float or Byte Color primitive and can + * be used for non-color operations. NEVER delete + * this as it points to one the color primitive + */ + GraphicsPrimitive* m_primitive = NULL; + std::unique_ptr m_primitiveFloatColor; std::unique_ptr m_primitiveByteColor; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 0b366c80b..be31f9b41 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -637,6 +637,25 @@ GraphicsPrimitive::replaceFloatXYZ(const std::vector& xyz) m_boundingBoxValid = false; } +/** + * Replace the XYZ coordinate at the given index + * + * @param vertexIndex + * Index of the vertex + * @param xyz + * The new XYZ coordinate + */ +void +GraphicsPrimitive::replaceVertexFloatXYZ(const int32_t vertexIndex, + const float xyz[3]) +{ + const int32_t offset = vertexIndex * 3; + CaretAssertVectorIndex(m_xyz, offset + 2); + m_xyz[offset] = xyz[0]; + m_xyz[offset + 1] = xyz[1]; + m_xyz[offset + 2] = xyz[2]; +} + /** * Get a bounds box for the vertex coordinates. * diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 427d24dfd..034dbaa7a 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -239,6 +239,14 @@ namespace caret { void replaceFloatXYZ(const std::vector& xyz); + /** + * @return The number of vertices + */ + inline int32_t getNumberOfVertices() const { return (m_xyz.size() / 3); } + + void replaceVertexFloatXYZ(const int32_t vertexIndex, + const float xyz[3]); + bool getVertexBounds(BoundingBox& boundingBoxOut) const; GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx new file mode 100644 index 000000000..4d0a83a54 --- /dev/null +++ b/src/Graphics/GraphicsShape.cxx @@ -0,0 +1,207 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_SHAPE_DECLARE__ +#include "GraphicsShape.h" +#undef __GRAPHICS_SHAPE_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "GraphicsEngineDataOpenGL.h" +#include "GraphicsOpenGLLineDrawing.h" +#include "GraphicsPrimitiveV3f.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsShape + * \brief Methods for drawing shapes. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsShape::GraphicsShape() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +GraphicsShape::~GraphicsShape() +{ +} + +/** + * Draw an outline ellipse. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param majorAxis + * Diameter of the major axis. + * @param minorAxis + * Diameter of the minor axis. + * @param rgba + * Color for drawing. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, + const double majorAxis, + const double minorAxis, + const uint8_t rgba[4], + const double lineThickness) +{ + std::vector ellipseXYZ; + createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); + + GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(openglContextPointer, + ellipseXYZ, + rgba, + lineThickness); +} + +/** + * Draw a filled ellipse. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param majorAxis + * Diameter of the major axis. + * @param minorAxis + * Diameter of the minor axis. + * @param rgba + * Color for drawing. + */ +void +GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, + const double majorAxis, + const double minorAxis, + const uint8_t rgba[4]) +{ + std::vector ellipseXYZ; + createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); + + + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN, + rgba)); + const float center[3] = { 0.0f, 0.0f, 0.0f }; + primitive->addVertex(center); + const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&ellipseXYZ[i * 3]); + } + primitive->addVertex(&ellipseXYZ[0]); + + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + +/** + * Create the vertices for the ellipse + * + * @param majorAxis + * Diameter of the major axis. + * @param minorAxis + * Diameter of the minor axis. + * @param elliposeXYZOut + * Contains vertices upon exit. + */ +void +GraphicsShape::createEllipseVertices(const double majorAxis, + const double minorAxis, + std::vector& ellipseXYZOut) +{ + const float a = majorAxis / 2.0f; + const float b = minorAxis / 2.0f; + + const float z = 0.0f; + + const int32_t numSlices = 10; + + const float totalPoints = numSlices * 4; + ellipseXYZOut.resize(totalPoints * 3); + + /* + * Computation of the points on the ellipse is performed + * using the parametric equation (a * cos(t), b*sin(t)). + * Using this parametric equation provides an equal length + * between points on the ellipse. + * The symmetry of the four quadrants is used to that + * we only need to compute points in the first quadrant. + */ + const float angleStep = ((M_PI / 2.0f) / numSlices); + + for (int32_t i = 0; i <= numSlices; i++) { + const float x = a * std::cos(i * angleStep); + const float y = b * std::sin(i * angleStep); + + const int32_t quadOneIndex = i * 3; + CaretAssertVectorIndex(ellipseXYZOut, quadOneIndex + 2); + ellipseXYZOut[quadOneIndex] = x; + ellipseXYZOut[quadOneIndex + 1] = y; + ellipseXYZOut[quadOneIndex + 2] = z; + + if (i < numSlices) { + const int32_t quadTwoIndex = ((numSlices * 2) - i) * 3; + CaretAssertVectorIndex(ellipseXYZOut, quadTwoIndex + 2); + ellipseXYZOut[quadTwoIndex] = -x; + ellipseXYZOut[quadTwoIndex + 1] = y; + ellipseXYZOut[quadTwoIndex + 2] = z; + } + + if (i > 0) { + const int32_t quadThreeIndex = ((numSlices * 2) + i) * 3; + CaretAssertVectorIndex(ellipseXYZOut, quadThreeIndex + 2); + ellipseXYZOut[quadThreeIndex] = -x; + ellipseXYZOut[quadThreeIndex + 1] = -y; + ellipseXYZOut[quadThreeIndex + 2] = z; + } + + if ((i > 0) && (i < numSlices)) { + const int32_t quadFourIndex = ((numSlices * 4) - i) * 3; + CaretAssertVectorIndex(ellipseXYZOut, quadFourIndex + 2); + ellipseXYZOut[quadFourIndex] = x; + ellipseXYZOut[quadFourIndex + 1] = -y; + ellipseXYZOut[quadFourIndex + 2] = z; + } + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsShape::toString() const +{ + return "GraphicsShape"; +} + diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h new file mode 100644 index 000000000..72873e022 --- /dev/null +++ b/src/Graphics/GraphicsShape.h @@ -0,0 +1,74 @@ +#ifndef __GRAPHICS_SHAPE_H__ +#define __GRAPHICS_SHAPE_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class GraphicsShape : public CaretObject { + + public: + virtual ~GraphicsShape(); + + static void drawEllipseOutlineByteColor(void* openglContextPointer, + const double majorAxis, + const double minorAxis, + const uint8_t rgba[4], + const double lineThickness); + + static void drawEllipseFilledByteColor(void* openglContextPointer, + const double majorAxis, + const double minorAxis, + const uint8_t rgba[4]); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + GraphicsShape(); + + GraphicsShape(const GraphicsShape&); + + GraphicsShape& operator=(const GraphicsShape&); + + static void createEllipseVertices(const double majorAxis, + const double minorAxis, + std::vector& ellipseXYZOut); + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_SHAPE_DECLARE__ + // +#endif // __GRAPHICS_SHAPE_DECLARE__ + +} // namespace +#endif //__GRAPHICS_SHAPE_H__ -- GitLab From b7b0f10973c50e530da242bd9095785cd0c6f281 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 3 Nov 2017 11:52:09 -0500 Subject: [PATCH 491/755] When a scene is created, there is a test for modified files. This test was only testing "mappable" data files (brainordinate attributes types) and missing other types of files (eg: border, foci) --- src/GuiQt/GuiManager.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 70f76389b..522daebb1 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -722,15 +722,14 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, * Is modification data but NOT palette */ CaretMappableDataFile* mappableDataFile = dynamic_cast(file); - bool dataModFlag = false; if (mappableDataFile != NULL) { if ( ! mappableDataFile->isModifiedPaletteColorMapping()) { if (mappableDataFile->isModifiedExcludingPaletteColorMapping()) { - dataModFlag = true; + modifiedDataFiles.push_back(file); } } } - if (dataModFlag) { + else { modifiedDataFiles.push_back(file); } break; -- GitLab From 7f3e915dc385f41ce57d7e3e8e89fe0ae288e868 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 6 Nov 2017 12:33:29 -0600 Subject: [PATCH 492/755] Continuing development of line drawing with polygons. Improvements to miter joins buy adding a 'miter limit' to prevent very long miter joins at share angles. When drawing lines, added ability to 'restart primitives' without have to create separate primitives (such as a gap in a line when unstretched lines is used in border lines). Also, set line widths and point sizes for some graphics primitives. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 2 + ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 5 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 354 +++++++++++--- src/Brain/BrainOpenGLFixedPipeline.h | 2 + src/Graphics/GraphicsEngineDataOpenGL.cxx | 70 +++ src/Graphics/GraphicsEngineDataOpenGL.h | 4 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 440 +++++++++++++----- src/Graphics/GraphicsOpenGLLineDrawing.h | 61 ++- src/Graphics/GraphicsPrimitive.cxx | 387 ++++++++++++++- src/Graphics/GraphicsPrimitive.h | 56 +++ src/Graphics/GraphicsShape.cxx | 17 +- 11 files changed, 1188 insertions(+), 210 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 0fa04fae3..96e99bd52 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -293,6 +293,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, redRGBA)); + crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); crossShape->addVertex(drawingSpaceXYZ[0], drawingSpaceXYZ[1] - 10); crossShape->addVertex(drawingSpaceXYZ[0], @@ -2459,6 +2460,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi annXYZ[1]); crossShape->addVertex(annXYZ[0] + 10, annXYZ[1]); + crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), crossShape.get()); } diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 1863b61d6..d8b7c4863 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1489,6 +1489,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnOutlineData->addVertex(maxX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, maxY, highlightRGBA); columnOutlineData->addVertex(minX, maxY, highlightRGBA); + columnOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, highlightLineWidth); float modelViewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); @@ -1681,7 +1682,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons boxData->addVertex(boxLeft - cornerOffset, boxTop); boxData->addVertex(boxLeft, boxTop); boxData->addVertex(boxLeft, boxBottom); - BrainOpenGL::setLineWidth(lineThicknessPixels); + boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); drawPrimitivePrivate(boxData.get()); } @@ -2539,6 +2540,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh * Draw the ticks. */ BrainOpenGL::setLineWidth(m_lineDrawingWidth); + ticksData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } @@ -2567,6 +2569,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh boxPrimitive->addVertex(bottomRight); boxPrimitive->addVertex(topRight); boxPrimitive->addVertex(topLeft); + boxPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); // Complete offsets and maybe examine alignments from the text annotation to set the offsets // diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index f0cb741ce..c18b035a1 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -101,7 +101,9 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" +#include "GraphicsEngineDataOpenGL.h" #include "GraphicsOpenGLLineDrawing.h" +#include "GraphicsPrimitiveV3fC4ub.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" @@ -2560,6 +2562,291 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) } } +/** + * Draw a border on a surface. The color must be set prior + * to calling this method. + * + * @param borderDrawInfo + * Info about border being drawn. + */ +void +BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) +{ + if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + drawBorderOld(borderDrawInfo); + return; + } + + CaretAssert(borderDrawInfo.surface); + CaretAssert(borderDrawInfo.border); + + const StructureEnum::Enum surfaceStructure = borderDrawInfo.surface->getStructure(); + const StructureEnum::Enum contralateralSurfaceStructure = StructureEnum::getContralateralStructure(surfaceStructure); + const int32_t numBorderPoints = borderDrawInfo.border->getNumberOfPoints(); + const bool isHighlightEndPoints = borderDrawInfo.isHighlightEndPoints; + + float pointDiameter = 2.0; + float lineWidth = 2.0; + BorderDrawingTypeEnum::Enum drawType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; + if (borderDrawInfo.borderFileIndex >= 0) { + const BrainStructure* bs = borderDrawInfo.surface->getBrainStructure(); + const Brain* brain = bs->getBrain(); + const DisplayPropertiesBorders* dpb = brain->getDisplayPropertiesBorders(); + const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(this->windowTabIndex); + pointDiameter = dpb->getPointSize(displayGroup, + this->windowTabIndex); + lineWidth = dpb->getLineWidth(displayGroup, + this->windowTabIndex); + drawType = dpb->getDrawingType(displayGroup, + this->windowTabIndex); + } + + bool drawSphericalPoints = false; + bool drawSquarePoints = false; + bool drawLines = false; + switch (drawType) { + case BorderDrawingTypeEnum::DRAW_AS_LINES: + drawLines = true; + break; + case BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES: + drawSphericalPoints = true; + break; + case BorderDrawingTypeEnum::DRAW_AS_POINTS_SQUARES: + drawSquarePoints = true; + break; + case BorderDrawingTypeEnum::DRAW_AS_POINTS_AND_LINES: + drawLines = true; + drawSphericalPoints = true; + break; + } + + const bool flatSurfaceFlag = (borderDrawInfo.surface->getSurfaceType() == SurfaceTypeEnum::FLAT); + bool flatSurfaceDrawUnstretchedLinesFlag = false; + float unstretchedLinesLength = -1.0; + if (flatSurfaceFlag) { + if ((borderDrawInfo.anatomicalSurface != NULL) + && (borderDrawInfo.unstretchedLinesLength > 0.0)) { + flatSurfaceDrawUnstretchedLinesFlag = true; + unstretchedLinesLength = borderDrawInfo.unstretchedLinesLength; + } + } + + const float drawAtDistanceAboveSurface = 0.0; + + const CaretPointer th = borderDrawInfo.surface->getTopologyHelper(); + const std::vector& nodesBoundaryEdgeCount = th->getNumberOfBoundaryEdgesForAllNodes(); + CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); + + std::unique_ptr pointsPrimitive; + if (drawSphericalPoints || drawSquarePoints) { + pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POINTS)); + } + std::unique_ptr linesPrimitive; + if (drawLines) { + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); + } + + const bool featureClippingFlag = isFeatureClippingEnabled(); + + const uint8_t highlightFirstPointRGBA[4] = { 0, 255, 0, 1 }; + const uint8_t highlightLastPointRGBA[4] = { 0, 192, 0, 1 }; + + const uint8_t solidColorRGBA[4] = { + borderDrawInfo.rgba[0] * 255.0f, + borderDrawInfo.rgba[1] * 255.0f, + borderDrawInfo.rgba[2] * 255.0f, + borderDrawInfo.rgba[3] * 255.0f + }; + + bool lastPointForLineValidFlag = false; + float lastPointForLineXYZ[3] = { 0.0f, 0.0f, 0.0f }; + int32_t lastPointIndex = -1; + /* + * Find points valid for this surface + */ + for (int32_t i = 0; i < numBorderPoints; i++) { + /* + * If previous point was not valid, need to "restart" the border lines + */ + if (i > 0) { + if ( ! lastPointForLineValidFlag) { + if (linesPrimitive) { + linesPrimitive->addPrimitiveRestart(); + } + } + } + + const SurfaceProjectedItem* p = borderDrawInfo.border->getPoint(i); + + /* + * Test to match structure + */ + const StructureEnum::Enum pointStructure = p->getStructure(); + bool structureMatches = true; + if (surfaceStructure != pointStructure) { + structureMatches = false; + if (borderDrawInfo.isContralateralEnabled) { + if (contralateralSurfaceStructure == pointStructure) { + structureMatches = true; + } + } + } + if ( ! structureMatches) { + lastPointForLineValidFlag = false; + continue; + } + + /* + * Test if point projects to surface successfully + */ + float xyz[3]; + bool projectionValidFlag = p->getProjectedPositionAboveSurface(*borderDrawInfo.surface, + xyz, + drawAtDistanceAboveSurface); + if ( ! projectionValidFlag) { + lastPointForLineValidFlag = false; + continue; + } + + /* + * Test if point is inside clipping planes + */ + if (featureClippingFlag) { + if ( ! isCoordinateInsideClippingPlanesForStructure(surfaceStructure, + xyz)) { + lastPointForLineValidFlag = false; + continue; + } + } + + /* + * If this is a flat surface and unstretched lines is enabled + * Do not use point if it was projected to all nodes that are on edges + * Typically these edges are where cuts were made for flattening + */ + if (flatSurfaceDrawUnstretchedLinesFlag){ + if (p->getBarycentricProjection()->isValid()) { + const int32_t* baryNodes = p->getBarycentricProjection()->getTriangleNodes(); + if (baryNodes != NULL) { + int32_t edgeNodeCount = 0; + if (nodesBoundaryEdgeCount[baryNodes[0]] > 0) edgeNodeCount++; + if (nodesBoundaryEdgeCount[baryNodes[1]] > 0) edgeNodeCount++; + if (nodesBoundaryEdgeCount[baryNodes[2]] > 0) edgeNodeCount++; + if (edgeNodeCount >= 3) { + lastPointForLineValidFlag = false; + continue; + } + } + } + } + + /* + * For Lines ONLY: + * If flat surface and unstretched lines is enabled + * + */ + if (flatSurfaceDrawUnstretchedLinesFlag) { + if (i > 0) { + if (lastPointForLineValidFlag) { + float anatXYZ[3]; + const bool anatXyzValid = p->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, + anatXYZ, + drawAtDistanceAboveSurface); + const SurfaceProjectedItem* lastP = borderDrawInfo.border->getPoint(i - 1); + float lastAnatXYZ[3]; + const bool lastAnatXyzValid = lastP->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, + lastAnatXYZ, + drawAtDistanceAboveSurface); + if (anatXyzValid && lastAnatXyzValid) { + if (unstretchedBorderLineTest(xyz, + lastPointForLineXYZ, + anatXYZ, + lastAnatXYZ, + unstretchedLinesLength)) { + if (linesPrimitive) { + linesPrimitive->addPrimitiveRestart(); + } + } + } + } + + } + + } + + /* + * Color for point + */ + uint8_t pointRGBA[4] = { + solidColorRGBA[0], + solidColorRGBA[1], + solidColorRGBA[2], + solidColorRGBA[3], + }; + if (borderDrawInfo.isSelect) { + uint8_t idRGBA[4]; + this->colorIdentification->addItem(idRGBA, + SelectionItemDataTypeEnum::BORDER_SURFACE, + borderDrawInfo.borderFileIndex, + borderDrawInfo.borderIndex, + i); + pointRGBA[3] = 255; + + if (pointsPrimitive) { + pointsPrimitive->addVertex(xyz, idRGBA); + } + if (linesPrimitive) { + linesPrimitive->addVertex(xyz, idRGBA); + } + } + else { + if (pointsPrimitive) { + if (isHighlightEndPoints) { + if (i == 0) { + pointsPrimitive->addVertex(xyz, highlightFirstPointRGBA); + } + else if (i == (numBorderPoints - 1)) { + pointsPrimitive->addVertex(xyz, highlightLastPointRGBA); + } + } + else { + pointsPrimitive->addVertex(xyz, solidColorRGBA); + } + } + if (linesPrimitive) { + linesPrimitive->addVertex(xyz, solidColorRGBA); + } + } + + /* + * May need point for next time + */ + lastPointForLineXYZ[0] = xyz[0]; + lastPointForLineXYZ[1] = xyz[1]; + lastPointForLineXYZ[2] = xyz[2]; + lastPointIndex = i; + lastPointForLineValidFlag = true; + } + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + + if (pointsPrimitive) { + pointsPrimitive->setPointDiameter(GraphicsPrimitive::SizeType::PIXELS, + pointDiameter); + GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), + pointsPrimitive.get()); + } + if (linesPrimitive) { + linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + lineWidth); + GraphicsOpenGLLineDrawing::draw(getContextSharingGroupPointer(), + linesPrimitive.get()); + } + + glPopAttrib(); +} + /** * Draw a border on a surface. The color must be set prior * to calling this method. @@ -2576,7 +2863,7 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) * Selection mode is active. */ void -BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) +BrainOpenGLFixedPipeline::drawBorderOld(const BorderDrawInfo& borderDrawInfo) { CaretAssert(borderDrawInfo.surface); CaretAssert(borderDrawInfo.border); @@ -2874,70 +3161,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } else { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - - std::vector linesXYZ; - for (int32_t i = 1; i < numPointsToDraw; i++) { - /* - * On a flat surface, do not draw a line segment if it is - * from non-consecutive border points. This occurs when - * a border point does not project to the flat surface - * due to a cut or removal of the medial wall. If helps - * prevent long border lines stretching from one edge of the - * surface to a far away edge. - */ - if (flatSurfaceDrawUnstretchedLinesFlag) { - if (pointIndex[i] != (pointIndex[i-1] + 1)) { - continue; - } - } - - const int32_t i3 = i * 3; - CaretAssertVectorIndex(pointXYZ, i3 + 2); - const float* xyz1 = &pointXYZ[i3 - 3]; - const float* xyz2 = &pointXYZ[i3]; - - bool drawIt = true; - if (doClipping) { - if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz1) - && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz2)) ) { - /* nothing */ - } - else { - drawIt = false; - } - } - - - if (drawIt) { - if (flatSurfaceDrawUnstretchedLinesFlag) { - CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); - if (unstretchedBorderLineTest(xyz1, - xyz2, - &pointAnatomicalXYZ[i3], - &pointAnatomicalXYZ[i3-3], - unstretchedLinesLength)) { - drawIt = false; - } - } - } - - if (drawIt) { - linesXYZ.insert(linesXYZ.end(), xyz1, xyz1 + 3); - linesXYZ.insert(linesXYZ.end(), xyz2, xyz2 + 3); - } - } - - if (linesXYZ.size() >= 6) { - GraphicsOpenGLLineDrawing::drawLineStripSolidFloatColor(getContextSharingGroupPointer(), - linesXYZ, - borderDrawInfo.rgba, - lineWidth); - } - } - else { glColor3fv(borderDrawInfo.rgba); /* @@ -2998,7 +3221,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } glEnd(); } - } this->enableLighting(); } diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index deac26cd2..0ee3761b8 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -228,6 +228,8 @@ namespace caret { void drawBorder(const BorderDrawInfo& borderDrawInfo); + void drawBorderOld(const BorderDrawInfo& borderDrawInfo); + bool unstretchedBorderLineTest(const float p1[3], const float p2[3], const float anat1[3], diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index cf31cdaa7..f5b77f980 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -1030,15 +1030,19 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::LINE_LOOP: openGLPrimitiveType = GL_LINE_LOOP; + glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::LINE_STRIP: openGLPrimitiveType = GL_LINE_STRIP; + glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::LINES: openGLPrimitiveType = GL_LINES; + glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::POINTS: openGLPrimitiveType = GL_POINTS; + glPointSize(getPointDiameterForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::POLYGON: openGLPrimitiveType = GL_POLYGON; @@ -1088,5 +1092,71 @@ GraphicsEngineDataOpenGL::getOpenGLContextPointer() const return m_openglContextPointer; } +/** + * Get the line width in pixels for drawing lines. + * If the primitive's line width type is a percentage + * of viewport height, convert it to pixels. + * + * @param primtive + * The graphics primitive. + * @return + * Width of line in pixels. + */ +float +GraphicsEngineDataOpenGL::getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + float width = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + + width = (viewport[3] * (width / 100.0f)); + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + return width; +} + +/** + * Get the point diameter in pixels for drawing points. + * If the primitive's point diameter type is a percentage + * of viewport height, convert it to pixels. + * + * @param primtive + * The graphics primitive. + * @return + * Diameter of point in pixels. + */ +float +GraphicsEngineDataOpenGL::getPointDiameterForDrawingInPixels(const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + + float pointSize = primitive->m_pointDiameterValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + + pointSize = (viewport[3] * (pointSize / 100.0f)); + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + return pointSize; +} + diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index f2d40dc72..8fb00d307 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -107,6 +107,10 @@ namespace caret { GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; + static float getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive); + + static float getPointDiameterForDrawingInPixels(const GraphicsPrimitive* primitive); + const void* m_openglContextPointer; GLsizei m_arrayIndicesCount = 0; diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index 7a93f0749..4292cfdc8 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -57,6 +57,104 @@ GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() { } +/** + * Draw the given graphics primitive containing lines + * by converting the lines to polygons. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param primtive + * The graphics primitive. + */ +bool +GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, + const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + if (primitive->isValid()) { + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretLogSevere("INVALID color type NONE for graphics primitive"); + return false; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::LINES: + lineType = LineType::LINES; + break; + case GraphicsPrimitive::PrimitiveType::POINTS: + CaretLogSevere("POINTS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::POLYGON: + CaretLogSevere("POLYGON is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::QUADS: + CaretLogSevere("QUADS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::TRIANGLES: + CaretLogSevere("TRIANGLES is not a valid line drawing type"); + return false; + break; + } + + return drawLinesPrivate(openglContextPointer, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_primitiveRestartIndices, + lineWidth, + colorType, + lineType); + } + + return false; +} + + /** * Constructor. * @@ -68,6 +166,9 @@ GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() * The Float RGBA coloring. * @param byteRGBA * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * The primitive will stop at the index and not connect to the next index. * @param lineThicknessPixels * Thickness of lines in pixels. * @param colorType @@ -79,6 +180,7 @@ GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(void* openglContextPointer, const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType) @@ -86,6 +188,7 @@ GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(void* openglContextPointer, m_inputXYZ(xyz), m_inputFloatRGBA(floatRGBA), m_inputByteRGBA(byteRGBA), +m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), m_lineThicknessPixels(lineThicknessPixels), m_colorType(colorType), m_lineType(lineType) @@ -114,11 +217,13 @@ GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(void* openglContextPoint const std::vector& rgba, const float lineThicknessPixels) { + std::set emptyPrimitiveRestartIndices; std::vector emptyByteRGBA; return drawLinesPrivate(openglContextPointer, xyz, rgba, emptyByteRGBA, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::FLOAT_RGBA_PER_VERTEX, LineType::LINES); @@ -147,11 +252,13 @@ GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(void* openglContextPointer, { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; + std::set emptyPrimitiveRestartIndices; std::vector emptyByteRGBA; return drawLinesPrivate(openglContextPointer, xyz, rgbaVector, emptyByteRGBA, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::FLOAT_RGBA_SOLID, LineType::LINES); @@ -179,11 +286,13 @@ GraphicsOpenGLLineDrawing::drawLineStripSolidFloatColor(void* openglContextPoint { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; std::vector emptyByteRGBA; + std::set emptyPrimitiveRestartIndices; return drawLinesPrivate(openglContextPointer, xyz, rgbaVector, emptyByteRGBA, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::FLOAT_RGBA_SOLID, LineType::LINE_STRIP); @@ -211,10 +320,13 @@ GraphicsOpenGLLineDrawing::drawLineLoopSolidFloatColor(void* openglContextPointe { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; std::vector emptyByteRGBA; + std::set emptyPrimitiveRestartIndices; + return drawLinesPrivate(openglContextPointer, xyz, rgbaVector, emptyByteRGBA, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::FLOAT_RGBA_SOLID, LineType::LINE_LOOP); @@ -246,10 +358,13 @@ GraphicsOpenGLLineDrawing::drawLinesPerVertexByteColor(void* openglContextPointe const float lineThicknessPixels) { std::vector emptyFloatRGBA; + std::set emptyPrimitiveRestartIndices; + return drawLinesPrivate(openglContextPointer, xyz, emptyFloatRGBA, rgba, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::BYTE_RGBA_PER_VERTEX, LineType::LINES); @@ -279,10 +394,13 @@ GraphicsOpenGLLineDrawing::drawLinesSolidByteColor(void* openglContextPointer, std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; std::vector emptyFloatRGBA; + std::set emptyPrimitiveRestartIndices; + return drawLinesPrivate(openglContextPointer, xyz, emptyFloatRGBA, rgbaVector, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::BYTE_RGBA_SOLID, LineType::LINES); @@ -310,11 +428,13 @@ GraphicsOpenGLLineDrawing::drawLineStripSolidByteColor(void* openglContextPointe { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; std::vector emptyFloatRGBA; + std::set emptyPrimitiveRestartIndices; return drawLinesPrivate(openglContextPointer, xyz, emptyFloatRGBA, rgbaVector, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::BYTE_RGBA_SOLID, LineType::LINE_STRIP); @@ -342,10 +462,13 @@ GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(void* openglContextPointer { std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; std::vector emptyFloatRGBA; + std::set emptyPrimitiveRestartIndices; + return drawLinesPrivate(openglContextPointer, xyz, emptyFloatRGBA, rgbaVector, + emptyPrimitiveRestartIndices, lineThicknessPixels, ColorType::BYTE_RGBA_SOLID, LineType::LINE_LOOP); @@ -364,6 +487,8 @@ GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(void* openglContextPointer * The Float RGBA coloring. * @param byteRGBA * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. * @param lineThicknessPixels * Thickness of line in pixels. * @param colorType @@ -378,6 +503,7 @@ GraphicsOpenGLLineDrawing::drawLinesPrivate(void* openglContextPointer, const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType) @@ -386,6 +512,7 @@ GraphicsOpenGLLineDrawing::drawLinesPrivate(void* openglContextPointer, xyz, floatRGBA, byteRGBA, + vertexPrimitiveRestartIndices, lineThicknessPixels, colorType, lineType); @@ -709,13 +836,10 @@ GraphicsOpenGLLineDrawing::convertFromModelToWindowCoordinate(const float modelX * Index of first vertex. * @param indexTwo * Index of second vertex. - * @param lastVertexFlag - * Flag indicating last vertex used when joining line loop last to first */ void GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo, - const bool lastVertexFlag) + const int32_t indexTwo) { const int32_t iOne3 = indexOne * 3; CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); @@ -875,88 +999,58 @@ GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, break; } -// /* -// * Perform joins of connected lines -// */ -// switch (m_lineType) { -// case LineType::LINES: -// return; -// break; -// case LineType::LINE_LOOP: -// break; -// case LineType::LINE_STRIP: -// break; -// } -// -// if (indexTwo >= 2) { -// CaretAssert(m_primitive); -// const int32_t numQuadVertices = m_primitive->getNumberOfVertices(); -// -// switch (m_joinType) { -// case JoinType::NONE: -// return; -// break; -// case JoinType::MITER: -// if (lastVertexFlag) { -// /* Join last quad to first quad */ -// performJoin(indexOne, -// indexTwo, -// 0, -// numQuadVertices - 4, -// 0); -// } -// else { -// performJoin(indexOne - 1, -// indexOne, -// indexTwo, -// numQuadVertices - 8, -// numQuadVertices - 4); -// } -// break; -// } -// } + m_quadInfo.push_back(QuadInfo(indexOne, indexTwo)); } +/** + * Join quads to create connected line segments + * without cracks where the quads join together. + */ void GraphicsOpenGLLineDrawing::joinQuads() { - /* - * Perform joins of connected lines - */ - CaretAssert(m_primitive); - const int32_t numberOfLineVertices = (m_vertexWindowXYZ.size() / 3); - const int32_t lastVertexIndex = numberOfLineVertices - 1; - int32_t numberOfLines = numberOfLineVertices; + const int32_t numQuads = static_cast(m_quadInfo.size()); + const int32_t numQuadsMinusOne = numQuads - 1; + + int32_t numQuadsToConnect = 0; switch (m_lineType) { case LineType::LINES: - numberOfLines = 0; + numQuadsToConnect = 0; break; case LineType::LINE_LOOP: + numQuadsToConnect = numQuads; break; case LineType::LINE_STRIP: - numberOfLines = numberOfLines - 2; + numQuadsToConnect = numQuadsMinusOne; break; } - - switch (m_joinType) { - case JoinType::NONE: - numberOfLines = 0; - break; - case JoinType::MITER: - for (int32_t indexOne = 0; indexOne < numberOfLines; indexOne++) { - const int32_t indexTwo = (((indexOne + 1) <= lastVertexIndex) ? (indexOne + 1) : 0); - const int32_t indexThree = (((indexTwo + 1) <= lastVertexIndex) ? (indexTwo + 1) : 0); - if (m_debugFlag) { - std::cout << "JOIN: " << indexOne << ", " << indexTwo << ", " << indexThree << std::endl; - } - - const int32_t quadOneVertexIndex = indexOne * 4; - const int32_t quadTwoVertexIndex = indexTwo * 4; - performJoin(indexOne, indexTwo, indexThree, quadOneVertexIndex, quadTwoVertexIndex); - } - break; + + /* + * Perform joins of connected quads + */ + for (int32_t i = 0; i < numQuadsToConnect; i++) { + CaretAssertVectorIndex(m_quadInfo, i); + const QuadInfo& quad = m_quadInfo[i]; + + const int32_t nextQuadIndex = ((i < numQuadsMinusOne) ? (i + 1) : 0); + CaretAssertVectorIndex(m_quadInfo, nextQuadIndex); + const QuadInfo& nextQuad = m_quadInfo[nextQuadIndex]; + + /* + * Does quad "i" connect to quad "i+1" ? + */ + if (quad.m_vertexTwoIndex == nextQuad.m_vertexOneIndex) { + const int32_t quadOneVertexIndex = i * 4; + const int32_t quadTwoVertexIndex = nextQuadIndex * 4; + + performJoin(quad.m_vertexOneIndex, + quad.m_vertexTwoIndex, + nextQuad.m_vertexTwoIndex, + quadOneVertexIndex, + quadTwoVertexIndex); + } } } @@ -964,25 +1058,25 @@ GraphicsOpenGLLineDrawing::joinQuads() * Perform a join using the last two vertices in quad one * and the first two vertices in quad two * - * @param lineVertexIndexOne - * Index of first vertex in line segment - * @param lineVertexIndexTwo - * Index of second vertex in line segment - * @param lineVertexIndexThree - * Index of three vertex in line segment + * @param windowVertexIndexOne + * Index of first window vertex from line segment + * @param windowVertexIndexTwo + * Index of second window from line segment + * @param windowVertexIndexThree + * Index of three window from line segment * @param quadOneVertexIndex * Index of first vertex in first quad * @param quadTwoVertexIndex * Index of first vertex in second quad */ void -GraphicsOpenGLLineDrawing::performJoin(const int32_t lineVertexIndexOne, - const int32_t lineVertexIndexTwo, - const int32_t lineVertexIndexThree, +GraphicsOpenGLLineDrawing::performJoin(const int32_t windowVertexIndexOne, + const int32_t windowVertexIndexTwo, + const int32_t windowVertexIndexThree, const int32_t quadOneVertexIndex, const int32_t quadTwoVertexIndex) { - if (m_debugFlag) std::cout << "Join: " << lineVertexIndexOne << ", " << lineVertexIndexTwo << ", " << lineVertexIndexThree << std::endl; + if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; CaretAssert(m_primitive); /* @@ -990,12 +1084,12 @@ GraphicsOpenGLLineDrawing::performJoin(const int32_t lineVertexIndexOne, * line segments in window coordinates makes a left * or right turn */ - CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexOne * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexTwo * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (lineVertexIndexThree * 3) + 2); - const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[lineVertexIndexOne * 3], - &m_vertexWindowXYZ[lineVertexIndexTwo * 3], - &m_vertexWindowXYZ[lineVertexIndexThree * 3]); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); + const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], + &m_vertexWindowXYZ[windowVertexIndexTwo * 3], + &m_vertexWindowXYZ[windowVertexIndexThree * 3]); int32_t quadOneSideBeginVertexIndex = -1; @@ -1038,6 +1132,12 @@ GraphicsOpenGLLineDrawing::performJoin(const int32_t lineVertexIndexOne, const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; + /* + * Miter limit is a multiple of the line thickness + */ + const float miterLimit = m_lineThicknessPixels;// * 2.0f; + const float miterLimitSquared = miterLimit * miterLimit; + /* * Find location of where the edges in the quads intersect */ @@ -1045,8 +1145,110 @@ GraphicsOpenGLLineDrawing::performJoin(const int32_t lineVertexIndexOne, if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { intersectionXYZ[2] = q1v1[2]; if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; - m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); - m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); + + /* + * When the angle is very sharp, the miter point can be very long and pointy + * so limit to a multiplier of the line thickness + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; + const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, + intersectionXYZ); + if (distanceSquared > miterLimitSquared) { + /* + * Extend lines by the miter limit to create a new quad + */ + float newV1[3]; + createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); + float newV2[3]; + createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); + + m_quadJoins.push_back(QuadJoin(q1v2, + newV1, + q2v1, + newV2, + quadOneSideEndVertexIndex, + quadTwoSideBeginVertexIndex)); + } + else { + /* + * Move the existing quad vertices to their intersection point + */ + m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); + } + } +} + +/** + * Create a vertex for a miter join when the length limit is exceeded + * + * @param v1 + * First vertex + * @param v2 + * Second vertex that is connected to the miter join vertex. + * @param miterLength + * Length of output vertex from v2 + * @param xyzOut + * Output with vertex used for miter join. + */ +void +GraphicsOpenGLLineDrawing::createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]) +{ + float n2[3]; + MathFunctions::subtractVectors(v2, v1, n2); + MathFunctions::normalizeVector(n2); + n2[0] *= miterLength; + n2[1] *= miterLength; + n2[2] *= miterLength; + xyzOut[0] = v2[0] + n2[0]; + xyzOut[1] = v2[1] + n2[1]; + xyzOut[2] = v2[2] + n2[2]; +} + +/** + * When the quads are joined, additional quads may be + * created to to fill in the gaps. + */ +void +GraphicsOpenGLLineDrawing::addMiterJoinQuads() +{ + const int32_t numJoinQuads = static_cast(m_quadJoins.size()); + for (int32_t i = 0; i < numJoinQuads; i++) { + CaretAssertVectorIndex(m_quadJoins, i); + const QuadJoin& quadJoin = m_quadJoins[i]; + + /* + * Add the join quad to the primitive + */ + switch (m_primitive->getColorType()) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + float rgba[4]; + m_primitiveFloatColor->getVertexFloatRGBA(quadJoin.m_primitiveOneTwoIndex, rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[0], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[3], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[6], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[9], rgba); + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + uint8_t rgba[4]; + m_primitiveByteColor->getVertexByteRGBA(quadJoin.m_primitiveThreeFourIndex, rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[0], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[3], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[6], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[9], rgba); + } + break; + } } } @@ -1062,16 +1264,21 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); + /* + * When estimating number of quads, + * include both the quads formed by the vertices + * and possible quads added for joining end points + */ int32_t estimatedNumberOfQuads = 0; switch (m_lineType) { case LineType::LINES: estimatedNumberOfQuads = numVertices / 2; break; case LineType::LINE_LOOP: - estimatedNumberOfQuads = numVertices; + estimatedNumberOfQuads = numVertices * 2; break; case LineType::LINE_STRIP: - estimatedNumberOfQuads = numVertices - 1; + estimatedNumberOfQuads = (numVertices - 1) * 2; break; } @@ -1095,6 +1302,18 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() m_primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); const int32_t numVerticesMinusOne = numVertices - 1; + + std::vector restartVertexFlags(numVertices, false); + for (auto index : m_vertexPrimitiveRestartIndices) { + restartVertexFlags[index] = true; + } + + /* + * Restart is disabled because it removes vertices that break joins + * Might want to draw all quads and use alpha=0 for quads that + * should not be joined. + */ + const bool restartEnabledFlag = true; switch (m_lineType) { case LineType::LINES: @@ -1102,19 +1321,27 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() const int32_t numLineSegments = (numVertices / 2); for (int32_t i = 0; i < numLineSegments; i++) { const int32_t i2 = i * 2; - createQuadFromWindowVertices(i2, i2 + 1, false); + createQuadFromWindowVertices(i2, i2 + 1); } } break; case LineType::LINE_LOOP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { - createQuadFromWindowVertices(i, i + 1, false); + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createQuadFromWindowVertices(i, i + 1); } - createQuadFromWindowVertices(numVerticesMinusOne, 0, true); + createQuadFromWindowVertices(numVerticesMinusOne, 0); break; case LineType::LINE_STRIP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { - createQuadFromWindowVertices(i, i + 1, false); + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createQuadFromWindowVertices(i, i + 1); } break; } @@ -1152,29 +1379,6 @@ GraphicsOpenGLLineDrawing::drawQuads() std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; } - -// switch (m_colorType) { -// case ColorType::BYTE_RGBA_PER_VERTEX: -// case ColorType::BYTE_RGBA_SOLID: -// CaretAssert(m_primitiveByteColor.get()); -// GraphicsEngineDataOpenGL::draw(m_openglContextPointer, -// m_primitiveByteColor.get()); -// if (m_debugFlag) { -// std::cout << std::endl << "Quad Primitive: " << m_primitiveByteColor->toString() << std::endl; -// std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; -// } -// break; -// case ColorType::FLOAT_RGBA_PER_VERTEX: -// case ColorType::FLOAT_RGBA_SOLID: -// CaretAssert(m_primitiveFloatColor.get()); -// GraphicsEngineDataOpenGL::draw(m_openglContextPointer, -// m_primitiveFloatColor.get()); -// if (m_debugFlag) { -// std::cout << std::endl << "Quad Primitive: " << m_primitiveFloatColor->toString() << std::endl; -// std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; -// } -// break; -// } } /** diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index d15a37dba..1be146c09 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -24,6 +24,7 @@ #include +#include #include "CaretObject.h" #include "Matrix4x4.h" @@ -49,6 +50,9 @@ namespace caret { virtual ~GraphicsOpenGLLineDrawing(); + static bool draw(void* openglContextPointer, + const GraphicsPrimitive* primitive); + static bool drawLinesPerVertexFloatColor(void* openglContextPointer, const std::vector& xyz, const std::vector& rgba, @@ -120,11 +124,51 @@ namespace caret { /** A connected set of lines (last is not connected to first) */ LINE_STRIP }; + + /** + * Indices into input vertices of line + * that formed the quad + */ + class QuadInfo { + public: + QuadInfo(const int32_t vertexOneIndex, + const int32_t vertexTwoIndex) + : m_vertexOneIndex(vertexOneIndex), + m_vertexTwoIndex(vertexTwoIndex) { } + + int32_t m_vertexOneIndex; + int32_t m_vertexTwoIndex; + }; + + /** + * Quads created by joining of lines + */ + class QuadJoin { + public: + QuadJoin(const float xyzOne[3], + const float xyzTwo[3], + const float xyzThree[3], + const float xyzFour[3], + const int32_t primitiveOneTwoIndex, + const int32_t primitiveThreeFourIndex) + : m_primitiveOneTwoIndex(primitiveOneTwoIndex), + m_primitiveThreeFourIndex(primitiveThreeFourIndex) { + m_xyz.insert(m_xyz.end(), xyzOne, xyzOne + 3); + m_xyz.insert(m_xyz.end(), xyzTwo, xyzTwo + 3); + m_xyz.insert(m_xyz.end(), xyzThree, xyzThree + 3); + m_xyz.insert(m_xyz.end(), xyzFour, xyzFour + 3); + } + + std::vector m_xyz; + int32_t m_primitiveOneTwoIndex; + int32_t m_primitiveThreeFourIndex; + }; GraphicsOpenGLLineDrawing(void* openglContextPointer, const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType); @@ -137,6 +181,7 @@ namespace caret { const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType); @@ -157,8 +202,7 @@ namespace caret { void convertLineSegmentsToQuads(); void createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo, - const bool lastVertexFlag); + const int32_t indexTwo); void drawQuads(); @@ -170,6 +214,13 @@ namespace caret { void joinQuads(); + void addMiterJoinQuads(); + + void createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]); + void* m_openglContextPointer; const std::vector& m_inputXYZ; @@ -178,6 +229,8 @@ namespace caret { const std::vector& m_inputByteRGBA; + std::set m_vertexPrimitiveRestartIndices; + const float m_lineThicknessPixels; const ColorType m_colorType; @@ -214,6 +267,10 @@ namespace caret { std::unique_ptr m_primitiveByteColor; + std::vector m_quadInfo; + + std::vector m_quadJoins; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index be31f9b41..be2f7d022 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -117,6 +117,11 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) m_alternativeFloatRGBA = obj.m_alternativeFloatRGBA; m_alternativeUnsignedByteRGBA = obj.m_alternativeUnsignedByteRGBA; m_floatTextureSTR = obj.m_floatTextureSTR; + m_lineWidthType = obj.m_lineWidthType; + m_lineWidthValue = obj.m_lineWidthValue; + m_pointSizeType = obj.m_pointSizeType; + m_pointDiameterValue = obj.m_pointDiameterValue; + m_primitiveRestartIndices = obj.m_primitiveRestartIndices; m_textureImageBytesRGBA = obj.m_textureImageBytesRGBA; m_textureImageWidth = obj.m_textureImageWidth; m_textureImageHeight = obj.m_textureImageHeight; @@ -372,51 +377,87 @@ GraphicsPrimitive::toString() const } /** - * Convert to string. - * - * @param includeAllDataFlag - * If true, numerical values are included. Else, only type of data. + * @return Type of primitive as text. */ AString -GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const +GraphicsPrimitive::getPrimitiveTypeAsText() const { AString s; switch (m_primitiveType) { case PrimitiveType::LINE_LOOP: - s.appendWithNewLine("Primitive: Line Loop"); + s = "Line Loop"; break; case PrimitiveType::LINE_STRIP: - s.appendWithNewLine("Primitive: Line Strip"); + s = "Line Strip"; break; case PrimitiveType::LINES: - s.appendWithNewLine("Primitive: Lines"); + s = "Lines"; break; case PrimitiveType::POINTS: - s.appendWithNewLine("Primitive: Points"); + s = "Points"; break; case PrimitiveType::POLYGON: - s.appendWithNewLine("Primitive: Polygon"); + s = "Polygon"; break; case PrimitiveType::QUAD_STRIP: - s.appendWithNewLine("Primitive: Quad Strip"); + s = "Quad Strip"; break; case PrimitiveType::QUADS: - s.appendWithNewLine("Primitive: Quads"); + s = "Quads"; break; case PrimitiveType::TRIANGLE_FAN: - s.appendWithNewLine("Primitive: Triangle Fan"); + s = "Triangle Fan"; break; case PrimitiveType::TRIANGLE_STRIP: - s.appendWithNewLine("Primitive: Triangle Strip"); + s = "Triangle Strip"; break; case PrimitiveType::TRIANGLES: - s.appendWithNewLine("Primitive: Triangles"); + s = "Triangles"; + break; + } + + return s; +} + +/** + * @return Size type as text for the given size type. + * + * @param sizeType + * The size type. + */ +AString +GraphicsPrimitive::getSizeTypeAsText(const SizeType sizeType) const +{ + AString s; + + switch (sizeType) { + case SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + s = "Percentage Viewport Height"; + break; + case SizeType::PIXELS: + s = "Pixels"; break; } + return s; +} + +/** + * Convert to string. + * + * @param includeAllDataFlag + * If true, numerical values are included. Else, only type of data. + */ +AString +GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const +{ + AString s("Primitive: "); + + s.append(getPrimitiveTypeAsText()); + switch (m_vertexType) { case VertexType::FLOAT_XYZ: - s.appendWithNewLine("Vertex: " + AString::number(m_xyz.size()) + " Float XYZ. "); + s.appendWithNewLine("Vertex Count: " + AString::number(m_xyz.size() / 3) + " Float XYZ. "); if (includeAllDataFlag ) { s.append("\n "); const int32_t count = static_cast(m_xyz.size()); @@ -431,9 +472,18 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } + if ( ! m_primitiveRestartIndices.empty()) { + s.appendWithNewLine("Restart Indices Count: " + AString::number(m_primitiveRestartIndices.size())); + if (includeAllDataFlag) { + std::vector temp(m_primitiveRestartIndices.begin(), + m_primitiveRestartIndices.end()); + s.appendWithNewLine(" " + AString::fromNumbers(temp, ", ")); + } + } + switch (m_normalVectorType) { case NormalVectorType::FLOAT_XYZ: - s.appendWithNewLine("Normal Vector: " + AString::number(m_floatNormalVectorXYZ.size()) + " Float XYZ. "); + s.appendWithNewLine("Normal Vector Count: " + AString::number(m_floatNormalVectorXYZ.size() / 3) + " Float XYZ. "); break; if (includeAllDataFlag ) { s.append("\n "); @@ -454,7 +504,7 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const case GraphicsPrimitive::ColorType::NONE: break; case ColorType::FLOAT_RGBA: - s.appendWithNewLine("Color: " + AString::number(m_floatRGBA.size()) + " Float RGBA 0.0 to 1.0. "); + s.appendWithNewLine("Color Count: " + AString::number(m_floatRGBA.size() / 4) + " Float RGBA 0.0 to 1.0. "); if (includeAllDataFlag ) { s.append("\n "); const int32_t count = static_cast(m_floatRGBA.size()); @@ -467,7 +517,7 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const } break; case ColorType::UNSIGNED_BYTE_RGBA: - s.appendWithNewLine("Color: " + AString::number(m_unsignedByteRGBA.size()) + " Unsigned Byte RGBA 0 to 255"); + s.appendWithNewLine("Color Count: " + AString::number(m_unsignedByteRGBA.size() / 4) + " Unsigned Byte RGBA 0 to 255"); if (includeAllDataFlag ) { s.append("\n "); const int32_t count = static_cast(m_unsignedByteRGBA.size()); @@ -501,6 +551,50 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } + bool addLineWidthFlag = false; + bool addPointSizeFlag = false; + + switch (m_primitiveType) { + case PrimitiveType::LINE_LOOP: + addLineWidthFlag = true; + break; + case PrimitiveType::LINE_STRIP: + addLineWidthFlag = true; + break; + case PrimitiveType::LINES: + addLineWidthFlag = true; + break; + case PrimitiveType::POINTS: + addPointSizeFlag = true; + break; + case PrimitiveType::POLYGON: + break; + case PrimitiveType::QUAD_STRIP: + break; + case PrimitiveType::QUADS: + break; + case PrimitiveType::TRIANGLE_FAN: + break; + case PrimitiveType::TRIANGLE_STRIP: + break; + case PrimitiveType::TRIANGLES: + break; + } + + if (addLineWidthFlag) { + s.appendWithNewLine("Line Width Type: " + + getSizeTypeAsText(m_lineWidthType) + + "; Width Value: " + + AString::number(m_lineWidthValue, 'f', 3)); + } + + if (addPointSizeFlag) { + s.appendWithNewLine("Point Diameter Type: " + + getSizeTypeAsText(m_pointSizeType) + + "; Diameter Value: " + + AString::number(m_pointDiameterValue, 'f', 3)); + } + return s; } @@ -656,6 +750,130 @@ GraphicsPrimitive::replaceVertexFloatXYZ(const int32_t vertexIndex, m_xyz[offset + 2] = xyz[2]; } +/** + * Get the float RGBA coloring for a vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param rgbaOut + * Output with RGBA. + */ +void +GraphicsPrimitive::getVertexFloatRGBA(const int32_t vertexIndex, + float rgbaOut[4]) const +{ + const int32_t i4 = vertexIndex * 4; + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertVectorIndex(m_floatRGBA, i4 + 3); + rgbaOut[0] = m_floatRGBA[i4]; + rgbaOut[1] = m_floatRGBA[i4 + 1]; + rgbaOut[2] = m_floatRGBA[i4 + 2]; + rgbaOut[3] = m_floatRGBA[i4 + 3]; + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertMessage(0, "Getting float RGBA from primitive but coloring type is Byte"); + CaretLogWarning("Getting float RGBA from primitive but coloring type is Byte"); + break; + } +} + +/** + * Replace the float RGBA coloring for a vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param rgba + * New RGBA for vertex. + */ +void +GraphicsPrimitive::replaceVertexFloatRGBA(const int32_t vertexIndex, + const float rgba[4]) +{ + const int32_t i4 = vertexIndex * 4; + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertVectorIndex(m_floatRGBA, i4 + 3); + m_floatRGBA[i4] = rgba[0]; + m_floatRGBA[i4 + 1] = rgba[1]; + m_floatRGBA[i4 + 2] = rgba[2]; + m_floatRGBA[i4 + 3] = rgba[3]; + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertMessage(0, "Replacing float RGBA in primitive but coloring type is Byte"); + CaretLogWarning("Replacing float RGBA in primitive but coloring type is Byte"); + break; + } +} + +/** + * Get the byte RGBA coloring for a vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param rgbaOut + * Output with RGBA. + */ +void +GraphicsPrimitive::getVertexByteRGBA(const int32_t vertexIndex, + uint8_t rgbaOut[4]) const +{ + const int32_t i4 = vertexIndex * 4; + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertMessage(0, "Getting Byte RGBA in primitive but coloring type is Float"); + CaretLogWarning("Getting Byte RGBA in primitive but coloring type is Float"); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); + rgbaOut[0] = m_unsignedByteRGBA[i4]; + rgbaOut[1] = m_unsignedByteRGBA[i4 + 1]; + rgbaOut[2] = m_unsignedByteRGBA[i4 + 2]; + rgbaOut[3] = m_unsignedByteRGBA[i4 + 3]; + break; + } +} + +/** + * Replace the float RGBA coloring for a vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param rgba + * New RGBA for vertex. + */ +void +GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, + const uint8_t rgba[4]) +{ + const int32_t i4 = vertexIndex * 4; + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); + CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); + m_unsignedByteRGBA[i4] = rgba[0]; + m_unsignedByteRGBA[i4 + 1] = rgba[1]; + m_unsignedByteRGBA[i4 + 2] = rgba[2]; + m_unsignedByteRGBA[i4 + 3] = rgba[3]; + break; + } +} + /** * Get a bounds box for the vertex coordinates. * @@ -687,6 +905,137 @@ GraphicsPrimitive::getVertexBounds(BoundingBox& boundingBoxOut) const return m_boundingBoxValid; } +/** + * There may be instances where a primitive should stop and restart at + * non-consecutive vertices (such as a gap in connected line segment). + * Typically, this requires creating separate primitives around + * the gap. + * + * When this method is called, it indicates that any previously + * added points will not connect to any points after this method + * is called. + * + * This functionality is similar to that of glPrimitiveRestartIndex() + * that is not available in versions of OpenGL prior to 3.1. + * + * At this time, this functionality if available only for + * line strip and line loop. + */ +void +GraphicsPrimitive::addPrimitiveRestart() +{ + bool notApplicableFlag = false; + bool supportedFlag = false; + + switch (m_primitiveType) { + case PrimitiveType::LINE_LOOP: + supportedFlag = true; + break; + case PrimitiveType::LINE_STRIP: + supportedFlag = true; + break; + case PrimitiveType::LINES: + notApplicableFlag = true; + break; + case PrimitiveType::POINTS: + notApplicableFlag = true; + break; + case PrimitiveType::POLYGON: + notApplicableFlag = true; + break; + case PrimitiveType::QUAD_STRIP: + break; + case PrimitiveType::QUADS: + notApplicableFlag = true; + break; + case PrimitiveType::TRIANGLE_FAN: + break; + case PrimitiveType::TRIANGLE_STRIP: + break; + case PrimitiveType::TRIANGLES: + notApplicableFlag = true; + break; + } + + if (notApplicableFlag) { + CaretLogWarning("Requested primitive restart on non-applicable primitive type: " + + getPrimitiveTypeAsText()); + } + else if (supportedFlag) { + /* + * A set is used because a vertex could be added more than one time + */ + m_primitiveRestartIndices.insert(getNumberOfVertices()); + } + else { + CaretLogSevere("Requested primitive restart on not yet supported primitive type: " + + getPrimitiveTypeAsText()); + } +} + +/** + * Get the point diameter. + * + * @param sizeTypeOut + * Type of sizing. + * @param pointDiameterOut + * Diameter of point. + */ +void +GraphicsPrimitive::getPointDiameter(SizeType& sizeTypeOut, + float& pointDiameterOut) const +{ + sizeTypeOut = m_pointSizeType; + pointDiameterOut = m_pointDiameterValue; +} + +/** + * Set the point diameter. + * + * @param sizeType + * Type of sizing. + * @param pointDiameter + * Diameter of point. + */ +void +GraphicsPrimitive::setPointDiameter(const SizeType sizeType, + const float pointDiameter) +{ + m_pointSizeType = sizeType; + m_pointDiameterValue = pointDiameter; +} + +/** + * Get the line width. + * + * @param sizeTypeOut + * Type of sizing. + * @param lineWidthOut + * Width of line. + */ +void +GraphicsPrimitive::getLineWidth(SizeType& widthTypeOut, + float lineWidthOut) const +{ + widthTypeOut = m_lineWidthType; + lineWidthOut = m_lineWidthValue; +} + +/** + * Set the line width. + * + * @param sizeType + * Type of sizing. + * @param lineWidth + * Width of line. + */ +void +GraphicsPrimitive::setLineWidth(const SizeType widthType, + const float lineWidth) +{ + m_lineWidthType = widthType; + m_lineWidthValue = lineWidth; +} /** * @return A reference to the alternative coloring. An empty vector is returned diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 034dbaa7a..fcaa51528 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -24,6 +24,7 @@ #include #include +#include #include "CaretObject.h" #include "EventListenerInterface.h" @@ -143,6 +144,21 @@ namespace caret { TRIANGLES }; + /** + * Type for point size and line width + */ + enum class SizeType { + /** + * Size of point or width of line is a percentage of viewport height. + * Ranges [0.0, 100.0] + */ + PERCENTAGE_VIEWPORT_HEIGHT, + /** + * Size of point or width of line is in pixels + */ + PIXELS + }; + /** * Hint to graphics engine on how the primitive is used. * The hint must be set prior to loading of buffers. @@ -247,8 +263,34 @@ namespace caret { void replaceVertexFloatXYZ(const int32_t vertexIndex, const float xyz[3]); + void getVertexFloatRGBA(const int32_t vertexIndex, + float rgbaOut[4]) const; + + void replaceVertexFloatRGBA(const int32_t vertexIndex, + const float rgba[4]); + + void getVertexByteRGBA(const int32_t vertexIndex, + uint8_t rgbaOut[4]) const; + + void replaceVertexByteRGBA(const int32_t vertexIndex, + const uint8_t rgba[4]); + bool getVertexBounds(BoundingBox& boundingBoxOut) const; + void addPrimitiveRestart(); + + void getPointDiameter(SizeType& sizeTypeOut, + float& pointDiameterOut) const; + + void setPointDiameter(const SizeType sizeType, + const float pointDiameter); + + void getLineWidth(SizeType& widthTypeOut, + float lineWidthOut) const; + + void setLineWidth(const SizeType widthType, + const float lineWidth); + GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); @@ -289,6 +331,10 @@ namespace caret { const float y, const float z); + AString getPrimitiveTypeAsText() const; + + AString getSizeTypeAsText(const SizeType sizeType) const; + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; @@ -323,8 +369,18 @@ namespace caret { int32_t m_textureImageHeight = -1; + SizeType m_pointSizeType = SizeType::PIXELS; + + float m_pointDiameterValue = 1.0f; + + SizeType m_lineWidthType = SizeType::PIXELS; + + float m_lineWidthValue = 1.0f; + mutable std::unique_ptr m_boundingBox; + std::set m_primitiveRestartIndices; + private: std::vector m_xyz; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 4d0a83a54..285c4f415 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -80,10 +80,19 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(openglContextPointer, - ellipseXYZ, - rgba, - lineThickness); + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + rgba)); + const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&ellipseXYZ[i * 3]); + } + + primitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + lineThickness); + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsOpenGLLineDrawing::draw(openglContextPointer, + primitive.get()); } /** -- GitLab From 73f062f91db4cf02d5150ad4b227f0773713d6fd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 6 Nov 2017 16:05:51 -0600 Subject: [PATCH 493/755] Fixed bug that may prevented changing of matrix grid outline color (currently loaded matrix ignored changed color). --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 9 +- src/Files/ChartableTwoFileMatrixChart.cxx | 8 +- src/Files/ChartableTwoFileMatrixChart.h | 4 +- src/Files/CiftiMappableDataFile.cxx | 117 ++++++++++++------ src/Files/CiftiMappableDataFile.h | 13 +- 5 files changed, 107 insertions(+), 44 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index d8b7c4863..eca93646a 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1310,7 +1310,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const float zooming, std::vector& rowColumnHighlightingOut) { - GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType); + GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, + CiftiMappableDataFile::MatrixGridMode::FILLED); if (matrixPrimitive == NULL) { return; } @@ -1363,9 +1364,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT glPolygonMode(GL_FRONT, GL_LINE); - GraphicsEngineDataOpenGL::drawWithAlternativeColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - matrixPrimitive, - matrixChart->getMatrixChartGraphicsPrimitiveGridColorIdentifier()); + GraphicsPrimitiveV3fC4f* matrixGridPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, + CiftiMappableDataFile::MatrixGridMode::OUTLINE); + drawPrimitivePrivate(matrixGridPrimitive); glPolygonMode(GL_FRONT, GL_FILL); } diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 43f2f8fbc..64b029030 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -409,14 +409,18 @@ ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, * * @param matrixViewMode * The matrix visualization mode (upper/lower). + * @param gridMode + * The grid mode (filled or outline) */ GraphicsPrimitiveV3fC4f* -ChartableTwoFileMatrixChart::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const +ChartableTwoFileMatrixChart::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, + const CiftiMappableDataFile::MatrixGridMode gridMode) const { const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); - return ciftiMapFile->getMatrixChartingGraphicsPrimitive(matrixViewMode); + return ciftiMapFile->getMatrixChartingGraphicsPrimitive(matrixViewMode, + gridMode); } /** diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index bcec3c116..bdffb709e 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -26,6 +26,7 @@ #include "ChartTwoMatrixLoadingDimensionEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "ChartableTwoFileBaseChart.h" +#include "CiftiMappableDataFile.h" namespace caret { @@ -58,7 +59,8 @@ namespace caret { int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; - GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, + const CiftiMappableDataFile::MatrixGridMode gridMode) const; int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const; diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 4c126722a..95f72e39e 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1398,6 +1398,7 @@ CiftiMappableDataFile::invalidateColoringInAllMaps() * and in particular, matrix grid outline coloring */ m_matrixGraphicsPrimitive.reset(); + m_matrixGraphicsOutlinePrimitive.reset(); invalidateHistogramChartColoring(); } @@ -1484,39 +1485,61 @@ CiftiMappableDataFile::getMatrixRGBA(std::vector &rgba, * * @param matrixViewMode * The matrix visualization mode (upper/lower). + * @param gridMode + * The grid mode (filled or outline) */ GraphicsPrimitiveV3fC4f* -CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const -{ - if (m_matrixGraphicsPrimitive == NULL) { +CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, + const MatrixGridMode gridMode) const +{ + EventCaretPreferencesGet preferencesEvent; + EventManager::get()->sendEvent(preferencesEvent.getPointer()); + CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); + uint8_t gridByteRGBA[4] = { 0, 0, 0, 0 }; + + GraphicsPrimitiveV3fC4f* matrixPrimitive = NULL; + switch (gridMode) { + case MatrixGridMode::FILLED: + matrixPrimitive = m_matrixGraphicsPrimitive.get(); + break; + case MatrixGridMode::OUTLINE: + caretPreferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridByteRGBA); + matrixPrimitive = m_matrixGraphicsOutlinePrimitive.get(); + + if ((gridByteRGBA[0] != m_previousMatrixGridRGBA[0]) + || (gridByteRGBA[1] != m_previousMatrixGridRGBA[1]) + || (gridByteRGBA[2] != m_previousMatrixGridRGBA[2]) + || (gridByteRGBA[3] != m_previousMatrixGridRGBA[3])) { + matrixPrimitive = NULL; + m_previousMatrixGridRGBA[0] = gridByteRGBA[0]; + m_previousMatrixGridRGBA[1] = gridByteRGBA[1]; + m_previousMatrixGridRGBA[2] = gridByteRGBA[2]; + m_previousMatrixGridRGBA[3] = gridByteRGBA[3]; + } + break; + } + + if (matrixPrimitive == NULL) { int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; if (getMatrixForChartingRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { const int32_t numberOfCells = numberOfRows * numberOfColumns; if (numberOfCells > 0) { - m_matrixGraphicsPrimitive - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); - m_matrixGraphicsPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS - m_matrixGraphicsPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS + matrixPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); /* * RGBA for grid outline */ - EventCaretPreferencesGet preferencesEvent; - EventManager::get()->sendEvent(preferencesEvent.getPointer()); - CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); float cellOutlineRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; if (caretPreferences != NULL) { - uint8_t gridByteRGBA[4]; - caretPreferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridByteRGBA); cellOutlineRGBA[0] = static_cast(gridByteRGBA[0]) / 255.0f; cellOutlineRGBA[1] = static_cast(gridByteRGBA[1]) / 255.0f; cellOutlineRGBA[2] = static_cast(gridByteRGBA[2]) / 255.0f; cellOutlineRGBA[3] = 1.0; } - std::vector gridOutlineRGBA; - gridOutlineRGBA.reserve(numberOfCells * 4 * 4); // four vertices per cell, four color components per vertex /* * Alpha zero for cells that are "not drawn" @@ -1602,23 +1625,35 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr } } - if (drawCellFlag) { - m_matrixGraphicsPrimitive->addVertex(cellX, cellY, 0.0, rgba); - m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, rgba); - m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); - m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); - for (int32_t i4 = 0; i4 < 4; i4++) { - gridOutlineRGBA.insert(gridOutlineRGBA.end(), cellOutlineRGBA, cellOutlineRGBA + 4); - } - } - else { - m_matrixGraphicsPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); - m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); - m_matrixGraphicsPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); - m_matrixGraphicsPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); - for (int32_t i4 = 0; i4 < 4; i4++) { - gridOutlineRGBA.insert(gridOutlineRGBA.end(), cellNotDrawRGBA, cellNotDrawRGBA + 4); - } + switch (gridMode) { + case MatrixGridMode::FILLED: + if (drawCellFlag) { + matrixPrimitive->addVertex(cellX, cellY, 0.0, rgba); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, rgba); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); + } + else { + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); + } + break; + case MatrixGridMode::OUTLINE: + if (drawCellFlag) { + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellOutlineRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellOutlineRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellOutlineRGBA); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellOutlineRGBA); + } + else { + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); + } + break; } cellX += cellWidth; @@ -1626,15 +1661,24 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr cellY -= cellHeight; } - - m_matrixGraphicsPrimitive->setAlternativeFloatRGBA(getMatrixChartGraphicsPrimitiveGridColorIdentifier(), - gridOutlineRGBA); } - } } - return m_matrixGraphicsPrimitive.get(); + switch (gridMode) { + case MatrixGridMode::FILLED: + if (matrixPrimitive != m_matrixGraphicsPrimitive.get()) { + m_matrixGraphicsPrimitive.reset(matrixPrimitive); + } + break; + case MatrixGridMode::OUTLINE: + if (matrixPrimitive != m_matrixGraphicsOutlinePrimitive.get()) { + m_matrixGraphicsOutlinePrimitive.reset(matrixPrimitive); + } + break; + } + + return matrixPrimitive; } @@ -2462,6 +2506,7 @@ CiftiMappableDataFile::updateScalarColoringForMap(const int32_t mapIndex, invalidateHistogramChartColoring(); m_matrixGraphicsPrimitive.reset(); + m_matrixGraphicsOutlinePrimitive.reset(); } /** diff --git a/src/Files/CiftiMappableDataFile.h b/src/Files/CiftiMappableDataFile.h index eb0655f9a..92ce980ff 100644 --- a/src/Files/CiftiMappableDataFile.h +++ b/src/Files/CiftiMappableDataFile.h @@ -477,6 +477,10 @@ namespace caret { CiftiMappableDataFile& operator=(const CiftiMappableDataFile&); public: + enum class MatrixGridMode { + FILLED, + OUTLINE + }; virtual void getMapData(const int32_t mapIndex, std::vector& dataOut) const; @@ -490,7 +494,8 @@ namespace caret { int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; - GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) const; + GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, + const MatrixGridMode gridMode) const; /** Identifier for the matrix primitives alternative color used for the grid coloring */ int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const { return 1; } @@ -744,8 +749,14 @@ namespace caret { /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; + /** Primitive for matrix cells */ mutable std::unique_ptr m_matrixGraphicsPrimitive; + /** Primitive for grid outline around matrix cells */ + mutable std::unique_ptr m_matrixGraphicsOutlinePrimitive; + + mutable uint8_t m_previousMatrixGridRGBA[4] = { 0, 1, 2, 3 }; + int32_t m_fileHistogramNumberOfBuckets = 100; /** Histogram with limited values used when statistics computed on all data in file */ -- GitLab From 6156434215523366975f0751b226120365db6ae4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Nov 2017 09:14:32 -0600 Subject: [PATCH 494/755] Removed alternative coloring from graphics primitives as it is no longer used. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 270 +--------------------- src/Graphics/GraphicsEngineDataOpenGL.h | 21 +- src/Graphics/GraphicsPrimitive.cxx | 212 +---------------- src/Graphics/GraphicsPrimitive.h | 20 -- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 17 -- src/Graphics/GraphicsPrimitiveV3fC4f.h | 3 - src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 17 -- src/Graphics/GraphicsPrimitiveV3fC4ub.h | 3 - 8 files changed, 16 insertions(+), 547 deletions(-) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index f5b77f980..967858862 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -67,42 +67,12 @@ GraphicsEngineDataOpenGL::~GraphicsEngineDataOpenGL() deleteBuffers(); } -/** - * Delete an OpenGL buffer object. - * - * @param bufferObject - * Reference to pointer of buffer object for deletion. - * If NULL, no action is taken. - * Will be NULL upon exit. - */ -void -GraphicsEngineDataOpenGL::deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject) -{ - if (bufferObject != NULL) { - delete bufferObject; - bufferObject = NULL; - } -} - /** * Delete the OpenGL buffer objects. */ void GraphicsEngineDataOpenGL::deleteBuffers() { - //deleteBufferObjectHelper(m_coordinateBufferObject); - - //deleteBufferObjectHelper(m_normalVectorBufferObject); - - //deleteBufferObjectHelper(m_colorBufferObject); - - //deleteBufferObjectHelper(m_textureCoordinatesBufferObject); - -// for (auto& mapBuff: m_alternativeColorBufferObjectMap) { -// deleteBufferObjectHelper(mapBuff.second); -// } - m_alternativeColorBufferObjectMap.clear(); - if (m_textureImageDataName != NULL) { delete m_textureImageDataName; m_textureImageDataName = NULL; @@ -485,118 +455,6 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv } } - -/** - * Load the buffer for the given alternative color identifier. If the buffer - * was previously loaded, no action is taken. - * - * @param primitive - * The graphics primitive that will be drawn. - * @param alternativeColorIdentifier - * Identifier for the alternative color. - * @return - * True if the alternative color buffer is valid for the given alternative - * color identifier so drawing can be performed. Otherwise, false is returned. - */ -GraphicsOpenGLBufferObject* -GraphicsEngineDataOpenGL::loadAlternativeColorBuffer(GraphicsPrimitive* primitive, - const int32_t alternativeColorIdentifier) -{ - const auto& iter = m_alternativeColorBufferObjectMap.find(alternativeColorIdentifier); - if (iter != m_alternativeColorBufferObjectMap.end()) { - return iter->second.get(); - } - - GraphicsOpenGLBufferObject* outputOpenGLBufferObject = NULL; - - GLenum usageHint = getOpeGLBufferUsageHint(primitive); - - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - { - const std::vector& alternativeFloatRGBA = primitive->getAlternativeFloatRGBAProtected(alternativeColorIdentifier); - if ((alternativeFloatRGBA.size() / 4) != (primitive->m_xyz.size() / 3)) { - const AString msg("Number of alternative RGBA values is for " - + AString::number((alternativeFloatRGBA.size() / 4)) - + " vertices but should be for " - + AString::number((primitive->m_xyz.size() / 3)) - + " vertices."); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return NULL; - } - - EventGraphicsOpenGLCreateBufferObject createEvent; - EventManager::get()->sendEvent(createEvent.getPointer()); - GraphicsOpenGLBufferObject* bufferObject = createEvent.getOpenGLBufferObject(); - CaretAssert(bufferObject->getBufferObjectName()); - - m_componentsPerColor = 4; - m_colorDataType = GL_FLOAT; - - const GLuint colorSizeBytes = alternativeFloatRGBA.size() * sizeof(float); - const GLvoid* colorDataPointer = (const GLvoid*)&alternativeFloatRGBA[0]; - - glBindBuffer(GL_ARRAY_BUFFER, - bufferObject->getBufferObjectName()); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - usageHint); - - std::shared_ptr bufferObjectPtr(bufferObject); - m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, - bufferObjectPtr)); - outputOpenGLBufferObject = bufferObject; - } - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - { - const std::vector& alternativeUnsignedByteRGBA = primitive->getAlternativeUnsignedByteRGBAProtected(alternativeColorIdentifier); - if ((alternativeUnsignedByteRGBA.size() / 4) != (primitive->m_xyz.size() / 3)) { - const AString msg("Number of alternative RGBA values is for " - + AString::number((alternativeUnsignedByteRGBA.size() / 4)) - + " vertices but should be for " - + AString::number((primitive->m_xyz.size() / 3)) - + " vertices."); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return NULL; - } - - EventGraphicsOpenGLCreateBufferObject createEvent; - EventManager::get()->sendEvent(createEvent.getPointer()); - GraphicsOpenGLBufferObject* bufferObject = createEvent.getOpenGLBufferObject(); - CaretAssert(bufferObject->getBufferObjectName()); - - m_componentsPerColor = 4; - m_colorDataType = GL_UNSIGNED_BYTE; - - const GLuint colorSizeBytes = alternativeUnsignedByteRGBA.size() * sizeof(uint8_t); - const GLvoid* colorDataPointer = (const GLvoid*)&alternativeUnsignedByteRGBA[0]; - - glBindBuffer(GL_ARRAY_BUFFER, - bufferObject->getBufferObjectName()); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - usageHint); - - std::shared_ptr bufferObjectPtr(bufferObject); - m_alternativeColorBufferObjectMap.insert(std::make_pair(alternativeColorIdentifier, - bufferObjectPtr)); - outputOpenGLBufferObject = bufferObject; - } - break; - } - - return outputOpenGLBufferObject; -} - - /** * Draw the given graphics primitive. * @@ -609,13 +467,10 @@ void GraphicsEngineDataOpenGL::draw(void* openglContextPointer, GraphicsPrimitive* primitive) { - float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; drawPrivate(PrivateDrawMode::DRAW_NORMAL, openglContextPointer, primitive, - NULL, - -1, - dummyRGBA); + NULL); } /** @@ -663,15 +518,12 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); - float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; GraphicsPrimitiveSelectionHelper selectionHelper(primitive); selectionHelper.setupSelectionBeforeDrawing(); drawPrivate(PrivateDrawMode::DRAW_SELECTION, openglContextPointer, primitive, - &selectionHelper, - -1, - dummyRGBA); + &selectionHelper); /* * QOpenGLWidget Note: The QOpenGLWidget always renders in a @@ -716,54 +568,6 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, } } - -/** - * Draw the given graphics primitive using a solid color. - * - * @param openglContextPointer - * Pointer to the active OpenGL context. - * @param primitive - * Primitive that is drawn. - * @param solidColorOverrideRGBA - * Color that is applied to all vertices. - */ -void -GraphicsEngineDataOpenGL::drawWithOverrideColor(void* openglContextPointer, - GraphicsPrimitive* primitive, - const float solidColorOverrideRGBA[4]) -{ - drawPrivate(PrivateDrawMode::DRAW_COLOR_SOLID, - openglContextPointer, - primitive, - NULL, - -1, - solidColorOverrideRGBA); -} - -/** - * Draw the given graphics primitive using an alternative color. - * - * @param openglContextPointer - * Pointer to the active OpenGL context. - * @param primitive - * Primitive that is drawn. - * @param alternativeColorIdentifier - * Identifier for the alternative color. - */ -void -GraphicsEngineDataOpenGL::drawWithAlternativeColor(void* openglContextPointer, - GraphicsPrimitive* primitive, - const int32_t alternativeColorIdentifier) -{ - float dummyRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - drawPrivate(PrivateDrawMode::DRAW_COLOR_ALTERNATIVE, - openglContextPointer, - primitive, NULL, - alternativeColorIdentifier, - dummyRGBA); -} - - /** * Draw the graphics primitive. * @@ -775,18 +579,12 @@ GraphicsEngineDataOpenGL::drawWithAlternativeColor(void* openglContextPointer, * Primitive that is drawn. * @param primitiveSelectionHelper * Selection helper when draw mode is selection. - * @param alternativeColorIdentifier - * Identifier for the alternative color. - * @param solidColorRGBA - * Color for solid color mode. */ void GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, void* openglContextPointer, GraphicsPrimitive* primitive, - GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, - const int32_t alternativeColorIdentifier, - const float solidColorRGBA[4]) + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { CaretAssert(openglContextPointer); CaretAssert(primitive); @@ -795,15 +593,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, } switch (drawMode) { - case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: - if ( ! primitive->isAlternativeColoringValid(alternativeColorIdentifier)) { - CaretLogSevere("Alternative coloring is invalid for index=" - + AString::number(alternativeColorIdentifier)); - return; - } - break; - case PrivateDrawMode::DRAW_COLOR_SOLID: - break; case PrivateDrawMode::DRAW_NORMAL: break; case PrivateDrawMode::DRAW_SELECTION: @@ -851,19 +640,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, return; } - GraphicsOpenGLBufferObject* alternativeColorBufferObject = NULL; switch (drawMode) { - case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: - alternativeColorBufferObject = openglData->loadAlternativeColorBuffer(primitive, - alternativeColorIdentifier); - if (alternativeColorBufferObject == NULL) { - CaretAssertMessage(0, "Coordinate buffer is INVALID"); - CaretLogSevere("Coordinate buffer is INVALID"); - return; - } - break; - case PrivateDrawMode::DRAW_COLOR_SOLID: - break; case PrivateDrawMode::DRAW_NORMAL: break; case PrivateDrawMode::DRAW_SELECTION: @@ -912,47 +689,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GLuint localColorBufferName = 0; if (hasColorFlag) { switch (drawMode) { - case PrivateDrawMode::DRAW_COLOR_ALTERNATIVE: - { - glEnableClientState(GL_COLOR_ARRAY); - CaretAssert(glIsBuffer(alternativeColorBufferObject->getBufferObjectName())); - glBindBuffer(GL_ARRAY_BUFFER, alternativeColorBufferObject->getBufferObjectName()); - glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); - } - break; - case PrivateDrawMode::DRAW_COLOR_SOLID: - { - const int32_t numberOfVertices = primitive->m_xyz.size() / 3; - if (numberOfVertices > 0) { - glGenBuffers(1, &localColorBufferName); - CaretAssert(localColorBufferName > 0); - - const GLint componentsPerColor = 4; - const GLenum colorDataType = GL_FLOAT; - - std::vector colorRGBA(numberOfVertices * componentsPerColor); - for (int32_t i = 0; i < numberOfVertices; i++) { - const int32_t i4 = i * 4; - CaretAssertVectorIndex(colorRGBA, i4 + 3); - colorRGBA[i4] = solidColorRGBA[0]; - colorRGBA[i4+1] = solidColorRGBA[1]; - colorRGBA[i4+2] = solidColorRGBA[2]; - colorRGBA[i4+3] = solidColorRGBA[3]; - } - - const GLuint colorSizeBytes = colorRGBA.size() * sizeof(float); - const GLvoid* colorDataPointer = (const GLvoid*)&colorRGBA[0]; - glBindBuffer(GL_ARRAY_BUFFER, - localColorBufferName); - glBufferData(GL_ARRAY_BUFFER, - colorSizeBytes, - colorDataPointer, - GL_STREAM_DRAW); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); - } - } - break; case PrivateDrawMode::DRAW_NORMAL: { glEnableClientState(GL_COLOR_ARRAY); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 8fb00d307..faef4556a 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -53,14 +53,6 @@ namespace caret { int32_t& selectedPrimitiveIndexOut, float& selectedPrimitiveDepthOut); - static void drawWithOverrideColor(void* openglContextPointer, - GraphicsPrimitive* primitive, - const float solidColorOverrideRGBA[4]); - - static void drawWithAlternativeColor(void* openglContextPointer, - GraphicsPrimitive* primitive, - const int32_t alternativeColorIdentifier); - const void* getOpenGLContextPointer() const; void invalidateCoordinates(); @@ -71,8 +63,6 @@ namespace caret { private: enum class PrivateDrawMode { - DRAW_COLOR_ALTERNATIVE, - DRAW_COLOR_SOLID, DRAW_NORMAL, DRAW_SELECTION, }; @@ -91,19 +81,12 @@ namespace caret { void loadTextureCoordinateBuffer(GraphicsPrimitive* primitive); - GraphicsOpenGLBufferObject* loadAlternativeColorBuffer(GraphicsPrimitive* primitive, - const int32_t alternativeColorIdentifier); - void loadTextureImageDataBuffer(GraphicsPrimitive* primitive); - void deleteBufferObjectHelper(GraphicsOpenGLBufferObject* &bufferObject); - static void drawPrivate(const PrivateDrawMode drawMode, void* openglContextPointer, GraphicsPrimitive* primitive, - GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper, - const int32_t alternativeColorIdentifier, - const float solidColorRGBA[4]); + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; @@ -131,8 +114,6 @@ namespace caret { std::unique_ptr m_colorBufferObject; - std::map> m_alternativeColorBufferObjectMap; - GLenum m_colorDataType = GL_FLOAT; GLint m_componentsPerColor = 0; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index be2f7d022..9a18351f3 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -114,8 +114,6 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; m_floatRGBA = obj.m_floatRGBA; m_unsignedByteRGBA = obj.m_unsignedByteRGBA; - m_alternativeFloatRGBA = obj.m_alternativeFloatRGBA; - m_alternativeUnsignedByteRGBA = obj.m_alternativeUnsignedByteRGBA; m_floatTextureSTR = obj.m_floatTextureSTR; m_lineWidthType = obj.m_lineWidthType; m_lineWidthValue = obj.m_lineWidthValue; @@ -598,76 +596,6 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const return s; } -/** - * @return Is the alternative coloring with the given identifier valid? - * - * @param identifier - * Identifier of the alternative coloring. - */ -bool -GraphicsPrimitive::isAlternativeColoringValid(const int32_t identifier) const -{ - bool validFlag = false; - - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - break; - case ColorType::FLOAT_RGBA: - validFlag = isAlternativeFloatRGBAValidProtected(identifier); - break; - case ColorType::UNSIGNED_BYTE_RGBA: - validFlag = isAlternativeUnsignedByteRGBAValidProtected(identifier); - break; - } - - return validFlag; -} - - -/** - * @return Is the alternative float coloring valid for the given identifier? - * - * @param identifier - * Identifier for alternative coloring. - */ -bool -GraphicsPrimitive::isAlternativeFloatRGBAValidProtected(const int32_t identifier) const -{ - std::map>::const_iterator iter = m_alternativeFloatRGBA.find(identifier); - - if (iter != m_alternativeFloatRGBA.end()) { - const int32_t numVerticesFromXYZ = m_xyz.size() / 3; - const int32_t numVerticesFromRGBA = iter->second.size() / 4; - if (numVerticesFromRGBA == numVerticesFromXYZ) { - return true; - } - } - - return false; -} - -/** - * @return Is the alternative unsigned byte coloring valid for the given identifier? - * - * @param identifier - * Identifier for alternative coloring. - */ -bool -GraphicsPrimitive::isAlternativeUnsignedByteRGBAValidProtected(const int32_t identifier) const -{ - std::map>::const_iterator iter = m_alternativeUnsignedByteRGBA.find(identifier); - - if (iter != m_alternativeUnsignedByteRGBA.end()) { - const int32_t numVerticesFromXYZ = m_xyz.size() / 3; - const int32_t numVerticesFromRGBA = iter->second.size() / 4; - if (numVerticesFromRGBA == numVerticesFromXYZ) { - return true; - } - } - - return false; -} - /** * Add a vertex. * @@ -748,6 +676,10 @@ GraphicsPrimitive::replaceVertexFloatXYZ(const int32_t vertexIndex, m_xyz[offset] = xyz[0]; m_xyz[offset + 1] = xyz[1]; m_xyz[offset + 2] = xyz[2]; + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateCoordinates(); + } } /** @@ -810,6 +742,10 @@ GraphicsPrimitive::replaceVertexFloatRGBA(const int32_t vertexIndex, CaretLogWarning("Replacing float RGBA in primitive but coloring type is Byte"); break; } + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateColors(); + } } /** @@ -872,6 +808,10 @@ GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, m_unsignedByteRGBA[i4 + 3] = rgba[3]; break; } + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateColors(); + } } /** @@ -1037,134 +977,6 @@ GraphicsPrimitive::setLineWidth(const SizeType widthType, m_lineWidthValue = lineWidth; } -/** - * @return A reference to the alternative coloring. An empty vector is returned - * if the alternative coloring data is invalid. - * - * @param identifier - * Identifier for alternative coloring. - */ -const std::vector& -GraphicsPrimitive::getAlternativeFloatRGBAProtected(const int32_t identifier) const -{ - std::map>::const_iterator iter = m_alternativeFloatRGBA.find(identifier); - - if (iter != m_alternativeFloatRGBA.end()) { - return iter->second; - } - - return m_dummyFloatRGBAVector; -} - -/** - * @return A reference to the alternative coloring. An empty vector is returned - * if the alternative coloring data is invalid. - * - * @param identifier - * Identifier for alternative coloring. - */ -const std::vector& -GraphicsPrimitive::getAlternativeUnsignedByteRGBAProtected(const int32_t identifier) const -{ - std::map>::const_iterator iter = m_alternativeUnsignedByteRGBA.find(identifier); - - if (iter != m_alternativeUnsignedByteRGBA.end()) { - return iter->second; - } - - return m_dummyUnsignedByteRGBAVector; -} - -/** - * Set alternative RGBA coloring with float data. - * - * @param identifier - * Any integer value used to identify the alternative coloring. - * @param rgbaFloat - * The alternative coloring that must contain the correct number of - * RGBA components for the primitive's number of vertices. - */ -void -GraphicsPrimitive::setAlternativeFloatRGBAProtected(const int32_t identifier, - const std::vector& rgbaFloat) -{ - const int32_t numVerticesFromXYZ = m_xyz.size() / 3; - const int32_t numVerticesFromRGBA = rgbaFloat.size() / 4; - if (numVerticesFromRGBA != numVerticesFromXYZ) { - const AString msg("Number of alternative RGBA values is for " - + AString::number(numVerticesFromRGBA) - + " vertices but should be for " - + AString::number(numVerticesFromXYZ) - + " vertices."); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return; - } - - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case ColorType::FLOAT_RGBA: - break; - case ColorType::UNSIGNED_BYTE_RGBA: - { - const AString msg("Alternative RGBA must match primitive color type which is unsigned byte"); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - } - break; - } - - m_alternativeFloatRGBA.insert(std::make_pair(identifier, - rgbaFloat)); -} - -/** - * Set alternative RGBA coloring with float data. - * - * @param identifier - * Any integer value used to identify the alternative coloring. - * @param rgbaByte - * The alternative coloring that must contain the correct number of - * RGBA components for the primitive's number of vertices. - */ -void -GraphicsPrimitive::setAlternativeUnsignedByteRGBAProtected(const int32_t identifier, - const std::vector& rgbaByte) -{ - const int32_t numVerticesFromXYZ = m_xyz.size() / 3; - const int32_t numVerticesFromRGBA = rgbaByte.size() / 4; - if (numVerticesFromRGBA != numVerticesFromXYZ) { - const AString msg("Number of alternative RGBA values is for " - + AString::number(numVerticesFromRGBA) - + " vertices but should be for " - + AString::number(numVerticesFromXYZ) - + " vertices."); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return; - } - - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case ColorType::FLOAT_RGBA: - { - const AString msg("Alternative RGBA must match primitive color type which is float"); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - } - break; - case ColorType::UNSIGNED_BYTE_RGBA: - break; - } - - m_alternativeUnsignedByteRGBA.insert(std::make_pair(identifier, - rgbaByte)); -} - /** * Set the image for the texture. * diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index fcaa51528..5ab7eaeca 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -221,8 +221,6 @@ namespace caret { bool isValid() const; - bool isAlternativeColoringValid(const int32_t identifier) const; - /** * @return Type of the vertices. */ @@ -307,20 +305,6 @@ namespace caret { protected: AString toStringPrivate(const bool includeAllDataFlag) const; - void setAlternativeFloatRGBAProtected(const int32_t identifier, - const std::vector& rgbaFloat); - - void setAlternativeUnsignedByteRGBAProtected(const int32_t identifier, - const std::vector& rgbaByte); - - const std::vector& getAlternativeFloatRGBAProtected(const int32_t identifier) const; - - const std::vector& getAlternativeUnsignedByteRGBAProtected(const int32_t identifier) const; - - bool isAlternativeFloatRGBAValidProtected(const int32_t identifier) const; - - bool isAlternativeUnsignedByteRGBAValidProtected(const int32_t identifier) const; - void setTextureImage(const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); @@ -357,10 +341,6 @@ namespace caret { std::vector m_unsignedByteRGBA; - std::map> m_alternativeFloatRGBA; - - std::map> m_alternativeUnsignedByteRGBA; - std::vector m_floatTextureSTR; std::vector m_textureImageBytesRGBA; diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index d759e4d69..7e76389d0 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -139,23 +139,6 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, rgba, rgba + 4); } -/** - * Set alternative RGBA coloring with float data. - * - * @param identifier - * Any integer value used to identify the alternative coloring. - * @param rgbaFloat - * The alternative coloring that must contain the correct number of - * RGBA components for the primitive's number of vertices. - */ -void -GraphicsPrimitiveV3fC4f::setAlternativeFloatRGBA(const int32_t identifier, - const std::vector& rgbaFloat) -{ - setAlternativeFloatRGBAProtected(identifier, - rgbaFloat); -} - /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.h b/src/Graphics/GraphicsPrimitiveV3fC4f.h index f5bd03fdf..0de2cc905 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.h +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.h @@ -52,9 +52,6 @@ namespace caret { const float y, const float rgba[4]); - void setAlternativeFloatRGBA(const int32_t identifier, - const std::vector& rgbaFloat); - virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 0558d59d3..649cfdfe2 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -119,23 +119,6 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, rgba, rgba + 4); } -/** - * Set alternative RGBA coloring with unsigned byte data. - * - * @param identifier - * Any integer value used to identify the alternative coloring. - * @param rgbaUnsignedByte - * The alternative coloring that must contain the correct number of - * RGBA components for the primitive's number of vertices. - */ -void -GraphicsPrimitiveV3fC4ub::setAlternativeUnsignedByteRGBA(const int32_t identifier, - const std::vector& rgbaUnsignedByte) -{ - setAlternativeUnsignedByteRGBAProtected(identifier, - rgbaUnsignedByte); -} - /** * Clone this primitive. */ diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.h b/src/Graphics/GraphicsPrimitiveV3fC4ub.h index b86e57b65..b17781e6d 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.h +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.h @@ -46,9 +46,6 @@ namespace caret { const float z, const uint8_t rgba[4]); - void setAlternativeUnsignedByteRGBA(const int32_t identifier, - const std::vector& rgbaUnsignedByte); - virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE -- GitLab From 4dc613ea8506a929a8d9a1ae9b98f6fbf525cea0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 7 Nov 2017 09:31:20 -0600 Subject: [PATCH 495/755] Renamed GraphicsPrimitive::PrimitiveType enumerated values to include "OPENGL" in their names so that additional "workbench" primitives may be added. --- src/Annotations/AnnotationImage.cxx | 2 +- src/Brain/BrainOpenGL.cxx | 7 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 4 +- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 16 ++-- src/Brain/BrainOpenGLFixedPipeline.cxx | 4 +- src/Charting/ChartTwoLineSeriesHistory.cxx | 2 +- src/Files/ChartableTwoFileHistogramChart.cxx | 6 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 2 +- src/Files/CiftiMappableDataFile.cxx | 2 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 20 ++--- src/Graphics/GraphicsOpenGLLineDrawing.cxx | 24 +++--- src/Graphics/GraphicsPrimitive.cxx | 80 +++++++++---------- src/Graphics/GraphicsPrimitive.h | 23 +++--- .../GraphicsPrimitiveSelectionHelper.cxx | 20 ++--- src/Graphics/GraphicsShape.cxx | 4 +- 15 files changed, 112 insertions(+), 104 deletions(-) diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index 11f967d75..4a907b855 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -231,7 +231,7 @@ AnnotationImage::getGraphicsPrimitive() const { if (m_graphicsPrimitive == NULL) { if ( ! m_imageBytesRGBA.empty()) { - GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::QUADS, + GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, &m_imageBytesRGBA[0], m_imageWidth, m_imageHeight); diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index b9bd7682e..00fc6ca14 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -1029,9 +1029,14 @@ BrainOpenGL::getOpenGLInformation() const AString smoothLineWidthGranularity = ("GL_SMOOTH_LINE_WIDTH_GRANULARITY value is " + AString::number(values[0])); + glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, values); + const AString smoothPointSizeRange = ("GL_SMOOTH_POINT_SIZE_RANGE value is " + + AString::fromNumbers(values, 2, ", ")); + lineInfo += ("\n" + aliasedLineWidthRange + "\n" + smoothLineWidthRange - + "\n" + smoothLineWidthGranularity); + + "\n" + smoothLineWidthGranularity + + "\n" + smoothPointSizeRange); } #endif // GL_VERSION_2_0 //#else // GL_VERSION_2_0 diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 96e99bd52..d3b1a0b4e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -291,7 +291,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c const bool drawCrossFlag = false; if (drawCrossFlag) { const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; - std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); crossShape->addVertex(drawingSpaceXYZ[0], @@ -2450,7 +2450,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi const bool drawCrossFlag = false; if (drawCrossFlag) { const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; - std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); crossShape->addVertex(annXYZ[0], annXYZ[1] - 10); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index eca93646a..e4e282fdc 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1404,7 +1404,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT for (auto rowIndex : selectedRowIndices) { // std::unique_ptr rowOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, // highlightRGBA)); // rowOutlineData4f->reserveForNumberOfVertices(4); @@ -1436,7 +1436,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT // BrainOpenGL::setLineWidth(highlightLineWidth); // //drawPrimitivePrivate(rowOutlineData4f.get()); - GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_LOOP); + GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); rowOutlineData->reserveForNumberOfVertices(4); rowOutlineData->addVertex(minX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, minY, highlightRGBA); @@ -1452,7 +1452,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT for (auto columnIndex : selectedColumnIndices) { // std::unique_ptr columnOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, +// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, // highlightRGBA)); // columnOutlineData4f->reserveForNumberOfVertices(4); @@ -1484,7 +1484,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT // BrainOpenGL::setLineWidth(highlightLineWidth); // //drawPrimitivePrivate(columnOutlineData4f.get()); - GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINE_LOOP); + GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); columnOutlineData->reserveForNumberOfVertices(4); columnOutlineData->addVertex(minX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, minY, highlightRGBA); @@ -1671,7 +1671,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons * and vertical lines are joined */ std::unique_ptr boxData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, m_fixedPipelineDrawing->m_foregroundColorFloat)); const float cornerOffset = halfGridLineWidth; boxData->reserveForNumberOfVertices(8); @@ -2468,7 +2468,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh const bool showTicksEnabledFlag = m_axis->isShowTickmarks(); std::unique_ptr ticksData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINES, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, foregroundFloatRGBA)); ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); @@ -2563,7 +2563,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh m_tabViewportWidth, m_tabViewportHeight, bottomLeft, bottomRight, topRight, topLeft); - std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, + std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, foregroundFloatRGBA)); boxPrimitive->reserveForNumberOfVertices(4); boxPrimitive->addVertex(bottomLeft); @@ -2610,7 +2610,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh // const float right = xyz[0] + halfWidth; // const float bottom = xyz[1] - halfHeight; // const float top = xyz[1] + halfHeight; -// std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::QUADS, +// std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, // foregroundFloatRGBA)); // boxPrimitive->addVertex(left, bottom, 0.0f); // boxPrimitive->addVertex(right, bottom, 0.0f); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c18b035a1..a676984fa 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2639,11 +2639,11 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) std::unique_ptr pointsPrimitive; if (drawSphericalPoints || drawSquarePoints) { - pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POINTS)); + pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); } std::unique_ptr linesPrimitive; if (drawLines) { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::LINE_STRIP)); + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP)); } const bool featureClippingFlag = isFeatureClippingEnabled(); diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index 6ee3bb019..c7021b528 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -589,7 +589,7 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, CaretUnitsTypeEnum::NONE, CaretUnitsTypeEnum::NONE, - GraphicsPrimitive::PrimitiveType::LINES); + GraphicsPrimitive::PrimitiveType::OPENGL_LINES); historyItem->restoreFromScene(sceneAttributes, historyClass); diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index df22b05bb..3e216ff05 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -421,9 +421,9 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m * Use Lines when drawing envelope (two vertices per line) * Using quads and lines simplifies identification of individual bars in the histogram */ - GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); - GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::LINES); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES); envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; @@ -465,7 +465,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); - thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); switch (paletteColorMapping->getThresholdTest()) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 2ad846f75..3f03dc25d 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -266,7 +266,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, xUnits, CaretUnitsTypeEnum::NONE, - GraphicsPrimitive::PrimitiveType::LINES); + GraphicsPrimitive::PrimitiveType::OPENGL_LINES); cartesianData->setMapFileDataSelector(mapFileDataSelector); float x = 0.0f; diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 95f72e39e..bf3f6fbd3 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1526,7 +1526,7 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr if (getMatrixForChartingRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { const int32_t numberOfCells = numberOfRows * numberOfColumns; if (numberOfCells > 0) { - matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS); + matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS matrixPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 967858862..ccc5059c2 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -764,38 +764,38 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, */ GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; - case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; - case GraphicsPrimitive::PrimitiveType::LINES: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: openGLPrimitiveType = GL_LINES; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; - case GraphicsPrimitive::PrimitiveType::POINTS: + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: openGLPrimitiveType = GL_POINTS; glPointSize(getPointDiameterForDrawingInPixels(primitive)); break; - case GraphicsPrimitive::PrimitiveType::POLYGON: + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: openGLPrimitiveType = GL_POLYGON; break; - case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: openGLPrimitiveType = GL_QUAD_STRIP; break; - case GraphicsPrimitive::PrimitiveType::QUADS: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: openGLPrimitiveType = GL_QUADS; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: openGLPrimitiveType = GL_TRIANGLE_FAN; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: openGLPrimitiveType = GL_TRIANGLE_STRIP; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLES: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: openGLPrimitiveType = GL_TRIANGLES; break; } diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index 4292cfdc8..0d4274cbd 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -102,40 +102,40 @@ GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, LineType lineType = LineType::LINES; switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: lineType = LineType::LINE_LOOP; break; - case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: lineType = LineType::LINE_STRIP; break; - case GraphicsPrimitive::PrimitiveType::LINES: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: lineType = LineType::LINES; break; - case GraphicsPrimitive::PrimitiveType::POINTS: + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: CaretLogSevere("POINTS is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::POLYGON: + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: CaretLogSevere("POLYGON is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::QUADS: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: CaretLogSevere("QUADS is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLES: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: CaretLogSevere("TRIANGLES is not a valid line drawing type"); return false; break; @@ -1286,13 +1286,13 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: case ColorType::BYTE_RGBA_SOLID: - m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::QUADS)); + m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); m_primitive = m_primitiveByteColor.get(); break; case ColorType::FLOAT_RGBA_PER_VERTEX: case ColorType::FLOAT_RGBA_SOLID: - m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::QUADS)); + m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); m_primitive = m_primitiveFloatColor.get(); break; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 9a18351f3..1cdf1255b 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -275,17 +275,17 @@ GraphicsPrimitive::isValid() const } switch (m_primitiveType) { - case PrimitiveType::LINE_LOOP: + case PrimitiveType::OPENGL_LINE_LOOP: if (numXYZ < 3) { CaretLogWarning("Line loop must have at least 3 vertices."); } break; - case PrimitiveType::LINE_STRIP: + case PrimitiveType::OPENGL_LINE_STRIP: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } break; - case PrimitiveType::LINES: + case PrimitiveType::OPENGL_LINES: if (numXYZ < 2) { CaretLogWarning("Lines must have at least 2 vertices."); } @@ -296,14 +296,14 @@ GraphicsPrimitive::isValid() const } } break; - case PrimitiveType::POINTS: + case PrimitiveType::OPENGL_POINTS: break; - case PrimitiveType::POLYGON: + case PrimitiveType::OPENGL_POLYGON: if (numXYZ < 3) { CaretLogWarning("Polygon must have at least 3 vertices."); } break; - case PrimitiveType::QUAD_STRIP: + case PrimitiveType::OPENGL_QUAD_STRIP: if (numXYZ < 4) { CaretLogWarning("Quad strip must have at least 4 vertices."); } @@ -314,7 +314,7 @@ GraphicsPrimitive::isValid() const } } break; - case PrimitiveType::QUADS: + case PrimitiveType::OPENGL_QUADS: if (numXYZ < 4) { CaretLogWarning("Quads must have at least 4 vertices."); } @@ -325,17 +325,17 @@ GraphicsPrimitive::isValid() const } } break; - case PrimitiveType::TRIANGLE_FAN: + case PrimitiveType::OPENGL_TRIANGLE_FAN: if (numXYZ < 3) { CaretLogWarning("Triangle fan must have at least 3 vertices."); } break; - case PrimitiveType::TRIANGLE_STRIP: + case PrimitiveType::OPENGL_TRIANGLE_STRIP: if (numXYZ < 3) { CaretLogWarning("Triangle strip must have at least 3 vertices."); } break; - case PrimitiveType::TRIANGLES: + case PrimitiveType::OPENGL_TRIANGLES: if (numXYZ < 3) { CaretLogWarning("Triangles must have at least 3 vertices."); } @@ -383,34 +383,34 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const AString s; switch (m_primitiveType) { - case PrimitiveType::LINE_LOOP: + case PrimitiveType::OPENGL_LINE_LOOP: s = "Line Loop"; break; - case PrimitiveType::LINE_STRIP: + case PrimitiveType::OPENGL_LINE_STRIP: s = "Line Strip"; break; - case PrimitiveType::LINES: + case PrimitiveType::OPENGL_LINES: s = "Lines"; break; - case PrimitiveType::POINTS: + case PrimitiveType::OPENGL_POINTS: s = "Points"; break; - case PrimitiveType::POLYGON: + case PrimitiveType::OPENGL_POLYGON: s = "Polygon"; break; - case PrimitiveType::QUAD_STRIP: + case PrimitiveType::OPENGL_QUAD_STRIP: s = "Quad Strip"; break; - case PrimitiveType::QUADS: + case PrimitiveType::OPENGL_QUADS: s = "Quads"; break; - case PrimitiveType::TRIANGLE_FAN: + case PrimitiveType::OPENGL_TRIANGLE_FAN: s = "Triangle Fan"; break; - case PrimitiveType::TRIANGLE_STRIP: + case PrimitiveType::OPENGL_TRIANGLE_STRIP: s = "Triangle Strip"; break; - case PrimitiveType::TRIANGLES: + case PrimitiveType::OPENGL_TRIANGLES: s = "Triangles"; break; } @@ -553,29 +553,29 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const bool addPointSizeFlag = false; switch (m_primitiveType) { - case PrimitiveType::LINE_LOOP: + case PrimitiveType::OPENGL_LINE_LOOP: addLineWidthFlag = true; break; - case PrimitiveType::LINE_STRIP: + case PrimitiveType::OPENGL_LINE_STRIP: addLineWidthFlag = true; break; - case PrimitiveType::LINES: + case PrimitiveType::OPENGL_LINES: addLineWidthFlag = true; break; - case PrimitiveType::POINTS: + case PrimitiveType::OPENGL_POINTS: addPointSizeFlag = true; break; - case PrimitiveType::POLYGON: + case PrimitiveType::OPENGL_POLYGON: break; - case PrimitiveType::QUAD_STRIP: + case PrimitiveType::OPENGL_QUAD_STRIP: break; - case PrimitiveType::QUADS: + case PrimitiveType::OPENGL_QUADS: break; - case PrimitiveType::TRIANGLE_FAN: + case PrimitiveType::OPENGL_TRIANGLE_FAN: break; - case PrimitiveType::TRIANGLE_STRIP: + case PrimitiveType::OPENGL_TRIANGLE_STRIP: break; - case PrimitiveType::TRIANGLES: + case PrimitiveType::OPENGL_TRIANGLES: break; } @@ -868,31 +868,31 @@ GraphicsPrimitive::addPrimitiveRestart() bool supportedFlag = false; switch (m_primitiveType) { - case PrimitiveType::LINE_LOOP: + case PrimitiveType::OPENGL_LINE_LOOP: supportedFlag = true; break; - case PrimitiveType::LINE_STRIP: + case PrimitiveType::OPENGL_LINE_STRIP: supportedFlag = true; break; - case PrimitiveType::LINES: + case PrimitiveType::OPENGL_LINES: notApplicableFlag = true; break; - case PrimitiveType::POINTS: + case PrimitiveType::OPENGL_POINTS: notApplicableFlag = true; break; - case PrimitiveType::POLYGON: + case PrimitiveType::OPENGL_POLYGON: notApplicableFlag = true; break; - case PrimitiveType::QUAD_STRIP: + case PrimitiveType::OPENGL_QUAD_STRIP: break; - case PrimitiveType::QUADS: + case PrimitiveType::OPENGL_QUADS: notApplicableFlag = true; break; - case PrimitiveType::TRIANGLE_FAN: + case PrimitiveType::OPENGL_TRIANGLE_FAN: break; - case PrimitiveType::TRIANGLE_STRIP: + case PrimitiveType::OPENGL_TRIANGLE_STRIP: break; - case PrimitiveType::TRIANGLES: + case PrimitiveType::OPENGL_TRIANGLES: notApplicableFlag = true; break; } diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 5ab7eaeca..f6b4f1196 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -90,27 +90,30 @@ namespace caret { /** * Draws a connected group of line segments from the first vertex to the last. * Vertices n and n+1 define line n. n-1 lines are drawn. + * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ - LINE_LOOP, + OPENGL_LINE_LOOP, /** * Treats each pair of vertices as an independent line segment. * Vertices 2n-1 and 2n define line n. n/2 lines are drawn. + * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ - LINE_STRIP, + OPENGL_LINE_STRIP, /** * Draws a connected group of line segments from the first vertex to the last, then back * to the first. Vertices n and n+1 define line n. The last line, however, is defined by * vertices n and 1. n lines are drawn. + * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ - LINES, + OPENGL_LINES, /** * Treats each vertex as a single point. Vertex n defines point n. n points are drawn. */ - POINTS, + OPENGL_POINTS, /** * Draws a single, convex polygon. Vertices 1 through n define this polygon. */ - POLYGON, + OPENGL_POLYGON, /** * Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair * of vertices presented after the first pair. Vertices 2n-1, 2n, 2n+2, and 2n+1 define @@ -118,30 +121,30 @@ namespace caret { * are used to construct a quadrilateral from strip data is different from that used with * independent data. */ - QUAD_STRIP, + OPENGL_QUAD_STRIP, /** * Treats each group of four vertices as an independent quadrilateral. * Vertices 4n-3, 4n-2, 4n-3, and 4n define quadrilateral n. n/4 quadrilaterals are drawn. */ - QUADS, + OPENGL_QUADS, /** * Draws a connected group of triangles. One triangle is defined for each vertex * presented after the first two vertices. Vertices 1, n+1, and n+2 define triangle n. n-2 * triangles are drawn. */ - TRIANGLE_FAN, + OPENGL_TRIANGLE_FAN, /** * Draws a connected group of triangles. One triangle is defined for each vertex * presented after the first two vertices. For odd n, vertices n, n+1, and n+2 define * triangle n. For even n, vertices n+1, n, and n+2 define triangle n. n-2 triangles are * drawn. */ - TRIANGLE_STRIP, + OPENGL_TRIANGLE_STRIP, /** * Treats each triplet of vertices as an independent triangle. Vertices 3n-2, 3n-1, and * 3n define triangle n. n/3 triangles are drawn. */ - TRIANGLES + OPENGL_TRIANGLES }; /** diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index 5dd2ca201..efce0b28a 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -72,34 +72,34 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() m_numberOfVerticesPerPrimitive = 0; switch (m_parentGraphicsPrimitive->getPrimitiveType()) { - case GraphicsPrimitive::PrimitiveType::LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; - case GraphicsPrimitive::PrimitiveType::LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; - case GraphicsPrimitive::PrimitiveType::LINES: + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: m_numberOfVerticesPerPrimitive = 2; break; - case GraphicsPrimitive::PrimitiveType::POINTS: + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: m_numberOfVerticesPerPrimitive = 1; break; - case GraphicsPrimitive::PrimitiveType::POLYGON: + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: m_numberOfVerticesPerPrimitive = numberOfVertices; break; - case GraphicsPrimitive::PrimitiveType::QUAD_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: CaretAssertMessage(0, "Not yet implemented"); break; - case GraphicsPrimitive::PrimitiveType::QUADS: + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: m_numberOfVerticesPerPrimitive = 4; break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: CaretAssertMessage(0, "Not yet implemented"); break; - case GraphicsPrimitive::PrimitiveType::TRIANGLE_STRIP: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: CaretAssertMessage(0, "Not yet implemented"); break; - case GraphicsPrimitive::PrimitiveType::TRIANGLES: + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: m_numberOfVerticesPerPrimitive = 3; break; } diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 285c4f415..332a9797b 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -80,7 +80,7 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); for (int32_t i = 0; i < numVertices; i++) { @@ -117,7 +117,7 @@ GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::TRIANGLE_FAN, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, rgba)); const float center[3] = { 0.0f, 0.0f, 0.0f }; primitive->addVertex(center); -- GitLab From ea13d54dd56a72efdfdfb7b903fc01ee61ff9c9a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 8 Nov 2017 09:13:39 -0600 Subject: [PATCH 496/755] Continuing new line drawing: Updated annotation drawing for lines, box, oval. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 289 ++++++----- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 7 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 454 +----------------- src/Brain/BrainOpenGLFixedPipeline.h | 11 - src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 141 ++---- src/Graphics/GraphicsEngineDataOpenGL.cxx | 202 +++++++- src/Graphics/GraphicsEngineDataOpenGL.h | 12 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 237 +++++++++ src/Graphics/GraphicsOpenGLLineDrawing.h | 6 + src/Graphics/GraphicsPrimitive.cxx | 25 +- src/Graphics/GraphicsPrimitive.h | 14 +- .../GraphicsPrimitiveSelectionHelper.cxx | 3 + src/Graphics/GraphicsShape.cxx | 168 ++++++- src/Graphics/GraphicsShape.h | 30 ++ 14 files changed, 876 insertions(+), 723 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index d3b1a0b4e..c4d56eb1d 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -49,12 +49,10 @@ #include "CaretAssert.h" #include "CaretColorEnum.h" #include "CaretLogger.h" -#include "DeveloperFlagsEnum.h" #include "DisplayPropertiesAnnotation.h" #include "EventBrowserTabGet.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" -#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fT3f.h" @@ -1205,7 +1203,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil if (box->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(box); } - const float outlineWidth = getLineWidthFromPercentageHeight(box->getLineWidthPercentage()); const bool depthTestFlag = isDrawnWithDepthTesting(box); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); @@ -1218,9 +1215,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil std::vector dummyNormals; - float backgroundRGBA[4]; + uint8_t backgroundRGBA[4]; box->getBackgroundColorRGBA(backgroundRGBA); - float foregroundRGBA[4]; + uint8_t foregroundRGBA[4]; box->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0); @@ -1240,30 +1237,26 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * since it is opaque and prevents "behind" annotations * from being selected */ - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - selectionColorRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ - const float slightlyThicker = 2.0; - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - float widthPixels = (box->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - coords, selectionColorRGBA, widthPixels); - } - else { - BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - selectionColorRGBA, - outlineWidth + slightlyThicker); - } + GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + box->getLineWidthPercentage()); } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -1273,36 +1266,24 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil } else { if (drawBackgroundFlag) { - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - backgroundRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { - const bool drawOutlineWithPolygonsFlag = true; - if (drawOutlineWithPolygonsFlag) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - float widthPixels = (box->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLineLoopSolidFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - coords, foregroundRGBA, widthPixels); - } - else { - BrainOpenGLPrimitiveDrawing::drawRectangleOutline(bottomLeft, bottomRight, topRight, topLeft, - outlineWidth, - foregroundRGBA); - } - } - else { - const float tempRGBA[4] = { 1.0, 1.0, 0.0, 1.0 }; - BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - tempRGBA, - outlineWidth); - } + GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + box->getLineWidthPercentage()); drawnFlag = true; } } @@ -1941,7 +1922,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi if (oval->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(oval); } - const float outlineWidth = getLineWidthFromPercentageHeight(oval->getLineWidthPercentage()); const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, @@ -1980,38 +1960,22 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * since it is opaque and prevents "behind" annotations * from being selected */ - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, - minorAxis * 2.0f, - selectionColorRGBA); - } - else { - m_brainOpenGLFixedPipeline->drawEllipseFilled(selectionColorRGBA, - majorAxis, - minorAxis); - } + GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ - const float slightlyThicker = 2.0; - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - float widthPixels = (oval->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, - minorAxis * 2.0f, - selectionColorRGBA, - widthPixels + slightlyThicker); - } - else { - m_brainOpenGLFixedPipeline->drawEllipseOutline(selectionColorRGBA, - majorAxis, - minorAxis, - outlineWidth + slightlyThicker); - } + GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + selectionColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + oval->getLineWidthPercentage()); } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -2021,35 +1985,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi } else { if (drawBackgroundFlag) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, - minorAxis * 2.0f, - backgroundRGBA); - } - else { - m_brainOpenGLFixedPipeline->drawEllipseFilled(backgroundRGBA, - majorAxis, - minorAxis); - } + GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - float widthPixels = (oval->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, - minorAxis * 2.0f, - foregroundRGBA, - widthPixels); - } - else { - m_brainOpenGLFixedPipeline->drawEllipseOutline(foregroundRGBA, - majorAxis, - minorAxis, - outlineWidth); - } + GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + majorAxis * 2.0f, + minorAxis * 2.0f, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + oval->getLineWidthPercentage()); drawnFlag = true; } } @@ -2089,9 +2038,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin const float bottomRight[3], const float topRight[3], const float topLeft[3], - std::vector& lineCoordinatesOut) const + std::vector& lineCoordinatesOut, + std::vector& arrowCoordinatesOut) const { lineCoordinatesOut.clear(); + arrowCoordinatesOut.clear(); if (text->isConnectToBrainordinateValid()) { bool showLineFlag = false; @@ -2159,12 +2110,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordin convertObsoleteLineWidthPixelsToPercentageWidth(text); } const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); + std::vector unusedArrowCoordinates; createLineCoordinates(annXYZ, brainordinateXYZ, lineWidth, false, showArrowFlag, - lineCoordinatesOut); + lineCoordinatesOut, + unusedArrowCoordinates, + arrowCoordinatesOut); + } } } @@ -2357,6 +2312,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi } else { std::vector connectLineCoordinates; + std::vector arrowCoordinates; getTextLineToBrainordinateLineCoordinates(text, surfaceDisplayed, @@ -2364,16 +2320,30 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi bottomRight, topRight, topLeft, - connectLineCoordinates); + connectLineCoordinates, + arrowCoordinates); if ( ! connectLineCoordinates.empty()) { if (text->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(text); } - const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); - BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, - textColorRGBA, - lineWidth); + + GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + connectLineCoordinates, + textColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + text->getLineWidthPercentage()); + if ( ! arrowCoordinates.empty()) { + GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + arrowCoordinates, + textColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + text->getLineWidthPercentage()); + } +// const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); +// BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, +// textColorRGBA, +// lineWidth); } if (drawTextFlag) { @@ -2646,18 +2616,22 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF void BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lineHeadXYZ[3], const float lineTailXYZ[3], - const float lineThickness, + const float lineThicknessPixels, const bool validStartArrow, const bool validEndArrow, - std::vector& coordinatesOut) const + std::vector& lineCoordinatesOut, + std::vector& startArrowCoordinatesOut, + std::vector& endArrowCoordinatesOut) const { - coordinatesOut.clear(); + lineCoordinatesOut.clear(); + startArrowCoordinatesOut.clear(); + endArrowCoordinatesOut.clear(); /* * Length of arrow's tips is function of line thickness */ const float tipScale = 3.0; - const float tipLength = lineThickness * tipScale; + const float tipLength = lineThicknessPixels * tipScale; /* * Point on arrow's line that is between the arrow's left and right arrow tips @@ -2730,19 +2704,19 @@ BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lin tailArrowTipsOnLine[2] - headLeftRightTipOffset[2] }; - coordinatesOut.insert(coordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); - coordinatesOut.insert(coordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); + lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); + lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); if (validStartArrow) { - coordinatesOut.insert(coordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); - coordinatesOut.insert(coordinatesOut.end(), headRightTipEnd, headRightTipEnd + 3); - coordinatesOut.insert(coordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); - coordinatesOut.insert(coordinatesOut.end(), headLeftTipEnd, headLeftTipEnd + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headRightTipEnd, headRightTipEnd + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headLeftTipEnd, headLeftTipEnd + 3); } if (validEndArrow) { - coordinatesOut.insert(coordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); - coordinatesOut.insert(coordinatesOut.end(), tailRightTipEnd, tailRightTipEnd + 3); - coordinatesOut.insert(coordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); - coordinatesOut.insert(coordinatesOut.end(), tailLeftTipEnd, tailLeftTipEnd + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailRightTipEnd, tailRightTipEnd + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailLeftTipEnd, tailLeftTipEnd + 3); } } @@ -2786,7 +2760,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi convertObsoleteLineWidthPixelsToPercentageWidth(line); } const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPercentage()); - const float backgroundLineWidth = lineWidth + 4; const float selectionCenterXYZ[3] = { (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0, @@ -2797,18 +2770,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi const bool depthTestFlag = isDrawnWithDepthTesting(line); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); - std::vector coords; + std::vector lineCoordinates; + std::vector startArrowCoordinates; + std::vector endArrowCoordinates; createLineCoordinates(lineHeadXYZ, lineTailXYZ, lineWidth, line->isDisplayStartArrow(), line->isDisplayEndArrow(), - coords); + lineCoordinates, + startArrowCoordinates, + endArrowCoordinates); uint8_t foregroundRGBA[4]; line->getLineColorRGBA(foregroundRGBA); - float floatForegroundRGBA[4]; - line->getLineColorRGBA(floatForegroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); @@ -2818,19 +2793,25 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLinesSolidByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - coords, selectionColorRGBA, widthPixels); + + GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + lineCoordinates, + selectionColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); + if ( ! startArrowCoordinates.empty()) { + GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + startArrowCoordinates, + selectionColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); } - else { - BrainOpenGLPrimitiveDrawing::drawLines(coords, - selectionColorRGBA, - backgroundLineWidth); + if ( ! endArrowCoordinates.empty()) { + GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + endArrowCoordinates, + selectionColorRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); } m_selectionInfo.push_back(SelectionInfo(annotationFile, line, @@ -2839,21 +2820,25 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi } else { if (drawForegroundFlag) { - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - /* - * For testing new line drawing - * Width not limited to OpenGL min/max - */ - float widthPixels = (line->getLineWidthPercentage() / 100.0f) * m_modelSpaceViewport[3]; - GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - coords, floatForegroundRGBA, widthPixels); + GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + lineCoordinates, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); + if ( ! startArrowCoordinates.empty()) { + GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + startArrowCoordinates, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); } - else { - BrainOpenGLPrimitiveDrawing::drawLines(coords, - foregroundRGBA, - lineWidth); + if ( ! endArrowCoordinates.empty()) { + GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + endArrowCoordinates, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + line->getLineWidthPercentage()); } - drawnFlag = true; } } diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index d57ab76d9..7d9fab65e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -270,7 +270,9 @@ namespace caret { const float lineThickness, const bool validStartArrow, const bool validEndArrow, - std::vector& coordinatesOut) const; + std::vector& lineCoordinatesOut, + std::vector& startArrowCoordinatesOut, + std::vector& endArrowCoordinatesOut) const; void getTextLineToBrainordinateLineCoordinates(const AnnotationText* text, const Surface* surfaceDisplayed, @@ -278,7 +280,8 @@ namespace caret { const float bottomRight[3], const float topRight[3], const float topLeft[3], - std::vector& lineCoordinatesOut) const; + std::vector& lineCoordinatesOut, + std::vector& arrowCoordinatesOut) const; static void expandBox(float bottomLeft[3], float bottomRight[3], diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index a676984fa..4a813af44 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -102,7 +102,6 @@ #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" -#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" @@ -2572,11 +2571,6 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) void BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) { - if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - drawBorderOld(borderDrawInfo); - return; - } - CaretAssert(borderDrawInfo.surface); CaretAssert(borderDrawInfo.border); @@ -2643,7 +2637,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } std::unique_ptr linesPrimitive; if (drawLines) { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP)); + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP)); } const bool featureClippingFlag = isFeatureClippingEnabled(); @@ -2840,391 +2834,13 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) if (linesPrimitive) { linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineWidth); - GraphicsOpenGLLineDrawing::draw(getContextSharingGroupPointer(), - linesPrimitive.get()); + GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), + linesPrimitive.get()); } glPopAttrib(); } -/** - * Draw a border on a surface. The color must be set prior - * to calling this method. - * - * @param borderDrawInfo - * Info about border being drawn. - * @param border - * Border that is drawn on the surface. - * @param borderFileIndex - * Index of border file. - * @param borderIndex - * Index of border. - * @param isSelect - * Selection mode is active. - */ -void -BrainOpenGLFixedPipeline::drawBorderOld(const BorderDrawInfo& borderDrawInfo) -{ - CaretAssert(borderDrawInfo.surface); - CaretAssert(borderDrawInfo.border); - - const StructureEnum::Enum surfaceStructure = borderDrawInfo.surface->getStructure(); - const StructureEnum::Enum contralateralSurfaceStructure = StructureEnum::getContralateralStructure(surfaceStructure); - const int32_t numBorderPoints = borderDrawInfo.border->getNumberOfPoints(); - const bool isHighlightEndPoints = borderDrawInfo.isHighlightEndPoints; - - float pointDiameter = 2.0; - float lineWidth = 2.0; - BorderDrawingTypeEnum::Enum drawType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; - if (borderDrawInfo.borderFileIndex >= 0) { - const BrainStructure* bs = borderDrawInfo.surface->getBrainStructure(); - const Brain* brain = bs->getBrain(); - const DisplayPropertiesBorders* dpb = brain->getDisplayPropertiesBorders(); - const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(this->windowTabIndex); - pointDiameter = dpb->getPointSize(displayGroup, - this->windowTabIndex); - lineWidth = dpb->getLineWidth(displayGroup, - this->windowTabIndex); - drawType = dpb->getDrawingType(displayGroup, - this->windowTabIndex); - } - - bool drawSphericalPoints = false; - bool drawSquarePoints = false; - bool drawLines = false; - switch (drawType) { - case BorderDrawingTypeEnum::DRAW_AS_LINES: - drawLines = true; - break; - case BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES: - drawSphericalPoints = true; - break; - case BorderDrawingTypeEnum::DRAW_AS_POINTS_SQUARES: - drawSquarePoints = true; - break; - case BorderDrawingTypeEnum::DRAW_AS_POINTS_AND_LINES: - drawLines = true; - drawSphericalPoints = true; - break; - } - - const bool flatSurfaceFlag = (borderDrawInfo.surface->getSurfaceType() == SurfaceTypeEnum::FLAT); - bool flatSurfaceDrawUnstretchedLinesFlag = false; - float unstretchedLinesLength = -1.0; - if (flatSurfaceFlag) { - if ((borderDrawInfo.anatomicalSurface != NULL) - && (borderDrawInfo.unstretchedLinesLength > 0.0)) { - flatSurfaceDrawUnstretchedLinesFlag = true; - unstretchedLinesLength = borderDrawInfo.unstretchedLinesLength; - } - } - - const float drawAtDistanceAboveSurface = 0.0; - - std::vector pointXYZ; - std::vector pointAnatomicalXYZ; - std::vector pointIndex; - - const CaretPointer th = borderDrawInfo.surface->getTopologyHelper(); - const std::vector& nodesBoundaryEdgeCount = th->getNumberOfBoundaryEdgesForAllNodes(); - CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); - - /* - * Find points valid for this surface - */ - for (int32_t i = 0; i < numBorderPoints; i++) { - const SurfaceProjectedItem* p = borderDrawInfo.border->getPoint(i); - - /* - * If surface structure does not match the point's structure, - * check to see if contralateral display is enabled and - * compare contralateral surface structure to point's structure. - */ - const StructureEnum::Enum pointStructure = p->getStructure(); - bool structureMatches = true; - if (surfaceStructure != pointStructure) { - structureMatches = false; - if (borderDrawInfo.isContralateralEnabled) { - if (contralateralSurfaceStructure == pointStructure) { - structureMatches = true; - } - } - } - if (structureMatches == false) { - continue; - } - - float xyz[3]; - bool isXyzValid = p->getProjectedPositionAboveSurface(*borderDrawInfo.surface, - xyz, - drawAtDistanceAboveSurface); - - if (isXyzValid) { - /* - * On a flat surface, do not draw border points that are attached to all edge nodes - * as they will likely result in points outside of the flat surface - * (near cuts and medial wall) - */ - if (flatSurfaceDrawUnstretchedLinesFlag){ - if (p->getBarycentricProjection()->isValid()) { - const int32_t* baryNodes = p->getBarycentricProjection()->getTriangleNodes(); - if (baryNodes != NULL) { - int32_t edgeNodeCount = 0; - if (nodesBoundaryEdgeCount[baryNodes[0]] > 0) edgeNodeCount++; - if (nodesBoundaryEdgeCount[baryNodes[1]] > 0) edgeNodeCount++; - if (nodesBoundaryEdgeCount[baryNodes[2]] > 0) edgeNodeCount++; - if (edgeNodeCount >= 3) { - isXyzValid = false; - } - } - } - } - } - - if (isXyzValid) { - if (flatSurfaceDrawUnstretchedLinesFlag) { - float anatXYZ[3]; - const bool isAnatXyzValid = p->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, - anatXYZ, - drawAtDistanceAboveSurface); - if (isAnatXyzValid) { - pointXYZ.push_back(xyz[0]); - pointXYZ.push_back(xyz[1]); - pointXYZ.push_back(xyz[2]); - pointAnatomicalXYZ.push_back(anatXYZ[0]); - pointAnatomicalXYZ.push_back(anatXYZ[1]); - pointAnatomicalXYZ.push_back(anatXYZ[2]); - pointIndex.push_back(i); - - } - } - else { - pointXYZ.push_back(xyz[0]); - pointXYZ.push_back(xyz[1]); - pointXYZ.push_back(xyz[2]); - pointIndex.push_back(i); - } - } - } - - const bool doClipping = isFeatureClippingEnabled(); - - const int32_t numPointsToDraw = static_cast(pointXYZ.size() / 3); - if (flatSurfaceDrawUnstretchedLinesFlag) { - CaretAssert(pointXYZ.size() == pointAnatomicalXYZ.size()); - } - - /* - * Draw points - */ - if (drawSphericalPoints - || drawSquarePoints) { - for (int32_t i = 0; i < numPointsToDraw; i++) { - const int32_t i3 = i * 3; - - const float* xyz = &pointXYZ[i3]; - - if (doClipping) { - if ( ! isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz)) { - continue; - } - } - - glPushMatrix(); - glTranslatef(xyz[0], xyz[1], xyz[2]); - - if (borderDrawInfo.isSelect) { - uint8_t idRGBA[4]; - this->colorIdentification->addItem(idRGBA, - SelectionItemDataTypeEnum::BORDER_SURFACE, - borderDrawInfo.borderFileIndex, - borderDrawInfo.borderIndex, - pointIndex[i]); - idRGBA[3] = 255; - if (drawSphericalPoints) { - this->drawSphereWithDiameter(idRGBA, - pointDiameter); - } - else { - this->drawSquare(idRGBA, - pointDiameter); - } - } - else { - float rgba[4] = { - borderDrawInfo.rgba[0], - borderDrawInfo.rgba[1], - borderDrawInfo.rgba[2], - borderDrawInfo.rgba[3], - }; - if (isHighlightEndPoints) { - if (i == 0) { - rgba[0] = 0.0; - rgba[1] = 1.0; - rgba[2] = 0.0; - rgba[3] = 1.0; - } - else if (i == (numPointsToDraw - 1)) { - rgba[0] = 0.0; - rgba[1] = 0.75; - rgba[2] = 0.0; - rgba[3] = 1.0; - } - } - if (drawSphericalPoints) { - this->drawSphereWithDiameter(rgba, - pointDiameter); - } - else { - this->drawSquare(rgba, - pointDiameter); - } - } - - glPopMatrix(); - } - } - - /* - * Draw lines - */ - if (drawLines - && (numPointsToDraw > 1)) { - this->setLineWidth(lineWidth); - - this->disableLighting(); - - if (borderDrawInfo.isSelect) { - /* - * Start at one, since need two points for each line - */ - for (int32_t i = 1; i < numPointsToDraw; i++) { - /* - * On a flat surface, do not draw a line segment if it is - * from non-consecutive border points. This occurs when - * a border point does not project to the flat surface - * due to a cut or removal of the medial wall. If helps - * prevent long border lines stretching from one edge of the - * surface to a far away edge. - */ - if (flatSurfaceDrawUnstretchedLinesFlag) { - if (pointIndex[i] != (pointIndex[i-1] + 1)) { - continue; - } - } - - const int32_t i3 = i * 3; - uint8_t idRGBA[4]; - this->colorIdentification->addItem(idRGBA, - SelectionItemDataTypeEnum::BORDER_SURFACE, - borderDrawInfo.borderFileIndex, - borderDrawInfo.borderIndex, - pointIndex[i]); - glColor3ubv(idRGBA); - - CaretAssertVectorIndex(pointXYZ, i3 + 2); - const float* xyz1 = &pointXYZ[i3 - 3]; - const float* xyz2 = &pointXYZ[i3]; - - bool drawIt = true; - if (doClipping) { - if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz1) - && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz2)) ) { - /* nothing */ - } - else { - drawIt = false; - } - } - - if (drawIt) { - if (flatSurfaceDrawUnstretchedLinesFlag) { - CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); - if (unstretchedBorderLineTest(xyz1, - xyz2, - &pointAnatomicalXYZ[i3], - &pointAnatomicalXYZ[i3-3], - unstretchedLinesLength)) { - drawIt = false; - } - } - } - if (drawIt) { - glBegin(GL_LINES); - glVertex3fv(xyz1); - glVertex3fv(xyz2); - glEnd(); - } - } - } - else { - glColor3fv(borderDrawInfo.rgba); - - /* - * Start at one, since need two points for each line - */ - glBegin(GL_LINES); - for (int32_t i = 1; i < numPointsToDraw; i++) { - /* - * On a flat surface, do not draw a line segment if it is - * from non-consecutive border points. This occurs when - * a border point does not project to the flat surface - * due to a cut or removal of the medial wall. If helps - * prevent long border lines stretching from one edge of the - * surface to a far away edge. - */ - if (flatSurfaceDrawUnstretchedLinesFlag) { - if (pointIndex[i] != (pointIndex[i-1] + 1)) { - continue; - } - } - - const int32_t i3 = i * 3; - CaretAssertVectorIndex(pointXYZ, i3 + 2); - const float* xyz1 = &pointXYZ[i3 - 3]; - const float* xyz2 = &pointXYZ[i3]; - - bool drawIt = true; - if (doClipping) { - if (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz1) - && (isCoordinateInsideClippingPlanesForStructure(surfaceStructure, - xyz2)) ) { - /* nothing */ - } - else { - drawIt = false; - } - } - - - if (drawIt) { - if (flatSurfaceDrawUnstretchedLinesFlag) { - CaretAssertVectorIndex(pointAnatomicalXYZ, i3 + 2); - if (unstretchedBorderLineTest(xyz1, - xyz2, - &pointAnatomicalXYZ[i3], - &pointAnatomicalXYZ[i3-3], - unstretchedLinesLength)) { - drawIt = false; - } - } - } - - if (drawIt) { - glVertex3fv(xyz1); - glVertex3fv(xyz2); - } - } - glEnd(); - } - - this->enableLighting(); - } -} /** * Determine if the ratio if border length over anatomical border length @@ -6351,70 +5967,6 @@ BrainOpenGLFixedPipeline::drawCircleFilled(const uint8_t rgba[4], glPopMatrix(); } -/** - * Draw an outline ellipse. - * - * @param rgba - * Color for drawing. - * @param majorAxis - * Diameter of the major axis. - * @param minorAxis - * Diameter of the minor axis. - * @param lineThickness - * Thickness of the line. - */ -void -BrainOpenGLFixedPipeline::drawEllipseOutline(const uint8_t rgba[4], - const double majorAxis, - const double minorAxis, - const double lineThickness) -{ - glPushMatrix(); - glScaled(majorAxis, minorAxis, 1.0); - - BrainOpenGLShapeRingOutline* ringOutline = NULL; - - std::map::iterator iter = m_shapeEllipseOutlines.find(lineThickness); - if (iter != m_shapeEllipseOutlines.end()) { - ringOutline = iter->second; - } - else { - ringOutline = new BrainOpenGLShapeRingOutline(20, - 1.0, - lineThickness); - m_shapeEllipseOutlines.insert(std::make_pair(lineThickness, - ringOutline)); - } - - CaretAssert(ringOutline); - - ringOutline->draw(rgba); - - glPopMatrix(); -} - -/** - * Draw an outline ellipse. - * - * @param rgba - * Color for drawing. - * @param majorAxis - * Diameter of the major axis. - * @param minorAxis - * Diameter of the minor axis. - */ -void -BrainOpenGLFixedPipeline::drawEllipseFilled(const uint8_t rgba[4], - const double majorAxis, - const double minorAxis) -{ - glPushMatrix(); - glScaled(majorAxis, minorAxis, 1.0); - m_shapeCircleFilled->draw(rgba); - glPopMatrix(); -} - - /** * Draw a cuboid (3D Box) * diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 0ee3761b8..49d10a390 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -228,8 +228,6 @@ namespace caret { void drawBorder(const BorderDrawInfo& borderDrawInfo); - void drawBorderOld(const BorderDrawInfo& borderDrawInfo); - bool unstretchedBorderLineTest(const float p1[3], const float p2[3], const float anat1[3], @@ -395,15 +393,6 @@ namespace caret { void drawCircleFilled(const uint8_t rgba[4], const double diameter); - void drawEllipseOutline(const uint8_t rgba[4], - const double majorAxis, - const double minorAxis, - const double lineThickness); - - void drawEllipseFilled(const uint8_t rgba[4], - const double majorAxis, - const double minorAxis); - void drawSphereWithDiameter(const uint8_t rgba[4], const double diameter); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 5926228c7..d7bd46e8e 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -48,7 +48,9 @@ #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" +#include "GraphicsEngineDataOpenGL.h" #include "GraphicsOpenGLLineDrawing.h" +#include "GraphicsPrimitiveV3fC4f.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "IdentificationWithColor.h" @@ -3598,108 +3600,53 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) glColor3fv(CaretColorEnum::toRGB(outlineColor)); m_fixedPipelineDrawing->setLineWidth(thickness); - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - std::vector lineXYZ; - std::vector lineRGBA; - - /* - * Examine each triangle to see if it intersects the Plane - * in which the slice exists. - */ - for (int it = 0; it < numTriangles; it++) { - const int32_t* triangleNodes = surface->getTriangle(it); - const float* c1 = surface->getCoordinate(triangleNodes[0]); - const float* c2 = surface->getCoordinate(triangleNodes[1]); - const float* c3 = surface->getCoordinate(triangleNodes[2]); - - if (plane.triangleIntersectPlane(c1, c2, c3, - intersectionPoint1, - intersectionPoint2)) { - if (surfaceColorFlag) { - const int32_t rgbaOffset = triangleNodes[0] * 4; - /* - * Use coloring assigned to the first node in the triangle - * but only if Alpha is valid (greater than zero). - */ - if (nodeColoringRGBA[rgbaOffset + 3] <= 0.0f) { - continue; - } - lineRGBA.insert(lineRGBA.end(), &nodeColoringRGBA[rgbaOffset], &nodeColoringRGBA[rgbaOffset] + 4); - lineRGBA.insert(lineRGBA.end(), &nodeColoringRGBA[rgbaOffset], &nodeColoringRGBA[rgbaOffset] + 4); - } - lineXYZ.insert(lineXYZ.end(), intersectionPoint1, intersectionPoint1 + 3); - lineXYZ.insert(lineXYZ.end(), intersectionPoint2, intersectionPoint2 + 3); - } - } + float solidRGBA[4]; + CaretColorEnum::toRGBAFloat(outlineColor, solidRGBA); + + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES)); + + /* + * Examine each triangle to see if it intersects the Plane + * in which the slice exists. + */ + for (int it = 0; it < numTriangles; it++) { + const int32_t* triangleNodes = surface->getTriangle(it); + const float* c1 = surface->getCoordinate(triangleNodes[0]); + const float* c2 = surface->getCoordinate(triangleNodes[1]); + const float* c3 = surface->getCoordinate(triangleNodes[2]); - GLboolean depthTestFlag = GL_FALSE; - glGetBooleanv(GL_DEPTH_TEST, &depthTestFlag); - glDisable(GL_DEPTH_TEST); - float widthPixels = thickness; - if (surfaceColorFlag) { - /* - * Note: Must draw as line segments (each consecutive two points is independent of all others). - * The reason is that the intersection algorithm picks triangles for intersection with the - * surface in no particular order. Thus, two adjacent points in the lines may be nowhere - * near each others. - */ - GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - lineXYZ, - lineRGBA, - widthPixels); - } - else { - /* - * Ditto, comment above - */ - float rgba[4] = { 1.0, 0.0, 0.0, 1.0 }; - CaretColorEnum::toRGBAFloat(outlineColor, rgba); - GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - lineXYZ, - rgba, - widthPixels); - } - if (depthTestFlag) { - glEnable(GL_DEPTH_TEST); - } - } - else { - /* - * Examine each triangle to see if it intersects the Plane - * in which the slice exists. - */ - glBegin(GL_LINES); - for (int it = 0; it < numTriangles; it++) { - const int32_t* triangleNodes = surface->getTriangle(it); - const float* c1 = surface->getCoordinate(triangleNodes[0]); - const float* c2 = surface->getCoordinate(triangleNodes[1]); - const float* c3 = surface->getCoordinate(triangleNodes[2]); - - if (plane.triangleIntersectPlane(c1, c2, c3, - intersectionPoint1, - intersectionPoint2)) { - if (surfaceColorFlag) { - /* - * Use coloring assigned to the first node in the triangle - * but only if Alpha is valid (greater than zero). - */ - const int64_t colorIndex = triangleNodes[0] * 4; - if (nodeColoringRGBA[colorIndex + 3] > 0.0) { - glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); - } - else { - continue; - } - } - + if (plane.triangleIntersectPlane(c1, c2, c3, + intersectionPoint1, + intersectionPoint2)) { + if (surfaceColorFlag) { + const int32_t rgbaOffset = triangleNodes[0] * 4; /* - * Draw the line where the triangle intersections the slice + * Use coloring assigned to the first node in the triangle + * but only if Alpha is valid (greater than zero). */ - glVertex3fv(intersectionPoint1); - glVertex3fv(intersectionPoint2); + if (nodeColoringRGBA[rgbaOffset + 3] <= 0.0f) { + continue; + } + primitive->addVertex(intersectionPoint1, &nodeColoringRGBA[rgbaOffset]); + primitive->addVertex(intersectionPoint2, &nodeColoringRGBA[rgbaOffset]); + } + else { + primitive->addVertex(intersectionPoint1, solidRGBA); + primitive->addVertex(intersectionPoint2, solidRGBA); } } - glEnd(); + } + + GLboolean depthTestFlag = GL_FALSE; + glGetBooleanv(GL_DEPTH_TEST, &depthTestFlag); + glDisable(GL_DEPTH_TEST); + float widthPixels = thickness; + primitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + widthPixels); + GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), + primitive.get()); + if (depthTestFlag) { + glEnable(GL_DEPTH_TEST); } } } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index ccc5059c2..22ba6bf02 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -25,10 +25,12 @@ #include "CaretAssert.h" #include "CaretLogger.h" +#include "DeveloperFlagsEnum.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" +#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" @@ -467,10 +469,174 @@ void GraphicsEngineDataOpenGL::draw(void* openglContextPointer, GraphicsPrimitive* primitive) { - drawPrivate(PrivateDrawMode::DRAW_NORMAL, + CaretAssert(primitive); + + GraphicsPrimitive* primitiveToDraw = primitive; + + /* Conversion to window space creates a new primitive that must be deleted */ + std::unique_ptr windowSpacePrimitive; + + bool workbenchLineFlag = false; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + workbenchLineFlag = true; + } + break; + } + + if (workbenchLineFlag) { + AString errorMessage; + primitiveToDraw = GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, + primitive, + errorMessage); + if (primitiveToDraw == NULL) { + CaretLogSevere(errorMessage); + return; + } + windowSpacePrimitive.reset(primitiveToDraw); + drawWindowSpace(PrivateDrawMode::DRAW_NORMAL, + openglContextPointer, + primitiveToDraw, + NULL); + } + else { + drawPrivate(PrivateDrawMode::DRAW_NORMAL, + openglContextPointer, + primitiveToDraw, + NULL); + } +} + +/** + * Draw the graphics primitive in window space. + * + * @param drawMode + * Mode for drawing. + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * Primitive that is drawn. + * @param primitiveSelectionHelper + * Selection helper when draw mode is selection. + */ +void +GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, + void* openglContextPointer, + GraphicsPrimitive* primitive, + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) +{ + int32_t polygonMode[2]; + int32_t viewport[4]; + saveOpenGLStateForWindowSpaceDrawing(polygonMode, + viewport); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(viewport[0], viewport[0] + viewport[2], + viewport[1], viewport[1] + viewport[3], + 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPolygonMode(GL_FRONT, GL_FILL); + + drawPrivate(drawMode, openglContextPointer, primitive, - NULL); + primitiveSelectionHelper); + + restoreOpenGLStateForWindowSpaceDrawing(polygonMode, + viewport); +} + +/** + * Save the OpenGL State for drawing in window space. + * + * @param polygonMode + * Output with the polygon mode. + * @param viewport + * Output with viewport. + */ +void +GraphicsEngineDataOpenGL::saveOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], + int32_t viewport[4]) +{ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT + | GL_HINT_BIT + | GL_LIGHTING_BIT + | GL_POLYGON_BIT); + + /* + * For anti-aliasing requires sorting polygons + * and turning of depth testing + */ + const bool drawWithAntiAliasingFlag = false; + if (drawWithAntiAliasingFlag) { + glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); + glEnable(GL_BLEND); + glHint(GL_POLYGON_SMOOTH_HINT, + GL_NICEST); + glEnable(GL_POLYGON_SMOOTH); + } + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glGetIntegerv(GL_POLYGON_MODE, + polygonMode); + + glGetIntegerv(GL_VIEWPORT, + viewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + +/** + * Restore the OpenGL State from drawing in window space. + + * @param polygonMode + * Polygon mode. + * @param viewport + * Viewport. + */ +void +GraphicsEngineDataOpenGL::restoreOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], + int32_t viewport[4]) +{ + glPolygonMode(GL_FRONT, polygonMode[0]); + glPolygonMode(GL_BACK, polygonMode[1]); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + + glPopAttrib(); } /** @@ -499,6 +665,35 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, { CaretAssert(primitive); + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + break; + } + selectedPrimitiveIndexOut = -1; selectedPrimitiveDepthOut = 0.0; @@ -765,14 +960,17 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: openGLPrimitiveType = GL_LINES; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index faef4556a..1833be432 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -88,14 +88,26 @@ namespace caret { GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + static void drawWindowSpace(const PrivateDrawMode drawMode, + void* openglContextPointer, + GraphicsPrimitive* primitive, + GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; static float getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive); static float getPointDiameterForDrawingInPixels(const GraphicsPrimitive* primitive); + static void saveOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], + int32_t viewport[4]); + + static void restoreOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], + int32_t viewport[4]); + const void* m_openglContextPointer; + GLsizei m_arrayIndicesCount = 0; std::unique_ptr m_coordinateBufferObject; diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index 0d4274cbd..2bff1d927 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -139,6 +139,12 @@ GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, CaretLogSevere("TRIANGLES is not a valid line drawing type"); return false; break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + break; } return drawLinesPrivate(openglContextPointer, @@ -154,6 +160,128 @@ GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, return false; } +/** + * Convert a Workbench Line Primitive to an OpenGL primitive. + * OpenGL has limits on the width of the lines that it draws. This method will + * convert the lines into polygons so that any line width may be drawn. + * + * @param openglContextPointer + * Pointer to current OpenGL context. + * @param primitive + * A graphics primitive with a primitive type that is one of the + * WORKBENCH_LINE* types. + * @param errorMessageOut + * Upon exit contains an error message if conversion failed. + * @return + * A graphics primitive with an OPENGL_QUADS type that draws the lines + * using polygons. NULL if error. + */ +GraphicsPrimitive* +GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut) +{ + CaretAssert(primitive); + errorMessageOut.clear(); + + if (openglContextPointer == NULL) { + errorMessageOut = "Pointer to current OpenGL context is invalid."; + return NULL; + } + + if ( ! primitive->isValid()) { + errorMessageOut = "Primitive is not valid."; + return NULL; + } + + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + errorMessageOut = "INVALID color type NONE for graphics primitive"; + return NULL; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + errorMessageOut = "Input type is OPENGL_LINES but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + errorMessageOut = "Input type is OPENGL_POINTS but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + errorMessageOut = "Input type is OPENGL_QUADS but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the WORKBENCH_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + lineType = LineType::LINES; + break; + } + + if ( ! errorMessageOut.isEmpty()) { + return NULL; + } + + GraphicsOpenGLLineDrawing lineConversion(NULL, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_primitiveRestartIndices, + lineWidth, + colorType, + lineType); + + GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); + + return primitiveOut; +} /** * Constructor. @@ -519,6 +647,115 @@ GraphicsOpenGLLineDrawing::drawLinesPrivate(void* openglContextPointer, return lineDrawing.performDrawing(); } +/** + * Convert the content of this instance to a new graphics primitive + * that draws the lines as polygons. + * + * @param errorMessageOut + * Contains error message if conversion failed. + * @return + * Pointer to new primitive or NULL if there is an error. + * Caller must destroy the primitive. + */ +GraphicsPrimitive* +GraphicsOpenGLLineDrawing::convertLinesToPolygons(AString& errorMessageOut) +{ + errorMessageOut.clear(); + + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + errorMessageOut = ("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return NULL; + } + + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return NULL; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numFloatRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have float coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numFloatRGBA)); + return NULL; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToQuads(); + + joinQuads(); + + CaretAssert(m_primitive); + } + + restoreOpenGLState(); + + GraphicsPrimitive* primitiveOut = NULL; + + if (m_primitive->isValid()) { + if (m_primitiveByteColor.get() != NULL) { + primitiveOut = m_primitiveByteColor.release(); + } + else if (m_primitiveFloatColor.get() != NULL) { + primitiveOut = m_primitiveFloatColor.release(); + } + else { + CaretAssert(0); + errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; + } + } + else { + errorMessageOut = "Converted primitive is invalid."; + } + + return primitiveOut; +} + + /** * Perform the line drawinhg. * diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h index 1be146c09..24daaca53 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ b/src/Graphics/GraphicsOpenGLLineDrawing.h @@ -50,6 +50,10 @@ namespace caret { virtual ~GraphicsOpenGLLineDrawing(); + static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut); + static bool draw(void* openglContextPointer, const GraphicsPrimitive* primitive); @@ -188,6 +192,8 @@ namespace caret { bool performDrawing(); + GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); + void saveOpenGLState(); void restoreOpenGLState(); diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 1cdf1255b..c944957e5 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -276,16 +276,19 @@ GraphicsPrimitive::isValid() const switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: + case PrimitiveType::WORKBENCH_LINE_LOOP: if (numXYZ < 3) { CaretLogWarning("Line loop must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_LINE_STRIP: + case PrimitiveType::WORKBENCH_LINE_STRIP: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } break; case PrimitiveType::OPENGL_LINES: + case PrimitiveType::WORKBENCH_LINES: if (numXYZ < 2) { CaretLogWarning("Lines must have at least 2 vertices."); } @@ -413,6 +416,12 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const case PrimitiveType::OPENGL_TRIANGLES: s = "Triangles"; break; + case PrimitiveType::WORKBENCH_LINE_LOOP: + break; + case PrimitiveType::WORKBENCH_LINE_STRIP: + break; + case PrimitiveType::WORKBENCH_LINES: + break; } return s; @@ -577,6 +586,12 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; case PrimitiveType::OPENGL_TRIANGLES: break; + case PrimitiveType::WORKBENCH_LINE_LOOP: + break; + case PrimitiveType::WORKBENCH_LINE_STRIP: + break; + case PrimitiveType::WORKBENCH_LINES: + break; } if (addLineWidthFlag) { @@ -869,10 +884,8 @@ GraphicsPrimitive::addPrimitiveRestart() switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: - supportedFlag = true; break; case PrimitiveType::OPENGL_LINE_STRIP: - supportedFlag = true; break; case PrimitiveType::OPENGL_LINES: notApplicableFlag = true; @@ -895,6 +908,14 @@ GraphicsPrimitive::addPrimitiveRestart() case PrimitiveType::OPENGL_TRIANGLES: notApplicableFlag = true; break; + case PrimitiveType::WORKBENCH_LINE_LOOP: + supportedFlag = true; + break; + case PrimitiveType::WORKBENCH_LINE_STRIP: + supportedFlag = true; + break; + case PrimitiveType::WORKBENCH_LINES: + break; } if (notApplicableFlag) { diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index f6b4f1196..fae929455 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -144,7 +144,19 @@ namespace caret { * Treats each triplet of vertices as an independent triangle. Vertices 3n-2, 3n-1, and * 3n define triangle n. n/3 triangles are drawn. */ - OPENGL_TRIANGLES + OPENGL_TRIANGLES, + /** + * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons. + */ + WORKBENCH_LINE_LOOP, + /** + * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons. + */ + WORKBENCH_LINE_STRIP, + /** + * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. + */ + WORKBENCH_LINES, }; /** diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index efce0b28a..2835e0c99 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -73,12 +73,15 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: m_numberOfVerticesPerPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 332a9797b..fa8617914 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -27,7 +27,6 @@ #include "CaretAssert.h" #include "GraphicsEngineDataOpenGL.h" -#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsPrimitiveV3f.h" using namespace caret; @@ -56,6 +55,89 @@ GraphicsShape::~GraphicsShape() { } +/** + * Draw an outline box. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param v1 + * First vertex. + * @param v2 + * Second vertex. + * @param v3 + * Third vertex. + * @param v4 + * Fourth vertex. + * @param rgba + * Color for drawing. + * @param lineThicknessType + * Type of line thickness. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP, + rgba)); + primitive->addVertex(v1); + primitive->addVertex(v2); + primitive->addVertex(v3); + primitive->addVertex(v4); + + primitive->setLineWidth(lineThicknessType, + lineThickness); + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + +/** + * Draw a filled box. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param v1 + * First vertex. + * @param v2 + * Second vertex. + * @param v3 + * Third vertex. + * @param v4 + * Fourth vertex. + * @param rgba + * Color for drawing. + */ +void +GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const uint8_t rgba[4]) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, + rgba)); + primitive->addVertex(v1); + primitive->addVertex(v2); + primitive->addVertex(v3); + primitive->addVertex(v4); + + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + + /** * Draw an outline ellipse. * @@ -67,6 +149,8 @@ GraphicsShape::~GraphicsShape() * Diameter of the minor axis. * @param rgba * Color for drawing. + * @param lineThicknessType + * Type of line thickness. * @param lineThickness * Thickness of the line. */ @@ -75,24 +159,25 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, const double majorAxis, const double minorAxis, const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } - primitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsOpenGLLineDrawing::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); } /** @@ -133,6 +218,79 @@ GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, primitive.get()); } +/** + * Draw lines: Each pair of vertices is a separate line segment + * similar to OpenGL's GL_LINES + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * Coordinates of the line end points. + * @param rgba + * Color for drawing. + * @param lineThicknessType + * Type of line thickness. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawLinesByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES, + rgba)); + const int32_t numVertices = static_cast(xyz.size() / 3); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&xyz[i * 3]); + } + + primitive->setLineWidth(lineThicknessType, + lineThickness); + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + +/** + * Draw line strip similar to OpenGL's GL_LINES + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * Coordinates of the line end points. + * @param rgba + * Color for drawing. + * @param lineThicknessType + * Type of line thickness. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawLineStripByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP, + rgba)); + const int32_t numVertices = static_cast(xyz.size() / 3); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&xyz[i * 3]); + } + + primitive->setLineWidth(lineThicknessType, + lineThickness); + primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + /** * Create the vertices for the ellipse * diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index 72873e022..aadc4c9bb 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -26,6 +26,7 @@ #include #include "CaretObject.h" +#include "GraphicsPrimitive.h" @@ -36,10 +37,27 @@ namespace caret { public: virtual ~GraphicsShape(); + static void drawBoxOutlineByteColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); + + static void drawBoxFilledByteColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const uint8_t rgba[4]); + static void drawEllipseOutlineByteColor(void* openglContextPointer, const double majorAxis, const double minorAxis, const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); static void drawEllipseFilledByteColor(void* openglContextPointer, @@ -47,6 +65,18 @@ namespace caret { const double minorAxis, const uint8_t rgba[4]); + static void drawLinesByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); + + static void drawLineStripByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); + // ADD_NEW_METHODS_HERE virtual AString toString() const; -- GitLab From 0fc2a732fafad3c0f4c76b25c7d1a7a23629dfc7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 10 Nov 2017 09:44:37 -0600 Subject: [PATCH 497/755] Consolidated 'addVertex' methods in Graphics Primitives. Added a 'primitive restart' for triangle strips. Updated border drawing to use newer line drawing. Renamed primitive types for newer lines to 'polygonal' lines and others that still use OpenGL to have 'OpenGL' in their name. Also added a 'sphere' primitive that draws a sphere at each vertex. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 21 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 2 +- src/Charting/ChartTwoDataCartesian.cxx | 2 +- src/Graphics/CMakeLists.txt | 2 + src/Graphics/GraphicsEngineDataOpenGL.cxx | 79 ++- src/Graphics/GraphicsEngineDataOpenGL.h | 3 + src/Graphics/GraphicsOpenGLLineDrawing.cxx | 45 +- src/Graphics/GraphicsPrimitive.cxx | 465 +++++++++++++++--- src/Graphics/GraphicsPrimitive.h | 71 ++- .../GraphicsPrimitiveSelectionHelper.cxx | 9 +- src/Graphics/GraphicsPrimitiveV3f.cxx | 94 +--- src/Graphics/GraphicsPrimitiveV3f.h | 2 - src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 16 +- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 13 +- src/Graphics/GraphicsPrimitiveV3fN3f.cxx | 225 +++++++++ src/Graphics/GraphicsPrimitiveV3fN3f.h | 88 ++++ src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 21 +- src/Graphics/GraphicsShape.cxx | 293 ++++++++++- src/Graphics/GraphicsShape.h | 28 +- 19 files changed, 1239 insertions(+), 240 deletions(-) create mode 100644 src/Graphics/GraphicsPrimitiveV3fN3f.cxx create mode 100644 src/Graphics/GraphicsPrimitiveV3fN3f.h diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 4a813af44..7714855a8 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -103,6 +103,7 @@ #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsShape.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" @@ -233,6 +234,8 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() delete this->colorIdentification; this->colorIdentification = NULL; + + GraphicsShape::deleteAllPrimitives(); } /** @@ -2632,12 +2635,15 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); std::unique_ptr pointsPrimitive; - if (drawSphericalPoints || drawSquarePoints) { + if (drawSquarePoints) { pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); } + if (drawSphericalPoints) { + pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); + } std::unique_ptr linesPrimitive; if (drawLines) { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP)); + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP)); } const bool featureClippingFlag = isFeatureClippingEnabled(); @@ -2802,6 +2808,9 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) else if (i == (numBorderPoints - 1)) { pointsPrimitive->addVertex(xyz, highlightLastPointRGBA); } + else { + pointsPrimitive->addVertex(xyz, solidColorRGBA); + } } else { pointsPrimitive->addVertex(xyz, solidColorRGBA); @@ -2828,10 +2837,18 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) if (pointsPrimitive) { pointsPrimitive->setPointDiameter(GraphicsPrimitive::SizeType::PIXELS, pointDiameter); + pointsPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, + pointDiameter); + if (pointsPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES) { + if ( ! borderDrawInfo.isSelect) { + glEnable(GL_LIGHTING); + } + } GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), pointsPrimitive.get()); } if (linesPrimitive) { + glDisable(GL_LIGHTING); linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineWidth); GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index d7bd46e8e..c8dc46bfa 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3603,7 +3603,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) float solidRGBA[4]; CaretColorEnum::toRGBAFloat(outlineColor, solidRGBA); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES)); + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); /* * Examine each triangle to see if it intersects the Plane diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index e0d74c47d..11b4d6cf4 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -414,7 +414,7 @@ ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) if (m_graphicsPrimitive != NULL) { float rgba[4]; CaretColorEnum::toRGBAFloat(m_color, rgba); - m_graphicsPrimitive->replaceColoring(rgba); + m_graphicsPrimitive->replaceAllVertexSolidFloatRGBA(rgba); } } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index ba5c4c7d3..02a9f3f44 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -22,6 +22,7 @@ GraphicsPrimitiveSelectionHelper.h GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h +GraphicsPrimitiveV3fN3f.h GraphicsPrimitiveV3fT3f.h GraphicsShape.h @@ -39,6 +40,7 @@ GraphicsPrimitiveSelectionHelper.cxx GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx +GraphicsPrimitiveV3fN3f.cxx GraphicsPrimitiveV3fT3f.cxx GraphicsShape.cxx ) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 22ba6bf02..182d58dda 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -34,6 +34,7 @@ #include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" +#include "GraphicsShape.h" using namespace caret; @@ -477,6 +478,7 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, std::unique_ptr windowSpacePrimitive; bool workbenchLineFlag = false; + bool spheresFlag = false; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: break; @@ -498,16 +500,23 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { workbenchLineFlag = true; } break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + spheresFlag = true; + break; } - if (workbenchLineFlag) { + if (spheresFlag) { + drawSpheresPrimitive(openglContextPointer, + primitive); + } + else if (workbenchLineFlag) { AString errorMessage; primitiveToDraw = GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, primitive, @@ -572,6 +581,50 @@ GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, viewport); } +/** + * Draw a sphere primitive type. + * + * @param openglContextPointer + * Pointer to the active OpenGL context. + * @param primitive + * The spheres primitive type. + */ +void +GraphicsEngineDataOpenGL::drawSpheresPrimitive(void* openglContextPointer, + const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES); + + GraphicsPrimitive::SizeType sizeType; + float sizeValue = 0.0f; + primitive->getSphereDiameter(sizeType, + sizeValue); + + const int32_t numberOfVertices = primitive->getNumberOfVertices(); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); + const int32_t i4 = i * 4; + + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); + GraphicsShape::drawSphereByteColor(openglContextPointer, + &primitive->m_xyz[i3], + &primitive->m_unsignedByteRGBA[i4], + sizeValue); + break; + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; + } + } +} + /** * Save the OpenGL State for drawing in window space. * @@ -686,11 +739,14 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + CaretAssertMessage(0, "Not yet implemented"); break; } @@ -960,17 +1016,17 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: openGLPrimitiveType = GL_LINES; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; @@ -996,6 +1052,9 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: openGLPrimitiveType = GL_TRIANGLES; break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + CaretAssertMessage(0, "SPHERES are not drawn with this method"); + break; } CaretAssert(openGLPrimitiveType != GL_INVALID_ENUM); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 1833be432..4c5a269e6 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -93,6 +93,9 @@ namespace caret { GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + static void drawSpheresPrimitive(void* openglContextPointer, + const GraphicsPrimitive* primitive); + GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; static float getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive); diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index 2bff1d927..afa10a58a 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -139,11 +139,14 @@ GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, CaretLogSevere("TRIANGLES is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + CaretLogSevere("SPHERES is not a valid line drawing type"); break; } @@ -151,7 +154,7 @@ GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, - primitive->m_primitiveRestartIndices, + primitive->m_polygonalLinePrimitiveRestartIndices, lineWidth, colorType, lineType); @@ -225,44 +228,47 @@ GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openg LineType lineType = LineType::LINES; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - errorMessageOut = "Input type is OPENGL_LINES but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - errorMessageOut = "Input type is OPENGL_POINTS but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - errorMessageOut = "Input type is OPENGL_QUADS but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the WORKBENCH_LINE* types"; + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: lineType = LineType::LINE_LOOP; break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: lineType = LineType::LINE_STRIP; break; - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: lineType = LineType::LINES; break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; + break; } if ( ! errorMessageOut.isEmpty()) { @@ -273,7 +279,7 @@ GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openg primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, - primitive->m_primitiveRestartIndices, + primitive->m_polygonalLinePrimitiveRestartIndices, lineWidth, colorType, lineType); @@ -999,7 +1005,7 @@ GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, windowNextXYZ); if (distSQ < coincidentMaxDistSQ) { - CaretLogSevere("Filtered out line pairs conincident points " + CaretLogFine("Filtered out line pairs conincident points " + AString::number(i) + " and " + AString::number(i + 1)); @@ -1607,7 +1613,6 @@ GraphicsOpenGLLineDrawing::drawQuads() glLoadIdentity(); glPolygonMode(GL_FRONT, GL_FILL); - //glPolygonMode(GL_BACK, GL_LINE); CaretAssert(m_primitive); GraphicsEngineDataOpenGL::draw(m_openglContextPointer, diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index c944957e5..8ba739616 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -31,6 +31,7 @@ #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsPrimitiveV3fT3f.h" using namespace caret; @@ -119,7 +120,9 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) m_lineWidthValue = obj.m_lineWidthValue; m_pointSizeType = obj.m_pointSizeType; m_pointDiameterValue = obj.m_pointDiameterValue; - m_primitiveRestartIndices = obj.m_primitiveRestartIndices; + m_polygonalLinePrimitiveRestartIndices = obj.m_polygonalLinePrimitiveRestartIndices; + m_sphereSizeType = obj.m_sphereSizeType; + m_sphereDiameterValue = obj.m_sphereDiameterValue; m_textureImageBytesRGBA = obj.m_textureImageBytesRGBA; m_textureImageWidth = obj.m_textureImageWidth; m_textureImageHeight = obj.m_textureImageHeight; @@ -276,19 +279,19 @@ GraphicsPrimitive::isValid() const switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: - case PrimitiveType::WORKBENCH_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_LOOP: if (numXYZ < 3) { CaretLogWarning("Line loop must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_LINE_STRIP: - case PrimitiveType::WORKBENCH_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINE_STRIP: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } break; case PrimitiveType::OPENGL_LINES: - case PrimitiveType::WORKBENCH_LINES: + case PrimitiveType::POLYGONAL_LINES: if (numXYZ < 2) { CaretLogWarning("Lines must have at least 2 vertices."); } @@ -349,6 +352,11 @@ GraphicsPrimitive::isValid() const } } break; + case PrimitiveType::SPHERES: + if (numXYZ < 1) { + CaretLogWarning("Spheres must have at least 1 vertices."); + } + break; } return true; @@ -387,40 +395,46 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: - s = "Line Loop"; + s = "OpenGL Line Loop"; break; case PrimitiveType::OPENGL_LINE_STRIP: - s = "Line Strip"; + s = "OpenGL Line Strip"; break; case PrimitiveType::OPENGL_LINES: - s = "Lines"; + s = "OpenGL Lines"; break; case PrimitiveType::OPENGL_POINTS: - s = "Points"; + s = "OpenGL Points"; break; case PrimitiveType::OPENGL_POLYGON: - s = "Polygon"; + s = "OpenGL Polygon"; break; case PrimitiveType::OPENGL_QUAD_STRIP: - s = "Quad Strip"; + s = "OpenGL Quad Strip"; break; case PrimitiveType::OPENGL_QUADS: - s = "Quads"; + s = "OpenGL Quads"; break; case PrimitiveType::OPENGL_TRIANGLE_FAN: - s = "Triangle Fan"; + s = "OpenGL Triangle Fan"; break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: - s = "Triangle Strip"; + s = "OpenGL Triangle Strip"; break; case PrimitiveType::OPENGL_TRIANGLES: - s = "Triangles"; + s = "OpenGL Triangles"; + break; + case PrimitiveType::POLYGONAL_LINE_LOOP: + s = "Polygonal Line Loop"; break; - case PrimitiveType::WORKBENCH_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_STRIP: + s = "Polygonal Line Strip"; break; - case PrimitiveType::WORKBENCH_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINES: + s = "Polygonal Lines"; break; - case PrimitiveType::WORKBENCH_LINES: + case PrimitiveType::SPHERES: + s = "Spheres"; break; } @@ -479,11 +493,11 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } - if ( ! m_primitiveRestartIndices.empty()) { - s.appendWithNewLine("Restart Indices Count: " + AString::number(m_primitiveRestartIndices.size())); + if ( ! m_polygonalLinePrimitiveRestartIndices.empty()) { + s.appendWithNewLine("Polygonal Line Primitive Restart Indices Count: " + AString::number(m_polygonalLinePrimitiveRestartIndices.size())); if (includeAllDataFlag) { - std::vector temp(m_primitiveRestartIndices.begin(), - m_primitiveRestartIndices.end()); + std::vector temp(m_polygonalLinePrimitiveRestartIndices.begin(), + m_polygonalLinePrimitiveRestartIndices.end()); s.appendWithNewLine(" " + AString::fromNumbers(temp, ", ")); } } @@ -558,8 +572,9 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } - bool addLineWidthFlag = false; - bool addPointSizeFlag = false; + bool addLineWidthFlag = false; + bool addPointSizeFlag = false; + bool addSphereSizeFlag = false; switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: @@ -586,11 +601,17 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; case PrimitiveType::OPENGL_TRIANGLES: break; - case PrimitiveType::WORKBENCH_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_LOOP: + addLineWidthFlag = true; + break; + case PrimitiveType::POLYGONAL_LINE_STRIP: + addLineWidthFlag = true; break; - case PrimitiveType::WORKBENCH_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINES: + addLineWidthFlag = true; break; - case PrimitiveType::WORKBENCH_LINES: + case PrimitiveType::SPHERES: + addSphereSizeFlag = true; break; } @@ -608,45 +629,90 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const + AString::number(m_pointDiameterValue, 'f', 3)); } + if (addSphereSizeFlag) { + s.appendWithNewLine("Sphere Diameter Type: " + + getSizeTypeAsText(m_sphereSizeType) + + "; Diameter Value: " + + AString::number(m_sphereDiameterValue, 'f', 3)); + } + return s; } /** - * Add a vertex. + * Add a vertex and its normal vector * * @param xyz * Coordinate of vertex. + * @param normalVector + * Normal vector for the vertex. + * @param rgbaFloat + * Float RGBA color components. + * @param rgbaByte + * Byte RGBA color components. */ void -GraphicsPrimitive::addVertexProtected(const float xyz[3]) +GraphicsPrimitive::addVertexProtected(const float xyz[3], + const float normalVector[3], + const float rgbaFloat[4], + const uint8_t rgbaByte[4], + const float textureSTR[3]) { m_xyz.insert(m_xyz.end(), xyz, xyz + 3); + + switch (m_normalVectorType) { + case NormalVectorType::FLOAT_XYZ: + CaretAssert(normalVector); + m_floatNormalVectorXYZ.insert(m_floatNormalVectorXYZ.end(), + normalVector, + normalVector + 3); + break; + case NormalVectorType::NONE: + break; + } + + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssert(rgbaFloat); + m_floatRGBA.insert(m_floatRGBA.end(), + rgbaFloat, + rgbaFloat + 4); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssert(rgbaByte); + m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), + rgbaByte, + rgbaByte + 4); + break; + } + + switch (m_textureType) { + case TextureType::NONE: + break; + case TextureType::FLOAT_STR: + CaretAssert(textureSTR); + m_floatTextureSTR.insert(m_floatTextureSTR.end(), + textureSTR, + textureSTR + 3); + break; + } + m_boundingBoxValid = false; + + /* + * The triangle strip primitve vertces are filled after two + * vertices are added after requesting a restart + */ + if (m_triangleStripPrimitiveRestartIndex == getNumberOfVertices()) { + m_triangleStripPrimitiveRestartIndex = -1; + fillTriangleStripPrimitiveRestartVertices(); + } } -/** - * Add a vertex. - * - * @param x - * X-coordinate of vertex. - * @param y - * Y-coordinate of vertex. - * @param z - * Z-coordinate of vertex. - */ -void -GraphicsPrimitive::addVertexProtected(const float x, - const float y, - const float z) -{ - m_xyz.push_back(x); - m_xyz.push_back(y); - m_xyz.push_back(z); - m_boundingBoxValid = false; -} - - /** * Replace the existing XYZ coordinates with the given * XYZ coordinates. The existing and new coordinates @@ -829,6 +895,78 @@ GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, } } +/** + * Replace all vertex RGBA with the given solid color RGBA. + * + * @param rgba + * RGBA values for all vertices + */ +void +GraphicsPrimitive::replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]) +{ + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); + CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); + break; + case ColorType::UNSIGNED_BYTE_RGBA: + { + const int32_t numRGBA = static_cast(m_unsignedByteRGBA.size() / 4); + for (int32_t i = 0; i < numRGBA; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); + m_unsignedByteRGBA[i4] = rgba[0]; + m_unsignedByteRGBA[i4 + 1] = rgba[1]; + m_unsignedByteRGBA[i4 + 2] = rgba[2]; + m_unsignedByteRGBA[i4 + 3] = rgba[3]; + } + } + } + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateColors(); + } +} + +/** + * Replace all vertex RGBA with the given solid color RGBA. + * + * @param rgba + * RGBA values for all vertices + */ +void +GraphicsPrimitive::replaceAllVertexSolidFloatRGBA(const float rgba[4]) +{ + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + { + const int32_t numRGBA = static_cast(m_floatRGBA.size() / 4); + for (int32_t i = 0; i < numRGBA; i++) { + const int32_t i4 = i * 4; + CaretAssertVectorIndex(m_floatRGBA, i4 + 3); + m_floatRGBA[i4] = rgba[0]; + m_floatRGBA[i4 + 1] = rgba[1]; + m_floatRGBA[i4 + 2] = rgba[2]; + m_floatRGBA[i4 + 3] = rgba[3]; + } + } + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); + CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); + break; + } +} + + + + /** * Get a bounds box for the vertex coordinates. * @@ -879,8 +1017,8 @@ GraphicsPrimitive::getVertexBounds(BoundingBox& boundingBoxOut) const void GraphicsPrimitive::addPrimitiveRestart() { - bool notApplicableFlag = false; - bool supportedFlag = false; + bool polygonalLineFlag = false; + bool triangleStripFlag = false; switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: @@ -888,45 +1026,62 @@ GraphicsPrimitive::addPrimitiveRestart() case PrimitiveType::OPENGL_LINE_STRIP: break; case PrimitiveType::OPENGL_LINES: - notApplicableFlag = true; break; case PrimitiveType::OPENGL_POINTS: - notApplicableFlag = true; break; case PrimitiveType::OPENGL_POLYGON: - notApplicableFlag = true; break; case PrimitiveType::OPENGL_QUAD_STRIP: break; case PrimitiveType::OPENGL_QUADS: - notApplicableFlag = true; break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: + triangleStripFlag = true; break; case PrimitiveType::OPENGL_TRIANGLES: - notApplicableFlag = true; break; - case PrimitiveType::WORKBENCH_LINE_LOOP: - supportedFlag = true; + case PrimitiveType::POLYGONAL_LINE_LOOP: + polygonalLineFlag = true; break; - case PrimitiveType::WORKBENCH_LINE_STRIP: - supportedFlag = true; + case PrimitiveType::POLYGONAL_LINE_STRIP: + polygonalLineFlag = true; break; - case PrimitiveType::WORKBENCH_LINES: + case PrimitiveType::POLYGONAL_LINES: + break; + case PrimitiveType::SPHERES: break; } - if (notApplicableFlag) { - CaretLogWarning("Requested primitive restart on non-applicable primitive type: " - + getPrimitiveTypeAsText()); - } - else if (supportedFlag) { + if (polygonalLineFlag) { /* * A set is used because a vertex could be added more than one time */ - m_primitiveRestartIndices.insert(getNumberOfVertices()); + m_polygonalLinePrimitiveRestartIndices.insert(getNumberOfVertices()); + } + else if (triangleStripFlag) { + const int32_t numVertices = getNumberOfVertices(); + if (numVertices > 3) { + /* + * Add 18 dummy vertices that will be used for the + * 6 degenerate triangles at a later time + */ + float float4[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + uint8_t byte4[4] = { 0, 0, 0, 0 }; + for (int32_t i = 0; i < 18; i++) { + addVertexProtected(float4, float4, float4, byte4, float4); + } + + /* + * When the number of vertices becomes the index below, + * the degenerate triangles will be added. + */ + m_triangleStripPrimitiveRestartIndex = getNumberOfVertices() + 2; + } + else { + CaretLogSevere("Must have at least three vertices before requesting a triangle strip primitive restart."); + } } else { CaretLogSevere("Requested primitive restart on not yet supported primitive type: " @@ -934,6 +1089,132 @@ GraphicsPrimitive::addPrimitiveRestart() } } +/** + * Copy a vertex to another vertex. + * + * @param copyFromIndex + * Index of the 'copied' vertex. + * @param copyToIndex + */ +void +GraphicsPrimitive::copyVertex(const int32_t copyFromIndex, + const int32_t copyToIndex) +{ + const int32_t from3 = copyFromIndex * 3; + const int32_t to3 = copyToIndex * 3; + + for (int32_t i = 0; i < 3; i++) { + CaretAssertVectorIndex(m_xyz, from3 + i); + CaretAssertVectorIndex(m_xyz, to3 + i); + m_xyz[to3 + i] = m_xyz[from3 + i]; + + switch (m_normalVectorType) { + case NormalVectorType::FLOAT_XYZ: + CaretAssertVectorIndex(m_floatNormalVectorXYZ, from3 + i); + CaretAssertVectorIndex(m_floatNormalVectorXYZ, to3 + i); + m_floatNormalVectorXYZ[to3 + i] = m_floatNormalVectorXYZ[from3 + i]; + break; + case NormalVectorType::NONE: + break; + } + + switch (m_textureType) { + case TextureType::NONE: + break; + case TextureType::FLOAT_STR: + CaretAssertVectorIndex(m_floatTextureSTR, from3 + i); + CaretAssertVectorIndex(m_floatTextureSTR, to3 + i); + m_floatTextureSTR[to3 + i] = m_floatTextureSTR[from3 + i]; + break; + } + } + + const int32_t from4 = copyFromIndex * 4; + const int32_t to4 = copyToIndex * 4; + + for (int32_t i = 0; i < 4; i++) { + switch (m_colorType) { + case ColorType::NONE: + CaretAssert(0); + break; + case ColorType::FLOAT_RGBA: + CaretAssertVectorIndex(m_floatRGBA, from4 + i); + CaretAssertVectorIndex(m_floatRGBA, to4 + i); + m_floatRGBA[to4 + i] = m_floatRGBA[from4 + i]; + break; + case ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(m_unsignedByteRGBA, from4 + i); + CaretAssertVectorIndex(m_unsignedByteRGBA, to4 + i); + m_unsignedByteRGBA[to4 + i] = m_unsignedByteRGBA[from4 + i]; + break; + } + } + + m_boundingBoxValid = false; +} + +/** + * Fill the degenerate vertices for the triangle strip. + * Since OpenGL's primitive restart (glPrimitiveRestartIndices()) + * function is not available prior to OpenGL 3.1, add + * degenerate triangles as explained in the following links. + * + * @param newStripVertexOneXYZ + * First vertex in new strip that will be added after calling this method. + * @param newStripVertexTwoXYZ + * Second vertex in new strip that will be added after calling this method. + * + * @see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/concatenating-triangle-strips-r1871 + * @see http://en.wikipedia.org/wiki/Triangle_strip + */ +void +GraphicsPrimitive::fillTriangleStripPrimitiveRestartVertices() +{ + const int32_t numVertices = getNumberOfVertices(); + + /* + * Vertices "F" and "F" were added just before the call to addPrimitiveRestart() + * Vertices "G" and "H" were added after the call to addPrimitiveRestart() and + * this method was called immediately after "H" was added + * addPrimitiveRestart() added 18 vertices: + * DEF + EFF + FFG + FGG + GGH + GHG + GGH + GHI + * + * From: https://www.gamedev.net/articles/programming/graphics/concatenating-triangle-strips-r1871 + */ + + const int32_t vertexH = numVertices - 1; + const int32_t vertexG = numVertices - 2; + const int32_t vertexF = numVertices - 21; + const int32_t vertexE = numVertices - 22; + int32_t copyToIndex = vertexF + 1; + + copyVertex(vertexE, copyToIndex++); + copyVertex(vertexF, copyToIndex++); + copyVertex(vertexF, copyToIndex++); + + copyVertex(vertexF, copyToIndex++); + copyVertex(vertexF, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + + copyVertex(vertexF, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexH, copyToIndex++); + + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexH, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexG, copyToIndex++); + copyVertex(vertexH, copyToIndex++); + + CaretAssert(copyToIndex == vertexG); +} + /** * Get the point diameter. * @@ -998,6 +1279,38 @@ GraphicsPrimitive::setLineWidth(const SizeType widthType, m_lineWidthValue = lineWidth; } +/** + * Get the point diameter. + * + * @param sizeTypeOut + * Type of sizing. + * @param pointDiameterOut + * Diameter of point. + */ +void +GraphicsPrimitive::getSphereDiameter(SizeType& sizeTypeOut, + float& sphereDiameterOut) const +{ + sizeTypeOut = m_sphereSizeType; + sphereDiameterOut = m_sphereDiameterValue; +} + +/** + * Set the point diameter. + * + * @param sizeType + * Type of sizing. + * @param pointDiameter + * Diameter of point. + */ +void +GraphicsPrimitive::setSphereDiameter(const SizeType sizeType, + const float sphereDiameter) +{ + m_sphereSizeType = sizeType; + m_sphereDiameterValue = sphereDiameter; +} + /** * Set the image for the texture. * @@ -1086,6 +1399,22 @@ GraphicsPrimitive::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primit return primitive; } +/** + * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible + * for deleting the returned pointer. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + */ +GraphicsPrimitiveV3fN3f* +GraphicsPrimitive::newPrimitiveV3fN3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]) +{ + GraphicsPrimitiveV3fN3f* primitive = new GraphicsPrimitiveV3fN3f(primitiveType, + unsignedByteRGBA); + return primitive; +} + /** * @return A new primitive for XYZ with solid color unsigned byte RGBA. Caller is responsible * for deleting the returned pointer. diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index fae929455..ec654262f 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -37,6 +37,7 @@ namespace caret { class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; + class GraphicsPrimitiveV3fN3f; class GraphicsPrimitiveV3fT3f; class GraphicsPrimitive : public CaretObject, public EventListenerInterface { @@ -148,15 +149,19 @@ namespace caret { /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons. */ - WORKBENCH_LINE_LOOP, + POLYGONAL_LINE_LOOP, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons. */ - WORKBENCH_LINE_STRIP, + POLYGONAL_LINE_STRIP, /** * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. */ - WORKBENCH_LINES, + POLYGONAL_LINES, + /* + * Draws sphere at each vertex + */ + SPHERES }; /** @@ -215,6 +220,9 @@ namespace caret { static GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t unsignedByteRGBA[4]); + static GraphicsPrimitiveV3fN3f* newPrimitiveV3fN3f(const GraphicsPrimitive::PrimitiveType primitiveType, + const uint8_t unsignedByteRGBA[4]); + static GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); static GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); @@ -288,6 +296,10 @@ namespace caret { void replaceVertexByteRGBA(const int32_t vertexIndex, const uint8_t rgba[4]); + void replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]); + + void replaceAllVertexSolidFloatRGBA(const float rgba[4]); + bool getVertexBounds(BoundingBox& boundingBoxOut) const; void addPrimitiveRestart(); @@ -304,6 +316,12 @@ namespace caret { void setLineWidth(const SizeType widthType, const float lineWidth); + void getSphereDiameter(SizeType& sizeTypeOut, + float& sphereDiameterOut) const; + + void setSphereDiameter(const SizeType sizeType, + const float sphereDiameter); + GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); @@ -324,11 +342,11 @@ namespace caret { const int32_t imageWidth, const int32_t imageHeight); - void addVertexProtected(const float xyz[3]); - - void addVertexProtected(const float x, - const float y, - const float z); + void addVertexProtected(const float xyz[3], + const float normalVector[3], + const float rgbaFloat[4], + const uint8_t rgbaByte[4], + const float textureSTR[3]); AString getPrimitiveTypeAsText() const; @@ -350,16 +368,6 @@ namespace caret { std::unique_ptr m_graphicsEngineDataForOpenGL; - std::vector m_floatNormalVectorXYZ; - - std::vector m_floatRGBA; - - std::vector m_unsignedByteRGBA; - - std::vector m_floatTextureSTR; - - std::vector m_textureImageBytesRGBA; - int32_t m_textureImageWidth = -1; int32_t m_textureImageHeight = -1; @@ -372,15 +380,36 @@ namespace caret { float m_lineWidthValue = 1.0f; + SizeType m_sphereSizeType = SizeType::PIXELS; + + float m_sphereDiameterValue = 1.0f; + mutable std::unique_ptr m_boundingBox; - std::set m_primitiveRestartIndices; + std::set m_polygonalLinePrimitiveRestartIndices; + + int32_t m_triangleStripPrimitiveRestartIndex = -1; private: - std::vector m_xyz; void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); - + + void copyVertex(const int32_t copyFromIndex, + const int32_t copyToIndex); + + void fillTriangleStripPrimitiveRestartVertices(); + + std::vector m_xyz; + + std::vector m_floatNormalVectorXYZ; + + std::vector m_floatRGBA; + + std::vector m_unsignedByteRGBA; + + std::vector m_floatTextureSTR; + + std::vector m_textureImageBytesRGBA; friend class GraphicsEngineDataOpenGL; friend class GraphicsOpenGLLineDrawing; friend class GraphicsPrimitiveSelectionHelper; diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index 2835e0c99..f9839d863 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -73,15 +73,15 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - case GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: m_numberOfVerticesPerPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: @@ -105,6 +105,9 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: m_numberOfVerticesPerPrimitive = 3; break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + m_numberOfVerticesPerPrimitive = numberOfVertices; + break; } if (numberOfVertices > 0) { diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index de19238a7..c92269446 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -125,21 +125,11 @@ GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& void GraphicsPrimitiveV3f::addVertex(const float xyz[3]) { - addVertexProtected(xyz); - - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - m_floatRGBA.insert(m_floatRGBA.end(), - m_floatSolidRGBA, m_floatSolidRGBA + 4); - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), - m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); - break; - } + addVertexProtected(xyz, + NULL, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); } /** @@ -154,23 +144,15 @@ GraphicsPrimitiveV3f::addVertex(const float xyz[3]) */ void GraphicsPrimitiveV3f::addVertex(const float x, - const float y, - const float z) + const float y, + const float z) { - addVertexProtected(x, y, z); - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - m_floatRGBA.insert(m_floatRGBA.end(), - m_floatSolidRGBA, m_floatSolidRGBA + 4); - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), - m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); - break; - } + const float xyz[3] = { x, y, z }; + addVertexProtected(xyz, + NULL, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); } /** @@ -185,22 +167,9 @@ GraphicsPrimitiveV3f::addVertex(const float x, */ void GraphicsPrimitiveV3f::addVertex(const float x, - const float y) + const float y) { - addVertexProtected(x, y, 0.0f); - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - m_floatRGBA.insert(m_floatRGBA.end(), - m_floatSolidRGBA, m_floatSolidRGBA + 4); - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), - m_unsignedByteSolidRGBA, m_unsignedByteSolidRGBA + 4); - break; - } + addVertex(x, y, 0.0f); } /** @@ -231,36 +200,3 @@ GraphicsPrimitiveV3f::clone() const return obj; } -/** - * Replace the coloring in the primitive with float data. - * When primitive was constructed it must have used the - * constructor that accepts float data. - * - * @param rgba - * Replacement color RGBA components. - */ -void -GraphicsPrimitiveV3f::replaceColoring(const float rgba[4]) -{ - CaretAssert(m_colorType == ColorType::FLOAT_RGBA); - if (m_colorType == ColorType::FLOAT_RGBA) { - const int32_t numVertices = static_cast(m_floatRGBA.size() / 4); - for (int32_t i = 0; i < numVertices; i++) { - const int32_t i4 = i * 4; - CaretAssertVectorIndex(m_floatRGBA, i4+3); - m_floatRGBA[i4] = rgba[0]; - m_floatRGBA[i4+1] = rgba[1]; - m_floatRGBA[i4+2] = rgba[2]; - m_floatRGBA[i4+3] = rgba[3]; - - if (m_graphicsEngineDataForOpenGL != NULL) { - m_graphicsEngineDataForOpenGL->invalidateColors(); - } - } - } - else { - CaretLogSevere("Replacement coloring is wrong data type (Float)"); - } -} - - diff --git a/src/Graphics/GraphicsPrimitiveV3f.h b/src/Graphics/GraphicsPrimitiveV3f.h index 760a3a7d1..f11925420 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.h +++ b/src/Graphics/GraphicsPrimitiveV3f.h @@ -58,8 +58,6 @@ namespace caret { virtual GraphicsPrimitive* clone() const; - void replaceColoring(const float rgba[4]); - // ADD_NEW_METHODS_HERE private: diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 7e76389d0..8dc0fc078 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -91,9 +91,11 @@ void GraphicsPrimitiveV3fC4f::addVertex(const float xyz[3], const float rgba[4]) { - addVertexProtected(xyz); - m_floatRGBA.insert(m_floatRGBA.end(), - rgba, rgba + 4); + addVertexProtected(xyz, + NULL, + rgba, + NULL, + NULL); } /** @@ -114,9 +116,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float z, const float rgba[4]) { - addVertexProtected(x, y, z); - m_floatRGBA.insert(m_floatRGBA.end(), - rgba, rgba + 4); + addVertex((float[]){ x, y, z}, rgba); } /** @@ -134,9 +134,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float rgba[4]) { - addVertexProtected(x, y, 0.0f); - m_floatRGBA.insert(m_floatRGBA.end(), - rgba, rgba + 4); + addVertex((float[]){ x, y, 0.0f}, rgba); } /** diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 649cfdfe2..4c3905ba0 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -91,9 +91,11 @@ void GraphicsPrimitiveV3fC4ub::addVertex(const float xyz[3], const uint8_t rgba[4]) { - addVertexProtected(xyz); - m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), - rgba, rgba + 4); + addVertexProtected(xyz, + NULL, + NULL, + rgba, + NULL); } /** @@ -114,9 +116,8 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, const float z, const uint8_t rgba[4]) { - addVertexProtected(x, y, z); - m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), - rgba, rgba + 4); + addVertex((float[]){x, y, z}, + rgba); } /** diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx new file mode 100644 index 000000000..5907ec732 --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx @@ -0,0 +1,225 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ +#include "GraphicsPrimitiveV3fN3f.h" +#undef __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "GraphicsEngineDataOpenGL.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsPrimitiveV3fN3f + * \brief Primitive containing vertices, normals, and with one color (float, unsigned byte) applied to all vertices. + * \ingroup Graphics + * + * When we move to using the programmable pipeline OpenGL, the color components + * can be passed to the shader to avoid adding the color to each vertex. + */ + +/** + * Constructor for solid color float RGBA. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, + const float rgba[4]) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::FLOAT_XYZ, + ColorType::FLOAT_RGBA, + TextureType::NONE, + primitiveType) +{ + m_floatSolidRGBA[0] = rgba[0]; + m_floatSolidRGBA[1] = rgba[1]; + m_floatSolidRGBA[2] = rgba[2]; + m_floatSolidRGBA[3] = rgba[3]; +} + +/** + * Constructor for solid color unsigned byte RGBA. + * + * @param primitiveType + * Type of primitive drawn (triangles, lines, etc.) + * @param rgba + * RGBA color components ranging 0.0 to 1.0. + */ +GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, + const uint8_t rgba[4]) +: GraphicsPrimitive(VertexType::FLOAT_XYZ, + NormalVectorType::FLOAT_XYZ, + ColorType::UNSIGNED_BYTE_RGBA, + TextureType::NONE, + primitiveType) +{ + m_unsignedByteSolidRGBA[0] = rgba[0]; + m_unsignedByteSolidRGBA[1] = rgba[1]; + m_unsignedByteSolidRGBA[2] = rgba[2]; + m_unsignedByteSolidRGBA[3] = rgba[3]; +} + +/** + * Destructor. + */ +GraphicsPrimitiveV3fN3f::~GraphicsPrimitiveV3fN3f() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj) +: GraphicsPrimitive(obj) +{ + this->copyHelperGraphicsPrimitiveV3fN3f(obj); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +GraphicsPrimitiveV3fN3f::copyHelperGraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj) +{ + for (int32_t i = 0; i < 4; i++) { + m_floatSolidRGBA[i] = obj.m_floatSolidRGBA[i]; + m_unsignedByteSolidRGBA[i] = obj.m_unsignedByteSolidRGBA[i]; + } +} + +/** + * Add a vertex. + * + * @param xyz + * Coordinate of vertex. + * @param normalXYZ + * Normal vector + */ +void +GraphicsPrimitiveV3fN3f::addVertex(const float xyz[3], + const float normalXYZ[3]) +{ + addVertexProtected(xyz, + normalXYZ, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); +} + +/** + * Add a vertex. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param z + * Z-coordinate of vertex. + * @param normalX + * X component of normal vector + * @param normalY + * Y component of normal vector + * @param normalZ + * Z component of normal vector + */ +void +GraphicsPrimitiveV3fN3f::addVertex(const float x, + const float y, + const float z, + const float normalX, + const float normalY, + const float normalZ) +{ + addVertexProtected((float[]){ x, y, z }, + (float[]){ normalX, normalY, normalZ }, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); +} + +/** + * Add a 2D vertex. Z will be zero. + * + * @param x + * X-coordinate of vertex. + * @param y + * Y-coordinate of vertex. + * @param normalX + * X component of normal vector + * @param normalY + * Y component of normal vector + */ +void +GraphicsPrimitiveV3fN3f::addVertex(const float x, + const float y, + const float normalX, + const float normalY) +{ + addVertexProtected((float[]){ x, y, 0.0f }, + (float[]){ normalX, normalY, 0.0f }, + m_floatSolidRGBA, + m_unsignedByteSolidRGBA, + NULL); +} + +/** + * Add XYZ vertices from an array. + * + * @param xyzArray + * Array containing XYZ vertex data. + * @param normalXyzArray + * Array containing XYZ normal vector data. + * @param numberOfVertices + * Number of vertices (xyz triplets) to add + */ +void +GraphicsPrimitiveV3fN3f::addVertices(const float xyzArray[], + const float normalXyzArray[], + const int32_t numberOfVertices) +{ + for (int32_t i = 0; i < numberOfVertices; i++) { + addVertex(&xyzArray[i*3], + &normalXyzArray[i*3]); + } +} + + +/** + * Clone this primitive. + */ +GraphicsPrimitive* +GraphicsPrimitiveV3fN3f::clone() const +{ + GraphicsPrimitiveV3fN3f* obj = new GraphicsPrimitiveV3fN3f(*this); + return obj; +} + diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.h b/src/Graphics/GraphicsPrimitiveV3fN3f.h new file mode 100644 index 000000000..85a49cc1f --- /dev/null +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.h @@ -0,0 +1,88 @@ +#ifndef __GRAPHICS_PRIMITIVE_V3F_N3F_H__ +#define __GRAPHICS_PRIMITIVE_V3F_N3F_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "GraphicsPrimitive.h" + + + +namespace caret { + + class GraphicsPrimitiveV3fN3f : public GraphicsPrimitive { + + public: + GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, + const float rgba[4]); + + GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, + const uint8_t rgba[4]); + + virtual ~GraphicsPrimitiveV3fN3f(); + + GraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj); + + void addVertex(const float xyz[3], + const float normalXYZ[3]); + + void addVertex(const float x, + const float y, + const float z, + const float normalX, + const float normalY, + const float normalZ); + + void addVertex(const float x, + const float y, + const float normalX, + const float normalY); + + void addVertices(const float xyzArray[], + const float normalXyzArray[], + const int32_t numberOfVertices); + + virtual GraphicsPrimitive* clone() const; + + // ADD_NEW_METHODS_HERE + + private: + GraphicsPrimitiveV3fN3f& operator=(const GraphicsPrimitiveV3fN3f& obj); + + void copyHelperGraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj); + + float m_floatSolidRGBA[4]; + + uint8_t m_unsignedByteSolidRGBA[4]; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ + // +#endif // __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ + +} // namespace +#endif //__GRAPHICS_PRIMITIVE_V3F_N3F_H__ diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 39da63b74..721726b40 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -102,10 +102,11 @@ void GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], const float st[2]) { - addVertexProtected(xyz); - m_floatTextureSTR.push_back(st[0]); - m_floatTextureSTR.push_back(st[1]); - m_floatTextureSTR.push_back(0.0f); + addVertexProtected(xyz, + NULL, + NULL, + NULL, + (float[]){ st[0], st[1], 0.0f }); } /** @@ -129,10 +130,8 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertexProtected(x, y, z); - m_floatTextureSTR.push_back(s); - m_floatTextureSTR.push_back(t); - m_floatTextureSTR.push_back(0.0f); + addVertex((float[]){ x, y, z }, + (float[]){ s, t }); } /** @@ -153,10 +152,8 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertexProtected(x, y, 0.0f); - m_floatTextureSTR.push_back(s); - m_floatTextureSTR.push_back(t); - m_floatTextureSTR.push_back(0.0f); + addVertex((float[]){ x, y, 0.0f }, + (float[]){ s, t }); } /** diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index fa8617914..01963d09b 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -26,8 +26,12 @@ #include #include "CaretAssert.h" +#include "CaretLogger.h" #include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3f.h" +#include "GraphicsPrimitiveV3fN3f.h" +#include "MathFunctions.h" using namespace caret; @@ -55,6 +59,19 @@ GraphicsShape::~GraphicsShape() { } +/** + * Delete all primitives. + */ +void +GraphicsShape::deleteAllPrimitives() +{ + for (auto iter : s_byteSpherePrimitives) { + delete iter.second; + } + s_byteSpherePrimitives.clear(); +} + + /** * Draw an outline box. * @@ -85,7 +102,7 @@ GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, rgba)); primitive->addVertex(v1); primitive->addVertex(v2); @@ -165,7 +182,7 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); for (int32_t i = 0; i < numVertices; i++) { @@ -240,7 +257,7 @@ GraphicsShape::drawLinesByteColor(void* openglContextPointer, const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINES, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); for (int32_t i = 0; i < numVertices; i++) { @@ -276,7 +293,7 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::WORKBENCH_LINE_STRIP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); for (int32_t i = 0; i < numVertices; i++) { @@ -291,6 +308,61 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, primitive.get()); } +/** + * Draw line a sphere at the given XYZ coordinate + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * XYZ-coordinate of sphere + * @param rgba + * Color for drawing. + * @param radius + * Radius of the sphere. + */ +void +GraphicsShape::drawSphereByteColor(void* openglContextPointer, + const float xyz[3], + const uint8_t rgba[4], + const float radius) +{ + const int32_t numLatLonDivisions = 10; + + GraphicsPrimitive* spherePrimitive = NULL; + for (const auto iter : s_byteSpherePrimitives) { + const auto& key = iter.first; + if ((key.first == openglContextPointer) + && (key.second == numLatLonDivisions)) { + spherePrimitive = iter.second; + CaretAssert(spherePrimitive); + break; + } + } + + if (spherePrimitive == NULL) { + const bool useStripsFlag = true; + if (useStripsFlag) { + spherePrimitive = createSpherePrimitiveTriangleStrips(10); + } + else { + spherePrimitive = createSpherePrimitiveTriangles(10); + } + s_byteSpherePrimitives.insert(std::make_pair(std::make_pair(openglContextPointer, numLatLonDivisions), + spherePrimitive)); + } + + CaretAssert(spherePrimitive); + + spherePrimitive->replaceAllVertexSolidByteRGBA(rgba); + + glPushMatrix(); + glTranslatef(xyz[0], xyz[1], xyz[2]); + glScalef(radius, radius, radius); + GraphicsEngineDataOpenGL::draw(openglContextPointer, + spherePrimitive); + glPopMatrix(); +} + /** * Create the vertices for the ellipse * @@ -362,6 +434,219 @@ GraphicsShape::createEllipseVertices(const double majorAxis, } } +/** + * Create an XYZ coordinate on a sphere. + * + * @param radius + * Radius of the sphere + * @param latDegrees + * Latitude on sphere in degrees + * @param lonDegrees + * Longitude on sphere in degrees + * @param latIndex + * Index of the latitude sections + * @param numLat + * Number of latitude sections + * @param xyzOut + * Output with XYZ coordinate + * @param normalXyzOut + * Output with Normal vector + */ +void +GraphicsShape::createSphereXYZ(const float radius, + const float latDegrees, + const float lonDegrees, + const int32_t latIndex, + const int32_t numLat, + float xyzOut[3], + float normalXyzOut[3]) +{ + constexpr float degToRad = M_PI / 180.0f; + + const float lonRad = lonDegrees * degToRad; + const float latRad = latDegrees * degToRad; + const float z = radius * std::sin(latRad); + + + xyzOut[0] = radius * std::cos(latRad) * std::cos(lonRad); + xyzOut[1] = radius * std::cos(latRad) * std::sin(lonRad); + xyzOut[2] = z; + + if (latIndex == 0) { + xyzOut[0] = 0.0f; + xyzOut[1] = 0.0f; + xyzOut[2] = -radius; + } + else if (latIndex == (numLat - 1)) { + xyzOut[0] = 0.0f; + xyzOut[1] = 0.0f; + xyzOut[2] = radius; + } + + normalXyzOut[0] = xyzOut[0]; + normalXyzOut[1] = xyzOut[1]; + normalXyzOut[2] = xyzOut[2]; + MathFunctions::normalizeVector(normalXyzOut); + +} + +/** + * Create a sphere with radius of 0.5 and with the given number + * of latitude and longitude divisions. + * + * @param numberOfLatLon + * Number of latitude/longitude divisions + * @return + * Graphics primitive containing the sphere. + */ +GraphicsPrimitiveV3fN3f* +GraphicsShape::createSpherePrimitiveTriangles(const int32_t numberOfLatLon) +{ + if (numberOfLatLon < 3) { + CaretAssertMessage(0, "For sphere, must have at least 3 lat/lon divisions"); + CaretLogSevere("For sphere, must have at least 3 lat/lon divisions"); + return NULL; + } + + bool debugFlag = false; + if (debugFlag) { + std::cout << std::endl; + std::cout << "TRIANGLE START" << std::endl; + } + + const float radius = 0.5f; + + const int numLat = numberOfLatLon; + const int numLon = numberOfLatLon; + + uint8_t rgba[4] = { 255, 255, 255, 255 }; + GraphicsPrimitiveV3fN3f* primitive = GraphicsPrimitive::newPrimitiveV3fN3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, + rgba); + + const float dLat = 180.0 / numLat; + for (int iLat = 0; iLat < numLat; iLat++) { + const float latDeg = -90.0f + (iLat * dLat); + + const float latDeg2 = -90.0f + ((iLat + 1) * dLat); + + const float dLon = 360.0f / numLon; + for (int iLon = 0; iLon < numLon; iLon++) { + const float lonDeg = iLon * dLon; + + float xyz1[3]; + float normal1[3]; + createSphereXYZ(radius, latDeg, lonDeg, iLat, numLat, xyz1, normal1); + + float xyz2[3]; + float normal2[3]; + createSphereXYZ(radius, latDeg2, lonDeg, iLat + 1, numLat, xyz2, normal2); + + + float xyz3[3]; + float normal3[3]; + createSphereXYZ(radius, latDeg, (lonDeg + dLon), iLat, numLat, xyz3, normal3); + + float xyz4[3]; + float normal4[3]; + createSphereXYZ(radius, latDeg2, (lonDeg + dLon), iLat + 1, numLat, xyz4, normal4); + + primitive->addVertex(xyz1, normal1); + primitive->addVertex(xyz3, normal3); + primitive->addVertex(xyz2, normal2); + + primitive->addVertex(xyz2, normal2); + primitive->addVertex(xyz3, normal3); + primitive->addVertex(xyz4, normal4); + + if (debugFlag) { + const int32_t indx1 = (primitive->getNumberOfVertices() - 2); + const int32_t indx2 = (primitive->getNumberOfVertices() - 1); + std::cout << " " << iLat << ", " << iLon << std::endl; + std::cout << " " << indx1 << ":" << latDeg << ", " << lonDeg << ", " << AString::fromNumbers(xyz1, 3, ",") << std::endl; + std::cout << " " << indx2 << ":" << latDeg2 << ", " << lonDeg << ", " << AString::fromNumbers(xyz2, 3, ",") << std::endl; + std::cout << " " << AString::fromNumbers(xyz3, 3, ",") << std::endl; + std::cout << " " << AString::fromNumbers(xyz4, 3, ",") << std::endl; + } + } + + if (debugFlag) std::cout << std::endl; + } + + return primitive; +} + +/** + * Create a sphere with radius of 0.5 and with the given number + * of latitude and longitude divisions. + * + * @param numberOfLatLon + * Number of latitude/longitude divisions + * @return + * Graphics primitive containing the sphere. + */ +GraphicsPrimitiveV3fN3f* +GraphicsShape::createSpherePrimitiveTriangleStrips(const int32_t numberOfLatLon) +{ + if (numberOfLatLon < 3) { + CaretAssertMessage(0, "For sphere, must have at least 3 lat/lon divisions"); + CaretLogSevere("For sphere, must have at least 3 lat/lon divisions"); + return NULL; + } + + bool debugFlag = false; + if (debugFlag) { + std::cout << std::endl; + std::cout << "TRIANGLE START" << std::endl; + } + + const float radius = 0.5f; + + const int numLat = numberOfLatLon; + const int numLon = numberOfLatLon; + + uint8_t rgba[4] = { 255, 255, 255, 255 }; + GraphicsPrimitiveV3fN3f* primitive = GraphicsPrimitive::newPrimitiveV3fN3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, + rgba); + + const float dLat = 180.0 / numLat; + for (int iLat = 0; iLat < numLat; iLat++) { + const float latDeg = -90.0f + (iLat * dLat); + + const float latDeg2 = -90.0f + ((iLat + 1) * dLat); + + const float dLon = 360.0f / numLon; + for (int iLon = 0; iLon <= numLon; iLon++) { + const float lonDeg = iLon * dLon; + + float xyz1[3]; + float normal1[3]; + createSphereXYZ(radius, latDeg, lonDeg, iLat, numLat, xyz1, normal1); + + float xyz2[3]; + float normal2[3]; + createSphereXYZ(radius, latDeg2, lonDeg, iLat + 1, numLat, xyz2, normal2); + + primitive->addVertex(xyz2, normal2); + primitive->addVertex(xyz1, normal1); + + if (debugFlag) { + const int32_t indx1 = (primitive->getNumberOfVertices() - 2); + const int32_t indx2 = (primitive->getNumberOfVertices() - 1); + std::cout << " " << iLat << ", " << iLon << std::endl; + std::cout << " " << indx1 << ":" << latDeg << ", " << lonDeg << ", " << AString::fromNumbers(xyz1, 3, ",") << std::endl; + std::cout << " " << indx2 << ":" << latDeg2 << ", " << lonDeg << ", " << AString::fromNumbers(xyz2, 3, ",") << std::endl; + } + } + + if (iLat < (numLat - 1)) { + primitive->addPrimitiveRestart(); + } + if (debugFlag) std::cout << std::endl; + } + + return primitive; +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index aadc4c9bb..4e366bf35 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ - +#include #include #include "CaretObject.h" @@ -32,6 +32,8 @@ namespace caret { + class GraphicsPrimitiveV3fN3f; + class GraphicsShape : public CaretObject { public: @@ -77,6 +79,13 @@ namespace caret { const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); + static void drawSphereByteColor(void* openglContextPointer, + const float xyz[3], + const uint8_t rgba[4], + const float radius); + + static void deleteAllPrimitives(); + // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -92,12 +101,27 @@ namespace caret { const double minorAxis, std::vector& ellipseXYZOut); + + static GraphicsPrimitiveV3fN3f* createSpherePrimitiveTriangles(const int32_t numberOfLatLon); + + static GraphicsPrimitiveV3fN3f* createSpherePrimitiveTriangleStrips(const int32_t numberOfLatLon); + + static void createSphereXYZ(const float radius, + const float latDegrees, + const float lonDegrees, + const int32_t latIndex, + const int32_t numLat, + float xyzOut[3], + float normalXyzOut[3]); + + static std::map, GraphicsPrimitive*> s_byteSpherePrimitives; + // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_SHAPE_DECLARE__ - // + std::map, GraphicsPrimitive*> GraphicsShape::s_byteSpherePrimitives; #endif // __GRAPHICS_SHAPE_DECLARE__ } // namespace -- GitLab From 9cdc3c6e1b5dbea58566aa8cd82a155ea41cac67 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 10 Nov 2017 10:18:05 -0600 Subject: [PATCH 498/755] One 'graphics buffer usage type' was used for all data types in a graphics primitive. It has been split into usage types for each data type (coordinates, normals, colors, texture coordinates). --- src/Files/CiftiMappableDataFile.cxx | 2 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 16 ++-- src/Graphics/GraphicsEngineDataOpenGL.h | 5 +- src/Graphics/GraphicsOpenGLLineDrawing.cxx | 2 +- src/Graphics/GraphicsPrimitive.cxx | 89 ++++++++++++++++++++-- src/Graphics/GraphicsPrimitive.h | 26 ++++++- src/Graphics/GraphicsShape.cxx | 15 ++-- 7 files changed, 128 insertions(+), 27 deletions(-) diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index bf3f6fbd3..73b42dde0 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1528,7 +1528,7 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr if (numberOfCells > 0) { matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS - matrixPrimitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + matrixPrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); /* * RGBA for grid outline diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 182d58dda..4891b1f45 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -105,16 +105,16 @@ GraphicsEngineDataOpenGL::invalidateColors() /** * Get the OpenGL Buffer Usage Hint from the primitive. * - * @param primitive - * The graphics primitive + * @param primitiveUsageType + * The graphics primitive usage type * @return * The OpenGL Buffer Usage Hint. */ GLenum -GraphicsEngineDataOpenGL::getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const +GraphicsEngineDataOpenGL::getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const { GLenum usageHint = GL_STREAM_DRAW; - switch (primitive->getUsageType()) { + switch (primitiveUsageType) { case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES: usageHint = GL_STREAM_DRAW; break; @@ -140,7 +140,7 @@ GraphicsEngineDataOpenGL::loadCoordinateBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); - GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeCoordinates()); GLsizei coordinateCount = 0; @@ -197,7 +197,7 @@ GraphicsEngineDataOpenGL::loadNormalVectorBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); - GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeNormals()); switch (primitive->m_normalVectorType) { @@ -236,7 +236,7 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); - GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeColors()); switch (primitive->m_colorType) { case GraphicsPrimitive::ColorType::NONE: @@ -300,7 +300,7 @@ GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primiti { CaretAssert(primitive); - GLenum usageHint = getOpeGLBufferUsageHint(primitive); + GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeTextureCoordinates()); switch (primitive->m_textureType) { case GraphicsPrimitive::TextureType::FLOAT_STR: diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 4c5a269e6..2ac7029d2 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -24,8 +24,9 @@ #include #include -#include "GraphicsEngineData.h" #include "CaretOpenGLInclude.h" +#include "GraphicsEngineData.h" +#include "GraphicsPrimitive.h" namespace caret { @@ -96,7 +97,7 @@ namespace caret { static void drawSpheresPrimitive(void* openglContextPointer, const GraphicsPrimitive* primitive); - GLenum getOpeGLBufferUsageHint(const GraphicsPrimitive* primitive) const; + GLenum getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const; static float getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive); diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx index afa10a58a..da34d20cc 100644 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ b/src/Graphics/GraphicsOpenGLLineDrawing.cxx @@ -1542,7 +1542,7 @@ GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() } CaretAssert(m_primitive); - m_primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); const int32_t numVerticesMinusOne = numVertices - 1; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 8ba739616..821f14096 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -180,26 +180,103 @@ GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) } /** - * @return The usage type hint for graphics system. + * @return The coordinates usage type hint for graphics system. */ GraphicsPrimitive::UsageType -GraphicsPrimitive::getUsageType() const +GraphicsPrimitive::getUsageTypeCoordinates() const { - return m_usageType; + return m_usageTypeCoordinates; +} +/** + * @return The normals usage type hint for graphics system. + */ +GraphicsPrimitive::UsageType +GraphicsPrimitive::getUsageTypeNormals() const +{ + return m_usageTypeNormals; +} + +/** + * @return The colors usage type hint for graphics system. + */ +GraphicsPrimitive::UsageType +GraphicsPrimitive::getUsageTypeColors() const +{ + return m_usageTypeColors; +} + +/** + * @return The texture coordinates usage type hint for graphics system. + */ +GraphicsPrimitive::UsageType +GraphicsPrimitive::getUsageTypeTextureCoordinates() const +{ + return m_usageTypeTextureCoordinates; } /** - * Set the usage type hint for graphics system. + * Set the usage type hint for all data types for graphics system. + * This will override any of the individual (vertex, normal, etc) + * usage types so they should be called after calling this method. * * @param usageType * New value for usage type. */ void -GraphicsPrimitive::setUsageType(const UsageType usageType) +GraphicsPrimitive::setUsageTypeAll(const UsageType usageType) { - m_usageType = usageType; + m_usageTypeCoordinates = usageType; + m_usageTypeNormals = usageType; + m_usageTypeColors = usageType; + m_usageTypeTextureCoordinates = usageType; +} +/** + * Set the coordinates usage type hint for graphics system. + * + * @param usageType + * New value for usage type. + */ +void +GraphicsPrimitive::setUsageTypeCoordinates(const UsageType usageType) +{ + m_usageTypeCoordinates = usageType; } +/** + * Set the normals usage type hint for graphics system. + * + * @param usageType + * New value for usage type. + */ +void +GraphicsPrimitive::setUsageTypeNormals(const UsageType usageType) +{ + m_usageTypeNormals = usageType; +} + +/** + * Set the colors usage type hint for graphics system. + * + * @param usageType + * New value for usage type. + */ +void +GraphicsPrimitive::setUsageTypeColors(const UsageType usageType) +{ + m_usageTypeColors = usageType; +} + +/** + * Set the texture coordinates usage type hint for graphics system. + * + * @param usageType + * New value for usage type. + */ +void +GraphicsPrimitive::setUsageTypeTextureCoordinates(const UsageType usageType) +{ + m_usageTypeTextureCoordinates = usageType; +} /** * @return Is this graphics primitive valid. diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index ec654262f..79fe97e8d 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -236,9 +236,23 @@ namespace caret { void reserveForNumberOfVertices(const int32_t numberOfVertices); - UsageType getUsageType() const; + UsageType getUsageTypeCoordinates() const; - void setUsageType(const UsageType usage); + UsageType getUsageTypeNormals() const; + + UsageType getUsageTypeColors() const; + + UsageType getUsageTypeTextureCoordinates() const; + + void setUsageTypeAll(const UsageType usage); + + void setUsageTypeCoordinates(const UsageType usage); + + void setUsageTypeNormals(const UsageType usage); + + void setUsageTypeColors(const UsageType usage); + + void setUsageTypeTextureCoordinates(const UsageType usage); virtual void receiveEvent(Event* event); @@ -364,7 +378,13 @@ namespace caret { mutable bool m_boundingBoxValid = false; - UsageType m_usageType = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; + UsageType m_usageTypeCoordinates = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; + + UsageType m_usageTypeNormals = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; + + UsageType m_usageTypeColors = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; + + UsageType m_usageTypeTextureCoordinates = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; std::unique_ptr m_graphicsEngineDataForOpenGL; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 01963d09b..5fa00102a 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -111,7 +111,7 @@ GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, primitive->setLineWidth(lineThicknessType, lineThickness); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -148,7 +148,7 @@ GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, primitive->addVertex(v3); primitive->addVertex(v4); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -191,7 +191,7 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, primitive->setLineWidth(lineThicknessType, lineThickness); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -229,7 +229,7 @@ GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, } primitive->addVertex(&ellipseXYZ[0]); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -266,7 +266,7 @@ GraphicsShape::drawLinesByteColor(void* openglContextPointer, primitive->setLineWidth(lineThicknessType, lineThickness); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -302,7 +302,7 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, primitive->setLineWidth(lineThicknessType, lineThickness); - primitive->setUsageType(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(openglContextPointer, primitive.get()); @@ -347,6 +347,9 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, else { spherePrimitive = createSpherePrimitiveTriangles(10); } + /* colors may change but not coordinates/normals */ + spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + spherePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); s_byteSpherePrimitives.insert(std::make_pair(std::make_pair(openglContextPointer, numLatLonDivisions), spherePrimitive)); } -- GitLab From d2bf73601573b88f0a38ef6e59fafeccd047db78 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 10 Nov 2017 16:58:01 -0600 Subject: [PATCH 499/755] In the code to convert OpenGL lines to polylines, the polygons were drawn using quads. Found out that quads are deprecated in newer versions of OpenGL so changed polyline code to use triangles. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 1 - src/Graphics/CMakeLists.txt | 6 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 12 +- src/Graphics/GraphicsOpenGLPolylineQuads.cxx | 1635 ++++++++++++++++ src/Graphics/GraphicsOpenGLPolylineQuads.h | 289 +++ .../GraphicsOpenGLPolylineTriangles.cxx | 1697 +++++++++++++++++ .../GraphicsOpenGLPolylineTriangles.h | 289 +++ src/Graphics/GraphicsPrimitive.h | 3 +- 8 files changed, 3924 insertions(+), 8 deletions(-) create mode 100644 src/Graphics/GraphicsOpenGLPolylineQuads.cxx create mode 100644 src/Graphics/GraphicsOpenGLPolylineQuads.h create mode 100644 src/Graphics/GraphicsOpenGLPolylineTriangles.cxx create mode 100644 src/Graphics/GraphicsOpenGLPolylineTriangles.h diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index c8dc46bfa..7d8804cc0 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -49,7 +49,6 @@ #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" -#include "GraphicsOpenGLLineDrawing.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 02a9f3f44..4e4f926e4 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -15,7 +15,8 @@ EventGraphicsOpenGLDeleteTextureName.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h -GraphicsOpenGLLineDrawing.h +GraphicsOpenGLPolylineQuads.h +GraphicsOpenGLPolylineTriangles.h GraphicsOpenGLTextureName.h GraphicsPrimitive.h GraphicsPrimitiveSelectionHelper.h @@ -33,7 +34,8 @@ EventGraphicsOpenGLDeleteTextureName.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx -GraphicsOpenGLLineDrawing.cxx +GraphicsOpenGLPolylineQuads.cxx +GraphicsOpenGLPolylineTriangles.cxx GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx GraphicsPrimitiveSelectionHelper.cxx diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 4891b1f45..25dc538bf 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -30,7 +30,8 @@ #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" -#include "GraphicsOpenGLLineDrawing.h" +#include "GraphicsOpenGLPolylineQuads.h" +#include "GraphicsOpenGLPolylineTriangles.h" #include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" @@ -518,9 +519,12 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, } else if (workbenchLineFlag) { AString errorMessage; - primitiveToDraw = GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, - primitive, - errorMessage); +// primitiveToDraw = GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, +// primitive, +// errorMessage); + primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, + primitive, + errorMessage); if (primitiveToDraw == NULL) { CaretLogSevere(errorMessage); return; diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx new file mode 100644 index 000000000..db1c7653b --- /dev/null +++ b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx @@ -0,0 +1,1635 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ +#include "GraphicsOpenGLPolylineQuads.h" +#undef __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "GraphicsEngineDataOpenGL.h" +#include "CaretOpenGLInclude.h" +#include "GraphicsPrimitive.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" +#include "MathFunctions.h" +#include "Matrix4x4.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLPolylineQuads + * \brief Converts lines to rectangles + * \ingroup Graphics + * + * Convert lines to polygons. + * OpenGL lines have a limited width whose maximum is often exceeded. + * Convert the lines to rectangles. All drawing is done in + * two dimensional windows coordinates. + */ + +/** + * Destructor. + */ +GraphicsOpenGLPolylineQuads::~GraphicsOpenGLPolylineQuads() +{ +} + +/** + * Draw the given graphics primitive containing lines + * by converting the lines to polygons. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param primtive + * The graphics primitive. + */ +bool +GraphicsOpenGLPolylineQuads::draw(void* openglContextPointer, + const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + if (primitive->isValid()) { + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretLogSevere("INVALID color type NONE for graphics primitive"); + return false; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + lineType = LineType::LINES; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + CaretLogSevere("POINTS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + CaretLogSevere("POLYGON is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + CaretLogSevere("QUADS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + CaretLogSevere("TRIANGLES is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + CaretLogSevere("SPHERES is not a valid line drawing type"); + break; + } + + return drawLinesPrivate(openglContextPointer, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_polygonalLinePrimitiveRestartIndices, + lineWidth, + colorType, + lineType); + } + + return false; +} + +/** + * Convert a Workbench Line Primitive to an OpenGL primitive. + * OpenGL has limits on the width of the lines that it draws. This method will + * convert the lines into polygons so that any line width may be drawn. + * + * @param openglContextPointer + * Pointer to current OpenGL context. + * @param primitive + * A graphics primitive with a primitive type that is one of the + * WORKBENCH_LINE* types. + * @param errorMessageOut + * Upon exit contains an error message if conversion failed. + * @return + * A graphics primitive with an OPENGL_QUADS type that draws the lines + * using polygons. NULL if error. + */ +GraphicsPrimitive* +GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut) +{ + CaretAssert(primitive); + errorMessageOut.clear(); + + if (openglContextPointer == NULL) { + errorMessageOut = "Pointer to current OpenGL context is invalid."; + return NULL; + } + + if ( ! primitive->isValid()) { + errorMessageOut = "Primitive is not valid."; + return NULL; + } + + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + errorMessageOut = "INVALID color type NONE for graphics primitive"; + return NULL; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + lineType = LineType::LINES; + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; + break; + } + + if ( ! errorMessageOut.isEmpty()) { + return NULL; + } + + GraphicsOpenGLPolylineQuads lineConversion(NULL, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_polygonalLinePrimitiveRestartIndices, + lineWidth, + colorType, + lineType); + + GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); + + return primitiveOut; +} + +/** + * Constructor. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The XYZ vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * The primitive will stop at the index and not connect to the next index. + * @param lineThicknessPixels + * Thickness of lines in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + */ +GraphicsOpenGLPolylineQuads::GraphicsOpenGLPolylineQuads(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +: m_openglContextPointer(openglContextPointer), +m_inputXYZ(xyz), +m_inputFloatRGBA(floatRGBA), +m_inputByteRGBA(byteRGBA), +m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), +m_lineThicknessPixels(lineThicknessPixels), +m_colorType(colorType), +m_lineType(lineType) +{ + +} + +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLinesPerVertexFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels) +//{ +// std::set emptyPrimitiveRestartIndices; +// std::vector emptyByteRGBA; +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgba, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_PER_VERTEX, +// LineType::LINES); +//} +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLinesSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// +// std::set emptyPrimitiveRestartIndices; +// std::vector emptyByteRGBA; +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINES); +//} +// +///** +// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLineStripSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyByteRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINE_STRIP); +//} +// +///** +// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLineLoopSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyByteRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINE_LOOP); +//} +// +// +// +// +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLinesPerVertexByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels) +//{ +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgba, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_PER_VERTEX, +// LineType::LINES); +//} +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLinesSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINES); +//} +// +///** +// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLineStripSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINE_STRIP); +//} +// +///** +// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineQuads::drawLineLoopSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINE_LOOP); +//} + + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * @param lineThicknessPixels + * Thickness of line in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLPolylineQuads::drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +{ + GraphicsOpenGLPolylineQuads lineDrawing(openglContextPointer, + xyz, + floatRGBA, + byteRGBA, + vertexPrimitiveRestartIndices, + lineThicknessPixels, + colorType, + lineType); + return lineDrawing.performDrawing(); +} + +/** + * Convert the content of this instance to a new graphics primitive + * that draws the lines as polygons. + * + * @param errorMessageOut + * Contains error message if conversion failed. + * @return + * Pointer to new primitive or NULL if there is an error. + * Caller must destroy the primitive. + */ +GraphicsPrimitive* +GraphicsOpenGLPolylineQuads::convertLinesToPolygons(AString& errorMessageOut) +{ + errorMessageOut.clear(); + + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + errorMessageOut = ("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return NULL; + } + + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return NULL; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numFloatRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have float coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numFloatRGBA)); + return NULL; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToQuads(); + + joinQuads(); + + CaretAssert(m_primitive); + } + + restoreOpenGLState(); + + GraphicsPrimitive* primitiveOut = NULL; + + if (m_primitive->isValid()) { + if (m_primitiveByteColor.get() != NULL) { + primitiveOut = m_primitiveByteColor.release(); + } + else if (m_primitiveFloatColor.get() != NULL) { + primitiveOut = m_primitiveFloatColor.release(); + } + else { + CaretAssert(0); + errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; + } + } + else { + errorMessageOut = "Converted primitive is invalid."; + } + + return primitiveOut; +} + + +/** + * Perform the line drawinhg. + * + * @return + * True if no errors, false if errors. + */ +bool +GraphicsOpenGLPolylineQuads::performDrawing() +{ + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + CaretLogWarning("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return false; + } + + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return false; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numFloatRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have float coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numFloatRGBA)); + return false; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToQuads(); + + joinQuads(); + + CaretAssert(m_primitive); + if (m_primitive->isValid()) { + drawQuads(); + } + } + + restoreOpenGLState(); + + return true; +} + +/** + * Save the OpenGL State. + */ +void +GraphicsOpenGLPolylineQuads::saveOpenGLState() +{ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT + | GL_HINT_BIT + | GL_LIGHTING_BIT + | GL_POLYGON_BIT); + + /* + * For anti-aliasing requires sorting polygons + * and turning of depth testing + */ + const bool drawWithAntiAliasingFlag = false; + if (drawWithAntiAliasingFlag) { + glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); + glEnable(GL_BLEND); + glHint(GL_POLYGON_SMOOTH_HINT, + GL_NICEST); + glEnable(GL_POLYGON_SMOOTH); + } + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glGetIntegerv(GL_POLYGON_MODE, + m_savedPolygonMode); + + glGetIntegerv(GL_VIEWPORT, + m_savedViewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + +/** + * Restore the OpenGL State. + */ +void +GraphicsOpenGLPolylineQuads::restoreOpenGLState() +{ + glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); + glPolygonMode(GL_BACK, m_savedPolygonMode[1]); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); + + glPopAttrib(); +} + +/** + * Create the projection matrix. + */ +void +GraphicsOpenGLPolylineQuads::createProjectionMatrix() +{ + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, + modelviewArray); + Matrix4x4 modelviewMatrix; + modelviewMatrix.setMatrixFromOpenGL(modelviewArray); + + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, + projectionArray); + + m_projectionMatrix.setMatrixFromOpenGL(projectionArray); + //m_projectionMatrix.postmultiply(modelviewMatrix); + m_projectionMatrix.premultiply(modelviewMatrix); +} + + +/** + * Create window coordinates from the input vertices. + */ +void +GraphicsOpenGLPolylineQuads::createWindowCoordinatesFromVertices() +{ + const float coincidentMaxDistSQ = (0.01f * 0.01f); + + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + + int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); + int32_t iStep = 1; + switch (m_lineType) { + case LineType::LINES: + iStep = 2; + if (MathFunctions::isOddNumber(numInputPoints)) { + CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); + --numInputPoints; + } + break; + case LineType::LINE_LOOP: + iStep = 1; + break; + case LineType::LINE_STRIP: + iStep = 1; + break; + } + + m_vertexWindowXYZ.reserve(numInputPoints * 3); + m_vertexWindowInputIndices.reserve(numInputPoints); + + /* + * Coincident points that result in zero length + * line segments are filtered out + */ + for (int32_t i = 0; i < numInputPoints; i += iStep) { + const int32_t i3 = i * 3; + + /* + * Convert model coordinate to a window coordinate + * as described by the documentation from gluProject(). + */ + float windowXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, i3 + 1); + convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); + + if (iStep == 1) { + if (i > 0) { + const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); + CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + &m_vertexWindowXYZ[previousPointOffset]); + if (distSQ < coincidentMaxDistSQ) { + CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); + continue; + } + } + + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + } + else if (iStep == 2) { + const int32_t iNext3 = (i + 1) * 3; + float windowNextXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); + convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], + windowNextXYZ); + + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + windowNextXYZ); + if (distSQ < coincidentMaxDistSQ) { + CaretLogFine("Filtered out line pairs conincident points " + + AString::number(i) + + " and " + + AString::number(i + 1)); + continue; + } + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + + m_vertexWindowXYZ.push_back(windowNextXYZ[0]); + m_vertexWindowXYZ.push_back(windowNextXYZ[1]); + m_vertexWindowXYZ.push_back(windowNextXYZ[2]); + m_vertexWindowInputIndices.push_back(i + 1); + } + else { + CaretAssertMessage(0, "Invalid step value"); + } + + if (m_debugFlag) { + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); + GLdouble winX, winY, winZ; + gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], + modelviewArray, projectionArray, viewport, + &winX, &winY, &winZ); + std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; + std::cout << " Pt " << i << ": " + << winX << ", " << winY << ", " << winZ << std::endl; + std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; + } + } + + CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); +} + +/** + * Convert from a model coordinate to a window coordinate. + * + * @param modelXYZ + * The coordinate in model space. + * @param windowXYZOut + * Output with coordinate in window space. + */ +void +GraphicsOpenGLPolylineQuads::convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const +{ + float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; + m_projectionMatrix.multiplyPoint4(xyzw); + windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); + windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); + windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; + + /* + * From OpenGL Programming Guide 3rd Ed, p 133: + * + * If the near value is 1.0 and the far value is 3.0, + * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. + * So, negate the Z-value to be negative. + */ + windowXYZOut[2] = -windowXYZOut[2]; +} + +/** + * Create a quad from the two window vertices + * + * @param indexOne + * Index of first vertex. + * @param indexTwo + * Index of second vertex. + */ +void +GraphicsOpenGLPolylineQuads::createQuadFromWindowVertices(const int32_t indexOne, + const int32_t indexTwo) +{ + const int32_t iOne3 = indexOne * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); + const int32_t iTwo3 = indexTwo * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); + float x1 = m_vertexWindowXYZ[iOne3]; + float y1 = m_vertexWindowXYZ[iOne3 + 1]; + float z1 = m_vertexWindowXYZ[iOne3 + 2]; + float x2 = m_vertexWindowXYZ[iTwo3]; + float y2 = m_vertexWindowXYZ[iTwo3 + 1]; + float z2 = m_vertexWindowXYZ[iTwo3 + 2]; + + /* + * Normalized vector from start to end on line segment in 2D coordinates + */ + float startToEndVector[3] = { + x2 - x1, + y2 - y1, + 0.0f + }; + const float lineLength = MathFunctions::normalizeVector(startToEndVector); + if (lineLength < 0.001f) { + CaretLogWarning("This should not happen: Failure to filter coincident points with indices=" + + AString::number(indexOne) + + ", " + + AString::number(indexTwo) + + " Coordinates: " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") + + " " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); + } + + /* + * Create a perpendicualar vector to the line segment + */ + float perpendicularVector[3] = { + startToEndVector[1], + -startToEndVector[0], + 0.0f + }; + + /* + * "Width" of rectangle + */ + const float halfWidth = m_lineThicknessPixels / 2.0f; + const float halfWidthX = perpendicularVector[0] * halfWidth; + const float halfWidthY = perpendicularVector[1] * halfWidth; + + /* + * Points of the rectangle + * They should be counter-clockwise oriented + */ + float p1[3] = { + x1 - halfWidthX, + y1 - halfWidthY, + z1 + }; + float p2[3] = { + x1 + halfWidthX, + y1 + halfWidthY, + z1 + }; + float p3[3] = { + x2 + halfWidthX, + y2 + halfWidthY, + z2 + }; + float p4[3] = { + x2 - halfWidthX, + y2 - halfWidthY, + z2 + }; + + /* + * Indices to input coloring. + * Note that coincident points may be removed + */ + CaretAssertVectorIndex(m_vertexWindowInputIndices, indexOne); + const int32_t indexOneRgba = m_vertexWindowInputIndices[indexOne]; + CaretAssertVectorIndex(m_vertexWindowInputIndices, indexTwo); + const int32_t indexTwoRgba = m_vertexWindowInputIndices[indexTwo]; + + /* + * RGBA for the points P1, P2, P3, P4 + */ + int32_t rgbaOffsetP1P2 = 0; + int32_t rgbaOffsetP3P4 = 0; + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; + break; + case ColorType::BYTE_RGBA_SOLID: + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; + break; + case ColorType::FLOAT_RGBA_SOLID: + break; + } + + float crossProduct[3]; + MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); + if (crossProduct[2] == 0.0f) { + /* This should get caught by vector length check above */ + } + + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + { + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); + const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); + const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; + + CaretAssert(m_primitiveByteColor.get()); + if (crossProduct[2] <= 0.0f) { + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p3, rgbaP34); + m_primitiveByteColor->addVertex(p4, rgbaP34); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p4, rgbaP34); + m_primitiveByteColor->addVertex(p3, rgbaP34); + } + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + { + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); + const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); + const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; + + CaretAssert(m_primitiveFloatColor.get()); + if (crossProduct[2] <= 0.0f) { + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + } + } + break; + } + + m_quadInfo.push_back(QuadInfo(indexOne, indexTwo)); +} + +/** + * Join quads to create connected line segments + * without cracks where the quads join together. + */ +void +GraphicsOpenGLPolylineQuads::joinQuads() +{ + CaretAssert(m_primitive); + + const int32_t numQuads = static_cast(m_quadInfo.size()); + const int32_t numQuadsMinusOne = numQuads - 1; + + int32_t numQuadsToConnect = 0; + switch (m_lineType) { + case LineType::LINES: + numQuadsToConnect = 0; + break; + case LineType::LINE_LOOP: + numQuadsToConnect = numQuads; + break; + case LineType::LINE_STRIP: + numQuadsToConnect = numQuadsMinusOne; + break; + } + + /* + * Perform joins of connected quads + */ + for (int32_t i = 0; i < numQuadsToConnect; i++) { + CaretAssertVectorIndex(m_quadInfo, i); + const QuadInfo& quad = m_quadInfo[i]; + + const int32_t nextQuadIndex = ((i < numQuadsMinusOne) ? (i + 1) : 0); + CaretAssertVectorIndex(m_quadInfo, nextQuadIndex); + const QuadInfo& nextQuad = m_quadInfo[nextQuadIndex]; + + /* + * Does quad "i" connect to quad "i+1" ? + */ + if (quad.m_vertexTwoIndex == nextQuad.m_vertexOneIndex) { + const int32_t quadOneVertexIndex = i * 4; + const int32_t quadTwoVertexIndex = nextQuadIndex * 4; + + performJoin(quad.m_vertexOneIndex, + quad.m_vertexTwoIndex, + nextQuad.m_vertexTwoIndex, + quadOneVertexIndex, + quadTwoVertexIndex); + } + } +} + +/** + * Perform a join using the last two vertices in quad one + * and the first two vertices in quad two + * + * @param windowVertexIndexOne + * Index of first window vertex from line segment + * @param windowVertexIndexTwo + * Index of second window from line segment + * @param windowVertexIndexThree + * Index of three window from line segment + * @param quadOneVertexIndex + * Index of first vertex in first quad + * @param quadTwoVertexIndex + * Index of first vertex in second quad + */ +void +GraphicsOpenGLPolylineQuads::performJoin(const int32_t windowVertexIndexOne, + const int32_t windowVertexIndexTwo, + const int32_t windowVertexIndexThree, + const int32_t quadOneVertexIndex, + const int32_t quadTwoVertexIndex) +{ + if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; + CaretAssert(m_primitive); + + /* + * Determine if the junction of the two consecutive + * line segments in window coordinates makes a left + * or right turn + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); + const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], + &m_vertexWindowXYZ[windowVertexIndexTwo * 3], + &m_vertexWindowXYZ[windowVertexIndexThree * 3]); + + + int32_t quadOneSideBeginVertexIndex = -1; + int32_t quadOneSideEndVertexIndex = -1; + int32_t quadTwoSideBeginVertexIndex = -1; + int32_t quadTwoSideEndVertexIndex = -1; + const float smallNumber = 0.001; + if (signedArea > smallNumber) { + if (m_debugFlag) std::cout << " Left Turn" << std::endl; + /* + * Right side is vertices two and three + */ + quadOneSideBeginVertexIndex = quadOneVertexIndex + 1; + quadOneSideEndVertexIndex = quadOneVertexIndex + 2; + quadTwoSideBeginVertexIndex = quadTwoVertexIndex + 1; + quadTwoSideEndVertexIndex = quadTwoVertexIndex + 2; + } + else if (signedArea < -smallNumber) { + if (m_debugFlag) std::cout << " Right Turn" << std::endl; + /* + * Right side is vertices 1 and 4 + */ + quadOneSideBeginVertexIndex = quadOneVertexIndex; + quadOneSideEndVertexIndex = quadOneVertexIndex + 3; + quadTwoSideBeginVertexIndex = quadTwoVertexIndex; + quadTwoSideEndVertexIndex = quadTwoVertexIndex + 3; + } + else { + if (m_debugFlag) std::cout << " Parallel" << std::endl; + return; + } + + const std::vector& xyz = m_primitive->getFloatXYZ(); + CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); + const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; + const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; + const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; + const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; + + /* + * Miter limit is a multiple of the line thickness + */ + const float miterLimit = m_lineThicknessPixels;// * 2.0f; + const float miterLimitSquared = miterLimit * miterLimit; + + /* + * Find location of where the edges in the quads intersect + */ + float intersectionXYZ[3]; + if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { + intersectionXYZ[2] = q1v1[2]; + if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; + + /* + * When the angle is very sharp, the miter point can be very long and pointy + * so limit to a multiplier of the line thickness + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; + const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, + intersectionXYZ); + if (distanceSquared > miterLimitSquared) { + /* + * Extend lines by the miter limit to create a new quad + */ + float newV1[3]; + createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); + float newV2[3]; + createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); + + m_quadJoins.push_back(QuadJoin(q1v2, + newV1, + newV2, //q2v1, + q2v1, //newV2, + quadOneSideEndVertexIndex, + quadTwoSideBeginVertexIndex)); + } + else { + /* + * Move the existing quad vertices to their intersection point + */ + m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); + } + } +} + +/** + * Create a vertex for a miter join when the length limit is exceeded + * + * @param v1 + * First vertex + * @param v2 + * Second vertex that is connected to the miter join vertex. + * @param miterLength + * Length of output vertex from v2 + * @param xyzOut + * Output with vertex used for miter join. + */ +void +GraphicsOpenGLPolylineQuads::createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]) +{ + float n2[3]; + MathFunctions::subtractVectors(v2, v1, n2); + MathFunctions::normalizeVector(n2); + n2[0] *= miterLength; + n2[1] *= miterLength; + n2[2] *= miterLength; + xyzOut[0] = v2[0] + n2[0]; + xyzOut[1] = v2[1] + n2[1]; + xyzOut[2] = v2[2] + n2[2]; +} + +/** + * When the quads are joined, additional quads may be + * created to to fill in the gaps. + */ +void +GraphicsOpenGLPolylineQuads::addMiterJoinQuads() +{ + const int32_t numJoinQuads = static_cast(m_quadJoins.size()); + for (int32_t i = 0; i < numJoinQuads; i++) { + CaretAssertVectorIndex(m_quadJoins, i); + const QuadJoin& quadJoin = m_quadJoins[i]; + + /* + * Add the join quad to the primitive + */ + switch (m_primitive->getColorType()) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + float rgba[4]; + m_primitiveFloatColor->getVertexFloatRGBA(quadJoin.m_primitiveOneTwoIndex, rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[0], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[3], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[6], rgba); + m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[9], rgba); + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + uint8_t rgba[4]; + m_primitiveByteColor->getVertexByteRGBA(quadJoin.m_primitiveThreeFourIndex, rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[0], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[3], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[6], rgba); + m_primitiveByteColor->addVertex(&quadJoin.m_xyz[9], rgba); + } + break; + } + } +} + +/** + * Convert each line segment into a rectangle + * using the line width. "Length" of the + * rectangle is the length of the line segment + * and "width" of the rectangle is the line width. + */ +void +GraphicsOpenGLPolylineQuads::convertLineSegmentsToQuads() +{ + + const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); + + /* + * When estimating number of quads, + * include both the quads formed by the vertices + * and possible quads added for joining end points + */ + int32_t estimatedNumberOfQuads = 0; + switch (m_lineType) { + case LineType::LINES: + estimatedNumberOfQuads = numVertices / 2; + break; + case LineType::LINE_LOOP: + estimatedNumberOfQuads = numVertices * 2; + break; + case LineType::LINE_STRIP: + estimatedNumberOfQuads = (numVertices - 1) * 2; + break; + } + + m_primitive = NULL; + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); + m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + m_primitive = m_primitiveByteColor.get(); + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); + m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); + m_primitive = m_primitiveFloatColor.get(); + break; + } + CaretAssert(m_primitive); + + m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + const int32_t numVerticesMinusOne = numVertices - 1; + + std::vector restartVertexFlags(numVertices, false); + for (auto index : m_vertexPrimitiveRestartIndices) { + restartVertexFlags[index] = true; + } + + /* + * Restart is disabled because it removes vertices that break joins + * Might want to draw all quads and use alpha=0 for quads that + * should not be joined. + */ + const bool restartEnabledFlag = true; + + switch (m_lineType) { + case LineType::LINES: + { + const int32_t numLineSegments = (numVertices / 2); + for (int32_t i = 0; i < numLineSegments; i++) { + const int32_t i2 = i * 2; + createQuadFromWindowVertices(i2, i2 + 1); + } + } + break; + case LineType::LINE_LOOP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createQuadFromWindowVertices(i, i + 1); + } + createQuadFromWindowVertices(numVerticesMinusOne, 0); + break; + case LineType::LINE_STRIP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createQuadFromWindowVertices(i, i + 1); + } + break; + } +} + +/** + * Draw the lines using quads. + */ +void +GraphicsOpenGLPolylineQuads::drawQuads() +{ + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(viewport[0], viewport[0] + viewport[2], + viewport[1], viewport[1] + viewport[3], + 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPolygonMode(GL_FRONT, GL_FILL); + + CaretAssert(m_primitive); + GraphicsEngineDataOpenGL::draw(m_openglContextPointer, + m_primitive); + if (m_debugFlag) { + std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsOpenGLPolylineQuads::toString() const +{ + return "GraphicsOpenGLPolylineQuads"; +} + diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.h b/src/Graphics/GraphicsOpenGLPolylineQuads.h new file mode 100644 index 000000000..6cf4f3c9d --- /dev/null +++ b/src/Graphics/GraphicsOpenGLPolylineQuads.h @@ -0,0 +1,289 @@ +#ifndef __GRAPHICS_OPENGL_POLYLINE_QUADS_H__ +#define __GRAPHICS_OPENGL_POLYLINE_QUADS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include + +#include "CaretObject.h" +#include "Matrix4x4.h" + +namespace caret { + + class GraphicsPrimitive; + class GraphicsPrimitiveV3fC4f; + class GraphicsPrimitiveV3fC4ub; + + class GraphicsOpenGLPolylineQuads : public CaretObject { + + public: + /** + * Join tyupe of how connected lines are drawn to remove gaps between segments + */ + enum JoinType { + /** None */ + NONE, + /* Extends 'outsides' of lines to meet forming a pointed shape */ + MITER + }; + + virtual ~GraphicsOpenGLPolylineQuads(); + + static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut); + + static bool draw(void* openglContextPointer, + const GraphicsPrimitive* primitive); + + static bool drawLinesPerVertexFloatColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); + + static bool drawLinesSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + + static bool drawLinesPerVertexByteColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); + + static bool drawLinesSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + /** + * Type of line coloring + */ + enum class ColorType { + /** Byte RGBA color at each vertex */ + BYTE_RGBA_PER_VERTEX, + /** One Byte RGBA color for all vertices */ + BYTE_RGBA_SOLID, + /** Float RGBA color at each vertex */ + FLOAT_RGBA_PER_VERTEX, + /** One Float RGBA color for all vertices */ + FLOAT_RGBA_SOLID + }; + + /** + * Type of line drawing + */ + enum class LineType { + /** Each pair of vertices is an independent line segment (GL_LINES) */ + LINES, + /** A connected set of lines forming a loop (last is automaticall connected to first) */ + LINE_LOOP, + /** A connected set of lines (last is not connected to first) */ + LINE_STRIP + }; + + /** + * Indices into input vertices of line + * that formed the quad + */ + class QuadInfo { + public: + QuadInfo(const int32_t vertexOneIndex, + const int32_t vertexTwoIndex) + : m_vertexOneIndex(vertexOneIndex), + m_vertexTwoIndex(vertexTwoIndex) { } + + int32_t m_vertexOneIndex; + int32_t m_vertexTwoIndex; + }; + + /** + * Quads created by joining of lines + */ + class QuadJoin { + public: + QuadJoin(const float xyzOne[3], + const float xyzTwo[3], + const float xyzThree[3], + const float xyzFour[3], + const int32_t primitiveOneTwoIndex, + const int32_t primitiveThreeFourIndex) + : m_primitiveOneTwoIndex(primitiveOneTwoIndex), + m_primitiveThreeFourIndex(primitiveThreeFourIndex) { + m_xyz.insert(m_xyz.end(), xyzOne, xyzOne + 3); + m_xyz.insert(m_xyz.end(), xyzTwo, xyzTwo + 3); + m_xyz.insert(m_xyz.end(), xyzThree, xyzThree + 3); + m_xyz.insert(m_xyz.end(), xyzFour, xyzFour + 3); + } + + std::vector m_xyz; + int32_t m_primitiveOneTwoIndex; + int32_t m_primitiveThreeFourIndex; + }; + + GraphicsOpenGLPolylineQuads(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + + GraphicsOpenGLPolylineQuads(const GraphicsOpenGLPolylineQuads& obj); + + GraphicsOpenGLPolylineQuads& operator=(const GraphicsOpenGLPolylineQuads& obj) const; + + static bool drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + + bool performDrawing(); + + GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); + + void saveOpenGLState(); + + void restoreOpenGLState(); + + void createProjectionMatrix(); + + void convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const; + + void createWindowCoordinatesFromVertices(); + + void convertLineSegmentsToQuads(); + + void createQuadFromWindowVertices(const int32_t indexOne, + const int32_t indexTwo); + + void drawQuads(); + + void performJoin(const int32_t lineVertexIndexOne, + const int32_t lineVertexIndexTwo, + const int32_t lineVertexIndexThree, + const int32_t quadOneVertexIndex, + const int32_t quadTwoVertexIndex); + + void joinQuads(); + + void addMiterJoinQuads(); + + void createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]); + + void* m_openglContextPointer; + + const std::vector& m_inputXYZ; + + const std::vector& m_inputFloatRGBA; + + const std::vector& m_inputByteRGBA; + + std::set m_vertexPrimitiveRestartIndices; + + const float m_lineThicknessPixels; + + const ColorType m_colorType; + + const LineType m_lineType; + + std::vector m_vertexWindowXYZ; + + std::vector m_vertexWindowInputIndices; + + //std::vector m_windowQuadsXYZ; + + //std::vector m_windowQuadsRGBA; + + JoinType m_joinType = JoinType::MITER; + + bool m_debugFlag = false; + + int m_savedPolygonMode[2]; + + int m_savedViewport[4]; + + Matrix4x4 m_projectionMatrix; + + /* + * The base class graphics primitive that points to + * either the Float or Byte Color primitive and can + * be used for non-color operations. NEVER delete + * this as it points to one the color primitive + */ + GraphicsPrimitive* m_primitive = NULL; + + std::unique_ptr m_primitiveFloatColor; + + std::unique_ptr m_primitiveByteColor; + + std::vector m_quadInfo; + + std::vector m_quadJoins; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ + // +#endif // __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPENGL_POLYLINE_QUADS_H__ diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx new file mode 100644 index 000000000..e1fa0b323 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -0,0 +1,1697 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ +#include "GraphicsOpenGLPolylineTriangles.h" +#undef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "GraphicsEngineDataOpenGL.h" +#include "CaretOpenGLInclude.h" +#include "GraphicsPrimitive.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsPrimitiveV3fC4ub.h" +#include "MathFunctions.h" +#include "Matrix4x4.h" + +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLPolylineTriangles + * \brief Converts lines to rectangles + * \ingroup Graphics + * + * Convert lines to polygons. + * OpenGL lines have a limited width whose maximum is often exceeded. + * Convert the lines to rectangles. All drawing is done in + * two dimensional windows coordinates. + */ + +/** + * Destructor. + */ +GraphicsOpenGLPolylineTriangles::~GraphicsOpenGLPolylineTriangles() +{ +} + +/** + * Draw the given graphics primitive containing lines + * by converting the lines to polygons. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param primtive + * The graphics primitive. + */ +bool +GraphicsOpenGLPolylineTriangles::draw(void* openglContextPointer, + const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + if (primitive->isValid()) { + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + CaretLogSevere("INVALID color type NONE for graphics primitive"); + return false; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + lineType = LineType::LINES; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + CaretLogSevere("POINTS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + CaretLogSevere("POLYGON is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + CaretLogSevere("QUADS is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + CaretLogSevere("TRIANGLES is not a valid line drawing type"); + return false; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + CaretLogSevere("SPHERES is not a valid line drawing type"); + break; + } + + return drawLinesPrivate(openglContextPointer, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_polygonalLinePrimitiveRestartIndices, + lineWidth, + colorType, + lineType); + } + + return false; +} + +/** + * Convert a Workbench Line Primitive to an OpenGL primitive. + * OpenGL has limits on the width of the lines that it draws. This method will + * convert the lines into polygons so that any line width may be drawn. + * + * @param openglContextPointer + * Pointer to current OpenGL context. + * @param primitive + * A graphics primitive with a primitive type that is one of the + * WORKBENCH_LINE* types. + * @param errorMessageOut + * Upon exit contains an error message if conversion failed. + * @return + * A graphics primitive with an OPENGL_QUADS type that draws the lines + * using polygons. NULL if error. + */ +GraphicsPrimitive* +GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut) +{ + CaretAssert(primitive); + errorMessageOut.clear(); + + if (openglContextPointer == NULL) { + errorMessageOut = "Pointer to current OpenGL context is invalid."; + return NULL; + } + + if ( ! primitive->isValid()) { + errorMessageOut = "Primitive is not valid."; + return NULL; + } + + float lineWidth = primitive->m_lineWidthValue; + + switch (primitive->m_lineWidthType) { + case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + lineWidth = (lineWidth / 100.0) * viewport[3]; + } + break; + case GraphicsPrimitive::SizeType::PIXELS: + break; + } + + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + errorMessageOut = "INVALID color type NONE for graphics primitive"; + return NULL; + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + colorType = ColorType::FLOAT_RGBA_PER_VERTEX; + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + colorType = ColorType::BYTE_RGBA_PER_VERTEX; + break; + } + + LineType lineType = LineType::LINES; + switch (primitive->m_primitiveType) { + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: + errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: + errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: + errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: + errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: + errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: + errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: + errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: + errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + lineType = LineType::LINE_LOOP; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + lineType = LineType::LINE_STRIP; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: + lineType = LineType::LINES; + break; + case GraphicsPrimitive::PrimitiveType::SPHERES: + errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; + break; + } + + if ( ! errorMessageOut.isEmpty()) { + return NULL; + } + + GraphicsOpenGLPolylineTriangles lineConversion(NULL, + primitive->m_xyz, + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_polygonalLinePrimitiveRestartIndices, + lineWidth, + colorType, + lineType); + + GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); + + return primitiveOut; +} + +/** + * Constructor. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The XYZ vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * The primitive will stop at the index and not connect to the next index. + * @param lineThicknessPixels + * Thickness of lines in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + */ +GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +: m_openglContextPointer(openglContextPointer), +m_inputXYZ(xyz), +m_inputFloatRGBA(floatRGBA), +m_inputByteRGBA(byteRGBA), +m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), +m_lineThicknessPixels(lineThicknessPixels), +m_colorType(colorType), +m_lineType(lineType) +{ + +} + +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLinesPerVertexFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels) +//{ +// std::set emptyPrimitiveRestartIndices; +// std::vector emptyByteRGBA; +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgba, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_PER_VERTEX, +// LineType::LINES); +//} +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLinesSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// +// std::set emptyPrimitiveRestartIndices; +// std::vector emptyByteRGBA; +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINES); +//} +// +///** +// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLineStripSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyByteRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINE_STRIP); +//} +// +///** +// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0.0, 1.0] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLineLoopSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyByteRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// rgbaVector, +// emptyByteRGBA, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::FLOAT_RGBA_SOLID, +// LineType::LINE_LOOP); +//} +// +// +// +// +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLinesPerVertexByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels) +//{ +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgba, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_PER_VERTEX, +// LineType::LINES); +//} +// +///** +// * Draw lines where each pair of vertices is drawn as an independent +// * line segment. Same as OpenGL GL_LINES mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLinesSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINES); +//} +// +///** +// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLineStripSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINE_STRIP); +//} +// +///** +// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). +// * +// * @param openglContextPointer +// * Pointer to OpenGL context. +// * @param xyz +// * The vertices. +// * @param rgba +// * RGBA color for the lines with values ranging [0, 255] +// * @param lineThicknessPixels +// * Thickness of line in pixels. +// * @return +// * True if drawn, or false if there was an error. +// */ +//bool +//GraphicsOpenGLPolylineTriangles::drawLineLoopSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels) +//{ +// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; +// std::vector emptyFloatRGBA; +// std::set emptyPrimitiveRestartIndices; +// +// return drawLinesPrivate(openglContextPointer, +// xyz, +// emptyFloatRGBA, +// rgbaVector, +// emptyPrimitiveRestartIndices, +// lineThicknessPixels, +// ColorType::BYTE_RGBA_SOLID, +// LineType::LINE_LOOP); +//} + + +/** + * Draw lines where each pair of vertices is drawn as an independent + * line segment. Same as OpenGL GL_LINES mode with glBegin(). + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * The vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * @param lineThicknessPixels + * Thickness of line in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + * @return + * True if drawn, or false if there was an error. + */ +bool +GraphicsOpenGLPolylineTriangles::drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType) +{ + GraphicsOpenGLPolylineTriangles lineDrawing(openglContextPointer, + xyz, + floatRGBA, + byteRGBA, + vertexPrimitiveRestartIndices, + lineThicknessPixels, + colorType, + lineType); + return lineDrawing.performDrawing(); +} + +/** + * Convert the content of this instance to a new graphics primitive + * that draws the lines as polygons. + * + * @param errorMessageOut + * Contains error message if conversion failed. + * @return + * Pointer to new primitive or NULL if there is an error. + * Caller must destroy the primitive. + */ +GraphicsPrimitive* +GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut) +{ + errorMessageOut.clear(); + + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + errorMessageOut = ("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return NULL; + } + + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return NULL; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numFloatRGBA / 4; + if (numVertices != numRgbaVertices) { + errorMessageOut = ("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have float coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return NULL; + } + } + break; + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { + errorMessageOut = ("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numFloatRGBA)); + return NULL; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToTriangles(); + + joinTriangles(); + + CaretAssert(m_primitive); + } + + restoreOpenGLState(); + + GraphicsPrimitive* primitiveOut = NULL; + + if (m_primitive->isValid()) { + if (m_primitiveByteColor.get() != NULL) { + primitiveOut = m_primitiveByteColor.release(); + } + else if (m_primitiveFloatColor.get() != NULL) { + primitiveOut = m_primitiveFloatColor.release(); + } + else { + CaretAssert(0); + errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; + } + } + else { + errorMessageOut = "Converted primitive is invalid."; + } + + return primitiveOut; +} + + +/** + * Perform the line drawinhg. + * + * @return + * True if no errors, false if errors. + */ +bool +GraphicsOpenGLPolylineTriangles::performDrawing() +{ + const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); + if (numVertices < 2) { + CaretLogWarning("Invalid number of vertices=" + + AString::number(numVertices) + + " for line drawing. Must be at least 2."); + return false; + } + + const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); + const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numByteRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have byte coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::BYTE_RGBA_SOLID: + if (numByteRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numByteRGBA)); + return false; + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + { + const int32_t numRgbaVertices = numFloatRGBA / 4; + if (numVertices != numRgbaVertices) { + CaretLogSevere("Mismatch in vertices and coloring. There are " + + AString::number(numVertices) + + " vertices but have float coloring for " + + AString::number(numRgbaVertices) + + " vertices"); + return false; + } + } + break; + case ColorType::FLOAT_RGBA_SOLID: + if (numFloatRGBA < 4) { + CaretLogSevere("Must have at last 4 color components for solid color line drawing" + "Number of color components is " + + AString::number(numFloatRGBA)); + return false; + } + break; + } + + saveOpenGLState(); + + createProjectionMatrix(); + + createWindowCoordinatesFromVertices(); + + const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); + if (numWindowPoints >= 2) { + convertLineSegmentsToTriangles(); + + joinTriangles(); + + CaretAssert(m_primitive); + if (m_primitive->isValid()) { + drawTriangles(); + } + } + + restoreOpenGLState(); + + return true; +} + +/** + * Save the OpenGL State. + */ +void +GraphicsOpenGLPolylineTriangles::saveOpenGLState() +{ + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_ENABLE_BIT + | GL_HINT_BIT + | GL_LIGHTING_BIT + | GL_POLYGON_BIT); + + /* + * For anti-aliasing requires sorting polygons + * and turning of depth testing + */ + const bool drawWithAntiAliasingFlag = false; + if (drawWithAntiAliasingFlag) { + glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); + glEnable(GL_BLEND); + glHint(GL_POLYGON_SMOOTH_HINT, + GL_NICEST); + glEnable(GL_POLYGON_SMOOTH); + } + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glGetIntegerv(GL_POLYGON_MODE, + m_savedPolygonMode); + + glGetIntegerv(GL_VIEWPORT, + m_savedViewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + +/** + * Restore the OpenGL State. + */ +void +GraphicsOpenGLPolylineTriangles::restoreOpenGLState() +{ + glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); + glPolygonMode(GL_BACK, m_savedPolygonMode[1]); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); + + glPopAttrib(); +} + +/** + * Create the projection matrix. + */ +void +GraphicsOpenGLPolylineTriangles::createProjectionMatrix() +{ + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, + modelviewArray); + Matrix4x4 modelviewMatrix; + modelviewMatrix.setMatrixFromOpenGL(modelviewArray); + + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, + projectionArray); + + m_projectionMatrix.setMatrixFromOpenGL(projectionArray); + //m_projectionMatrix.postmultiply(modelviewMatrix); + m_projectionMatrix.premultiply(modelviewMatrix); +} + + +/** + * Create window coordinates from the input vertices. + */ +void +GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() +{ + const float coincidentMaxDistSQ = (0.01f * 0.01f); + + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + + int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); + int32_t iStep = 1; + switch (m_lineType) { + case LineType::LINES: + iStep = 2; + if (MathFunctions::isOddNumber(numInputPoints)) { + CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); + --numInputPoints; + } + break; + case LineType::LINE_LOOP: + iStep = 1; + break; + case LineType::LINE_STRIP: + iStep = 1; + break; + } + + m_vertexWindowXYZ.reserve(numInputPoints * 3); + m_vertexWindowInputIndices.reserve(numInputPoints); + + /* + * Coincident points that result in zero length + * line segments are filtered out + */ + for (int32_t i = 0; i < numInputPoints; i += iStep) { + const int32_t i3 = i * 3; + + /* + * Convert model coordinate to a window coordinate + * as described by the documentation from gluProject(). + */ + float windowXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, i3 + 1); + convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); + + if (iStep == 1) { + if (i > 0) { + const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); + CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + &m_vertexWindowXYZ[previousPointOffset]); + if (distSQ < coincidentMaxDistSQ) { + CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); + continue; + } + } + + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + } + else if (iStep == 2) { + const int32_t iNext3 = (i + 1) * 3; + float windowNextXYZ[3]; + CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); + convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], + windowNextXYZ); + + const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, + windowNextXYZ); + if (distSQ < coincidentMaxDistSQ) { + CaretLogFine("Filtered out line pairs conincident points " + + AString::number(i) + + " and " + + AString::number(i + 1)); + continue; + } + m_vertexWindowXYZ.push_back(windowXYZ[0]); + m_vertexWindowXYZ.push_back(windowXYZ[1]); + m_vertexWindowXYZ.push_back(windowXYZ[2]); + m_vertexWindowInputIndices.push_back(i); + + m_vertexWindowXYZ.push_back(windowNextXYZ[0]); + m_vertexWindowXYZ.push_back(windowNextXYZ[1]); + m_vertexWindowXYZ.push_back(windowNextXYZ[2]); + m_vertexWindowInputIndices.push_back(i + 1); + } + else { + CaretAssertMessage(0, "Invalid step value"); + } + + if (m_debugFlag) { + GLdouble modelviewArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); + GLdouble projectionArray[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); + GLdouble winX, winY, winZ; + gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], + modelviewArray, projectionArray, viewport, + &winX, &winY, &winZ); + std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; + std::cout << " Pt " << i << ": " + << winX << ", " << winY << ", " << winZ << std::endl; + std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; + } + } + + CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); +} + +/** + * Convert from a model coordinate to a window coordinate. + * + * @param modelXYZ + * The coordinate in model space. + * @param windowXYZOut + * Output with coordinate in window space. + */ +void +GraphicsOpenGLPolylineTriangles::convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const +{ + float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; + m_projectionMatrix.multiplyPoint4(xyzw); + windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); + windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); + windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; + + /* + * From OpenGL Programming Guide 3rd Ed, p 133: + * + * If the near value is 1.0 and the far value is 3.0, + * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. + * So, negate the Z-value to be negative. + */ + windowXYZOut[2] = -windowXYZOut[2]; +} + +/** + * Create two triangles from the two window vertices + * + * @param windowVertexOneIndex + * Index of first window vertex at start of line + * @param windowVertexTwoIndex + * Index of second window vertex at end of line + */ +void +GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t windowVertexOneIndex, + const int32_t windowVertexTwoIndex) +{ + const int32_t iOne3 = windowVertexOneIndex * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); + const int32_t iTwo3 = windowVertexTwoIndex * 3; + CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); + float x1 = m_vertexWindowXYZ[iOne3]; + float y1 = m_vertexWindowXYZ[iOne3 + 1]; + float z1 = m_vertexWindowXYZ[iOne3 + 2]; + float x2 = m_vertexWindowXYZ[iTwo3]; + float y2 = m_vertexWindowXYZ[iTwo3 + 1]; + float z2 = m_vertexWindowXYZ[iTwo3 + 2]; + + /* + * Normalized vector from start to end on line segment in 2D coordinates + */ + float startToEndVector[3] = { + x2 - x1, + y2 - y1, + 0.0f + }; + const float lineLength = MathFunctions::normalizeVector(startToEndVector); + if (lineLength < 0.001f) { + CaretLogWarning("This should not happen: Failure to filter coincident points with indices=" + + AString::number(windowVertexOneIndex) + + ", " + + AString::number(windowVertexTwoIndex) + + " Coordinates: " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") + + " " + + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); + } + + /* + * Create a perpendicualar vector to the line segment + */ + float perpendicularVector[3] = { + startToEndVector[1], + -startToEndVector[0], + 0.0f + }; + + /* + * "Width" of rectangle + */ + const float halfWidth = m_lineThicknessPixels / 2.0f; + const float halfWidthX = perpendicularVector[0] * halfWidth; + const float halfWidthY = perpendicularVector[1] * halfWidth; + + /* + * Points of the rectangle + * They should be counter-clockwise oriented + */ + float p1[3] = { + x1 - halfWidthX, + y1 - halfWidthY, + z1 + }; + float p2[3] = { + x1 + halfWidthX, + y1 + halfWidthY, + z1 + }; + float p3[3] = { + x2 + halfWidthX, + y2 + halfWidthY, + z2 + }; + float p4[3] = { + x2 - halfWidthX, + y2 - halfWidthY, + z2 + }; + + /* + * Indices to input coloring. + * Note that coincident points may be removed + */ + CaretAssertVectorIndex(m_vertexWindowInputIndices, windowVertexOneIndex); + const int32_t indexOneRgba = m_vertexWindowInputIndices[windowVertexOneIndex]; + CaretAssertVectorIndex(m_vertexWindowInputIndices, windowVertexTwoIndex); + const int32_t indexTwoRgba = m_vertexWindowInputIndices[windowVertexTwoIndex]; + + /* + * RGBA for the points P1, P2, P3, P4 + */ + int32_t rgbaOffsetP1P2 = 0; + int32_t rgbaOffsetP3P4 = 0; + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; + break; + case ColorType::BYTE_RGBA_SOLID: + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + rgbaOffsetP1P2 = indexOneRgba * 4; + rgbaOffsetP3P4 = indexTwoRgba * 4; + break; + case ColorType::FLOAT_RGBA_SOLID: + break; + } + + float crossProduct[3]; + MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); + if (crossProduct[2] == 0.0f) { + /* This should get caught by vector length check above */ + } + + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + { + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); + const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); + const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; + + CaretAssert(m_primitiveByteColor.get()); + if (crossProduct[2] <= 0.0f) { + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p4, rgbaP34); + + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p3, rgbaP34); + m_primitiveByteColor->addVertex(p4, rgbaP34); + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveByteColor->addVertex(p2, rgbaP12); + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p3, rgbaP34); + + m_primitiveByteColor->addVertex(p1, rgbaP12); + m_primitiveByteColor->addVertex(p4, rgbaP34); + m_primitiveByteColor->addVertex(p3, rgbaP34); + } + } + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + { + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); + const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; + CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); + const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; + + CaretAssert(m_primitiveFloatColor.get()); + if (crossProduct[2] <= 0.0f) { + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + + } + else { + std::cout << "Flipped Quad" << std::endl; + m_primitiveFloatColor->addVertex(p2, rgbaP12); + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + + m_primitiveFloatColor->addVertex(p1, rgbaP12); + m_primitiveFloatColor->addVertex(p4, rgbaP34); + m_primitiveFloatColor->addVertex(p3, rgbaP34); + } + } + break; + } + + const int32_t numVertices = m_primitiveByteColor->getNumberOfVertices(); + const int32_t triangleOneIndices[3] = { + numVertices - 6, + numVertices - 5, + numVertices - 4 + }; + const int32_t triangleTwoIndices[3] = { + numVertices - 3, + numVertices - 2, + numVertices - 1 + }; + + m_polyLineInfo.push_back(PolylineInfo(windowVertexOneIndex, + windowVertexTwoIndex, + triangleOneIndices, + triangleTwoIndices)); +} + +/** + * Join triangles to create connected line segments + * without cracks where the triangles join together. + */ +void +GraphicsOpenGLPolylineTriangles::joinTriangles() +{ + CaretAssert(m_primitive); + + const int32_t numPolylines = static_cast(m_polyLineInfo.size()); + const int32_t numPolylinesMinusOne = numPolylines - 1; + + int32_t numPolylinesToConnect = 0; + switch (m_lineType) { + case LineType::LINES: + numPolylinesToConnect = 0; + break; + case LineType::LINE_LOOP: + numPolylinesToConnect = numPolylines; + break; + case LineType::LINE_STRIP: + numPolylinesToConnect = numPolylinesMinusOne; + break; + } + + /* + * Perform joins of connected polylines + */ + for (int32_t i = 0; i < numPolylinesToConnect; i++) { + CaretAssertVectorIndex(m_polyLineInfo, i); + const PolylineInfo& poly = m_polyLineInfo[i]; + + const int32_t nextPolyIndex = ((i < numPolylinesMinusOne) ? (i + 1) : 0); + CaretAssertVectorIndex(m_polyLineInfo, nextPolyIndex); + const PolylineInfo& nextPoly = m_polyLineInfo[nextPolyIndex]; + + /* + * Does triangle "i" connect to triangle "i+1" ? + */ + if (poly.m_windowVertexTwoIndex == nextPoly.m_windowVertexOneIndex) { + performJoin(poly, + nextPoly); + } + } + + addMiterJoinTriangles(); +} + +/** + * Join the second triangle in poly one to poly two. + * + * @param polyOne + * Info about triangles in first polyline + * @param polyTwo + * Info about triangles in second polyline + */ +void +GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) +{ + const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; + const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; + const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; + + if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; + CaretAssert(m_primitive); + + /* + * Determine if the junction of the two consecutive + * line segments in window coordinates makes a left + * or right turn + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); + const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], + &m_vertexWindowXYZ[windowVertexIndexTwo * 3], + &m_vertexWindowXYZ[windowVertexIndexThree * 3]); + + + int32_t quadOneSideBeginVertexIndex = -1; + int32_t quadOneSideEndVertexIndex = -1; + int32_t quadTwoSideBeginVertexIndex = -1; + int32_t quadTwoSideEndVertexIndex = -1; + const float smallNumber = 0.001; + bool leftTurnFlag = false; + if (signedArea > smallNumber) { + leftTurnFlag = true; + if (m_debugFlag) std::cout << " Left Turn" << std::endl; + /* + * Right side is first two vertices in triangle two + */ + quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; + quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; + quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; + } + else if (signedArea < -smallNumber) { + if (m_debugFlag) std::cout << " Right Turn" << std::endl; + /* + * Left side is first and third vertices in triangle one + */ + quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; + quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; + quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; + } + else { + if (m_debugFlag) std::cout << " Parallel" << std::endl; + return; + } + + const std::vector& xyz = m_primitive->getFloatXYZ(); + CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); + CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); + const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; + const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; + const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; + const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; + + /* + * Miter limit is a multiple of the line thickness + */ + const float miterLimit = m_lineThicknessPixels;// * 2.0f; + const float miterLimitSquared = miterLimit * miterLimit; + + /* + * Find location of where the edges in the quads intersect + */ + float intersectionXYZ[3]; + if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { + intersectionXYZ[2] = q1v1[2]; + if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; + + /* + * When the angle is very sharp, the miter point can be very long and pointy + * so limit to a multiplier of the line thickness + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; + const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, + intersectionXYZ); + if (distanceSquared > miterLimitSquared) { + /* + * Extend lines by the miter limit to create a new quad + */ + float newV1[3]; + createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); + float newV2[3]; + createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); + + /* + * Extend vertices to the new miter limit + */ + int32_t primitiveIndexV1 = -1; + int32_t primitiveIndexV2 = -1; + if (leftTurnFlag) { + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], newV1); + primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[1]; + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], newV2); + primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[1]; + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], newV2); + } + else { + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], newV1); + primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[2]; + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], newV1); + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], newV2); + primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[0]; + } + + /* + * Add a triangle to fill in the gap + */ + m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, + primitiveIndexV1, + primitiveIndexV2)); + } + else { + /* + * Move the existing quad vertices to their intersection point + */ + if (leftTurnFlag) { + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], intersectionXYZ); + } + else { + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], intersectionXYZ); + m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], intersectionXYZ); + } + } + } +} + +/** + * Create a vertex for a miter join when the length limit is exceeded + * + * @param v1 + * First vertex + * @param v2 + * Second vertex that is connected to the miter join vertex. + * @param miterLength + * Length of output vertex from v2 + * @param xyzOut + * Output with vertex used for miter join. + */ +void +GraphicsOpenGLPolylineTriangles::createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]) +{ + float n2[3]; + MathFunctions::subtractVectors(v2, v1, n2); + MathFunctions::normalizeVector(n2); + n2[0] *= miterLength; + n2[1] *= miterLength; + n2[2] *= miterLength; + xyzOut[0] = v2[0] + n2[0]; + xyzOut[1] = v2[1] + n2[1]; + xyzOut[2] = v2[2] + n2[2]; +} + +/** + * Add triangles to fill in the gaps at limited miter joins. + */ +void +GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() +{ + for (const auto tj : m_triangleJoins) { + CaretAssertVectorIndex(m_vertexWindowXYZ, tj.m_windowVertexIndex * 3 + 2); + const float* v1 = &m_vertexWindowXYZ[tj.m_windowVertexIndex*3]; + + const std::vector& xyz = m_primitive->getFloatXYZ(); + CaretAssertVectorIndex(xyz, tj.m_primitiveVertexOneIndex * 3 + 2); + CaretAssertVectorIndex(xyz, tj.m_primitiveVertexTwoIndex * 3 + 2); + + const float* v2 = &xyz[tj.m_primitiveVertexOneIndex * 3]; + const float* v3 = &xyz[tj.m_primitiveVertexTwoIndex * 3]; + + /* + * If signed area is positive, the triangle is correctly oriented; + * otherwise, flip the vertices + */ + const float signedArea = MathFunctions::triangleAreaSigned2D(v1, v2, v3); + const float smallNumber = 0.001; + const bool normalOutFlag = (signedArea > smallNumber); + + const float* tv2 = (normalOutFlag ? v2 : v3); + const float* tv3 = (normalOutFlag ? v3 : v2); + + switch (m_primitive->getColorType()) { + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + { + float rgba[4]; + m_primitiveFloatColor->getVertexFloatRGBA(tj.m_primitiveVertexOneIndex, rgba); + m_primitiveFloatColor->addVertex(v1, rgba); + m_primitiveFloatColor->addVertex(tv2, rgba); + m_primitiveFloatColor->addVertex(tv3, rgba); + } + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + { + uint8_t rgba[4]; + m_primitiveByteColor->getVertexByteRGBA(tj.m_primitiveVertexOneIndex, rgba); + m_primitiveByteColor->addVertex(v1, rgba); + m_primitiveByteColor->addVertex(tv2, rgba); + m_primitiveByteColor->addVertex(tv3, rgba); + } + break; + } + } +} + +/** + * Convert each line segment into two triangles + * using the line width. "Length" of the + * two triangles is the length of the line segment + * and "width" of the two triangles is the line width. + */ +void +GraphicsOpenGLPolylineTriangles::convertLineSegmentsToTriangles() +{ + + const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); + + /* + * When estimating number of triangles, + * include both the triangles formed by the vertices + * and possible triangles added for joining end points + */ + int32_t estimatedNumberOfQuads = 0; + int32_t maximumNumberOfJoinTriangles = 0; + switch (m_lineType) { + case LineType::LINES: + estimatedNumberOfQuads = numVertices / 2; + maximumNumberOfJoinTriangles = 0; + break; + case LineType::LINE_LOOP: + estimatedNumberOfQuads = numVertices * 2; + maximumNumberOfJoinTriangles = numVertices; + break; + case LineType::LINE_STRIP: + estimatedNumberOfQuads = (numVertices - 1) * 2; + maximumNumberOfJoinTriangles = numVertices - 1; + break; + } + + int32_t estimatedNumberOfTriangles = ((estimatedNumberOfQuads * 2) + + maximumNumberOfJoinTriangles); + const int32_t estimatedNumberOfVertices = estimatedNumberOfTriangles * 3; + + m_primitive = NULL; + switch (m_colorType) { + case ColorType::BYTE_RGBA_PER_VERTEX: + case ColorType::BYTE_RGBA_SOLID: + m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); + m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfVertices); + m_primitive = m_primitiveByteColor.get(); + break; + case ColorType::FLOAT_RGBA_PER_VERTEX: + case ColorType::FLOAT_RGBA_SOLID: + m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); + m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfVertices); + m_primitive = m_primitiveFloatColor.get(); + break; + } + CaretAssert(m_primitive); + + m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + const int32_t numVerticesMinusOne = numVertices - 1; + + std::vector restartVertexFlags(numVertices, false); + for (auto index : m_vertexPrimitiveRestartIndices) { + restartVertexFlags[index] = true; + } + + const bool restartEnabledFlag = true; + + switch (m_lineType) { + case LineType::LINES: + { + const int32_t numLineSegments = (numVertices / 2); + for (int32_t i = 0; i < numLineSegments; i++) { + const int32_t i2 = i * 2; + createTrianglesFromWindowVertices(i2, i2 + 1); + } + } + break; + case LineType::LINE_LOOP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createTrianglesFromWindowVertices(i, i + 1); + } + createTrianglesFromWindowVertices(numVerticesMinusOne, 0); + break; + case LineType::LINE_STRIP: + for (int32_t i = 0; i < numVerticesMinusOne; i++) { + CaretAssertVectorIndex(restartVertexFlags, i + 1); + if (restartVertexFlags[i + 1]) { + if (restartEnabledFlag) continue; + } + createTrianglesFromWindowVertices(i, i + 1); + } + break; + } +} + +/** + * Draw the lines using triangles. + */ +void +GraphicsOpenGLPolylineTriangles::drawTriangles() +{ + GLdouble depthRange[2]; + glGetDoublev(GL_DEPTH_RANGE, + depthRange); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, + viewport); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(viewport[0], viewport[0] + viewport[2], + viewport[1], viewport[1] + viewport[3], + 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPolygonMode(GL_FRONT, GL_FILL); + + CaretAssert(m_primitive); + GraphicsEngineDataOpenGL::draw(m_openglContextPointer, + m_primitive); + if (m_debugFlag) { + std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; + std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +GraphicsOpenGLPolylineTriangles::toString() const +{ + return "GraphicsOpenGLPolylineTriangles"; +} + diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h new file mode 100644 index 000000000..592a8594c --- /dev/null +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -0,0 +1,289 @@ +#ifndef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ +#define __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include +#include + +#include "CaretObject.h" +#include "Matrix4x4.h" + +namespace caret { + + class GraphicsPrimitive; + class GraphicsPrimitiveV3fC4f; + class GraphicsPrimitiveV3fC4ub; + + class GraphicsOpenGLPolylineTriangles : public CaretObject { + + public: + /** + * Join tyupe of how connected lines are drawn to remove gaps between segments + */ + enum JoinType { + /** None */ + NONE, + /* Extends 'outsides' of lines to meet forming a pointed shape */ + MITER + }; + + virtual ~GraphicsOpenGLPolylineTriangles(); + + static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, + const GraphicsPrimitive* primitive, + AString& errorMessageOut); + + static bool draw(void* openglContextPointer, + const GraphicsPrimitive* primitive); + + static bool drawLinesPerVertexFloatColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); + + static bool drawLinesSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidFloatColor(void* openglContextPointer, + const std::vector& xyz, + const float rgba[4], + const float lineThicknessPixels); + + + static bool drawLinesPerVertexByteColor(void* openglContextPointer, + const std::vector& xyz, + const std::vector& rgba, + const float lineThicknessPixels); + + static bool drawLinesSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineStripSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + static bool drawLineLoopSolidByteColor(void* openglContextPointer, + const std::vector& xyz, + const uint8_t rgba[4], + const float lineThicknessPixels); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + /** + * Type of line coloring + */ + enum class ColorType { + /** Byte RGBA color at each vertex */ + BYTE_RGBA_PER_VERTEX, + /** One Byte RGBA color for all vertices */ + BYTE_RGBA_SOLID, + /** Float RGBA color at each vertex */ + FLOAT_RGBA_PER_VERTEX, + /** One Float RGBA color for all vertices */ + FLOAT_RGBA_SOLID + }; + + /** + * Type of line drawing + */ + enum class LineType { + /** Each pair of vertices is an independent line segment (GL_LINES) */ + LINES, + /** A connected set of lines forming a loop (last is automaticall connected to first) */ + LINE_LOOP, + /** A connected set of lines (last is not connected to first) */ + LINE_STRIP + }; + + /** + * Indices into input vertices of line + * that formed the polyline + */ + class PolylineInfo { + public: + PolylineInfo(const int32_t windowVertexOneIndex, + const int32_t windowVertexTwoIndex, + const int32_t triangleOnePrimitiveIndices[3], + const int32_t triangleTwoPrimitiveIndices[3]) + : m_windowVertexOneIndex(windowVertexOneIndex), + m_windowVertexTwoIndex(windowVertexTwoIndex) { + m_triangleOnePrimitiveIndices[0] = triangleOnePrimitiveIndices[0]; + m_triangleOnePrimitiveIndices[1] = triangleOnePrimitiveIndices[1]; + m_triangleOnePrimitiveIndices[2] = triangleOnePrimitiveIndices[2]; + m_triangleTwoPrimitiveIndices[0] = triangleTwoPrimitiveIndices[0]; + m_triangleTwoPrimitiveIndices[1] = triangleTwoPrimitiveIndices[1]; + m_triangleTwoPrimitiveIndices[2] = triangleTwoPrimitiveIndices[2]; + } + + int32_t m_windowVertexOneIndex; + int32_t m_windowVertexTwoIndex; + int32_t m_triangleOnePrimitiveIndices[3]; + int32_t m_triangleTwoPrimitiveIndices[3]; + }; + + /** + * Triangles created by joining of polylines + */ + class TriangleJoin { + public: + TriangleJoin(const int32_t windowVertexIndex, + const int32_t primitiveVertexOneIndex, + const int32_t primitiveVertexTwoIndex) + : m_windowVertexIndex(windowVertexIndex), + m_primitiveVertexOneIndex(primitiveVertexOneIndex), + m_primitiveVertexTwoIndex(primitiveVertexTwoIndex) + { + + } + + const int32_t m_windowVertexIndex; + const int32_t m_primitiveVertexOneIndex; + const int32_t m_primitiveVertexTwoIndex; + }; + + GraphicsOpenGLPolylineTriangles(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + + GraphicsOpenGLPolylineTriangles(const GraphicsOpenGLPolylineTriangles& obj); + + GraphicsOpenGLPolylineTriangles& operator=(const GraphicsOpenGLPolylineTriangles& obj) const; + + static bool drawLinesPrivate(void* openglContextPointer, + const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType); + + bool performDrawing(); + + GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); + + void saveOpenGLState(); + + void restoreOpenGLState(); + + void createProjectionMatrix(); + + void convertFromModelToWindowCoordinate(const float modelXYZ[3], + float windowXYZOut[3]) const; + + void createWindowCoordinatesFromVertices(); + + void convertLineSegmentsToTriangles(); + + void createTrianglesFromWindowVertices(const int32_t windowVertexOneIndex, + const int32_t windowVertexTwoIndex); + + void drawTriangles(); + + void performJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo); + + void joinTriangles(); + + void addMiterJoinTriangles(); + + void createMiterJoinVertex(const float v1[3], + const float v2[3], + const float miterLength, + float xyzOut[3]); + + void* m_openglContextPointer; + + const std::vector& m_inputXYZ; + + const std::vector& m_inputFloatRGBA; + + const std::vector& m_inputByteRGBA; + + std::set m_vertexPrimitiveRestartIndices; + + const float m_lineThicknessPixels; + + const ColorType m_colorType; + + const LineType m_lineType; + + std::vector m_vertexWindowXYZ; + + std::vector m_vertexWindowInputIndices; + + JoinType m_joinType = JoinType::MITER; + + bool m_debugFlag = false; + + int m_savedPolygonMode[2]; + + int m_savedViewport[4]; + + Matrix4x4 m_projectionMatrix; + + /* + * The base class graphics primitive that points to + * either the Float or Byte Color primitive and can + * be used for non-color operations. NEVER delete + * this as it points to one the color primitive + */ + GraphicsPrimitive* m_primitive = NULL; + + std::unique_ptr m_primitiveFloatColor; + + std::unique_ptr m_primitiveByteColor; + + std::vector m_polyLineInfo; + + std::vector m_triangleJoins; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ + // +#endif // __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 79fe97e8d..9754490eb 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -431,7 +431,8 @@ namespace caret { std::vector m_textureImageBytesRGBA; friend class GraphicsEngineDataOpenGL; - friend class GraphicsOpenGLLineDrawing; + friend class GraphicsOpenGLPolylineQuads; + friend class GraphicsOpenGLPolylineTriangles; friend class GraphicsPrimitiveSelectionHelper; std::vector m_dummyFloatRGBAVector; -- GitLab From 0c46e44a39b036381b517c866813ebd0598e1efe Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Nov 2017 09:47:39 -0600 Subject: [PATCH 500/755] Removed/replaced older/unused graphics code. --- src/Brain/BrainOpenGL.cxx | 10 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 257 ++---- src/Brain/BrainOpenGLFixedPipeline.cxx | 65 -- src/Brain/BrainOpenGLFixedPipeline.h | 16 - src/Brain/BrainOpenGLPrimitiveDrawing.cxx | 793 ------------------ src/Brain/BrainOpenGLPrimitiveDrawing.h | 73 -- src/Brain/BrainOpenGLShapeRingOutline.cxx | 377 --------- src/Brain/BrainOpenGLShapeRingOutline.h | 92 -- src/Brain/BrainOpenGLTextRenderInterface.h | 2 + src/Brain/CMakeLists.txt | 2 - src/Brain/DummyFontTextRenderer.cxx | 11 + src/Brain/DummyFontTextRenderer.h | 2 + src/Brain/FtglFontTextRenderer.cxx | 39 +- src/Brain/FtglFontTextRenderer.h | 4 + src/Desktop/desktop.cxx | 1 + src/Graphics/GraphicsOpenGLPolylineQuads.cxx | 1 + .../GraphicsOpenGLPolylineTriangles.cxx | 281 +------ .../GraphicsOpenGLPolylineTriangles.h | 82 +- src/Graphics/GraphicsShape.cxx | 223 ++++- src/Graphics/GraphicsShape.h | 30 + 20 files changed, 424 insertions(+), 1937 deletions(-) delete mode 100644 src/Brain/BrainOpenGLShapeRingOutline.cxx delete mode 100644 src/Brain/BrainOpenGLShapeRingOutline.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 00fc6ca14..2648fa3c8 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -205,6 +205,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, std::vector& viewportContents) { m_contextSharingGroupPointer = contextSharingGroupPointer; + m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); drawModelsImplementation(windowIndex, brain, @@ -213,6 +214,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; + m_textRenderer->setSharedOpenGLContextPointer(NULL); } /** @@ -247,7 +249,8 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, const bool applySelectionBackgroundFiltering) { m_contextSharingGroupPointer = contextSharingGroupPointer; - + m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); + selectModelImplementation(windowIndex, brain, viewportContent, @@ -258,6 +261,7 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; + m_textRenderer->setSharedOpenGLContextPointer(NULL); } /** @@ -290,7 +294,8 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, SurfaceProjectedItem& projectionOut) { m_contextSharingGroupPointer = contextSharingGroupPointer; - + m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); + projectToModelImplementation(windowIndex, brain, viewportContent, @@ -300,6 +305,7 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; + m_textRenderer->setSharedOpenGLContextPointer(NULL); } diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index c4d56eb1d..eab1e5b04 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -42,7 +42,6 @@ #include "AnnotationText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" -#include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLShapeRing.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrowserTabContent.h" @@ -1207,14 +1206,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil const bool depthTestFlag = isDrawnWithDepthTesting(box); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); - std::vector coords; - coords.insert(coords.end(), bottomLeft, bottomLeft + 3); - coords.insert(coords.end(), bottomRight, bottomRight + 3); - coords.insert(coords.end(), topRight, topRight + 3); - coords.insert(coords.end(), topLeft, topLeft + 3); - - std::vector dummyNormals; - uint8_t backgroundRGBA[4]; box->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; @@ -1345,14 +1336,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati const bool depthTestFlag = isDrawnWithDepthTesting(colorBar); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); - std::vector coords; - coords.insert(coords.end(), bottomLeft, bottomLeft + 3); - coords.insert(coords.end(), bottomRight, bottomRight + 3); - coords.insert(coords.end(), topRight, topRight + 3); - coords.insert(coords.end(), topLeft, topLeft + 3); - - std::vector dummyNormals; - float backgroundRGBA[4]; colorBar->getBackgroundColorRGBA(backgroundRGBA); float foregroundRGBA[4]; @@ -1363,9 +1346,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - selectionColorRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, bottomRight, topRight, topLeft, + selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, colorBar, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, @@ -1391,9 +1374,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati bgCoords.insert(bgCoords.end(), bgTopRight, bgTopRight + 3); bgCoords.insert(bgCoords.end(), bgTopLeft, bgTopLeft + 3); - BrainOpenGLPrimitiveDrawing::drawPolygon(bgCoords, - dummyNormals, - backgroundRGBA); + GraphicsShape::drawBoxFilledFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, + backgroundRGBA); } /* @@ -1555,29 +1538,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio const float xTopRight = (xBottomRight + (bottomToTopUnitVector[0] * tickMarksHeightInPixels)); const float yTopRight = (yBottomRight + (bottomToTopUnitVector[1] * tickMarksHeightInPixels)); - std::vector colorBarLines; - float rgba[4]; colorBar->getTextColorRGBA(rgba); const float z = 0.0; - + std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, + rgba)); /* * Horizontal line at top of tick marks */ const bool showHorizontalLineFlag = false; if (showHorizontalLineFlag) { - std::vector lineCoords; - lineCoords.push_back(xTopLeft); - lineCoords.push_back(yTopLeft); - lineCoords.push_back(z); - lineCoords.push_back(xTopRight); - lineCoords.push_back(yTopRight); - lineCoords.push_back(z); - - colorBarLines.push_back(ColorBarLine(lineCoords, - rgba)); + linesPrimitive->addVertex(xTopLeft, yTopLeft, z); + linesPrimitive->addVertex(xTopRight, yTopRight, z); } float leftToRightVector[3]; @@ -1601,16 +1575,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio const float tickBottomX = xBottomLeft + (dx * scalar); const float tickBottomY = yBottomLeft + (dy * scalar); - std::vector lineCoords; - lineCoords.push_back(tickTopX); - lineCoords.push_back(tickTopY); - lineCoords.push_back(z); - lineCoords.push_back(tickBottomX); - lineCoords.push_back(tickBottomY); - lineCoords.push_back(z); - - colorBarLines.push_back(ColorBarLine(lineCoords, - rgba)); + linesPrimitive->addVertex(tickTopX, tickTopY, z); + linesPrimitive->addVertex(tickBottomX, tickBottomY, z); } /* @@ -1618,14 +1584,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio */ glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); - for (std::vector::iterator iter = colorBarLines.begin(); - iter != colorBarLines.end(); - iter++) { - CaretAssert(iter->m_lineCoords.size() == 6); - BrainOpenGLPrimitiveDrawing::drawLines(iter->m_lineCoords, - iter->m_rgba, - tickThickness); - } + linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, tickThickness); + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } @@ -1654,13 +1615,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float topLeft[3], const float sectionsHeightInPixels) { - std::vector normals; - for (int32_t i = 0; i < 4; i++) { - normals.push_back(0.0); - normals.push_back(0.0); - normals.push_back(1.0); - } - std::vector colorBarLines; float bottomToTopUnitVector[3]; @@ -1693,6 +1647,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float z = 0.0; + std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 1.0f); + std::unique_ptr trianglesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); + const int32_t numSections = colorBar->getNumberOfSections(); for (int32_t iSect = 0; iSect < numSections; iSect++) { @@ -1714,16 +1672,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float tlY = yTopLeft + (dy * startNormalizedScalar); if (startScalar == endScalar) { - std::vector lineCoords; - lineCoords.push_back(blX); - lineCoords.push_back(blY); - lineCoords.push_back(z); - lineCoords.push_back(tlX); - lineCoords.push_back(tlY); - lineCoords.push_back(z); + const float* rgba = section->getStartRGBA(); + linesPrimitive->addVertex((float[]){ blX, blY, z}, rgba); + linesPrimitive->addVertex((float[]){ tlX, tlY, z}, rgba); - colorBarLines.push_back(ColorBarLine(lineCoords, - section->getStartRGBA())); } else { const float brX = xBottomLeft + (dx * endNormalizedScalar); @@ -1731,32 +1683,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float trX = xTopLeft + (dx * endNormalizedScalar); const float trY = yTopLeft + (dy * endNormalizedScalar); - - std::vector coords; - coords.push_back(blX); - coords.push_back(blY); - coords.push_back(z); - coords.push_back(brX); - coords.push_back(brY); - coords.push_back(z); - coords.push_back(trX); - coords.push_back(trY); - coords.push_back(z); - coords.push_back(tlX); - coords.push_back(tlY); - coords.push_back(z); - const float* rgbaLeft = section->getStartRGBA(); const float* rgbaRight = section->getEndRGBA(); - std::vector rgbaColors; - rgbaColors.insert(rgbaColors.end(), rgbaLeft, rgbaLeft + 4); - rgbaColors.insert(rgbaColors.end(), rgbaRight, rgbaRight + 4); - rgbaColors.insert(rgbaColors.end(), rgbaRight, rgbaRight + 4); - rgbaColors.insert(rgbaColors.end(), rgbaLeft, rgbaLeft + 4); - BrainOpenGLPrimitiveDrawing::drawQuads(coords, - normals, - rgbaColors); + trianglesPrimitive->addVertex(blX, blY, z, rgbaLeft); + trianglesPrimitive->addVertex(brX, brY, z, rgbaRight); + trianglesPrimitive->addVertex(tlX, tlY, z, rgbaLeft); + trianglesPrimitive->addVertex(tlX, tlY, z, rgbaLeft); + trianglesPrimitive->addVertex(brX, brY, z, rgbaRight); + trianglesPrimitive->addVertex(trX, trY, z, rgbaRight); if (printDebugFlag) { const AString msg("Section (" @@ -1785,16 +1720,16 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation * Lines need to be drawn OVER any quads (otherwise the quads * would obscure the lines */ + /* + * Lines need to be drawn OVER any quads (otherwise the quads + * would obscure the lines + */ + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + trianglesPrimitive.get()); glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); - for (std::vector::iterator iter = colorBarLines.begin(); - iter != colorBarLines.end(); - iter++) { - CaretAssert(iter->m_lineCoords.size() == 6); - BrainOpenGLPrimitiveDrawing::drawLines(iter->m_lineCoords, - iter->m_rgba, - 1.0); - } + GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } @@ -2267,14 +2202,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi annXYZ[0], annXYZ[1], annXYZ[2], m_modelSpaceViewport[2], m_modelSpaceViewport[3], bottomLeft, bottomRight, topRight, topLeft); - - std::vector coords; - coords.insert(coords.end(), bottomLeft, bottomLeft + 3); - coords.insert(coords.end(), bottomRight, bottomRight + 3); - coords.insert(coords.end(), topRight, topRight + 3); - coords.insert(coords.end(), topLeft, topLeft + 3); - - std::vector dummyNormals; const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, @@ -2302,9 +2229,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - selectionColorRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, bottomRight, topRight, topLeft, + selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, text, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, @@ -2340,10 +2267,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); } -// const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); -// BrainOpenGLPrimitiveDrawing::drawLines(connectLineCoordinates, -// textColorRGBA, -// lineWidth); } if (drawTextFlag) { @@ -2378,18 +2301,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi float tl[3]; getAnnotationTwoDimShapeBounds(text, annXYZ, bl, br, tr, tl); - std::vector boxCoords; - boxCoords.insert(boxCoords.end(), bl, bl + 3); - boxCoords.insert(boxCoords.end(), br, br + 3); - boxCoords.insert(boxCoords.end(), tr, tr + 3); - boxCoords.insert(boxCoords.end(), tl, tl + 3); - - if (boxCoords.size() == 12) { - const float lineWidthPixelsForDrawingNewTextAnnotation = 2.0f; - BrainOpenGLPrimitiveDrawing::drawLineLoop(boxCoords, - foregroundRGBA, - lineWidthPixelsForDrawingNewTextAnnotation); - } + GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bl, br, tr, tl, + foregroundRGBA, + GraphicsPrimitive::SizeType::PIXELS, + 2.0f); } else { m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(annXYZ[0], @@ -2499,14 +2415,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF return false; } - std::vector coords; - coords.insert(coords.end(), bottomLeft, bottomLeft + 3); - coords.insert(coords.end(), bottomRight, bottomRight + 3); - coords.insert(coords.end(), topRight, topRight + 3); - coords.insert(coords.end(), topLeft, topLeft + 3); - - std::vector dummyNormals; - const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, @@ -2528,9 +2436,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - selectionColorRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, bottomRight, topRight, topLeft, + selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, image, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, @@ -2572,10 +2480,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (image->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(image); } - const float lineWidth = getLineWidthFromPercentageHeight(image->getLineWidthPercentage()); - BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - foregroundRGBA, - lineWidth); + GraphicsShape::drawBoxOutlineFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, bottomRight, topRight, topLeft, + foregroundRGBA, + GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, image->getLineWidthPercentage()); } setDepthTestingStatus(depthTestFlag); @@ -2888,22 +2796,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi glRotatef(-rotationAngle, 0.0, 0.0, 1.0); } - std::vector coords; - coords.push_back(-halfWidthHeight); - coords.push_back(-halfWidthHeight); - coords.push_back(0.0); - coords.push_back( halfWidthHeight); - coords.push_back(-halfWidthHeight); - coords.push_back(0.0); - coords.push_back( halfWidthHeight); - coords.push_back( halfWidthHeight); - coords.push_back(0.0); - coords.push_back(-halfWidthHeight); - coords.push_back( halfWidthHeight); - coords.push_back(0.0); - - std::vector dummyNormals; - + const float bottomLeft[3] = { -halfWidthHeight, -halfWidthHeight, 0.0f }; + const float bottomRight[3] = { halfWidthHeight, -halfWidthHeight, 0.0f }; + const float topRight[3] = { halfWidthHeight, halfWidthHeight, 0.0f }; + const float topLeft[3] = { -halfWidthHeight, halfWidthHeight, 0.0f }; + bool drawFilledCircleFlag = false; bool drawOutlineCircleFlag = false; bool drawSquareFlag = false; @@ -2949,9 +2846,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi if (m_selectionModeFlag) { uint8_t identificationRGBA[4]; getIdentificationColor(identificationRGBA); - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - identificationRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + identificationRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, annotation, handleType, @@ -2959,13 +2859,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi } else { if (drawFilledCircleFlag) { - m_brainOpenGLFixedPipeline->drawCircleFilled(m_selectionBoxRGBA, - halfWidthHeight); + GraphicsShape::drawCircleFilled(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + NULL, + m_selectionBoxRGBA, + halfWidthHeight); } else if (drawSquareFlag) { - BrainOpenGLPrimitiveDrawing::drawPolygon(coords, - dummyNormals, - m_selectionBoxRGBA); + GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + bottomLeft, + bottomRight, + topRight, + topLeft, + m_selectionBoxRGBA); } else if (drawOutlineCircleFlag) { const float diameter = halfWidthHeight; @@ -3168,15 +3073,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, innerSpacing, innerSpacing); if (! m_selectionModeFlag) { - std::vector coords; - coords.insert(coords.end(), handleBottomLeft, handleBottomLeft + 3); - coords.insert(coords.end(), handleBottomRight, handleBottomRight + 3); - coords.insert(coords.end(), handleTopRight, handleTopRight + 3); - coords.insert(coords.end(), handleTopLeft, handleTopLeft + 3); - - BrainOpenGLPrimitiveDrawing::drawLineLoop(coords, - m_selectionBoxRGBA, - 2.0); + GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, + m_selectionBoxRGBA, GraphicsPrimitive::SizeType::PIXELS, 2.0f); } const float handleLeft[3] = { @@ -3321,9 +3220,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann std::vector coords; coords.insert(coords.end(), handleRotationLineEnd, handleRotationLineEnd + 3); coords.insert(coords.end(), handleOffset, handleOffset + 3); - BrainOpenGLPrimitiveDrawing::drawLines(coords, - m_selectionBoxRGBA, - 2.0); + GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), + coords, m_selectionBoxRGBA, + GraphicsPrimitive::SizeType::PIXELS, 2.0f); drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, annotation, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 7714855a8..cd74f0b6d 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -51,7 +51,6 @@ #include "BrainOpenGLShapeCube.h" #include "BrainOpenGLShapeCylinder.h" #include "BrainOpenGLShapeRing.h" -#include "BrainOpenGLShapeRingOutline.h" #include "BrainOpenGLShapeSphere.h" #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" @@ -175,8 +174,6 @@ BrainOpenGLFixedPipeline::BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterfac m_shapeCylinder = NULL; m_shapeCube = NULL; m_shapeCubeRounded = NULL; - m_shapeCircleOutline = NULL; - m_shapeCircleFilled = NULL; this->surfaceNodeColoring = new SurfaceNodeColoring(); m_brain = NULL; m_clippingPlaneGroup = NULL; @@ -211,27 +208,11 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() delete m_shapeCubeRounded; m_shapeCubeRounded = NULL; } - if (m_shapeCircleFilled != NULL) { - delete m_shapeCircleFilled; - m_shapeCircleFilled = NULL; - } - if (m_shapeCircleOutline != NULL) { - delete m_shapeCircleOutline; - m_shapeCircleOutline = NULL; - } if (this->surfaceNodeColoring != NULL) { delete this->surfaceNodeColoring; this->surfaceNodeColoring = NULL; } - for (std::map::iterator iter = m_shapeEllipseOutlines.begin(); - iter != m_shapeEllipseOutlines.end(); - iter++) { - BrainOpenGLShapeRingOutline* shape = iter->second; - delete shape; - } - m_shapeEllipseOutlines.clear(); - delete this->colorIdentification; this->colorIdentification = NULL; @@ -1566,16 +1547,6 @@ BrainOpenGLFixedPipeline::initializeOpenGL() m_shapeCubeRounded = new BrainOpenGLShapeCube(1.0, BrainOpenGLShapeCube::ROUNDED); } - if (m_shapeCircleOutline == NULL) { - m_shapeCircleOutline = new BrainOpenGLShapeRing(20, - 0.9, - 1.0); - } - if (m_shapeCircleFilled == NULL) { - m_shapeCircleFilled = new BrainOpenGLShapeRing(20, - 0.0, - 1.0); - } if (this->initializedOpenGLFlag) { return; @@ -5948,42 +5919,6 @@ BrainOpenGLFixedPipeline::drawRoundedCube(const float rgba[4], glPopMatrix(); } -/** - * Draw an outline circle. - * - * @param rgba - * Color for drawing. - * @param diameter - * Diameter of the circle. - */ -void -BrainOpenGLFixedPipeline::drawCircleOutline(const uint8_t rgba[4], - const double diameter) -{ - glPushMatrix(); - glScaled(diameter, diameter, 1.0); - m_shapeCircleOutline->draw(rgba); - glPopMatrix(); -} - -/** - * Draw a filled circle. - * - * @param rgba - * Color for drawing. - * @param diameter - * Diameter of the circle. - */ -void -BrainOpenGLFixedPipeline::drawCircleFilled(const uint8_t rgba[4], - const double diameter) -{ - glPushMatrix(); - glScaled(diameter, diameter, 1.0); - m_shapeCircleFilled->draw(rgba); - glPopMatrix(); -} - /** * Draw a cuboid (3D Box) * diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 49d10a390..65a2777e9 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -51,7 +51,6 @@ namespace caret { class BrainOpenGLShapeCube; class BrainOpenGLShapeCylinder; class BrainOpenGLShapeRing; - class BrainOpenGLShapeRingOutline; class BrainOpenGLShapeSphere; class BrainOpenGLViewportContent; class BrowserTabContent; @@ -387,12 +386,6 @@ namespace caret { void drawSurfaceAxes(); - void drawCircleOutline(const uint8_t rgba[4], - const double diameter); - - void drawCircleFilled(const uint8_t rgba[4], - const double diameter); - void drawSphereWithDiameter(const uint8_t rgba[4], const double diameter); @@ -578,15 +571,6 @@ namespace caret { /** Cube symbol */ BrainOpenGLShapeCube* m_shapeCube; - /** Outline circle symbol */ - BrainOpenGLShapeRing* m_shapeCircleOutline; - - /** Outline ellipse symbol. KEY is line thickness */ - std::map m_shapeEllipseOutlines; - - /** Filled circle symbol */ - BrainOpenGLShapeRing* m_shapeCircleFilled; - /** Rounded Cube symbol */ BrainOpenGLShapeCube* m_shapeCubeRounded; diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx index 6c4248e3b..bc1bc1936 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.cxx +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.cxx @@ -170,12 +170,6 @@ BrainOpenGLPrimitiveDrawing::drawQuads(const std::vector& coordinates, rgbaColors, coordinateOffset, coordinateToDrawCount); - -// drawQuadsImmediateMode(coordinates, -// normals, -// rgbaColors, -// coordinateOffset, -// coordinateToDrawCount); } coordinateOffset += maximumCoordinatesToDraw; } @@ -185,84 +179,6 @@ BrainOpenGLPrimitiveDrawing::drawQuads(const std::vector& coordinates, } } -/** - * Draw quads using immediate mode. - * - * @param coordinates - * Coordinates of the quads. - * @param normals - * Normal vectors for the quads. - * @param rgbaColors - * RGBA colors for the quads. - */ -void -BrainOpenGLPrimitiveDrawing::drawQuadsImmediateMode(const std::vector& coordinates, - const std::vector& normals, - const std::vector& rgbaColors, - const int64_t coordinateOffset, - const int64_t coordinateCount) -{ -// const uint64_t numCoords = coordinates.size() / 3; -// const uint64_t numQuads = numCoords / 4; // 4 three-d coords per quad - - const float* coordPtr = &coordinates[0]; - const float* normalPtr = &normals[0]; - const uint8_t* colorPtr = &rgbaColors[0]; - - CaretAssertVectorIndex(coordinates, ((coordinateOffset * 3) - + (coordinateCount * 3) - 1)); - CaretAssertVectorIndex(normals, ((coordinateOffset * 3) - + (coordinateCount * 3) - 1)); - CaretAssertVectorIndex(rgbaColors, ((coordinateOffset * 4) - + (coordinateCount * 4) - 1)); - - glBegin(GL_QUADS); - uint64_t iColor = coordinateOffset * 4; - uint64_t iNormal = coordinateOffset * 3; - uint64_t iCoord = coordinateOffset * 3; - for (int64_t i = 0; i < coordinateCount; i++) { - glNormal3fv(&normalPtr[iNormal]); - iNormal += 3; - glColor4ubv(&colorPtr[iColor]); - iColor += 4; - glVertex3fv(&coordPtr[iCoord]); - iCoord += 3; - } - - glEnd(); -// for (uint64_t i = 0; i < numQuads; i++) { -// glNormal3fv(&normalPtr[iNormal]); -// iNormal += 3; -// glColor4ubv(&colorPtr[iColor]); -// iColor += 4; -// glVertex3fv(&coordPtr[iCoord]); -// iCoord += 3; -// -// glNormal3fv(&normalPtr[iNormal]); -// iNormal += 3; -// glColor4ubv(&colorPtr[iColor]); -// iColor += 4; -// glVertex3fv(&coordPtr[iCoord]); -// iCoord += 3; -// -// glNormal3fv(&normalPtr[iNormal]); -// iNormal += 3; -// glColor4ubv(&colorPtr[iColor]); -// iColor += 4; -// glVertex3fv(&coordPtr[iCoord]); -// iCoord += 3; -// -// glNormal3fv(&normalPtr[iNormal]); -// iNormal += 3; -// glColor4ubv(&colorPtr[iColor]); -// iColor += 4; -// glVertex3fv(&coordPtr[iCoord]); -// iCoord += 3; -// } -// glEnd(); - -} - /** * Draw quads using vertex arrays. * @@ -616,712 +532,3 @@ BrainOpenGLPrimitiveDrawing::drawQuadIndicesVertexArrays(const std::vector& coordinates, - const float rgba[4], - const float lineWidth) -{ - const uint8_t rgbaByte[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINE_LOOP, - coordinates, - emptyNormals, - rgbaByte, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * One RGBA colors (4 elements) ranging [0, 255] that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLineLoop(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth) -{ - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINE_LOOP, - coordinates, - emptyNormals, - rgba, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * One RGBA colors (4 elements) ranging [0.0, 1.0] that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, - const float rgba[4], - const float lineWidth) -{ - const uint8_t rgbaByte[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINES, - coordinates, - emptyNormals, - rgbaByte, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * One RGBA colors (4 elements) ranging [0, 255] that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth) -{ - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINES, - coordinates, - emptyNormals, - rgba, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * RGBA Colors [0.0, 1.0] for each vertex. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth) -{ - std::vector emptyNormals; - - std::vector rgbaBytes; - rgbaBytes.reserve(rgbaColors.size()); - for (const float component : rgbaColors) { - rgbaBytes.push_back(static_cast(component * 255.0)); - } - - drawPrimitiveWithVertexArrays(GL_LINES, - coordinates, - emptyNormals, - rgbaBytes, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * RGBA Colors [0, 255] for each vertex. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLines(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth) -{ - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINES, - coordinates, - emptyNormals, - rgbaColors, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * RGBA Colors [0.0, 1.0] for each vertex. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth) -{ - std::vector emptyNormals; - - std::vector rgbaBytes; - rgbaBytes.reserve(rgbaColors.size()); - for (const float component : rgbaColors) { - rgbaBytes.push_back(static_cast(component * 255.0)); - } - - drawPrimitiveWithVertexArrays(GL_LINE_STRIP, - coordinates, - emptyNormals, - rgbaBytes, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * RGBA Colors [0, 255] for each vertex. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth) -{ - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINE_STRIP, - coordinates, - emptyNormals, - rgbaColors, - lineWidth); -} - -/** - * Draw a line strip with the given coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * One RGBA colors (4 elements) ranging [0.0, 1.0] that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, - const float rgba[4], - const float lineWidth) -{ - const uint8_t rgbaByte[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINE_STRIP, - coordinates, - emptyNormals, - rgbaByte, - lineWidth); -} - -/** - * Draw a line strip with the given coordinates in the given color - * with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param rgba - * One RGBA colors (4 elements) ranging [0, 255] that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawLineStrip(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth) -{ - std::vector emptyNormals; - drawPrimitiveWithVertexArrays(GL_LINE_STRIP, - coordinates, - emptyNormals, - rgba, - lineWidth); -} - -/** - * Draw a polygon with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param normals - * Normal vectors. There number of elements must match the numer of - * coordinates (in which case normal vectors are applied) or empty - * (in which case normal vectors are not applied). - * @param rgba - * One RGBA colors (4 elements) ranging [0.0, 1.0] that is used for drawing all of the lines. - */ -void -BrainOpenGLPrimitiveDrawing::drawPolygon(const std::vector& coordinates, - const std::vector& normals, - const float rgba[4]) -{ - const uint8_t rgbaByte[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - const float lineWidth = 1.0; - drawPrimitiveWithVertexArrays(GL_POLYGON, - coordinates, - normals, - rgbaByte, - lineWidth); -} - -/** - * Draw a polygon with optional normal vectors. - * - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param normals - * Normal vectors. There number of elements must match the numer of - * coordinates (in which case normal vectors are applied) or empty - * (in which case normal vectors are not applied). - * @param rgba - * One RGBA colors (4 elements) ranging [0.0, 1.0] that is used for drawing all of the lines. - */ -void -BrainOpenGLPrimitiveDrawing::drawPolygon(const std::vector& coordinates, - const std::vector& normals, - const uint8_t rgba[4]) -{ - const float lineWidth = 1.0; - drawPrimitiveWithVertexArrays(GL_POLYGON, - coordinates, - normals, - rgba, - lineWidth); -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given color - * with optional normal vectors using the given OpenGL mode. - * - * @param mode - * The OpenGL drawing mode. - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param normals - * Normal vectors. There number of elements must match the numer of - * coordinates (in which case normal vectors are applied) or empty - * (in which case normal vectors are not applied). - * @param rgba - * One RGBA color (size=4) that is used for drawing all of the lines. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, - const std::vector& coordinates, - const std::vector& normals, - const uint8_t rgba[4], - const float lineWidth) -{ - const int64_t numCoords = static_cast(coordinates.size() / 3); - if (numCoords < 1) { - CaretLogWarning("Invalid number of coordinates=" + QString::number(numCoords)); - return; - } - - std::vector rgbaVector; - rgbaVector.reserve(numCoords * 4); - for (int32_t i = 0; i < numCoords; i++) { - rgbaVector.push_back(rgba[0]); - rgbaVector.push_back(rgba[1]); - rgbaVector.push_back(rgba[2]); - rgbaVector.push_back(rgba[3]); - } - - CaretAssert(numCoords == (rgbaVector.size() / 4)); - - const int64_t numNormals = static_cast(normals.size() / 3); - if (numNormals > 0) { - if (numCoords != numNormals) { - const AString msg("Number of coordinates " - + QString::number(numCoords) - + " does not equal number of normals=" - + QString::number(numNormals)); - CaretAssertMessage(0, msg); - CaretLogWarning(msg); - return; - } - } - - - if ((mode == GL_LINES) - || (mode == GL_LINE_LOOP) - || (mode == GL_LINE_STRIP)) { - glLineWidth(lineWidth); - } - - glVertexPointer(3, - GL_FLOAT, - 0, - reinterpret_cast(&coordinates[0])); - glColorPointer(4, - GL_UNSIGNED_BYTE, - 0, - reinterpret_cast(&rgbaVector[0])); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - if (numNormals > 0) { - glNormalPointer(GL_FLOAT, - 0, - reinterpret_cast(&normals[0])); - glEnableClientState(GL_NORMAL_ARRAY); - } - - glDrawArrays(mode, 0, numCoords); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - if (numNormals > 0) { - glDisableClientState(GL_NORMAL_ARRAY); - } -} - -/** - * Draw a line between each pair of three-dimensional coordinates in the given colors - * per vertex with optional normal vectors using the given OpenGL mode. - * - * @param mode - * The OpenGL drawing mode. - * @param coordinates - * Three-Dimensional coordinates (XYZ). - * @param normals - * Normal vectors. There number of elements must match the numer of - * coordinates (in which case normal vectors are applied) or empty - * (in which case normal vectors are not applied). - * @param rgba - * 4 components per vertex.. - * @param lineWidth - * Line width used by line drawing modes. - */ -void -BrainOpenGLPrimitiveDrawing::drawPrimitiveWithVertexArrays(GLenum mode, - const std::vector& coordinates, - const std::vector& normals, - const std::vector& rgbaColors, - const float lineWidth) -{ - const int64_t numCoords = static_cast(coordinates.size() / 3); - if (numCoords < 1) { - CaretLogWarning("Invalid number of coordinates=" + QString::number(numCoords)); - return; - } - -// std::vector rgbaVector; -// rgbaVector.reserve(numCoords * 4); -// for (int32_t i = 0; i < numCoords; i++) { -// rgbaVector.push_back(rgba[0]); -// rgbaVector.push_back(rgba[1]); -// rgbaVector.push_back(rgba[2]); -// rgbaVector.push_back(rgba[3]); -// } - - CaretAssert(numCoords == (rgbaColors.size() / 4)); - - const int64_t numNormals = static_cast(normals.size() / 3); - if (numNormals > 0) { - if (numCoords != numNormals) { - const AString msg("Number of coordinates " - + QString::number(numCoords) - + " does not equal number of normals=" - + QString::number(numNormals)); - CaretAssertMessage(0, msg); - CaretLogWarning(msg); - return; - } - } - - - if ((mode == GL_LINES) - || (mode == GL_LINE_LOOP) - || (mode == GL_LINE_STRIP)) { - glLineWidth(lineWidth); - } - - glVertexPointer(3, - GL_FLOAT, - 0, - reinterpret_cast(&coordinates[0])); - glColorPointer(4, - GL_UNSIGNED_BYTE, - 0, - reinterpret_cast(&rgbaColors[0])); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - if (numNormals > 0) { - glNormalPointer(GL_FLOAT, - 0, - reinterpret_cast(&normals[0])); - glEnableClientState(GL_NORMAL_ARRAY); - } - - glDrawArrays(mode, 0, numCoords); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - if (numNormals > 0) { - glDisableClientState(GL_NORMAL_ARRAY); - } -} - -static void -createRectangle(const float center[3], - const float leftToRightUnitVector[3], - const float bottomToTopUnitVector[3], - const float width, - const float height, - float bottomLeftOut[3], - float bottomRightOut[3], - float topRightOut[3], - float topLeftOut[3]) { - - const float halfWidth = width / 2.0; - const float halfHeight = height / 2.0; - - for (int32_t i = 0; i < 3; i++) { - bottomLeftOut[i] = (center[i] - - (bottomToTopUnitVector[i] * halfHeight) - - (leftToRightUnitVector[i] * halfWidth)); - bottomRightOut[i] = (center[i] - - (bottomToTopUnitVector[i] * halfHeight) - + (leftToRightUnitVector[i] * halfWidth)); - topRightOut[i] = (center[i] - + (bottomToTopUnitVector[i] * halfHeight) - + (leftToRightUnitVector[i] * halfWidth)); - topLeftOut[i] = (center[i] - + (bottomToTopUnitVector[i] * halfHeight) - - (leftToRightUnitVector[i] * halfWidth)); - } -} - -/** - * Draw a outlined rectangle. - * - * @param bottomLeft - * Bottom left corner. - * @param bottomRight - * Bottom right corner. - * @param topRight - * Top right corner. - * @param topLeft - * Top left corner. - * @param lineThickness - * Thickness of outline. - * @param rgba - * RGBA colors (4 elements) ranging [0.0, 1.0] that is used for drawing all of the lines. - */ -void -BrainOpenGLPrimitiveDrawing::drawRectangleOutline(const float bottomLeft[3], - const float bottomRight[3], - const float topRight[3], - const float topLeft[3], - const float lineThickness, - const float rgba[4]) -{ - float leftToRightUnitVector[3]; - MathFunctions::createUnitVector(bottomLeft, bottomRight, leftToRightUnitVector); - const float width = MathFunctions::distance3D(bottomLeft, bottomRight); - - float bottomToTopUnitVector[3]; - MathFunctions::createUnitVector(bottomLeft, topLeft, bottomToTopUnitVector); - const float height = MathFunctions::distance3D(bottomLeft, topLeft); - - const float center[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f - }; - - float normalVector[3]; - MathFunctions::normalVector(topLeft, bottomLeft, bottomRight, normalVector); - - const float halfThickness = std::min(lineThickness / 2.0f, - std::min(width / 2.0f, - height / 2.0f)); - - std::vector coords; - coords.reserve(8*3); - - { - float bli[3]; - float bri[3]; - float tri[3]; - float tli[3]; - createRectangle(center, - leftToRightUnitVector, bottomToTopUnitVector, - width - halfThickness*2, height - halfThickness*2, - bli, bri, tri, tli); - - coords.insert(coords.end(), - bli, bli + 3); - coords.insert(coords.end(), - bri, bri + 3); - coords.insert(coords.end(), - tri, tri + 3); - coords.insert(coords.end(), - tli, tli + 3); - - - -// std::vector innerRectCoords; -// innerRectCoords.insert(innerRectCoords.end(), -// bli, bli + 3); -// innerRectCoords.insert(innerRectCoords.end(), -// bri, bri + 3); -// innerRectCoords.insert(innerRectCoords.end(), -// tri, tri + 3); -// innerRectCoords.insert(innerRectCoords.end(), -// tli, tli + 3); -// drawLineLoop(innerRectCoords, rgba, 1); - } - - { - float blo[3]; - float bro[3]; - float tro[3]; - float tlo[3]; - createRectangle(center, - leftToRightUnitVector, bottomToTopUnitVector, - width + halfThickness*2, height + halfThickness*2, - blo, bro, tro, tlo); - - coords.insert(coords.end(), - blo, blo + 3); - coords.insert(coords.end(), - bro, bro + 3); - coords.insert(coords.end(), - tro, tro + 3); - coords.insert(coords.end(), - tlo, tlo + 3); -// std::vector outerRectCoords; -// outerRectCoords.insert(outerRectCoords.end(), -// blo, blo + 3); -// outerRectCoords.insert(outerRectCoords.end(), -// bro, bro + 3); -// outerRectCoords.insert(outerRectCoords.end(), -// tro, tro + 3); -// outerRectCoords.insert(outerRectCoords.end(), -// tlo, tlo + 3); -// drawLineLoop(outerRectCoords, rgba, 1); - } - - const int32_t numCoords = static_cast(coords.size() / 3); - - std::vector normals; - normals.reserve(numCoords*3); - std::vector rgbaBytes; - rgbaBytes.reserve(numCoords*4); - - const uint8_t colorBytes[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - for (int32_t i = 0; i < numCoords; i++) { - normals.insert(normals.end(), - normalVector, normalVector + 3); - rgbaBytes.insert(rgbaBytes.end(), - colorBytes, colorBytes + 4); - } - - CaretAssert(coords.size() == normals.size()); - CaretAssert(coords.size() == ((rgbaBytes.size() / 4) * 3)); - - std::vector indices; - indices.push_back(0); - indices.push_back(4); - indices.push_back(1); - indices.push_back(5); - indices.push_back(2); - indices.push_back(6); - indices.push_back(3); - indices.push_back(7); - indices.push_back(0); - indices.push_back(4); - - const bool enableAntiAliasingFlag = false; - if (enableAntiAliasingFlag) { - glPushAttrib(GL_COLOR_BUFFER_BIT - | GL_HINT_BIT - | GL_POLYGON_BIT); - - glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - glHint(GL_POLYGON_SMOOTH_HINT, - GL_NICEST); - glEnable(GL_POLYGON_SMOOTH); - } - - drawQuadStrips(coords, - normals, - rgbaBytes, - indices); - - if (enableAntiAliasingFlag) { - glPopAttrib(); - } -} diff --git a/src/Brain/BrainOpenGLPrimitiveDrawing.h b/src/Brain/BrainOpenGLPrimitiveDrawing.h index a75a7c1cf..68b57d29f 100644 --- a/src/Brain/BrainOpenGLPrimitiveDrawing.h +++ b/src/Brain/BrainOpenGLPrimitiveDrawing.h @@ -50,67 +50,6 @@ namespace caret { const std::vector& rgbaColors, const std::vector& quadStripIndices); - static void drawLineLoop(const std::vector& coordinates, - const float rgba[4], - const float lineWidth); - - static void drawLineLoop(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth); - - static void drawLines(const std::vector& coordinates, - const float rgba[4], - const float lineWidth); - - static void drawLines(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth); - - static void drawLines(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth); - - static void drawLines(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth); - - static void drawLineStrip(const std::vector& coordinates, - const float rgba[4], - const float lineWidth); - - static void drawLineStrip(const std::vector& coordinates, - const uint8_t rgba[4], - const float lineWidth); - - static void drawLineStrip(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth); - - static void drawLineStrip(const std::vector& coordinates, - const std::vector& rgbaColors, - const float lineWidth); - - static void drawPolygon(const std::vector& coordinates, - const std::vector& normals, - const float rgba[4]); - - static void drawPolygon(const std::vector& coordinates, - const std::vector& normals, - const uint8_t rgba[4]); - - static void drawRectangleOutline(const float bottomLeft[3], - const float bottomRight[3], - const float topRight[3], - const float topLeft[3], - const float lineThickness, - const float rgba[4]); - -// static void drawRectangle(const float bottomLeft[3], -// const float bottomRight[3], -// const float topRight[3], -// const float topLeft[3], -// const float rgba[4]); - private: BrainOpenGLPrimitiveDrawing(); @@ -147,18 +86,6 @@ namespace caret { const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadIndices); - - static void drawPrimitiveWithVertexArrays(GLenum mode, - const std::vector& coordinates, - const std::vector& normals, - const uint8_t rgba[4], - const float lineWidth); - - static void drawPrimitiveWithVertexArrays(GLenum mode, - const std::vector& coordinates, - const std::vector& normals, - const std::vector& rgba, - const float lineWidth); }; #ifdef __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ diff --git a/src/Brain/BrainOpenGLShapeRingOutline.cxx b/src/Brain/BrainOpenGLShapeRingOutline.cxx deleted file mode 100644 index 0c0470579..000000000 --- a/src/Brain/BrainOpenGLShapeRingOutline.cxx +++ /dev/null @@ -1,377 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#define __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_DECLARE__ -#include "BrainOpenGLShapeRingOutline.h" -#undef __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_DECLARE__ - -#include "CaretAssert.h" -#include "MathFunctions.h" - -using namespace caret; - - - -/** - * \class caret::BrainOpenGLShapeRingOutline - * \brief Create a ring shape drawn with a line for use with OpenGL. - */ - -/** - * Constructor. - * @param numberOfSides - * Number of sides in the ring. - */ -BrainOpenGLShapeRingOutline::BrainOpenGLShapeRingOutline(const int32_t numberOfSides, - const float radius, - const float lineThickness) -: BrainOpenGLShape(), -m_numberOfSides(numberOfSides), -m_radius(radius), -m_lineThickness(lineThickness) -{ - m_isApplyColoring = true; - - bool debugFlag = false; - - /* - * Setup step size based upon number of points around circle - */ - // const int32_t numberOfPoints = 8; - const float step = (2.0 * M_PI) / m_numberOfSides; - - /* - * Generate points around ring - */ - const float z = 0.0; - for (int32_t i = 0; i < m_numberOfSides; i++) { - const float t = step * i; - - // const float x = majorRadius * std::cos(t); - // const float y = minorRadius * std::sin(t); - const float x = m_radius * std::cos(t); - const float y = m_radius * std::sin(t); - - m_lineLoop.push_back(m_coordinates.size() / 3); - - m_coordinates.push_back(x); - m_coordinates.push_back(y); - m_coordinates.push_back(z); - - m_normals.push_back(0.0); - m_normals.push_back(0.0); - m_normals.push_back(1.0); - } - - if (debugFlag) { - CaretAssert(m_coordinates.size() == m_normals.size()); - const int32_t numPoints = static_cast(m_coordinates.size() / 3); - for (int32_t i = 0; i < numPoints; i++) { - const int32_t i3 = i * 3; - std::cout << "points[" << i << "]=(" << AString::fromNumbers(&m_coordinates[i3], 3, ",") - << ")" << std::endl; - std::cout << "side normal[" << i << "]=(" << AString::fromNumbers(&m_normals[i3], 3, ",") - << ")" << std::endl; - } - - //std::cout << "Sides: "; - //printTriangleStrip(m_triangleStrip); - //std::cout << std::endl; - } - - /* - * Create storage for colors - */ - const int64_t numCoords = static_cast(m_coordinates.size()) / 3; - const int64_t numRGBA = numCoords * 4; - m_rgbaByte.resize(numRGBA * 4, 0); - for (GLuint i = 0; i < numCoords; i++) { - const int32_t i4 = i * 4; - - CaretAssertVectorIndex(m_rgbaByte, i4+3); - m_rgbaByte[i4] = 0; - m_rgbaByte[i4+1] = 0; - m_rgbaByte[i4+2] = 0; - m_rgbaByte[i4+3] = 255; - } -} - -/** - * Destructor. - */ -BrainOpenGLShapeRingOutline::~BrainOpenGLShapeRingOutline() -{ - -} - -void -BrainOpenGLShapeRingOutline::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) -{ - m_displayList = 0; - - m_coordinatesBufferID = 0; - m_coordinatesRgbaByteBufferID = 0; - m_normalBufferID = 0; - m_lineLoopBufferID = 0; - switch (drawMode) { - case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: - { - m_displayList = createDisplayList(); - - if (m_displayList > 0) { - glNewList(m_displayList, - GL_COMPILE); - uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; - m_isApplyColoring = false; - drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, - rgbaUnused); - m_isApplyColoring = true; - glEndList(); - } - } - break; - case BrainOpenGL::DRAW_MODE_IMMEDIATE: - { - /* nothing to do for this case */ - } - break; - case BrainOpenGL::DRAW_MODE_INVALID: - { - CaretAssert(0); - } - break; - case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: -#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS - /* - * Put coordinates into its buffer. - */ - m_coordinatesBufferID = createBufferID(); - glBindBuffer(GL_ARRAY_BUFFER, - m_coordinatesBufferID); - glBufferData(GL_ARRAY_BUFFER, - m_coordinates.size() * sizeof(GLfloat), - &m_coordinates[0], - GL_STATIC_DRAW); - - /* - * For RGBA coloring - */ - m_coordinatesRgbaByteBufferID = createBufferID(); - glBindBuffer(GL_ARRAY_BUFFER, - m_coordinatesRgbaByteBufferID); - glBufferData(GL_ARRAY_BUFFER, - m_rgbaByte.size() * sizeof(GLubyte), - &m_rgbaByte[0], - GL_DYNAMIC_DRAW); - - /* - * Put side normals into its buffer. - */ - m_normalBufferID = createBufferID(); - glBindBuffer(GL_ARRAY_BUFFER, - m_normalBufferID); - glBufferData(GL_ARRAY_BUFFER, - m_normals.size() * sizeof(GLfloat), - &m_normals[0], - GL_STATIC_DRAW); - - /* - * Put line loop into its buffer. - */ - m_lineLoopBufferID = createBufferID(); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - m_lineLoopBufferID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - m_lineLoop.size() * sizeof(GLuint), - &m_lineLoop[0], - GL_STATIC_DRAW); - - /* - * Deselect active buffer. - */ - glBindBuffer(GL_ARRAY_BUFFER, - 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - 0); -#endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS - break; - } -} - -/** - * Draw the shape. - * - * @param drawMode - * How to draw the shape. - * @param rgba - * RGBA coloring ranging 0.0 to 1.0 - */ -void -BrainOpenGLShapeRingOutline::drawShape(const BrainOpenGL::DrawMode drawMode, - const float rgba[4]) -{ - const uint8_t rgbaByte[4] = { - static_cast(rgba[0] * 255.0), - static_cast(rgba[1] * 255.0), - static_cast(rgba[2] * 255.0), - static_cast(rgba[3] * 255.0) - }; - - drawShape(drawMode, - rgbaByte); -} - -/** - * Draw the shape. - * - * @param drawMode - * How to draw the shape. - * @param rgba - * RGBA coloring ranging 0 to 255. - */ -void -BrainOpenGLShapeRingOutline::drawShape(const BrainOpenGL::DrawMode drawMode, - const uint8_t rgba[4]) -{ - switch (drawMode) { - case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: - { - if (m_displayList > 0) { - if (m_isApplyColoring) { - glColor4ubv(rgba); - } - glCallList(m_displayList); - } - } - break; - case BrainOpenGL::DRAW_MODE_IMMEDIATE: - { - glLineWidth(m_lineThickness); - if (m_isApplyColoring) { - glColor4ubv(rgba); - } - const int32_t numVertices = static_cast(m_lineLoop.size()); - glBegin(GL_LINE_LOOP); - for (int32_t j = 0; j < numVertices; j++) { - const int32_t vertexIndex = m_lineLoop[j] * 3; - - CaretAssertVectorIndex(m_normals, vertexIndex); - CaretAssertVectorIndex(m_coordinates, vertexIndex); - - glNormal3fv(&m_normals[vertexIndex]); - glVertex3fv(&m_coordinates[vertexIndex]); - } - glEnd(); - } - break; - case BrainOpenGL::DRAW_MODE_INVALID: - { - CaretAssert(0); - } - break; - case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: -#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS - /* - * Enable vertices and normals for buffers - */ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - /* - * Set the vertices for drawing. - */ - glBindBuffer(GL_ARRAY_BUFFER, - m_coordinatesBufferID); - glVertexPointer(3, - GL_FLOAT, - 0, - (GLvoid*)0); - - /* - * Put BYTE colors into its buffer - */ - const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; - for (int64_t ir = 0; ir < numRGBA; ir++) { - const int64_t ir4 = ir * 4; - CaretAssertVectorIndex(m_rgbaByte, ir4+3); - m_rgbaByte[ir4] = rgba[0]; - m_rgbaByte[ir4+1] = rgba[1]; - m_rgbaByte[ir4+2] = rgba[2]; - m_rgbaByte[ir4+3] = rgba[3]; - } - CaretAssert(glIsBuffer(m_coordinatesRgbaByteBufferID) == GL_TRUE); - glBindBuffer(GL_ARRAY_BUFFER, - m_coordinatesRgbaByteBufferID); - glBufferData(GL_ARRAY_BUFFER, - m_rgbaByte.size() * sizeof(GLubyte), - &m_rgbaByte[0], - GL_DYNAMIC_DRAW); - glColorPointer(4, - GL_UNSIGNED_BYTE, - 0, - (GLvoid*)0); - - /* - * Set the side normal vectors for drawing. - */ - glBindBuffer(GL_ARRAY_BUFFER, - m_normalBufferID); - glNormalPointer(GL_FLOAT, - 0, - (GLvoid*)0); - - /* - * Apply the line width - */ - glLineWidth(m_lineThickness); - - /* - * Draw the side triangle fans. - */ - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - m_lineLoopBufferID); - glDrawElements(GL_LINE_LOOP, - m_lineLoop.size(), - GL_UNSIGNED_INT, - (GLvoid*)0); - /* - * Deselect active buffer. - */ - glBindBuffer(GL_ARRAY_BUFFER, - 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - 0); - - /* - * Disable vertices and normals for buffers. - * Otherwise, bad thing will happen. - */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); -#endif // __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_DECLARE__ - break; - } -} - diff --git a/src/Brain/BrainOpenGLShapeRingOutline.h b/src/Brain/BrainOpenGLShapeRingOutline.h deleted file mode 100644 index a79aa458c..000000000 --- a/src/Brain/BrainOpenGLShapeRingOutline.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_H_ -#define __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_H_ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#include "BrainOpenGLShape.h" - -namespace caret { - - class BrainOpenGLShapeRingOutline : public BrainOpenGLShape { - - public: - BrainOpenGLShapeRingOutline(const int32_t numberOfSides, - const float radius, - const float lineThickness); - - virtual ~BrainOpenGLShapeRingOutline(); - - float getLineThickness() const; - - private: - BrainOpenGLShapeRingOutline(const BrainOpenGLShapeRingOutline&); - - BrainOpenGLShapeRingOutline& operator=(const BrainOpenGLShapeRingOutline&); - - public: - - // ADD_NEW_METHODS_HERE - - protected: - void drawShape(const BrainOpenGL::DrawMode drawMode, - const uint8_t rgba[4]); - - void drawShape(const BrainOpenGL::DrawMode drawMode, - const float rgba[4]); - - - void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); - - private: - - // ADD_NEW_MEMBERS_HERE - - const int32_t m_numberOfSides; - const float m_radius; - const float m_lineThickness; - - GLuint m_coordinatesBufferID; - GLuint m_coordinatesRgbaByteBufferID; - GLuint m_normalBufferID; - GLuint m_lineLoopBufferID; - - - GLuint m_displayList; - - std::vector m_coordinates; - - std::vector m_rgbaByte; - - std::vector m_normals; - - std::vector m_lineLoop; - - bool m_isApplyColoring; - }; - -#ifdef __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_DECLARE__ - // -#endif // __BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_DECLARE__ - -} // namespace -#endif //__BRAIN_OPEN_GL_SHAPE_RING_OUTLINE_H_ diff --git a/src/Brain/BrainOpenGLTextRenderInterface.h b/src/Brain/BrainOpenGLTextRenderInterface.h index c8844cd8b..51e36872b 100644 --- a/src/Brain/BrainOpenGLTextRenderInterface.h +++ b/src/Brain/BrainOpenGLTextRenderInterface.h @@ -35,6 +35,8 @@ namespace caret { public: virtual ~BrainOpenGLTextRenderInterface(); + virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) = 0; + /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 7c94fc12e..cb789c816 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -43,7 +43,6 @@ BrainOpenGLShapeCone.h BrainOpenGLShapeCube.h BrainOpenGLShapeCylinder.h BrainOpenGLShapeRing.h -BrainOpenGLShapeRingOutline.h BrainOpenGLShapeSphere.h BrainOpenGLTextRenderInterface.h BrainOpenGLViewportContent.h @@ -191,7 +190,6 @@ BrainOpenGLShapeCone.cxx BrainOpenGLShapeCube.cxx BrainOpenGLShapeCylinder.cxx BrainOpenGLShapeRing.cxx -BrainOpenGLShapeRingOutline.cxx BrainOpenGLShapeSphere.cxx BrainOpenGLTextRenderInterface.cxx BrainOpenGLViewportContent.cxx diff --git a/src/Brain/DummyFontTextRenderer.cxx b/src/Brain/DummyFontTextRenderer.cxx index cc14ef7a8..7bfc5b31c 100644 --- a/src/Brain/DummyFontTextRenderer.cxx +++ b/src/Brain/DummyFontTextRenderer.cxx @@ -56,6 +56,17 @@ DummyFontTextRenderer::~DummyFontTextRenderer() { } +/** + * Constructor. + * + * @param contextSharingGroupPointer + * Shared OpenGL context pointer. + */ +void +DummyFontTextRenderer::setSharedOpenGLContextPointer(void* /*contextSharingGroupPointer*/) +{ +} + /** * @return The font system is valid. */ diff --git a/src/Brain/DummyFontTextRenderer.h b/src/Brain/DummyFontTextRenderer.h index 3dabcd5af..47355dd74 100644 --- a/src/Brain/DummyFontTextRenderer.h +++ b/src/Brain/DummyFontTextRenderer.h @@ -35,6 +35,8 @@ namespace caret { virtual ~DummyFontTextRenderer(); + virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) override; + bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index a0403963f..822ae0ef4 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -76,10 +76,11 @@ #include #include "AnnotationPointSizeText.h" -#include "BrainOpenGLPrimitiveDrawing.h" +#include "BrainOpenGL.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" +#include "GraphicsShape.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -116,7 +117,8 @@ static const bool drawCrosshairsAtFontStartingCoordinate = false; * Constructor. */ FtglFontTextRenderer::FtglFontTextRenderer() -: BrainOpenGLTextRenderInterface() +: BrainOpenGLTextRenderInterface(), +m_contextSharingGroupPointer(0) { m_defaultFont = NULL; #ifdef HAVE_FREETYPE @@ -155,6 +157,18 @@ FtglFontTextRenderer::~FtglFontTextRenderer() #endif // HAVE_FREETYPE } +/** + * Constructor. + * + * @param contextSharingGroupPointer + * Shared OpenGL context pointer. + */ +void +FtglFontTextRenderer::setSharedOpenGLContextPointer(void* contextSharingGroupPointer) +{ + m_contextSharingGroupPointer = contextSharingGroupPointer; +} + /** * @return The font system is valid. */ @@ -531,9 +545,11 @@ FtglFontTextRenderer::drawUnderline(const double lineStartX, underlineCoords.insert(underlineCoords.end(), lineY); underlineCoords.insert(underlineCoords.end(), lineZ); - BrainOpenGLPrimitiveDrawing::drawLines(underlineCoords, - foregroundRgba, - underlineThickness); + GraphicsShape::drawLinesByteColor(m_contextSharingGroupPointer, + underlineCoords, + foregroundRgba, + GraphicsPrimitive::SizeType::PIXELS, + underlineThickness); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -581,15 +597,10 @@ FtglFontTextRenderer::drawOutline(const double minX, expandBox(bottomLeft, bottomRight, topRight, topLeft, outlineThickness, outlineThickness); - std::vector underlineCoords; - underlineCoords.insert(underlineCoords.end(), bottomLeft, bottomLeft + 3); - underlineCoords.insert(underlineCoords.end(), bottomRight, bottomRight + 3); - underlineCoords.insert(underlineCoords.end(), topRight, topRight + 3); - underlineCoords.insert(underlineCoords.end(), topLeft, topLeft + 3); - - BrainOpenGLPrimitiveDrawing::drawLineLoop(underlineCoords, - foregroundRgba, - outlineThickness); + GraphicsShape::drawBoxOutlineByteColor(m_contextSharingGroupPointer, + bottomLeft, bottomRight, topRight, topLeft, + foregroundRgba, + GraphicsPrimitive::SizeType::PIXELS, outlineThickness); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index 938670ddb..ba1a4acc6 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -39,6 +39,8 @@ namespace caret { virtual ~FtglFontTextRenderer(); + virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) override; + bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, @@ -291,6 +293,8 @@ namespace caret { void restoreStateOfOpenGL(); + void* m_contextSharingGroupPointer; + /** * The default font. DO NOT delete it since it points to * a font in "m_fontNameToFontMap". diff --git a/src/Desktop/desktop.cxx b/src/Desktop/desktop.cxx index d94ae3dbe..68d5035bb 100644 --- a/src/Desktop/desktop.cxx +++ b/src/Desktop/desktop.cxx @@ -331,6 +331,7 @@ main(int argc, char* argv[]) * QApplication is created. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); BrainOpenGLWidget::initializeDefaultGLFormat(); #endif diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx index db1c7653b..0a7764292 100644 --- a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx @@ -55,6 +55,7 @@ using namespace caret; */ GraphicsOpenGLPolylineQuads::~GraphicsOpenGLPolylineQuads() { + CaretAssertMessage(0, "This class should not be used. Instead, use GraphicsOpenGLPolylineTriangles"); } /** diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index e1fa0b323..5094bf94d 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -330,285 +330,6 @@ m_lineType(lineType) } -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLinesPerVertexFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels) -//{ -// std::set emptyPrimitiveRestartIndices; -// std::vector emptyByteRGBA; -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgba, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_PER_VERTEX, -// LineType::LINES); -//} -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLinesSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// -// std::set emptyPrimitiveRestartIndices; -// std::vector emptyByteRGBA; -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINES); -//} -// -///** -// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLineStripSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyByteRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINE_STRIP); -//} -// -///** -// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLineLoopSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyByteRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINE_LOOP); -//} -// -// -// -// -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLinesPerVertexByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels) -//{ -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgba, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_PER_VERTEX, -// LineType::LINES); -//} -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLinesSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINES); -//} -// -///** -// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLineStripSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINE_STRIP); -//} -// -///** -// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineTriangles::drawLineLoopSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINE_LOOP); -//} - - /** * Draw lines where each pair of vertices is drawn as an independent * line segment. Same as OpenGL GL_LINES mode with glBegin(). @@ -1255,7 +976,7 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t break; } - const int32_t numVertices = m_primitiveByteColor->getNumberOfVertices(); + const int32_t numVertices = m_primitive->getNumberOfVertices(); const int32_t triangleOneIndices[3] = { numVertices - 6, numVertices - 5, diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index 592a8594c..24c4dd773 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -57,47 +57,47 @@ namespace caret { static bool draw(void* openglContextPointer, const GraphicsPrimitive* primitive); - static bool drawLinesPerVertexFloatColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - - static bool drawLinesPerVertexByteColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - +// static bool drawLinesPerVertexFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels); +// +// static bool drawLinesSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineStripSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineLoopSolidFloatColor(void* openglContextPointer, +// const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// +// static bool drawLinesPerVertexByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels); +// +// static bool drawLinesSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineStripSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineLoopSolidByteColor(void* openglContextPointer, +// const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); +// // ADD_NEW_METHODS_HERE virtual AString toString() const; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 5fa00102a..aaad9729e 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -69,6 +69,11 @@ GraphicsShape::deleteAllPrimitives() delete iter.second; } s_byteSpherePrimitives.clear(); + + for (auto iter : s_byteCirclePrimitives) { + delete iter.second; + } + s_byteCirclePrimitives.clear(); } @@ -117,6 +122,51 @@ GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, primitive.get()); } +/** + * Draw an outline box. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param v1 + * First vertex. + * @param v2 + * Second vertex. + * @param v3 + * Third vertex. + * @param v4 + * Fourth vertex. + * @param rgba + * Color for drawing. + * @param lineThicknessType + * Type of line thickness. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawBoxOutlineFloatColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const float rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, + rgba)); + primitive->addVertex(v1); + primitive->addVertex(v2); + primitive->addVertex(v3); + primitive->addVertex(v4); + + primitive->setLineWidth(lineThicknessType, + lineThickness); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + /** * Draw a filled box. * @@ -154,6 +204,43 @@ GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, primitive.get()); } +/** + * Draw a filled box. + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param v1 + * First vertex. + * @param v2 + * Second vertex. + * @param v3 + * Third vertex. + * @param v4 + * Fourth vertex. + * @param rgba + * Color for drawing. + */ +void +GraphicsShape::drawBoxFilledFloatColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const float rgba[4]) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, + rgba)); + primitive->addVertex(v1); + primitive->addVertex(v2); + primitive->addVertex(v3); + primitive->addVertex(v4); + + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(openglContextPointer, + primitive.get()); +} + /** * Draw an outline ellipse. @@ -309,7 +396,7 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, } /** - * Draw line a sphere at the given XYZ coordinate + * Draw a sphere at the given XYZ coordinate * * @param openglContextPointer * Pointer to OpenGL context. @@ -342,10 +429,10 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, if (spherePrimitive == NULL) { const bool useStripsFlag = true; if (useStripsFlag) { - spherePrimitive = createSpherePrimitiveTriangleStrips(10); + spherePrimitive = createSpherePrimitiveTriangleStrips(numLatLonDivisions); } else { - spherePrimitive = createSpherePrimitiveTriangles(10); + spherePrimitive = createSpherePrimitiveTriangles(numLatLonDivisions); } /* colors may change but not coordinates/normals */ spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); @@ -366,6 +453,136 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, glPopMatrix(); } +/** + * Draw a filled circle at the given XYZ coordinate + * + * @param openglContextPointer + * Pointer to OpenGL context. + * @param xyz + * XYZ-coordinate of circle + * @param rgba + * Color for drawing. + * @param radius + * Radius of the circle. + */ +void +GraphicsShape::drawCircleFilled(void *openglContextPointer, + const float xyz[3], + const uint8_t rgba[4], + const float radius) +{ + const int32_t numberOfDivisions = 20; + + GraphicsPrimitive* circlePrimitive = NULL; + for (const auto keyPrim : s_byteCirclePrimitives) { + if (keyPrim.first == numberOfDivisions) { + circlePrimitive = keyPrim.second; + break; + } + } + + if (circlePrimitive == NULL) { + circlePrimitive = createCirclePrimitive(numberOfDivisions, + 0.5f); + circlePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + circlePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); + s_byteCirclePrimitives.insert(std::make_pair(numberOfDivisions, + circlePrimitive)); + } + + CaretAssert(circlePrimitive); + + circlePrimitive->replaceAllVertexSolidByteRGBA(rgba); + + glPushMatrix(); + if (xyz != NULL) { + glTranslatef(xyz[0], xyz[1], xyz[2]); + } + glScalef(radius, radius, 1.0f); + GraphicsEngineDataOpenGL::draw(openglContextPointer, + circlePrimitive); + glPopMatrix(); +} + +/** + * Create the primitive for a circle. + * + * @param radius + * Radius of the circle. + */ +GraphicsPrimitive* +GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, + const double radius) +{ + /* + * Setup step size based upon number of points around circle + */ + // const int32_t numberOfPoints = 8; + const float step = (2.0 * M_PI) / numberOfDivisions; + + GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, + (float[]) { 1.0f, 1.0f, 1.0f, 1.0f }); + /* + * Generate points around ring + */ + const float z = 0.0; + primitive->addVertex(0.0f, 0.0f, z); + for (int32_t i = 0; i <= numberOfDivisions; i++) { + const float t = step * i; + const float x = radius * std::cos(t); + const float y = radius * std::sin(t); + + primitive->addVertex(x, y, z); + } + + return primitive; + +} + + +/** + * Create the vertices for a ring. + * + * @param innerRadius + * Inner radius of the ring. + * @param outerRadius + * Outer radius of the ring. + * @return + * Primitive containing vertices of ring. + */ +GraphicsPrimitive* +GraphicsShape::createRingPrimitive(const double innerRadius, + const double outerRadius) +{ + const int32_t numberOfSides = 20; + + /* + * Setup step size based upon number of points around circle + */ + // const int32_t numberOfPoints = 8; + const float step = (2.0 * M_PI) / numberOfSides; + + GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, + (float[]) { 1.0f, 1.0f, 1.0f, 1.0f }); + /* + * Generate points around ring + */ + const float z = 0.0; + for (int32_t i = 0; i <= numberOfSides; i++) { + const float t = step * i; + + const float xin = innerRadius * std::cos(t); + const float yin = innerRadius * std::sin(t); + const float xout = outerRadius * std::cos(t); + const float yout = outerRadius * std::sin(t); + + primitive->addVertex(xin, yin, z); + primitive->addVertex(xout, yout, z); + } + + return primitive; +} + /** * Create the vertices for the ellipse * diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index 4e366bf35..d9a8385cf 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -48,6 +48,15 @@ namespace caret { const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); + static void drawBoxOutlineFloatColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const float rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); + static void drawBoxFilledByteColor(void* openglContextPointer, const float v1[3], const float v2[3], @@ -55,6 +64,13 @@ namespace caret { const float v4[3], const uint8_t rgba[4]); + static void drawBoxFilledFloatColor(void* openglContextPointer, + const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + const float rgba[4]); + static void drawEllipseOutlineByteColor(void* openglContextPointer, const double majorAxis, const double minorAxis, @@ -84,6 +100,11 @@ namespace caret { const uint8_t rgba[4], const float radius); + static void drawCircleFilled(void *openglContextPointer, + const float xyz[3], + const uint8_t rgba[4], + const float radius); + static void deleteAllPrimitives(); // ADD_NEW_METHODS_HERE @@ -97,6 +118,12 @@ namespace caret { GraphicsShape& operator=(const GraphicsShape&); + static GraphicsPrimitive* createCirclePrimitive(const int32_t numberOfDivisions, + const double radius); + + static GraphicsPrimitive* createRingPrimitive(const double innerRadius, + const double outerRadius); + static void createEllipseVertices(const double majorAxis, const double minorAxis, std::vector& ellipseXYZOut); @@ -116,12 +143,15 @@ namespace caret { static std::map, GraphicsPrimitive*> s_byteSpherePrimitives; + static std::map s_byteCirclePrimitives; + // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_SHAPE_DECLARE__ std::map, GraphicsPrimitive*> GraphicsShape::s_byteSpherePrimitives; + std::map GraphicsShape::s_byteCirclePrimitives; #endif // __GRAPHICS_SHAPE_DECLARE__ } // namespace -- GitLab From 11334ed15e9837ad4db4661fc58bbad724b5ec98 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 14 Nov 2017 15:52:09 -0600 Subject: [PATCH 501/755] In the graphics code, logic was present for in the vertex buffer classes to track the OpenGL context in the event that multiple windows used a different OpenGL context (a different context may not share vertex buffers, textures, etc.). We share the OpenGL context among multiple wb_view windows. Both the deprecated QGLWidget which we currently use (and the newer QOpenGLWIdget) make it very easy for context sharing. Since the logic for non-context sharing was cumbersome, and is not needed, it has been removed. --- src/Brain/BrainOpenGL.cxx | 6 - ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 111 +- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 4 - ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 28 +- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 1 - src/Brain/BrainOpenGLFixedPipeline.cxx | 6 +- src/Brain/BrainOpenGLTextRenderInterface.h | 2 - src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 3 +- src/Brain/DummyFontTextRenderer.cxx | 11 - src/Brain/DummyFontTextRenderer.h | 2 - src/Brain/FtglFontTextRenderer.cxx | 21 +- src/Brain/FtglFontTextRenderer.h | 4 - src/Graphics/GraphicsEngineDataOpenGL.cxx | 65 +- src/Graphics/GraphicsEngineDataOpenGL.h | 18 +- src/Graphics/GraphicsOpenGLLineDrawing.cxx | 1635 ----------------- src/Graphics/GraphicsOpenGLLineDrawing.h | 289 --- src/Graphics/GraphicsOpenGLPolylineQuads.cxx | 319 +--- src/Graphics/GraphicsOpenGLPolylineQuads.h | 92 +- .../GraphicsOpenGLPolylineTriangles.cxx | 40 +- .../GraphicsOpenGLPolylineTriangles.h | 14 +- src/Graphics/GraphicsPrimitive.cxx | 2 - src/Graphics/GraphicsShape.cxx | 167 +- src/Graphics/GraphicsShape.h | 84 +- 23 files changed, 274 insertions(+), 2650 deletions(-) delete mode 100644 src/Graphics/GraphicsOpenGLLineDrawing.cxx delete mode 100644 src/Graphics/GraphicsOpenGLLineDrawing.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 2648fa3c8..c47b2926d 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -205,7 +205,6 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, std::vector& viewportContents) { m_contextSharingGroupPointer = contextSharingGroupPointer; - m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); drawModelsImplementation(windowIndex, brain, @@ -214,7 +213,6 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; - m_textRenderer->setSharedOpenGLContextPointer(NULL); } /** @@ -249,7 +247,6 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, const bool applySelectionBackgroundFiltering) { m_contextSharingGroupPointer = contextSharingGroupPointer; - m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); selectModelImplementation(windowIndex, brain, @@ -261,7 +258,6 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; - m_textRenderer->setSharedOpenGLContextPointer(NULL); } /** @@ -294,7 +290,6 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, SurfaceProjectedItem& projectionOut) { m_contextSharingGroupPointer = contextSharingGroupPointer; - m_textRenderer->setSharedOpenGLContextPointer(contextSharingGroupPointer); projectToModelImplementation(windowIndex, brain, @@ -305,7 +300,6 @@ void BrainOpenGL::projectToModel(const int32_t windowIndex, deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; - m_textRenderer->setSharedOpenGLContextPointer(NULL); } diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index eab1e5b04..7bdd75c26 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -42,7 +42,6 @@ #include "AnnotationText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" -#include "BrainOpenGLShapeRing.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrowserTabContent.h" #include "CaretAssert.h" @@ -91,9 +90,6 @@ m_volumeSliceThickness(0.0) m_dummyAnnotationFile = new AnnotationFile(); m_dummyAnnotationFile->setFileName("DummyFileForDrawing" + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::ANNOTATION)); - m_rotationHandleCircle = new BrainOpenGLShapeRing(20, - 0.7, - 1.0); BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, m_lineWidthMaximum); @@ -104,7 +100,6 @@ m_volumeSliceThickness(0.0) */ BrainOpenGLAnnotationDrawingFixedPipeline::~BrainOpenGLAnnotationDrawingFixedPipeline() { - delete m_rotationHandleCircle; delete m_dummyAnnotationFile; } @@ -299,8 +294,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c drawingSpaceXYZ[1]); crossShape->addVertex(drawingSpaceXYZ[0] + 10, drawingSpaceXYZ[1]); - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - crossShape.get()); + GraphicsEngineDataOpenGL::draw(crossShape.get()); } } break; @@ -1228,8 +1222,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * since it is opaque and prevents "behind" annotations * from being selected */ - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -1240,8 +1233,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ - GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -1257,8 +1249,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil } else { if (drawBackgroundFlag) { - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -1267,8 +1258,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil } if (drawForegroundFlag) { - GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -1346,8 +1336,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, bottomRight, topRight, topLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, colorBar, @@ -1374,8 +1363,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati bgCoords.insert(bgCoords.end(), bgTopRight, bgTopRight + 3); bgCoords.insert(bgCoords.end(), bgTopLeft, bgTopLeft + 3); - GraphicsShape::drawBoxFilledFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, + GraphicsShape::drawBoxFilledFloatColor(bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, backgroundRGBA); } @@ -1585,8 +1573,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, tickThickness); - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - linesPrimitive.get()); + GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } @@ -1724,12 +1711,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation * Lines need to be drawn OVER any quads (otherwise the quads * would obscure the lines */ - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - trianglesPrimitive.get()); + GraphicsEngineDataOpenGL::draw(trianglesPrimitive.get()); glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - linesPrimitive.get()); + GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } @@ -1895,8 +1880,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * since it is opaque and prevents "behind" annotations * from being selected */ - GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, + GraphicsShape::drawEllipseFilledByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA); } @@ -1905,8 +1889,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ - GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, + GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, @@ -1920,16 +1903,14 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi } else { if (drawBackgroundFlag) { - GraphicsShape::drawEllipseFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, + GraphicsShape::drawEllipseFilledByteColor(majorAxis * 2.0f, minorAxis * 2.0f, backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { - GraphicsShape::drawEllipseOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - majorAxis * 2.0f, + GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, @@ -2229,8 +2210,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, bottomRight, topRight, topLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, text, @@ -2255,14 +2235,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi convertObsoleteLineWidthPixelsToPercentageWidth(text); } - GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - connectLineCoordinates, + GraphicsShape::drawLinesByteColor(connectLineCoordinates, textColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); if ( ! arrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - arrowCoordinates, + GraphicsShape::drawLineStripByteColor(arrowCoordinates, textColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); @@ -2301,8 +2279,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi float tl[3]; getAnnotationTwoDimShapeBounds(text, annXYZ, bl, br, tr, tl); - GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bl, br, tr, tl, + GraphicsShape::drawBoxOutlineByteColor(bl, br, tr, tl, foregroundRGBA, GraphicsPrimitive::SizeType::PIXELS, 2.0f); @@ -2347,8 +2324,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi crossShape->addVertex(annXYZ[0] + 10, annXYZ[1]); crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - crossShape.get()); + GraphicsEngineDataOpenGL::draw(crossShape.get()); } } } @@ -2436,8 +2412,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, bottomRight, topRight, topLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, image, @@ -2470,8 +2445,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF xyz.insert(xyz.end(), topLeft, topLeft + 3); primitive->replaceFloatXYZ(xyz); - GraphicsEngineDataOpenGL::draw(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - primitive); + GraphicsEngineDataOpenGL::draw(primitive); } drawnFlag = true; } @@ -2480,8 +2454,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF if (image->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(image); } - GraphicsShape::drawBoxOutlineFloatColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, bottomRight, topRight, topLeft, + GraphicsShape::drawBoxOutlineFloatColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, image->getLineWidthPercentage()); } @@ -2702,21 +2675,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); - GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - lineCoordinates, + GraphicsShape::drawLinesByteColor(lineCoordinates, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - startArrowCoordinates, + GraphicsShape::drawLineStripByteColor(startArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - endArrowCoordinates, + GraphicsShape::drawLineStripByteColor(endArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); @@ -2728,21 +2698,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi } else { if (drawForegroundFlag) { - GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - lineCoordinates, + GraphicsShape::drawLinesByteColor(lineCoordinates, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - startArrowCoordinates, + GraphicsShape::drawLineStripByteColor(startArrowCoordinates, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - endArrowCoordinates, + GraphicsShape::drawLineStripByteColor(endArrowCoordinates, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); @@ -2846,8 +2813,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi if (m_selectionModeFlag) { uint8_t identificationRGBA[4]; getIdentificationColor(identificationRGBA); - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -2859,14 +2825,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi } else { if (drawFilledCircleFlag) { - GraphicsShape::drawCircleFilled(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - NULL, + GraphicsShape::drawCircleFilled(NULL, m_selectionBoxRGBA, - halfWidthHeight); + halfWidthHeight * 2); } else if (drawSquareFlag) { - GraphicsShape::drawBoxFilledByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - bottomLeft, + GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -2876,7 +2840,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi const float diameter = halfWidthHeight; glPushMatrix(); glScaled(diameter, diameter, 1.0); - m_rotationHandleCircle->draw(m_selectionBoxRGBA); + GraphicsShape::drawRing(NULL, + m_selectionBoxRGBA, + 0.7, + 1.0); glPopMatrix(); } } @@ -3073,8 +3040,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, innerSpacing, innerSpacing); if (! m_selectionModeFlag) { - GraphicsShape::drawBoxOutlineByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, + GraphicsShape::drawBoxOutlineByteColor(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, m_selectionBoxRGBA, GraphicsPrimitive::SizeType::PIXELS, 2.0f); } @@ -3220,8 +3186,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann std::vector coords; coords.insert(coords.end(), handleRotationLineEnd, handleRotationLineEnd + 3); coords.insert(coords.end(), handleOffset, handleOffset + 3); - GraphicsShape::drawLinesByteColor(m_brainOpenGLFixedPipeline->getContextSharingGroupPointer(), - coords, m_selectionBoxRGBA, + GraphicsShape::drawLinesByteColor(coords, m_selectionBoxRGBA, GraphicsPrimitive::SizeType::PIXELS, 2.0f); drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 7d9fab65e..f7557e7ec 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -46,7 +46,6 @@ namespace caret { class Brain; class BrainOpenGLFixedPipeline; - class BrainOpenGLShapeRing; class Surface; class BrainOpenGLAnnotationDrawingFixedPipeline : public CaretObject { @@ -347,9 +346,6 @@ namespace caret { /** Color for selection box and sizing handles */ uint8_t m_selectionBoxRGBA[4]; - /** Used for rotation hanlde circle */ - BrainOpenGLShapeRing* m_rotationHandleCircle; - float m_lineWidthMinimum = 1.0f; float m_lineWidthMaximum = 5.0f; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index e4e282fdc..0c0d7ec8b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -677,7 +677,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch titleInfo.drawTitle(foregroundRGBA); leftAxisInfo.drawAxis(this, m_chartOverlaySet, - m_fixedPipelineDrawing->getContextSharingGroupPointer(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, @@ -685,7 +684,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxLeft); rightAxisInfo.drawAxis(this, m_chartOverlaySet, - m_fixedPipelineDrawing->getContextSharingGroupPointer(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, @@ -693,7 +691,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch yMaxRight); topAxisInfo.drawAxis(this, m_chartOverlaySet, - m_fixedPipelineDrawing->getContextSharingGroupPointer(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, @@ -701,7 +698,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch xMaxTop); bottomAxisInfo.drawAxis(this, m_chartOverlaySet, - m_fixedPipelineDrawing->getContextSharingGroupPointer(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, @@ -913,8 +909,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch */ glPushMatrix(); glScalef(1.0, 1000.0, 1.0); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - histogramPrimitives->getBarsPrimitive(), + GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getBarsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, @@ -926,8 +921,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch * Increase line width for identification */ BrainOpenGL::setLineWidth(envelopeLineWidth * 3.0f); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - histogramPrimitives->getEnvelopePrimitive(), + GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, @@ -1021,8 +1015,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch float primitiveDepth = 0.0; BrainOpenGL::setLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), + GraphicsEngineDataOpenGL::drawWithSelection(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, @@ -1045,8 +1038,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch */ m_fixedPipelineDrawing->enableLineAntiAliasing(); BrainOpenGL::setLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); - GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); + GraphicsEngineDataOpenGL::draw(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); } @@ -1332,8 +1324,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; - GraphicsEngineDataOpenGL::drawWithSelection(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - matrixPrimitive, + GraphicsEngineDataOpenGL::drawWithSelection(matrixPrimitive, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, @@ -1828,8 +1819,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* return; } - GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - primitive); + GraphicsEngineDataOpenGL::draw(primitive); } /** @@ -2425,8 +2415,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo * The chart drawing parent. * @param chartTwoOverlaySet * Chart overlay set containing the axis. - * @param openGLContextSharingGroupPointer - * Pointer to current OpenGL context. * @param mouseX * X-coordinate of the mouse. * @param mouseY @@ -2441,7 +2429,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, ChartTwoOverlaySet* chartTwoOverlaySet, - void* openGLContextSharingGroupPointer, const int32_t mouseX, const int32_t mouseY, const float foregroundFloatRGBA[4], @@ -2617,8 +2604,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh // boxPrimitive->addVertex(right, top, 0.0f); // boxPrimitive->addVertex(left, top, 0.0f); - GraphicsEngineDataOpenGL::drawWithSelection(openGLContextSharingGroupPointer, - boxPrimitive.get(), + GraphicsEngineDataOpenGL::drawWithSelection(boxPrimitive.get(), mouseX, mouseY, primitiveIndex, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index b07781640..ca69247b6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -158,7 +158,6 @@ namespace caret { void drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, ChartTwoOverlaySet* chartTwoOverlaySet, - void* openGLContextSharingGroupPointer, const int32_t mouseX, const int32_t mouseY, const float foregroundFloatRGBA[4], diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index cd74f0b6d..85a8f4857 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2815,15 +2815,13 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) glEnable(GL_LIGHTING); } } - GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), - pointsPrimitive.get()); + GraphicsEngineDataOpenGL::draw(pointsPrimitive.get()); } if (linesPrimitive) { glDisable(GL_LIGHTING); linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineWidth); - GraphicsEngineDataOpenGL::draw(getContextSharingGroupPointer(), - linesPrimitive.get()); + GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); } glPopAttrib(); diff --git a/src/Brain/BrainOpenGLTextRenderInterface.h b/src/Brain/BrainOpenGLTextRenderInterface.h index 51e36872b..c8844cd8b 100644 --- a/src/Brain/BrainOpenGLTextRenderInterface.h +++ b/src/Brain/BrainOpenGLTextRenderInterface.h @@ -35,8 +35,6 @@ namespace caret { public: virtual ~BrainOpenGLTextRenderInterface(); - virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) = 0; - /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 7d8804cc0..9f7452a34 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3642,8 +3642,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) float widthPixels = thickness; primitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, widthPixels); - GraphicsEngineDataOpenGL::draw(m_fixedPipelineDrawing->getContextSharingGroupPointer(), - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); if (depthTestFlag) { glEnable(GL_DEPTH_TEST); } diff --git a/src/Brain/DummyFontTextRenderer.cxx b/src/Brain/DummyFontTextRenderer.cxx index 7bfc5b31c..cc14ef7a8 100644 --- a/src/Brain/DummyFontTextRenderer.cxx +++ b/src/Brain/DummyFontTextRenderer.cxx @@ -56,17 +56,6 @@ DummyFontTextRenderer::~DummyFontTextRenderer() { } -/** - * Constructor. - * - * @param contextSharingGroupPointer - * Shared OpenGL context pointer. - */ -void -DummyFontTextRenderer::setSharedOpenGLContextPointer(void* /*contextSharingGroupPointer*/) -{ -} - /** * @return The font system is valid. */ diff --git a/src/Brain/DummyFontTextRenderer.h b/src/Brain/DummyFontTextRenderer.h index 47355dd74..3dabcd5af 100644 --- a/src/Brain/DummyFontTextRenderer.h +++ b/src/Brain/DummyFontTextRenderer.h @@ -35,8 +35,6 @@ namespace caret { virtual ~DummyFontTextRenderer(); - virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) override; - bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 822ae0ef4..6c5d47cee 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -117,8 +117,7 @@ static const bool drawCrosshairsAtFontStartingCoordinate = false; * Constructor. */ FtglFontTextRenderer::FtglFontTextRenderer() -: BrainOpenGLTextRenderInterface(), -m_contextSharingGroupPointer(0) +: BrainOpenGLTextRenderInterface() { m_defaultFont = NULL; #ifdef HAVE_FREETYPE @@ -157,18 +156,6 @@ FtglFontTextRenderer::~FtglFontTextRenderer() #endif // HAVE_FREETYPE } -/** - * Constructor. - * - * @param contextSharingGroupPointer - * Shared OpenGL context pointer. - */ -void -FtglFontTextRenderer::setSharedOpenGLContextPointer(void* contextSharingGroupPointer) -{ - m_contextSharingGroupPointer = contextSharingGroupPointer; -} - /** * @return The font system is valid. */ @@ -545,8 +532,7 @@ FtglFontTextRenderer::drawUnderline(const double lineStartX, underlineCoords.insert(underlineCoords.end(), lineY); underlineCoords.insert(underlineCoords.end(), lineZ); - GraphicsShape::drawLinesByteColor(m_contextSharingGroupPointer, - underlineCoords, + GraphicsShape::drawLinesByteColor(underlineCoords, foregroundRgba, GraphicsPrimitive::SizeType::PIXELS, underlineThickness); @@ -597,8 +583,7 @@ FtglFontTextRenderer::drawOutline(const double minX, expandBox(bottomLeft, bottomRight, topRight, topLeft, outlineThickness, outlineThickness); - GraphicsShape::drawBoxOutlineByteColor(m_contextSharingGroupPointer, - bottomLeft, bottomRight, topRight, topLeft, + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRgba, GraphicsPrimitive::SizeType::PIXELS, outlineThickness); diff --git a/src/Brain/FtglFontTextRenderer.h b/src/Brain/FtglFontTextRenderer.h index ba1a4acc6..938670ddb 100644 --- a/src/Brain/FtglFontTextRenderer.h +++ b/src/Brain/FtglFontTextRenderer.h @@ -39,8 +39,6 @@ namespace caret { virtual ~FtglFontTextRenderer(); - virtual void setSharedOpenGLContextPointer(void* contextSharingGroupPointer) override; - bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, @@ -293,8 +291,6 @@ namespace caret { void restoreStateOfOpenGL(); - void* m_contextSharingGroupPointer; - /** * The default font. DO NOT delete it since it points to * a font in "m_fontNameToFontMap". diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 25dc538bf..b5750c94b 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -49,16 +49,9 @@ using namespace caret; /** * Constructor. - * - * @param openglContextPointer - * Context to which the OpenGL buffers apply. The current usage of QGLWidget - * shares the OpenGL context among all QGLWidgets. However, in the event - * OpenGL contexts are not shared, this implementation will need to be - * updated. */ -GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL(const void* openglContextPointer) -: GraphicsEngineData(), -m_openglContextPointer(openglContextPointer) +GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL() +: GraphicsEngineData() { } @@ -462,14 +455,11 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv /** * Draw the given graphics primitive. * - * @param openglContextPointer - * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. */ void -GraphicsEngineDataOpenGL::draw(void* openglContextPointer, - GraphicsPrimitive* primitive) +GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) { CaretAssert(primitive); @@ -514,16 +504,14 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, } if (spheresFlag) { - drawSpheresPrimitive(openglContextPointer, - primitive); + drawSpheresPrimitive(primitive); } else if (workbenchLineFlag) { AString errorMessage; // primitiveToDraw = GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, // primitive, // errorMessage); - primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, - primitive, + primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(primitive, errorMessage); if (primitiveToDraw == NULL) { CaretLogSevere(errorMessage); @@ -531,13 +519,11 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, } windowSpacePrimitive.reset(primitiveToDraw); drawWindowSpace(PrivateDrawMode::DRAW_NORMAL, - openglContextPointer, primitiveToDraw, NULL); } else { drawPrivate(PrivateDrawMode::DRAW_NORMAL, - openglContextPointer, primitiveToDraw, NULL); } @@ -548,8 +534,6 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, * * @param drawMode * Mode for drawing. - * @param openglContextPointer - * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. * @param primitiveSelectionHelper @@ -557,7 +541,6 @@ GraphicsEngineDataOpenGL::draw(void* openglContextPointer, */ void GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, - void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { @@ -577,7 +560,6 @@ GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, glPolygonMode(GL_FRONT, GL_FILL); drawPrivate(drawMode, - openglContextPointer, primitive, primitiveSelectionHelper); @@ -588,14 +570,11 @@ GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, /** * Draw a sphere primitive type. * - * @param openglContextPointer - * Pointer to the active OpenGL context. * @param primitive * The spheres primitive type. */ void -GraphicsEngineDataOpenGL::drawSpheresPrimitive(void* openglContextPointer, - const GraphicsPrimitive* primitive) +GraphicsEngineDataOpenGL::drawSpheresPrimitive(const GraphicsPrimitive* primitive) { CaretAssert(primitive); CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES); @@ -617,8 +596,7 @@ GraphicsEngineDataOpenGL::drawSpheresPrimitive(void* openglContextPointer, break; case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); - GraphicsShape::drawSphereByteColor(openglContextPointer, - &primitive->m_xyz[i3], + GraphicsShape::drawSphereByteColor(&primitive->m_xyz[i3], &primitive->m_unsignedByteRGBA[i4], sizeValue); break; @@ -699,8 +677,6 @@ GraphicsEngineDataOpenGL::restoreOpenGLStateForWindowSpaceDrawing(int32_t polygo /** * Draw to determine the index of primitive at the given (X, Y) location * - * @param openglContextPointer - * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. * @param pixelX @@ -713,8 +689,7 @@ GraphicsEngineDataOpenGL::restoreOpenGLStateForWindowSpaceDrawing(int32_t polygo * Output with depth at the location. */ void -GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, - GraphicsPrimitive* primitive, +GraphicsEngineDataOpenGL::drawWithSelection(GraphicsPrimitive* primitive, const int32_t pixelX, const int32_t pixelY, int32_t& selectedPrimitiveIndexOut, @@ -776,7 +751,6 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, GraphicsPrimitiveSelectionHelper selectionHelper(primitive); selectionHelper.setupSelectionBeforeDrawing(); drawPrivate(PrivateDrawMode::DRAW_SELECTION, - openglContextPointer, primitive, &selectionHelper); @@ -828,8 +802,6 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, * * @param drawMode * Mode for drawing. - * @param openglContextPointer - * Pointer to the active OpenGL context. * @param primitive * Primitive that is drawn. * @param primitiveSelectionHelper @@ -837,11 +809,9 @@ GraphicsEngineDataOpenGL::drawWithSelection(void* openglContextPointer, */ void GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, - void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { - CaretAssert(openglContextPointer); CaretAssert(primitive); if ( ! primitive->isValid()) { return; @@ -856,7 +826,7 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); if (openglData == NULL) { - openglData = new GraphicsEngineDataOpenGL(openglContextPointer); + openglData = new GraphicsEngineDataOpenGL(); primitive->setGraphicsEngineDataForOpenGL(openglData); openglData->loadAllBuffers(primitive); @@ -879,14 +849,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, openglData->loadTextureImageDataBuffer(primitive); - if (openglContextPointer != openglData->getOpenGLContextPointer()) { - const AString msg("Only one OpenGL graphics context is allowed. Have there been " - "changes made to QGLWidget creation?"); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return; - } - const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); CaretAssert(coordBufferID); if ( ! glIsBuffer(coordBufferID)) { @@ -1080,15 +1042,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, glDisable(GL_TEXTURE_2D); } -/** - * @return Pointer to the OpenGL graphics context to which the buffers belong. - */ -const void* -GraphicsEngineDataOpenGL::getOpenGLContextPointer() const -{ - return m_openglContextPointer; -} - /** * Get the line width in pixels for drawing lines. * If the primitive's line width type is a percentage diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index 2ac7029d2..cd3a658e8 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -38,24 +38,20 @@ namespace caret { class GraphicsEngineDataOpenGL : public GraphicsEngineData { public: - GraphicsEngineDataOpenGL(const void* openglContextPointer); + GraphicsEngineDataOpenGL(); virtual ~GraphicsEngineDataOpenGL(); void deleteBuffers(); - static void draw(void* openglContextPointer, - GraphicsPrimitive* primitive); + static void draw(GraphicsPrimitive* primitive); - static void drawWithSelection(void* openglContextPointer, - GraphicsPrimitive* primitive, + static void drawWithSelection(GraphicsPrimitive* primitive, const int32_t pixelX, const int32_t pixelY, int32_t& selectedPrimitiveIndexOut, float& selectedPrimitiveDepthOut); - const void* getOpenGLContextPointer() const; - void invalidateCoordinates(); void invalidateColors(); @@ -85,17 +81,14 @@ namespace caret { void loadTextureImageDataBuffer(GraphicsPrimitive* primitive); static void drawPrivate(const PrivateDrawMode drawMode, - void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); static void drawWindowSpace(const PrivateDrawMode drawMode, - void* openglContextPointer, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); - static void drawSpheresPrimitive(void* openglContextPointer, - const GraphicsPrimitive* primitive); + static void drawSpheresPrimitive(const GraphicsPrimitive* primitive); GLenum getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const; @@ -109,9 +102,6 @@ namespace caret { static void restoreOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], int32_t viewport[4]); - const void* m_openglContextPointer; - - GLsizei m_arrayIndicesCount = 0; std::unique_ptr m_coordinateBufferObject; diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.cxx b/src/Graphics/GraphicsOpenGLLineDrawing.cxx deleted file mode 100644 index da34d20cc..000000000 --- a/src/Graphics/GraphicsOpenGLLineDrawing.cxx +++ /dev/null @@ -1,1635 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#define __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ -#include "GraphicsOpenGLLineDrawing.h" -#undef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "GraphicsEngineDataOpenGL.h" -#include "CaretOpenGLInclude.h" -#include "GraphicsPrimitive.h" -#include "GraphicsPrimitiveV3fC4f.h" -#include "GraphicsPrimitiveV3fC4ub.h" -#include "MathFunctions.h" -#include "Matrix4x4.h" - -using namespace caret; - - - -/** - * \class caret::GraphicsOpenGLLineDrawing - * \brief Converts lines to rectangles - * \ingroup Graphics - * - * Convert lines to rectangles. - * OpenGL lines have a limited width whose maximum is often exceeded. - * Convert the lines to rectangles. All drawing is done in - * two dimensional windows coordinates. - */ - -/** - * Destructor. - */ -GraphicsOpenGLLineDrawing::~GraphicsOpenGLLineDrawing() -{ -} - -/** - * Draw the given graphics primitive containing lines - * by converting the lines to polygons. - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param primtive - * The graphics primitive. - */ -bool -GraphicsOpenGLLineDrawing::draw(void* openglContextPointer, - const GraphicsPrimitive* primitive) -{ - CaretAssert(primitive); - if (primitive->isValid()) { - float lineWidth = primitive->m_lineWidthValue; - - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: - { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; - } - break; - case GraphicsPrimitive::SizeType::PIXELS: - break; - } - - ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretLogSevere("INVALID color type NONE for graphics primitive"); - return false; - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - colorType = ColorType::BYTE_RGBA_PER_VERTEX; - break; - } - - LineType lineType = LineType::LINES; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - lineType = LineType::LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - lineType = LineType::LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - lineType = LineType::LINES; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - CaretLogSevere("POINTS is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - CaretLogSevere("POLYGON is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - CaretLogSevere("QUADS is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - CaretLogSevere("TRIANGLES is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - break; - case GraphicsPrimitive::PrimitiveType::SPHERES: - CaretLogSevere("SPHERES is not a valid line drawing type"); - break; - } - - return drawLinesPrivate(openglContextPointer, - primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); - } - - return false; -} - -/** - * Convert a Workbench Line Primitive to an OpenGL primitive. - * OpenGL has limits on the width of the lines that it draws. This method will - * convert the lines into polygons so that any line width may be drawn. - * - * @param openglContextPointer - * Pointer to current OpenGL context. - * @param primitive - * A graphics primitive with a primitive type that is one of the - * WORKBENCH_LINE* types. - * @param errorMessageOut - * Upon exit contains an error message if conversion failed. - * @return - * A graphics primitive with an OPENGL_QUADS type that draws the lines - * using polygons. NULL if error. - */ -GraphicsPrimitive* -GraphicsOpenGLLineDrawing::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, - AString& errorMessageOut) -{ - CaretAssert(primitive); - errorMessageOut.clear(); - - if (openglContextPointer == NULL) { - errorMessageOut = "Pointer to current OpenGL context is invalid."; - return NULL; - } - - if ( ! primitive->isValid()) { - errorMessageOut = "Primitive is not valid."; - return NULL; - } - - float lineWidth = primitive->m_lineWidthValue; - - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: - { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; - } - break; - case GraphicsPrimitive::SizeType::PIXELS: - break; - } - - ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - errorMessageOut = "INVALID color type NONE for graphics primitive"; - return NULL; - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - colorType = ColorType::BYTE_RGBA_PER_VERTEX; - break; - } - - LineType lineType = LineType::LINES; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - lineType = LineType::LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: - lineType = LineType::LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - lineType = LineType::LINES; - break; - case GraphicsPrimitive::PrimitiveType::SPHERES: - errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; - break; - } - - if ( ! errorMessageOut.isEmpty()) { - return NULL; - } - - GraphicsOpenGLLineDrawing lineConversion(NULL, - primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); - - GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); - - return primitiveOut; -} - -/** - * Constructor. - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The XYZ vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * The primitive will stop at the index and not connect to the next index. - * @param lineThicknessPixels - * Thickness of lines in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - */ -GraphicsOpenGLLineDrawing::GraphicsOpenGLLineDrawing(void* openglContextPointer, - const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -: m_openglContextPointer(openglContextPointer), -m_inputXYZ(xyz), -m_inputFloatRGBA(floatRGBA), -m_inputByteRGBA(byteRGBA), -m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), -m_lineThicknessPixels(lineThicknessPixels), -m_colorType(colorType), -m_lineType(lineType) -{ - -} - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0.0, 1.0] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLinesPerVertexFloatColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels) -{ - std::set emptyPrimitiveRestartIndices; - std::vector emptyByteRGBA; - return drawLinesPrivate(openglContextPointer, - xyz, - rgba, - emptyByteRGBA, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::FLOAT_RGBA_PER_VERTEX, - LineType::LINES); -} - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0.0, 1.0] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLinesSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - - std::set emptyPrimitiveRestartIndices; - std::vector emptyByteRGBA; - return drawLinesPrivate(openglContextPointer, - xyz, - rgbaVector, - emptyByteRGBA, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::FLOAT_RGBA_SOLID, - LineType::LINES); -} - -/** - * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0.0, 1.0] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLineStripSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - std::vector emptyByteRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - rgbaVector, - emptyByteRGBA, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::FLOAT_RGBA_SOLID, - LineType::LINE_STRIP); -} - -/** - * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0.0, 1.0] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLineLoopSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - std::vector emptyByteRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - rgbaVector, - emptyByteRGBA, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::FLOAT_RGBA_SOLID, - LineType::LINE_LOOP); -} - - - - - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0, 255] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLinesPerVertexByteColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels) -{ - std::vector emptyFloatRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - emptyFloatRGBA, - rgba, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::BYTE_RGBA_PER_VERTEX, - LineType::LINES); -} - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0, 255] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLinesSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - - std::vector emptyFloatRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - emptyFloatRGBA, - rgbaVector, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::BYTE_RGBA_SOLID, - LineType::LINES); -} - -/** - * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0, 255] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLineStripSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - std::vector emptyFloatRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - emptyFloatRGBA, - rgbaVector, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::BYTE_RGBA_SOLID, - LineType::LINE_STRIP); -} - -/** - * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param rgba - * RGBA color for the lines with values ranging [0, 255] - * @param lineThicknessPixels - * Thickness of line in pixels. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLineLoopSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels) -{ - std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; - std::vector emptyFloatRGBA; - std::set emptyPrimitiveRestartIndices; - - return drawLinesPrivate(openglContextPointer, - xyz, - emptyFloatRGBA, - rgbaVector, - emptyPrimitiveRestartIndices, - lineThicknessPixels, - ColorType::BYTE_RGBA_SOLID, - LineType::LINE_LOOP); -} - - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param openglContextPointer - * Pointer to OpenGL context. - * @param xyz - * The vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * @param lineThicknessPixels - * Thickness of line in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLLineDrawing::drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -{ - GraphicsOpenGLLineDrawing lineDrawing(openglContextPointer, - xyz, - floatRGBA, - byteRGBA, - vertexPrimitiveRestartIndices, - lineThicknessPixels, - colorType, - lineType); - return lineDrawing.performDrawing(); -} - -/** - * Convert the content of this instance to a new graphics primitive - * that draws the lines as polygons. - * - * @param errorMessageOut - * Contains error message if conversion failed. - * @return - * Pointer to new primitive or NULL if there is an error. - * Caller must destroy the primitive. - */ -GraphicsPrimitive* -GraphicsOpenGLLineDrawing::convertLinesToPolygons(AString& errorMessageOut) -{ - errorMessageOut.clear(); - - const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); - if (numVertices < 2) { - errorMessageOut = ("Invalid number of vertices=" - + AString::number(numVertices) - + " for line drawing. Must be at least 2."); - return NULL; - } - - const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); - const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numByteRGBA / 4; - if (numVertices != numRgbaVertices) { - errorMessageOut = ("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have byte coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return NULL; - } - } - break; - case ColorType::BYTE_RGBA_SOLID: - if (numByteRGBA < 4) { - errorMessageOut = ("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numByteRGBA)); - return NULL; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numFloatRGBA / 4; - if (numVertices != numRgbaVertices) { - errorMessageOut = ("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have float coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return NULL; - } - } - break; - case ColorType::FLOAT_RGBA_SOLID: - if (numFloatRGBA < 4) { - errorMessageOut = ("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numFloatRGBA)); - return NULL; - } - break; - } - - saveOpenGLState(); - - createProjectionMatrix(); - - createWindowCoordinatesFromVertices(); - - const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); - if (numWindowPoints >= 2) { - convertLineSegmentsToQuads(); - - joinQuads(); - - CaretAssert(m_primitive); - } - - restoreOpenGLState(); - - GraphicsPrimitive* primitiveOut = NULL; - - if (m_primitive->isValid()) { - if (m_primitiveByteColor.get() != NULL) { - primitiveOut = m_primitiveByteColor.release(); - } - else if (m_primitiveFloatColor.get() != NULL) { - primitiveOut = m_primitiveFloatColor.release(); - } - else { - CaretAssert(0); - errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; - } - } - else { - errorMessageOut = "Converted primitive is invalid."; - } - - return primitiveOut; -} - - -/** - * Perform the line drawinhg. - * - * @return - * True if no errors, false if errors. - */ -bool -GraphicsOpenGLLineDrawing::performDrawing() -{ - const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); - if (numVertices < 2) { - CaretLogWarning("Invalid number of vertices=" - + AString::number(numVertices) - + " for line drawing. Must be at least 2."); - return false; - } - - const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); - const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numByteRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have byte coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::BYTE_RGBA_SOLID: - if (numByteRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numByteRGBA)); - return false; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numFloatRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have float coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::FLOAT_RGBA_SOLID: - if (numFloatRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numFloatRGBA)); - return false; - } - break; - } - - saveOpenGLState(); - - createProjectionMatrix(); - - createWindowCoordinatesFromVertices(); - - const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); - if (numWindowPoints >= 2) { - convertLineSegmentsToQuads(); - - joinQuads(); - - CaretAssert(m_primitive); - if (m_primitive->isValid()) { - drawQuads(); - } - } - - restoreOpenGLState(); - - return true; -} - -/** - * Save the OpenGL State. - */ -void -GraphicsOpenGLLineDrawing::saveOpenGLState() -{ - glPushAttrib(GL_COLOR_BUFFER_BIT - | GL_ENABLE_BIT - | GL_HINT_BIT - | GL_LIGHTING_BIT - | GL_POLYGON_BIT); - - /* - * For anti-aliasing requires sorting polygons - * and turning of depth testing - */ - const bool drawWithAntiAliasingFlag = false; - if (drawWithAntiAliasingFlag) { - glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); - glEnable(GL_BLEND); - glHint(GL_POLYGON_SMOOTH_HINT, - GL_NICEST); - glEnable(GL_POLYGON_SMOOTH); - } - - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glGetIntegerv(GL_POLYGON_MODE, - m_savedPolygonMode); - - glGetIntegerv(GL_VIEWPORT, - m_savedViewport); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); -} - -/** - * Restore the OpenGL State. - */ -void -GraphicsOpenGLLineDrawing::restoreOpenGLState() -{ - glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); - glPolygonMode(GL_BACK, m_savedPolygonMode[1]); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); - - glPopAttrib(); -} - -/** - * Create the projection matrix. - */ -void -GraphicsOpenGLLineDrawing::createProjectionMatrix() -{ - GLdouble modelviewArray[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, - modelviewArray); - Matrix4x4 modelviewMatrix; - modelviewMatrix.setMatrixFromOpenGL(modelviewArray); - - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, - projectionArray); - - m_projectionMatrix.setMatrixFromOpenGL(projectionArray); - //m_projectionMatrix.postmultiply(modelviewMatrix); - m_projectionMatrix.premultiply(modelviewMatrix); -} - - -/** - * Create window coordinates from the input vertices. - */ -void -GraphicsOpenGLLineDrawing::createWindowCoordinatesFromVertices() -{ - const float coincidentMaxDistSQ = (0.01f * 0.01f); - - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - - int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); - int32_t iStep = 1; - switch (m_lineType) { - case LineType::LINES: - iStep = 2; - if (MathFunctions::isOddNumber(numInputPoints)) { - CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); - --numInputPoints; - } - break; - case LineType::LINE_LOOP: - iStep = 1; - break; - case LineType::LINE_STRIP: - iStep = 1; - break; - } - - m_vertexWindowXYZ.reserve(numInputPoints * 3); - m_vertexWindowInputIndices.reserve(numInputPoints); - - /* - * Coincident points that result in zero length - * line segments are filtered out - */ - for (int32_t i = 0; i < numInputPoints; i += iStep) { - const int32_t i3 = i * 3; - - /* - * Convert model coordinate to a window coordinate - * as described by the documentation from gluProject(). - */ - float windowXYZ[3]; - CaretAssertVectorIndex(m_inputXYZ, i3 + 1); - convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); - - if (iStep == 1) { - if (i > 0) { - const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); - CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); - const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, - &m_vertexWindowXYZ[previousPointOffset]); - if (distSQ < coincidentMaxDistSQ) { - CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); - continue; - } - } - - m_vertexWindowXYZ.push_back(windowXYZ[0]); - m_vertexWindowXYZ.push_back(windowXYZ[1]); - m_vertexWindowXYZ.push_back(windowXYZ[2]); - m_vertexWindowInputIndices.push_back(i); - } - else if (iStep == 2) { - const int32_t iNext3 = (i + 1) * 3; - float windowNextXYZ[3]; - CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); - convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], - windowNextXYZ); - - const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, - windowNextXYZ); - if (distSQ < coincidentMaxDistSQ) { - CaretLogFine("Filtered out line pairs conincident points " - + AString::number(i) - + " and " - + AString::number(i + 1)); - continue; - } - m_vertexWindowXYZ.push_back(windowXYZ[0]); - m_vertexWindowXYZ.push_back(windowXYZ[1]); - m_vertexWindowXYZ.push_back(windowXYZ[2]); - m_vertexWindowInputIndices.push_back(i); - - m_vertexWindowXYZ.push_back(windowNextXYZ[0]); - m_vertexWindowXYZ.push_back(windowNextXYZ[1]); - m_vertexWindowXYZ.push_back(windowNextXYZ[2]); - m_vertexWindowInputIndices.push_back(i + 1); - } - else { - CaretAssertMessage(0, "Invalid step value"); - } - - if (m_debugFlag) { - GLdouble modelviewArray[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); - GLdouble winX, winY, winZ; - gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], - modelviewArray, projectionArray, viewport, - &winX, &winY, &winZ); - std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; - std::cout << " Pt " << i << ": " - << winX << ", " << winY << ", " << winZ << std::endl; - std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; - } - } - - CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); -} - -/** - * Convert from a model coordinate to a window coordinate. - * - * @param modelXYZ - * The coordinate in model space. - * @param windowXYZOut - * Output with coordinate in window space. - */ -void -GraphicsOpenGLLineDrawing::convertFromModelToWindowCoordinate(const float modelXYZ[3], - float windowXYZOut[3]) const -{ - float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; - m_projectionMatrix.multiplyPoint4(xyzw); - windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); - windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); - windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; - - /* - * From OpenGL Programming Guide 3rd Ed, p 133: - * - * If the near value is 1.0 and the far value is 3.0, - * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. - * So, negate the Z-value to be negative. - */ - windowXYZOut[2] = -windowXYZOut[2]; -} - -/** - * Create a quad from the two window vertices - * - * @param indexOne - * Index of first vertex. - * @param indexTwo - * Index of second vertex. - */ -void -GraphicsOpenGLLineDrawing::createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo) -{ - const int32_t iOne3 = indexOne * 3; - CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); - const int32_t iTwo3 = indexTwo * 3; - CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); - float x1 = m_vertexWindowXYZ[iOne3]; - float y1 = m_vertexWindowXYZ[iOne3 + 1]; - float z1 = m_vertexWindowXYZ[iOne3 + 2]; - float x2 = m_vertexWindowXYZ[iTwo3]; - float y2 = m_vertexWindowXYZ[iTwo3 + 1]; - float z2 = m_vertexWindowXYZ[iTwo3 + 2]; - - /* - * Normalized vector from start to end on line segment in 2D coordinates - */ - float startToEndVector[3] = { - x2 - x1, - y2 - y1, - 0.0f - }; - const float lineLength = MathFunctions::normalizeVector(startToEndVector); - if (lineLength < 0.001f) { - CaretLogWarning("This should not happen: Failure to filter coincident points with indices=" - + AString::number(indexOne) - + ", " - + AString::number(indexTwo) - + " Coordinates: " - + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") - + " " - + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); - } - - /* - * Create a perpendicualar vector to the line segment - */ - float perpendicularVector[3] = { - startToEndVector[1], - -startToEndVector[0], - 0.0f - }; - - /* - * "Width" of rectangle - */ - const float halfWidth = m_lineThicknessPixels / 2.0f; - const float halfWidthX = perpendicularVector[0] * halfWidth; - const float halfWidthY = perpendicularVector[1] * halfWidth; - - /* - * Points of the rectangle - * They should be counter-clockwise oriented - */ - float p1[3] = { - x1 - halfWidthX, - y1 - halfWidthY, - z1 - }; - float p2[3] = { - x1 + halfWidthX, - y1 + halfWidthY, - z1 - }; - float p3[3] = { - x2 + halfWidthX, - y2 + halfWidthY, - z2 - }; - float p4[3] = { - x2 - halfWidthX, - y2 - halfWidthY, - z2 - }; - - /* - * Indices to input coloring. - * Note that coincident points may be removed - */ - CaretAssertVectorIndex(m_vertexWindowInputIndices, indexOne); - const int32_t indexOneRgba = m_vertexWindowInputIndices[indexOne]; - CaretAssertVectorIndex(m_vertexWindowInputIndices, indexTwo); - const int32_t indexTwoRgba = m_vertexWindowInputIndices[indexTwo]; - - /* - * RGBA for the points P1, P2, P3, P4 - */ - int32_t rgbaOffsetP1P2 = 0; - int32_t rgbaOffsetP3P4 = 0; - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOneRgba * 4; - rgbaOffsetP3P4 = indexTwoRgba * 4; - break; - case ColorType::BYTE_RGBA_SOLID: - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOneRgba * 4; - rgbaOffsetP3P4 = indexTwoRgba * 4; - break; - case ColorType::FLOAT_RGBA_SOLID: - break; - } - - float crossProduct[3]; - MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); - if (crossProduct[2] == 0.0f) { - /* This should get caught by vector length check above */ - } - - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - case ColorType::BYTE_RGBA_SOLID: - { - CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); - const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; - CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); - const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; - - CaretAssert(m_primitiveByteColor.get()); - if (crossProduct[2] <= 0.0f) { - m_primitiveByteColor->addVertex(p1, rgbaP12); - m_primitiveByteColor->addVertex(p2, rgbaP12); - m_primitiveByteColor->addVertex(p3, rgbaP34); - m_primitiveByteColor->addVertex(p4, rgbaP34); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_primitiveByteColor->addVertex(p2, rgbaP12); - m_primitiveByteColor->addVertex(p1, rgbaP12); - m_primitiveByteColor->addVertex(p4, rgbaP34); - m_primitiveByteColor->addVertex(p3, rgbaP34); - } - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - case ColorType::FLOAT_RGBA_SOLID: - { - CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); - const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; - CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); - const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; - - CaretAssert(m_primitiveFloatColor.get()); - if (crossProduct[2] <= 0.0f) { - m_primitiveFloatColor->addVertex(p1, rgbaP12); - m_primitiveFloatColor->addVertex(p2, rgbaP12); - m_primitiveFloatColor->addVertex(p3, rgbaP34); - m_primitiveFloatColor->addVertex(p4, rgbaP34); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_primitiveFloatColor->addVertex(p2, rgbaP12); - m_primitiveFloatColor->addVertex(p1, rgbaP12); - m_primitiveFloatColor->addVertex(p4, rgbaP34); - m_primitiveFloatColor->addVertex(p3, rgbaP34); - } - } - break; - } - - m_quadInfo.push_back(QuadInfo(indexOne, indexTwo)); -} - -/** - * Join quads to create connected line segments - * without cracks where the quads join together. - */ -void -GraphicsOpenGLLineDrawing::joinQuads() -{ - CaretAssert(m_primitive); - - const int32_t numQuads = static_cast(m_quadInfo.size()); - const int32_t numQuadsMinusOne = numQuads - 1; - - int32_t numQuadsToConnect = 0; - switch (m_lineType) { - case LineType::LINES: - numQuadsToConnect = 0; - break; - case LineType::LINE_LOOP: - numQuadsToConnect = numQuads; - break; - case LineType::LINE_STRIP: - numQuadsToConnect = numQuadsMinusOne; - break; - } - - /* - * Perform joins of connected quads - */ - for (int32_t i = 0; i < numQuadsToConnect; i++) { - CaretAssertVectorIndex(m_quadInfo, i); - const QuadInfo& quad = m_quadInfo[i]; - - const int32_t nextQuadIndex = ((i < numQuadsMinusOne) ? (i + 1) : 0); - CaretAssertVectorIndex(m_quadInfo, nextQuadIndex); - const QuadInfo& nextQuad = m_quadInfo[nextQuadIndex]; - - /* - * Does quad "i" connect to quad "i+1" ? - */ - if (quad.m_vertexTwoIndex == nextQuad.m_vertexOneIndex) { - const int32_t quadOneVertexIndex = i * 4; - const int32_t quadTwoVertexIndex = nextQuadIndex * 4; - - performJoin(quad.m_vertexOneIndex, - quad.m_vertexTwoIndex, - nextQuad.m_vertexTwoIndex, - quadOneVertexIndex, - quadTwoVertexIndex); - } - } -} - -/** - * Perform a join using the last two vertices in quad one - * and the first two vertices in quad two - * - * @param windowVertexIndexOne - * Index of first window vertex from line segment - * @param windowVertexIndexTwo - * Index of second window from line segment - * @param windowVertexIndexThree - * Index of three window from line segment - * @param quadOneVertexIndex - * Index of first vertex in first quad - * @param quadTwoVertexIndex - * Index of first vertex in second quad - */ -void -GraphicsOpenGLLineDrawing::performJoin(const int32_t windowVertexIndexOne, - const int32_t windowVertexIndexTwo, - const int32_t windowVertexIndexThree, - const int32_t quadOneVertexIndex, - const int32_t quadTwoVertexIndex) -{ - if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; - CaretAssert(m_primitive); - - /* - * Determine if the junction of the two consecutive - * line segments in window coordinates makes a left - * or right turn - */ - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); - const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], - &m_vertexWindowXYZ[windowVertexIndexTwo * 3], - &m_vertexWindowXYZ[windowVertexIndexThree * 3]); - - - int32_t quadOneSideBeginVertexIndex = -1; - int32_t quadOneSideEndVertexIndex = -1; - int32_t quadTwoSideBeginVertexIndex = -1; - int32_t quadTwoSideEndVertexIndex = -1; - const float smallNumber = 0.001; - if (signedArea > smallNumber) { - if (m_debugFlag) std::cout << " Left Turn" << std::endl; - /* - * Right side is vertices two and three - */ - quadOneSideBeginVertexIndex = quadOneVertexIndex + 1; - quadOneSideEndVertexIndex = quadOneVertexIndex + 2; - quadTwoSideBeginVertexIndex = quadTwoVertexIndex + 1; - quadTwoSideEndVertexIndex = quadTwoVertexIndex + 2; - } - else if (signedArea < -smallNumber) { - if (m_debugFlag) std::cout << " Right Turn" << std::endl; - /* - * Right side is vertices 1 and 4 - */ - quadOneSideBeginVertexIndex = quadOneVertexIndex; - quadOneSideEndVertexIndex = quadOneVertexIndex + 3; - quadTwoSideBeginVertexIndex = quadTwoVertexIndex; - quadTwoSideEndVertexIndex = quadTwoVertexIndex + 3; - } - else { - if (m_debugFlag) std::cout << " Parallel" << std::endl; - return; - } - - const std::vector& xyz = m_primitive->getFloatXYZ(); - CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); - const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; - const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; - const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; - const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; - - /* - * Miter limit is a multiple of the line thickness - */ - const float miterLimit = m_lineThicknessPixels;// * 2.0f; - const float miterLimitSquared = miterLimit * miterLimit; - - /* - * Find location of where the edges in the quads intersect - */ - float intersectionXYZ[3]; - if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { - intersectionXYZ[2] = q1v1[2]; - if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; - - /* - * When the angle is very sharp, the miter point can be very long and pointy - * so limit to a multiplier of the line thickness - */ - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); - const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; - const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, - intersectionXYZ); - if (distanceSquared > miterLimitSquared) { - /* - * Extend lines by the miter limit to create a new quad - */ - float newV1[3]; - createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); - float newV2[3]; - createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); - - m_quadJoins.push_back(QuadJoin(q1v2, - newV1, - q2v1, - newV2, - quadOneSideEndVertexIndex, - quadTwoSideBeginVertexIndex)); - } - else { - /* - * Move the existing quad vertices to their intersection point - */ - m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); - m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); - } - } -} - -/** - * Create a vertex for a miter join when the length limit is exceeded - * - * @param v1 - * First vertex - * @param v2 - * Second vertex that is connected to the miter join vertex. - * @param miterLength - * Length of output vertex from v2 - * @param xyzOut - * Output with vertex used for miter join. - */ -void -GraphicsOpenGLLineDrawing::createMiterJoinVertex(const float v1[3], - const float v2[3], - const float miterLength, - float xyzOut[3]) -{ - float n2[3]; - MathFunctions::subtractVectors(v2, v1, n2); - MathFunctions::normalizeVector(n2); - n2[0] *= miterLength; - n2[1] *= miterLength; - n2[2] *= miterLength; - xyzOut[0] = v2[0] + n2[0]; - xyzOut[1] = v2[1] + n2[1]; - xyzOut[2] = v2[2] + n2[2]; -} - -/** - * When the quads are joined, additional quads may be - * created to to fill in the gaps. - */ -void -GraphicsOpenGLLineDrawing::addMiterJoinQuads() -{ - const int32_t numJoinQuads = static_cast(m_quadJoins.size()); - for (int32_t i = 0; i < numJoinQuads; i++) { - CaretAssertVectorIndex(m_quadJoins, i); - const QuadJoin& quadJoin = m_quadJoins[i]; - - /* - * Add the join quad to the primitive - */ - switch (m_primitive->getColorType()) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - { - float rgba[4]; - m_primitiveFloatColor->getVertexFloatRGBA(quadJoin.m_primitiveOneTwoIndex, rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[0], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[3], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[6], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[9], rgba); - } - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - { - uint8_t rgba[4]; - m_primitiveByteColor->getVertexByteRGBA(quadJoin.m_primitiveThreeFourIndex, rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[0], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[3], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[6], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[9], rgba); - } - break; - } - } -} - -/** - * Convert each line segment into a rectangle - * using the line width. "Length" of the - * rectangle is the length of the line segment - * and "width" of the rectangle is the line width. - */ -void -GraphicsOpenGLLineDrawing::convertLineSegmentsToQuads() -{ - - const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); - - /* - * When estimating number of quads, - * include both the quads formed by the vertices - * and possible quads added for joining end points - */ - int32_t estimatedNumberOfQuads = 0; - switch (m_lineType) { - case LineType::LINES: - estimatedNumberOfQuads = numVertices / 2; - break; - case LineType::LINE_LOOP: - estimatedNumberOfQuads = numVertices * 2; - break; - case LineType::LINE_STRIP: - estimatedNumberOfQuads = (numVertices - 1) * 2; - break; - } - - m_primitive = NULL; - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - case ColorType::BYTE_RGBA_SOLID: - m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); - m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); - m_primitive = m_primitiveByteColor.get(); - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - case ColorType::FLOAT_RGBA_SOLID: - m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); - m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); - m_primitive = m_primitiveFloatColor.get(); - break; - } - CaretAssert(m_primitive); - - m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - - const int32_t numVerticesMinusOne = numVertices - 1; - - std::vector restartVertexFlags(numVertices, false); - for (auto index : m_vertexPrimitiveRestartIndices) { - restartVertexFlags[index] = true; - } - - /* - * Restart is disabled because it removes vertices that break joins - * Might want to draw all quads and use alpha=0 for quads that - * should not be joined. - */ - const bool restartEnabledFlag = true; - - switch (m_lineType) { - case LineType::LINES: - { - const int32_t numLineSegments = (numVertices / 2); - for (int32_t i = 0; i < numLineSegments; i++) { - const int32_t i2 = i * 2; - createQuadFromWindowVertices(i2, i2 + 1); - } - } - break; - case LineType::LINE_LOOP: - for (int32_t i = 0; i < numVerticesMinusOne; i++) { - CaretAssertVectorIndex(restartVertexFlags, i + 1); - if (restartVertexFlags[i + 1]) { - if (restartEnabledFlag) continue; - } - createQuadFromWindowVertices(i, i + 1); - } - createQuadFromWindowVertices(numVerticesMinusOne, 0); - break; - case LineType::LINE_STRIP: - for (int32_t i = 0; i < numVerticesMinusOne; i++) { - CaretAssertVectorIndex(restartVertexFlags, i + 1); - if (restartVertexFlags[i + 1]) { - if (restartEnabledFlag) continue; - } - createQuadFromWindowVertices(i, i + 1); - } - break; - } -} - -/** - * Draw the lines using quads. - */ -void -GraphicsOpenGLLineDrawing::drawQuads() -{ - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(viewport[0], viewport[0] + viewport[2], - viewport[1], viewport[1] + viewport[3], - 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glPolygonMode(GL_FRONT, GL_FILL); - - CaretAssert(m_primitive); - GraphicsEngineDataOpenGL::draw(m_openglContextPointer, - m_primitive); - if (m_debugFlag) { - std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -GraphicsOpenGLLineDrawing::toString() const -{ - return "GraphicsOpenGLLineDrawing"; -} - diff --git a/src/Graphics/GraphicsOpenGLLineDrawing.h b/src/Graphics/GraphicsOpenGLLineDrawing.h deleted file mode 100644 index 24daaca53..000000000 --- a/src/Graphics/GraphicsOpenGLLineDrawing.h +++ /dev/null @@ -1,289 +0,0 @@ -#ifndef __GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ -#define __GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include -#include - -#include "CaretObject.h" -#include "Matrix4x4.h" - -namespace caret { - - class GraphicsPrimitive; - class GraphicsPrimitiveV3fC4f; - class GraphicsPrimitiveV3fC4ub; - - class GraphicsOpenGLLineDrawing : public CaretObject { - - public: - /** - * Join tyupe of how connected lines are drawn to remove gaps between segments - */ - enum JoinType { - /** None */ - NONE, - /* Extends 'outsides' of lines to meet forming a pointed shape */ - MITER - }; - - virtual ~GraphicsOpenGLLineDrawing(); - - static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, - AString& errorMessageOut); - - static bool draw(void* openglContextPointer, - const GraphicsPrimitive* primitive); - - static bool drawLinesPerVertexFloatColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - - static bool drawLinesPerVertexByteColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - private: - /** - * Type of line coloring - */ - enum class ColorType { - /** Byte RGBA color at each vertex */ - BYTE_RGBA_PER_VERTEX, - /** One Byte RGBA color for all vertices */ - BYTE_RGBA_SOLID, - /** Float RGBA color at each vertex */ - FLOAT_RGBA_PER_VERTEX, - /** One Float RGBA color for all vertices */ - FLOAT_RGBA_SOLID - }; - - /** - * Type of line drawing - */ - enum class LineType { - /** Each pair of vertices is an independent line segment (GL_LINES) */ - LINES, - /** A connected set of lines forming a loop (last is automaticall connected to first) */ - LINE_LOOP, - /** A connected set of lines (last is not connected to first) */ - LINE_STRIP - }; - - /** - * Indices into input vertices of line - * that formed the quad - */ - class QuadInfo { - public: - QuadInfo(const int32_t vertexOneIndex, - const int32_t vertexTwoIndex) - : m_vertexOneIndex(vertexOneIndex), - m_vertexTwoIndex(vertexTwoIndex) { } - - int32_t m_vertexOneIndex; - int32_t m_vertexTwoIndex; - }; - - /** - * Quads created by joining of lines - */ - class QuadJoin { - public: - QuadJoin(const float xyzOne[3], - const float xyzTwo[3], - const float xyzThree[3], - const float xyzFour[3], - const int32_t primitiveOneTwoIndex, - const int32_t primitiveThreeFourIndex) - : m_primitiveOneTwoIndex(primitiveOneTwoIndex), - m_primitiveThreeFourIndex(primitiveThreeFourIndex) { - m_xyz.insert(m_xyz.end(), xyzOne, xyzOne + 3); - m_xyz.insert(m_xyz.end(), xyzTwo, xyzTwo + 3); - m_xyz.insert(m_xyz.end(), xyzThree, xyzThree + 3); - m_xyz.insert(m_xyz.end(), xyzFour, xyzFour + 3); - } - - std::vector m_xyz; - int32_t m_primitiveOneTwoIndex; - int32_t m_primitiveThreeFourIndex; - }; - - GraphicsOpenGLLineDrawing(void* openglContextPointer, - const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); - - GraphicsOpenGLLineDrawing(const GraphicsOpenGLLineDrawing& obj); - - GraphicsOpenGLLineDrawing& operator=(const GraphicsOpenGLLineDrawing& obj) const; - - static bool drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); - - bool performDrawing(); - - GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); - - void saveOpenGLState(); - - void restoreOpenGLState(); - - void createProjectionMatrix(); - - void convertFromModelToWindowCoordinate(const float modelXYZ[3], - float windowXYZOut[3]) const; - - void createWindowCoordinatesFromVertices(); - - void convertLineSegmentsToQuads(); - - void createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo); - - void drawQuads(); - - void performJoin(const int32_t lineVertexIndexOne, - const int32_t lineVertexIndexTwo, - const int32_t lineVertexIndexThree, - const int32_t quadOneVertexIndex, - const int32_t quadTwoVertexIndex); - - void joinQuads(); - - void addMiterJoinQuads(); - - void createMiterJoinVertex(const float v1[3], - const float v2[3], - const float miterLength, - float xyzOut[3]); - - void* m_openglContextPointer; - - const std::vector& m_inputXYZ; - - const std::vector& m_inputFloatRGBA; - - const std::vector& m_inputByteRGBA; - - std::set m_vertexPrimitiveRestartIndices; - - const float m_lineThicknessPixels; - - const ColorType m_colorType; - - const LineType m_lineType; - - std::vector m_vertexWindowXYZ; - - std::vector m_vertexWindowInputIndices; - - //std::vector m_windowQuadsXYZ; - - //std::vector m_windowQuadsRGBA; - - JoinType m_joinType = JoinType::MITER; - - bool m_debugFlag = false; - - int m_savedPolygonMode[2]; - - int m_savedViewport[4]; - - Matrix4x4 m_projectionMatrix; - - /* - * The base class graphics primitive that points to - * either the Float or Byte Color primitive and can - * be used for non-color operations. NEVER delete - * this as it points to one the color primitive - */ - GraphicsPrimitive* m_primitive = NULL; - - std::unique_ptr m_primitiveFloatColor; - - std::unique_ptr m_primitiveByteColor; - - std::vector m_quadInfo; - - std::vector m_quadJoins; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ - // -#endif // __GRAPHICS_OPEN_G_L_LINE_DRAWING_DECLARE__ - -} // namespace -#endif //__GRAPHICS_OPEN_G_L_LINE_DRAWING_H__ diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx index 0a7764292..3f0ad4424 100644 --- a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx @@ -62,14 +62,11 @@ GraphicsOpenGLPolylineQuads::~GraphicsOpenGLPolylineQuads() * Draw the given graphics primitive containing lines * by converting the lines to polygons. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param primtive * The graphics primitive. */ bool -GraphicsOpenGLPolylineQuads::draw(void* openglContextPointer, - const GraphicsPrimitive* primitive) +GraphicsOpenGLPolylineQuads::draw(const GraphicsPrimitive* primitive) { CaretAssert(primitive); if (primitive->isValid()) { @@ -151,8 +148,7 @@ GraphicsOpenGLPolylineQuads::draw(void* openglContextPointer, break; } - return drawLinesPrivate(openglContextPointer, - primitive->m_xyz, + return drawLinesPrivate(primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, @@ -169,8 +165,6 @@ GraphicsOpenGLPolylineQuads::draw(void* openglContextPointer, * OpenGL has limits on the width of the lines that it draws. This method will * convert the lines into polygons so that any line width may be drawn. * - * @param openglContextPointer - * Pointer to current OpenGL context. * @param primitive * A graphics primitive with a primitive type that is one of the * WORKBENCH_LINE* types. @@ -181,18 +175,12 @@ GraphicsOpenGLPolylineQuads::draw(void* openglContextPointer, * using polygons. NULL if error. */ GraphicsPrimitive* -GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, +GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut) { CaretAssert(primitive); errorMessageOut.clear(); - if (openglContextPointer == NULL) { - errorMessageOut = "Pointer to current OpenGL context is invalid."; - return NULL; - } - if ( ! primitive->isValid()) { errorMessageOut = "Primitive is not valid."; return NULL; @@ -276,8 +264,7 @@ GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(void* ope return NULL; } - GraphicsOpenGLPolylineQuads lineConversion(NULL, - primitive->m_xyz, + GraphicsOpenGLPolylineQuads lineConversion(primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, @@ -293,8 +280,6 @@ GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(void* ope /** * Constructor. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * The XYZ vertices. * @param floatRGBA @@ -311,16 +296,14 @@ GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(void* ope * @param lineType * Type of lines drawn. */ -GraphicsOpenGLPolylineQuads::GraphicsOpenGLPolylineQuads(void* openglContextPointer, - const std::vector& xyz, +GraphicsOpenGLPolylineQuads::GraphicsOpenGLPolylineQuads(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType) -: m_openglContextPointer(openglContextPointer), -m_inputXYZ(xyz), +: m_inputXYZ(xyz), m_inputFloatRGBA(floatRGBA), m_inputByteRGBA(byteRGBA), m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), @@ -331,291 +314,10 @@ m_lineType(lineType) } -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLinesPerVertexFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels) -//{ -// std::set emptyPrimitiveRestartIndices; -// std::vector emptyByteRGBA; -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgba, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_PER_VERTEX, -// LineType::LINES); -//} -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLinesSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// -// std::set emptyPrimitiveRestartIndices; -// std::vector emptyByteRGBA; -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINES); -//} -// -///** -// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLineStripSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyByteRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINE_STRIP); -//} -// -///** -// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0.0, 1.0] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLineLoopSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyByteRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// rgbaVector, -// emptyByteRGBA, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::FLOAT_RGBA_SOLID, -// LineType::LINE_LOOP); -//} -// -// -// -// -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLinesPerVertexByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels) -//{ -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgba, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_PER_VERTEX, -// LineType::LINES); -//} -// -///** -// * Draw lines where each pair of vertices is drawn as an independent -// * line segment. Same as OpenGL GL_LINES mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLinesSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINES); -//} -// -///** -// * Draw a connect line strip. Same as OpenGL GL_LINE_STRIP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLineStripSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINE_STRIP); -//} -// -///** -// * Draw a connect line loop (last is connected to first). Same as OpenGL GL_LINE_LOOP mode with glBegin(). -// * -// * @param openglContextPointer -// * Pointer to OpenGL context. -// * @param xyz -// * The vertices. -// * @param rgba -// * RGBA color for the lines with values ranging [0, 255] -// * @param lineThicknessPixels -// * Thickness of line in pixels. -// * @return -// * True if drawn, or false if there was an error. -// */ -//bool -//GraphicsOpenGLPolylineQuads::drawLineLoopSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels) -//{ -// std::vector rgbaVector = { rgba[0], rgba[1], rgba[2], rgba[3] }; -// std::vector emptyFloatRGBA; -// std::set emptyPrimitiveRestartIndices; -// -// return drawLinesPrivate(openglContextPointer, -// xyz, -// emptyFloatRGBA, -// rgbaVector, -// emptyPrimitiveRestartIndices, -// lineThicknessPixels, -// ColorType::BYTE_RGBA_SOLID, -// LineType::LINE_LOOP); -//} - - /** * Draw lines where each pair of vertices is drawn as an independent * line segment. Same as OpenGL GL_LINES mode with glBegin(). * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * The vertices. * @param floatRGBA @@ -634,8 +336,7 @@ m_lineType(lineType) * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLPolylineQuads::drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, +GraphicsOpenGLPolylineQuads::drawLinesPrivate(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -643,8 +344,7 @@ GraphicsOpenGLPolylineQuads::drawLinesPrivate(void* openglContextPointer, const ColorType colorType, const LineType lineType) { - GraphicsOpenGLPolylineQuads lineDrawing(openglContextPointer, - xyz, + GraphicsOpenGLPolylineQuads lineDrawing(xyz, floatRGBA, byteRGBA, vertexPrimitiveRestartIndices, @@ -1616,8 +1316,7 @@ GraphicsOpenGLPolylineQuads::drawQuads() glPolygonMode(GL_FRONT, GL_FILL); CaretAssert(m_primitive); - GraphicsEngineDataOpenGL::draw(m_openglContextPointer, - m_primitive); + GraphicsEngineDataOpenGL::draw(m_primitive); if (m_debugFlag) { std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.h b/src/Graphics/GraphicsOpenGLPolylineQuads.h index 6cf4f3c9d..f2ee8030f 100644 --- a/src/Graphics/GraphicsOpenGLPolylineQuads.h +++ b/src/Graphics/GraphicsOpenGLPolylineQuads.h @@ -50,53 +50,43 @@ namespace caret { virtual ~GraphicsOpenGLPolylineQuads(); - static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, + static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut); - static bool draw(void* openglContextPointer, - const GraphicsPrimitive* primitive); - - static bool drawLinesPerVertexFloatColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidFloatColor(void* openglContextPointer, - const std::vector& xyz, - const float rgba[4], - const float lineThicknessPixels); - - - static bool drawLinesPerVertexByteColor(void* openglContextPointer, - const std::vector& xyz, - const std::vector& rgba, - const float lineThicknessPixels); - - static bool drawLinesSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineStripSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); - - static bool drawLineLoopSolidByteColor(void* openglContextPointer, - const std::vector& xyz, - const uint8_t rgba[4], - const float lineThicknessPixels); + static bool draw(const GraphicsPrimitive* primitive); + +// static bool drawLinesPerVertexFloatColor(const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels); +// +// static bool drawLinesSolidFloatColor(const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineStripSolidFloatColor(const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineLoopSolidFloatColor(const std::vector& xyz, +// const float rgba[4], +// const float lineThicknessPixels); +// +// +// static bool drawLinesPerVertexByteColor(const std::vector& xyz, +// const std::vector& rgba, +// const float lineThicknessPixels); +// +// static bool drawLinesSolidByteColor(const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineStripSolidByteColor(const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); +// +// static bool drawLineLoopSolidByteColor(const std::vector& xyz, +// const uint8_t rgba[4], +// const float lineThicknessPixels); // ADD_NEW_METHODS_HERE @@ -168,8 +158,7 @@ namespace caret { int32_t m_primitiveThreeFourIndex; }; - GraphicsOpenGLPolylineQuads(void* openglContextPointer, - const std::vector& xyz, + GraphicsOpenGLPolylineQuads(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -181,8 +170,7 @@ namespace caret { GraphicsOpenGLPolylineQuads& operator=(const GraphicsOpenGLPolylineQuads& obj) const; - static bool drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, + static bool drawLinesPrivate(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -227,8 +215,6 @@ namespace caret { const float miterLength, float xyzOut[3]); - void* m_openglContextPointer; - const std::vector& m_inputXYZ; const std::vector& m_inputFloatRGBA; @@ -247,10 +233,6 @@ namespace caret { std::vector m_vertexWindowInputIndices; - //std::vector m_windowQuadsXYZ; - - //std::vector m_windowQuadsRGBA; - JoinType m_joinType = JoinType::MITER; bool m_debugFlag = false; diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 5094bf94d..a560e289f 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -61,14 +61,11 @@ GraphicsOpenGLPolylineTriangles::~GraphicsOpenGLPolylineTriangles() * Draw the given graphics primitive containing lines * by converting the lines to polygons. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param primtive * The graphics primitive. */ bool -GraphicsOpenGLPolylineTriangles::draw(void* openglContextPointer, - const GraphicsPrimitive* primitive) +GraphicsOpenGLPolylineTriangles::draw(const GraphicsPrimitive* primitive) { CaretAssert(primitive); if (primitive->isValid()) { @@ -150,8 +147,7 @@ GraphicsOpenGLPolylineTriangles::draw(void* openglContextPointer, break; } - return drawLinesPrivate(openglContextPointer, - primitive->m_xyz, + return drawLinesPrivate(primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, @@ -168,8 +164,6 @@ GraphicsOpenGLPolylineTriangles::draw(void* openglContextPointer, * OpenGL has limits on the width of the lines that it draws. This method will * convert the lines into polygons so that any line width may be drawn. * - * @param openglContextPointer - * Pointer to current OpenGL context. * @param primitive * A graphics primitive with a primitive type that is one of the * WORKBENCH_LINE* types. @@ -180,18 +174,12 @@ GraphicsOpenGLPolylineTriangles::draw(void* openglContextPointer, * using polygons. NULL if error. */ GraphicsPrimitive* -GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, +GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut) { CaretAssert(primitive); errorMessageOut.clear(); - if (openglContextPointer == NULL) { - errorMessageOut = "Pointer to current OpenGL context is invalid."; - return NULL; - } - if ( ! primitive->isValid()) { errorMessageOut = "Primitive is not valid."; return NULL; @@ -275,8 +263,7 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(void* return NULL; } - GraphicsOpenGLPolylineTriangles lineConversion(NULL, - primitive->m_xyz, + GraphicsOpenGLPolylineTriangles lineConversion(primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, @@ -292,8 +279,6 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(void* /** * Constructor. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * The XYZ vertices. * @param floatRGBA @@ -310,16 +295,14 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(void* * @param lineType * Type of lines drawn. */ -GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(void* openglContextPointer, - const std::vector& xyz, +GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, const float lineThicknessPixels, const ColorType colorType, const LineType lineType) -: m_openglContextPointer(openglContextPointer), -m_inputXYZ(xyz), +: m_inputXYZ(xyz), m_inputFloatRGBA(floatRGBA), m_inputByteRGBA(byteRGBA), m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), @@ -334,8 +317,6 @@ m_lineType(lineType) * Draw lines where each pair of vertices is drawn as an independent * line segment. Same as OpenGL GL_LINES mode with glBegin(). * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * The vertices. * @param floatRGBA @@ -354,8 +335,7 @@ m_lineType(lineType) * True if drawn, or false if there was an error. */ bool -GraphicsOpenGLPolylineTriangles::drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, +GraphicsOpenGLPolylineTriangles::drawLinesPrivate(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -363,8 +343,7 @@ GraphicsOpenGLPolylineTriangles::drawLinesPrivate(void* openglContextPointer, const ColorType colorType, const LineType lineType) { - GraphicsOpenGLPolylineTriangles lineDrawing(openglContextPointer, - xyz, + GraphicsOpenGLPolylineTriangles lineDrawing(xyz, floatRGBA, byteRGBA, vertexPrimitiveRestartIndices, @@ -1398,8 +1377,7 @@ GraphicsOpenGLPolylineTriangles::drawTriangles() glPolygonMode(GL_FRONT, GL_FILL); CaretAssert(m_primitive); - GraphicsEngineDataOpenGL::draw(m_openglContextPointer, - m_primitive); + GraphicsEngineDataOpenGL::draw(m_primitive); if (m_debugFlag) { std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index 24c4dd773..93d67a337 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -50,12 +50,10 @@ namespace caret { virtual ~GraphicsOpenGLPolylineTriangles(); - static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(void* openglContextPointer, - const GraphicsPrimitive* primitive, + static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut); - static bool draw(void* openglContextPointer, - const GraphicsPrimitive* primitive); + static bool draw(const GraphicsPrimitive* primitive); // static bool drawLinesPerVertexFloatColor(void* openglContextPointer, // const std::vector& xyz, @@ -175,8 +173,7 @@ namespace caret { const int32_t m_primitiveVertexTwoIndex; }; - GraphicsOpenGLPolylineTriangles(void* openglContextPointer, - const std::vector& xyz, + GraphicsOpenGLPolylineTriangles(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -188,8 +185,7 @@ namespace caret { GraphicsOpenGLPolylineTriangles& operator=(const GraphicsOpenGLPolylineTriangles& obj) const; - static bool drawLinesPrivate(void* openglContextPointer, - const std::vector& xyz, + static bool drawLinesPrivate(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, @@ -231,8 +227,6 @@ namespace caret { const float miterLength, float xyzOut[3]); - void* m_openglContextPointer; - const std::vector& m_inputXYZ; const std::vector& m_inputFloatRGBA; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 821f14096..4688a0291 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -751,7 +751,6 @@ GraphicsPrimitive::addVertexProtected(const float xyz[3], switch (m_colorType) { case ColorType::NONE: - CaretAssert(0); break; case ColorType::FLOAT_RGBA: CaretAssert(rgbaFloat); @@ -1212,7 +1211,6 @@ GraphicsPrimitive::copyVertex(const int32_t copyFromIndex, for (int32_t i = 0; i < 4; i++) { switch (m_colorType) { case ColorType::NONE: - CaretAssert(0); break; case ColorType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, from4 + i); diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index aaad9729e..27bd5c7a0 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -74,14 +74,17 @@ GraphicsShape::deleteAllPrimitives() delete iter.second; } s_byteCirclePrimitives.clear(); + + for (auto iter : s_byteRingPrimitives) { + delete iter.second; + } + s_byteRingPrimitives.clear(); } /** * Draw an outline box. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param v1 * First vertex. * @param v2 @@ -98,8 +101,7 @@ GraphicsShape::deleteAllPrimitives() * Thickness of the line. */ void -GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, - const float v1[3], +GraphicsShape::drawBoxOutlineByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -118,15 +120,12 @@ GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw an outline box. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param v1 * First vertex. * @param v2 @@ -143,8 +142,7 @@ GraphicsShape::drawBoxOutlineByteColor(void* openglContextPointer, * Thickness of the line. */ void -GraphicsShape::drawBoxOutlineFloatColor(void* openglContextPointer, - const float v1[3], +GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -163,15 +161,12 @@ GraphicsShape::drawBoxOutlineFloatColor(void* openglContextPointer, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled box. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param v1 * First vertex. * @param v2 @@ -184,8 +179,7 @@ GraphicsShape::drawBoxOutlineFloatColor(void* openglContextPointer, * Color for drawing. */ void -GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, - const float v1[3], +GraphicsShape::drawBoxFilledByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -200,15 +194,12 @@ GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled box. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param v1 * First vertex. * @param v2 @@ -221,8 +212,7 @@ GraphicsShape::drawBoxFilledByteColor(void* openglContextPointer, * Color for drawing. */ void -GraphicsShape::drawBoxFilledFloatColor(void* openglContextPointer, - const float v1[3], +GraphicsShape::drawBoxFilledFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -237,16 +227,13 @@ GraphicsShape::drawBoxFilledFloatColor(void* openglContextPointer, primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw an outline ellipse. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param majorAxis * Diameter of the major axis. * @param minorAxis @@ -259,8 +246,7 @@ GraphicsShape::drawBoxFilledFloatColor(void* openglContextPointer, * Thickness of the line. */ void -GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, - const double majorAxis, +GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, @@ -280,15 +266,12 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled ellipse. * - * @param openglContextPointer - * Pointer to OpenGL context. * @param majorAxis * Diameter of the major axis. * @param minorAxis @@ -297,8 +280,7 @@ GraphicsShape::drawEllipseOutlineByteColor(void* openglContextPointer, * Color for drawing. */ void -GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, - const double majorAxis, +GraphicsShape::drawEllipseFilledByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4]) { @@ -318,16 +300,13 @@ GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw lines: Each pair of vertices is a separate line segment * similar to OpenGL's GL_LINES * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * Coordinates of the line end points. * @param rgba @@ -338,8 +317,7 @@ GraphicsShape::drawEllipseFilledByteColor(void* openglContextPointer, * Thickness of the line. */ void -GraphicsShape::drawLinesByteColor(void* openglContextPointer, - const std::vector& xyz, +GraphicsShape::drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) @@ -355,15 +333,12 @@ GraphicsShape::drawLinesByteColor(void* openglContextPointer, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw line strip similar to OpenGL's GL_LINES * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * Coordinates of the line end points. * @param rgba @@ -374,8 +349,7 @@ GraphicsShape::drawLinesByteColor(void* openglContextPointer, * Thickness of the line. */ void -GraphicsShape::drawLineStripByteColor(void* openglContextPointer, - const std::vector& xyz, +GraphicsShape::drawLineStripByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) @@ -391,15 +365,12 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - primitive.get()); + GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a sphere at the given XYZ coordinate * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * XYZ-coordinate of sphere * @param rgba @@ -408,8 +379,7 @@ GraphicsShape::drawLineStripByteColor(void* openglContextPointer, * Radius of the sphere. */ void -GraphicsShape::drawSphereByteColor(void* openglContextPointer, - const float xyz[3], +GraphicsShape::drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], const float radius) { @@ -418,8 +388,7 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, GraphicsPrimitive* spherePrimitive = NULL; for (const auto iter : s_byteSpherePrimitives) { const auto& key = iter.first; - if ((key.first == openglContextPointer) - && (key.second == numLatLonDivisions)) { + if ((key == numLatLonDivisions)) { spherePrimitive = iter.second; CaretAssert(spherePrimitive); break; @@ -437,7 +406,7 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, /* colors may change but not coordinates/normals */ spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); spherePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); - s_byteSpherePrimitives.insert(std::make_pair(std::make_pair(openglContextPointer, numLatLonDivisions), + s_byteSpherePrimitives.insert(std::make_pair(numLatLonDivisions, spherePrimitive)); } @@ -448,16 +417,13 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(radius, radius, radius); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - spherePrimitive); + GraphicsEngineDataOpenGL::draw(spherePrimitive); glPopMatrix(); } /** * Draw a filled circle at the given XYZ coordinate * - * @param openglContextPointer - * Pointer to OpenGL context. * @param xyz * XYZ-coordinate of circle * @param rgba @@ -466,8 +432,7 @@ GraphicsShape::drawSphereByteColor(void* openglContextPointer, * Radius of the circle. */ void -GraphicsShape::drawCircleFilled(void *openglContextPointer, - const float xyz[3], +GraphicsShape::drawCircleFilled(const float xyz[3], const uint8_t rgba[4], const float radius) { @@ -499,14 +464,66 @@ GraphicsShape::drawCircleFilled(void *openglContextPointer, glTranslatef(xyz[0], xyz[1], xyz[2]); } glScalef(radius, radius, 1.0f); - GraphicsEngineDataOpenGL::draw(openglContextPointer, - circlePrimitive); + GraphicsEngineDataOpenGL::draw(circlePrimitive); + glPopMatrix(); +} + +/** + * Draw a ring at the given XYZ coordinate + * + * @param xyz + * XYZ-coordinate of ring + * @param rgba + * Color for drawing. + * @param innerRadius + * Inner adius of the ring. + * @param outerRadius + * Outer adius of the ring. + */ +void +GraphicsShape::drawRing(const float xyz[3], + const uint8_t rgba[4], + const double innerRadius, + const double outerRadius) +{ + const int32_t numberOfDivisions = 20; + + GraphicsPrimitive* ringPrimitive = NULL; + for (const auto keyPrim : s_byteRingPrimitives) { + if (keyPrim.first.matches(numberOfDivisions, + innerRadius, + outerRadius)) { + ringPrimitive = keyPrim.second; + break; + } + } + + if (ringPrimitive == NULL) { + RingKey ringKey(numberOfDivisions, innerRadius, outerRadius); + ringPrimitive = createRingPrimitive(ringKey); + ringPrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); + ringPrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); + s_byteRingPrimitives.insert(std::make_pair(RingKey(numberOfDivisions, innerRadius, outerRadius), + ringPrimitive)); + } + + CaretAssert(ringPrimitive); + + ringPrimitive->replaceAllVertexSolidByteRGBA(rgba); + + glPushMatrix(); + if (xyz != NULL) { + glTranslatef(xyz[0], xyz[1], xyz[2]); + } + GraphicsEngineDataOpenGL::draw(ringPrimitive); glPopMatrix(); } /** * Create the primitive for a circle. * + * @param numberOfDivisions + * Number of divisions * @param radius * Radius of the circle. */ @@ -521,7 +538,7 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, const float step = (2.0 * M_PI) / numberOfDivisions; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, - (float[]) { 1.0f, 1.0f, 1.0f, 1.0f }); + (uint8_t[]) { 255, 255, 255, 255 }); /* * Generate points around ring */ @@ -543,6 +560,8 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, /** * Create the vertices for a ring. * + * @param numberOfDivisions + * Number of divisions * @param innerRadius * Inner radius of the ring. * @param outerRadius @@ -551,30 +570,26 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, * Primitive containing vertices of ring. */ GraphicsPrimitive* -GraphicsShape::createRingPrimitive(const double innerRadius, - const double outerRadius) +GraphicsShape::createRingPrimitive(const RingKey& ringKey) { - const int32_t numberOfSides = 20; - /* * Setup step size based upon number of points around circle */ - // const int32_t numberOfPoints = 8; - const float step = (2.0 * M_PI) / numberOfSides; + const float step = (2.0 * M_PI) / ringKey.m_numberOfDivisions; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, - (float[]) { 1.0f, 1.0f, 1.0f, 1.0f }); + (uint8_t[]) { 255, 255, 255, 255 }); /* * Generate points around ring */ const float z = 0.0; - for (int32_t i = 0; i <= numberOfSides; i++) { + for (int32_t i = 0; i <= ringKey.m_numberOfDivisions; i++) { const float t = step * i; - const float xin = innerRadius * std::cos(t); - const float yin = innerRadius * std::sin(t); - const float xout = outerRadius * std::cos(t); - const float yout = outerRadius * std::sin(t); + const float xin = ringKey.m_innerRadius * std::cos(t); + const float yin = ringKey.m_innerRadius * std::sin(t); + const float xout = ringKey.m_outerRadius * std::cos(t); + const float yout = ringKey.m_outerRadius * std::sin(t); primitive->addVertex(xin, yin, z); primitive->addVertex(xout, yout, z); diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index d9a8385cf..cac700d79 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -39,8 +39,7 @@ namespace caret { public: virtual ~GraphicsShape(); - static void drawBoxOutlineByteColor(void* openglContextPointer, - const float v1[3], + static void drawBoxOutlineByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -48,8 +47,7 @@ namespace caret { const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawBoxOutlineFloatColor(void* openglContextPointer, - const float v1[3], + static void drawBoxOutlineFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], @@ -57,54 +55,51 @@ namespace caret { const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawBoxFilledByteColor(void* openglContextPointer, - const float v1[3], + static void drawBoxFilledByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const uint8_t rgba[4]); - static void drawBoxFilledFloatColor(void* openglContextPointer, - const float v1[3], + static void drawBoxFilledFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float rgba[4]); - static void drawEllipseOutlineByteColor(void* openglContextPointer, - const double majorAxis, + static void drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawEllipseFilledByteColor(void* openglContextPointer, - const double majorAxis, + static void drawEllipseFilledByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4]); - static void drawLinesByteColor(void* openglContextPointer, - const std::vector& xyz, + static void drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawLineStripByteColor(void* openglContextPointer, - const std::vector& xyz, + static void drawLineStripByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawSphereByteColor(void* openglContextPointer, - const float xyz[3], + static void drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], const float radius); - static void drawCircleFilled(void *openglContextPointer, - const float xyz[3], + static void drawCircleFilled(const float xyz[3], const uint8_t rgba[4], const float radius); + static void drawRing(const float xyz[3], + const uint8_t rgba[4], + const double innerRadius, + const double outerRadius); + static void deleteAllPrimitives(); // ADD_NEW_METHODS_HERE @@ -112,6 +107,44 @@ namespace caret { virtual AString toString() const; private: + class RingKey { + public: + RingKey(const int32_t numberOfDivisions, + const float innerRadius, + const float outerRadius) + : m_numberOfDivisions(numberOfDivisions), + m_innerRadius(innerRadius), + m_outerRadius(outerRadius) { } + + bool matches(const int32_t numberOfDivisions, + const float innerRadius, + const float outerRadius) const { + if ((m_numberOfDivisions == numberOfDivisions) + && (m_innerRadius == innerRadius) + && (m_outerRadius == outerRadius)) { + return true; + } + return false; + } + + bool operator<(const RingKey& rhs) const { + if (m_numberOfDivisions < rhs.m_numberOfDivisions) { + return true; + } + if (m_innerRadius < rhs.m_innerRadius) { + return true; + } + if (m_outerRadius < rhs.m_outerRadius) { + return true; + } + return false; + } + + int32_t m_numberOfDivisions; + float m_innerRadius; + float m_outerRadius; + }; + GraphicsShape(); GraphicsShape(const GraphicsShape&); @@ -121,8 +154,7 @@ namespace caret { static GraphicsPrimitive* createCirclePrimitive(const int32_t numberOfDivisions, const double radius); - static GraphicsPrimitive* createRingPrimitive(const double innerRadius, - const double outerRadius); + static GraphicsPrimitive* createRingPrimitive(const RingKey& ringKey); static void createEllipseVertices(const double majorAxis, const double minorAxis, @@ -141,17 +173,21 @@ namespace caret { float xyzOut[3], float normalXyzOut[3]); - static std::map, GraphicsPrimitive*> s_byteSpherePrimitives; + static std::map s_byteSpherePrimitives; static std::map s_byteCirclePrimitives; + + static std::map s_byteRingPrimitives; + // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_SHAPE_DECLARE__ - std::map, GraphicsPrimitive*> GraphicsShape::s_byteSpherePrimitives; + std::map GraphicsShape::s_byteSpherePrimitives; std::map GraphicsShape::s_byteCirclePrimitives; + std::map GraphicsShape::s_byteRingPrimitives; #endif // __GRAPHICS_SHAPE_DECLARE__ } // namespace -- GitLab From 1f333503b2739d2ca7e2f4380cd58cb034ff87cb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 15 Nov 2017 16:00:09 -0600 Subject: [PATCH 502/755] From the graphic primitives (in the Graphics directory), removed the QUADS, QUAD_STRIPS, and POLYGON types. These types are removed from OpenGL 3.x (3.2?) so we should avoid using them. All code that used these primitive types has been updated to use triangle primitive types. --- src/Annotations/AnnotationImage.cxx | 45 +- src/Annotations/AnnotationImage.h | 4 + ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 15 +- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 155 +- src/Files/ChartableTwoFileHistogramChart.cxx | 56 +- src/Files/CiftiMappableDataFile.cxx | 63 +- src/Graphics/CMakeLists.txt | 2 - src/Graphics/GraphicsEngineDataOpenGL.cxx | 25 - src/Graphics/GraphicsOpenGLPolylineQuads.cxx | 1335 ----------------- src/Graphics/GraphicsOpenGLPolylineQuads.h | 271 ---- .../GraphicsOpenGLPolylineTriangles.cxx | 25 +- src/Graphics/GraphicsPrimitive.cxx | 54 +- src/Graphics/GraphicsPrimitive.h | 41 +- .../GraphicsPrimitiveSelectionHelper.cxx | 57 +- .../GraphicsPrimitiveSelectionHelper.h | 6 +- src/Graphics/GraphicsShape.cxx | 24 +- 16 files changed, 216 insertions(+), 1962 deletions(-) delete mode 100644 src/Graphics/GraphicsOpenGLPolylineQuads.cxx delete mode 100644 src/Graphics/GraphicsOpenGLPolylineQuads.h diff --git a/src/Annotations/AnnotationImage.cxx b/src/Annotations/AnnotationImage.cxx index 4a907b855..3ff626f30 100644 --- a/src/Annotations/AnnotationImage.cxx +++ b/src/Annotations/AnnotationImage.cxx @@ -231,26 +231,55 @@ AnnotationImage::getGraphicsPrimitive() const { if (m_graphicsPrimitive == NULL) { if ( ! m_imageBytesRGBA.empty()) { - GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, + GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, &m_imageBytesRGBA[0], m_imageWidth, m_imageHeight); /* - * Four coordinates are needed but XY values do not mattter. - * These XY values are replaced when the image is drawn. - * The texture (S, T) do matter. + * A Triangle Strip (consisting of two triangles) is used + * for drawing the image. At this time, the XYZ coordinates + * do not matter and they will be updated when the annotation + * is drawn by a call to ::setVertexBounds(). + * The order of the vertices in the triangle strip is + * Top Left, Bottom Left, Top Right, Bottom Right. If this + * order changes, ::setVertexBounds must be updated. + * + * Zeros are used for the X- and Y-coordinates. + * The third and fourth parameters are the texture + * S and T coordinates. */ - primitive->addVertex(50, 50, 0.0, 0.0); - primitive->addVertex(250, 50, 1.0, 0.0); - primitive->addVertex(250, 250, 1.0, 1.0); - primitive->addVertex(50, 250, 0.0, 1.0); + primitive->addVertex(0, 0, 0, 1); /* Top Left */ + primitive->addVertex(0, 0, 0, 0); /* Bottom Left */ + primitive->addVertex(0, 0, 1, 1); /* Top Right */ + primitive->addVertex(0, 0, 1, 0); /* Bottom Right */ + m_graphicsPrimitive.reset(primitive); + + +// create triangles above and add method to set the vertex coordintes (bottom left, bottom right, etc) } } return m_graphicsPrimitive.get(); } +void +AnnotationImage::setVertexBounds(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3]) +{ + GraphicsPrimitiveV3fT3f* primitive = getGraphicsPrimitive(); + CaretAssert(primitive); + + CaretAssert(primitive->getNumberOfVertices() == 4); + + primitive->replaceVertexFloatXYZ(0, topLeft); + primitive->replaceVertexFloatXYZ(1, bottomLeft); + primitive->replaceVertexFloatXYZ(2, topRight); + primitive->replaceVertexFloatXYZ(3, bottomRight); +} + /** * Save subclass data to the scene. * diff --git a/src/Annotations/AnnotationImage.h b/src/Annotations/AnnotationImage.h index 8d3078755..172e616ef 100644 --- a/src/Annotations/AnnotationImage.h +++ b/src/Annotations/AnnotationImage.h @@ -56,6 +56,10 @@ namespace caret { GraphicsPrimitiveV3fT3f* getGraphicsPrimitive() const; + void setVertexBounds(const float bottomLeft[3], + const float bottomRight[3], + const float topRight[3], + const float topLeft[3]); // ADD_NEW_METHODS_HERE diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 7bdd75c26..cdaabb16e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -2431,20 +2431,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } } + image->setVertexBounds(bottomLeft, + bottomRight, + topRight, + topLeft); GraphicsPrimitiveV3fT3f* primitive = image->getGraphicsPrimitive(); if (primitive != NULL) { if (primitive->isValid()) { - /* - * Replace the primitive's XYZ values here - * Image ALWAYS has four coordinates - */ - std::vector xyz; - xyz.insert(xyz.end(), bottomLeft, bottomLeft + 3); - xyz.insert(xyz.end(), bottomRight, bottomRight + 3); - xyz.insert(xyz.end(), topRight, topRight + 3); - xyz.insert(xyz.end(), topLeft, topLeft + 3); - primitive->replaceFloatXYZ(xyz); - GraphicsEngineDataOpenGL::draw(primitive); } drawnFlag = true; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 0c0d7ec8b..705276029 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -533,8 +533,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); - //double width = 0.0, height = 0.0; - GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); @@ -732,61 +730,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch chartGraphicsDrawingViewport); } -// /* -// * Ensure that there is sufficient space for the axes data display. -// */ -// if ((tabViewportWidth > (leftAxisWidth + rightAxisWidth)) -// && (tabViewportHeight > (bottomAxisHeight + topAxisHeight + topTitleHeight))) { -// -// titleInfo.drawTitle(foregroundRGBA); -// leftAxisInfo.drawAxis(this, -// m_chartOverlaySet, -// m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// foregroundRGBA, -// yMinLeft, -// yMaxLeft); -// rightAxisInfo.drawAxis(this, -// m_chartOverlaySet, -// m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// foregroundRGBA, -// yMinRight, -// yMaxRight); -// topAxisInfo.drawAxis(this, -// m_chartOverlaySet, -// m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// foregroundRGBA, -// xMinTop, -// xMaxTop); -// bottomAxisInfo.drawAxis(this, -// m_chartOverlaySet, -// m_fixedPipelineDrawing->getContextSharingGroupPointer(), -// m_fixedPipelineDrawing->mouseX, -// m_fixedPipelineDrawing->mouseY, -// foregroundRGBA, -// xMinBottom, -// xMaxBottom); -// -// -// drawChartGraphicsBoxAndSetViewport(tabViewportX, -// tabViewportY, -// tabViewportWidth, -// tabViewportHeight, -// m_chartOverlaySet->getAxisLineThickness(), -// topTitleHeight, -// bottomAxisHeight, -// topAxisHeight, -// leftAxisWidth, -// rightAxisWidth, -// true, /* draw the box */ -// chartGraphicsDrawingViewport); -// } - /* * When the user is editing an axis minimum or maximum value, * their difference may become zero which will cause @@ -914,13 +857,23 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); + + /* + * Each bar is drawn using two triangles + */ + CaretAssert(histogramPrimitives->getBarsPrimitive()->getPrimitiveType() + == GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); + if (primitiveIndex > 0) { + primitiveIndex /= 2; + } glPopMatrix(); } else if (drawEnvelopeFlag) { /* * Increase line width for identification */ - BrainOpenGL::setLineWidth(envelopeLineWidth * 3.0f); + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + envelopeLineWidth * 3.0f); GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -943,7 +896,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { - BrainOpenGL::setLineWidth(envelopeLineWidth); + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + envelopeLineWidth); m_fixedPipelineDrawing->enableLineAntiAliasing(); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); @@ -1330,6 +1284,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT primitiveIndex, primitiveDepth); if (primitiveIndex >= 0) { + /* + * Two triangles per cell so divided the primitive index by two + */ + CaretAssert(matrixPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); + primitiveIndex /= 2; + int32_t numberOfRows = 0; int32_t numberOfColumns = 0; matrixChart->getMatrixDimensions(numberOfRows, @@ -1394,11 +1354,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const bool limitSelectionToTriangularFlag = false; for (auto rowIndex : selectedRowIndices) { -// std::unique_ptr rowOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, -// highlightRGBA)); -// rowOutlineData4f->reserveForNumberOfVertices(4); - float minX = 0; float maxX = numberOfColumns; const float minY = numberOfRows - rowIndex - 1; @@ -1420,12 +1375,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); -// rowOutlineData4f->addVertex(minX, minY); -// rowOutlineData4f->addVertex(maxX, minY); -// rowOutlineData4f->addVertex(maxX, maxY); -// rowOutlineData4f->addVertex(minX, maxY); -// BrainOpenGL::setLineWidth(highlightLineWidth); -// //drawPrimitivePrivate(rowOutlineData4f.get()); GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); rowOutlineData->reserveForNumberOfVertices(4); @@ -1442,11 +1391,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } for (auto columnIndex : selectedColumnIndices) { -// std::unique_ptr columnOutlineData4f -// = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP, -// highlightRGBA)); -// columnOutlineData4f->reserveForNumberOfVertices(4); - const float minX = columnIndex; const float maxX = columnIndex + 1; float minY = 0; @@ -1468,12 +1412,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); -// columnOutlineData4f->addVertex(minX, minY); -// columnOutlineData4f->addVertex(maxX, minY); -// columnOutlineData4f->addVertex(maxX, maxY); -// columnOutlineData4f->addVertex(minX, maxY); -// BrainOpenGL::setLineWidth(highlightLineWidth); -// //drawPrimitivePrivate(columnOutlineData4f.get()); GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); columnOutlineData->reserveForNumberOfVertices(4); @@ -2540,7 +2478,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh m_labelText->getCoordinate()->getXYZ(xyz); if (chartDrawing->m_identificationModeFlag) { /* - * For identification simply draw a box in a single quad + * For identification simply draw a box using a triangle strip */ int32_t primitiveIndex = -1; float primitiveDepth = 0.0; @@ -2550,60 +2488,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh m_tabViewportWidth, m_tabViewportHeight, bottomLeft, bottomRight, topRight, topLeft); - std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, - foregroundFloatRGBA)); + std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, + foregroundFloatRGBA)); boxPrimitive->reserveForNumberOfVertices(4); + boxPrimitive->addVertex(topLeft); boxPrimitive->addVertex(bottomLeft); - boxPrimitive->addVertex(bottomRight); boxPrimitive->addVertex(topRight); - boxPrimitive->addVertex(topLeft); + boxPrimitive->addVertex(bottomRight); boxPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); -// Complete offsets and maybe examine alignments from the text annotation to set the offsets -// -// float horizSize = 0.0f; -// float vertSize = 0.0f; -// switch (m_axisLocation) { -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: -// horizSize = m_labelWidth; -// vertSize = m_labelHeight; -// xyz[1] += (vertSize / 2.0f); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: -// horizSize = m_labelWidth; -// vertSize = m_labelHeight; -// xyz[1] -= (vertSize / 2.0f); -// break; -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: -// /* -// * Label is drawn rotated 90 degrees ! -// */ -// horizSize = m_labelHeight; -// vertSize = m_labelWidth; -// xyz[0] += (horizSize / 2.0f); -// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: -// /* -// * Label is drawn rotated 90 degrees ! -// */ -// horizSize = m_labelHeight; -// vertSize = m_labelWidth; -// xyz[0] -= (horizSize / 2.0f); -// break; -// } -// -// const float halfWidth = horizSize / 2.0f; -// const float halfHeight = vertSize / 2.0f; -// const float left = xyz[0] - halfWidth; -// const float right = xyz[0] + halfWidth; -// const float bottom = xyz[1] - halfHeight; -// const float top = xyz[1] + halfHeight; -// std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, -// foregroundFloatRGBA)); -// boxPrimitive->addVertex(left, bottom, 0.0f); -// boxPrimitive->addVertex(right, bottom, 0.0f); -// boxPrimitive->addVertex(right, top, 0.0f); -// boxPrimitive->addVertex(left, top, 0.0f); - GraphicsEngineDataOpenGL::drawWithSelection(boxPrimitive.get(), mouseX, mouseY, diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 3e216ff05..24a630b07 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -88,11 +88,6 @@ m_histogramContentType(histogramContentType) */ ChartableTwoFileHistogramChart::~ChartableTwoFileHistogramChart() { -// for (auto mapHistoPair : m_indexHistogramsMap) { -// delete mapHistoPair.second; -// } -// m_indexHistogramsMap.clear(); - delete m_sceneAssistant; } @@ -134,7 +129,6 @@ void ChartableTwoFileHistogramChart::invalidateAllColoring() { m_mapHistogramPrimitives.clear(); - //std::cout << "Invalidating histograms..." << std::endl; } /** @@ -421,7 +415,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m * Use Lines when drawing envelope (two vertices per line) * Using quads and lines simplifies identification of individual bars in the histogram */ - GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); + GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES); envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); @@ -465,30 +459,42 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); - thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); + thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); switch (paletteColorMapping->getThresholdTest()) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: { - thresholdPrimitive->reserveForNumberOfVertices(8); + thresholdPrimitive->reserveForNumberOfVertices(12); + + thresholdPrimitive->addVertex(minX, maxY, threshRGBA); thresholdPrimitive->addVertex(minX, minY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(minX, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); thresholdPrimitive->addVertex(maxX, minY, threshRGBA); - thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(maxX, minY, threshRGBA); + thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); } break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: { - thresholdPrimitive->reserveForNumberOfVertices(4); + thresholdPrimitive->reserveForNumberOfVertices(6); + + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); - thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); + thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); } break; } @@ -548,22 +554,20 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m } if (barsSolidColorFlag) { - /* - * Use alpha from normal coloring - */ barsSolidColorRGBA[3] = rgba[3]; - barsPrimitive->addVertex(xMin, yMin, barsSolidColorRGBA); - barsPrimitive->addVertex(xMax, yMin, barsSolidColorRGBA); - barsPrimitive->addVertex(xMax, yMax, barsSolidColorRGBA); - barsPrimitive->addVertex(xMin, yMax, barsSolidColorRGBA); - } - else { - barsPrimitive->addVertex(xMin, yMin, rgba); - barsPrimitive->addVertex(xMax, yMin, rgba); - barsPrimitive->addVertex(xMax, yMax, rgba); - barsPrimitive->addVertex(xMin, yMax, rgba); } + const float* cellRGBA = (barsSolidColorFlag ? barsSolidColorRGBA : rgba); + + /* Triangle One for Cell*/ + barsPrimitive->addVertex(xMin, yMax, cellRGBA); + barsPrimitive->addVertex(xMin, yMin, cellRGBA); + barsPrimitive->addVertex(xMax, yMin, cellRGBA); + /* Triangle Two for Cell */ + barsPrimitive->addVertex(xMin, yMax, cellRGBA); + barsPrimitive->addVertex(xMax, yMin, cellRGBA); + barsPrimitive->addVertex(xMax, yMax, cellRGBA); + if (envelopeSolidColorFlag) { const float envelopeX = x + halfBucketWidth; if (i == 0) { diff --git a/src/Files/CiftiMappableDataFile.cxx b/src/Files/CiftiMappableDataFile.cxx index 73b42dde0..bc053a77b 100644 --- a/src/Files/CiftiMappableDataFile.cxx +++ b/src/Files/CiftiMappableDataFile.cxx @@ -1526,8 +1526,17 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr if (getMatrixForChartingRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { const int32_t numberOfCells = numberOfRows * numberOfColumns; if (numberOfCells > 0) { - matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS); - matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 4); // QUADS + switch (gridMode) { + case MatrixGridMode::FILLED: + matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); + matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 6); // 2 triangles per cell, 3 vertices per triangle + break; + case MatrixGridMode::OUTLINE: + /* Lines are used around each cell to simplify upper/lower triangular options */ + matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES); + matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 8); // 4 lines per cell, 2 vertices per line + break; + } matrixPrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); /* @@ -1551,7 +1560,7 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr * not displayed due to the triangular view selection. * The reason is that it greatly simplifies identification as * one can derive the row and column from the primitive index. - * Using quads also simplifies identification. Lastly, since + * Using triangles also simplifies identification. Lastly, since * OpenGL buffers are used, drawing is very fast. */ int32_t rgbaOffset = 0; @@ -1627,32 +1636,32 @@ CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTr switch (gridMode) { case MatrixGridMode::FILLED: - if (drawCellFlag) { - matrixPrimitive->addVertex(cellX, cellY, 0.0, rgba); - matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, rgba); - matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, rgba); - matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, rgba); - } - else { - matrixPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); - } + { + const float* cellRGBA = (drawCellFlag ? rgba : cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); + + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); + } break; case MatrixGridMode::OUTLINE: - if (drawCellFlag) { - matrixPrimitive->addVertex(cellX, cellY, 0.0, cellOutlineRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellOutlineRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellOutlineRGBA); - matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellOutlineRGBA); - } - else { - matrixPrimitive->addVertex(cellX, cellY, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellNotDrawRGBA); - matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellNotDrawRGBA); - } + { + const float* cellRGBA = (drawCellFlag ? cellOutlineRGBA : cellNotDrawRGBA); + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); + + matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); + + matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); + + matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); + matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); + } break; } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 4e4f926e4..c034eb124 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -15,7 +15,6 @@ EventGraphicsOpenGLDeleteTextureName.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h -GraphicsOpenGLPolylineQuads.h GraphicsOpenGLPolylineTriangles.h GraphicsOpenGLTextureName.h GraphicsPrimitive.h @@ -34,7 +33,6 @@ EventGraphicsOpenGLDeleteTextureName.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx -GraphicsOpenGLPolylineQuads.cxx GraphicsOpenGLPolylineTriangles.cxx GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index b5750c94b..f5219090b 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -30,7 +30,6 @@ #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" -#include "GraphicsOpenGLPolylineQuads.h" #include "GraphicsOpenGLPolylineTriangles.h" #include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" @@ -479,12 +478,6 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: @@ -508,9 +501,6 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) } else if (workbenchLineFlag) { AString errorMessage; -// primitiveToDraw = GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(openglContextPointer, -// primitive, -// errorMessage); primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(primitive, errorMessage); if (primitiveToDraw == NULL) { @@ -706,12 +696,6 @@ GraphicsEngineDataOpenGL::drawWithSelection(GraphicsPrimitive* primitive, break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: @@ -1000,15 +984,6 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, openGLPrimitiveType = GL_POINTS; glPointSize(getPointDiameterForDrawingInPixels(primitive)); break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - openGLPrimitiveType = GL_POLYGON; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - openGLPrimitiveType = GL_QUAD_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - openGLPrimitiveType = GL_QUADS; - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: openGLPrimitiveType = GL_TRIANGLE_FAN; break; diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx b/src/Graphics/GraphicsOpenGLPolylineQuads.cxx deleted file mode 100644 index 3f0ad4424..000000000 --- a/src/Graphics/GraphicsOpenGLPolylineQuads.cxx +++ /dev/null @@ -1,1335 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include - -#define __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ -#include "GraphicsOpenGLPolylineQuads.h" -#undef __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "GraphicsEngineDataOpenGL.h" -#include "CaretOpenGLInclude.h" -#include "GraphicsPrimitive.h" -#include "GraphicsPrimitiveV3fC4f.h" -#include "GraphicsPrimitiveV3fC4ub.h" -#include "MathFunctions.h" -#include "Matrix4x4.h" - -using namespace caret; - - - -/** - * \class caret::GraphicsOpenGLPolylineQuads - * \brief Converts lines to rectangles - * \ingroup Graphics - * - * Convert lines to polygons. - * OpenGL lines have a limited width whose maximum is often exceeded. - * Convert the lines to rectangles. All drawing is done in - * two dimensional windows coordinates. - */ - -/** - * Destructor. - */ -GraphicsOpenGLPolylineQuads::~GraphicsOpenGLPolylineQuads() -{ - CaretAssertMessage(0, "This class should not be used. Instead, use GraphicsOpenGLPolylineTriangles"); -} - -/** - * Draw the given graphics primitive containing lines - * by converting the lines to polygons. - * - * @param primtive - * The graphics primitive. - */ -bool -GraphicsOpenGLPolylineQuads::draw(const GraphicsPrimitive* primitive) -{ - CaretAssert(primitive); - if (primitive->isValid()) { - float lineWidth = primitive->m_lineWidthValue; - - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: - { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; - } - break; - case GraphicsPrimitive::SizeType::PIXELS: - break; - } - - ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretLogSevere("INVALID color type NONE for graphics primitive"); - return false; - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - colorType = ColorType::BYTE_RGBA_PER_VERTEX; - break; - } - - LineType lineType = LineType::LINES; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - lineType = LineType::LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - lineType = LineType::LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - lineType = LineType::LINES; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - CaretLogSevere("POINTS is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - CaretLogSevere("POLYGON is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - CaretLogSevere("QUADS is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - CaretLogSevere("TRIANGLES is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - break; - case GraphicsPrimitive::PrimitiveType::SPHERES: - CaretLogSevere("SPHERES is not a valid line drawing type"); - break; - } - - return drawLinesPrivate(primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); - } - - return false; -} - -/** - * Convert a Workbench Line Primitive to an OpenGL primitive. - * OpenGL has limits on the width of the lines that it draws. This method will - * convert the lines into polygons so that any line width may be drawn. - * - * @param primitive - * A graphics primitive with a primitive type that is one of the - * WORKBENCH_LINE* types. - * @param errorMessageOut - * Upon exit contains an error message if conversion failed. - * @return - * A graphics primitive with an OPENGL_QUADS type that draws the lines - * using polygons. NULL if error. - */ -GraphicsPrimitive* -GraphicsOpenGLPolylineQuads::convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, - AString& errorMessageOut) -{ - CaretAssert(primitive); - errorMessageOut.clear(); - - if ( ! primitive->isValid()) { - errorMessageOut = "Primitive is not valid."; - return NULL; - } - - float lineWidth = primitive->m_lineWidthValue; - - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: - { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; - } - break; - case GraphicsPrimitive::SizeType::PIXELS: - break; - } - - ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - errorMessageOut = "INVALID color type NONE for graphics primitive"; - return NULL; - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - colorType = ColorType::BYTE_RGBA_PER_VERTEX; - break; - } - - LineType lineType = LineType::LINES; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - lineType = LineType::LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: - lineType = LineType::LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - lineType = LineType::LINES; - break; - case GraphicsPrimitive::PrimitiveType::SPHERES: - errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; - break; - } - - if ( ! errorMessageOut.isEmpty()) { - return NULL; - } - - GraphicsOpenGLPolylineQuads lineConversion(primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); - - GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); - - return primitiveOut; -} - -/** - * Constructor. - * - * @param xyz - * The XYZ vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * The primitive will stop at the index and not connect to the next index. - * @param lineThicknessPixels - * Thickness of lines in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - */ -GraphicsOpenGLPolylineQuads::GraphicsOpenGLPolylineQuads(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -: m_inputXYZ(xyz), -m_inputFloatRGBA(floatRGBA), -m_inputByteRGBA(byteRGBA), -m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), -m_lineThicknessPixels(lineThicknessPixels), -m_colorType(colorType), -m_lineType(lineType) -{ - -} - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param xyz - * The vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * @param lineThicknessPixels - * Thickness of line in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLPolylineQuads::drawLinesPrivate(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -{ - GraphicsOpenGLPolylineQuads lineDrawing(xyz, - floatRGBA, - byteRGBA, - vertexPrimitiveRestartIndices, - lineThicknessPixels, - colorType, - lineType); - return lineDrawing.performDrawing(); -} - -/** - * Convert the content of this instance to a new graphics primitive - * that draws the lines as polygons. - * - * @param errorMessageOut - * Contains error message if conversion failed. - * @return - * Pointer to new primitive or NULL if there is an error. - * Caller must destroy the primitive. - */ -GraphicsPrimitive* -GraphicsOpenGLPolylineQuads::convertLinesToPolygons(AString& errorMessageOut) -{ - errorMessageOut.clear(); - - const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); - if (numVertices < 2) { - errorMessageOut = ("Invalid number of vertices=" - + AString::number(numVertices) - + " for line drawing. Must be at least 2."); - return NULL; - } - - const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); - const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numByteRGBA / 4; - if (numVertices != numRgbaVertices) { - errorMessageOut = ("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have byte coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return NULL; - } - } - break; - case ColorType::BYTE_RGBA_SOLID: - if (numByteRGBA < 4) { - errorMessageOut = ("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numByteRGBA)); - return NULL; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numFloatRGBA / 4; - if (numVertices != numRgbaVertices) { - errorMessageOut = ("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have float coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return NULL; - } - } - break; - case ColorType::FLOAT_RGBA_SOLID: - if (numFloatRGBA < 4) { - errorMessageOut = ("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numFloatRGBA)); - return NULL; - } - break; - } - - saveOpenGLState(); - - createProjectionMatrix(); - - createWindowCoordinatesFromVertices(); - - const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); - if (numWindowPoints >= 2) { - convertLineSegmentsToQuads(); - - joinQuads(); - - CaretAssert(m_primitive); - } - - restoreOpenGLState(); - - GraphicsPrimitive* primitiveOut = NULL; - - if (m_primitive->isValid()) { - if (m_primitiveByteColor.get() != NULL) { - primitiveOut = m_primitiveByteColor.release(); - } - else if (m_primitiveFloatColor.get() != NULL) { - primitiveOut = m_primitiveFloatColor.release(); - } - else { - CaretAssert(0); - errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; - } - } - else { - errorMessageOut = "Converted primitive is invalid."; - } - - return primitiveOut; -} - - -/** - * Perform the line drawinhg. - * - * @return - * True if no errors, false if errors. - */ -bool -GraphicsOpenGLPolylineQuads::performDrawing() -{ - const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); - if (numVertices < 2) { - CaretLogWarning("Invalid number of vertices=" - + AString::number(numVertices) - + " for line drawing. Must be at least 2."); - return false; - } - - const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); - const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numByteRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have byte coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::BYTE_RGBA_SOLID: - if (numByteRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numByteRGBA)); - return false; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numFloatRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have float coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::FLOAT_RGBA_SOLID: - if (numFloatRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numFloatRGBA)); - return false; - } - break; - } - - saveOpenGLState(); - - createProjectionMatrix(); - - createWindowCoordinatesFromVertices(); - - const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); - if (numWindowPoints >= 2) { - convertLineSegmentsToQuads(); - - joinQuads(); - - CaretAssert(m_primitive); - if (m_primitive->isValid()) { - drawQuads(); - } - } - - restoreOpenGLState(); - - return true; -} - -/** - * Save the OpenGL State. - */ -void -GraphicsOpenGLPolylineQuads::saveOpenGLState() -{ - glPushAttrib(GL_COLOR_BUFFER_BIT - | GL_ENABLE_BIT - | GL_HINT_BIT - | GL_LIGHTING_BIT - | GL_POLYGON_BIT); - - /* - * For anti-aliasing requires sorting polygons - * and turning of depth testing - */ - const bool drawWithAntiAliasingFlag = false; - if (drawWithAntiAliasingFlag) { - glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); - glEnable(GL_BLEND); - glHint(GL_POLYGON_SMOOTH_HINT, - GL_NICEST); - glEnable(GL_POLYGON_SMOOTH); - } - - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glGetIntegerv(GL_POLYGON_MODE, - m_savedPolygonMode); - - glGetIntegerv(GL_VIEWPORT, - m_savedViewport); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); -} - -/** - * Restore the OpenGL State. - */ -void -GraphicsOpenGLPolylineQuads::restoreOpenGLState() -{ - glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); - glPolygonMode(GL_BACK, m_savedPolygonMode[1]); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); - - glPopAttrib(); -} - -/** - * Create the projection matrix. - */ -void -GraphicsOpenGLPolylineQuads::createProjectionMatrix() -{ - GLdouble modelviewArray[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, - modelviewArray); - Matrix4x4 modelviewMatrix; - modelviewMatrix.setMatrixFromOpenGL(modelviewArray); - - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, - projectionArray); - - m_projectionMatrix.setMatrixFromOpenGL(projectionArray); - //m_projectionMatrix.postmultiply(modelviewMatrix); - m_projectionMatrix.premultiply(modelviewMatrix); -} - - -/** - * Create window coordinates from the input vertices. - */ -void -GraphicsOpenGLPolylineQuads::createWindowCoordinatesFromVertices() -{ - const float coincidentMaxDistSQ = (0.01f * 0.01f); - - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - - int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); - int32_t iStep = 1; - switch (m_lineType) { - case LineType::LINES: - iStep = 2; - if (MathFunctions::isOddNumber(numInputPoints)) { - CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); - --numInputPoints; - } - break; - case LineType::LINE_LOOP: - iStep = 1; - break; - case LineType::LINE_STRIP: - iStep = 1; - break; - } - - m_vertexWindowXYZ.reserve(numInputPoints * 3); - m_vertexWindowInputIndices.reserve(numInputPoints); - - /* - * Coincident points that result in zero length - * line segments are filtered out - */ - for (int32_t i = 0; i < numInputPoints; i += iStep) { - const int32_t i3 = i * 3; - - /* - * Convert model coordinate to a window coordinate - * as described by the documentation from gluProject(). - */ - float windowXYZ[3]; - CaretAssertVectorIndex(m_inputXYZ, i3 + 1); - convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); - - if (iStep == 1) { - if (i > 0) { - const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); - CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); - const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, - &m_vertexWindowXYZ[previousPointOffset]); - if (distSQ < coincidentMaxDistSQ) { - CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); - continue; - } - } - - m_vertexWindowXYZ.push_back(windowXYZ[0]); - m_vertexWindowXYZ.push_back(windowXYZ[1]); - m_vertexWindowXYZ.push_back(windowXYZ[2]); - m_vertexWindowInputIndices.push_back(i); - } - else if (iStep == 2) { - const int32_t iNext3 = (i + 1) * 3; - float windowNextXYZ[3]; - CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); - convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], - windowNextXYZ); - - const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, - windowNextXYZ); - if (distSQ < coincidentMaxDistSQ) { - CaretLogFine("Filtered out line pairs conincident points " - + AString::number(i) - + " and " - + AString::number(i + 1)); - continue; - } - m_vertexWindowXYZ.push_back(windowXYZ[0]); - m_vertexWindowXYZ.push_back(windowXYZ[1]); - m_vertexWindowXYZ.push_back(windowXYZ[2]); - m_vertexWindowInputIndices.push_back(i); - - m_vertexWindowXYZ.push_back(windowNextXYZ[0]); - m_vertexWindowXYZ.push_back(windowNextXYZ[1]); - m_vertexWindowXYZ.push_back(windowNextXYZ[2]); - m_vertexWindowInputIndices.push_back(i + 1); - } - else { - CaretAssertMessage(0, "Invalid step value"); - } - - if (m_debugFlag) { - GLdouble modelviewArray[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); - GLdouble winX, winY, winZ; - gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], - modelviewArray, projectionArray, viewport, - &winX, &winY, &winZ); - std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; - std::cout << " Pt " << i << ": " - << winX << ", " << winY << ", " << winZ << std::endl; - std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; - } - } - - CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); -} - -/** - * Convert from a model coordinate to a window coordinate. - * - * @param modelXYZ - * The coordinate in model space. - * @param windowXYZOut - * Output with coordinate in window space. - */ -void -GraphicsOpenGLPolylineQuads::convertFromModelToWindowCoordinate(const float modelXYZ[3], - float windowXYZOut[3]) const -{ - float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; - m_projectionMatrix.multiplyPoint4(xyzw); - windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); - windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); - windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; - - /* - * From OpenGL Programming Guide 3rd Ed, p 133: - * - * If the near value is 1.0 and the far value is 3.0, - * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. - * So, negate the Z-value to be negative. - */ - windowXYZOut[2] = -windowXYZOut[2]; -} - -/** - * Create a quad from the two window vertices - * - * @param indexOne - * Index of first vertex. - * @param indexTwo - * Index of second vertex. - */ -void -GraphicsOpenGLPolylineQuads::createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo) -{ - const int32_t iOne3 = indexOne * 3; - CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); - const int32_t iTwo3 = indexTwo * 3; - CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); - float x1 = m_vertexWindowXYZ[iOne3]; - float y1 = m_vertexWindowXYZ[iOne3 + 1]; - float z1 = m_vertexWindowXYZ[iOne3 + 2]; - float x2 = m_vertexWindowXYZ[iTwo3]; - float y2 = m_vertexWindowXYZ[iTwo3 + 1]; - float z2 = m_vertexWindowXYZ[iTwo3 + 2]; - - /* - * Normalized vector from start to end on line segment in 2D coordinates - */ - float startToEndVector[3] = { - x2 - x1, - y2 - y1, - 0.0f - }; - const float lineLength = MathFunctions::normalizeVector(startToEndVector); - if (lineLength < 0.001f) { - CaretLogWarning("This should not happen: Failure to filter coincident points with indices=" - + AString::number(indexOne) - + ", " - + AString::number(indexTwo) - + " Coordinates: " - + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") - + " " - + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); - } - - /* - * Create a perpendicualar vector to the line segment - */ - float perpendicularVector[3] = { - startToEndVector[1], - -startToEndVector[0], - 0.0f - }; - - /* - * "Width" of rectangle - */ - const float halfWidth = m_lineThicknessPixels / 2.0f; - const float halfWidthX = perpendicularVector[0] * halfWidth; - const float halfWidthY = perpendicularVector[1] * halfWidth; - - /* - * Points of the rectangle - * They should be counter-clockwise oriented - */ - float p1[3] = { - x1 - halfWidthX, - y1 - halfWidthY, - z1 - }; - float p2[3] = { - x1 + halfWidthX, - y1 + halfWidthY, - z1 - }; - float p3[3] = { - x2 + halfWidthX, - y2 + halfWidthY, - z2 - }; - float p4[3] = { - x2 - halfWidthX, - y2 - halfWidthY, - z2 - }; - - /* - * Indices to input coloring. - * Note that coincident points may be removed - */ - CaretAssertVectorIndex(m_vertexWindowInputIndices, indexOne); - const int32_t indexOneRgba = m_vertexWindowInputIndices[indexOne]; - CaretAssertVectorIndex(m_vertexWindowInputIndices, indexTwo); - const int32_t indexTwoRgba = m_vertexWindowInputIndices[indexTwo]; - - /* - * RGBA for the points P1, P2, P3, P4 - */ - int32_t rgbaOffsetP1P2 = 0; - int32_t rgbaOffsetP3P4 = 0; - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOneRgba * 4; - rgbaOffsetP3P4 = indexTwoRgba * 4; - break; - case ColorType::BYTE_RGBA_SOLID: - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - rgbaOffsetP1P2 = indexOneRgba * 4; - rgbaOffsetP3P4 = indexTwoRgba * 4; - break; - case ColorType::FLOAT_RGBA_SOLID: - break; - } - - float crossProduct[3]; - MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); - if (crossProduct[2] == 0.0f) { - /* This should get caught by vector length check above */ - } - - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - case ColorType::BYTE_RGBA_SOLID: - { - CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); - const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; - CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); - const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; - - CaretAssert(m_primitiveByteColor.get()); - if (crossProduct[2] <= 0.0f) { - m_primitiveByteColor->addVertex(p1, rgbaP12); - m_primitiveByteColor->addVertex(p2, rgbaP12); - m_primitiveByteColor->addVertex(p3, rgbaP34); - m_primitiveByteColor->addVertex(p4, rgbaP34); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_primitiveByteColor->addVertex(p2, rgbaP12); - m_primitiveByteColor->addVertex(p1, rgbaP12); - m_primitiveByteColor->addVertex(p4, rgbaP34); - m_primitiveByteColor->addVertex(p3, rgbaP34); - } - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - case ColorType::FLOAT_RGBA_SOLID: - { - CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); - const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; - CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); - const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; - - CaretAssert(m_primitiveFloatColor.get()); - if (crossProduct[2] <= 0.0f) { - m_primitiveFloatColor->addVertex(p1, rgbaP12); - m_primitiveFloatColor->addVertex(p2, rgbaP12); - m_primitiveFloatColor->addVertex(p3, rgbaP34); - m_primitiveFloatColor->addVertex(p4, rgbaP34); - } - else { - std::cout << "Flipped Quad" << std::endl; - m_primitiveFloatColor->addVertex(p2, rgbaP12); - m_primitiveFloatColor->addVertex(p1, rgbaP12); - m_primitiveFloatColor->addVertex(p4, rgbaP34); - m_primitiveFloatColor->addVertex(p3, rgbaP34); - } - } - break; - } - - m_quadInfo.push_back(QuadInfo(indexOne, indexTwo)); -} - -/** - * Join quads to create connected line segments - * without cracks where the quads join together. - */ -void -GraphicsOpenGLPolylineQuads::joinQuads() -{ - CaretAssert(m_primitive); - - const int32_t numQuads = static_cast(m_quadInfo.size()); - const int32_t numQuadsMinusOne = numQuads - 1; - - int32_t numQuadsToConnect = 0; - switch (m_lineType) { - case LineType::LINES: - numQuadsToConnect = 0; - break; - case LineType::LINE_LOOP: - numQuadsToConnect = numQuads; - break; - case LineType::LINE_STRIP: - numQuadsToConnect = numQuadsMinusOne; - break; - } - - /* - * Perform joins of connected quads - */ - for (int32_t i = 0; i < numQuadsToConnect; i++) { - CaretAssertVectorIndex(m_quadInfo, i); - const QuadInfo& quad = m_quadInfo[i]; - - const int32_t nextQuadIndex = ((i < numQuadsMinusOne) ? (i + 1) : 0); - CaretAssertVectorIndex(m_quadInfo, nextQuadIndex); - const QuadInfo& nextQuad = m_quadInfo[nextQuadIndex]; - - /* - * Does quad "i" connect to quad "i+1" ? - */ - if (quad.m_vertexTwoIndex == nextQuad.m_vertexOneIndex) { - const int32_t quadOneVertexIndex = i * 4; - const int32_t quadTwoVertexIndex = nextQuadIndex * 4; - - performJoin(quad.m_vertexOneIndex, - quad.m_vertexTwoIndex, - nextQuad.m_vertexTwoIndex, - quadOneVertexIndex, - quadTwoVertexIndex); - } - } -} - -/** - * Perform a join using the last two vertices in quad one - * and the first two vertices in quad two - * - * @param windowVertexIndexOne - * Index of first window vertex from line segment - * @param windowVertexIndexTwo - * Index of second window from line segment - * @param windowVertexIndexThree - * Index of three window from line segment - * @param quadOneVertexIndex - * Index of first vertex in first quad - * @param quadTwoVertexIndex - * Index of first vertex in second quad - */ -void -GraphicsOpenGLPolylineQuads::performJoin(const int32_t windowVertexIndexOne, - const int32_t windowVertexIndexTwo, - const int32_t windowVertexIndexThree, - const int32_t quadOneVertexIndex, - const int32_t quadTwoVertexIndex) -{ - if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; - CaretAssert(m_primitive); - - /* - * Determine if the junction of the two consecutive - * line segments in window coordinates makes a left - * or right turn - */ - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); - const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], - &m_vertexWindowXYZ[windowVertexIndexTwo * 3], - &m_vertexWindowXYZ[windowVertexIndexThree * 3]); - - - int32_t quadOneSideBeginVertexIndex = -1; - int32_t quadOneSideEndVertexIndex = -1; - int32_t quadTwoSideBeginVertexIndex = -1; - int32_t quadTwoSideEndVertexIndex = -1; - const float smallNumber = 0.001; - if (signedArea > smallNumber) { - if (m_debugFlag) std::cout << " Left Turn" << std::endl; - /* - * Right side is vertices two and three - */ - quadOneSideBeginVertexIndex = quadOneVertexIndex + 1; - quadOneSideEndVertexIndex = quadOneVertexIndex + 2; - quadTwoSideBeginVertexIndex = quadTwoVertexIndex + 1; - quadTwoSideEndVertexIndex = quadTwoVertexIndex + 2; - } - else if (signedArea < -smallNumber) { - if (m_debugFlag) std::cout << " Right Turn" << std::endl; - /* - * Right side is vertices 1 and 4 - */ - quadOneSideBeginVertexIndex = quadOneVertexIndex; - quadOneSideEndVertexIndex = quadOneVertexIndex + 3; - quadTwoSideBeginVertexIndex = quadTwoVertexIndex; - quadTwoSideEndVertexIndex = quadTwoVertexIndex + 3; - } - else { - if (m_debugFlag) std::cout << " Parallel" << std::endl; - return; - } - - const std::vector& xyz = m_primitive->getFloatXYZ(); - CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); - CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); - const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; - const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; - const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; - const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; - - /* - * Miter limit is a multiple of the line thickness - */ - const float miterLimit = m_lineThicknessPixels;// * 2.0f; - const float miterLimitSquared = miterLimit * miterLimit; - - /* - * Find location of where the edges in the quads intersect - */ - float intersectionXYZ[3]; - if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { - intersectionXYZ[2] = q1v1[2]; - if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; - - /* - * When the angle is very sharp, the miter point can be very long and pointy - * so limit to a multiplier of the line thickness - */ - CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); - const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; - const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, - intersectionXYZ); - if (distanceSquared > miterLimitSquared) { - /* - * Extend lines by the miter limit to create a new quad - */ - float newV1[3]; - createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); - float newV2[3]; - createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); - - m_quadJoins.push_back(QuadJoin(q1v2, - newV1, - newV2, //q2v1, - q2v1, //newV2, - quadOneSideEndVertexIndex, - quadTwoSideBeginVertexIndex)); - } - else { - /* - * Move the existing quad vertices to their intersection point - */ - m_primitive->replaceVertexFloatXYZ(quadOneSideEndVertexIndex, intersectionXYZ); - m_primitive->replaceVertexFloatXYZ(quadTwoSideBeginVertexIndex, intersectionXYZ); - } - } -} - -/** - * Create a vertex for a miter join when the length limit is exceeded - * - * @param v1 - * First vertex - * @param v2 - * Second vertex that is connected to the miter join vertex. - * @param miterLength - * Length of output vertex from v2 - * @param xyzOut - * Output with vertex used for miter join. - */ -void -GraphicsOpenGLPolylineQuads::createMiterJoinVertex(const float v1[3], - const float v2[3], - const float miterLength, - float xyzOut[3]) -{ - float n2[3]; - MathFunctions::subtractVectors(v2, v1, n2); - MathFunctions::normalizeVector(n2); - n2[0] *= miterLength; - n2[1] *= miterLength; - n2[2] *= miterLength; - xyzOut[0] = v2[0] + n2[0]; - xyzOut[1] = v2[1] + n2[1]; - xyzOut[2] = v2[2] + n2[2]; -} - -/** - * When the quads are joined, additional quads may be - * created to to fill in the gaps. - */ -void -GraphicsOpenGLPolylineQuads::addMiterJoinQuads() -{ - const int32_t numJoinQuads = static_cast(m_quadJoins.size()); - for (int32_t i = 0; i < numJoinQuads; i++) { - CaretAssertVectorIndex(m_quadJoins, i); - const QuadJoin& quadJoin = m_quadJoins[i]; - - /* - * Add the join quad to the primitive - */ - switch (m_primitive->getColorType()) { - case GraphicsPrimitive::ColorType::NONE: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - { - float rgba[4]; - m_primitiveFloatColor->getVertexFloatRGBA(quadJoin.m_primitiveOneTwoIndex, rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[0], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[3], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[6], rgba); - m_primitiveFloatColor->addVertex(&quadJoin.m_xyz[9], rgba); - } - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - { - uint8_t rgba[4]; - m_primitiveByteColor->getVertexByteRGBA(quadJoin.m_primitiveThreeFourIndex, rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[0], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[3], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[6], rgba); - m_primitiveByteColor->addVertex(&quadJoin.m_xyz[9], rgba); - } - break; - } - } -} - -/** - * Convert each line segment into a rectangle - * using the line width. "Length" of the - * rectangle is the length of the line segment - * and "width" of the rectangle is the line width. - */ -void -GraphicsOpenGLPolylineQuads::convertLineSegmentsToQuads() -{ - - const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); - - /* - * When estimating number of quads, - * include both the quads formed by the vertices - * and possible quads added for joining end points - */ - int32_t estimatedNumberOfQuads = 0; - switch (m_lineType) { - case LineType::LINES: - estimatedNumberOfQuads = numVertices / 2; - break; - case LineType::LINE_LOOP: - estimatedNumberOfQuads = numVertices * 2; - break; - case LineType::LINE_STRIP: - estimatedNumberOfQuads = (numVertices - 1) * 2; - break; - } - - m_primitive = NULL; - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - case ColorType::BYTE_RGBA_SOLID: - m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); - m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); - m_primitive = m_primitiveByteColor.get(); - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - case ColorType::FLOAT_RGBA_SOLID: - m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS)); - m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfQuads * 4); - m_primitive = m_primitiveFloatColor.get(); - break; - } - CaretAssert(m_primitive); - - m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); - - const int32_t numVerticesMinusOne = numVertices - 1; - - std::vector restartVertexFlags(numVertices, false); - for (auto index : m_vertexPrimitiveRestartIndices) { - restartVertexFlags[index] = true; - } - - /* - * Restart is disabled because it removes vertices that break joins - * Might want to draw all quads and use alpha=0 for quads that - * should not be joined. - */ - const bool restartEnabledFlag = true; - - switch (m_lineType) { - case LineType::LINES: - { - const int32_t numLineSegments = (numVertices / 2); - for (int32_t i = 0; i < numLineSegments; i++) { - const int32_t i2 = i * 2; - createQuadFromWindowVertices(i2, i2 + 1); - } - } - break; - case LineType::LINE_LOOP: - for (int32_t i = 0; i < numVerticesMinusOne; i++) { - CaretAssertVectorIndex(restartVertexFlags, i + 1); - if (restartVertexFlags[i + 1]) { - if (restartEnabledFlag) continue; - } - createQuadFromWindowVertices(i, i + 1); - } - createQuadFromWindowVertices(numVerticesMinusOne, 0); - break; - case LineType::LINE_STRIP: - for (int32_t i = 0; i < numVerticesMinusOne; i++) { - CaretAssertVectorIndex(restartVertexFlags, i + 1); - if (restartVertexFlags[i + 1]) { - if (restartEnabledFlag) continue; - } - createQuadFromWindowVertices(i, i + 1); - } - break; - } -} - -/** - * Draw the lines using quads. - */ -void -GraphicsOpenGLPolylineQuads::drawQuads() -{ - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(viewport[0], viewport[0] + viewport[2], - viewport[1], viewport[1] + viewport[3], - 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glPolygonMode(GL_FRONT, GL_FILL); - - CaretAssert(m_primitive); - GraphicsEngineDataOpenGL::draw(m_primitive); - if (m_debugFlag) { - std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } -} - -/** - * Get a description of this object's content. - * @return String describing this object's content. - */ -AString -GraphicsOpenGLPolylineQuads::toString() const -{ - return "GraphicsOpenGLPolylineQuads"; -} - diff --git a/src/Graphics/GraphicsOpenGLPolylineQuads.h b/src/Graphics/GraphicsOpenGLPolylineQuads.h deleted file mode 100644 index f2ee8030f..000000000 --- a/src/Graphics/GraphicsOpenGLPolylineQuads.h +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef __GRAPHICS_OPENGL_POLYLINE_QUADS_H__ -#define __GRAPHICS_OPENGL_POLYLINE_QUADS_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include -#include - -#include "CaretObject.h" -#include "Matrix4x4.h" - -namespace caret { - - class GraphicsPrimitive; - class GraphicsPrimitiveV3fC4f; - class GraphicsPrimitiveV3fC4ub; - - class GraphicsOpenGLPolylineQuads : public CaretObject { - - public: - /** - * Join tyupe of how connected lines are drawn to remove gaps between segments - */ - enum JoinType { - /** None */ - NONE, - /* Extends 'outsides' of lines to meet forming a pointed shape */ - MITER - }; - - virtual ~GraphicsOpenGLPolylineQuads(); - - static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, - AString& errorMessageOut); - - static bool draw(const GraphicsPrimitive* primitive); - -// static bool drawLinesPerVertexFloatColor(const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels); -// -// static bool drawLinesSolidFloatColor(const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineStripSolidFloatColor(const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineLoopSolidFloatColor(const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// -// static bool drawLinesPerVertexByteColor(const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels); -// -// static bool drawLinesSolidByteColor(const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineStripSolidByteColor(const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineLoopSolidByteColor(const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); - - // ADD_NEW_METHODS_HERE - - virtual AString toString() const; - - private: - /** - * Type of line coloring - */ - enum class ColorType { - /** Byte RGBA color at each vertex */ - BYTE_RGBA_PER_VERTEX, - /** One Byte RGBA color for all vertices */ - BYTE_RGBA_SOLID, - /** Float RGBA color at each vertex */ - FLOAT_RGBA_PER_VERTEX, - /** One Float RGBA color for all vertices */ - FLOAT_RGBA_SOLID - }; - - /** - * Type of line drawing - */ - enum class LineType { - /** Each pair of vertices is an independent line segment (GL_LINES) */ - LINES, - /** A connected set of lines forming a loop (last is automaticall connected to first) */ - LINE_LOOP, - /** A connected set of lines (last is not connected to first) */ - LINE_STRIP - }; - - /** - * Indices into input vertices of line - * that formed the quad - */ - class QuadInfo { - public: - QuadInfo(const int32_t vertexOneIndex, - const int32_t vertexTwoIndex) - : m_vertexOneIndex(vertexOneIndex), - m_vertexTwoIndex(vertexTwoIndex) { } - - int32_t m_vertexOneIndex; - int32_t m_vertexTwoIndex; - }; - - /** - * Quads created by joining of lines - */ - class QuadJoin { - public: - QuadJoin(const float xyzOne[3], - const float xyzTwo[3], - const float xyzThree[3], - const float xyzFour[3], - const int32_t primitiveOneTwoIndex, - const int32_t primitiveThreeFourIndex) - : m_primitiveOneTwoIndex(primitiveOneTwoIndex), - m_primitiveThreeFourIndex(primitiveThreeFourIndex) { - m_xyz.insert(m_xyz.end(), xyzOne, xyzOne + 3); - m_xyz.insert(m_xyz.end(), xyzTwo, xyzTwo + 3); - m_xyz.insert(m_xyz.end(), xyzThree, xyzThree + 3); - m_xyz.insert(m_xyz.end(), xyzFour, xyzFour + 3); - } - - std::vector m_xyz; - int32_t m_primitiveOneTwoIndex; - int32_t m_primitiveThreeFourIndex; - }; - - GraphicsOpenGLPolylineQuads(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); - - GraphicsOpenGLPolylineQuads(const GraphicsOpenGLPolylineQuads& obj); - - GraphicsOpenGLPolylineQuads& operator=(const GraphicsOpenGLPolylineQuads& obj) const; - - static bool drawLinesPrivate(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); - - bool performDrawing(); - - GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); - - void saveOpenGLState(); - - void restoreOpenGLState(); - - void createProjectionMatrix(); - - void convertFromModelToWindowCoordinate(const float modelXYZ[3], - float windowXYZOut[3]) const; - - void createWindowCoordinatesFromVertices(); - - void convertLineSegmentsToQuads(); - - void createQuadFromWindowVertices(const int32_t indexOne, - const int32_t indexTwo); - - void drawQuads(); - - void performJoin(const int32_t lineVertexIndexOne, - const int32_t lineVertexIndexTwo, - const int32_t lineVertexIndexThree, - const int32_t quadOneVertexIndex, - const int32_t quadTwoVertexIndex); - - void joinQuads(); - - void addMiterJoinQuads(); - - void createMiterJoinVertex(const float v1[3], - const float v2[3], - const float miterLength, - float xyzOut[3]); - - const std::vector& m_inputXYZ; - - const std::vector& m_inputFloatRGBA; - - const std::vector& m_inputByteRGBA; - - std::set m_vertexPrimitiveRestartIndices; - - const float m_lineThicknessPixels; - - const ColorType m_colorType; - - const LineType m_lineType; - - std::vector m_vertexWindowXYZ; - - std::vector m_vertexWindowInputIndices; - - JoinType m_joinType = JoinType::MITER; - - bool m_debugFlag = false; - - int m_savedPolygonMode[2]; - - int m_savedViewport[4]; - - Matrix4x4 m_projectionMatrix; - - /* - * The base class graphics primitive that points to - * either the Float or Byte Color primitive and can - * be used for non-color operations. NEVER delete - * this as it points to one the color primitive - */ - GraphicsPrimitive* m_primitive = NULL; - - std::unique_ptr m_primitiveFloatColor; - - std::unique_ptr m_primitiveByteColor; - - std::vector m_quadInfo; - - std::vector m_quadJoins; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ - // -#endif // __GRAPHICS_OPENGL_POLYLINE_QUADS_DECLARE__ - -} // namespace -#endif //__GRAPHICS_OPENGL_POLYLINE_QUADS_H__ diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index a560e289f..25ab75c9b 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -112,18 +112,6 @@ GraphicsOpenGLPolylineTriangles::draw(const GraphicsPrimitive* primitive) CaretLogSevere("POINTS is not a valid line drawing type"); return false; break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - CaretLogSevere("POLYGON is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - CaretLogSevere("QUAD_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - CaretLogSevere("QUADS is not a valid line drawing type"); - return false; - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); return false; @@ -170,8 +158,8 @@ GraphicsOpenGLPolylineTriangles::draw(const GraphicsPrimitive* primitive) * @param errorMessageOut * Upon exit contains an error message if conversion failed. * @return - * A graphics primitive with an OPENGL_QUADS type that draws the lines - * using polygons. NULL if error. + * A graphics primitive with an OPENGL_TRIANGLES type that draws the lines + * using triangles. NULL if error. */ GraphicsPrimitive* GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, @@ -227,15 +215,6 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - errorMessageOut = "Input type is OPENGL_POLYGON but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - errorMessageOut = "Input type is OPENGL_QUAD_STRIP but must be one of the POLYGONAL_LINE* types"; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - errorMessageOut = "Input type is OPENGL_QUADS but must be one of the POLYGONAL_LINE* types"; - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; break; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 4688a0291..d09fe73bd 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -381,33 +381,6 @@ GraphicsPrimitive::isValid() const break; case PrimitiveType::OPENGL_POINTS: break; - case PrimitiveType::OPENGL_POLYGON: - if (numXYZ < 3) { - CaretLogWarning("Polygon must have at least 3 vertices."); - } - break; - case PrimitiveType::OPENGL_QUAD_STRIP: - if (numXYZ < 4) { - CaretLogWarning("Quad strip must have at least 4 vertices."); - } - else { - const uint32_t extraVertices = numXYZ % 2; - if (extraVertices > 0) { - CaretLogWarning("Extra vertices for drawing quads ignored."); - } - } - break; - case PrimitiveType::OPENGL_QUADS: - if (numXYZ < 4) { - CaretLogWarning("Quads must have at least 4 vertices."); - } - else { - const uint32_t extraVertices = numXYZ % 4; - if (extraVertices > 0) { - CaretLogWarning("Extra vertices for drawing quads ignored."); - } - } - break; case PrimitiveType::OPENGL_TRIANGLE_FAN: if (numXYZ < 3) { CaretLogWarning("Triangle fan must have at least 3 vertices."); @@ -483,15 +456,6 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const case PrimitiveType::OPENGL_POINTS: s = "OpenGL Points"; break; - case PrimitiveType::OPENGL_POLYGON: - s = "OpenGL Polygon"; - break; - case PrimitiveType::OPENGL_QUAD_STRIP: - s = "OpenGL Quad Strip"; - break; - case PrimitiveType::OPENGL_QUADS: - s = "OpenGL Quads"; - break; case PrimitiveType::OPENGL_TRIANGLE_FAN: s = "OpenGL Triangle Fan"; break; @@ -666,12 +630,6 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const case PrimitiveType::OPENGL_POINTS: addPointSizeFlag = true; break; - case PrimitiveType::OPENGL_POLYGON: - break; - case PrimitiveType::OPENGL_QUAD_STRIP: - break; - case PrimitiveType::OPENGL_QUADS: - break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: @@ -1105,12 +1063,6 @@ GraphicsPrimitive::addPrimitiveRestart() break; case PrimitiveType::OPENGL_POINTS: break; - case PrimitiveType::OPENGL_POLYGON: - break; - case PrimitiveType::OPENGL_QUAD_STRIP: - break; - case PrimitiveType::OPENGL_QUADS: - break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: @@ -1316,7 +1268,7 @@ GraphicsPrimitive::getPointDiameter(SizeType& sizeTypeOut, */ void GraphicsPrimitive::setPointDiameter(const SizeType sizeType, - const float pointDiameter) + const float pointDiameter) const { m_pointSizeType = sizeType; m_pointDiameterValue = pointDiameter; @@ -1348,7 +1300,7 @@ GraphicsPrimitive::getLineWidth(SizeType& widthTypeOut, */ void GraphicsPrimitive::setLineWidth(const SizeType widthType, - const float lineWidth) + const float lineWidth) const { m_lineWidthType = widthType; m_lineWidthValue = lineWidth; @@ -1380,7 +1332,7 @@ GraphicsPrimitive::getSphereDiameter(SizeType& sizeTypeOut, */ void GraphicsPrimitive::setSphereDiameter(const SizeType sizeType, - const float sphereDiameter) + const float sphereDiameter) const { m_sphereSizeType = sizeType; m_sphereDiameterValue = sphereDiameter; diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 9754490eb..40d8edc42 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -84,7 +84,10 @@ namespace caret { }; /** - * Type of primitives for drawing + * Type of primitives for drawing. There are NO primitives equivalent to + * OpenGL's GL_QUAD_STRIP and GL_POLYGON. The reason is that these + * primitive types are removed in 3.x (probably 3.2). + * * Descriptions are copied from the glVertex man page. */ enum class PrimitiveType { @@ -111,23 +114,6 @@ namespace caret { * Treats each vertex as a single point. Vertex n defines point n. n points are drawn. */ OPENGL_POINTS, - /** - * Draws a single, convex polygon. Vertices 1 through n define this polygon. - */ - OPENGL_POLYGON, - /** - * Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair - * of vertices presented after the first pair. Vertices 2n-1, 2n, 2n+2, and 2n+1 define - * quadrilateral n. n/2 quadrilaterals are drawn. Note that the order in which vertices - * are used to construct a quadrilateral from strip data is different from that used with - * independent data. - */ - OPENGL_QUAD_STRIP, - /** - * Treats each group of four vertices as an independent quadrilateral. - * Vertices 4n-3, 4n-2, 4n-3, and 4n define quadrilateral n. n/4 quadrilaterals are drawn. - */ - OPENGL_QUADS, /** * Draws a connected group of triangles. One triangle is defined for each vertex * presented after the first two vertices. Vertices 1, n+1, and n+2 define triangle n. n-2 @@ -322,19 +308,19 @@ namespace caret { float& pointDiameterOut) const; void setPointDiameter(const SizeType sizeType, - const float pointDiameter); + const float pointDiameter) const; void getLineWidth(SizeType& widthTypeOut, float lineWidthOut) const; void setLineWidth(const SizeType widthType, - const float lineWidth); + const float lineWidth) const; void getSphereDiameter(SizeType& sizeTypeOut, float& sphereDiameterOut) const; void setSphereDiameter(const SizeType sizeType, - const float sphereDiameter); + const float sphereDiameter) const; GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); @@ -392,17 +378,17 @@ namespace caret { int32_t m_textureImageHeight = -1; - SizeType m_pointSizeType = SizeType::PIXELS; + mutable SizeType m_pointSizeType = SizeType::PIXELS; - float m_pointDiameterValue = 1.0f; + mutable float m_pointDiameterValue = 1.0f; - SizeType m_lineWidthType = SizeType::PIXELS; + mutable SizeType m_lineWidthType = SizeType::PIXELS; - float m_lineWidthValue = 1.0f; + mutable float m_lineWidthValue = 1.0f; - SizeType m_sphereSizeType = SizeType::PIXELS; + mutable SizeType m_sphereSizeType = SizeType::PIXELS; - float m_sphereDiameterValue = 1.0f; + mutable float m_sphereDiameterValue = 1.0f; mutable std::unique_ptr m_boundingBox; @@ -431,7 +417,6 @@ namespace caret { std::vector m_textureImageBytesRGBA; friend class GraphicsEngineDataOpenGL; - friend class GraphicsOpenGLPolylineQuads; friend class GraphicsOpenGLPolylineTriangles; friend class GraphicsPrimitiveSelectionHelper; diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index f9839d863..821377c46 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -70,6 +70,7 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() } m_numberOfVerticesPerPrimitive = 0; + m_vertexOffsetForPrimitive = 0; switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: @@ -87,20 +88,25 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: m_numberOfVerticesPerPrimitive = 1; break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POLYGON: - m_numberOfVerticesPerPrimitive = numberOfVertices; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUAD_STRIP: - CaretAssertMessage(0, "Not yet implemented"); - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_QUADS: - m_numberOfVerticesPerPrimitive = 4; - break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - CaretAssertMessage(0, "Not yet implemented"); + /* + * Assuming vertices start at ZERO + * Color is at vertex (i + 2): + * Vertex[2] is color for first triangle, + * Vertex[3] is color for second triangle... + */ + m_numberOfVerticesPerPrimitive = 1; + m_vertexOffsetForPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - CaretAssertMessage(0, "Not yet implemented"); + /* + * Assuming vertices start at ZERO + * Color is at vertex (i + 2): + * Vertex[2] is color for first triangle, + * Vertex[3] is color for second triangle... + */ + m_numberOfVerticesPerPrimitive = 1; + m_vertexOffsetForPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: m_numberOfVerticesPerPrimitive = 3; @@ -111,7 +117,7 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() } if (numberOfVertices > 0) { - const int32_t numberOfPrimitives = numberOfVertices / m_numberOfVerticesPerPrimitive; + const int32_t numberOfPrimitives = (numberOfVertices / m_numberOfVerticesPerPrimitive) - m_vertexOffsetForPrimitive; const int32_t maxPrimitivesSupported = 255 * 255 * 255; if (numberOfPrimitives > maxPrimitivesSupported) { const AString msg("Number of primitives for selection=" @@ -130,10 +136,12 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() m_selectionEncodedRGBA.resize(selectionRgbaSize); /* - * Encode the primitive index into the RGBA selection data + * Encode the primitive index into the RGBA selection data. */ int32_t indexRGBA = 0; - for (int32_t primitiveIndex = 0; primitiveIndex < numberOfPrimitives; primitiveIndex++) { + const int32_t startIndex = m_vertexOffsetForPrimitive; + const int32_t endIndex = m_vertexOffsetForPrimitive + numberOfPrimitives; + for (int32_t primitiveIndex = startIndex; primitiveIndex < endIndex; primitiveIndex++) { uint8_t blue = (uint8_t)(primitiveIndex & 0xff); uint8_t green = (uint8_t)((primitiveIndex >> 8) & 0xff); uint8_t red = (uint8_t)((primitiveIndex >> 16) & 0xff); @@ -166,6 +174,25 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() } m_selectionEncodedRGBA[indexRGBA+3] = vertexAlpha; + + if (primitiveIndex == startIndex) { + if (startIndex > 0) { + /* + * For THE FIRST triangle in a triangle strip or fan, + * its color is at vertex 2 (assuming first index is ZERO). + * Here we copy the color from vertex 2 to vertices + * 0 and 1. This is not absolutely necessary but it + * ensures correct color values and avoid a possible + * NaN from unintialized values. + */ + for (int32_t m = 0; m < startIndex; m++) { + const int32_t m4 = m * 4; + for (int32_t n = 0; n < 4; n++) { + m_selectionEncodedRGBA[m4 + n] = m_selectionEncodedRGBA[indexRGBA + n]; + } + } + } + } indexRGBA += 4; } } @@ -200,7 +227,7 @@ GraphicsPrimitiveSelectionHelper::getPrimitiveIndexFromEncodedRGBA(const uint8_t && (rgba[1] == m_selectionEncodedRGBA[i4+1]) && (rgba[2] == m_selectionEncodedRGBA[i4+2])) { if (m_selectionEncodedRGBA[i4+3] > 0) { - primitiveIndex = i / m_numberOfVerticesPerPrimitive; + primitiveIndex = (i / m_numberOfVerticesPerPrimitive) + m_vertexOffsetForPrimitive; } break; } diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.h b/src/Graphics/GraphicsPrimitiveSelectionHelper.h index 68f3bf2e0..096af0002 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.h +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.h @@ -58,13 +58,11 @@ namespace caret { GraphicsPrimitive* m_parentGraphicsPrimitive; int32_t m_numberOfVerticesPerPrimitive = 0; - - //int32_t m_numberOfSelectionIndicesPerPrimitive = 0; + + int32_t m_vertexOffsetForPrimitive = 0; std::vector m_selectionEncodedRGBA; - //std::vector m_selectionIndices; - // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 27bd5c7a0..698de6558 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -111,6 +111,7 @@ GraphicsShape::drawBoxOutlineByteColor(const float v1[3], { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, rgba)); + primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); @@ -152,6 +153,7 @@ GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, rgba)); + primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); @@ -165,7 +167,7 @@ GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], } /** - * Draw a filled box. + * Draw a filled box. Vertices must be in a counter-clockwise order. * * @param v1 * First vertex. @@ -185,12 +187,15 @@ GraphicsShape::drawBoxFilledByteColor(const float v1[3], const float v4[3], const uint8_t rgba[4]) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); + primitive->reserveForNumberOfVertices(6); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); + primitive->addVertex(v3); primitive->addVertex(v4); + primitive->addVertex(v1); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); @@ -198,7 +203,7 @@ GraphicsShape::drawBoxFilledByteColor(const float v1[3], } /** - * Draw a filled box. + * Draw a filled box. Vertices must be in a counter-clockwise order. * * @param v1 * First vertex. @@ -218,12 +223,15 @@ GraphicsShape::drawBoxFilledFloatColor(const float v1[3], const float v4[3], const float rgba[4]) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_QUADS, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); + primitive->reserveForNumberOfVertices(6); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); + primitive->addVertex(v3); primitive->addVertex(v4); + primitive->addVertex(v1); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); @@ -258,6 +266,7 @@ GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); + primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } @@ -286,13 +295,14 @@ GraphicsShape::drawEllipseFilledByteColor(const double majorAxis, { std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); + const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, rgba)); + primitive->reserveForNumberOfVertices(numVertices + 1); const float center[3] = { 0.0f, 0.0f, 0.0f }; primitive->addVertex(center); - const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } @@ -325,6 +335,7 @@ GraphicsShape::drawLinesByteColor(const std::vector& xyz, std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); + primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&xyz[i * 3]); } @@ -357,6 +368,7 @@ GraphicsShape::drawLineStripByteColor(const std::vector& xyz, std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); + primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&xyz[i * 3]); } @@ -539,6 +551,7 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, (uint8_t[]) { 255, 255, 255, 255 }); + primitive->reserveForNumberOfVertices(numberOfDivisions + 2); /* * Generate points around ring */ @@ -579,6 +592,7 @@ GraphicsShape::createRingPrimitive(const RingKey& ringKey) GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, (uint8_t[]) { 255, 255, 255, 255 }); + primitive->reserveForNumberOfVertices((ringKey.m_numberOfDivisions + 1) * 2); /* * Generate points around ring */ -- GitLab From 26885965b3317efde7c65a472acae78e970156e7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 16 Nov 2017 10:06:38 -0600 Subject: [PATCH 503/755] Do not limit an annotations width/height to 100%. --- src/Annotations/AnnotationTwoDimensionalShape.cxx | 6 +----- src/GuiQt/AnnotationWidthHeightWidget.cxx | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index fd8ae0292..3141b8563 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -1181,11 +1181,7 @@ AnnotationTwoDimensionalShape::applySpatialModificationTabOrWindowSpace(const An if ((newX >= 0.0) && (newX <= 100.0) && (newY >= 0.0) - && (newY <= 100.0) - && (newWidth > 0.01) - && (newWidth <= 100.0) - && (newHeight > 0.01) - && (newHeight <= 100.0)) { + && (newY <= 100.0)) { if (isFixedAspectRatio()) { xyz[0] = newX; diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index ac8ad91b0..0896ca317 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -79,14 +79,14 @@ m_browserWindowIndex(browserWindowIndex) break; } QLabel* widthLabel = new QLabel(widthLabelText); - m_widthSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, 1, + m_widthSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 1000.0, 0.1, 1, this, SLOT(widthValueChanged(double))); m_widthSpinBox->setSuffix("%"); WuQtUtilities::setWordWrappedToolTip(m_widthSpinBox, "Percentage width of 2D Shapes (Box, Image, Oval)"); QLabel* heightLabel = new QLabel(heightLabelText); - m_heightSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, 1, + m_heightSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 1000.0, 0.1, 1, this, SLOT(heightValueChanged(double))); m_heightSpinBox->setSuffix("%"); WuQtUtilities::setWordWrappedToolTip(m_heightSpinBox, -- GitLab From 52a4f7b00691b2b6198d6f87d4210c683f2568c9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 16 Nov 2017 10:07:02 -0600 Subject: [PATCH 504/755] Minor fix for a debug print --- src/Graphics/GraphicsOpenGLPolylineTriangles.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 25ab75c9b..6baee137d 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -791,7 +791,7 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t + " Coordinates: " + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") + " " - + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",")); + + AString::fromNumbers(&m_vertexWindowXYZ[iTwo3], 3, ",")); } /* -- GitLab From 74122c65bd9b8be1ecd0cea2892d9449cae5910d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 20 Nov 2017 10:19:38 -0600 Subject: [PATCH 505/755] Fixed bugs on line chart history editor for changing color and line width. --- src/Charting/ChartTwoDataCartesian.cxx | 5 +++++ src/Graphics/GraphicsPrimitive.cxx | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 11b4d6cf4..8c56c0276 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -130,6 +130,7 @@ ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() colorFound = true; } } + setColor(m_color); m_sceneAssistant = new SceneClassAssistant(); @@ -263,6 +264,8 @@ ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesi GraphicsPrimitiveV3f* ChartTwoDataCartesian::getGraphicsPrimitive() const { + m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + m_lineWidth); return m_graphicsPrimitive.get(); } @@ -437,6 +440,8 @@ void ChartTwoDataCartesian::setLineWidth(const float lineWidth) { m_lineWidth = lineWidth; + m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + m_lineWidth); } /** diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index d09fe73bd..f70652b6a 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -996,6 +996,10 @@ GraphicsPrimitive::replaceAllVertexSolidFloatRGBA(const float rgba[4]) CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; } + + if (m_graphicsEngineDataForOpenGL != NULL) { + m_graphicsEngineDataForOpenGL->invalidateColors(); + } } -- GitLab From 25bc8847fabbcc75c611197ca2fc0b63d2d73c2d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 20 Nov 2017 16:10:51 -0600 Subject: [PATCH 506/755] For polygonal line drawing, add a second join type 'bevel' and use it with some data types such as border lines, chart data lines, and histogram envelope mode. Use miter join with annotation line arrows. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 12 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- src/Files/ChartableTwoFileHistogramChart.cxx | 2 +- src/Files/ChartableTwoFileLineSeriesChart.cxx | 6 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 18 +- .../GraphicsOpenGLPolylineTriangles.cxx | 734 ++++++++++-------- .../GraphicsOpenGLPolylineTriangles.h | 114 +-- src/Graphics/GraphicsPrimitive.cxx | 32 +- src/Graphics/GraphicsPrimitive.h | 20 +- .../GraphicsPrimitiveSelectionHelper.cxx | 6 +- src/Graphics/GraphicsShape.cxx | 53 +- src/Graphics/GraphicsShape.h | 13 +- 12 files changed, 561 insertions(+), 451 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index cdaabb16e..0cb09bcdc 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -2240,7 +2240,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); if ( ! arrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(arrowCoordinates, + GraphicsShape::drawLineStripMiterJoinByteColor(arrowCoordinates, textColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); @@ -2581,13 +2581,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lin lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); if (validStartArrow) { - startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headRightTipEnd, headRightTipEnd + 3); startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headLeftTipEnd, headLeftTipEnd + 3); } if (validEndArrow) { - endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailRightTipEnd, tailRightTipEnd + 3); endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailLeftTipEnd, tailLeftTipEnd + 3); @@ -2673,13 +2671,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(startArrowCoordinates, + GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(endArrowCoordinates, + GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); @@ -2696,13 +2694,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(startArrowCoordinates, + GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { - GraphicsShape::drawLineStripByteColor(endArrowCoordinates, + GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, foregroundRGBA, GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 85a8f4857..dc52bb2dd 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2614,7 +2614,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } std::unique_ptr linesPrimitive; if (drawLines) { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP)); + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); } const bool featureClippingFlag = isFeatureClippingEnabled(); diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 24a630b07..3774d34d5 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -417,7 +417,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m */ GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); - GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN); envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 3f03dc25d..77cc70936 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -266,7 +266,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, xUnits, CaretUnitsTypeEnum::NONE, - GraphicsPrimitive::PrimitiveType::OPENGL_LINES); + GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN); cartesianData->setMapFileDataSelector(mapFileDataSelector); float x = 0.0f; @@ -281,8 +281,8 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie CaretAssertVectorIndex(data, i - 1); cartesianData->addPoint(x, data[i - 1]); x += xStep; - CaretAssertVectorIndex(data, i); - cartesianData->addPoint(x, data[i]); +// CaretAssertVectorIndex(data, i); +// cartesianData->addPoint(x, data[i]); } m_lineChartHistory->addHistoryItem(cartesianData); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index f5219090b..df5b9f983 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -484,8 +484,10 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { workbenchLineFlag = true; @@ -702,9 +704,11 @@ GraphicsEngineDataOpenGL::drawWithSelection(GraphicsPrimitive* primitive, break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: break; @@ -966,12 +970,14 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 6baee137d..a1bc43a22 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -51,100 +51,50 @@ using namespace caret; */ /** - * Destructor. + * Constructor. + * + * @param xyz + * The XYZ vertices. + * @param floatRGBA + * The Float RGBA coloring. + * @param byteRGBA + * The Byte RGBA coloring. + * @param vertexPrimitiveRestartIndices + * Contains indices at which the primitive should restart. + * The primitive will stop at the index and not connect to the next index. + * @param lineThicknessPixels + * Thickness of lines in pixels. + * @param colorType + * Type of color (solid or per-vertex) + * @param lineType + * Type of lines drawn. + * @param joinType + * Type of joining for line loop and line strip */ -GraphicsOpenGLPolylineTriangles::~GraphicsOpenGLPolylineTriangles() +GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(const std::vector& xyz, + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType, + const JoinType joinType) +: m_inputXYZ(xyz), +m_inputFloatRGBA(floatRGBA), +m_inputByteRGBA(byteRGBA), +m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), +m_lineThicknessPixels(lineThicknessPixels), +m_colorType(colorType), +m_lineType(lineType), +m_joinType(joinType) { } /** - * Draw the given graphics primitive containing lines - * by converting the lines to polygons. - * - * @param primtive - * The graphics primitive. + * Destructor. */ -bool -GraphicsOpenGLPolylineTriangles::draw(const GraphicsPrimitive* primitive) +GraphicsOpenGLPolylineTriangles::~GraphicsOpenGLPolylineTriangles() { - CaretAssert(primitive); - if (primitive->isValid()) { - float lineWidth = primitive->m_lineWidthValue; - - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: - { - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; - } - break; - case GraphicsPrimitive::SizeType::PIXELS: - break; - } - - ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - CaretLogSevere("INVALID color type NONE for graphics primitive"); - return false; - break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: - colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: - colorType = ColorType::BYTE_RGBA_PER_VERTEX; - break; - } - - LineType lineType = LineType::LINES; - switch (primitive->m_primitiveType) { - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - lineType = LineType::LINE_LOOP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - lineType = LineType::LINE_STRIP; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: - lineType = LineType::LINES; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: - CaretLogSevere("POINTS is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: - CaretLogSevere("TRIANGLE_FAN is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: - CaretLogSevere("TRIANGLE_STRIP is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: - CaretLogSevere("TRIANGLES is not a valid line drawing type"); - return false; - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: - break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - break; - case GraphicsPrimitive::PrimitiveType::SPHERES: - CaretLogSevere("SPHERES is not a valid line drawing type"); - break; - } - - return drawLinesPrivate(primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); - } - - return false; } /** @@ -202,6 +152,7 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const } LineType lineType = LineType::LINES; + JoinType joinType = JoinType::NONE; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; @@ -224,11 +175,21 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + lineType = LineType::LINE_LOOP; + joinType = JoinType::BEVEL; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: lineType = LineType::LINE_LOOP; + joinType = JoinType::MITER; + break; + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + lineType = LineType::LINE_STRIP; + joinType = JoinType::BEVEL; break; - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: lineType = LineType::LINE_STRIP; + joinType = JoinType::MITER; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: lineType = LineType::LINES; @@ -243,95 +204,19 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const } GraphicsOpenGLPolylineTriangles lineConversion(primitive->m_xyz, - primitive->m_floatRGBA, - primitive->m_unsignedByteRGBA, - primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, - colorType, - lineType); + primitive->m_floatRGBA, + primitive->m_unsignedByteRGBA, + primitive->m_polygonalLinePrimitiveRestartIndices, + lineWidth, + colorType, + lineType, + joinType); GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); return primitiveOut; } -/** - * Constructor. - * - * @param xyz - * The XYZ vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * The primitive will stop at the index and not connect to the next index. - * @param lineThicknessPixels - * Thickness of lines in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - */ -GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -: m_inputXYZ(xyz), -m_inputFloatRGBA(floatRGBA), -m_inputByteRGBA(byteRGBA), -m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), -m_lineThicknessPixels(lineThicknessPixels), -m_colorType(colorType), -m_lineType(lineType) -{ - -} - -/** - * Draw lines where each pair of vertices is drawn as an independent - * line segment. Same as OpenGL GL_LINES mode with glBegin(). - * - * @param xyz - * The vertices. - * @param floatRGBA - * The Float RGBA coloring. - * @param byteRGBA - * The Byte RGBA coloring. - * @param vertexPrimitiveRestartIndices - * Contains indices at which the primitive should restart. - * @param lineThicknessPixels - * Thickness of line in pixels. - * @param colorType - * Type of color (solid or per-vertex) - * @param lineType - * Type of lines drawn. - * @return - * True if drawn, or false if there was an error. - */ -bool -GraphicsOpenGLPolylineTriangles::drawLinesPrivate(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType) -{ - GraphicsOpenGLPolylineTriangles lineDrawing(xyz, - floatRGBA, - byteRGBA, - vertexPrimitiveRestartIndices, - lineThicknessPixels, - colorType, - lineType); - return lineDrawing.performDrawing(); -} - /** * Convert the content of this instance to a new graphics primitive * that draws the lines as polygons. @@ -440,94 +325,6 @@ GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut return primitiveOut; } - -/** - * Perform the line drawinhg. - * - * @return - * True if no errors, false if errors. - */ -bool -GraphicsOpenGLPolylineTriangles::performDrawing() -{ - const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); - if (numVertices < 2) { - CaretLogWarning("Invalid number of vertices=" - + AString::number(numVertices) - + " for line drawing. Must be at least 2."); - return false; - } - - const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); - const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); - switch (m_colorType) { - case ColorType::BYTE_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numByteRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have byte coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::BYTE_RGBA_SOLID: - if (numByteRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numByteRGBA)); - return false; - } - break; - case ColorType::FLOAT_RGBA_PER_VERTEX: - { - const int32_t numRgbaVertices = numFloatRGBA / 4; - if (numVertices != numRgbaVertices) { - CaretLogSevere("Mismatch in vertices and coloring. There are " - + AString::number(numVertices) - + " vertices but have float coloring for " - + AString::number(numRgbaVertices) - + " vertices"); - return false; - } - } - break; - case ColorType::FLOAT_RGBA_SOLID: - if (numFloatRGBA < 4) { - CaretLogSevere("Must have at last 4 color components for solid color line drawing" - "Number of color components is " - + AString::number(numFloatRGBA)); - return false; - } - break; - } - - saveOpenGLState(); - - createProjectionMatrix(); - - createWindowCoordinatesFromVertices(); - - const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); - if (numWindowPoints >= 2) { - convertLineSegmentsToTriangles(); - - joinTriangles(); - - CaretAssert(m_primitive); - if (m_primitive->isValid()) { - drawTriangles(); - } - } - - restoreOpenGLState(); - - return true; -} - /** * Save the OpenGL State. */ @@ -961,6 +758,16 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() { CaretAssert(m_primitive); + switch (m_joinType) { + case JoinType::BEVEL: + break; + case JoinType::MITER: + break; + case JoinType::NONE: + return; + break; + } + const int32_t numPolylines = static_cast(m_polyLineInfo.size()); const int32_t numPolylinesMinusOne = numPolylines - 1; @@ -992,8 +799,18 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() * Does triangle "i" connect to triangle "i+1" ? */ if (poly.m_windowVertexTwoIndex == nextPoly.m_windowVertexOneIndex) { - performJoin(poly, - nextPoly); + switch (m_joinType) { + case JoinType::BEVEL: + performBevelJoin(poly, + nextPoly); + break; + case JoinType::MITER: + performMiterJoin(poly, + nextPoly); + break; + case JoinType::NONE: + break; + } } } @@ -1001,22 +818,26 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() } /** - * Join the second triangle in poly one to poly two. + * Determine the turn direction at the connection point of two line segments. * * @param polyOne - * Info about triangles in first polyline + * Info about first polyline * @param polyTwo - * Info about triangles in second polyline + * Info about second polyline + * @return + * The turn direction. */ -void -GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, - const PolylineInfo& polyTwo) +GraphicsOpenGLPolylineTriangles::TurnDirection +GraphicsOpenGLPolylineTriangles::getTurnDirection(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) const { + TurnDirection turnDirection = TurnDirection::PARALLEL; + const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; - if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; + if (m_debugFlag) std::cout << "Turn Direction: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; CaretAssert(m_primitive); /* @@ -1032,36 +853,161 @@ GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, &m_vertexWindowXYZ[windowVertexIndexThree * 3]); - int32_t quadOneSideBeginVertexIndex = -1; - int32_t quadOneSideEndVertexIndex = -1; - int32_t quadTwoSideBeginVertexIndex = -1; - int32_t quadTwoSideEndVertexIndex = -1; const float smallNumber = 0.001; - bool leftTurnFlag = false; if (signedArea > smallNumber) { - leftTurnFlag = true; - if (m_debugFlag) std::cout << " Left Turn" << std::endl; - /* - * Right side is first two vertices in triangle two - */ - quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; - quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; - quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; + turnDirection = TurnDirection::LEFT; } else if (signedArea < -smallNumber) { - if (m_debugFlag) std::cout << " Right Turn" << std::endl; - /* - * Left side is first and third vertices in triangle one - */ - quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; - quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; - quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; + turnDirection = TurnDirection::RIGHT; } else { - if (m_debugFlag) std::cout << " Parallel" << std::endl; - return; + turnDirection = TurnDirection::PARALLEL; + } + + return turnDirection; +} + +/** + * Join the second triangle in poly one to poly two with a bevel join. + * A triangle is added that connects the outside corners of the + * two polylines. + * + * @param polyOne + * Info about triangles in first polyline + * @param polyTwo + * Info about triangles in second polyline + */ +void +GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) +{ + const TurnDirection turnDirection = getTurnDirection(polyOne, + polyTwo); + + const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; + + if (m_debugFlag) { + const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; + const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; + std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; + } + CaretAssert(m_primitive); + + /* + * Determine if the junction of the two consecutive + * line segments in window coordinates makes a left + * or right turn + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + + int32_t quadOneSideEndVertexIndex = -1; + int32_t quadTwoSideBeginVertexIndex = -1; + bool leftTurnFlag = false; + switch (turnDirection) { + case TurnDirection::LEFT: + leftTurnFlag = true; + if (m_debugFlag) std::cout << " Left Turn" << std::endl; + + /* + * Join the right side that is first two vertices in triangle two + */ + quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; + break; + case TurnDirection::PARALLEL: + if (m_debugFlag) std::cout << " Parallel" << std::endl; + return; + break; + case TurnDirection::RIGHT: + leftTurnFlag = false; + if (m_debugFlag) std::cout << " Right Turn" << std::endl; + + /* + * Join left side that is first and third vertices in triangle one + */ + quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; + break; + } + + /* + * Add a triangle to fill in the gap + */ + m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, + quadOneSideEndVertexIndex, + quadTwoSideBeginVertexIndex)); +} + +/** + * Join the second triangle in poly one to poly two with a miter join. + * A miter join extends the 'outside' edges of the turn to their intersection. + * If the angle is sharp (very small) this intersection may be long way + * from the original vertex. The miter limit keeps this from happening by + * extending the intersection just a little bit and adding essentially a + * bevel-like join. + * + * @param polyOne + * Info about triangles in first polyline + * @param polyTwo + * Info about triangles in second polyline + */ +void +GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) +{ + const TurnDirection turnDirection = getTurnDirection(polyOne, + polyTwo); + + const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; + + if (m_debugFlag) { + const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; + const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; + std::cout << "Miter Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; + } + CaretAssert(m_primitive); + + /* + * Determine if the junction of the two consecutive + * line segments in window coordinates makes a left + * or right turn + */ + CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); + + int32_t quadOneSideBeginVertexIndex = -1; + int32_t quadOneSideEndVertexIndex = -1; + int32_t quadTwoSideBeginVertexIndex = -1; + int32_t quadTwoSideEndVertexIndex = -1; + bool leftTurnFlag = false; + switch (turnDirection) { + case TurnDirection::LEFT: + leftTurnFlag = true; + if (m_debugFlag) std::cout << " Miter Left Turn" << std::endl; + + /* + * Join the right side that is first two vertices in triangle two + */ + quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; + quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; + quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; + break; + case TurnDirection::PARALLEL: + if (m_debugFlag) std::cout << " Miter Parallel" << std::endl; + return; + break; + case TurnDirection::RIGHT: + leftTurnFlag = false; + if (m_debugFlag) std::cout << " Miter Right Turn" << std::endl; + + /* + * Join left side that is first and third vertices in triangle one + */ + quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; + quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; + quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; + break; } const std::vector& xyz = m_primitive->getFloatXYZ(); @@ -1086,7 +1032,7 @@ GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, float intersectionXYZ[3]; if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { intersectionXYZ[2] = q1v1[2]; - if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; + if (m_debugFlag) std::cout << " Miter Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; /* * When the angle is very sharp, the miter point can be very long and pointy @@ -1124,10 +1070,10 @@ GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], newV2); primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[0]; } - - /* - * Add a triangle to fill in the gap - */ + + /* + * Add a triangle to fill in the gap + */ m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, primitiveIndexV1, primitiveIndexV2)); @@ -1150,6 +1096,166 @@ GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, } } +///** +// * Join the second triangle in poly one to poly two. +// * +// * @param polyOne +// * Info about triangles in first polyline +// * @param polyTwo +// * Info about triangles in second polyline +// */ +//void +//GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, +// const PolylineInfo& polyTwo) +//{ +// const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; +// const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; +// const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; +// +// if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; +// CaretAssert(m_primitive); +// +// /* +// * Determine if the junction of the two consecutive +// * line segments in window coordinates makes a left +// * or right turn +// */ +// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); +// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); +// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); +// const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], +// &m_vertexWindowXYZ[windowVertexIndexTwo * 3], +// &m_vertexWindowXYZ[windowVertexIndexThree * 3]); +// +// +// int32_t quadOneSideBeginVertexIndex = -1; +// int32_t quadOneSideEndVertexIndex = -1; +// int32_t quadTwoSideBeginVertexIndex = -1; +// int32_t quadTwoSideEndVertexIndex = -1; +// const float smallNumber = 0.001; +// bool leftTurnFlag = false; +// if (signedArea > smallNumber) { +// leftTurnFlag = true; +// if (m_debugFlag) std::cout << " Left Turn" << std::endl; +// /* +// * Right side is first two vertices in triangle two +// */ +// quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; +// quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; +// quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; +// quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; +// } +// else if (signedArea < -smallNumber) { +// if (m_debugFlag) std::cout << " Right Turn" << std::endl; +// /* +// * Left side is first and third vertices in triangle one +// */ +// quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; +// quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; +// quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; +// quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; +// } +// else { +// if (m_debugFlag) std::cout << " Parallel" << std::endl; +// return; +// } +// +// switch (m_joinType) { +// case JoinType::BEVEL: +// break; +// case JoinType::MITER: +// break; +// case JoinType::NONE: +// CaretAssert(0); +// break; +// } +// +// const std::vector& xyz = m_primitive->getFloatXYZ(); +// CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); +// CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); +// CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); +// CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); +// const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; +// const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; +// const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; +// const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; +// +// /* +// * Miter limit is a multiple of the line thickness +// */ +// const float miterLimit = m_lineThicknessPixels;// * 2.0f; +// const float miterLimitSquared = miterLimit * miterLimit; +// +// /* +// * Find location of where the edges in the quads intersect +// */ +// float intersectionXYZ[3]; +// if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { +// intersectionXYZ[2] = q1v1[2]; +// if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; +// +// /* +// * When the angle is very sharp, the miter point can be very long and pointy +// * so limit to a multiplier of the line thickness +// */ +// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); +// const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; +// const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, +// intersectionXYZ); +// if (distanceSquared > miterLimitSquared) { +// /* +// * Extend lines by the miter limit to create a new quad +// */ +// float newV1[3]; +// createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); +// float newV2[3]; +// createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); +// +// /* +// * Extend vertices to the new miter limit +// */ +// int32_t primitiveIndexV1 = -1; +// int32_t primitiveIndexV2 = -1; +// if (leftTurnFlag) { +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], newV1); +// primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[1]; +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], newV2); +// primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[1]; +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], newV2); +// } +// else { +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], newV1); +// primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[2]; +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], newV1); +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], newV2); +// primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[0]; +// } +// +// /* +// * Add a triangle to fill in the gap +// */ +// m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, +// primitiveIndexV1, +// primitiveIndexV2)); +// } +// else { +// /* +// * Move the existing quad vertices to their intersection point +// */ +// if (leftTurnFlag) { +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], intersectionXYZ); +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], intersectionXYZ); +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], intersectionXYZ); +// } +// else { +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], intersectionXYZ); +// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], intersectionXYZ); +// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], intersectionXYZ); +// } +// } +// } +//} + /** * Create a vertex for a miter join when the length limit is exceeded * @@ -1331,38 +1437,6 @@ GraphicsOpenGLPolylineTriangles::convertLineSegmentsToTriangles() } } -/** - * Draw the lines using triangles. - */ -void -GraphicsOpenGLPolylineTriangles::drawTriangles() -{ - GLdouble depthRange[2]; - glGetDoublev(GL_DEPTH_RANGE, - depthRange); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, - viewport); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(viewport[0], viewport[0] + viewport[2], - viewport[1], viewport[1] + viewport[3], - 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glPolygonMode(GL_FRONT, GL_FILL); - - CaretAssert(m_primitive); - GraphicsEngineDataOpenGL::draw(m_primitive); - if (m_debugFlag) { - std::cout << std::endl << "Quad Primitive: " << m_primitive->toString() << std::endl; - std::cout << "viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; - } -} - /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index 93d67a337..5a07bdd86 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -38,64 +38,11 @@ namespace caret { class GraphicsOpenGLPolylineTriangles : public CaretObject { public: - /** - * Join tyupe of how connected lines are drawn to remove gaps between segments - */ - enum JoinType { - /** None */ - NONE, - /* Extends 'outsides' of lines to meet forming a pointed shape */ - MITER - }; - virtual ~GraphicsOpenGLPolylineTriangles(); static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut); - static bool draw(const GraphicsPrimitive* primitive); - -// static bool drawLinesPerVertexFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels); -// -// static bool drawLinesSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineStripSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineLoopSolidFloatColor(void* openglContextPointer, -// const std::vector& xyz, -// const float rgba[4], -// const float lineThicknessPixels); -// -// -// static bool drawLinesPerVertexByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const std::vector& rgba, -// const float lineThicknessPixels); -// -// static bool drawLinesSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineStripSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); -// -// static bool drawLineLoopSolidByteColor(void* openglContextPointer, -// const std::vector& xyz, -// const uint8_t rgba[4], -// const float lineThicknessPixels); -// // ADD_NEW_METHODS_HERE virtual AString toString() const; @@ -115,6 +62,18 @@ namespace caret { FLOAT_RGBA_SOLID }; + /** + * Join tyupe of how connected lines are drawn to remove gaps between segments + */ + enum class JoinType { + /** None */ + NONE, + /** Bevel fills the gap by adding a triangle */ + BEVEL, + /** Miter extends 'outsides' of lines to meet forming a pointed shape */ + MITER + }; + /** * Type of line drawing */ @@ -127,6 +86,18 @@ namespace caret { LINE_STRIP }; + /** + * Turn direction add joint vertex of two lines + */ + enum class TurnDirection { + /** Turns left */ + LEFT, + /** Does not turn (straight) or coincident */ + PARALLEL, + /** Turns right */ + RIGHT, + }; + /** * Indices into input vertices of line * that formed the polyline @@ -174,27 +145,18 @@ namespace caret { }; GraphicsOpenGLPolylineTriangles(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); + const std::vector& floatRGBA, + const std::vector& byteRGBA, + const std::set& vertexPrimitiveRestartIndices, + const float lineThicknessPixels, + const ColorType colorType, + const LineType lineType, + const JoinType joinType); GraphicsOpenGLPolylineTriangles(const GraphicsOpenGLPolylineTriangles& obj); GraphicsOpenGLPolylineTriangles& operator=(const GraphicsOpenGLPolylineTriangles& obj) const; - static bool drawLinesPrivate(const std::vector& xyz, - const std::vector& floatRGBA, - const std::vector& byteRGBA, - const std::set& vertexPrimitiveRestartIndices, - const float lineThicknessPixels, - const ColorType colorType, - const LineType lineType); - - bool performDrawing(); - GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); void saveOpenGLState(); @@ -213,10 +175,11 @@ namespace caret { void createTrianglesFromWindowVertices(const int32_t windowVertexOneIndex, const int32_t windowVertexTwoIndex); - void drawTriangles(); + void performBevelJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo); - void performJoin(const PolylineInfo& polyOne, - const PolylineInfo& polyTwo); + void performMiterJoin(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo); void joinTriangles(); @@ -227,6 +190,9 @@ namespace caret { const float miterLength, float xyzOut[3]); + TurnDirection getTurnDirection(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) const; + const std::vector& m_inputXYZ; const std::vector& m_inputFloatRGBA; @@ -241,12 +207,12 @@ namespace caret { const LineType m_lineType; + const JoinType m_joinType; + std::vector m_vertexWindowXYZ; std::vector m_vertexWindowInputIndices; - JoinType m_joinType = JoinType::MITER; - bool m_debugFlag = false; int m_savedPolygonMode[2]; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index f70652b6a..dde8fe192 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -356,13 +356,15 @@ GraphicsPrimitive::isValid() const switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: - case PrimitiveType::POLYGONAL_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: if (numXYZ < 3) { CaretLogWarning("Line loop must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_LINE_STRIP: - case PrimitiveType::POLYGONAL_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } @@ -465,11 +467,17 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const case PrimitiveType::OPENGL_TRIANGLES: s = "OpenGL Triangles"; break; - case PrimitiveType::POLYGONAL_LINE_LOOP: - s = "Polygonal Line Loop"; + case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + s = "Polygonal Line Loop Bevel Join"; break; - case PrimitiveType::POLYGONAL_LINE_STRIP: - s = "Polygonal Line Strip"; + case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: + s = "Polygonal Line Loop Miter Join"; + break; + case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + s = "Polygonal Line Strip Bevel Join"; + break; + case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: + s = "Polygonal Line Strip Miter Join"; break; case PrimitiveType::POLYGONAL_LINES: s = "Polygonal Lines"; @@ -636,10 +644,12 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; case PrimitiveType::OPENGL_TRIANGLES: break; - case PrimitiveType::POLYGONAL_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: addLineWidthFlag = true; break; - case PrimitiveType::POLYGONAL_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: addLineWidthFlag = true; break; case PrimitiveType::POLYGONAL_LINES: @@ -1074,10 +1084,12 @@ GraphicsPrimitive::addPrimitiveRestart() break; case PrimitiveType::OPENGL_TRIANGLES: break; - case PrimitiveType::POLYGONAL_LINE_LOOP: + case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: polygonalLineFlag = true; break; - case PrimitiveType::POLYGONAL_LINE_STRIP: + case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: polygonalLineFlag = true; break; case PrimitiveType::POLYGONAL_LINES: diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 40d8edc42..c3ede120c 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -133,13 +133,25 @@ namespace caret { */ OPENGL_TRIANGLES, /** - * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons. + * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a BEVEL join at vertices */ - POLYGONAL_LINE_LOOP, + POLYGONAL_LINE_LOOP_BEVEL_JOIN, /** - * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons. + * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a MITER join at vertices */ - POLYGONAL_LINE_STRIP, + POLYGONAL_LINE_LOOP_MITER_JOIN, + /** + * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a BEVEL join at vertices + */ + POLYGONAL_LINE_STRIP_BEVEL_JOIN, + /** + * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons + * and polygons that form the line use a MITER join at vertices + */ + POLYGONAL_LINE_STRIP_MITER_JOIN, /** * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. */ diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index 821377c46..f6bf3eae7 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -74,11 +74,13 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: - case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: + case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: m_numberOfVerticesPerPrimitive = numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 698de6558..bddea8474 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -109,7 +109,7 @@ GraphicsShape::drawBoxOutlineByteColor(const float v1[3], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); @@ -151,7 +151,7 @@ GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); @@ -263,7 +263,7 @@ GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); primitive->reserveForNumberOfVertices(numVertices); @@ -348,7 +348,8 @@ GraphicsShape::drawLinesByteColor(const std::vector& xyz, } /** - * Draw line strip similar to OpenGL's GL_LINES + * Draw line strip similar to OpenGL's GL_LINE_STRIP + * and use Bevel Joins at connected vertices * * @param xyz * Coordinates of the line end points. @@ -360,12 +361,46 @@ GraphicsShape::drawLinesByteColor(const std::vector& xyz, * Thickness of the line. */ void -GraphicsShape::drawLineStripByteColor(const std::vector& xyz, - const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, - const double lineThickness) +GraphicsShape::drawLineStripBevelJoinByteColor(const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) +{ + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN, + rgba)); + const int32_t numVertices = static_cast(xyz.size() / 3); + primitive->reserveForNumberOfVertices(numVertices); + for (int32_t i = 0; i < numVertices; i++) { + primitive->addVertex(&xyz[i * 3]); + } + + primitive->setLineWidth(lineThicknessType, + lineThickness); + primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); + + GraphicsEngineDataOpenGL::draw(primitive.get()); +} + +/** + * Draw line strip similar to OpenGL's GL_LINE_STRIP + * and use Bevel Joins at connected vertices + * + * @param xyz + * Coordinates of the line end points. + * @param rgba + * Color for drawing. + * @param lineThicknessType + * Type of line thickness. + * @param lineThickness + * Thickness of the line. + */ +void +GraphicsShape::drawLineStripMiterJoinByteColor(const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness) { - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP, + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); primitive->reserveForNumberOfVertices(numVertices); diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index cac700d79..2453218ae 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -82,10 +82,15 @@ namespace caret { const GraphicsPrimitive::SizeType lineThicknessType, const double lineThickness); - static void drawLineStripByteColor(const std::vector& xyz, - const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, - const double lineThickness); + static void drawLineStripBevelJoinByteColor(const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); + + static void drawLineStripMiterJoinByteColor(const std::vector& xyz, + const uint8_t rgba[4], + const GraphicsPrimitive::SizeType lineThicknessType, + const double lineThickness); static void drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], -- GitLab From 08fdd3c90841a8d9ccfab384eefb057e6e4de24e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 21 Nov 2017 10:32:41 -0600 Subject: [PATCH 507/755] Improvements/fixes for drawing annotation arrows. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 140 +++++++++--------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 2 - 2 files changed, 72 insertions(+), 70 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 0cb09bcdc..976e7ba1f 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -91,8 +91,9 @@ m_volumeSliceThickness(0.0) m_dummyAnnotationFile->setFileName("DummyFileForDrawing" + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::ANNOTATION)); + float unusedLineWidthMaximum(0); BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, - m_lineWidthMaximum); + unusedLineWidthMaximum); } /** @@ -2471,6 +2472,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF return drawnFlag; } + /** * Create the coordinates for drawing a line with optional arrows at the end points. * @@ -2504,92 +2506,97 @@ BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lin /* * Length of arrow's tips is function of line thickness */ - const float tipScale = 3.0; - const float tipLength = lineThicknessPixels * tipScale; + const float lineLength = MathFunctions::distance3D(lineHeadXYZ, + lineTailXYZ); + const float thirdLineLength = lineLength / 3.0f; /* - * Point on arrow's line that is between the arrow's left and right arrow tips + * Vector from Tail to Head of line */ - float headToTailVector[3]; - MathFunctions::createUnitVector(lineHeadXYZ, lineTailXYZ, headToTailVector); - const float startArrowTipsOnLine[3] = { - lineHeadXYZ[0] + (headToTailVector[0] * tipLength), - lineHeadXYZ[1] + (headToTailVector[1] * tipLength), - lineHeadXYZ[2] + (headToTailVector[2] * tipLength) - }; - const float tailArrowTipsOnLine[3] = { - lineTailXYZ[0] - (headToTailVector[0] * tipLength), - lineTailXYZ[1] - (headToTailVector[1] * tipLength), - lineTailXYZ[2] - (headToTailVector[2] * tipLength) - }; + float tailToHeadUnitVector[3]; + MathFunctions::createUnitVector(lineTailXYZ, + lineHeadXYZ, + tailToHeadUnitVector); + /* - * Vector for arrow tip's on left and right - * * Create a perpendicular vector by swapping first two elements * and negating the second element. */ - float headLeftRightTipOffset[3] = { - headToTailVector[0], - headToTailVector[1], - headToTailVector[2] + const float leftToRightUnitVector[3] = { + tailToHeadUnitVector[1], + -tailToHeadUnitVector[0], + tailToHeadUnitVector[2] }; - MathFunctions::normalizeVector(headLeftRightTipOffset); - std::swap(headLeftRightTipOffset[0], - headLeftRightTipOffset[1]); - headLeftRightTipOffset[1] *= -1; - headLeftRightTipOffset[0] *= tipLength; - headLeftRightTipOffset[1] *= tipLength; - headLeftRightTipOffset[2] *= tipLength; /* - * Tip of arrow's head pointer on the right + * Left to right vector moves the arrows tips away from the line + * in a direction perpendicular to the line */ - const float headRightTipEnd[3] = { - startArrowTipsOnLine[0] - headLeftRightTipOffset[0], - startArrowTipsOnLine[1] - headLeftRightTipOffset[1], - startArrowTipsOnLine[2] - headLeftRightTipOffset[2] + const float awayFromLineScale = 3.0f; + const float awayFromLineDistance = lineThicknessPixels * awayFromLineScale; + const float leftToRightVector[3] = { + leftToRightUnitVector[0] * awayFromLineDistance, + leftToRightUnitVector[1] * awayFromLineDistance, + leftToRightUnitVector[2] }; /* - * Tip of arrow's head pointer on the left + * Away from tail vector moves the arrows tips away from the tail + * of the line in a direction along the line */ - const float headLeftTipEnd[3] = { - startArrowTipsOnLine[0] + headLeftRightTipOffset[0], - startArrowTipsOnLine[1] + headLeftRightTipOffset[1], - startArrowTipsOnLine[2] + headLeftRightTipOffset[2] + const float awayFromTipScale = 3.0f; + const float alongLineDistanceFromTip = std::min((lineThicknessPixels * awayFromTipScale), + (thirdLineLength)); + + const float awayFromTailVector[3] = { + (tailToHeadUnitVector[0] * alongLineDistanceFromTip), + (tailToHeadUnitVector[1] * alongLineDistanceFromTip), + (tailToHeadUnitVector[2]) }; - /* - * Tip of arrow tail pointer on the right - */ - const float tailRightTipEnd[3] = { - tailArrowTipsOnLine[0] + headLeftRightTipOffset[0], - tailArrowTipsOnLine[1] + headLeftRightTipOffset[1], - tailArrowTipsOnLine[2] + headLeftRightTipOffset[2] - }; + if (validEndArrow) { + const float tailTipRightXYZ[3] = { + lineTailXYZ[0] + leftToRightVector[0] + awayFromTailVector[0], + lineTailXYZ[1] + leftToRightVector[1] + awayFromTailVector[1], + lineTailXYZ[2] + leftToRightVector[2] + awayFromTailVector[2] + }; + const float tailTipLeftXYZ[3] = { + lineTailXYZ[0] - leftToRightVector[0] + awayFromTailVector[0], + lineTailXYZ[1] - leftToRightVector[1] + awayFromTailVector[1], + lineTailXYZ[2] + leftToRightVector[2] + awayFromTailVector[2] + }; + + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), + tailTipLeftXYZ, tailTipLeftXYZ + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), + lineTailXYZ, lineTailXYZ + 3); + endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), + tailTipRightXYZ, tailTipRightXYZ + 3); + } - /* - * Tip of arrow tail pointer on the right - */ - const float tailLeftTipEnd[3] = { - tailArrowTipsOnLine[0] - headLeftRightTipOffset[0], - tailArrowTipsOnLine[1] - headLeftRightTipOffset[1], - tailArrowTipsOnLine[2] - headLeftRightTipOffset[2] - }; + if (validStartArrow) { + const float headTipRightXYZ[3] = { + lineHeadXYZ[0] + leftToRightVector[0] - awayFromTailVector[0], + lineHeadXYZ[1] + leftToRightVector[1] - awayFromTailVector[1], + lineHeadXYZ[2] + leftToRightVector[2] - awayFromTailVector[2] + }; + const float headTipLeftXYZ[3] = { + lineHeadXYZ[0] - leftToRightVector[0] - awayFromTailVector[0], + lineHeadXYZ[1] - leftToRightVector[1] - awayFromTailVector[1], + lineHeadXYZ[2] + leftToRightVector[2] - awayFromTailVector[2] + }; + + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), + headTipLeftXYZ, headTipLeftXYZ + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), + lineHeadXYZ, lineHeadXYZ + 3); + startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), + headTipRightXYZ, headTipRightXYZ + 3); + } lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); - if (validStartArrow) { - startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headRightTipEnd, headRightTipEnd + 3); - startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); - startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headLeftTipEnd, headLeftTipEnd + 3); - } - if (validEndArrow) { - endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailRightTipEnd, tailRightTipEnd + 3); - endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); - endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailLeftTipEnd, tailLeftTipEnd + 3); - } } /** @@ -3297,9 +3304,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthFromPercentageHeight(cons if (widthPixels < m_lineWidthMinimum) { widthPixels = m_lineWidthMinimum; } - else if (widthPixels > m_lineWidthMaximum) { - widthPixels = m_lineWidthMaximum; - } return widthPixels; } diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index f7557e7ec..cfa6c75c4 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -348,8 +348,6 @@ namespace caret { float m_lineWidthMinimum = 1.0f; - float m_lineWidthMaximum = 5.0f; - static constexpr float s_sizingHandleLineWidthInPixels = 2.0f; // ADD_NEW_MEMBERS_HERE -- GitLab From c2abb3ff9e8509b33e2a1dbd723333f15fa2d90e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Nov 2017 09:52:34 -0600 Subject: [PATCH 508/755] Created an event, EventOpenGLObjectToWindowTransform, that is received by OpenGL drawing to create a matrix for transforming coordinates from object space to window space. Using this transform fixed drawing of 'polygonal lines' in surface or stereotaxic space. --- src/Brain/BrainOpenGL.cxx | 6 + src/Brain/BrainOpenGL.h | 3 + ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 9 + src/Brain/BrainOpenGLFixedPipeline.cxx | 37 ++- src/Brain/BrainOpenGLFixedPipeline.h | 3 + src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/Graphics/CMakeLists.txt | 2 + .../EventOpenGLObjectToWindowTransform.cxx | 230 +++++++++++++++++ .../EventOpenGLObjectToWindowTransform.h | 96 +++++++ .../GraphicsOpenGLPolylineTriangles.cxx | 244 +++--------------- .../GraphicsOpenGLPolylineTriangles.h | 6 +- 13 files changed, 431 insertions(+), 212 deletions(-) create mode 100644 src/Graphics/EventOpenGLObjectToWindowTransform.cxx create mode 100644 src/Graphics/EventOpenGLObjectToWindowTransform.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index c47b2926d..40ee37c59 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -37,6 +37,7 @@ #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" #include "EventGraphicsOpenGLDeleteTextureName.h" +#include "EventOpenGLObjectToWindowTransform.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" #include "GraphicsOpenGLTextureName.h" @@ -66,6 +67,7 @@ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM); } /** @@ -185,6 +187,10 @@ BrainOpenGL::receiveEvent(Event* event) textRenderEvent->setTextRenderer(m_textRenderer); textRenderEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM) { + EventOpenGLObjectToWindowTransform* transformEvent = dynamic_cast(event); + loadObjectToWindowTransform(transformEvent); + } } /** diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 3df77103b..19be603c1 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -68,6 +68,7 @@ namespace caret { class Brain; class BrainOpenGLTextRenderInterface; class BrainOpenGLViewportContent; + class EventOpenGLObjectToWindowTransform; class Model; class SurfaceProjectedItem; @@ -308,6 +309,8 @@ namespace caret { const GLenum enumValue, const int32_t numberOfValues) const; + virtual void loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) = 0; + Border* borderBeingDrawn; bool m_drawHighlightedEndPoints; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 976e7ba1f..d7eff031e 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -2098,12 +2098,21 @@ BrainOpenGLAnnotationDrawingFixedPipeline::clipLineAtTextBox(const float bottomL break; } + /* + * perform a 2D intersection test + */ float intersection[3] = { 0.0, 0.0, 0.0 }; const bool yesFlag = MathFunctions::lineIntersection2D(p1, p2, startXYZ, endXYZ, tol, intersection); if (yesFlag) { + /* + * Intersection is TWO-D so must set + * the correct Z-coordinate + */ + const float averageZ = ((p1[2] + p2[2]) / 2.0f); + intersection[2] = averageZ; const float dist = MathFunctions::distance3D(startXYZ, intersection); if ( ( ! clippedValid) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index dc52bb2dd..851e4f1d5 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -89,6 +89,7 @@ #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "EventNodeIdentificationColorsGetFromCharts.h" +#include "EventOpenGLObjectToWindowTransform.h" #include "EventPaletteGetByName.h" #include "FastStatistics.h" #include "Fiber.h" @@ -364,7 +365,41 @@ BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex } /** - * Update the foreground and background colors using the model in + * Setup the content of the transform event with current transformation data. + * + * @param transformEvent + * The transform event. + */ +void +BrainOpenGLFixedPipeline::loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) +{ + + if (getContextSharingGroupPointer() != NULL) { + std::array modelviewArray; + std::array projectionArray; + std::array depthRange; + std::array viewport; + + glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray.data()); + glGetDoublev(GL_PROJECTION_MATRIX, projectionArray.data()); + glGetDoublev(GL_DEPTH_RANGE, depthRange.data()); + glGetIntegerv(GL_VIEWPORT, viewport.data()); + + transformEvent->setup(modelviewArray, + projectionArray, + viewport, + depthRange, + s_gluLookAtCenterFromEyeOffsetDistance); + transformEvent->setEventProcessed(); + } + else { + CaretAssertMessage(0, "Received EventOpenGLObjectToWindowTransform but current context is invalid."); + } + +} + +/** + * Update the foreground and background colors using the model in * the given viewport content. */ void diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 65a2777e9..02fbccb40 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -133,6 +133,9 @@ namespace caret { const int32_t mouseY, SurfaceProjectedItem& projectionOut) override; + protected: + virtual void loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) override; + private: class VolumeDrawInfo { public: diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index a4d754699..e99ee3259 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -525,6 +525,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED: case EventTypeEnum::EVENT_MODEL_SURFACE_GET: case EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS: + case EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM: case EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE: case EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW: case EventTypeEnum::EVENT_OVERLAY_VALIDATE: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index ba7581906..ae1e2bf4f 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -302,6 +302,10 @@ EventTypeEnum::initialize() "EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS", "Get the color for node identification symbols from all charts that contain nodes")); + enumData.push_back(EventTypeEnum(EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM, + "EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM", + "Get transformation for converting object coordinates to window coordinates")); + enumData.push_back(EventTypeEnum(EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, "EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE", "Operating system requests open data file (Mac only)")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index ea319b502..ede8246bb 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -158,6 +158,8 @@ public: EVENT_MODEL_SURFACE_GET, /** Get the color for a node's identification symbol from a chart that contains the node */ EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, + /** Get the transformation for converting object coordinates to window coordinates */ + EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM, /** open file request from the operating system (Mac only) for now */ EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, /** request display of overlay settings editor */ diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index c034eb124..2957c0b70 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -12,6 +12,7 @@ EventGraphicsOpenGLCreateBufferObject.h EventGraphicsOpenGLCreateTextureName.h EventGraphicsOpenGLDeleteBufferObject.h EventGraphicsOpenGLDeleteTextureName.h +EventOpenGLObjectToWindowTransform.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h @@ -30,6 +31,7 @@ EventGraphicsOpenGLCreateBufferObject.cxx EventGraphicsOpenGLCreateTextureName.cxx EventGraphicsOpenGLDeleteBufferObject.cxx EventGraphicsOpenGLDeleteTextureName.cxx +EventOpenGLObjectToWindowTransform.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx diff --git a/src/Graphics/EventOpenGLObjectToWindowTransform.cxx b/src/Graphics/EventOpenGLObjectToWindowTransform.cxx new file mode 100644 index 000000000..d2bd9ded9 --- /dev/null +++ b/src/Graphics/EventOpenGLObjectToWindowTransform.cxx @@ -0,0 +1,230 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ +#include "EventOpenGLObjectToWindowTransform.h" +#undef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ + +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventOpenGLObjectToWindowTransform + * \brief Get a transform for converting OpenGL Object to Window Coordinates + * \ingroup Graphics + * + * Creates a transform (matrix) that is used to convert + * object coordinates to window coordinates. + * There must be a valid OpenGL context that is "current". + */ + +/** + * Constructor. + * + * @param spaceType + * Type of space of objects being transformed + */ +EventOpenGLObjectToWindowTransform::EventOpenGLObjectToWindowTransform(const SpaceType spaceType) +: Event(EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM), +m_spaceType(spaceType) +{ + +} + +/** + * Destructor. + */ +EventOpenGLObjectToWindowTransform::~EventOpenGLObjectToWindowTransform() +{ +} + +/** + * @return The object to window matrix. + */ +Matrix4x4 +EventOpenGLObjectToWindowTransform::getMatrix() const +{ + return m_transformMatrix; +} + + +/** + * @return Is the data for performing transformations valid? + */ +bool +EventOpenGLObjectToWindowTransform::isValid() const +{ + return m_validFlag; +} + +/** + * Transform an object coordinate to a window coordinate. + * + * @param objectXYZ + * The object's coordinate. + * @param windowXYZOut + * Output containing the computed window coordinate. + * @return + * True if output coordinate is valid, else false. + */ +bool +EventOpenGLObjectToWindowTransform::transformPoint(const float objectXYZ[3], + float windowXYZOut[3]) const +{ + if ( ! m_validFlag) { + CaretAssert(0); + CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform is not valid"); + return false; + } + + float xyzw[4] = { objectXYZ[0], objectXYZ[1], objectXYZ[2], 1.0f }; + m_transformMatrix.multiplyPoint4(xyzw); + windowXYZOut[0] = m_viewport[0] + (m_viewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); + windowXYZOut[1] = m_viewport[1] + (m_viewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); + windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; + + /* + * From OpenGL Programming Guide 3rd Ed, p 133: + * + * If the near value is 1.0 and the far value is 3.0, + * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. + * So, negate the Z-value to be negative. + */ + const float windowZ = windowXYZOut[2]; + windowXYZOut[2] = -windowXYZOut[2]; + + bool modelSpaceFlag = false; + bool volumeSpaceFlag = false; + switch (m_spaceType) { + case SpaceType::MODEL: + modelSpaceFlag = true; + break; + case SpaceType::VOLUME_SLICE_MODEL: + modelSpaceFlag = true; + volumeSpaceFlag = true; + break; + case SpaceType::WINDOW: + break; + } + /* + * If window space, we DO NOT need to offset for the 'eye' location + * Even when we do, the offset for the eye is very small + */ + if (modelSpaceFlag) { + if ((m_projectionMatrixArray[0] != 0.0) + && (m_projectionMatrixArray[5] != 0.0) + && (m_projectionMatrixArray[10] != 0.0)) { + /* + * From http://lektiondestages.blogspot.com/2013/11/decompose-opengl-projection-matrix.html + */ + float nearValue = (1.0f + m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; + float farValue = -(1.0f - m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; + float left = -(1.0f + m_projectionMatrixArray[12]) / m_projectionMatrixArray[0]; + float right = (1.0f - m_projectionMatrixArray[12]) / m_projectionMatrixArray[0]; + + /* + * Depending upon view, near may be positive and far negative + */ + const float farNearRange = std::fabs(farValue - nearValue); + if ((m_centerToEyeDistance > 0.0) + && (farNearRange > 0.0)) { + /* + * Using gluLookAt moves the eye away from the center which + * causes the window Z to also move. Thus, we need to remove + * this amount from the window's Z-coordinate. + */ + const float eyeAdjustment = (m_centerToEyeDistance / farNearRange); + if (volumeSpaceFlag) { + windowXYZOut[2] = -(windowZ - eyeAdjustment); + } + else if (left > right) { + windowXYZOut[2] = -(windowZ - eyeAdjustment); + } + else { + windowXYZOut[2] = -(windowZ + eyeAdjustment); + } + } + } + } + + return true; +} + +/** + * Setup the transformation's data. + * + * @param modelviewMatrixArray + * The OpenGL modelview matrix as an array. + * @param projectionMatrixArray + * The OpenGL projection matrix as an array. + * @param viewport + * The OpenGL Viewport (x, y, w, h) + * @param depthRange + * The depth range (near, far) + * @param centerToEyeDistance + * Distance from object space center to the viewer's eye along Z-axis. + */ +void +EventOpenGLObjectToWindowTransform::setup(const std::array& modelviewMatrixArray, + const std::array& projectionMatrixArray, + const std::array& viewport, + const std::array& depthRange, + const double centerToEyeDistance) +{ + m_projectionMatrixArray = projectionMatrixArray; + m_viewport = viewport; + m_depthRange = depthRange; + m_centerToEyeDistance = centerToEyeDistance; + + Matrix4x4 modelviewMatrix; + modelviewMatrix.setMatrixFromOpenGL(modelviewMatrixArray.data()); + + m_transformMatrix.setMatrixFromOpenGL(m_projectionMatrixArray.data()); + //m_projectionMatrix.postmultiply(modelviewMatrix); + m_transformMatrix.premultiply(modelviewMatrix); + + const bool autoDetectWindowSpaceFlag = false; + if (autoDetectWindowSpaceFlag) { + /* + * Far/near from http://lektiondestages.blogspot.com/2013/11/decompose-opengl-projection-matrix.html + */ + const float nearValue = (1.0f + m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; + const float farValue = -(1.0f - m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; + + /* + * Window space when near is zero, far is one + */ + const float smallValue = 0.005; + if ((std::fabs(nearValue) < smallValue) + && (std::fabs(farValue - 1.0) < smallValue)) { + //m_windowDepthFlag = true; + } + } + + m_validFlag = true; +} diff --git a/src/Graphics/EventOpenGLObjectToWindowTransform.h b/src/Graphics/EventOpenGLObjectToWindowTransform.h new file mode 100644 index 000000000..785471d6f --- /dev/null +++ b/src/Graphics/EventOpenGLObjectToWindowTransform.h @@ -0,0 +1,96 @@ +#ifndef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ +#define __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "Event.h" +#include "Matrix4x4.h" + + +namespace caret { + + class EventOpenGLObjectToWindowTransform : public Event { + + public: + /** + * Space in which data is drawn + */ + enum class SpaceType { + /** Transformation data that is being drawn in model space (except volume)*/ + MODEL, + /** Transformation data that is being drawn in VOLUME model space*/ + VOLUME_SLICE_MODEL, + /** Transformation data that is being drawn in window space*/ + WINDOW + }; + + EventOpenGLObjectToWindowTransform(const SpaceType spaceType); + + virtual ~EventOpenGLObjectToWindowTransform(); + + Matrix4x4 getMatrix() const; + + bool isValid() const; + + bool transformPoint(const float objectXYZ[3], + float windowXYZOut[3]) const; + + void setup(const std::array& modelviewMatrixArray, + const std::array& projectionMatrixArray, + const std::array& viewport, + const std::array& depthRange, + const double centerToEyeDistance); + + // ADD_NEW_METHODS_HERE + + private: + EventOpenGLObjectToWindowTransform(const EventOpenGLObjectToWindowTransform&); + + EventOpenGLObjectToWindowTransform& operator=(const EventOpenGLObjectToWindowTransform&); + + const SpaceType m_spaceType; + + Matrix4x4 m_transformMatrix; + + std::array m_projectionMatrixArray; + + std::array m_viewport; + + std::array m_depthRange; + + double m_centerToEyeDistance; + + bool m_validFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ + // +#endif // __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ + +} // namespace +#endif //__EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index a1bc43a22..b597c39a3 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -32,8 +32,9 @@ #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "EventManager.h" +#include "EventOpenGLObjectToWindowTransform.h" #include "MathFunctions.h" -#include "Matrix4x4.h" using namespace caret; @@ -289,7 +290,7 @@ GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut saveOpenGLState(); - createProjectionMatrix(); + createTransform(); createWindowCoordinatesFromVertices(); @@ -306,20 +307,25 @@ GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut GraphicsPrimitive* primitiveOut = NULL; - if (m_primitive->isValid()) { - if (m_primitiveByteColor.get() != NULL) { - primitiveOut = m_primitiveByteColor.release(); - } - else if (m_primitiveFloatColor.get() != NULL) { - primitiveOut = m_primitiveFloatColor.release(); + if (m_primitive != NULL) { + if (m_primitive->isValid()) { + if (m_primitiveByteColor.get() != NULL) { + primitiveOut = m_primitiveByteColor.release(); + } + else if (m_primitiveFloatColor.get() != NULL) { + primitiveOut = m_primitiveFloatColor.release(); + } + else { + CaretAssert(0); + errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; + } } else { - CaretAssert(0); - errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; + errorMessageOut = "Converted primitive is invalid."; } } else { - errorMessageOut = "Converted primitive is invalid."; + errorMessageOut = "Primitive invalid, all points may be coincident"; } return primitiveOut; @@ -381,24 +387,17 @@ GraphicsOpenGLPolylineTriangles::restoreOpenGLState() } /** - * Create the projection matrix. + * Create the transform matrix. */ void -GraphicsOpenGLPolylineTriangles::createProjectionMatrix() +GraphicsOpenGLPolylineTriangles::createTransform() { - GLdouble modelviewArray[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, - modelviewArray); - Matrix4x4 modelviewMatrix; - modelviewMatrix.setMatrixFromOpenGL(modelviewArray); - - GLdouble projectionArray[16]; - glGetDoublev(GL_PROJECTION_MATRIX, - projectionArray); - - m_projectionMatrix.setMatrixFromOpenGL(projectionArray); - //m_projectionMatrix.postmultiply(modelviewMatrix); - m_projectionMatrix.premultiply(modelviewMatrix); + m_transformEvent.reset(new EventOpenGLObjectToWindowTransform(EventOpenGLObjectToWindowTransform::SpaceType::WINDOW)); + EventManager::get()->sendEvent(m_transformEvent.get()->getPointer()); + if ( ! m_transformEvent->isValid()) { + CaretLogSevere("Getting OpenGL Transform Failed"); + return; + } } @@ -532,20 +531,9 @@ void GraphicsOpenGLPolylineTriangles::convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const { - float xyzw[4] = { modelXYZ[0], modelXYZ[1], modelXYZ[2], 1.0f }; - m_projectionMatrix.multiplyPoint4(xyzw); - windowXYZOut[0] = m_savedViewport[0] + (m_savedViewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); - windowXYZOut[1] = m_savedViewport[1] + (m_savedViewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); - windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; - - /* - * From OpenGL Programming Guide 3rd Ed, p 133: - * - * If the near value is 1.0 and the far value is 3.0, - * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. - * So, negate the Z-value to be negative. - */ - windowXYZOut[2] = -windowXYZOut[2]; + CaretAssert(m_transformEvent); + m_transformEvent->transformPoint(modelXYZ, + windowXYZOut); } /** @@ -987,10 +975,10 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, /* * Join the right side that is first two vertices in triangle two */ - quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; - quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; - quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; + quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; + quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; + quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; break; case TurnDirection::PARALLEL: if (m_debugFlag) std::cout << " Miter Parallel" << std::endl; @@ -1003,10 +991,10 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, /* * Join left side that is first and third vertices in triangle one */ - quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; - quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; - quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; + quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; + quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; + quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; break; } @@ -1096,166 +1084,6 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, } } -///** -// * Join the second triangle in poly one to poly two. -// * -// * @param polyOne -// * Info about triangles in first polyline -// * @param polyTwo -// * Info about triangles in second polyline -// */ -//void -//GraphicsOpenGLPolylineTriangles::performJoin(const PolylineInfo& polyOne, -// const PolylineInfo& polyTwo) -//{ -// const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; -// const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; -// const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; -// -// if (m_debugFlag) std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; -// CaretAssert(m_primitive); -// -// /* -// * Determine if the junction of the two consecutive -// * line segments in window coordinates makes a left -// * or right turn -// */ -// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); -// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); -// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); -// const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], -// &m_vertexWindowXYZ[windowVertexIndexTwo * 3], -// &m_vertexWindowXYZ[windowVertexIndexThree * 3]); -// -// -// int32_t quadOneSideBeginVertexIndex = -1; -// int32_t quadOneSideEndVertexIndex = -1; -// int32_t quadTwoSideBeginVertexIndex = -1; -// int32_t quadTwoSideEndVertexIndex = -1; -// const float smallNumber = 0.001; -// bool leftTurnFlag = false; -// if (signedArea > smallNumber) { -// leftTurnFlag = true; -// if (m_debugFlag) std::cout << " Left Turn" << std::endl; -// /* -// * Right side is first two vertices in triangle two -// */ -// quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; //quadOneVertexIndex + 1; -// quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; -// quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; -// quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; //quadTwoVertexIndex + 2; -// } -// else if (signedArea < -smallNumber) { -// if (m_debugFlag) std::cout << " Right Turn" << std::endl; -// /* -// * Left side is first and third vertices in triangle one -// */ -// quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; //quadOneVertexIndex; -// quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; -// quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; -// quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; //quadTwoVertexIndex + 3; -// } -// else { -// if (m_debugFlag) std::cout << " Parallel" << std::endl; -// return; -// } -// -// switch (m_joinType) { -// case JoinType::BEVEL: -// break; -// case JoinType::MITER: -// break; -// case JoinType::NONE: -// CaretAssert(0); -// break; -// } -// -// const std::vector& xyz = m_primitive->getFloatXYZ(); -// CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); -// CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); -// CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); -// CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); -// const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; -// const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; -// const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; -// const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; -// -// /* -// * Miter limit is a multiple of the line thickness -// */ -// const float miterLimit = m_lineThicknessPixels;// * 2.0f; -// const float miterLimitSquared = miterLimit * miterLimit; -// -// /* -// * Find location of where the edges in the quads intersect -// */ -// float intersectionXYZ[3]; -// if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { -// intersectionXYZ[2] = q1v1[2]; -// if (m_debugFlag) std::cout << " Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; -// -// /* -// * When the angle is very sharp, the miter point can be very long and pointy -// * so limit to a multiplier of the line thickness -// */ -// CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); -// const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; -// const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, -// intersectionXYZ); -// if (distanceSquared > miterLimitSquared) { -// /* -// * Extend lines by the miter limit to create a new quad -// */ -// float newV1[3]; -// createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); -// float newV2[3]; -// createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); -// -// /* -// * Extend vertices to the new miter limit -// */ -// int32_t primitiveIndexV1 = -1; -// int32_t primitiveIndexV2 = -1; -// if (leftTurnFlag) { -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], newV1); -// primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[1]; -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], newV2); -// primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[1]; -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], newV2); -// } -// else { -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], newV1); -// primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[2]; -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], newV1); -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], newV2); -// primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[0]; -// } -// -// /* -// * Add a triangle to fill in the gap -// */ -// m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, -// primitiveIndexV1, -// primitiveIndexV2)); -// } -// else { -// /* -// * Move the existing quad vertices to their intersection point -// */ -// if (leftTurnFlag) { -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], intersectionXYZ); -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], intersectionXYZ); -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], intersectionXYZ); -// } -// else { -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], intersectionXYZ); -// m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], intersectionXYZ); -// m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], intersectionXYZ); -// } -// } -// } -//} - /** * Create a vertex for a miter join when the length limit is exceeded * diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index 5a07bdd86..ba1bd2cf2 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -27,10 +27,10 @@ #include #include "CaretObject.h" -#include "Matrix4x4.h" namespace caret { + class EventOpenGLObjectToWindowTransform; class GraphicsPrimitive; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; @@ -163,7 +163,7 @@ namespace caret { void restoreOpenGLState(); - void createProjectionMatrix(); + void createTransform(); void convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const; @@ -219,7 +219,7 @@ namespace caret { int m_savedViewport[4]; - Matrix4x4 m_projectionMatrix; + std::unique_ptr m_transformEvent; /* * The base class graphics primitive that points to -- GitLab From b8d1d3d2e9a17f57bf23553ccf15aa747ed5a02d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Nov 2017 11:14:40 -0600 Subject: [PATCH 509/755] In annotation drawing, remove usage of gluProject and instead, use the new EventOpenGLObjectToWindowTransform for transforming model space to window space. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 80 ++++--------------- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 5 +- 2 files changed, 19 insertions(+), 66 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index d7eff031e..318576e73 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -50,6 +50,7 @@ #include "DisplayPropertiesAnnotation.h" #include "EventBrowserTabGet.h" #include "EventManager.h" +#include "EventOpenGLObjectToWindowTransform.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" @@ -343,71 +344,12 @@ bool BrainOpenGLAnnotationDrawingFixedPipeline::convertModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const { - /* - * Convert model space coordinates to window coordinates - * as all annotations are drawn in window coordinates. - */ - GLdouble modelDoubleXYZ[3] = { modelXYZ[0], modelXYZ[1], modelXYZ[2] }; - GLdouble windowX, windowY, windowZ; - if (gluProject(modelDoubleXYZ[0], modelDoubleXYZ[1], modelDoubleXYZ[2], - m_modelSpaceModelMatrix, m_modelSpaceProjectionMatrix, m_modelSpaceViewport, - &windowX, &windowY, &windowZ) == GL_TRUE) { - windowXYZOut[0] = windowX - m_modelSpaceViewport[0]; - windowXYZOut[1] = windowY - m_modelSpaceViewport[1]; - - /* - * From OpenGL Programming Guide 3rd Ed, p 133, - * or 6th Ed, p 142 - * - * Remember that with the projection commands, the near and far coordinates measure - * distance from the viewpoint and that (by default) you're looking down the negative - * z axis. Thus, if the near value is 1.0 and the far 3.0, objects must have z coordinates - * between -1.0 and -3.0 in order to be visible. To ensure that you haven't clipped - * everything out of your scene, temporarily set the near and far clipping planes to - * some absurdly inclusive values, such as 0.001 and 1000000.0. This alters appearance - * for operations such as depth-buffering and fog, but it might uncover inadvertently - * clipped objects. */ - windowXYZOut[2] = -windowZ; - - if ((m_modelSpaceProjectionMatrix[0] != 0.0) - && (m_modelSpaceProjectionMatrix[5] != 0.0) - && (m_modelSpaceProjectionMatrix[10] != 0.0)) { - /* - * From http://lektiondestages.blogspot.com/2013/11/decompose-opengl-projection-matrix.html - */ - float nearValue = (1.0f + m_modelSpaceProjectionMatrix[14]) / m_modelSpaceProjectionMatrix[10]; - float farValue = -(1.0f - m_modelSpaceProjectionMatrix[14]) / m_modelSpaceProjectionMatrix[10]; - float left = -(1.0f + m_modelSpaceProjectionMatrix[12]) / m_modelSpaceProjectionMatrix[0]; - float right = (1.0f - m_modelSpaceProjectionMatrix[12]) / m_modelSpaceProjectionMatrix[0]; - - /* - * Depending upon view, near may be positive and far negative - */ - const float farNearRange = std::fabs(farValue - nearValue); - if ((m_inputs->m_centerToEyeDistance > 0.0) - && (farNearRange > 0.0)) { - /* - * Using gluLookAt moves the eye away from the center which - * causes the window Z to also move. Thus, we need to remove - * this amount from the window's Z-coordinate. - */ - const float eyeAdjustment = (m_inputs->m_centerToEyeDistance / farNearRange); - if (m_volumeSpacePlaneValid) { - windowXYZOut[2] = -(windowZ - eyeAdjustment); - } - else if (left > right) { - windowXYZOut[2] = -(windowZ - eyeAdjustment); - } - else { - windowXYZOut[2] = -(windowZ + eyeAdjustment); - } - } - } - - return true; - } - - return false; + CaretAssert(m_transformEvent); + CaretAssert(m_transformEvent->isValid()); + m_transformEvent->transformPoint(modelXYZ, windowXYZOut); + windowXYZOut[0] -= m_modelSpaceViewport[0]; + windowXYZOut[1] -= m_modelSpaceViewport[1]; + return true; } /** @@ -604,6 +546,14 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat return; } + EventOpenGLObjectToWindowTransform::SpaceType spaceType = EventOpenGLObjectToWindowTransform::SpaceType::MODEL; + if (m_volumeSpacePlaneValid) { + spaceType = EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL; + } + m_transformEvent.reset(new EventOpenGLObjectToWindowTransform(spaceType)); + EventManager::get()->sendEvent(m_transformEvent.get()->getPointer()); + CaretAssert(m_transformEvent->isValid()); + m_volumeSliceThickness = sliceThickness; setSelectionBoxColor(); diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index cfa6c75c4..beb1db1ed 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include #include "AnnotationCoordinateSpaceEnum.h" @@ -44,8 +45,8 @@ namespace caret { class AnnotationText; class AnnotationTwoDimensionalShape; class Brain; - class BrainOpenGLFixedPipeline; + class EventOpenGLObjectToWindowTransform; class Surface; class BrainOpenGLAnnotationDrawingFixedPipeline : public CaretObject { @@ -348,6 +349,8 @@ namespace caret { float m_lineWidthMinimum = 1.0f; + std::unique_ptr m_transformEvent; + static constexpr float s_sizingHandleLineWidthInPixels = 2.0f; // ADD_NEW_MEMBERS_HERE -- GitLab From 44b58de5a025bc11d246cbb43abe1ed49e5b2f33 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Nov 2017 12:44:02 -0600 Subject: [PATCH 510/755] Fixed histogram envelope drawing. It was mistakenly drawn with a line loop so that the end connected to the start. It has been corrected to use a line strip. --- src/Files/ChartableTwoFileHistogramChart.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 3774d34d5..20881e01d 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -417,7 +417,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m */ GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); - GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN); + GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN); envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; -- GitLab From 70a45062761b40a4f2e9b0550f1945f0f3cb48e2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Nov 2017 15:30:36 -0600 Subject: [PATCH 511/755] Replaced some older graphics code in chart two drawing and changed some items (chart box, ticks, matrix row highlight, etc) to line widths that are a percentage of the viewport height. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 128 ++++++++++-------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 5 +- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 705276029..06b5ec830 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -49,11 +49,13 @@ #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" +#include "DeveloperFlagsEnum.h" #include "FastStatistics.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsShape.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "ModelChartTwo.h" @@ -963,12 +965,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch 0.0); } - const float LINE_SERIES_LINE_WIDTH = 1.0f; if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; - BrainOpenGL::setLineWidth(LINE_SERIES_LINE_WIDTH * 5.0f); GraphicsEngineDataOpenGL::drawWithSelection(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -991,7 +991,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch * will alter the colors during drawing). */ m_fixedPipelineDrawing->enableLineAntiAliasing(); - BrainOpenGL::setLineWidth(lineChart.m_chartTwoCartesianData->getLineWidth()); GraphicsEngineDataOpenGL::draw(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); m_fixedPipelineDrawing->disableLineAntiAliasing(); } @@ -1224,7 +1223,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() glPushMatrix(); glLoadMatrixf(mrch->m_modelViewMatrix); - BrainOpenGL::setLineWidth(mrch->m_lineWidth); drawPrimitivePrivate(mrch->m_graphicsPrimitive.get()); delete mrch; @@ -1312,14 +1310,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { - glPolygonMode(GL_FRONT, - GL_LINE); - GraphicsPrimitiveV3fC4f* matrixGridPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, CiftiMappableDataFile::MatrixGridMode::OUTLINE); drawPrimitivePrivate(matrixGridPrimitive); - glPolygonMode(GL_FRONT, - GL_FILL); } int32_t numberOfRows = 0; @@ -1352,6 +1345,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT * Disabled by WB-741 */ const bool limitSelectionToTriangularFlag = false; + const float lineWidthPercentageHeight = 1.0f; for (auto rowIndex : selectedRowIndices) { float minX = 0; @@ -1374,19 +1368,18 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } } - const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - - GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); + GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN); rowOutlineData->reserveForNumberOfVertices(4); rowOutlineData->addVertex(minX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, maxY, highlightRGBA); rowOutlineData->addVertex(minX, maxY, highlightRGBA); + rowOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + lineWidthPercentageHeight); float modelViewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(rowOutlineData, - highlightLineWidth, modelViewMatrix)); } @@ -1411,20 +1404,20 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT } } - const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); +// const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); - GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP); + GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN); columnOutlineData->reserveForNumberOfVertices(4); columnOutlineData->addVertex(minX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, maxY, highlightRGBA); columnOutlineData->addVertex(minX, maxY, highlightRGBA); - columnOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, highlightLineWidth); + columnOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + lineWidthPercentageHeight); float modelViewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(columnOutlineData, - highlightLineWidth, modelViewMatrix)); } } @@ -1502,9 +1495,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToOpenGLLine if (pixelsWidthOrHeight < s_minimumLineWidthOpenGL) { pixelsWidthOrHeight = s_minimumLineWidthOpenGL; } - if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { - pixelsWidthOrHeight = s_maximumLineWidthOpenGL; - } +// if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { +// pixelsWidthOrHeight = s_maximumLineWidthOpenGL; +// } return pixelsWidthOrHeight; } @@ -1594,26 +1587,45 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const float boxBottom = bottomAxisHeight + halfGridLineWidth; const float boxTop = vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; - /* - * We adjust the horizontal lines by half the line width. - * Otherwise, there will be 'corner gaps' where the horizontal - * and vertical lines are joined - */ - std::unique_ptr boxData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - const float cornerOffset = halfGridLineWidth; - boxData->reserveForNumberOfVertices(8); - boxData->addVertex(boxLeft - cornerOffset, boxBottom); - boxData->addVertex(boxRight + cornerOffset, boxBottom); - boxData->addVertex(boxRight, boxBottom); - boxData->addVertex(boxRight, boxTop); - boxData->addVertex(boxRight + cornerOffset, boxTop); - boxData->addVertex(boxLeft - cornerOffset, boxTop); - boxData->addVertex(boxLeft, boxTop); - boxData->addVertex(boxLeft, boxBottom); - boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); - drawPrimitivePrivate(boxData.get()); + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + /* + * We adjust the horizontal lines by half the line width. + * Otherwise, there will be 'corner gaps' where the horizontal + * and vertical lines are joined + */ + std::unique_ptr boxData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + boxData->reserveForNumberOfVertices(4); + boxData->addVertex(boxLeft, boxBottom); + boxData->addVertex(boxRight, boxBottom); + boxData->addVertex(boxRight, boxTop); + boxData->addVertex(boxLeft, boxTop); + boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); + drawPrimitivePrivate(boxData.get()); + } + else { + /* + * We adjust the horizontal lines by half the line width. + * Otherwise, there will be 'corner gaps' where the horizontal + * and vertical lines are joined + */ + std::unique_ptr boxData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + const float cornerOffset = halfGridLineWidth; + boxData->reserveForNumberOfVertices(8); + boxData->addVertex(boxLeft - cornerOffset, boxBottom); + boxData->addVertex(boxRight + cornerOffset, boxBottom); + boxData->addVertex(boxRight, boxBottom); + boxData->addVertex(boxRight, boxTop); + boxData->addVertex(boxRight + cornerOffset, boxTop); + boxData->addVertex(boxLeft - cornerOffset, boxTop); + boxData->addVertex(boxLeft, boxTop); + boxData->addVertex(boxLeft, boxBottom); + boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); + drawPrimitivePrivate(boxData.get()); + } } /* @@ -2276,13 +2288,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo if (debugFlag) { glColor3f(1.0, 0.0, 0.0); - BrainOpenGL::setLineWidth(1.0); - glBegin(GL_LINE_LOOP); - glVertex2f(vpX, vpY); - glVertex2f(vpX + vpWidth, vpY); - glVertex2f(vpX + vpWidth, vpY + vpHeight); - glVertex2f(vpX, vpY + vpHeight); - glEnd(); + const float v1[3] = { vpX, vpY, 0.0f }; + const float v2[3] = { vpX + vpWidth, vpY, 0.0f }; + const float v3[3] = { vpX + vpWidth, vpY + vpHeight, 0.0f }; + const float v4[3] = { vpX, vpY + vpHeight, 0.0f }; + GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, + (uint8_t[]){ 255, 0, 0, 255}, + GraphicsPrimitive::SizeType::PIXELS, 1.0f); } /* @@ -2392,8 +2404,12 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh if (numScaleValuesToDraw > 0) { const bool showTicksEnabledFlag = m_axis->isShowTickmarks(); + GraphicsPrimitive::PrimitiveType primitiveType = GraphicsPrimitive::PrimitiveType::OPENGL_LINES; + if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + primitiveType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES; + } std::unique_ptr ticksData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(primitiveType, foregroundFloatRGBA)); ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); @@ -2465,7 +2481,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh /* * Draw the ticks. */ - BrainOpenGL::setLineWidth(m_lineDrawingWidth); ticksData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } @@ -2640,14 +2655,13 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float } if (debugFlag) { - glColor3f(1.0, 0.0, 0.0); - BrainOpenGL::setLineWidth(2.0); - glBegin(GL_LINE_LOOP); - glVertex2f(m_titleViewport[0], m_titleViewport[1]); - glVertex2f(m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1]); - glVertex2f(m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3]); - glVertex2f(m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3]); - glEnd(); + const float v1[3] = { m_titleViewport[0], m_titleViewport[1], 0.0f }; + const float v2[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1], 0.0f }; + const float v3[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3], 0.0f }; + const float v4[3] = { m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3], 0.0f }; + GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, + (uint8_t[]){ 255, 0, 0, 255}, + GraphicsPrimitive::SizeType::PIXELS, 2.0f); } m_text->setTextColor(CaretColorEnum::CUSTOM); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index ca69247b6..fa407652f 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -207,15 +207,12 @@ namespace caret { class MatrixRowColumnHighight { public: MatrixRowColumnHighight(GraphicsPrimitive* graphicsPrimitive, - const float lineWidth, const float modelViewMatrix[16]) - : m_graphicsPrimitive(std::unique_ptr(graphicsPrimitive)), - m_lineWidth(lineWidth) { + : m_graphicsPrimitive(std::unique_ptr(graphicsPrimitive)) { for (int32_t i = 0; i < 16; i++) m_modelViewMatrix[i] = modelViewMatrix[i]; } std::unique_ptr m_graphicsPrimitive; - float m_lineWidth; float m_modelViewMatrix[16]; }; -- GitLab From e96bf0727d5f8101e75118fa642f22815fcdc54b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 22 Nov 2017 16:03:15 -0600 Subject: [PATCH 512/755] Removed some calls to enable line anti-aliasing since it only works with OpenGL lines and the lines are now being drawn as triangles to avoid OpenGL line width limitations. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 11 ++++++-- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 28 ++++++------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 318576e73..3b49d97c3 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -47,6 +47,7 @@ #include "CaretAssert.h" #include "CaretColorEnum.h" #include "CaretLogger.h" +#include "DeveloperFlagsEnum.h" #include "DisplayPropertiesAnnotation.h" #include "EventBrowserTabGet.h" #include "EventManager.h" @@ -974,9 +975,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::startOpenGLForDrawing(GLint* savedSha glLoadIdentity(); /* - * Enable anti-aliasing for lines and polygons + * Enable anti-aliasing for lines */ - m_brainOpenGLFixedPipeline->enableLineAntiAliasing(); + if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + m_brainOpenGLFixedPipeline->enableLineAntiAliasing(); + } } /** @@ -994,7 +997,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::endOpenGLForDrawing(GLint savedShadeM /* * Disable anti-aliasing for lines */ - m_brainOpenGLFixedPipeline->disableLineAntiAliasing(); + if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { + m_brainOpenGLFixedPipeline->disableLineAntiAliasing(); + } if (savedLightingEnabled) { glEnable(GL_LIGHTING); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 06b5ec830..4596b7b6e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -839,8 +839,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if (histogramPrimitives != NULL) { const float lineWidthPercentage = histogramPrimitives->getEnvelopeLineWidthPercentage(); - const float envelopeLineWidth = convertPercentageOfViewportToOpenGLLineWidth(lineWidthPercentage, - tabViewportHeight); if (m_identificationModeFlag) { int32_t primitiveIndex = -1; @@ -874,8 +872,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Increase line width for identification */ - histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, - envelopeLineWidth * 3.0f); + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + (lineWidthPercentage + 0.5)); GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, @@ -898,11 +896,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { - histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, - envelopeLineWidth); - m_fixedPipelineDrawing->enableLineAntiAliasing(); + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + lineWidthPercentage); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); - m_fixedPipelineDrawing->disableLineAntiAliasing(); } } } @@ -984,15 +980,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch } } else { - /* - * Note: Anti-aliasing is only enabled when drawing the line. - * Anti-aliasing cannot be enabled during identification since - * identification encodes information in the colors (anti-aliasing - * will alter the colors during drawing). - */ - m_fixedPipelineDrawing->enableLineAntiAliasing(); GraphicsEngineDataOpenGL::draw(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); - m_fixedPipelineDrawing->disableLineAntiAliasing(); } /* @@ -1601,7 +1589,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons boxData->addVertex(boxRight, boxBottom); boxData->addVertex(boxRight, boxTop); boxData->addVertex(boxLeft, boxTop); - boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); + boxData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + lineThicknessPercentage); drawPrimitivePrivate(boxData.get()); } else { @@ -1623,7 +1612,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons boxData->addVertex(boxLeft - cornerOffset, boxTop); boxData->addVertex(boxLeft, boxTop); boxData->addVertex(boxLeft, boxBottom); - boxData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, lineThicknessPixels); + boxData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + lineThicknessPercentage); drawPrimitivePrivate(boxData.get()); } } @@ -2480,6 +2470,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh /* * Draw the ticks. + * Note Line width is set in pixel and was converted from PERCENTAGE OF VIEWPORT HEIGHT */ ticksData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); @@ -2510,7 +2501,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh boxPrimitive->addVertex(bottomLeft); boxPrimitive->addVertex(topRight); boxPrimitive->addVertex(bottomRight); - boxPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); GraphicsEngineDataOpenGL::drawWithSelection(boxPrimitive.get(), mouseX, -- GitLab From 367608450188193e8bffc1b86a0cf381f3f06547 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 27 Nov 2017 09:58:27 -0600 Subject: [PATCH 513/755] Corrections for setup and drawing of histogram as envelope. --- src/Files/ChartableTwoFileHistogramChart.cxx | 36 +--- .../GraphicsOpenGLPolylineTriangles.cxx | 16 +- src/Graphics/GraphicsPrimitive.cxx | 167 ++++++++---------- 3 files changed, 94 insertions(+), 125 deletions(-) diff --git a/src/Files/ChartableTwoFileHistogramChart.cxx b/src/Files/ChartableTwoFileHistogramChart.cxx index 20881e01d..25a0bf74b 100644 --- a/src/Files/ChartableTwoFileHistogramChart.cxx +++ b/src/Files/ChartableTwoFileHistogramChart.cxx @@ -450,7 +450,7 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m threshRGBA[2] = static_cast(threshByteRGBA[2]) / 255.0f; threshRGBA[3] = 1.0; } - const float minX = -1000000.0f; //minValueX; + const float minX = -1000000.0f; const float maxX = 1000000.0f; const float minY = 0.0; const float maxY = *std::max_element(histogramBuckets.begin(), @@ -570,42 +570,24 @@ ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t m if (envelopeSolidColorFlag) { const float envelopeX = x + halfBucketWidth; + if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); } - else { - const float xPrevious = envelopeX - bucketWidth; - CaretAssertVectorIndex(histogramBuckets, i - 1); - const float yPrevious = histogramBuckets[i - 1]; - - envelopePrimitive->addVertex(xPrevious, yPrevious, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); - envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); - } + envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); } } else { const float envelopeX = x + halfBucketWidth; + if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, rgba); - envelopePrimitive->addVertex(envelopeX, yMax, rgba); } - else { - const float xPrevious = envelopeX - bucketWidth; - CaretAssertVectorIndex(histogramBuckets, i - 1); - const float yPrevious = histogramBuckets[i - 1]; - CaretAssertVectorIndex(histogramRGBA, (i - 1) * 4 + 3); - - envelopePrimitive->addVertex(xPrevious, yPrevious, &histogramRGBA[(i - 1) * 4]); - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - - if (i == (numBucketValues - 1)) { - envelopePrimitive->addVertex(envelopeX, yMax, rgba); - envelopePrimitive->addVertex(envelopeX, yMin, rgba); - } + envelopePrimitive->addVertex(envelopeX, yMax, rgba); + if (i == (numBucketValues - 1)) { + envelopePrimitive->addVertex(envelopeX, yMin, rgba); } } diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index b597c39a3..0b8f94ec6 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -460,7 +460,11 @@ GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, &m_vertexWindowXYZ[previousPointOffset]); if (distSQ < coincidentMaxDistSQ) { - CaretLogSevere("Filtered out connected segment conincident point " + AString::number(i)); + CaretLogInfo("Filtered out connected segment conincident point index=" + AString::number(i) + + " after conversion to window coordinates. " + + AString::fromNumbers(windowXYZ, 3, ",") + + " " + + AString::fromNumbers(&m_vertexWindowXYZ[previousPointOffset], 3, ",")); continue; } } @@ -899,8 +903,8 @@ GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, /* * Join the right side that is first two vertices in triangle two */ - quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; //quadOneVertexIndex + 2; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; //quadTwoVertexIndex + 1; + quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; break; case TurnDirection::PARALLEL: if (m_debugFlag) std::cout << " Parallel" << std::endl; @@ -913,8 +917,8 @@ GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, /* * Join left side that is first and third vertices in triangle one */ - quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; //quadOneVertexIndex + 3; - quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; //quadTwoVertexIndex; + quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; + quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; break; } @@ -1011,7 +1015,7 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, /* * Miter limit is a multiple of the line thickness */ - const float miterLimit = m_lineThicknessPixels;// * 2.0f; + const float miterLimit = m_lineThicknessPixels; const float miterLimitSquared = miterLimit * miterLimit; /* diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index dde8fe192..95e10a50d 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -521,85 +521,10 @@ GraphicsPrimitive::getSizeTypeAsText(const SizeType sizeType) const AString GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const { - AString s("Primitive: "); + AString s("Primitive: " + getPrimitiveTypeAsText()); - s.append(getPrimitiveTypeAsText()); - - switch (m_vertexType) { - case VertexType::FLOAT_XYZ: - s.appendWithNewLine("Vertex Count: " + AString::number(m_xyz.size() / 3) + " Float XYZ. "); - if (includeAllDataFlag ) { - s.append("\n "); - const int32_t count = static_cast(m_xyz.size()); - for (int32_t i = 0; i < count; i++) { - s.append(AString::number(m_xyz[i]) + " "); - if (((i+1) % 3) == 0) { - s.append("\n "); - } - } - s.append("\n"); - } - break; - } - - if ( ! m_polygonalLinePrimitiveRestartIndices.empty()) { - s.appendWithNewLine("Polygonal Line Primitive Restart Indices Count: " + AString::number(m_polygonalLinePrimitiveRestartIndices.size())); - if (includeAllDataFlag) { - std::vector temp(m_polygonalLinePrimitiveRestartIndices.begin(), - m_polygonalLinePrimitiveRestartIndices.end()); - s.appendWithNewLine(" " + AString::fromNumbers(temp, ", ")); - } - } - - switch (m_normalVectorType) { - case NormalVectorType::FLOAT_XYZ: - s.appendWithNewLine("Normal Vector Count: " + AString::number(m_floatNormalVectorXYZ.size() / 3) + " Float XYZ. "); - break; - if (includeAllDataFlag ) { - s.append("\n "); - const int32_t count = static_cast(m_floatNormalVectorXYZ.size()); - for (int32_t i = 0; i < count; i++) { - s.append(AString::number(m_floatNormalVectorXYZ[i]) + " "); - if (((i+1) % 3) == 0) { - s.append("\n "); - } - } - } - case NormalVectorType::NONE: - s.appendWithNewLine("Normal Vector: None. "); - break; - } - - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: - break; - case ColorType::FLOAT_RGBA: - s.appendWithNewLine("Color Count: " + AString::number(m_floatRGBA.size() / 4) + " Float RGBA 0.0 to 1.0. "); - if (includeAllDataFlag ) { - s.append("\n "); - const int32_t count = static_cast(m_floatRGBA.size()); - for (int32_t i = 0; i < count; i++) { - s.append(AString::number(m_floatRGBA[i]) + " "); - if (((i+1) % 4) == 0) { - s.append("\n "); - } - } - } - break; - case ColorType::UNSIGNED_BYTE_RGBA: - s.appendWithNewLine("Color Count: " + AString::number(m_unsignedByteRGBA.size() / 4) + " Unsigned Byte RGBA 0 to 255"); - if (includeAllDataFlag ) { - s.append("\n "); - const int32_t count = static_cast(m_unsignedByteRGBA.size()); - for (int32_t i = 0; i < count; i++) { - s.append(AString::number(m_unsignedByteRGBA[i]) + " "); - if (((i+1) % 4) == 0) { - s.append("\n "); - } - } - } - break; - } + const int32_t numVertices = getNumberOfVertices(); + s.appendWithNewLine("Number of Vertices: " + AString::number(numVertices) + "\n"); switch (m_textureType) { case TextureType::NONE: @@ -608,16 +533,6 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const s.appendWithNewLine("Texture: " + AString::number(m_floatTextureSTR.size()) + " Float Texture 0.0 to 1.0. "); s.appendWithNewLine(" Width: " + AString::number(m_textureImageWidth) + " Height: " + AString::number(m_textureImageHeight)); - if (includeAllDataFlag ) { - s.append("\n "); - const int32_t count = static_cast(m_floatTextureSTR.size()); - for (int32_t i = 0; i < count; i++) { - s.append(AString::number(m_floatTextureSTR[i]) + " "); - if (((i+1) % 3) == 0) { - s.append("\n "); - } - } - } break; } @@ -660,27 +575,95 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } + if ( ! m_polygonalLinePrimitiveRestartIndices.empty()) { + s.appendWithNewLine("Polygonal Line Primitive Restart Indices Count: " + AString::number(m_polygonalLinePrimitiveRestartIndices.size())); + if (includeAllDataFlag) { + std::vector temp(m_polygonalLinePrimitiveRestartIndices.begin(), + m_polygonalLinePrimitiveRestartIndices.end()); + s.appendWithNewLine(" " + AString::fromNumbers(temp, ", ")); + } + } + if (addLineWidthFlag) { s.appendWithNewLine("Line Width Type: " + getSizeTypeAsText(m_lineWidthType) - + "; Width Value: " + + "; Value: " + AString::number(m_lineWidthValue, 'f', 3)); } if (addPointSizeFlag) { s.appendWithNewLine("Point Diameter Type: " + getSizeTypeAsText(m_pointSizeType) - + "; Diameter Value: " + + "; Value: " + AString::number(m_pointDiameterValue, 'f', 3)); } if (addSphereSizeFlag) { s.appendWithNewLine("Sphere Diameter Type: " + getSizeTypeAsText(m_sphereSizeType) - + "; Diameter Value: " + + "; Value: " + AString::number(m_sphereDiameterValue, 'f', 3)); } - + + s.append("\n"); + if (includeAllDataFlag) { + for (int32_t i = 0; i < numVertices; i++) { + s.append(AString("%1: ").arg(i, 5)); + + switch (m_vertexType) { + case VertexType::FLOAT_XYZ: + { + CaretAssertVectorIndex(m_xyz, i*3 + 2); + const float* xyz = &m_xyz[i * 3]; + s.append(AString("%1, %2, %3").arg(xyz[0], 10, 'f', 3).arg(xyz[1], 10, 'f', 3).arg(xyz[2], 10, 'f', 3)); + } + break; + } + + switch (m_normalVectorType) { + case NormalVectorType::FLOAT_XYZ: + { + CaretAssertVectorIndex(m_floatNormalVectorXYZ, i*3 + 2); + const float* xyz = &m_floatNormalVectorXYZ[i * 3]; + s.append(AString(" N:%1, %2, %3").arg(xyz[0], 7, 'f', 5).arg(xyz[1], 7, 'f', 5).arg(xyz[2], 7, 'f', 5)); + } + case NormalVectorType::NONE: + break; + } + + switch (m_colorType) { + case GraphicsPrimitive::ColorType::NONE: + break; + case ColorType::FLOAT_RGBA: + { + CaretAssertVectorIndex(m_floatRGBA, i*4 + 3); + const float* rgba = &m_floatRGBA[i * 4]; + s.append(AString(" RGBAf: %1, %2, %3, %4").arg(rgba[0], 5, 'f', 3).arg(rgba[1], 5, 'f', 3).arg(rgba[2], 5, 'f', 3).arg(rgba[3], 5, 'f', 3)); + } + break; + case ColorType::UNSIGNED_BYTE_RGBA: + { + CaretAssertVectorIndex(m_unsignedByteRGBA, i*4 + 3); + const uint8_t* rgba = &m_unsignedByteRGBA[i * 4]; + s.append(AString(" RGBAb: %1, %2, %3, %4").arg(rgba[0], 3).arg(rgba[1], 3).arg(rgba[2], 3).arg(rgba[3], 3)); + } + } + + switch (m_textureType) { + case TextureType::NONE: + break; + case TextureType::FLOAT_STR: + { + CaretAssertVectorIndex(m_floatTextureSTR, i*3 + 2); + const float* str = &m_floatTextureSTR[i * 3]; + s.append(AString(" T:%1, %2, %3").arg(str[0], 7, 'f', 5).arg(str[1], 7, 'f', 5).arg(str[2], 7, 'f', 5)); + } + break; + } + s.append("\n"); + } + } + return s; } -- GitLab From cf413db26dcd4a0d4bcf651c8873abeebfe80b88 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 27 Nov 2017 12:39:26 -0600 Subject: [PATCH 514/755] Fixed Information Window Properties button so that the Properties Dialog will move the the front if the Properties Dialog is already open. --- src/GuiQt/InformationDisplayDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/InformationDisplayDialog.cxx b/src/GuiQt/InformationDisplayDialog.cxx index 2cd3b5d44..a8552a5ce 100644 --- a/src/GuiQt/InformationDisplayDialog.cxx +++ b/src/GuiQt/InformationDisplayDialog.cxx @@ -318,6 +318,6 @@ InformationDisplayDialog::showPropertiesDialog() if (m_propertiesDialog == NULL) { m_propertiesDialog = new InformationDisplayPropertiesDialog(this); } - m_propertiesDialog->show(); + m_propertiesDialog->showDialog(); } -- GitLab From 41b617cf3ecc4a8f33dde9150f64ea2285750420 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 27 Nov 2017 14:23:42 -0600 Subject: [PATCH 515/755] Updates to Border, Foci, and Identification Symbol to draw with new graphics primitive. Also sized in millimeters. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 117 +++++++++++++------------ 1 file changed, 63 insertions(+), 54 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 851e4f1d5..c9f93647b 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2497,8 +2497,6 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) break; } - uint8_t idRGBA[4]; - for (std::vector::const_iterator iter = identifiedNodes.begin(); iter != identifiedNodes.end(); iter++) { @@ -2523,32 +2521,38 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) const float symbolDiameter = nodeID.getSymbolSize(); + uint8_t symbolRGBA[4]; + if (isSelect) { - this->colorIdentification->addItem(idRGBA, + this->colorIdentification->addItem(symbolRGBA, SelectionItemDataTypeEnum::SURFACE_NODE_IDENTIFICATION_SYMBOL, nodeIndex); } else { if (structure == nodeID.getStructure()) { - nodeID.getSymbolRGBA(idRGBA); + nodeID.getSymbolRGBA(symbolRGBA); colorsFromChartsEvent.applyChartColorToNode(nodeIndex, - idRGBA); + symbolRGBA); } else { - nodeID.getContralateralSymbolRGB(idRGBA); + nodeID.getContralateralSymbolRGB(symbolRGBA); } } - idRGBA[3] = 255; + symbolRGBA[3] = 255; - - glPushMatrix(); - glTranslatef(xyz[0], xyz[1], xyz[2]); - this->drawSphereWithDiameter(idRGBA, - symbolDiameter); - glPopMatrix(); + /* + * Need to draw each symbol independently since each symbol + * contains a unique size (diameter) + */ + std::unique_ptr idPrimitive(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); + idPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, symbolDiameter); + idPrimitive->addVertex(xyz, + symbolRGBA); + GraphicsEngineDataOpenGL::draw(idPrimitive.get()); } + if (isSelect) { int nodeIndex = -1; float depth = -1.0; @@ -2950,16 +2954,25 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) const bool doClipping = isFeatureClippingEnabled(); - bool drawAsSpheres = false; + bool lightingOnFlag = false; + std::unique_ptr fociPrimitive; switch (fociDisplayProperties->getDrawingType(displayGroup, this->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: - drawAsSpheres = true; + fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); + fociPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, focusDiameter); + lightingOnFlag = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: + fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); + fociPrimitive->setPointDiameter(GraphicsPrimitive::SizeType::PIXELS, focusDiameter); + lightingOnFlag = false; break; } - + if (isSelect) { + lightingOnFlag = false; + } + const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, this->windowTabIndex); float caretColorRGBA[4]; @@ -2987,7 +3000,7 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); - float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; + float rgbaFloat[4] = { 0, 0, 0, 255 }; const GroupAndNameHierarchyItem* nameItem = focus->getGroupNameSelectionItem(); if (nameItem != NULL) { @@ -2999,42 +3012,39 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) switch (fociColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: - if (focus->isClassRgbaValid() == false) { + if ( ! focus->isClassRgbaValid()) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); if (colorLabel != NULL) { - colorLabel->getColor(rgba); - focus->setClassRgba(rgba); + colorLabel->getColor(rgbaFloat); + focus->setClassRgba(rgbaFloat); } else { - focus->setClassRgba(rgba); + focus->setClassRgba(rgbaFloat); } } - focus->getClassRgba(rgba); + focus->getClassRgba(rgbaFloat); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: - rgba[0] = caretColorRGBA[0]; - rgba[1] = caretColorRGBA[1]; - rgba[2] = caretColorRGBA[2]; - rgba[3] = caretColorRGBA[3]; + rgbaFloat[0] = caretColorRGBA[0]; + rgbaFloat[1] = caretColorRGBA[1]; + rgbaFloat[2] = caretColorRGBA[2]; + rgbaFloat[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (focus->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); if (colorLabel != NULL) { - colorLabel->getColor(rgba); - focus->setNameRgba(rgba); + colorLabel->getColor(rgbaFloat); + focus->setNameRgba(rgbaFloat); } else { - focus->setNameRgba(rgba); + focus->setNameRgba(rgbaFloat); } } - focus->getNameRgba(rgba); + focus->getNameRgba(rgbaFloat); break; } - glColor3fv(rgba); - - const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); @@ -3064,9 +3074,6 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) } if (drawIt) { - glPushMatrix(); - glTranslatef(xyz[0], xyz[1], xyz[2]); - if (isSelect) { uint8_t idRGBA[4]; this->colorIdentification->addItem(idRGBA, @@ -3075,33 +3082,33 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) j, /* focus index */ k);/* projection index */ idRGBA[3] = 255; - if (drawAsSpheres) { - this->drawSphereWithDiameter(idRGBA, - focusDiameter); - } - else { - this->drawSquare(idRGBA, - focusDiameter); - } + fociPrimitive->addVertex(xyz, idRGBA); } else { - if (drawAsSpheres) { - this->drawSphereWithDiameter(rgba, - focusDiameter); - } - else { - this->drawSquare(rgba, - focusDiameter); - } + const uint8_t rgbaByte[4] = { + rgbaFloat[0] * 255, + rgbaFloat[1] * 255, + rgbaFloat[2] * 255, + rgbaFloat[3] * 255, + }; + fociPrimitive->addVertex(xyz, rgbaByte); } - - glPopMatrix(); } } } } } + glPushAttrib(GL_ENABLE_BIT); + if (lightingOnFlag) { + enableLighting(); + } + else { + disableLighting(); + } + + GraphicsEngineDataOpenGL::draw(fociPrimitive.get()); + if (isSelect) { int32_t fociFileIndex = -1; int32_t focusIndex = -1; @@ -3134,6 +3141,8 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) } } } + + glPopAttrib(); } -- GitLab From 8479d0a9c5f1e72b6316afba4168ea5602b1c99a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 28 Nov 2017 14:57:04 -0600 Subject: [PATCH 516/755] Correct foci squares so that they are drawn with size of millimeters. Add a square shape to GraphicsShape that is drawn with billboarding so that the square always faces the user. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 10 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 86 +++++++++++++-- src/Graphics/GraphicsEngineDataOpenGL.h | 2 + src/Graphics/GraphicsPrimitive.cxx | 65 ++++++++++-- src/Graphics/GraphicsPrimitive.h | 49 +++++++-- src/Graphics/GraphicsShape.cxx | 124 ++++++++++++++++++++-- src/Graphics/GraphicsShape.h | 14 ++- 7 files changed, 310 insertions(+), 40 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c9f93647b..360e033bd 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2546,7 +2546,7 @@ BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) * contains a unique size (diameter) */ std::unique_ptr idPrimitive(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); - idPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, symbolDiameter); + idPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, symbolDiameter); idPrimitive->addVertex(xyz, symbolRGBA); GraphicsEngineDataOpenGL::draw(idPrimitive.get()); @@ -2845,9 +2845,9 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) glDisable(GL_LIGHTING); if (pointsPrimitive) { - pointsPrimitive->setPointDiameter(GraphicsPrimitive::SizeType::PIXELS, + pointsPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, pointDiameter); - pointsPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, + pointsPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, pointDiameter); if (pointsPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES) { if ( ! borderDrawInfo.isSelect) { @@ -2960,12 +2960,12 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) this->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); - fociPrimitive->setSphereDiameter(GraphicsPrimitive::SizeType::PIXELS, focusDiameter); + fociPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, focusDiameter); lightingOnFlag = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); - fociPrimitive->setPointDiameter(GraphicsPrimitive::SizeType::PIXELS, focusDiameter); + fociPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, focusDiameter); lightingOnFlag = false; break; } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index df5b9f983..5c9094747 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -28,6 +28,7 @@ #include "DeveloperFlagsEnum.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventGraphicsOpenGLCreateTextureName.h" +#include "EventOpenGLObjectToWindowTransform.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" #include "GraphicsOpenGLPolylineTriangles.h" @@ -35,6 +36,7 @@ #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" #include "GraphicsShape.h" +#include "Matrix4x4.h" using namespace caret; @@ -468,6 +470,7 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) std::unique_ptr windowSpacePrimitive; bool workbenchLineFlag = false; + bool millimeterPointsFlag = false; bool spheresFlag = false; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: @@ -477,6 +480,15 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: + switch (primitive->m_pointSizeType) { + case GraphicsPrimitive::PointSizeType::MILLIMETERS: + millimeterPointsFlag = true; + break; + case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: + break; + case GraphicsPrimitive::PointSizeType::PIXELS: + break; + } break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: break; @@ -498,7 +510,13 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) break; } - if (spheresFlag) { + if (millimeterPointsFlag) { + /* + * Special case for points in millimeters + */ + drawPointsPrimitiveMillimeters(primitive); + } + else if (spheresFlag) { drawSpheresPrimitive(primitive); } else if (workbenchLineFlag) { @@ -559,6 +577,59 @@ GraphicsEngineDataOpenGL::drawWindowSpace(const PrivateDrawMode drawMode, viewport); } +/** + * Draw a point primitive type in millimeters (same as model space). + * + * @param primitive + * The points primitive type. + */ +void +GraphicsEngineDataOpenGL::drawPointsPrimitiveMillimeters(const GraphicsPrimitive* primitive) +{ + CaretAssert(primitive); + CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::OPENGL_POINTS); + CaretAssert(primitive->m_pointSizeType == GraphicsPrimitive::PointSizeType::MILLIMETERS); + + GraphicsPrimitive::PointSizeType sizeType; + float sizeValue = 0.0f; + primitive->getPointDiameter(sizeType, + sizeValue); + + const int32_t numberOfVertices = primitive->getNumberOfVertices(); + switch (primitive->m_pointSizeType) { + case GraphicsPrimitive::PointSizeType::MILLIMETERS: + { + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); + const float* xyz = &primitive->m_xyz[i3]; + const int32_t i4 = i * 4; + + uint8_t* rgba = NULL; + switch (primitive->m_colorType) { + case GraphicsPrimitive::ColorType::FLOAT_RGBA: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); + rgba = const_cast(&primitive->m_unsignedByteRGBA[i4]); + break; + case GraphicsPrimitive::ColorType::NONE: + CaretAssert(0); + break; + } + + GraphicsShape::drawSquare(xyz, rgba, sizeValue); + } + } + break; + case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: + case GraphicsPrimitive::PointSizeType::PIXELS: + CaretAssert(0); + break; + } +} + /** * Draw a sphere primitive type. * @@ -571,7 +642,7 @@ GraphicsEngineDataOpenGL::drawSpheresPrimitive(const GraphicsPrimitive* primitiv CaretAssert(primitive); CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES); - GraphicsPrimitive::SizeType sizeType; + GraphicsPrimitive::SphereSizeType sizeType; float sizeValue = 0.0f; primitive->getSphereDiameter(sizeType, sizeValue); @@ -1073,8 +1144,11 @@ GraphicsEngineDataOpenGL::getPointDiameterForDrawingInPixels(const GraphicsPrimi float pointSize = primitive->m_pointDiameterValue; - switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + switch (primitive->m_pointSizeType) { + case GraphicsPrimitive::PointSizeType::MILLIMETERS: + CaretAssert(0); /* millimeters not convertible to pixels */ + break; + case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); @@ -1082,12 +1156,10 @@ GraphicsEngineDataOpenGL::getPointDiameterForDrawingInPixels(const GraphicsPrimi pointSize = (viewport[3] * (pointSize / 100.0f)); } break; - case GraphicsPrimitive::SizeType::PIXELS: + case GraphicsPrimitive::PointSizeType::PIXELS: break; } return pointSize; } - - diff --git a/src/Graphics/GraphicsEngineDataOpenGL.h b/src/Graphics/GraphicsEngineDataOpenGL.h index cd3a658e8..6289ae561 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.h +++ b/src/Graphics/GraphicsEngineDataOpenGL.h @@ -88,6 +88,8 @@ namespace caret { GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); + static void drawPointsPrimitiveMillimeters(const GraphicsPrimitive* primitive); + static void drawSpheresPrimitive(const GraphicsPrimitive* primitive); GLenum getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const; diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 95e10a50d..c50ca07ec 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -490,6 +490,51 @@ GraphicsPrimitive::getPrimitiveTypeAsText() const return s; } +/** + * @return Sphere size type as text for the given size type. + * + * @param sizeType + * The size type. + */ +AString +GraphicsPrimitive::getSphereSizeTypeAsText(const SphereSizeType sizeType) const +{ + AString s; + + switch (sizeType) { + case SphereSizeType::MILLIMETERS: + s = "Millimeters"; + break; + } + return s; +} + +/** + * @return Point size type as text for the given size type. + * + * @param sizeType + * The size type. + */ +AString +GraphicsPrimitive::getPointSizeTypeAsText(const PointSizeType sizeType) const +{ + AString s; + + switch (sizeType) { + case PointSizeType::MILLIMETERS: + s = "Millimeters"; + break; + case PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: + s = "Percentage Viewport Height"; + break; + case PointSizeType::PIXELS: + s = "Pixels"; + break; + } + return s; +} + + /** * @return Size type as text for the given size type. * @@ -593,14 +638,14 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const if (addPointSizeFlag) { s.appendWithNewLine("Point Diameter Type: " - + getSizeTypeAsText(m_pointSizeType) + + getPointSizeTypeAsText(m_pointSizeType) + "; Value: " + AString::number(m_pointDiameterValue, 'f', 3)); } if (addSphereSizeFlag) { s.appendWithNewLine("Sphere Diameter Type: " - + getSizeTypeAsText(m_sphereSizeType) + + getSphereSizeTypeAsText(m_sphereSizeType) + "; Value: " + AString::number(m_sphereDiameterValue, 'f', 3)); } @@ -1250,7 +1295,7 @@ GraphicsPrimitive::fillTriangleStripPrimitiveRestartVertices() * Diameter of point. */ void -GraphicsPrimitive::getPointDiameter(SizeType& sizeTypeOut, +GraphicsPrimitive::getPointDiameter(PointSizeType& sizeTypeOut, float& pointDiameterOut) const { sizeTypeOut = m_pointSizeType; @@ -1266,7 +1311,7 @@ GraphicsPrimitive::getPointDiameter(SizeType& sizeTypeOut, * Diameter of point. */ void -GraphicsPrimitive::setPointDiameter(const SizeType sizeType, +GraphicsPrimitive::setPointDiameter(const PointSizeType sizeType, const float pointDiameter) const { m_pointSizeType = sizeType; @@ -1306,15 +1351,15 @@ GraphicsPrimitive::setLineWidth(const SizeType widthType, } /** - * Get the point diameter. + * Get the sphere diameter. * * @param sizeTypeOut * Type of sizing. * @param pointDiameterOut - * Diameter of point. + * Diameter of sphere. */ void -GraphicsPrimitive::getSphereDiameter(SizeType& sizeTypeOut, +GraphicsPrimitive::getSphereDiameter(SphereSizeType& sizeTypeOut, float& sphereDiameterOut) const { sizeTypeOut = m_sphereSizeType; @@ -1322,15 +1367,15 @@ GraphicsPrimitive::getSphereDiameter(SizeType& sizeTypeOut, } /** - * Set the point diameter. + * Set the sphere diameter. * * @param sizeType * Type of sizing. * @param pointDiameter - * Diameter of point. + * Diameter of sphere. */ void -GraphicsPrimitive::setSphereDiameter(const SizeType sizeType, +GraphicsPrimitive::setSphereDiameter(const SphereSizeType sizeType, const float sphereDiameter) const { m_sphereSizeType = sizeType; diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index c3ede120c..825d5a8d3 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -163,7 +163,27 @@ namespace caret { }; /** - * Type for point size and line width + * Type for point size + */ + enum class PointSizeType { + /** + * Millimeters (all models surface, volume, etc. are drawn + * in millimeters). + */ + MILLIMETERS, + /** + * Size of point or width of line is a percentage of viewport height. + * Ranges [0.0, 100.0] + */ + PERCENTAGE_VIEWPORT_HEIGHT, + /** + * Size of point or width of line is in pixels + */ + PIXELS + }; + + /** + * Type for line width */ enum class SizeType { /** @@ -177,6 +197,17 @@ namespace caret { PIXELS }; + /** + * Type for sphere size + */ + enum class SphereSizeType { + /** + * Millimeters (all models surface, volume, etc. are drawn + * in millimeters). + */ + MILLIMETERS + }; + /** * Hint to graphics engine on how the primitive is used. * The hint must be set prior to loading of buffers. @@ -316,10 +347,10 @@ namespace caret { void addPrimitiveRestart(); - void getPointDiameter(SizeType& sizeTypeOut, + void getPointDiameter(PointSizeType& sizeTypeOut, float& pointDiameterOut) const; - void setPointDiameter(const SizeType sizeType, + void setPointDiameter(const PointSizeType sizeType, const float pointDiameter) const; void getLineWidth(SizeType& widthTypeOut, @@ -328,10 +359,10 @@ namespace caret { void setLineWidth(const SizeType widthType, const float lineWidth) const; - void getSphereDiameter(SizeType& sizeTypeOut, + void getSphereDiameter(SphereSizeType& sizeTypeOut, float& sphereDiameterOut) const; - void setSphereDiameter(const SizeType sizeType, + void setSphereDiameter(const SphereSizeType sizeType, const float sphereDiameter) const; GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); @@ -364,6 +395,10 @@ namespace caret { AString getSizeTypeAsText(const SizeType sizeType) const; + AString getPointSizeTypeAsText(const PointSizeType sizeType) const; + + AString getSphereSizeTypeAsText(const SphereSizeType sizeType) const; + const VertexType m_vertexType; const NormalVectorType m_normalVectorType; @@ -390,7 +425,7 @@ namespace caret { int32_t m_textureImageHeight = -1; - mutable SizeType m_pointSizeType = SizeType::PIXELS; + mutable PointSizeType m_pointSizeType = PointSizeType::PIXELS; mutable float m_pointDiameterValue = 1.0f; @@ -398,7 +433,7 @@ namespace caret { mutable float m_lineWidthValue = 1.0f; - mutable SizeType m_sphereSizeType = SizeType::PIXELS; + mutable SphereSizeType m_sphereSizeType = SphereSizeType::MILLIMETERS; mutable float m_sphereDiameterValue = 1.0f; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index bddea8474..b36a8d312 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -30,8 +30,10 @@ #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3f.h" +#include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsPrimitiveV3fN3f.h" #include "MathFunctions.h" +#include "Matrix4x4.h" using namespace caret; @@ -79,6 +81,13 @@ GraphicsShape::deleteAllPrimitives() delete iter.second; } s_byteRingPrimitives.clear(); + + /* + * Need to delete here or it will cause a crash + * as there is no EventManager when static data + * is deleted. + */ + s_byteSquarePrimitive.reset(); } @@ -422,13 +431,13 @@ GraphicsShape::drawLineStripMiterJoinByteColor(const std::vector& xyz, * XYZ-coordinate of sphere * @param rgba * Color for drawing. - * @param radius - * Radius of the sphere. + * @param diameter + * Diameter of the sphere. */ void GraphicsShape::drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], - const float radius) + const float diameter) { const int32_t numLatLonDivisions = 10; @@ -463,7 +472,7 @@ GraphicsShape::drawSphereByteColor(const float xyz[3], glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); - glScalef(radius, radius, radius); + glScalef(diameter, diameter, diameter); GraphicsEngineDataOpenGL::draw(spherePrimitive); glPopMatrix(); } @@ -475,13 +484,13 @@ GraphicsShape::drawSphereByteColor(const float xyz[3], * XYZ-coordinate of circle * @param rgba * Color for drawing. - * @param radius - * Radius of the circle. + * @param diameter + * Diameter of the circle. */ void GraphicsShape::drawCircleFilled(const float xyz[3], const uint8_t rgba[4], - const float radius) + const float diameter) { const int32_t numberOfDivisions = 20; @@ -494,8 +503,9 @@ GraphicsShape::drawCircleFilled(const float xyz[3], } if (circlePrimitive == NULL) { + const float radius = 0.5f; circlePrimitive = createCirclePrimitive(numberOfDivisions, - 0.5f); + radius); circlePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); circlePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); s_byteCirclePrimitives.insert(std::make_pair(numberOfDivisions, @@ -510,11 +520,74 @@ GraphicsShape::drawCircleFilled(const float xyz[3], if (xyz != NULL) { glTranslatef(xyz[0], xyz[1], xyz[2]); } - glScalef(radius, radius, 1.0f); + glScalef(diameter, diameter, 1.0f); GraphicsEngineDataOpenGL::draw(circlePrimitive); glPopMatrix(); } +/** + * Draw a square at the given XYZ coordinate + * + * @param xyz + * XYZ-coordinate of square + * @param rgba + * Color for drawing. + * @param diameter + * Diameter of the square. + */ + +void +GraphicsShape::drawSquare(const float xyz[3], + const uint8_t rgba[4], + const float diameter) +{ + if ( ! s_byteSquarePrimitive) { + s_byteSquarePrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, + rgba)); + /* + * The square is made up of four triangles + * with two triangles for the 'front' and + * two triangles for the 'back' so that it is + * never culled. + */ + + const float radius = 0.5f; + + /* counter clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + + /* counter clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + s_byteSquarePrimitive->addVertex(-radius, radius); + + /* clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex(-radius, radius); + s_byteSquarePrimitive->addVertex( radius, radius); + + /* clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + s_byteSquarePrimitive->addVertex( radius, -radius); + } + + CaretAssert(s_byteSquarePrimitive.get()); + + s_byteSquarePrimitive->replaceAllVertexSolidByteRGBA(rgba); + + glPushMatrix(); + if (xyz != NULL) { + glTranslatef(xyz[0], xyz[1], xyz[2]); + updateModelMatrixToFaceViewer(); + glScalef(diameter, diameter, 1.0f); + } + GraphicsEngineDataOpenGL::draw(s_byteSquarePrimitive.get()); + glPopMatrix(); +} + /** * Draw a ring at the given XYZ coordinate * @@ -931,6 +1004,39 @@ GraphicsShape::createSpherePrimitiveTriangleStrips(const int32_t numberOfLatLon) return primitive; } +/** + * Update the model matrix to face the viewer by applying a + * technique known as "billboarding". Callers need to + * push/pop the modelview matrix before/after calling + * this method. + * + * The result is that the X-Y plane faces the user. + */ +void +GraphicsShape::updateModelMatrixToFaceViewer() +{ + /* + * Get the translation and rotation from the + * current modelview matrix. + */ + double modelMatrixArray[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrixArray); + Matrix4x4 matrix; + matrix.setMatrixFromOpenGL(modelMatrixArray); + float txyz[3]; + matrix.getTranslation(txyz); + double sx, sy, sz; + matrix.getScale(sx, sy, sz); + + /* + * Replace modelview matrix with + * just translation and scaling. + */ + glLoadIdentity(); + glTranslatef(txyz[0], txyz[1], txyz[2]); + glScalef(sx, sy, sz); +} + /** * Get a description of this object's content. * @return String describing this object's content. diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index 2453218ae..eca4405d7 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -32,6 +32,7 @@ namespace caret { + class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fN3f; class GraphicsShape : public CaretObject { @@ -94,11 +95,15 @@ namespace caret { static void drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], - const float radius); + const float diameter); static void drawCircleFilled(const float xyz[3], const uint8_t rgba[4], - const float radius); + const float diameter); + + static void drawSquare(const float xyz[3], + const uint8_t rgba[4], + const float diameter); static void drawRing(const float xyz[3], const uint8_t rgba[4], @@ -156,6 +161,8 @@ namespace caret { GraphicsShape& operator=(const GraphicsShape&); + static void updateModelMatrixToFaceViewer(); + static GraphicsPrimitive* createCirclePrimitive(const int32_t numberOfDivisions, const double radius); @@ -178,6 +185,8 @@ namespace caret { float xyzOut[3], float normalXyzOut[3]); + static std::unique_ptr s_byteSquarePrimitive; + static std::map s_byteSpherePrimitives; static std::map s_byteCirclePrimitives; @@ -193,6 +202,7 @@ namespace caret { std::map GraphicsShape::s_byteSpherePrimitives; std::map GraphicsShape::s_byteCirclePrimitives; std::map GraphicsShape::s_byteRingPrimitives; + std::unique_ptr GraphicsShape::s_byteSquarePrimitive; #endif // __GRAPHICS_SHAPE_DECLARE__ } // namespace -- GitLab From 1957ac05dba1978308151b7099e1f56b79307797 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 28 Nov 2017 15:36:45 -0600 Subject: [PATCH 517/755] Some foci were colored incorrectly due to alpha values equal to zero in the color tables in the foci file. There is no editing by the user of the alpha value so always assume a valid alpha when drawing foci. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 360e033bd..ecac08aad 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -3000,7 +3000,12 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); - float rgbaFloat[4] = { 0, 0, 0, 255 }; + float rgbaFloat[4] = { + caretColorRGBA[0], + caretColorRGBA[1], + caretColorRGBA[2], + caretColorRGBA[3] + }; const GroupAndNameHierarchyItem* nameItem = focus->getGroupNameSelectionItem(); if (nameItem != NULL) { @@ -3018,9 +3023,9 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) colorLabel->getColor(rgbaFloat); focus->setClassRgba(rgbaFloat); } - else { - focus->setClassRgba(rgbaFloat); - } +// else { +// focus->setClassRgba(rgbaFloat); +// } } focus->getClassRgba(rgbaFloat); break; @@ -3037,14 +3042,19 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) colorLabel->getColor(rgbaFloat); focus->setNameRgba(rgbaFloat); } - else { - focus->setNameRgba(rgbaFloat); - } +// else { +// focus->setNameRgba(rgbaFloat); +// } } focus->getNameRgba(rgbaFloat); break; } + /* + * Always have valid color for RGBA + */ + rgbaFloat[3] = 1.0f; + const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); -- GitLab From 6bf56ebff97c54144efc6bfebcdf478a5db51e67 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Nov 2017 11:52:04 -0600 Subject: [PATCH 518/755] Draw volume slice axis crosshairs with a line thickness that is 1% of the viewport height. Orientation axes in bottom left corner of Oblique All View has also been changed to be 1% of viewport height. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 39 +++--- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 124 ++---------------- 2 files changed, 31 insertions(+), 132 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index e20320543..44a667b5f 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -48,6 +48,8 @@ #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyModel.h" +#include "GraphicsEngineDataOpenGL.h" +#include "GraphicsPrimitiveV3fC4f.h" #include "IdentificationWithColor.h" #include "LabelDrawingProperties.h" #include "MathFunctions.h" @@ -3384,23 +3386,21 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo */ if (drawCrosshairsFlag) { glPushMatrix(); - glLineWidth(1.0); glTranslatef(horizTrans[0], horizTrans[1], horizTrans[2]); - glColor3fv(horizontalAxisRGBA); - glBegin(GL_LINES); - glVertex3fv(horizontalAxisStartXYZ); - glVertex3fv(horizontalAxisEndXYZ); - glEnd(); + std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + horizHairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); + horizHairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); + horizHairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); glPushMatrix(); - glLineWidth(1.0); glTranslatef(vertTrans[0], vertTrans[1], vertTrans[2]); - glColor3fv(verticalAxisRGBA); - glBegin(GL_LINES); - glVertex3fv(verticalAxisStartXYZ); - glVertex3fv(verticalAxisEndXYZ); - glEnd(); + std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + vertHairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); + vertHairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); + vertHairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); } @@ -3795,13 +3795,20 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) const double paraTextMin[3] = { 0.0, textMinCoord, 0.0 }; const double paraTextMax[3] = { 0.0, textMaxCoord, 0.0 }; - const float axesCrosshairRadius = 1.0; + /* + * Set radius as percentage of viewport height + */ + float axesCrosshairRadius = 1.0; + if (viewportHeight > 0) { + const float percentageRadius = 0.005f; + axesCrosshairRadius = percentageRadius * viewportHeight; + } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(blue, axialPlaneMin, axialPlaneMax, - axesCrosshairRadius); + axesCrosshairRadius * 0.5f); } AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); @@ -3826,7 +3833,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) m_fixedPipelineDrawing->drawCylinder(green, coronalPlaneMin, coronalPlaneMax, - axesCrosshairRadius); + axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { @@ -3844,7 +3851,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) m_fixedPipelineDrawing->drawCylinder(red, paraPlaneMin, paraPlaneMax, - axesCrosshairRadius); + axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 9f7452a34..4e0d03cea 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -126,6 +126,7 @@ BrainOpenGLVolumeSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawi return; } + CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL); CaretAssert(fixedPipelineDrawing); CaretAssert(browserTabContent); m_browserTabContent = browserTabContent; @@ -4141,30 +4142,17 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli * Crosshairs */ if (drawCrosshairsFlag) { - glLineWidth(1.0); - glColor3fv(horizontalAxisRGBA); - glBegin(GL_LINES); - glVertex3fv(horizontalAxisStartXYZ); - glVertex3fv(horizontalAxisEndXYZ); - glEnd(); - - glLineWidth(1.0); - glColor3fv(verticalAxisRGBA); - glBegin(GL_LINES); - glVertex3fv(verticalAxisStartXYZ); - glVertex3fv(verticalAxisEndXYZ); - glEnd(); + std::unique_ptr xhairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + xhairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); + xhairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); + xhairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); + xhairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); + xhairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + GraphicsEngineDataOpenGL::draw(xhairPrimitive.get()); } if (drawCrosshairLabelsFlag) { const AnnotationTextFontPointSizeEnum::Enum fontSize = AnnotationTextFontPointSizeEnum::SIZE18; -// const int32_t fontSizeInt = AnnotationTextFontPointSizeEnum::toSizeNumeric(fontSize); -// -// const int textCenter[2] = { -// textLeftWindowXY[0], -// textLeftWindowXY[1] -// }; -// const int halfFontSize = fontSizeInt / 2; uint8_t backgroundRGBA[4] = { m_fixedPipelineDrawing->m_backgroundColorByte[0], @@ -4173,102 +4161,6 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli m_fixedPipelineDrawing->m_backgroundColorByte[3] }; -// GLint savedViewport[4]; -// glGetIntegerv(GL_VIEWPORT, savedViewport); -// -// int vpLeftX = savedViewport[0] + textCenter[0] - halfFontSize; -// int vpRightX = savedViewport[0] + textCenter[0] + halfFontSize; -// int vpBottomY = savedViewport[1] + textCenter[1] - halfFontSize; -// int vpTopY = savedViewport[1] + textCenter[1] + halfFontSize; -// MathFunctions::limitRange(vpLeftX, -// savedViewport[0], -// savedViewport[0] + savedViewport[2]); -// MathFunctions::limitRange(vpRightX, -// savedViewport[0], -// savedViewport[0] + savedViewport[2]); -// MathFunctions::limitRange(vpBottomY, -// savedViewport[1], -// savedViewport[1] + savedViewport[3]); -// MathFunctions::limitRange(vpTopY, -// savedViewport[1], -// savedViewport[1] + savedViewport[3]); -// -// const int vpSizeX = vpRightX - vpLeftX; -// const int vpSizeY = vpTopY - vpBottomY; -// glViewport(vpLeftX, vpBottomY, vpSizeX, vpSizeY); - -// glMatrixMode(GL_PROJECTION); -// glPushMatrix(); -// glLoadIdentity(); -// glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); -// -// glMatrixMode(GL_MODELVIEW); -// glPushMatrix(); -// glLoadIdentity(); - -// std::vector rgba; -// std::vector coords, normals; -// -// coords.push_back(-1.0); -// coords.push_back(-1.0); -// coords.push_back( 0.0); -// normals.push_back(0.0); -// normals.push_back(0.0); -// normals.push_back(1.0); -// rgba.push_back(backgroundRGBA[0]); -// rgba.push_back(backgroundRGBA[1]); -// rgba.push_back(backgroundRGBA[2]); -// rgba.push_back(backgroundRGBA[3]); -// -// coords.push_back( 1.0); -// coords.push_back(-1.0); -// coords.push_back( 0.0); -// normals.push_back(0.0); -// normals.push_back(0.0); -// normals.push_back(1.0); -// rgba.push_back(backgroundRGBA[0]); -// rgba.push_back(backgroundRGBA[1]); -// rgba.push_back(backgroundRGBA[2]); -// rgba.push_back(backgroundRGBA[3]); -// -// coords.push_back( 1.0); -// coords.push_back( 1.0); -// coords.push_back( 0.0); -// normals.push_back(0.0); -// normals.push_back(0.0); -// normals.push_back(1.0); -// rgba.push_back(backgroundRGBA[0]); -// rgba.push_back(backgroundRGBA[1]); -// rgba.push_back(backgroundRGBA[2]); -// rgba.push_back(backgroundRGBA[3]); -// -// coords.push_back(-1.0); -// coords.push_back( 1.0); -// coords.push_back( 0.0); -// normals.push_back(0.0); -// normals.push_back(0.0); -// normals.push_back(1.0); -// rgba.push_back(backgroundRGBA[0]); -// rgba.push_back(backgroundRGBA[1]); -// rgba.push_back(backgroundRGBA[2]); -// rgba.push_back(backgroundRGBA[3]); - - -// BrainOpenGLPrimitiveDrawing::drawQuads(coords, -// normals, -// rgba); - -// glPopMatrix(); -// -// glMatrixMode(GL_PROJECTION); -// glPopMatrix(); -// glMatrixMode(GL_MODELVIEW); - -// glViewport(savedViewport[0], -// savedViewport[1], -// savedViewport[2], -// savedViewport[3]); - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); -- GitLab From 0e58c1dcc4c0a4f52f824492cf06de8d69bd4c97 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Nov 2017 12:03:41 -0600 Subject: [PATCH 519/755] Renamed 'SizeType' in GraphicsPrimitive to 'LineWidthType' since it is only used for lines now that points and spheres have their own unique size type. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 40 +++++++++---------- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 18 ++++----- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 +- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 4 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 4 +- src/Brain/FtglFontTextRenderer.cxx | 4 +- src/Charting/ChartTwoDataCartesian.cxx | 4 +- src/Graphics/GraphicsEngineDataOpenGL.cxx | 4 +- .../GraphicsOpenGLPolylineTriangles.cxx | 4 +- src/Graphics/GraphicsPrimitive.cxx | 30 +++++++------- src/Graphics/GraphicsPrimitive.h | 10 ++--- src/Graphics/GraphicsShape.cxx | 12 +++--- src/Graphics/GraphicsShape.h | 12 +++--- 13 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 3b49d97c3..44dc3db52 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -288,7 +288,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(c const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); - crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); + crossShape->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); crossShape->addVertex(drawingSpaceXYZ[0], drawingSpaceXYZ[1] - 10); crossShape->addVertex(drawingSpaceXYZ[0], @@ -1194,7 +1194,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil topRight, topLeft, selectionColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, box->getLineWidthPercentage()); } @@ -1219,7 +1219,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil topRight, topLeft, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, box->getLineWidthPercentage()); drawnFlag = true; } @@ -1528,7 +1528,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const Annotatio */ glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); - linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, tickThickness); + linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, tickThickness); GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } @@ -1591,7 +1591,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float z = 0.0; std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); - linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 1.0f); + linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); std::unique_ptr trianglesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); const int32_t numSections = colorBar->getNumberOfSections(); @@ -1848,7 +1848,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, oval->getLineWidthPercentage()); } @@ -1869,7 +1869,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, oval->getLineWidthPercentage()); drawnFlag = true; } @@ -2202,12 +2202,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi GraphicsShape::drawLinesByteColor(connectLineCoordinates, textColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); if ( ! arrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(arrowCoordinates, textColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); } } @@ -2246,7 +2246,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi GraphicsShape::drawBoxOutlineByteColor(bl, br, tr, tl, foregroundRGBA, - GraphicsPrimitive::SizeType::PIXELS, + GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } else { @@ -2288,7 +2288,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi annXYZ[1]); crossShape->addVertex(annXYZ[0] + 10, annXYZ[1]); - crossShape->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, 2.0f); + crossShape->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(crossShape.get()); } } @@ -2414,7 +2414,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } GraphicsShape::drawBoxOutlineFloatColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, image->getLineWidthPercentage()); + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, image->getLineWidthPercentage()); } setDepthTestingStatus(depthTestFlag); @@ -2639,18 +2639,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi GraphicsShape::drawLinesByteColor(lineCoordinates, selectionColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, selectionColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, selectionColorRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } m_selectionInfo.push_back(SelectionInfo(annotationFile, @@ -2662,18 +2662,18 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi if (drawForegroundFlag) { GraphicsShape::drawLinesByteColor(lineCoordinates, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, foregroundRGBA, - GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } drawnFlag = true; @@ -3003,7 +3003,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann if (! m_selectionModeFlag) { GraphicsShape::drawBoxOutlineByteColor(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, - m_selectionBoxRGBA, GraphicsPrimitive::SizeType::PIXELS, 2.0f); + m_selectionBoxRGBA, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } const float handleLeft[3] = { @@ -3149,7 +3149,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann coords.insert(coords.end(), handleRotationLineEnd, handleRotationLineEnd + 3); coords.insert(coords.end(), handleOffset, handleOffset + 3); GraphicsShape::drawLinesByteColor(coords, m_selectionBoxRGBA, - GraphicsPrimitive::SizeType::PIXELS, 2.0f); + GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, annotation, diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 4596b7b6e..f04f470c0 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -872,7 +872,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch /* * Increase line width for identification */ - histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, (lineWidthPercentage + 0.5)); GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, @@ -896,7 +896,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { - histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentage); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); } @@ -1362,7 +1362,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT rowOutlineData->addVertex(maxX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, maxY, highlightRGBA); rowOutlineData->addVertex(minX, maxY, highlightRGBA); - rowOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + rowOutlineData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentageHeight); float modelViewMatrix[16]; @@ -1400,7 +1400,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT columnOutlineData->addVertex(maxX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, maxY, highlightRGBA); columnOutlineData->addVertex(minX, maxY, highlightRGBA); - columnOutlineData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + columnOutlineData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentageHeight); float modelViewMatrix[16]; @@ -1589,7 +1589,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons boxData->addVertex(boxRight, boxBottom); boxData->addVertex(boxRight, boxTop); boxData->addVertex(boxLeft, boxTop); - boxData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineThicknessPercentage); drawPrimitivePrivate(boxData.get()); } @@ -1612,7 +1612,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons boxData->addVertex(boxLeft - cornerOffset, boxTop); boxData->addVertex(boxLeft, boxTop); boxData->addVertex(boxLeft, boxBottom); - boxData->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineThicknessPercentage); drawPrimitivePrivate(boxData.get()); } @@ -2284,7 +2284,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo const float v4[3] = { vpX, vpY + vpHeight, 0.0f }; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, (uint8_t[]){ 255, 0, 0, 255}, - GraphicsPrimitive::SizeType::PIXELS, 1.0f); + GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); } /* @@ -2472,7 +2472,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh * Draw the ticks. * Note Line width is set in pixel and was converted from PERCENTAGE OF VIEWPORT HEIGHT */ - ticksData->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, m_lineDrawingWidth); + ticksData->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } @@ -2651,7 +2651,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float const float v4[3] = { m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3], 0.0f }; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, (uint8_t[]){ 255, 0, 0, 255}, - GraphicsPrimitive::SizeType::PIXELS, 2.0f); + GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } m_text->setTextColor(CaretColorEnum::CUSTOM); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index ecac08aad..ce3197b85 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2858,7 +2858,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } if (linesPrimitive) { glDisable(GL_LIGHTING); - linesPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, lineWidth); GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 44a667b5f..e25355aaf 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -3390,7 +3390,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); horizHairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); horizHairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); - horizHairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); @@ -3399,7 +3399,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); vertHairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); vertHairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); - vertHairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); } diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 4e0d03cea..4da00de98 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3641,7 +3641,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) glGetBooleanv(GL_DEPTH_TEST, &depthTestFlag); glDisable(GL_DEPTH_TEST); float widthPixels = thickness; - primitive->setLineWidth(GraphicsPrimitive::SizeType::PIXELS, + primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, widthPixels); GraphicsEngineDataOpenGL::draw(primitive.get()); if (depthTestFlag) { @@ -4147,7 +4147,7 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli xhairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); xhairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); xhairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); - xhairPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + xhairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); GraphicsEngineDataOpenGL::draw(xhairPrimitive.get()); } diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 6c5d47cee..8859a59ee 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -534,7 +534,7 @@ FtglFontTextRenderer::drawUnderline(const double lineStartX, GraphicsShape::drawLinesByteColor(underlineCoords, foregroundRgba, - GraphicsPrimitive::SizeType::PIXELS, + GraphicsPrimitive::LineWidthType::PIXELS, underlineThickness); glDisable(GL_LINE_SMOOTH); @@ -585,7 +585,7 @@ FtglFontTextRenderer::drawOutline(const double minX, GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRgba, - GraphicsPrimitive::SizeType::PIXELS, outlineThickness); + GraphicsPrimitive::LineWidthType::PIXELS, outlineThickness); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); diff --git a/src/Charting/ChartTwoDataCartesian.cxx b/src/Charting/ChartTwoDataCartesian.cxx index 8c56c0276..29c0d4217 100644 --- a/src/Charting/ChartTwoDataCartesian.cxx +++ b/src/Charting/ChartTwoDataCartesian.cxx @@ -264,7 +264,7 @@ ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesi GraphicsPrimitiveV3f* ChartTwoDataCartesian::getGraphicsPrimitive() const { - m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_lineWidth); return m_graphicsPrimitive.get(); } @@ -440,7 +440,7 @@ void ChartTwoDataCartesian::setLineWidth(const float lineWidth) { m_lineWidth = lineWidth; - m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT, + m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_lineWidth); } diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 5c9094747..44e2075ca 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -1112,7 +1112,7 @@ GraphicsEngineDataOpenGL::getLineWidthForDrawingInPixels(const GraphicsPrimitive float width = primitive->m_lineWidthValue; switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + case GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); @@ -1120,7 +1120,7 @@ GraphicsEngineDataOpenGL::getLineWidthForDrawingInPixels(const GraphicsPrimitive width = (viewport[3] * (width / 100.0f)); } break; - case GraphicsPrimitive::SizeType::PIXELS: + case GraphicsPrimitive::LineWidthType::PIXELS: break; } diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 0b8f94ec6..d44ce3e2d 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -127,14 +127,14 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const float lineWidth = primitive->m_lineWidthValue; switch (primitive->m_lineWidthType) { - case GraphicsPrimitive::SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + case GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); lineWidth = (lineWidth / 100.0) * viewport[3]; } break; - case GraphicsPrimitive::SizeType::PIXELS: + case GraphicsPrimitive::LineWidthType::PIXELS: break; } diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index c50ca07ec..250a126d2 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -536,21 +536,21 @@ GraphicsPrimitive::getPointSizeTypeAsText(const PointSizeType sizeType) const /** - * @return Size type as text for the given size type. + * @return Line width type as text for the given line width type. * - * @param sizeType - * The size type. + * @param lineWidthType + * The line width type. */ AString -GraphicsPrimitive::getSizeTypeAsText(const SizeType sizeType) const +GraphicsPrimitive::getLineWidthTypeAsText(const LineWidthType lineWidthType) const { AString s; - switch (sizeType) { - case SizeType::PERCENTAGE_VIEWPORT_HEIGHT: + switch (lineWidthType) { + case LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: s = "Percentage Viewport Height"; break; - case SizeType::PIXELS: + case LineWidthType::PIXELS: s = "Pixels"; break; } @@ -631,7 +631,7 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const if (addLineWidthFlag) { s.appendWithNewLine("Line Width Type: " - + getSizeTypeAsText(m_lineWidthType) + + getLineWidthTypeAsText(m_lineWidthType) + "; Value: " + AString::number(m_lineWidthValue, 'f', 3)); } @@ -1321,13 +1321,13 @@ GraphicsPrimitive::setPointDiameter(const PointSizeType sizeType, /** * Get the line width. * - * @param sizeTypeOut - * Type of sizing. + * @param lineWidthTypeOut + * Type of width. * @param lineWidthOut * Width of line. */ void -GraphicsPrimitive::getLineWidth(SizeType& widthTypeOut, +GraphicsPrimitive::getLineWidth(LineWidthType& widthTypeOut, float lineWidthOut) const { widthTypeOut = m_lineWidthType; @@ -1337,16 +1337,16 @@ GraphicsPrimitive::getLineWidth(SizeType& widthTypeOut, /** * Set the line width. * - * @param sizeType - * Type of sizing. + * @param lineWidthType + * Type of width. * @param lineWidth * Width of line. */ void -GraphicsPrimitive::setLineWidth(const SizeType widthType, +GraphicsPrimitive::setLineWidth(const LineWidthType lineWidthType, const float lineWidth) const { - m_lineWidthType = widthType; + m_lineWidthType = lineWidthType; m_lineWidthValue = lineWidth; } diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 825d5a8d3..37171596d 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -185,7 +185,7 @@ namespace caret { /** * Type for line width */ - enum class SizeType { + enum class LineWidthType { /** * Size of point or width of line is a percentage of viewport height. * Ranges [0.0, 100.0] @@ -353,10 +353,10 @@ namespace caret { void setPointDiameter(const PointSizeType sizeType, const float pointDiameter) const; - void getLineWidth(SizeType& widthTypeOut, + void getLineWidth(LineWidthType& widthTypeOut, float lineWidthOut) const; - void setLineWidth(const SizeType widthType, + void setLineWidth(const LineWidthType widthType, const float lineWidth) const; void getSphereDiameter(SphereSizeType& sizeTypeOut, @@ -393,7 +393,7 @@ namespace caret { AString getPrimitiveTypeAsText() const; - AString getSizeTypeAsText(const SizeType sizeType) const; + AString getLineWidthTypeAsText(const LineWidthType lineWidthType) const; AString getPointSizeTypeAsText(const PointSizeType sizeType) const; @@ -429,7 +429,7 @@ namespace caret { mutable float m_pointDiameterValue = 1.0f; - mutable SizeType m_lineWidthType = SizeType::PIXELS; + mutable LineWidthType m_lineWidthType = LineWidthType::PIXELS; mutable float m_lineWidthValue = 1.0f; diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index b36a8d312..4e5945343 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -115,7 +115,7 @@ GraphicsShape::drawBoxOutlineByteColor(const float v1[3], const float v3[3], const float v4[3], const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, @@ -157,7 +157,7 @@ GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], const float v3[3], const float v4[3], const float rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, @@ -266,7 +266,7 @@ void GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::vector ellipseXYZ; @@ -338,7 +338,7 @@ GraphicsShape::drawEllipseFilledByteColor(const double majorAxis, void GraphicsShape::drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, @@ -372,7 +372,7 @@ GraphicsShape::drawLinesByteColor(const std::vector& xyz, void GraphicsShape::drawLineStripBevelJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN, @@ -406,7 +406,7 @@ GraphicsShape::drawLineStripBevelJoinByteColor(const std::vector& xyz, void GraphicsShape::drawLineStripMiterJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN, diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index eca4405d7..fff1fd122 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -45,7 +45,7 @@ namespace caret { const float v3[3], const float v4[3], const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawBoxOutlineFloatColor(const float v1[3], @@ -53,7 +53,7 @@ namespace caret { const float v3[3], const float v4[3], const float rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawBoxFilledByteColor(const float v1[3], @@ -71,7 +71,7 @@ namespace caret { static void drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawEllipseFilledByteColor(const double majorAxis, @@ -80,17 +80,17 @@ namespace caret { static void drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawLineStripBevelJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawLineStripMiterJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], - const GraphicsPrimitive::SizeType lineThicknessType, + const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawSphereByteColor(const float xyz[3], -- GitLab From 767f589624e3de29d4800d0551d7161372f4f19e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 29 Nov 2017 12:22:21 -0600 Subject: [PATCH 520/755] For lines drawn as using polygons, use 1.0 as the minimum line width after conversion to pixels. --- src/Graphics/GraphicsOpenGLPolylineTriangles.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index d44ce3e2d..7eab54b8f 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -138,6 +138,12 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const break; } + /* enforce a minimum line width */ + const float minimumLineWidth = 1.0f; + if (lineWidth < minimumLineWidth) { + lineWidth = minimumLineWidth; + } + ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; switch (primitive->m_colorType) { case GraphicsPrimitive::ColorType::NONE: -- GitLab From fbe3f585ad28821de49d51fbdda090136bc1511c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Nov 2017 09:45:08 -0600 Subject: [PATCH 521/755] Resolve WB-682 Control and consistency of text size for volume slice coordinates: Text displayed in volume view (axis character, montage slice coordinates, and oblique all view orientation axes) now all use a percentage of viewport height. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 38 +++++++++++------- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 39 ++++++++++++------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index e25355aaf..4802f3f0f 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -26,7 +26,7 @@ #undef __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_DECLARE__ #include "AnnotationCoordinate.h" -#include "AnnotationPointSizeText.h" +#include "AnnotationPercentSizeText.h" #include "BoundingBox.h" #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" @@ -623,10 +623,10 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewTypeMontage(const Volum + AString::number(sliceCoord, 'f', montageCoordPrecision) + "mm"); - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE12); + annotationText.setFontPercentViewportSize(10.0f); annotationText.setLineColor(CaretColorEnum::NONE); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); @@ -3360,25 +3360,29 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo break; } + /* + * Offset text labels be a percentage of viewort width/height + */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - const int textOffset = 15; + const int textOffsetX = viewport[2] * 0.01f; + const int textOffsetY = viewport[3] * 0.01f; const int textLeftWindowXY[2] = { - textOffset, + textOffsetX, (viewport[3] / 2) }; const int textRightWindowXY[2] = { - viewport[2] - textOffset, + viewport[2] - textOffsetX, (viewport[3] / 2) }; const int textBottomWindowXY[2] = { viewport[2] / 2, - textOffset + textOffsetY }; const int textTopWindowXY[2] = { (viewport[2] / 2), - viewport[3] - textOffset + viewport[3] - textOffsetY }; /* @@ -3516,26 +3520,30 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo savedViewport[2], savedViewport[3]); - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setBoldStyleEnabled(true); - annotationText.setFontPointSize(fontSize); + annotationText.setFontPercentViewportSize(5.0f); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], textLeftWindowXY[1], annotationText); annotationText.setText(horizontalRightText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], textRightWindowXY[1], annotationText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setCustomTextColor(verticalAxisRGBA); annotationText.setText(verticalBottomText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], @@ -3543,6 +3551,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo annotationText); annotationText.setText(verticalTopText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annotationText.getCoordinate()->setXYZ(textTopWindowXY[0], textTopWindowXY[1], 0.0); m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], textTopWindowXY[1], @@ -3811,10 +3821,10 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) axesCrosshairRadius * 0.5f); } - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); - annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE14); + annotationText.setFontPercentViewportSize(5.0f); annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); annotationText.setTextColor(CaretColorEnum::CUSTOM); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 4da00de98..aab7b8be6 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -26,6 +26,7 @@ #undef __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_DECLARE__ #include "AnnotationCoordinate.h" +#include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "BoundingBox.h" #include "Brain.h" @@ -622,10 +623,10 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewTypeMontage(const VolumeSliceD + AString::number(sliceCoord, 'f', montageCoordPrecision) + "mm"); - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - annotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE12); + annotationText.setFontPercentViewportSize(10.0f); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(foregroundRGBA); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); @@ -3603,7 +3604,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) float solidRGBA[4]; CaretColorEnum::toRGBAFloat(outlineColor, solidRGBA); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES)); /* * Examine each triangle to see if it intersects the Plane @@ -4117,25 +4118,29 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli break; } + /* + * Offset text labels be a percentage of viewort width/height + */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - const int textOffset = 15; + const int textOffsetX = viewport[2] * 0.01f; + const int textOffsetY = viewport[3] * 0.01f; const int textLeftWindowXY[2] = { - textOffset, + textOffsetX, (viewport[3] / 2) }; const int textRightWindowXY[2] = { - viewport[2] - textOffset, + viewport[2] - textOffsetX, (viewport[3] / 2) }; const int textBottomWindowXY[2] = { viewport[2] / 2, - textOffset + textOffsetY }; const int textTopWindowXY[2] = { (viewport[2] / 2), - viewport[3] - textOffset + viewport[3] - textOffsetY }; /* @@ -4152,8 +4157,6 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli } if (drawCrosshairLabelsFlag) { - const AnnotationTextFontPointSizeEnum::Enum fontSize = AnnotationTextFontPointSizeEnum::SIZE18; - uint8_t backgroundRGBA[4] = { m_fixedPipelineDrawing->m_backgroundColorByte[0], m_fixedPipelineDrawing->m_backgroundColorByte[1], @@ -4161,31 +4164,39 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli m_fixedPipelineDrawing->m_backgroundColorByte[3] }; - AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); - annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); - annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setBoldStyleEnabled(true); - annotationText.setFontPointSize(fontSize); + annotationText.setFontPercentViewportSize(5.0f); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); + + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], textLeftWindowXY[1], annotationText); annotationText.setText(horizontalRightText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], textRightWindowXY[1], annotationText); annotationText.setCustomTextColor(verticalAxisRGBA); + + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setText(verticalBottomText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], textBottomWindowXY[1], annotationText); + annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annotationText.setText(verticalTopText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], textTopWindowXY[1], -- GitLab From c2ba9fabc5a5ee779bf24ae77f38a001d16de8dd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Nov 2017 09:48:39 -0600 Subject: [PATCH 522/755] Enabled OpenGL Multi-Sampling to anti-alias lines and polygons. Unfortunately, multi-sampling is not available when capturing an image with QGLWidget::renderPixmap but if the user captures a large image, aliasing affects are not that obvious. --- src/Brain/BrainOpenGL.cxx | 10 ++++++++ src/Brain/BrainOpenGLFixedPipeline.cxx | 33 ++++++++++++++++++++++++++ src/GuiQt/BrainOpenGLWidget.cxx | 7 +++--- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 40ee37c59..97a8f5a3b 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -1099,6 +1099,16 @@ BrainOpenGL::getOpenGLInformation() lineInfo += ("\nVertex Buffers Supported: " + AString::fromBool(s_supportsVertexBuffers)); + GLint sampleBuffersCount = 0; + glGetIntegerv(GL_SAMPLE_BUFFERS, &sampleBuffersCount); + GLint sampleCount = 0; + glGetIntegerv(GL_SAMPLES, &sampleCount); + + lineInfo += "\n"; + lineInfo += ("\nSample Buffer Count: " + AString::number(sampleBuffersCount)); + lineInfo += ("\nSamples Count: " + AString::number(sampleCount)); + lineInfo += ("\nMultisampling Enabled: " + AString::fromBool(glIsEnabled(GL_MULTISAMPLE))); + lineInfo += "\n"; lineInfo += "\n"; lineInfo += "Note that State of OpenGL may be different when drawing objects.\n"; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index ce3197b85..36b710d93 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -1539,6 +1539,25 @@ BrainOpenGLFixedPipeline::initializeOpenGL() */ glEnable(GL_NORMALIZE); + + /* + * OpenGL RedBook status that multisampling is available if + * GL_SAMPLE_BUFFES is 1 and GL_SAMPLES is greater than one. + */ + GLint sampleBuffersCount = 0; + glGetIntegerv(GL_SAMPLE_BUFFERS, &sampleBuffersCount); + GLint sampleCount = 0; + glGetIntegerv(GL_SAMPLES, &sampleCount); + const bool enableMultiSampleFlag = ((sampleBuffersCount >= 1) + && (sampleCount > 1)); + + if (enableMultiSampleFlag) { + glEnable(GL_MULTISAMPLE); + } + else { + glDisable(GL_MULTISAMPLE); + } + /* * Avoid drawing backfacing polygons */ @@ -1643,6 +1662,13 @@ BrainOpenGLFixedPipeline::disableLighting() void BrainOpenGLFixedPipeline::enableLineAntiAliasing() { + /* + * If multi-sampling is enabled, it handle anti-aliasing + */ + if (glIsEnabled(GL_MULTISAMPLE)) { + return; + } + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -1655,6 +1681,13 @@ BrainOpenGLFixedPipeline::enableLineAntiAliasing() void BrainOpenGLFixedPipeline::disableLineAntiAliasing() { + /* + * If multi-sampling is enabled, it handle anti-aliasing + */ + if (glIsEnabled(GL_MULTISAMPLE)) { + return; + } + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 4bf2a35c5..a6493031c 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1657,7 +1657,8 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) */ QPixmap pixmap = this->renderPixmap(outputImageWidth, - outputImageHeight); + outputImageHeight, + true); image = pixmap.toImage(); #endif } @@ -1705,7 +1706,7 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); glfmt.setRedBufferSize(8); glfmt.setRenderableType(QSurfaceFormat::OpenGL); - //glfmt.setSampleBuffers(false); + glfmt.setSampleBuffers(true); //glfmt.setStencil(false); glfmt.setStereo(false); glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); @@ -1726,7 +1727,7 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setOverlay(false); glfmt.setProfile(QGLFormat::CompatibilityProfile); glfmt.setVersion(2, 1); - glfmt.setSampleBuffers(false); + glfmt.setSampleBuffers(true); glfmt.setStencil(false); glfmt.setStereo(false); -- GitLab From 45a7597d8128b38d785eaf03285aaec953d25182 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Nov 2017 12:39:54 -0600 Subject: [PATCH 523/755] Resolve WB-739 Chart axis numerics rotatable and removable: Checkboxes have been added to Toolbar: Chart Axes to enable/disable display of numerics and to rotate the numeric values. --- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 211 +++++++++++------- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 2 + src/Charting/ChartTwoCartesianAxis.cxx | 52 ++++- src/Charting/ChartTwoCartesianAxis.h | 14 ++ .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 27 ++- .../BrainBrowserWindowToolBarChartTwoAxes.h | 4 + 6 files changed, 229 insertions(+), 81 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index f04f470c0..8152efcc6 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1575,47 +1575,22 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(cons const float boxBottom = bottomAxisHeight + halfGridLineWidth; const float boxTop = vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - /* - * We adjust the horizontal lines by half the line width. - * Otherwise, there will be 'corner gaps' where the horizontal - * and vertical lines are joined - */ - std::unique_ptr boxData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - boxData->reserveForNumberOfVertices(4); - boxData->addVertex(boxLeft, boxBottom); - boxData->addVertex(boxRight, boxBottom); - boxData->addVertex(boxRight, boxTop); - boxData->addVertex(boxLeft, boxTop); - boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - lineThicknessPercentage); - drawPrimitivePrivate(boxData.get()); - } - else { - /* - * We adjust the horizontal lines by half the line width. - * Otherwise, there will be 'corner gaps' where the horizontal - * and vertical lines are joined - */ - std::unique_ptr boxData - = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, - m_fixedPipelineDrawing->m_foregroundColorFloat)); - const float cornerOffset = halfGridLineWidth; - boxData->reserveForNumberOfVertices(8); - boxData->addVertex(boxLeft - cornerOffset, boxBottom); - boxData->addVertex(boxRight + cornerOffset, boxBottom); - boxData->addVertex(boxRight, boxBottom); - boxData->addVertex(boxRight, boxTop); - boxData->addVertex(boxRight + cornerOffset, boxTop); - boxData->addVertex(boxLeft - cornerOffset, boxTop); - boxData->addVertex(boxLeft, boxTop); - boxData->addVertex(boxLeft, boxBottom); - boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - lineThicknessPercentage); - drawPrimitivePrivate(boxData.get()); - } + /* + * We adjust the horizontal lines by half the line width. + * Otherwise, there will be 'corner gaps' where the horizontal + * and vertical lines are joined + */ + std::unique_ptr boxData + = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, + m_fixedPipelineDrawing->m_foregroundColorFloat)); + boxData->reserveForNumberOfVertices(4); + boxData->addVertex(boxLeft, boxBottom); + boxData->addVertex(boxRight, boxBottom); + boxData->addVertex(boxRight, boxTop); + boxData->addVertex(boxLeft, boxTop); + boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + lineThicknessPercentage); + drawPrimitivePrivate(boxData.get()); } /* @@ -1943,7 +1918,10 @@ m_tabViewportHeight(tabViewport[3]) */ float numericsWidth = 0.0f; float numericsHeight = 0.0f; - initializeNumericText(dataMinimumValue, dataMaximumValue, numericsWidth, numericsHeight); + initializeNumericText(dataMinimumValue, dataMaximumValue, + m_axis->isNumericsTextDisplayed(), + m_axis->isNumericsTextRotated(), + numericsWidth, numericsHeight); /* * For the bottom and the top, we now have its height but we do not yet know its width @@ -2039,6 +2017,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const * Minimum data value for axis * @param dataMaximumDataValue * Maximum data value for axis + * @param showNumericFlag, + * Show numerics + * @param rotateNumericFlag + * Rotate numerics. * @param maxWidthOut * Output with maximum width of numeric text. * @param maxHeightOut @@ -2047,6 +2029,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText(const float dataMinimumDataValue, const float dataMaximumDataValue, + const bool showNumericFlag, + const bool rotateNumericFlag, float& maxWidthOut, float& maxHeightOut) { @@ -2086,63 +2070,131 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); text->setFontPercentViewportSize(m_axis->getNumericsTextSize()); + if (rotateNumericFlag) { + text->setRotationAngle(-90.0f); + } float xyz[3] = { 0.0f, 0.0f, 0.0f }; + + AnnotationTextAlignVerticalEnum::Enum verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; + AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = scaleValuePositions[i]; - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); - if (i == firstIndex) { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - } - else if (i == lastIndex) { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + if (rotateNumericFlag) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + if (i == firstIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + } + else if (i == lastIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + } + else { + verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; + } } else { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + if (i == firstIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + } + else if (i == lastIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + } + else { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; + } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = scaleValuePositions[i]; - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - if (i == firstIndex) { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - } - else if (i == lastIndex) { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); + if (rotateNumericFlag) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + if (i == firstIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + } + else if (i == lastIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + } + else { + verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; + } } else { - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + if (i == firstIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + } + else if (i == lastIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + } + else { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; + } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: xyz[1] = scaleValuePositions[i]; - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); - if (i == firstIndex) { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - } - else if (i == lastIndex) { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + if (rotateNumericFlag) { + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + if (i == firstIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + } + else if (i == lastIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + } + else { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; + } } else { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + if (i == firstIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + } + else if (i == lastIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + } + else { + verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; + } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: xyz[1] = scaleValuePositions[i]; - text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); - if (i == firstIndex) { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); - } - else if (i == lastIndex) { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); + if (rotateNumericFlag) { + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + if (i == firstIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + } + else if (i == lastIndex) { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; + } + else { + horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; + } } else { - text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); + horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; + if (i == firstIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; + } + else if (i == lastIndex) { + verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; + } + else { + verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; + } } break; } - text->setText(scaleValuesText[i]); + text->setHorizontalAlignment(horizontalAlignment); + text->setVerticalAlignment(verticalAlignment); + + + if (showNumericFlag) { + text->setText(scaleValuesText[i]); + } text->getCoordinate()->setXYZ(xyz); @@ -2151,11 +2203,15 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText( m_textRenderer->getTextWidthHeightInPixels(*text, m_tabViewportWidth, m_tabViewportHeight, textWidth, textHeight); + if (rotateNumericFlag) { + std::swap(textWidth, + textHeight); + } maxWidthOut = std::max(maxWidthOut, static_cast(textWidth)); maxHeightOut = std::max(maxHeightOut, static_cast(textHeight)); - text->setText(scaleValuesText[i]); + //text->setText(scaleValuesText[i]); m_numericsText.push_back(std::unique_ptr(text)); } } @@ -2394,10 +2450,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh if (numScaleValuesToDraw > 0) { const bool showTicksEnabledFlag = m_axis->isShowTickmarks(); - GraphicsPrimitive::PrimitiveType primitiveType = GraphicsPrimitive::PrimitiveType::OPENGL_LINES; - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - primitiveType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES; - } + GraphicsPrimitive::PrimitiveType primitiveType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES; std::unique_ptr ticksData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(primitiveType, foregroundFloatRGBA)); @@ -2472,8 +2525,10 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLCh * Draw the ticks. * Note Line width is set in pixel and was converted from PERCENTAGE OF VIEWPORT HEIGHT */ - ticksData->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, m_lineDrawingWidth); - chartDrawing->drawPrimitivePrivate(ticksData.get()); + if (ticksData->getNumberOfVertices() > 1) { + ticksData->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, m_lineDrawingWidth); + chartDrawing->drawPrimitivePrivate(ticksData.get()); + } } /* diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index fa407652f..7ad9b7474 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -195,6 +195,8 @@ namespace caret { void initializeNumericText(const float dataMinimumDataValue, const float dataMaximumDataValue, + const bool showNumericFlag, + const bool rotateNumericFlag, float& maxWidthOut, float& maxHeightOut); diff --git a/src/Charting/ChartTwoCartesianAxis.cxx b/src/Charting/ChartTwoCartesianAxis.cxx index ccbd96590..9b1af91d7 100644 --- a/src/Charting/ChartTwoCartesianAxis.cxx +++ b/src/Charting/ChartTwoCartesianAxis.cxx @@ -102,6 +102,10 @@ m_axisLocation(axisLocation) &m_labelTextSize); m_sceneAssistant->add("m_numericsTextSize", &m_numericsTextSize); + m_sceneAssistant->add("m_numericsTextDisplayed", + &m_numericsTextDisplayed); + m_sceneAssistant->add("m_numericsTextRotated", + &m_numericsTextRotated); m_sceneAssistant->add("m_paddingSize", &m_paddingSize); } @@ -169,6 +173,8 @@ ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAx m_showLabel = obj.m_showLabel; m_labelTextSize = obj.m_labelTextSize; m_numericsTextSize = obj.m_numericsTextSize; + m_numericsTextDisplayed = obj.m_numericsTextDisplayed; + m_numericsTextRotated = obj.m_numericsTextRotated; m_paddingSize = obj.m_paddingSize; limitUserScaleMinMaxToValidRange(); } @@ -555,6 +561,48 @@ ChartTwoCartesianAxis::setNumericsTextSize(const float numericsTextSize) m_numericsTextSize = numericsTextSize; } +/** + * @return display numeric text in scale + */ +bool +ChartTwoCartesianAxis::isNumericsTextDisplayed() const +{ + return m_numericsTextDisplayed; +} + +/** + * Set display numeric text in scale + * + * @param numericsTextDisplayed + * New value for display numeric text in scale + */ +void +ChartTwoCartesianAxis::setNumericsTextDisplayed(const bool numericsTextDisplayed) +{ + m_numericsTextDisplayed = numericsTextDisplayed; +} + +/** + * @return rotate numeric text + */ +bool +ChartTwoCartesianAxis::isNumericsTextRotated() const +{ + return m_numericsTextRotated; +} + +/** + * Set rotate numeric text + * + * @param numericsTextRotated + * New value for rotate numeric text + */ +void +ChartTwoCartesianAxis::setNumericsTextRotated(const bool numericsTextRotated) +{ + m_numericsTextRotated = numericsTextRotated; +} + /** * @return size of padding */ @@ -624,7 +672,9 @@ ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, } // may not be in older scenes - m_displayedByUser = true; + m_displayedByUser = true; + m_numericsTextDisplayed = true; + m_numericsTextRotated = false; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Charting/ChartTwoCartesianAxis.h b/src/Charting/ChartTwoCartesianAxis.h index 2218d389a..265749db1 100644 --- a/src/Charting/ChartTwoCartesianAxis.h +++ b/src/Charting/ChartTwoCartesianAxis.h @@ -109,6 +109,14 @@ namespace caret { void setNumericsTextSize(const float numericsTextSize); + bool isNumericsTextDisplayed() const; + + void setNumericsTextDisplayed(const bool numericsTextDisplayed); + + bool isNumericsTextRotated() const; + + void setNumericsTextRotated(const bool numericsTextRotated); + float getPaddingSize() const; void setPaddingSize(const float paddingSize); @@ -195,6 +203,12 @@ namespace caret { /** size of numerics text*/ float m_numericsTextSize = 2.5f; + /** display numeric text in scale*/ + bool m_numericsTextDisplayed = true; + + /** rotate numeric text*/ + bool m_numericsTextRotated = false; + /** size of padding*/ float m_paddingSize = 0.0f; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index a007a83a3..f11ddbf3b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -98,6 +98,16 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showLabelCheckBox->setToolTip("Show label on axis"); + m_showNumericsCheckBox = new QCheckBox("Nums"); + QObject::connect(m_showNumericsCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_showNumericsCheckBox->setToolTip("Show numeric scale values on axis"); + + m_rotateNumericsCheckBox = new QCheckBox("Rotate"); + QObject::connect(m_rotateNumericsCheckBox, &QCheckBox::clicked, + this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); + m_rotateNumericsCheckBox->setToolTip("Rotate numeric scale values on axis"); + /* * Axes selection */ @@ -216,6 +226,8 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra m_widgetGroup->add(m_userMaximumValueSpinBox); m_widgetGroup->add(m_showTickMarksCheckBox); m_widgetGroup->add(m_showLabelCheckBox); + m_widgetGroup->add(m_showNumericsCheckBox); + m_widgetGroup->add(m_rotateNumericsCheckBox); m_widgetGroup->add(m_axisLabelFromOverlayComboBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); @@ -249,16 +261,23 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra /* * Show widgets layout */ + const bool displayLabelShowAtTopFlag = false; QWidget* showWidget = new QWidget(); QGridLayout* showLayout = new QGridLayout(showWidget); WuQtUtilities::setLayoutSpacingAndMargins(showLayout, 8, 0); int32_t axisRow = 0; - showLayout->addWidget(new QLabel("Show"), axisRow, 0, Qt::AlignHCenter); - axisRow++; + if (displayLabelShowAtTopFlag) { + showLayout->addWidget(new QLabel("Show"), axisRow, 0, Qt::AlignHCenter); + axisRow++; + } showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_showLabelCheckBox, axisRow, 0); axisRow++; + showLayout->addWidget(m_showNumericsCheckBox, axisRow, 0); + axisRow++; + showLayout->addWidget(m_rotateNumericsCheckBox, axisRow, 0); + axisRow++; showLayout->addWidget(m_showTickMarksCheckBox, axisRow, 0); axisRow++; showWidget->setSizePolicy(showWidget->sizePolicy().horizontalPolicy(), @@ -522,6 +541,8 @@ BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browser m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); + m_showNumericsCheckBox->setChecked(m_chartAxis->isNumericsTextDisplayed()); + m_rotateNumericsCheckBox->setChecked(m_chartAxis->isNumericsTextRotated()); const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); @@ -606,6 +627,8 @@ BrainBrowserWindowToolBarChartTwoAxes::valueChanged() m_chartAxis->setUserScaleMaximumValue(m_userMaximumValueSpinBox->value()); m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); m_chartAxis->setShowLabel(m_showLabelCheckBox->isChecked()); + m_chartAxis->setNumericsTextDisplayed(m_showNumericsCheckBox->isChecked()); + m_chartAxis->setNumericsTextRotated(m_rotateNumericsCheckBox->isChecked()); m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h index 85b353f9b..df8db9b20 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h @@ -111,6 +111,10 @@ namespace caret { QCheckBox* m_showLabelCheckBox; + QCheckBox* m_showNumericsCheckBox; + + QCheckBox* m_rotateNumericsCheckBox; + EnumComboBoxTemplate* m_userNumericFormatComboBox; QSpinBox* m_userDigitsRightOfDecimalSpinBox; -- GitLab From be83259673f107fd5a64f58a1fe6e42fa47a73ac Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 30 Nov 2017 12:40:27 -0600 Subject: [PATCH 524/755] Remove DeveloperFlagsEnum for new line drawing using polygons. --- .../BrainOpenGLAnnotationDrawingFixedPipeline.cxx | 11 ++--------- src/Common/DeveloperFlagsEnum.cxx | 6 ------ src/Common/DeveloperFlagsEnum.h | 3 +-- src/Graphics/GraphicsEngineDataOpenGL.cxx | 4 +--- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 44dc3db52..f9f1577f4 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -974,12 +974,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::startOpenGLForDrawing(GLint* savedSha glPushMatrix(); glLoadIdentity(); - /* - * Enable anti-aliasing for lines - */ - if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - m_brainOpenGLFixedPipeline->enableLineAntiAliasing(); - } + m_brainOpenGLFixedPipeline->enableLineAntiAliasing(); } /** @@ -997,9 +992,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::endOpenGLForDrawing(GLint savedShadeM /* * Disable anti-aliasing for lines */ - if ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - m_brainOpenGLFixedPipeline->disableLineAntiAliasing(); - } + m_brainOpenGLFixedPipeline->disableLineAntiAliasing(); if (savedLightingEnabled) { glEnable(GL_LIGHTING); diff --git a/src/Common/DeveloperFlagsEnum.cxx b/src/Common/DeveloperFlagsEnum.cxx index 941abeffb..47ebd536d 100644 --- a/src/Common/DeveloperFlagsEnum.cxx +++ b/src/Common/DeveloperFlagsEnum.cxx @@ -95,9 +95,6 @@ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, case DEVELOPER_FLAG_UNUSED: this->flagStatus = false; break; - case DEVELOPER_FLAG_NEW_LINE_DRAWING: - this->flagStatus = true; - break; } } @@ -122,9 +119,6 @@ DeveloperFlagsEnum::initialize() enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, "DEVELOPER_FLAG_UNUSED", "Developer Flag Unused")); - enumData.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_NEW_LINE_DRAWING, - "DEVELOPER_FLAG_NEW_LINE_DRAWING", - "Developer Flag New Line Drawing")); } /** diff --git a/src/Common/DeveloperFlagsEnum.h b/src/Common/DeveloperFlagsEnum.h index 1263b7662..29de8d76c 100644 --- a/src/Common/DeveloperFlagsEnum.h +++ b/src/Common/DeveloperFlagsEnum.h @@ -35,8 +35,7 @@ public: * Enumerated values. */ enum Enum { - DEVELOPER_FLAG_UNUSED, - DEVELOPER_FLAG_NEW_LINE_DRAWING + DEVELOPER_FLAG_UNUSED }; ~DeveloperFlagsEnum(); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 44e2075ca..6cc0f7079 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -501,9 +501,7 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: - if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_NEW_LINE_DRAWING)) { - workbenchLineFlag = true; - } + workbenchLineFlag = true; break; case GraphicsPrimitive::PrimitiveType::SPHERES: spheresFlag = true; -- GitLab From 399b3a618ad80bee56116b09cbaf848556cb7b04 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Dec 2017 15:09:19 -0600 Subject: [PATCH 525/755] When selection is performed, the selected item is the one that is most "in front" (or closer to the viewer). This is performed using the screen depth. There may be multiple items under the cursor and in this case, the selected item changed only when the depth of an item drawn was less than the last item found under the cursor while drawing. This depth test has been changed to "less than or equal to" since some items, such as annotations, are drawn at the same depth so that the item last drawn, that is drawn on top of all other items, is selected. --- src/Brain/SelectionItem.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Brain/SelectionItem.cxx b/src/Brain/SelectionItem.cxx index babbe4371..63c7cf375 100644 --- a/src/Brain/SelectionItem.cxx +++ b/src/Brain/SelectionItem.cxx @@ -285,7 +285,7 @@ SelectionItem::isOtherScreenDepthCloserToViewer(const double otherScreenDepth) c return true; } - if (otherScreenDepth < m_screenDepth) { + if (otherScreenDepth <= m_screenDepth) { return true; } -- GitLab From 802c9188137e551c337118113183fc0940a7203c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Dec 2017 15:14:41 -0600 Subject: [PATCH 526/755] Update to last commit for selection depth, only test selection depth less than or equal to for annotations. --- src/Brain/SelectionItem.cxx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Brain/SelectionItem.cxx b/src/Brain/SelectionItem.cxx index 63c7cf375..7c29cbfc7 100644 --- a/src/Brain/SelectionItem.cxx +++ b/src/Brain/SelectionItem.cxx @@ -285,8 +285,19 @@ SelectionItem::isOtherScreenDepthCloserToViewer(const double otherScreenDepth) c return true; } - if (otherScreenDepth <= m_screenDepth) { - return true; + /* + * Multiple annotations that are on top of each other may be drawn at the same + * depth so using "<=" should select the one that appears to be "on top" to the user. + */ + if (m_itemDataType == SelectionItemDataTypeEnum::ANNOTATION) { + if (otherScreenDepth <= m_screenDepth) { + return true; + } + } + else { + if (otherScreenDepth < m_screenDepth) { + return true; + } } return false; -- GitLab From 645c52c18d428390a7e5934fbab42f687543dce1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Dec 2017 16:02:17 -0600 Subject: [PATCH 527/755] Added OffScreenOpenGLRenderer. This off screen rendered is a new mode for capturing images. When OpenGL multisampling was added for antialiasing, the antialiasing did not work with QGLWidget::renderPixmap. Anti-aliasing does work with this new off screen renderer. This off screen renderer does work with the newer QOpenGLWidget but multisampling does not work with QOpenGLWidget so we remain using the deprecated QGLWidget. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 3 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 2 + src/Common/ImageCaptureMethodEnum.cxx | 3 + src/Common/ImageCaptureMethodEnum.h | 4 +- src/GuiQt/BrainOpenGLWidget.cxx | 140 ++++++++++++++---- src/GuiQt/BrainOpenGLWidget.h | 5 + src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/UserInputModeAnnotations.cxx | 5 + 8 files changed, 134 insertions(+), 31 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index f9f1577f4..80fe3c00a 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -3201,10 +3201,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() * True if the annotation is drawn with depth testing, else false. */ bool -BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* /*annotation*/) +BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* annotation) { return true; - /* bool depthTestFlag = false; diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 36b710d93..194c2c35e 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -1669,6 +1669,8 @@ BrainOpenGLFixedPipeline::enableLineAntiAliasing() return; } + return ; + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/src/Common/ImageCaptureMethodEnum.cxx b/src/Common/ImageCaptureMethodEnum.cxx index 0c563af67..fd6ee9889 100644 --- a/src/Common/ImageCaptureMethodEnum.cxx +++ b/src/Common/ImageCaptureMethodEnum.cxx @@ -114,6 +114,9 @@ ImageCaptureMethodEnum::initialize() "IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER", "Grab Frame Buffer")); + enumData.push_back(ImageCaptureMethodEnum(IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER, + "IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER", + "Offscreen Frame Buffer")); } /** diff --git a/src/Common/ImageCaptureMethodEnum.h b/src/Common/ImageCaptureMethodEnum.h index 72c427143..0fb1c4675 100644 --- a/src/Common/ImageCaptureMethodEnum.h +++ b/src/Common/ImageCaptureMethodEnum.h @@ -38,7 +38,9 @@ public: /** Capture the image with QGLWidget::renderPixmap() */ IMAGE_CAPTURE_WITH_RENDER_PIXMAP, /** Capture the image with QGLWidget::grabFrameBuffer() */ - IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER + IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER, + /** Capture with QOffscreenSurface and QOpenGLFramebufferObject */ + IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER }; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index a6493031c..4cb9367f2 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -65,6 +65,7 @@ #include "Matrix4x4.h" #include "Model.h" #include "MouseEvent.h" +#include "OffScreenOpenGLRenderer.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" #include "SelectionItemSurfaceNode.h" @@ -149,24 +150,24 @@ windowIndex(windowIndex) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IMAGE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + m_openGLContextSharingValid = true; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Default format is set by desktop.cxx call to initializeDefaultGLFormat(). */ setFormat(QSurfaceFormat::defaultFormat()); -#endif - +#else /* * Test to see if OpenGL context sharing is valid. - * If there is no sharingWidget, then this is the + * If there is no sharingWidget, then this is the * first window opened. */ - m_openGLContextSharingValid = true; if (shareWidget != NULL) { if ( ! isSharing()) { m_openGLContextSharingValid = false; } } +#endif // std::cout << "Share widget: " << std::hex << (uint64_t)shareWidget // << ", Context Pointer: " << std::hex << (uint64_t)context() @@ -174,10 +175,15 @@ windowIndex(windowIndex) // << ", Sharing enabled: " << (isSharing() ? "Yes" : "No") // << std::endl; +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + /* Context is not yet valid for QOpenGLWidget */ + m_contextShareGroupPointer = NULL; +#else CaretAssert(context()); CaretAssert(context()->contextHandle()); m_contextShareGroupPointer = context()->contextHandle()->shareGroup(); CaretAssert(m_contextShareGroupPointer); +#endif s_brainOpenGLWidgets.insert(this); } @@ -447,21 +453,57 @@ BrainOpenGLWidget::updateCursor() } /** - * Paints the graphics. + * Perform experimental off screen image capture. */ -void -BrainOpenGLWidget::paintGL() +QImage +BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, + const int32_t imageHeight) { - updateCursor(); + QImage image; - this->clearDrawingViewportContents(); + OffScreenOpenGLRenderer offscreen(this, + imageWidth, + imageHeight); + if (offscreen.isError()) { + WuQMessageBox::errorOk(this, + offscreen.getErrorMessage()); + doneCurrent(); + return image; + } + + int32_t viewport[4] = { 0, 0, imageWidth, imageHeight }; + std::vector viewportContent = getDrawingViewportContent(viewport); - int windowViewport[4] = { - 0, - 0, - this->windowWidth[this->windowIndex], - this->windowHeight[this->windowIndex] - }; + s_singletonOpenGL->drawModels(this->windowIndex, + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, + viewportContent); + + for (auto vp : viewportContent) { + delete vp; + } + viewportContent.clear(); + + if (offscreen.isError()) { + WuQMessageBox::errorOk(this, + offscreen.getErrorMessage()); + doneCurrent(); + return image; + } + + return offscreen.getImage(); +} + +/** + * @return Content of viewport for drawing. + * + * @param windowViewport + * Viewport for drawing + */ +std::vector +BrainOpenGLWidget::getDrawingViewportContent(int32_t windowViewport[4]) const +{ + std::vector viewportContent; BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); @@ -469,7 +511,7 @@ BrainOpenGLWidget::paintGL() EventManager::get()->sendEvent(getModelEvent.getPointer()); if (getModelEvent.isError()) { - return; + return viewportContent; } if (bbw->isAspectRatioLocked()) { @@ -493,10 +535,10 @@ BrainOpenGLWidget::paintGL() const int32_t numToDraw = getModelEvent.getNumberOfItemsToDraw(); if (numToDraw == 1) { BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(getModelEvent.getTabContentToDraw(0), - gapsAndMargins, - this->windowIndex, - windowViewport); - this->drawingViewportContents.push_back(vc); + gapsAndMargins, + this->windowIndex, + windowViewport); + viewportContent.push_back(vc); } else if (numToDraw > 1) { const int32_t windowWidth = windowViewport[2]; @@ -520,7 +562,7 @@ BrainOpenGLWidget::paintGL() rowHeights, columnsWidths)) { CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); - return; + return viewportContent; } /* @@ -531,13 +573,41 @@ BrainOpenGLWidget::paintGL() allTabs.push_back(getModelEvent.getTabContentToDraw(i)); } - this->drawingViewportContents = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, - tileTabsConfiguration, - gapsAndMargins, - windowIndex, - windowViewport, - getModelEvent.getTabIndexForTileTabsHighlighting()); + viewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, + tileTabsConfiguration, + gapsAndMargins, + windowIndex, + windowViewport, + getModelEvent.getTabIndexForTileTabsHighlighting()); } + return viewportContent; +} + +/** + * Paints the graphics. + */ +void +BrainOpenGLWidget::paintGL() +{ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + if (m_contextShareGroupPointer == NULL) { + m_contextShareGroupPointer = context()->shareGroup(); + CaretAssert(m_contextShareGroupPointer); + } +#endif + + updateCursor(); + + this->clearDrawingViewportContents(); + + int windowViewport[4] = { + 0, + 0, + this->windowWidth[this->windowIndex], + this->windowHeight[this->windowIndex] + }; + + this->drawingViewportContents = getDrawingViewportContent(windowViewport); if (this->selectedUserInputProcessor == userInputBordersModeProcessor) { s_singletonOpenGL->setBorderBeingDrawn(this->borderBeingDrawn); @@ -553,6 +623,7 @@ BrainOpenGLWidget::paintGL() /* * Issue browser window redrawn event */ + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); if (bbw != NULL) { EventManager::get()->sendEvent(EventBrowserWindowGraphicsRedrawn(bbw).getPointer()); } @@ -1097,6 +1168,8 @@ BrainOpenGLWidget::performIdentification(const int x, */ this->repaint(); this->doneCurrent(); +#else + this->repaint(); #endif return idManager; @@ -1159,6 +1232,10 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, */ this->repaint(); this->doneCurrent(); +#else + //updateCursor(); + //this->repaint(); + //updateGL(); #endif return annotationID; @@ -1223,6 +1300,8 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi */ this->repaint(); this->doneCurrent(); +#else + this->repaint(); #endif return idManager; @@ -1663,6 +1742,10 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) #endif } break; + case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER: + image = performOffScreenImageCapture(outputImageWidth, + outputImageHeight); + break; } if ((image.size().width() <= 0) @@ -1706,7 +1789,8 @@ BrainOpenGLWidget::initializeDefaultGLFormat() glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); glfmt.setRedBufferSize(8); glfmt.setRenderableType(QSurfaceFormat::OpenGL); - glfmt.setSampleBuffers(true); + //glfmt.setSampleBuffers(true); + glfmt.setSamples(6); //2); //glfmt.setStencil(false); glfmt.setStereo(false); glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index bf16ed3f1..6cf53b6b4 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -111,6 +111,9 @@ namespace caret { bool isOpenGLContextSharingValid() const; + QImage performOffScreenImageCapture(const int32_t imageWidth, + const int32_t imageHeight); + protected: virtual void initializeGL(); @@ -142,6 +145,8 @@ namespace caret { private: + std::vector getDrawingViewportContent(int32_t windowViewport[4]) const; + void clearDrawingViewportContents(); BrainOpenGLViewportContent* getViewportContentAtXY(const int x, diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 1855e451a..312d129d6 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -146,6 +146,7 @@ ELSE() MetaDataEditorDialog.h MetaDataEditorWidget.h MovieDialog.h + OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h OverlayViewController.h @@ -368,6 +369,7 @@ MetaDataEditorDialog.h MetaDataEditorWidget.h MouseEvent.h MovieDialog.h +OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h OverlayViewController.h @@ -586,6 +588,7 @@ MetaDataEditorDialog.cxx MetaDataEditorWidget.cxx MouseEvent.cxx MovieDialog.cxx +OffScreenOpenGLRenderer.cxx OverlaySetViewController.cxx OverlayViewController.cxx OverlaySettingsEditorDialog.cxx diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 11bd49584..eeded0423 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -1007,6 +1007,11 @@ UserInputModeAnnotations::setAnnotationUnderMouse(const MouseEvent& mouseEvent, } openGLWidget->updateCursor(); +#if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS + openGLWidget->updateGL(); +#else + openGLWidget->update(); +#endif } /** -- GitLab From bfc45ce019e7fab923dd45be59313933f6040dd3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Dec 2017 16:08:54 -0600 Subject: [PATCH 528/755] Forgot to add QOffscreenOpenGLRender class from last commit. --- src/GuiQt/OffscreenOpenGLRenderer.cxx | 169 ++++++++++++++++++++++++++ src/GuiQt/OffscreenOpenGLRenderer.h | 85 +++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 src/GuiQt/OffscreenOpenGLRenderer.cxx create mode 100644 src/GuiQt/OffscreenOpenGLRenderer.h diff --git a/src/GuiQt/OffscreenOpenGLRenderer.cxx b/src/GuiQt/OffscreenOpenGLRenderer.cxx new file mode 100644 index 000000000..9a6c789f8 --- /dev/null +++ b/src/GuiQt/OffscreenOpenGLRenderer.cxx @@ -0,0 +1,169 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ +#include "OffScreenOpenGLRenderer.h" +#undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + +#include +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#else +#include +#include +#endif +#include +#include +#include + +#include "BrainOpenGLWidget.h" +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::OffScreenOpenGLRenderer + * \brief Performs offscreen rendering of a window. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param openGLWidgetInstance + * An instance of either QGLWidget or QOpenGLWidget + * @param width + * Width for image (may be different, perhaps larger, than width of 'openglWidget' + * @param height + * Height for image (may be different, perhaps larger, than hight of 'openglWidget' + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, +#else +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, +#endif + const int32_t width, + const int32_t height) +: QObject() +{ + CaretAssert(openglWidget); + + m_openglContext = NULL;; + QSurfaceFormat surfaceFormat; + + /* + * Copy the surface format + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + surfaceFormat = openglWidget->format(); + m_openglContext = openglWidget->context(); +#else + surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); + CaretAssert(openglWidget->context()); + m_openglContext = openglWidget->context()->contextHandle(); +#endif +// QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); +// QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); +// if (glWidget != NULL) { +// } +// else if (openglWidget != NULL) { +// } +// else { +// m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; +// return; +// } + + CaretAssert(m_openglContext); + if ( ! m_openglContext->isValid()) { + m_errorMessage = "The OpenGL Context is not valid"; + return; + } + + // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); + + m_offScreenSurface.reset(new QOffscreenSurface()); + m_offScreenSurface->setFormat(surfaceFormat); + m_offScreenSurface->create(); + if ( ! m_offScreenSurface->isValid()) { + m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; + return; + } + + if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { + m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; + return; + } + + QOpenGLFramebufferObjectFormat frameBufferFormat; + frameBufferFormat.setSamples(2); + frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); + frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); + + m_frameBuffer.reset(new QOpenGLFramebufferObject(width, + height, + frameBufferFormat)); + if ( ! m_frameBuffer->isValid()) { + m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; + m_openglContext->doneCurrent(); + return; + } + +} + +/** + * Destructor. + */ +OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() +{ + m_openglContext->doneCurrent(); +} + +bool +OffScreenOpenGLRenderer::isError() const +{ + return ( ! m_errorMessage.isEmpty()); +} + +QString +OffScreenOpenGLRenderer::getErrorMessage() const +{ + return m_errorMessage; +} + +QImage +OffScreenOpenGLRenderer::getImage() +{ + QImage image; + + if ( ! m_frameBuffer) { + m_errorMessage = "Frame buffer is invalid while trying to get image"; + return image; + } + + image = m_frameBuffer->toImage(); + + return image; +} + + + diff --git a/src/GuiQt/OffscreenOpenGLRenderer.h b/src/GuiQt/OffscreenOpenGLRenderer.h new file mode 100644 index 000000000..2a4441ac7 --- /dev/null +++ b/src/GuiQt/OffscreenOpenGLRenderer.h @@ -0,0 +1,85 @@ +#ifndef __OFF_SCREEN_OPEN_G_L_RENDERER_H__ +#define __OFF_SCREEN_OPEN_G_L_RENDERER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QGLWidget; +class QOpenGLFramebufferObject; +class QOffscreenSurface; +class QOpenGLContext; +class QOpenGLWidget; +class QSurfaceFormat; +class QWidget; + +namespace caret { + + class OffScreenOpenGLRenderer : public QObject { + + Q_OBJECT + + public: +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, +#else + OffScreenOpenGLRenderer(QGLWidget* openglWidget, +#endif + const int32_t width, + const int32_t height); + + virtual ~OffScreenOpenGLRenderer(); + + bool isError() const; + + QString getErrorMessage() const; + + QImage getImage(); + + // ADD_NEW_METHODS_HERE + + private: + OffScreenOpenGLRenderer(const OffScreenOpenGLRenderer&); + + OffScreenOpenGLRenderer& operator=(const OffScreenOpenGLRenderer&); + + std::unique_ptr m_offScreenSurface; + + std::unique_ptr m_frameBuffer; + + QOpenGLContext* m_openglContext; + + QString m_errorMessage; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + // +#endif // __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + +} // namespace +#endif //__OFF_SCREEN_OPEN_G_L_RENDERER_H__ -- GitLab From beb6a805429bf0bd8fd47f083a7e4f9fc96ab57c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 1 Dec 2017 16:29:29 -0600 Subject: [PATCH 529/755] Still trying to get OffScreenOpenGLRenderer files to commit; trying on command line --- src/GuiQt/OffscreenOpenGLRenderer.cxx | 169 -------------------------- src/GuiQt/OffscreenOpenGLRenderer.h | 85 ------------- 2 files changed, 254 deletions(-) delete mode 100644 src/GuiQt/OffscreenOpenGLRenderer.cxx delete mode 100644 src/GuiQt/OffscreenOpenGLRenderer.h diff --git a/src/GuiQt/OffscreenOpenGLRenderer.cxx b/src/GuiQt/OffscreenOpenGLRenderer.cxx deleted file mode 100644 index 9a6c789f8..000000000 --- a/src/GuiQt/OffscreenOpenGLRenderer.cxx +++ /dev/null @@ -1,169 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ -#include "OffScreenOpenGLRenderer.h" -#undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ - -#include -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -#include -#else -#include -#include -#endif -#include -#include -#include - -#include "BrainOpenGLWidget.h" -#include "CaretAssert.h" - -using namespace caret; - - - -/** - * \class caret::OffScreenOpenGLRenderer - * \brief Performs offscreen rendering of a window. - * \ingroup GuiQt - */ - -/** - * Constructor. - * - * @param openGLWidgetInstance - * An instance of either QGLWidget or QOpenGLWidget - * @param width - * Width for image (may be different, perhaps larger, than width of 'openglWidget' - * @param height - * Height for image (may be different, perhaps larger, than hight of 'openglWidget' - */ -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, -#else -OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, -#endif - const int32_t width, - const int32_t height) -: QObject() -{ - CaretAssert(openglWidget); - - m_openglContext = NULL;; - QSurfaceFormat surfaceFormat; - - /* - * Copy the surface format - */ -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - surfaceFormat = openglWidget->format(); - m_openglContext = openglWidget->context(); -#else - surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); - CaretAssert(openglWidget->context()); - m_openglContext = openglWidget->context()->contextHandle(); -#endif -// QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); -// QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); -// if (glWidget != NULL) { -// } -// else if (openglWidget != NULL) { -// } -// else { -// m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; -// return; -// } - - CaretAssert(m_openglContext); - if ( ! m_openglContext->isValid()) { - m_errorMessage = "The OpenGL Context is not valid"; - return; - } - - // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); - - m_offScreenSurface.reset(new QOffscreenSurface()); - m_offScreenSurface->setFormat(surfaceFormat); - m_offScreenSurface->create(); - if ( ! m_offScreenSurface->isValid()) { - m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; - return; - } - - if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { - m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; - return; - } - - QOpenGLFramebufferObjectFormat frameBufferFormat; - frameBufferFormat.setSamples(2); - frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); - frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); - - m_frameBuffer.reset(new QOpenGLFramebufferObject(width, - height, - frameBufferFormat)); - if ( ! m_frameBuffer->isValid()) { - m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; - m_openglContext->doneCurrent(); - return; - } - -} - -/** - * Destructor. - */ -OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() -{ - m_openglContext->doneCurrent(); -} - -bool -OffScreenOpenGLRenderer::isError() const -{ - return ( ! m_errorMessage.isEmpty()); -} - -QString -OffScreenOpenGLRenderer::getErrorMessage() const -{ - return m_errorMessage; -} - -QImage -OffScreenOpenGLRenderer::getImage() -{ - QImage image; - - if ( ! m_frameBuffer) { - m_errorMessage = "Frame buffer is invalid while trying to get image"; - return image; - } - - image = m_frameBuffer->toImage(); - - return image; -} - - - diff --git a/src/GuiQt/OffscreenOpenGLRenderer.h b/src/GuiQt/OffscreenOpenGLRenderer.h deleted file mode 100644 index 2a4441ac7..000000000 --- a/src/GuiQt/OffscreenOpenGLRenderer.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __OFF_SCREEN_OPEN_G_L_RENDERER_H__ -#define __OFF_SCREEN_OPEN_G_L_RENDERER_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include - -class QGLWidget; -class QOpenGLFramebufferObject; -class QOffscreenSurface; -class QOpenGLContext; -class QOpenGLWidget; -class QSurfaceFormat; -class QWidget; - -namespace caret { - - class OffScreenOpenGLRenderer : public QObject { - - Q_OBJECT - - public: -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, -#else - OffScreenOpenGLRenderer(QGLWidget* openglWidget, -#endif - const int32_t width, - const int32_t height); - - virtual ~OffScreenOpenGLRenderer(); - - bool isError() const; - - QString getErrorMessage() const; - - QImage getImage(); - - // ADD_NEW_METHODS_HERE - - private: - OffScreenOpenGLRenderer(const OffScreenOpenGLRenderer&); - - OffScreenOpenGLRenderer& operator=(const OffScreenOpenGLRenderer&); - - std::unique_ptr m_offScreenSurface; - - std::unique_ptr m_frameBuffer; - - QOpenGLContext* m_openglContext; - - QString m_errorMessage; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ - // -#endif // __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ - -} // namespace -#endif //__OFF_SCREEN_OPEN_G_L_RENDERER_H__ -- GitLab From 8f97f016e8a4b8aee4d480422457858408b9b7aa Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 5 Dec 2017 16:29:00 -0600 Subject: [PATCH 530/755] Initial implementation of new algorithm for drawing volume surface outlines using polygons to avoid limits on OpenGL line width. Width of volume surface outline has been changed to a percentage of the viewport height. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 90 ++-- src/Files/CMakeLists.txt | 4 +- .../SurfacePlaneIntersectionToContour.cxx | 400 ++++++++++++++++++ src/Files/SurfacePlaneIntersectionToContour.h | 186 ++++++++ .../GraphicsOpenGLPolylineTriangles.cxx | 2 +- .../VolumeSurfaceOutlineViewController.cxx | 24 +- .../VolumeSurfaceOutlineViewController.h | 4 +- src/GuiQt/WuQDoubleSpinBox.cxx | 2 +- src/GuiQt/WuQDoubleSpinBox.h | 2 +- 9 files changed, 633 insertions(+), 81 deletions(-) create mode 100644 src/Files/SurfacePlaneIntersectionToContour.cxx create mode 100644 src/Files/SurfacePlaneIntersectionToContour.h diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index aab7b8be6..8c68a4ff2 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -67,6 +67,7 @@ #include "SelectionItemVoxelIdentificationSymbol.h" #include "SelectionManager.h" #include "SessionManager.h" +#include "SurfacePlaneIntersectionToContour.h" #include "Surface.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" @@ -3549,14 +3550,9 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum void BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) { - if ( ! plane.isValidPlane()) { - return; - } - - float intersectionPoint1[3]; - float intersectionPoint2[3]; - - m_fixedPipelineDrawing->enableLineAntiAliasing(); + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); @@ -3568,14 +3564,14 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) for (int32_t io = (numberOfOutlines - 1); io >= 0; io--) { + std::vector contourPrimitives; + VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { const float thickness = outline->getThickness(); - int numTriangles = surface->getNumberOfTriangles(); - CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; @@ -3584,6 +3580,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) switch (selectedColorOrTabItem->getItemType()) { case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); + outlineColor = CaretColorEnum::CUSTOM; break; case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: outlineColor = selectedColorOrTabItem->getColor(); @@ -3598,61 +3595,34 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) colorSourceBrowserTabIndex); } - glColor3fv(CaretColorEnum::toRGB(outlineColor)); - m_fixedPipelineDrawing->setLineWidth(thickness); - - float solidRGBA[4]; - CaretColorEnum::toRGBAFloat(outlineColor, solidRGBA); - - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES)); - - /* - * Examine each triangle to see if it intersects the Plane - * in which the slice exists. - */ - for (int it = 0; it < numTriangles; it++) { - const int32_t* triangleNodes = surface->getTriangle(it); - const float* c1 = surface->getCoordinate(triangleNodes[0]); - const float* c2 = surface->getCoordinate(triangleNodes[1]); - const float* c3 = surface->getCoordinate(triangleNodes[2]); - - if (plane.triangleIntersectPlane(c1, c2, c3, - intersectionPoint1, - intersectionPoint2)) { - if (surfaceColorFlag) { - const int32_t rgbaOffset = triangleNodes[0] * 4; - /* - * Use coloring assigned to the first node in the triangle - * but only if Alpha is valid (greater than zero). - */ - if (nodeColoringRGBA[rgbaOffset + 3] <= 0.0f) { - continue; - } - primitive->addVertex(intersectionPoint1, &nodeColoringRGBA[rgbaOffset]); - primitive->addVertex(intersectionPoint2, &nodeColoringRGBA[rgbaOffset]); - } - else { - primitive->addVertex(intersectionPoint1, solidRGBA); - primitive->addVertex(intersectionPoint2, solidRGBA); - } - } - } - - GLboolean depthTestFlag = GL_FALSE; - glGetBooleanv(GL_DEPTH_TEST, &depthTestFlag); - glDisable(GL_DEPTH_TEST); - float widthPixels = thickness; - primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, - widthPixels); - GraphicsEngineDataOpenGL::draw(primitive.get()); - if (depthTestFlag) { - glEnable(GL_DEPTH_TEST); + SurfacePlaneIntersectionToContour contour(surface, + plane, + outlineColor, + nodeColoringRGBA, + thickness); + AString errorMessage; + if ( ! contour.createContours(contourPrimitives, + errorMessage)) { + CaretLogSevere(errorMessage); } } } + /** + * Draw the contours. + */ + for (auto primitive : contourPrimitives) { + glPolygonOffset(1.0, 1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + + GraphicsEngineDataOpenGL::draw(primitive); + delete primitive; + + glDisable(GL_POLYGON_OFFSET_FILL); + } } - m_fixedPipelineDrawing->disableLineAntiAliasing(); + + glPopAttrib(); } /** diff --git a/src/Files/CMakeLists.txt b/src/Files/CMakeLists.txt index ebab25029..92aafeab7 100755 --- a/src/Files/CMakeLists.txt +++ b/src/Files/CMakeLists.txt @@ -44,13 +44,11 @@ ChartableLineSeriesRowColumnInterface.h ChartableMatrixInterface.h ChartableMatrixParcelInterface.h ChartableMatrixSeriesInterface.h - ChartableTwoFileDelegate.h ChartableTwoFileBaseChart.h ChartableTwoFileHistogramChart.h ChartableTwoFileLineSeriesChart.h ChartableTwoFileMatrixChart.h - CiftiBrainordinateDataSeriesFile.h CiftiBrainordinateLabelFile.h CiftiBrainordinateScalarFile.h @@ -126,6 +124,7 @@ StudyMetaDataLink.h StudyMetaDataLinkSet.h StudyMetaDataLinkSetSaxReader.h SurfaceFile.h +SurfacePlaneIntersectionToContour.h SurfaceProjectedItem.h SurfaceProjectedItemSaxReader.h SurfaceProjection.h @@ -251,6 +250,7 @@ StudyMetaDataLink.cxx StudyMetaDataLinkSet.cxx StudyMetaDataLinkSetSaxReader.cxx SurfaceFile.cxx +SurfacePlaneIntersectionToContour.cxx SurfaceProjectedItem.cxx SurfaceProjectedItemSaxReader.cxx SurfaceProjection.cxx diff --git a/src/Files/SurfacePlaneIntersectionToContour.cxx b/src/Files/SurfacePlaneIntersectionToContour.cxx new file mode 100644 index 000000000..76a6a632d --- /dev/null +++ b/src/Files/SurfacePlaneIntersectionToContour.cxx @@ -0,0 +1,400 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ +#include "SurfacePlaneIntersectionToContour.h" +#undef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ + +#include "CaretAssert.h" +#include "CaretException.h" +#include "CaretLogger.h" +#include "GraphicsPrimitiveV3fC4f.h" +#include "Plane.h" +#include "SurfaceFile.h" +#include "TopologyHelper.h" + +using namespace caret; + + + +/** + * \class caret::SurfacePlaneIntersectionToContour + * \brief Create a contour from intersecting the plane with a surface. + * \ingroup Files + * + * This algorithm is model upon these papers: + * + * Utilizing Topological Information to Increase Scan Vector Generation Efficiency + * Stephen J. Rock Michael J. Wozny + * Rensselaer Design Research Center Rensselaer Polytechnic Institute Troy, New York 12180 + * Appears in Solid Freeform Fabrication Symposium Proceedings, H. L. Marcus, et. al. (eds.), pp. 28-36, The University of Texas at Austin, Austin, TX, 1991. + * https://pdfs.semanticscholar.org/1129/b21303dcae34fed2a523f5991f8a1f9b3e32.pdf + * + * + * A Simple Arbitrary Solid Slicer + * Jin Yao + * B-Division, Lawrence Livermore National Laboratory Livermore, California 94551 + * https://e-reports-ext.llnl.gov/pdf/321754.pdf + * + */ + +/** + * Constructor. + * + * @param surfaceFile + * The surface file. + * @param plane + * Plane intersected with the surface. + * @param caretColor + * Solid coloring or, if value is CUSTOM, use the vertex coloring + * @param vertexColoringRGBA + * The per-vertex coloring if 'caretColor' is CUSTOM + * @param contourThicknessPercentOfViewportHeight + * Thickness for the contour as a percentage of viewport height. + */ +SurfacePlaneIntersectionToContour::SurfacePlaneIntersectionToContour(const SurfaceFile* surfaceFile, + const Plane& plane, + const CaretColorEnum::Enum caretColor, + const float* vertexColoringRGBA, + const float contourThicknessPercentOfViewportHeight) +: CaretObject(), +m_surfaceFile(surfaceFile), +m_plane(plane), +m_caretColor(caretColor), +m_vertexColoringRGBA(vertexColoringRGBA), +m_contourThicknessPercentOfViewportHeight(contourThicknessPercentOfViewportHeight) +{ + CaretAssert(m_surfaceFile); + + CaretColorEnum::toRGBAFloat(caretColor, + m_solidRGBA.data()); +} + +/** + * Destructor. + */ +SurfacePlaneIntersectionToContour::~SurfacePlaneIntersectionToContour() +{ +} + +/** + * Create the contour(s). + * + * @param graphicsPrimitivesOut + * On exit, contains primitives for drawing the contours. + * @param errorMessageOut + * Output containing the error message. + * @return + * True if successful, otherwise false. + */ +bool +SurfacePlaneIntersectionToContour::createContours(std::vector& graphicsPrimitivesOut, + AString& errorMessageOut) +{ + graphicsPrimitivesOut.clear(); + errorMessageOut.clear(); + + try { + if (m_surfaceFile->getNumberOfNodes() <= 2) { + throw CaretException("Surface has an invalid number of vertices."); + } + if ( ! m_plane.isValidPlane()) { + throw CaretException("Plane is invalid."); + } + + m_topologyHelper = m_surfaceFile->getTopologyHelper(true); + if (m_topologyHelper->getNumberOfNodes() <= 2) { + throw CaretException("Toplogy helper has an invalid number of vertices."); + } + + if (m_surfaceFile->getNumberOfNodes() != m_topologyHelper->getNumberOfNodes()) { + throw CaretException("Surface File and its Topology contain a different number of vertices."); + } + + prepareVertices(); + + prepareEdges(); + + generateContours(graphicsPrimitivesOut); + } + catch (const CaretException& caretException) { + errorMessageOut = caretException.whatString(); + return false; + } + + return true; +} + +/** + * Prepare the vertices by computing their signed distance from the plane. + * If vertex is on of very, very close to the plane, move the vertex + * away from the play by a very small amount so that the plane + * always intersects edges and never at a vertex. + */ +void +SurfacePlaneIntersectionToContour::prepareVertices() +{ + const float epsilon = 0.0000001f; + + CaretAssert(m_surfaceFile); + + float planeNormalVector[3]; + m_plane.getNormalVector(planeNormalVector); + const float abovePlaneOffset[3] = { planeNormalVector[0] * epsilon, planeNormalVector[1] * epsilon, planeNormalVector[2] * epsilon }; + + const float* surfaceXYZ = m_surfaceFile->getCoordinateData(); + + const int32_t numberOfVertices = m_surfaceFile->getNumberOfNodes(); + + m_vertices.reserve(numberOfVertices); + + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + std::array xyz = {{ surfaceXYZ[i3], surfaceXYZ[i3 + 1], surfaceXYZ[i3 + 2] }}; + + const float signedDistanceToPlane = m_plane.signedDistanceToPlane(xyz.data()); + if ((signedDistanceToPlane < epsilon) + && (signedDistanceToPlane > -epsilon)) { + /* + * Point is on or nearly on the plane so move it away from the plane + */ + float projectedXYZ[3]; + m_plane.projectPointToPlane(xyz.data(), projectedXYZ); + + if (signedDistanceToPlane >= 0) { + xyz[0] = projectedXYZ[0] + abovePlaneOffset[0]; + xyz[1] = projectedXYZ[1] + abovePlaneOffset[1]; + xyz[2] = projectedXYZ[1] + abovePlaneOffset[2]; + } + else { + xyz[0] = projectedXYZ[0] - abovePlaneOffset[0]; + xyz[1] = projectedXYZ[1] - abovePlaneOffset[1]; + xyz[2] = projectedXYZ[1] - abovePlaneOffset[2]; + } + } + + std::unique_ptr vp(new Vertex(xyz, signedDistanceToPlane)); + m_vertices.push_back(std::move(vp)); + } + + CaretAssert(static_cast(m_vertices.size()) == numberOfVertices); +} + +/** + * Find the edges that intersect the plane and save + * information about these intersecting edges. + */ +void +SurfacePlaneIntersectionToContour::prepareEdges() +{ + const std::vector& allEdgeInfo = m_topologyHelper->getEdgeInfo(); + + const int32_t numEdges = static_cast(allEdgeInfo.size()); + for (int32_t i = 0; i < numEdges; i++) { + CaretAssertVectorIndex(allEdgeInfo, i); + const TopologyEdgeInfo& edgeInfo = allEdgeInfo[i]; + const int32_t indexOne = edgeInfo.node1; + const int32_t indexTwo = edgeInfo.node2; + CaretAssertVectorIndex(m_vertices, indexOne); + CaretAssertVectorIndex(m_vertices, indexTwo); + + int32_t intersectingEdgeIndex = -1; + + /* + * We are only interested in edges that have one vertex below the plane + * and one vertex above the plane so the edge MUST intersect the plane. + */ + if (m_vertices[indexOne]->m_abovePlaneFlag != m_vertices[indexTwo]->m_abovePlaneFlag) { + const int32_t abovePlaneVertexIndex = (m_vertices[indexOne]->m_abovePlaneFlag + ? indexOne + : indexTwo); + const int32_t belowPlaneVertexIndex = (m_vertices[indexOne]->m_abovePlaneFlag + ? indexTwo + : indexOne); + + std::array intersectionXYZ; + const bool validFlag = m_plane.lineSegmentIntersectPlane(m_vertices[belowPlaneVertexIndex]->m_xyz.data(), + m_vertices[abovePlaneVertexIndex]->m_xyz.data(), + intersectionXYZ.data()); + if (validFlag) { + /* + * Get the edge's triangles + */ + if (edgeInfo.numTiles <= 0) { + const AString msg = ("Edge index=" + + AString::number(i) + + " contains zero triangles. This should never happend!"); + throw CaretException(msg); + } + + int32_t triangleOne(edgeInfo.tiles[0].tile); + int32_t triangleTwo(-1); + if (edgeInfo.numTiles > 1) { + triangleTwo = edgeInfo.tiles[1].tile; + } + + std::unique_ptr edge(new IntersectionEdge(intersectionXYZ, + belowPlaneVertexIndex, + abovePlaneVertexIndex, + triangleOne, + triangleTwo)); + m_intersectingEdges.push_back(std::move(edge)); + + intersectingEdgeIndex = m_intersectingEdges.size() - 1; + } + } + + m_topoHelperEdgeToIntersectingEdgeIndices.push_back(intersectingEdgeIndex); + } + + CaretAssert(static_cast(m_topoHelperEdgeToIntersectingEdgeIndices.size()) == numEdges); +} + +/** + * Examine edges and find contours by moving from edge to neighboring triangle to edge. + * In many instances, there will be more than one contour due to the way the + * cortex intersects the plane. + * + * @param graphicsPrimitivesOut + * On exit, contains primitives for drawing the contours. + */ +void +SurfacePlaneIntersectionToContour::generateContours(std::vector& graphicsPrimitivesOut) +{ + if (m_debugFlag) { + std::cout << "*********************************************" << std::endl; + } + + for (auto& edge : m_intersectingEdges) { + if ( ! edge->m_processedFlag) { + GraphicsPrimitive* primitive = generateContourFromEdge(edge.get()); + if (primitive != NULL) { + graphicsPrimitivesOut.push_back(primitive); + } + } + } +} + +GraphicsPrimitive* +SurfacePlaneIntersectionToContour::generateContourFromEdge(IntersectionEdge* startingEdge) +{ + static std::array debugRgba = {{ 1.0f, 1.0f, 0.0f, 1.0f }}; + static std::array startDebugRgba = {{ 0.0, 1.0, 0.0, 1.0 }}; + static std::array endDebugRgba = {{ 1.0, 0.0, 0.0, 1.0 }}; + + const std::vector& allTileInfo = m_topologyHelper->getTileInfo(); + + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); + primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + m_contourThicknessPercentOfViewportHeight); + IntersectionEdge* edge = startingEdge; + + if (m_debugFlag) { + std::cout << "Start: " << startingEdge->toString() << std::endl; + } + + while (edge != NULL) { + edge->m_processedFlag = true; + + IntersectionEdge* nextEdge = NULL; + + for (int32_t iTile = 0; iTile < 2; iTile++) { + CaretAssert(edge); + const int32_t tileIndex = (iTile == 0) ? edge->m_triangleOneIndex : edge->m_triangleTwoIndex; + if (tileIndex >= 0) { + CaretAssertVectorIndex(allTileInfo, tileIndex); + const TopologyTileInfo& tileInfo = allTileInfo[tileIndex]; + + for (int32_t iEdge = 0; iEdge < 3; iEdge++) { + const int32_t tileEdgeIndex = tileInfo.edges[iEdge].edge; + const int32_t intersectingEdgeIndex = m_topoHelperEdgeToIntersectingEdgeIndices[tileEdgeIndex]; + if (intersectingEdgeIndex >= 0) { + CaretAssertVectorIndex(m_intersectingEdges, intersectingEdgeIndex); + if ( ! m_intersectingEdges[intersectingEdgeIndex]->m_processedFlag) { + nextEdge = m_intersectingEdges[intersectingEdgeIndex].get(); + break; + } + } + } + + if (nextEdge != NULL) { + break; + } + } + } + + std::array colorRGBA = m_solidRGBA; + if (m_debugFlag) { + colorRGBA = debugRgba; + if (primitive->getNumberOfVertices() == 0) { + colorRGBA = startDebugRgba; + } + if (nextEdge == NULL) { + colorRGBA = endDebugRgba; + if (m_debugFlag) { + std::cout << " End: " << edge->toString() << std::endl; + } + } + } + else { + if (m_caretColor == CaretColorEnum::CUSTOM) { + CaretAssert(m_vertexColoringRGBA); + const int32_t belowI4 = edge->m_belowPlaneVertexIndex * 4; + const int32_t aboveI4 = edge->m_abovePlaneVertexIndex * 4; + + for (int32_t m = 0; m < 4; m++) { + colorRGBA[m] = ((m_vertexColoringRGBA[belowI4+m] + m_vertexColoringRGBA[aboveI4+m]) / 2.0f); + } + } + } + + primitive->addVertex(edge->m_intersectionXYZ.data(), colorRGBA.data()); + + if (startingEdge->hasMatchingTriangle(edge)) { + if (primitive->getNumberOfVertices() > 3) { + if (m_debugFlag) { + primitive->addVertex(startingEdge->m_intersectionXYZ.data(), + startDebugRgba.data()); + std::cout << " Closed contour" << std::endl; + } + else { + primitive->addVertex(startingEdge->m_intersectionXYZ.data(), + colorRGBA.data()); + } + } + } + + edge = nextEdge; + } + + if (m_debugFlag) { + std::cout << " Contour vertex count: " << primitive->getNumberOfVertices() << std::endl; + } + + if (primitive->isValid()) { + return primitive.release(); + } + + return NULL; +} + diff --git a/src/Files/SurfacePlaneIntersectionToContour.h b/src/Files/SurfacePlaneIntersectionToContour.h new file mode 100644 index 000000000..5d74d7c80 --- /dev/null +++ b/src/Files/SurfacePlaneIntersectionToContour.h @@ -0,0 +1,186 @@ +#ifndef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ +#define __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include + +#include "CaretColorEnum.h" +#include "CaretObject.h" +#include "CaretPointer.h" +#include "TopologyHelper.h" + +namespace caret { + + class GraphicsPrimitive; + class Plane; + class SurfaceFile; + + class SurfacePlaneIntersectionToContour : public CaretObject { + + public: + SurfacePlaneIntersectionToContour(const SurfaceFile* surfaceFile, + const Plane& plane, + const CaretColorEnum::Enum caretColor, + const float* vertexColoringRGBA, + const float contourThicknessMillimeters); + + virtual ~SurfacePlaneIntersectionToContour(); + + bool createContours(std::vector& graphicsPrimitivesOut, + AString& errorMessageOut); + + // ADD_NEW_METHODS_HERE + private: + /** + * Contains information about each surface vertex + * and its relationship to the plane + */ + class Vertex { + public: + Vertex(const std::array& xyz, + const float signedDistanceAbovePlane) + : m_xyz(xyz), + m_signedDistanceAbovePlane(signedDistanceAbovePlane), + m_abovePlaneFlag(signedDistanceAbovePlane > 0.0f) { } + + ~Vertex() { } + + const std::array m_xyz; + const float m_signedDistanceAbovePlane; + const bool m_abovePlaneFlag; + }; + + /* + * Contains information about an edge that intersects the plane + */ + class IntersectionEdge { + public: + IntersectionEdge(const std::array& intersectionXYZ, + int32_t belowPlaneVertexIndex, + int32_t abovePlaneVertexIndex, + int32_t triangleOneIndex, + int32_t triangleTwoIndex) + : m_intersectionXYZ(intersectionXYZ), + m_belowPlaneVertexIndex(belowPlaneVertexIndex), + m_abovePlaneVertexIndex(abovePlaneVertexIndex), + m_triangleOneIndex(triangleOneIndex), + m_triangleTwoIndex(triangleTwoIndex) { } + + /** + * True if this and the other edge are connected to the same triangle. + * @param otherEdge + * The other edge + * @return + * True if connected to same triangle, else false. + */ + bool hasMatchingTriangle(const IntersectionEdge* otherEdge) { + if ((m_triangleOneIndex == otherEdge->m_triangleOneIndex) + || (m_triangleOneIndex == otherEdge->m_triangleTwoIndex)) { + return true; + } + if (m_triangleTwoIndex >= 0) { + if ((m_triangleTwoIndex == otherEdge->m_triangleOneIndex) + || (m_triangleTwoIndex == otherEdge->m_triangleTwoIndex)) { + return true; + } + } + return false; + } + + AString toString() const { + AString msg("Intersection=(" + + AString::fromNumbers(m_intersectionXYZ.data(), 3, ",") + + ") below=" + + AString::number(m_belowPlaneVertexIndex) + + " aboveV=" + + AString::number(m_abovePlaneVertexIndex) + + " T1=" + + AString::number(m_triangleOneIndex) + + " T2=" + + AString::number(m_triangleTwoIndex)); + return msg; + } + /** coordinate of where edge intersects plane */ + std::array m_intersectionXYZ; + + /** vertex below the plane (index for surface vertex, topology helper vertex, and this class' m_vertices */ + int32_t m_belowPlaneVertexIndex; + + /** vertex above the plane */ + int32_t m_abovePlaneVertexIndex; + + /** first triangle used by edge (index for ToplogyHelper's TopologyTileInfo) */ + int32_t m_triangleOneIndex; + + /** second triangle used by edge (index for ToplogyHelper's TopologyTileInfo) */ + int32_t m_triangleTwoIndex; + + bool m_processedFlag = false; + }; + + SurfacePlaneIntersectionToContour(const SurfacePlaneIntersectionToContour&); + + SurfacePlaneIntersectionToContour& operator=(const SurfacePlaneIntersectionToContour&); + + void prepareVertices(); + + void prepareEdges(); + + void generateContours(std::vector& graphicsPrimitivesOut); + + GraphicsPrimitive* generateContourFromEdge(IntersectionEdge* edge); + + const SurfaceFile* m_surfaceFile; + + const Plane& m_plane; + + const CaretColorEnum::Enum m_caretColor; + + const float* m_vertexColoringRGBA; + + const float m_contourThicknessPercentOfViewportHeight; + + std::array m_solidRGBA; + + CaretPointer m_topologyHelper; + + std::vector> m_vertices; + + std::vector> m_intersectingEdges; + + /** index with a topo helper edge index to get its intersecting edge (-1) if edge does not intersect */ + std::vector m_topoHelperEdgeToIntersectingEdgeIndices; + + bool m_debugFlag = false; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ + // +#endif // __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ + +} // namespace +#endif //__SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 7eab54b8f..cbdc1bed9 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -466,7 +466,7 @@ GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, &m_vertexWindowXYZ[previousPointOffset]); if (distSQ < coincidentMaxDistSQ) { - CaretLogInfo("Filtered out connected segment conincident point index=" + AString::number(i) + CaretLogFine("Filtered out connected segment conincident point index=" + AString::number(i) + " after conversion to window coordinates. " + AString::fromNumbers(windowXYZ, 3, ",") + " " diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index fb87225f7..8dacf46b0 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include "SurfaceSelectionViewController.h" #include "VolumeSurfaceOutlineColorOrTabViewController.h" #include "VolumeSurfaceOutlineModel.h" +#include "WuQDoubleSpinBox.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" #include "WuQtUtilities.h" @@ -78,17 +78,13 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: this->colorOrTabSelectionControl->getWidget()->setToolTip("Select coloring for surface outline.\n" "If tab, coloring assigned to selected surface\n" "in the selected tab is used.\n"); - const float minLineWidth = 0.1; - const float maxLineWidth = 100.0; - const float stepSize = 0.5; - this->thicknessSpinBox = WuQFactory::newDoubleSpinBox(); - this->thicknessSpinBox->setRange(minLineWidth, - maxLineWidth); - this->thicknessSpinBox->setSingleStep(stepSize); - this->thicknessSpinBox->setFixedWidth(100); - QObject::connect(this->thicknessSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(thicknessSpinBoxValueChanged(double))); - this->thicknessSpinBox->setToolTip("Thickness of surface outline"); + this->thicknessSpinBox = new WuQDoubleSpinBox(this); + this->thicknessSpinBox->setRangePercentage(0.0, 100.0); + QObject::connect(this->thicknessSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), + this, &VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged); +// QObject::connect(this->thicknessSpinBox, SIGNAL(valueChanged(double)), +// this, SLOT(thicknessSpinBoxValueChanged(double))); + this->thicknessSpinBox->setToolTip("Thickness of surface outline as percentage of viewport height"); if (orientation == Qt::Horizontal) { @@ -97,7 +93,7 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: int row = this->gridLayoutGroup->rowCount(); this->gridLayoutGroup->addWidget(this->enabledCheckBox, row, 0); this->gridLayoutGroup->addWidget(this->colorOrTabSelectionControl->getWidget(), row, 1); - this->gridLayoutGroup->addWidget(this->thicknessSpinBox, row, 2); + this->gridLayoutGroup->addWidget(this->thicknessSpinBox->getWidget(), row, 2); this->gridLayoutGroup->addWidget(this->surfaceSelectionViewController->getWidget(), row, 3); } else { @@ -113,7 +109,7 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: this->gridLayoutGroup->addWidget(this->surfaceSelectionViewController->getWidget(), row, 1, 1, 2); row++; this->gridLayoutGroup->addWidget(this->colorOrTabSelectionControl->getWidget(), row, 1); - this->gridLayoutGroup->addWidget(this->thicknessSpinBox, row, 2, Qt::AlignLeft); + this->gridLayoutGroup->addWidget(this->thicknessSpinBox->getWidget(), row, 2, Qt::AlignLeft); row++; this->gridLayoutGroup->addWidget(bottomHorizontalLineWidget, row, 0, 1, -1); } diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.h b/src/GuiQt/VolumeSurfaceOutlineViewController.h index 30db74f0a..74cb33885 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.h +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.h @@ -25,7 +25,6 @@ #include "VolumeSurfaceOutlineColorOrTabModel.h" class QCheckBox; -class QDoubleSpinBox; class QGridLayout; namespace caret { @@ -34,6 +33,7 @@ namespace caret { class SurfaceSelectionViewController; class VolumeSurfaceOutlineModel; class VolumeSurfaceOutlineColorOrTabViewController; + class WuQDoubleSpinBox; class WuQGridLayoutGroup; class VolumeSurfaceOutlineViewController : public QObject { @@ -75,7 +75,7 @@ namespace caret { VolumeSurfaceOutlineColorOrTabViewController* colorOrTabSelectionControl; - QDoubleSpinBox* thicknessSpinBox; + WuQDoubleSpinBox* thicknessSpinBox; SurfaceSelectionViewController* surfaceSelectionViewController; }; diff --git a/src/GuiQt/WuQDoubleSpinBox.cxx b/src/GuiQt/WuQDoubleSpinBox.cxx index d3f98f2ea..8b8f39022 100644 --- a/src/GuiQt/WuQDoubleSpinBox.cxx +++ b/src/GuiQt/WuQDoubleSpinBox.cxx @@ -73,7 +73,7 @@ using namespace caret; * @param parent * The parent widget. */ -WuQDoubleSpinBox::WuQDoubleSpinBox(QWidget* parent) +WuQDoubleSpinBox::WuQDoubleSpinBox(QObject* parent) : WuQWidget(parent) { /* diff --git a/src/GuiQt/WuQDoubleSpinBox.h b/src/GuiQt/WuQDoubleSpinBox.h index d50b7e6fe..53d752875 100644 --- a/src/GuiQt/WuQDoubleSpinBox.h +++ b/src/GuiQt/WuQDoubleSpinBox.h @@ -80,7 +80,7 @@ namespace caret { EXCEEDABLE }; - WuQDoubleSpinBox(QWidget* parent); + WuQDoubleSpinBox(QObject* parent); virtual ~WuQDoubleSpinBox(); -- GitLab From 34edd9116172a1988272785f28054b5745d86234 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Dec 2017 13:05:50 -0600 Subject: [PATCH 531/755] Corrections to code to fix compilation errors on Linux. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 4 +- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 4 +- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 4 +- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 2 +- src/Graphics/GraphicsPrimitiveV3fN3f.cxx | 8 +- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 10 +- src/Graphics/GraphicsShape.cxx | 4 +- src/GuiQt/OffscreenOpenGLRenderer.cxx | 169 ++++++++++++++++++ 8 files changed, 187 insertions(+), 18 deletions(-) create mode 100644 src/GuiQt/OffscreenOpenGLRenderer.cxx diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 80fe3c00a..0177e8367 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1609,8 +1609,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation if (startScalar == endScalar) { const float* rgba = section->getStartRGBA(); - linesPrimitive->addVertex((float[]){ blX, blY, z}, rgba); - linesPrimitive->addVertex((float[]){ tlX, tlY, z}, rgba); + linesPrimitive->addVertex(blX, blY, z, rgba); + linesPrimitive->addVertex(tlX, tlY, z, rgba); } else { diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 8152efcc6..d7b687bba 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -2339,7 +2339,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo const float v3[3] = { vpX + vpWidth, vpY + vpHeight, 0.0f }; const float v4[3] = { vpX, vpY + vpHeight, 0.0f }; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, - (uint8_t[]){ 255, 0, 0, 255}, + std::move((uint8_t[]){ 255, 0, 0, 255}), GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); } @@ -2705,7 +2705,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float const float v3[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3], 0.0f }; const float v4[3] = { m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3], 0.0f }; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, - (uint8_t[]){ 255, 0, 0, 255}, + std::move((uint8_t[]){ 255, 0, 0, 255}), GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index 8dc0fc078..f49508068 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -116,7 +116,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float z, const float rgba[4]) { - addVertex((float[]){ x, y, z}, rgba); + addVertex(std::move((float[]){ x, y, z}), rgba); } /** @@ -134,7 +134,7 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float rgba[4]) { - addVertex((float[]){ x, y, 0.0f}, rgba); + addVertex(std::move((float[]){ x, y, 0.0f}), rgba); } /** diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 4c3905ba0..249c33982 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -116,7 +116,7 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, const float z, const uint8_t rgba[4]) { - addVertex((float[]){x, y, z}, + addVertex(std::move((float[]){x, y, z}), rgba); } diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx index 5907ec732..f38566a18 100644 --- a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx @@ -159,8 +159,8 @@ GraphicsPrimitiveV3fN3f::addVertex(const float x, const float normalY, const float normalZ) { - addVertexProtected((float[]){ x, y, z }, - (float[]){ normalX, normalY, normalZ }, + addVertexProtected(std::move((float[]){ x, y, z }), + std::move((float[]){ normalX, normalY, normalZ }), m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); @@ -184,8 +184,8 @@ GraphicsPrimitiveV3fN3f::addVertex(const float x, const float normalX, const float normalY) { - addVertexProtected((float[]){ x, y, 0.0f }, - (float[]){ normalX, normalY, 0.0f }, + addVertexProtected(std::move((float[]){ x, y, 0.0f }), + std::move((float[]){ normalX, normalY, 0.0f }), m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 721726b40..58acbced7 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -106,7 +106,7 @@ GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], NULL, NULL, NULL, - (float[]){ st[0], st[1], 0.0f }); + std::move((float[]){ st[0], st[1], 0.0f })); } /** @@ -130,8 +130,8 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertex((float[]){ x, y, z }, - (float[]){ s, t }); + addVertex(std::move((float[]){ x, y, z }), + std::move((float[]){ s, t })); } /** @@ -152,8 +152,8 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertex((float[]){ x, y, 0.0f }, - (float[]){ s, t }); + addVertex(std::move((float[]){ x, y, 0.0f }), + std::move((float[]){ s, t })); } /** diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 4e5945343..a8b3a1c07 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -658,7 +658,7 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, const float step = (2.0 * M_PI) / numberOfDivisions; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, - (uint8_t[]) { 255, 255, 255, 255 }); + std::move((uint8_t[]) { 255, 255, 255, 255 })); primitive->reserveForNumberOfVertices(numberOfDivisions + 2); /* * Generate points around ring @@ -699,7 +699,7 @@ GraphicsShape::createRingPrimitive(const RingKey& ringKey) const float step = (2.0 * M_PI) / ringKey.m_numberOfDivisions; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, - (uint8_t[]) { 255, 255, 255, 255 }); + std::move((uint8_t[]) { 255, 255, 255, 255 })); primitive->reserveForNumberOfVertices((ringKey.m_numberOfDivisions + 1) * 2); /* * Generate points around ring diff --git a/src/GuiQt/OffscreenOpenGLRenderer.cxx b/src/GuiQt/OffscreenOpenGLRenderer.cxx new file mode 100644 index 000000000..37cec1b14 --- /dev/null +++ b/src/GuiQt/OffscreenOpenGLRenderer.cxx @@ -0,0 +1,169 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ +#include "OffScreenOpenGLRenderer.h" +#undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + +#include +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#else +#include +#include +#endif +#include +#include +#include + +#include "BrainOpenGLWidget.h" +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::OffScreenOpenGLRenderer + * \brief Performs offscreen rendering of a window. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param openGLWidgetInstance + * An instance of either QGLWidget or QOpenGLWidget + * @param width + * Width for image (may be different, perhaps larger, than width of 'openglWidget' + * @param height + * Height for image (may be different, perhaps larger, than hight of 'openglWidget' + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, +#else +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, +#endif + const int32_t width, + const int32_t height) +: QObject() +{ + CaretAssert(openglWidget); + + m_openglContext = NULL;; + QSurfaceFormat surfaceFormat; + + /* + * Copy the surface format + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + surfaceFormat = openglWidget->format(); + m_openglContext = openglWidget->context(); +#else + surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); + CaretAssert(openglWidget->context()); + m_openglContext = openglWidget->context()->contextHandle(); +#endif +// QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); +// QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); +// if (glWidget != NULL) { +// } +// else if (openglWidget != NULL) { +// } +// else { +// m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; +// return; +// } + + CaretAssert(m_openglContext); + if ( ! m_openglContext->isValid()) { + m_errorMessage = "The OpenGL Context is not valid"; + return; + } + + // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); + + m_offScreenSurface.reset(new QOffscreenSurface()); + m_offScreenSurface->setFormat(surfaceFormat); + m_offScreenSurface->create(); + if ( ! m_offScreenSurface->isValid()) { + m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; + return; + } + + if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { + m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; + return; + } + + QOpenGLFramebufferObjectFormat frameBufferFormat; + frameBufferFormat.setSamples(2); + frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); + frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); + + m_frameBuffer.reset(new QOpenGLFramebufferObject(width, + height, + frameBufferFormat)); + if ( ! m_frameBuffer->isValid()) { + m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; + m_openglContext->doneCurrent(); + return; + } + +} + +/** + * Destructor. + */ +OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() +{ + m_openglContext->doneCurrent(); +} + +bool +OffScreenOpenGLRenderer::isError() const +{ + return ( ! m_errorMessage.isEmpty()); +} + +QString +OffScreenOpenGLRenderer::getErrorMessage() const +{ + return m_errorMessage; +} + +QImage +OffScreenOpenGLRenderer::getImage() +{ + QImage image; + + if ( ! m_frameBuffer) { + m_errorMessage = "Frame buffer is invalid while trying to get image"; + return image; + } + + image = m_frameBuffer->toImage(); + + return image; +} + + + -- GitLab From 3dfffb9e85d48cffcf60cbee648f598869cf12c3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Dec 2017 15:16:37 -0600 Subject: [PATCH 532/755] Had capitalization wrong on OffScreenRenderer.cxx (4th character 'S' as both lower and upper case) so it got added twice (Mac is case insensitive). So moved the file, deleting it from GIT with this command and then adding file back to GIT in next commit (if it works). --- src/GuiQt/OffscreenOpenGLRenderer.cxx | 169 -------------------------- 1 file changed, 169 deletions(-) delete mode 100644 src/GuiQt/OffscreenOpenGLRenderer.cxx diff --git a/src/GuiQt/OffscreenOpenGLRenderer.cxx b/src/GuiQt/OffscreenOpenGLRenderer.cxx deleted file mode 100644 index 37cec1b14..000000000 --- a/src/GuiQt/OffscreenOpenGLRenderer.cxx +++ /dev/null @@ -1,169 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2017 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ -#include "OffScreenOpenGLRenderer.h" -#undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ - -#include -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -#include -#else -#include -#include -#endif -#include -#include -#include - -#include "BrainOpenGLWidget.h" -#include "CaretAssert.h" - -using namespace caret; - - - -/** - * \class caret::OffScreenOpenGLRenderer - * \brief Performs offscreen rendering of a window. - * \ingroup GuiQt - */ - -/** - * Constructor. - * - * @param openGLWidgetInstance - * An instance of either QGLWidget or QOpenGLWidget - * @param width - * Width for image (may be different, perhaps larger, than width of 'openglWidget' - * @param height - * Height for image (may be different, perhaps larger, than hight of 'openglWidget' - */ -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET -OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, -#else -OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, -#endif - const int32_t width, - const int32_t height) -: QObject() -{ - CaretAssert(openglWidget); - - m_openglContext = NULL;; - QSurfaceFormat surfaceFormat; - - /* - * Copy the surface format - */ -#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET - surfaceFormat = openglWidget->format(); - m_openglContext = openglWidget->context(); -#else - surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); - CaretAssert(openglWidget->context()); - m_openglContext = openglWidget->context()->contextHandle(); -#endif -// QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); -// QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); -// if (glWidget != NULL) { -// } -// else if (openglWidget != NULL) { -// } -// else { -// m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; -// return; -// } - - CaretAssert(m_openglContext); - if ( ! m_openglContext->isValid()) { - m_errorMessage = "The OpenGL Context is not valid"; - return; - } - - // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); - - m_offScreenSurface.reset(new QOffscreenSurface()); - m_offScreenSurface->setFormat(surfaceFormat); - m_offScreenSurface->create(); - if ( ! m_offScreenSurface->isValid()) { - m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; - return; - } - - if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { - m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; - return; - } - - QOpenGLFramebufferObjectFormat frameBufferFormat; - frameBufferFormat.setSamples(2); - frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); - frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); - - m_frameBuffer.reset(new QOpenGLFramebufferObject(width, - height, - frameBufferFormat)); - if ( ! m_frameBuffer->isValid()) { - m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; - m_openglContext->doneCurrent(); - return; - } - -} - -/** - * Destructor. - */ -OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() -{ - m_openglContext->doneCurrent(); -} - -bool -OffScreenOpenGLRenderer::isError() const -{ - return ( ! m_errorMessage.isEmpty()); -} - -QString -OffScreenOpenGLRenderer::getErrorMessage() const -{ - return m_errorMessage; -} - -QImage -OffScreenOpenGLRenderer::getImage() -{ - QImage image; - - if ( ! m_frameBuffer) { - m_errorMessage = "Frame buffer is invalid while trying to get image"; - return image; - } - - image = m_frameBuffer->toImage(); - - return image; -} - - - -- GitLab From 2ddb4f18256ab0c4bc54078ec15e6726b6f9bef1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Dec 2017 15:18:39 -0600 Subject: [PATCH 533/755] Adding OffScreenOpenGLRenderer.cxx back into GIT with correct capitalization (see previous commit 391b67102e21481e8490d821d883a0d6cb0734b5). --- src/GuiQt/OffScreenOpenGLRenderer.cxx | 169 ++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/GuiQt/OffScreenOpenGLRenderer.cxx diff --git a/src/GuiQt/OffScreenOpenGLRenderer.cxx b/src/GuiQt/OffScreenOpenGLRenderer.cxx new file mode 100644 index 000000000..37cec1b14 --- /dev/null +++ b/src/GuiQt/OffScreenOpenGLRenderer.cxx @@ -0,0 +1,169 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ +#include "OffScreenOpenGLRenderer.h" +#undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + +#include +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +#include +#else +#include +#include +#endif +#include +#include +#include + +#include "BrainOpenGLWidget.h" +#include "CaretAssert.h" + +using namespace caret; + + + +/** + * \class caret::OffScreenOpenGLRenderer + * \brief Performs offscreen rendering of a window. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param openGLWidgetInstance + * An instance of either QGLWidget or QOpenGLWidget + * @param width + * Width for image (may be different, perhaps larger, than width of 'openglWidget' + * @param height + * Height for image (may be different, perhaps larger, than hight of 'openglWidget' + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, +#else +OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, +#endif + const int32_t width, + const int32_t height) +: QObject() +{ + CaretAssert(openglWidget); + + m_openglContext = NULL;; + QSurfaceFormat surfaceFormat; + + /* + * Copy the surface format + */ +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + surfaceFormat = openglWidget->format(); + m_openglContext = openglWidget->context(); +#else + surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); + CaretAssert(openglWidget->context()); + m_openglContext = openglWidget->context()->contextHandle(); +#endif +// QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); +// QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); +// if (glWidget != NULL) { +// } +// else if (openglWidget != NULL) { +// } +// else { +// m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; +// return; +// } + + CaretAssert(m_openglContext); + if ( ! m_openglContext->isValid()) { + m_errorMessage = "The OpenGL Context is not valid"; + return; + } + + // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); + + m_offScreenSurface.reset(new QOffscreenSurface()); + m_offScreenSurface->setFormat(surfaceFormat); + m_offScreenSurface->create(); + if ( ! m_offScreenSurface->isValid()) { + m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; + return; + } + + if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { + m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; + return; + } + + QOpenGLFramebufferObjectFormat frameBufferFormat; + frameBufferFormat.setSamples(2); + frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); + frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); + + m_frameBuffer.reset(new QOpenGLFramebufferObject(width, + height, + frameBufferFormat)); + if ( ! m_frameBuffer->isValid()) { + m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; + m_openglContext->doneCurrent(); + return; + } + +} + +/** + * Destructor. + */ +OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() +{ + m_openglContext->doneCurrent(); +} + +bool +OffScreenOpenGLRenderer::isError() const +{ + return ( ! m_errorMessage.isEmpty()); +} + +QString +OffScreenOpenGLRenderer::getErrorMessage() const +{ + return m_errorMessage; +} + +QImage +OffScreenOpenGLRenderer::getImage() +{ + QImage image; + + if ( ! m_frameBuffer) { + m_errorMessage = "Frame buffer is invalid while trying to get image"; + return image; + } + + image = m_frameBuffer->toImage(); + + return image; +} + + + -- GitLab From e4686a380656877a3ab75b23dc39f83ce1ae206c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 6 Dec 2017 16:16:16 -0600 Subject: [PATCH 534/755] Added new volume slice surface outline drawing to Oblique Volume Drawing. Also verified that new volume surface outline functions on a surface with an open topology. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 189 +++++++++++++----- .../SurfacePlaneIntersectionToContour.cxx | 34 +++- src/Files/SurfacePlaneIntersectionToContour.h | 41 +++- 3 files changed, 207 insertions(+), 57 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 4802f3f0f..7e7aed119 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -63,6 +63,7 @@ #include "SelectionManager.h" #include "SessionManager.h" #include "Surface.h" +#include "SurfacePlaneIntersectionToContour.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" @@ -2781,32 +2782,28 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnu void BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) { - if ( ! plane.isValidPlane()) { - return; - } - - float intersectionPoint1[3]; - float intersectionPoint2[3]; - - m_fixedPipelineDrawing->enableLineAntiAliasing(); + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); /* * Process each surface outline + * As of 24 May, "zero" is on top so draw in reverse order */ const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); - for (int io = 0; - io < numberOfOutlines; - io++) { + for (int32_t io = (numberOfOutlines - 1); + io >= 0; + io--) { + std::vector contourPrimitives; + VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { const float thickness = outline->getThickness(); - int numTriangles = surface->getNumberOfTriangles(); - CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; @@ -2815,6 +2812,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) switch (selectedColorOrTabItem->getItemType()) { case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); + outlineColor = CaretColorEnum::CUSTOM; break; case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: outlineColor = selectedColorOrTabItem->getColor(); @@ -2829,52 +2827,139 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) colorSourceBrowserTabIndex); } - glColor3fv(CaretColorEnum::toRGB(outlineColor)); - m_fixedPipelineDrawing->setLineWidth(thickness); - - /* - * Examine each triangle to see if it intersects the Plane - * in which the slice exists. - */ - glBegin(GL_LINES); - for (int it = 0; it < numTriangles; it++) { - const int32_t* triangleNodes = surface->getTriangle(it); - const float* c1 = surface->getCoordinate(triangleNodes[0]); - const float* c2 = surface->getCoordinate(triangleNodes[1]); - const float* c3 = surface->getCoordinate(triangleNodes[2]); - - if (plane.triangleIntersectPlane(c1, c2, c3, - intersectionPoint1, - intersectionPoint2)) { - if (surfaceColorFlag) { - /* - * Use coloring assigned to the first node in the triangle - * but only if Alpha is valid (greater than zero). - */ - const int64_t colorIndex = triangleNodes[0] * 4; - if (nodeColoringRGBA[colorIndex + 3] > 0.0) { - glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); - } - else { - continue; - } - } - - /* - * Draw the line where the triangle intersections the slice - */ - glVertex3fv(intersectionPoint1); - glVertex3fv(intersectionPoint2); - } + SurfacePlaneIntersectionToContour contour(surface, + plane, + outlineColor, + nodeColoringRGBA, + thickness); + AString errorMessage; + if ( ! contour.createContours(contourPrimitives, + errorMessage)) { + CaretLogSevere(errorMessage); } - glEnd(); } } + /** + * Draw the contours. + */ + for (auto primitive : contourPrimitives) { + glPolygonOffset(1.0, 1.0); + glEnable(GL_POLYGON_OFFSET_FILL); + + GraphicsEngineDataOpenGL::draw(primitive); + delete primitive; + + glDisable(GL_POLYGON_OFFSET_FILL); + } } - m_fixedPipelineDrawing->disableLineAntiAliasing(); + + glPopAttrib(); } +///** +// * Draw surface outlines on the volume slices +// * +// * @param plane +// * Plane of the volume slice on which surface outlines are drawn. +// */ +//void +//BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) +//{ +// if ( ! plane.isValidPlane()) { +// return; +// } +// +// float intersectionPoint1[3]; +// float intersectionPoint2[3]; +// +// m_fixedPipelineDrawing->enableLineAntiAliasing(); +// +// VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); +// +// /* +// * Process each surface outline +// */ +// const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); +// for (int io = 0; +// io < numberOfOutlines; +// io++) { +// VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); +// if (outline->isDisplayed()) { +// Surface* surface = outline->getSurface(); +// if (surface != NULL) { +// const float thickness = outline->getThickness(); +// +// int numTriangles = surface->getNumberOfTriangles(); +// +// CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; +// int32_t colorSourceBrowserTabIndex = -1; +// +// VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); +// VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); +// switch (selectedColorOrTabItem->getItemType()) { +// case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: +// colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); +// break; +// case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: +// outlineColor = selectedColorOrTabItem->getColor(); +// break; +// } +// const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); +// +// float* nodeColoringRGBA = NULL; +// if (surfaceColorFlag) { +// nodeColoringRGBA = m_fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, +// surface, +// colorSourceBrowserTabIndex); +// } +// +// glColor3fv(CaretColorEnum::toRGB(outlineColor)); +// m_fixedPipelineDrawing->setLineWidth(thickness); +// +// /* +// * Examine each triangle to see if it intersects the Plane +// * in which the slice exists. +// */ +// glBegin(GL_LINES); +// for (int it = 0; it < numTriangles; it++) { +// const int32_t* triangleNodes = surface->getTriangle(it); +// const float* c1 = surface->getCoordinate(triangleNodes[0]); +// const float* c2 = surface->getCoordinate(triangleNodes[1]); +// const float* c3 = surface->getCoordinate(triangleNodes[2]); +// +// if (plane.triangleIntersectPlane(c1, c2, c3, +// intersectionPoint1, +// intersectionPoint2)) { +// if (surfaceColorFlag) { +// /* +// * Use coloring assigned to the first node in the triangle +// * but only if Alpha is valid (greater than zero). +// */ +// const int64_t colorIndex = triangleNodes[0] * 4; +// if (nodeColoringRGBA[colorIndex + 3] > 0.0) { +// glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); +// } +// else { +// continue; +// } +// } +// +// /* +// * Draw the line where the triangle intersections the slice +// */ +// glVertex3fv(intersectionPoint1); +// glVertex3fv(intersectionPoint2); +// } +// } +// glEnd(); +// } +// } +// } +// +// m_fixedPipelineDrawing->disableLineAntiAliasing(); +//} + /** * Draw foci on volume slice. * diff --git a/src/Files/SurfacePlaneIntersectionToContour.cxx b/src/Files/SurfacePlaneIntersectionToContour.cxx index 76a6a632d..60e4eaefe 100644 --- a/src/Files/SurfacePlaneIntersectionToContour.cxx +++ b/src/Files/SurfacePlaneIntersectionToContour.cxx @@ -28,6 +28,7 @@ #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" +#include "ElapsedTimer.h" #include "GraphicsPrimitiveV3fC4f.h" #include "Plane.h" #include "SurfaceFile.h" @@ -130,12 +131,27 @@ SurfacePlaneIntersectionToContour::createContours(std::vectorgetNumberOfNodes() != m_topologyHelper->getNumberOfNodes()) { throw CaretException("Surface File and its Topology contain a different number of vertices."); } + static bool timingFlag = false; + ElapsedTimer timer; + if (timingFlag) { + timer.start(); + } prepareVertices(); - + const float verticesTime = (timingFlag ? timer.getElapsedTimeMilliseconds(): 0.0f); + prepareEdges(); + const float edgesTime = (timingFlag ? timer.getElapsedTimeMilliseconds() - verticesTime : 0.0f); generateContours(graphicsPrimitivesOut); + const float contoursTime = (timingFlag ? timer.getElapsedTimeMilliseconds() - edgesTime : 0.0f); + + if (timingFlag) { + std::cout << "Total Time=" << timer.getElapsedTimeMilliseconds() << std::endl; + std::cout << " Vertices=" << verticesTime << std::endl; + std::cout << " Edges=" << edgesTime << std::endl; + std::cout << " Contours=" << contoursTime << std::endl; + } } catch (const CaretException& caretException) { errorMessageOut = caretException.whatString(); @@ -210,6 +226,9 @@ SurfacePlaneIntersectionToContour::prepareEdges() const std::vector& allEdgeInfo = m_topologyHelper->getEdgeInfo(); const int32_t numEdges = static_cast(allEdgeInfo.size()); + + m_topoHelperEdgeToIntersectingEdgeIndices.reserve(numEdges); + for (int32_t i = 0; i < numEdges; i++) { CaretAssertVectorIndex(allEdgeInfo, i); const TopologyEdgeInfo& edgeInfo = allEdgeInfo[i]; @@ -261,6 +280,8 @@ SurfacePlaneIntersectionToContour::prepareEdges() m_intersectingEdges.push_back(std::move(edge)); intersectingEdgeIndex = m_intersectingEdges.size() - 1; + + m_numberOfIntersectingEdges++; } } @@ -295,6 +316,15 @@ SurfacePlaneIntersectionToContour::generateContours(std::vector primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_contourThicknessPercentOfViewportHeight); + primitive->reserveForNumberOfVertices(m_numberOfIntersectingEdges + 5); + IntersectionEdge* edge = startingEdge; if (m_debugFlag) { diff --git a/src/Files/SurfacePlaneIntersectionToContour.h b/src/Files/SurfacePlaneIntersectionToContour.h index 5d74d7c80..22013717b 100644 --- a/src/Files/SurfacePlaneIntersectionToContour.h +++ b/src/Files/SurfacePlaneIntersectionToContour.h @@ -58,6 +58,15 @@ namespace caret { */ class Vertex { public: + /** + * Constructor. + * + * @param xyz + * The coordinate of the vertex. + * @param signedDistanceAbovePlane + * Distance of vertex above the plane. + * (negative if below the plane). + */ Vertex(const std::array& xyz, const float signedDistanceAbovePlane) : m_xyz(xyz), @@ -66,8 +75,13 @@ namespace caret { ~Vertex() { } + /** Coordinate of vertex */ const std::array m_xyz; + + /** Distance above plane (negative if below plane) */ const float m_signedDistanceAbovePlane; + + /** True if above plane, else false */ const bool m_abovePlaneFlag; }; @@ -76,11 +90,28 @@ namespace caret { */ class IntersectionEdge { public: + /** + * Constructor. + * + * @param intersectionXYZ + * Location in the edge that intersects the plane + * @param belowPlaneVertexIndex + * Vertex in the edge that is below the plane. + * @param abovePlaneVertexIndex + * Vertex in the edge that is above the plane. + * @param triangleOneIndex + * Index of a triangle that shares edge. This triangle + * will always be valid. + * @param triangleTwoIndex + * Index of a triangle that shares edge. This triangle + * may be invalid if the edge is on the boundary + * of an open topology. + */ IntersectionEdge(const std::array& intersectionXYZ, - int32_t belowPlaneVertexIndex, - int32_t abovePlaneVertexIndex, - int32_t triangleOneIndex, - int32_t triangleTwoIndex) + int32_t belowPlaneVertexIndex, + int32_t abovePlaneVertexIndex, + int32_t triangleOneIndex, + int32_t triangleTwoIndex) : m_intersectionXYZ(intersectionXYZ), m_belowPlaneVertexIndex(belowPlaneVertexIndex), m_abovePlaneVertexIndex(abovePlaneVertexIndex), @@ -172,6 +203,8 @@ namespace caret { /** index with a topo helper edge index to get its intersecting edge (-1) if edge does not intersect */ std::vector m_topoHelperEdgeToIntersectingEdgeIndices; + int32_t m_numberOfIntersectingEdges = 0; + bool m_debugFlag = false; // ADD_NEW_MEMBERS_HERE -- GitLab From 3a196f343301795cf7b5e257ad8195bd1e578964 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Dec 2017 12:17:39 -0600 Subject: [PATCH 535/755] Corrected MathFunctions::triangleSignedArea2D: Calculation were in float and the result was incorrect when an edge of the triangle was very, very small. Calculations are now performed in double-precision and area calculation is now correct. --- src/Common/MathFunctions.cxx | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Common/MathFunctions.cxx b/src/Common/MathFunctions.cxx index 89b7af704..bf2f76995 100644 --- a/src/Common/MathFunctions.cxx +++ b/src/Common/MathFunctions.cxx @@ -778,8 +778,28 @@ MathFunctions::triangleAreaSigned2D( const float p2[2], const float p3[2]) { - float area = ( p1[0]*p2[1] + p2[0]*p3[1] + p3[0]*p1[1] - - p1[1]*p2[0] - p2[1]*p3[0] - p3[1]*p1[0] ) * 0.5f; + /* + * Prior to 07 Dec 2017, this area calculation was performed + * using floats. However, when a triangle edge was very small, + * the area calculation was incorrect (did not match the area + * produced by triangleAreaSigned3D() and often with the incorrect + * sign). Using double precision values corrects the problem. + * + * When calculated as floats in this equation, changing the order + * even affected the area calculation: + * + * float area = ( p1[0]*p2[1] + p2[0]*p3[1] + p3[0]*p1[1] + * - p1[1]*p2[0] - p2[1]*p3[0] - p3[1]*p1[0] ) * 0.5f; + */ + + const double x1 = p1[0]; + const double y1 = p1[1]; + const double x2 = p2[0]; + const double y2 = p2[1]; + const double x3 = p3[0]; + const double y3 = p3[1]; + const double area = ( x1*y2 + x2*y3 + x3*y1 + - y1*x2 - y2*x3 - y3*x1) * 0.5; return area; } -- GitLab From 02458cd37b595fe5bc6eb8eaa6d7ee5dc3ef0d76 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Dec 2017 12:20:43 -0600 Subject: [PATCH 536/755] Add parallel computation to processing of vertices (distance of each vertex from plane). --- src/Files/SurfacePlaneIntersectionToContour.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Files/SurfacePlaneIntersectionToContour.cxx b/src/Files/SurfacePlaneIntersectionToContour.cxx index 60e4eaefe..a1d8ef5e0 100644 --- a/src/Files/SurfacePlaneIntersectionToContour.cxx +++ b/src/Files/SurfacePlaneIntersectionToContour.cxx @@ -28,6 +28,7 @@ #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" +#include "CaretOMP.h" #include "ElapsedTimer.h" #include "GraphicsPrimitiveV3fC4f.h" #include "Plane.h" @@ -182,8 +183,9 @@ SurfacePlaneIntersectionToContour::prepareVertices() const int32_t numberOfVertices = m_surfaceFile->getNumberOfNodes(); - m_vertices.reserve(numberOfVertices); + m_vertices.resize(numberOfVertices); +#pragma omp CARET_PARFOR for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; std::array xyz = {{ surfaceXYZ[i3], surfaceXYZ[i3 + 1], surfaceXYZ[i3 + 2] }}; @@ -209,8 +211,7 @@ SurfacePlaneIntersectionToContour::prepareVertices() } } - std::unique_ptr vp(new Vertex(xyz, signedDistanceToPlane)); - m_vertices.push_back(std::move(vp)); + m_vertices[i].reset(new Vertex(xyz, signedDistanceToPlane)); } CaretAssert(static_cast(m_vertices.size()) == numberOfVertices); -- GitLab From 7fff65ecab5a7102379e865dfb14e90a4b9334f7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Dec 2017 12:22:02 -0600 Subject: [PATCH 537/755] Small gaps noticed with volume surface outline were fixed by a previous commit that fixed 2D triangle area calculation and using zero for left/right turn calculation for line segments. --- src/Graphics/GraphicsOpenGLPolylineTriangles.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index cbdc1bed9..9306ca1d9 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -851,7 +851,7 @@ GraphicsOpenGLPolylineTriangles::getTurnDirection(const PolylineInfo& polyOne, &m_vertexWindowXYZ[windowVertexIndexThree * 3]); - const float smallNumber = 0.001; + const float smallNumber = 0.0f; if (signedArea > smallNumber) { turnDirection = TurnDirection::LEFT; } @@ -1145,7 +1145,7 @@ GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() * otherwise, flip the vertices */ const float signedArea = MathFunctions::triangleAreaSigned2D(v1, v2, v3); - const float smallNumber = 0.001; + const float smallNumber = 0.0f; const bool normalOutFlag = (signedArea > smallNumber); const float* tv2 = (normalOutFlag ? v2 : v3); -- GitLab From cd7b63fcbfa8b834f5397537ef5a6b16f94256ee Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 7 Dec 2017 14:53:39 -0600 Subject: [PATCH 538/755] One gap still remained in a surface contour where the first and last points connected. This has been fixed in the lines to polygon conversion by appending the points with the first two points. The first two points are needed for the join logic to fill the gap. --- .../SurfacePlaneIntersectionToContour.cxx | 2 +- .../GraphicsOpenGLPolylineTriangles.cxx | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Files/SurfacePlaneIntersectionToContour.cxx b/src/Files/SurfacePlaneIntersectionToContour.cxx index a1d8ef5e0..73637d914 100644 --- a/src/Files/SurfacePlaneIntersectionToContour.cxx +++ b/src/Files/SurfacePlaneIntersectionToContour.cxx @@ -335,7 +335,7 @@ SurfacePlaneIntersectionToContour::generateContourFromEdge(IntersectionEdge* sta const std::vector& allTileInfo = m_topologyHelper->getTileInfo(); - std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); + std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN)); primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_contourThicknessPercentOfViewportHeight); primitive->reserveForNumberOfVertices(m_numberOfIntersectingEdges + 5); diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 9306ca1d9..d9aa0f430 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -423,6 +423,7 @@ GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() glGetIntegerv(GL_VIEWPORT, viewport); + bool closeLoopFlag = false; int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); int32_t iStep = 1; switch (m_lineType) { @@ -434,7 +435,21 @@ GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() } break; case LineType::LINE_LOOP: + closeLoopFlag = true; iStep = 1; + if (numInputPoints > 3) { + /* + * For a loop, ignore the last point if it is the + * same as the first point + */ + const int32_t lastOffset = (numInputPoints - 1) * 3; + CaretAssertVectorIndex(m_inputXYZ, lastOffset + 2); + const float distance = MathFunctions::distance3D(&m_inputXYZ[0], + &m_inputXYZ[lastOffset]); + if (distance < 0.0001f) { + --numInputPoints; + } + } break; case LineType::LINE_STRIP: iStep = 1; @@ -526,6 +541,24 @@ GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() } } + if (closeLoopFlag) { + /* + * Close by adding first two points to end (duplicates them). + * Two points are necessary for the joins so that there is + * not a gap where the last and first points connect. + */ + const int32_t numXYZ = (m_vertexWindowXYZ.size() / 3); + if (numXYZ > 3) { + const int32_t closeCount = 2; + for (int32_t i = 0; i < (closeCount * 3); i++) { + m_vertexWindowXYZ.push_back(m_vertexWindowXYZ[i]); + } + for (int32_t i = 0; i < closeCount; i++) { + m_vertexWindowInputIndices.push_back(m_vertexWindowInputIndices[i]); + } + } + } + CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); } @@ -775,7 +808,7 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() numPolylinesToConnect = 0; break; case LineType::LINE_LOOP: - numPolylinesToConnect = numPolylines; + numPolylinesToConnect = numPolylinesMinusOne; //numPolylines; break; case LineType::LINE_STRIP: numPolylinesToConnect = numPolylinesMinusOne; -- GitLab From 26be8f9dd530c59c8e71163cee498a6d254a1ea0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 8 Dec 2017 11:13:59 -0600 Subject: [PATCH 539/755] Added an inverse transform that converts a window coordinate to an object coordinate. --- .../EventOpenGLObjectToWindowTransform.cxx | 60 +++++++++++++++++++ .../EventOpenGLObjectToWindowTransform.h | 7 +++ 2 files changed, 67 insertions(+) diff --git a/src/Graphics/EventOpenGLObjectToWindowTransform.cxx b/src/Graphics/EventOpenGLObjectToWindowTransform.cxx index d2bd9ded9..3b26b1be7 100644 --- a/src/Graphics/EventOpenGLObjectToWindowTransform.cxx +++ b/src/Graphics/EventOpenGLObjectToWindowTransform.cxx @@ -82,6 +82,55 @@ EventOpenGLObjectToWindowTransform::isValid() const return m_validFlag; } +/** + * Transform a window coordinate to an object coordinate. + * + * @param windowXYZ + * The window coordinate. + * @param objectXYZOut + * Output containing the computed object coordinate. + * @return + * True if output coordinate is valid, else false. + */ +bool +EventOpenGLObjectToWindowTransform::inverseTransformPoint(const float windowXYZ[3], + float objectXYZOut[3]) const +{ + if ( ! m_validFlag) { + CaretAssert(0); + CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform is not valid"); + return false; + } + + /* + * If needed, create the inverse matrix + */ + if ( ! m_inverseTransformMatrix) { + m_inverseTransformMatrix.reset(new Matrix4x4(m_transformMatrix)); + + if ( ! m_inverseTransformMatrix->invert()) { + CaretAssert(0); + CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform unable to invert matrix"); + return false; + } + } + + float xyzw[4] { + (2.0f * (windowXYZ[0] - m_viewport[0]) / m_viewport[2]) - 1.0f, + (2.0f * (windowXYZ[1] - m_viewport[1]) / m_viewport[3]) - 1.0f, + (2.0f * windowXYZ[2]) - 1.0f, + 1.0f + }; + + m_inverseTransformMatrix->multiplyPoint4(xyzw); + + objectXYZOut[0] = xyzw[0]; + objectXYZOut[1] = xyzw[1]; + objectXYZOut[2] = xyzw[2]; + + return true; +} + /** * Transform an object coordinate to a window coordinate. * @@ -228,3 +277,14 @@ EventOpenGLObjectToWindowTransform::setup(const std::array& modelvie m_validFlag = true; } + +/** + * @return The viewport. + */ +std::array +EventOpenGLObjectToWindowTransform::getViewport() const +{ + return m_viewport; +} + + diff --git a/src/Graphics/EventOpenGLObjectToWindowTransform.h b/src/Graphics/EventOpenGLObjectToWindowTransform.h index 785471d6f..2dd7c2573 100644 --- a/src/Graphics/EventOpenGLObjectToWindowTransform.h +++ b/src/Graphics/EventOpenGLObjectToWindowTransform.h @@ -54,6 +54,9 @@ namespace caret { bool isValid() const; + bool inverseTransformPoint(const float windowXYZ[3], + float objectXYZOut[3]) const; + bool transformPoint(const float objectXYZ[3], float windowXYZOut[3]) const; @@ -63,6 +66,8 @@ namespace caret { const std::array& depthRange, const double centerToEyeDistance); + std::array getViewport() const; + // ADD_NEW_METHODS_HERE private: @@ -74,6 +79,8 @@ namespace caret { Matrix4x4 m_transformMatrix; + mutable std::unique_ptr m_inverseTransformMatrix; + std::array m_projectionMatrixArray; std::array m_viewport; -- GitLab From cfda223e51bbe2517d27a943f16f7a2e74a18fa5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 8 Dec 2017 11:49:12 -0600 Subject: [PATCH 540/755] Changed volume surface outline drawing so that the surface outline width is in millimeters. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 192 +----------------- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 2 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 28 ++- src/Brain/BrainOpenGLVolumeSliceDrawing.h | 7 +- src/Graphics/CMakeLists.txt | 2 + src/Graphics/GraphicsUtilitiesOpenGL.cxx | 99 +++++++++ src/Graphics/GraphicsUtilitiesOpenGL.h | 54 +++++ .../VolumeSurfaceOutlineViewController.cxx | 6 +- 8 files changed, 187 insertions(+), 203 deletions(-) create mode 100644 src/Graphics/GraphicsUtilitiesOpenGL.cxx create mode 100644 src/Graphics/GraphicsUtilitiesOpenGL.h diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 7e7aed119..71cb53b8b 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -32,6 +32,7 @@ #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLViewportContent.h" +#include "BrainOpenGLVolumeSliceDrawing.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -2720,7 +2721,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnu glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - drawSurfaceOutline(slicePlane); + BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(slicePlane, + m_browserTabContent->getVolumeSurfaceOutlineSet(), + m_fixedPipelineDrawing); } if (drawFibersFlag) { @@ -2773,193 +2776,6 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnu } } -/** - * Draw surface outlines on the volume slices - * - * @param plane - * Plane of the volume slice on which surface outlines are drawn. - */ -void -BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) -{ - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - - VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); - - /* - * Process each surface outline - * As of 24 May, "zero" is on top so draw in reverse order - */ - const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); - for (int32_t io = (numberOfOutlines - 1); - io >= 0; - io--) { - std::vector contourPrimitives; - - VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); - if (outline->isDisplayed()) { - Surface* surface = outline->getSurface(); - if (surface != NULL) { - const float thickness = outline->getThickness(); - - CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; - int32_t colorSourceBrowserTabIndex = -1; - - VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); - VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); - switch (selectedColorOrTabItem->getItemType()) { - case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: - colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); - outlineColor = CaretColorEnum::CUSTOM; - break; - case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: - outlineColor = selectedColorOrTabItem->getColor(); - break; - } - const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); - - float* nodeColoringRGBA = NULL; - if (surfaceColorFlag) { - nodeColoringRGBA = m_fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, - surface, - colorSourceBrowserTabIndex); - } - - SurfacePlaneIntersectionToContour contour(surface, - plane, - outlineColor, - nodeColoringRGBA, - thickness); - AString errorMessage; - if ( ! contour.createContours(contourPrimitives, - errorMessage)) { - CaretLogSevere(errorMessage); - } - } - } - /** - * Draw the contours. - */ - for (auto primitive : contourPrimitives) { - glPolygonOffset(1.0, 1.0); - glEnable(GL_POLYGON_OFFSET_FILL); - - GraphicsEngineDataOpenGL::draw(primitive); - delete primitive; - - glDisable(GL_POLYGON_OFFSET_FILL); - } - } - - - glPopAttrib(); -} - -///** -// * Draw surface outlines on the volume slices -// * -// * @param plane -// * Plane of the volume slice on which surface outlines are drawn. -// */ -//void -//BrainOpenGLVolumeObliqueSliceDrawing::drawSurfaceOutline(const Plane& plane) -//{ -// if ( ! plane.isValidPlane()) { -// return; -// } -// -// float intersectionPoint1[3]; -// float intersectionPoint2[3]; -// -// m_fixedPipelineDrawing->enableLineAntiAliasing(); -// -// VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); -// -// /* -// * Process each surface outline -// */ -// const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); -// for (int io = 0; -// io < numberOfOutlines; -// io++) { -// VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); -// if (outline->isDisplayed()) { -// Surface* surface = outline->getSurface(); -// if (surface != NULL) { -// const float thickness = outline->getThickness(); -// -// int numTriangles = surface->getNumberOfTriangles(); -// -// CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; -// int32_t colorSourceBrowserTabIndex = -1; -// -// VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); -// VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); -// switch (selectedColorOrTabItem->getItemType()) { -// case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: -// colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); -// break; -// case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: -// outlineColor = selectedColorOrTabItem->getColor(); -// break; -// } -// const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); -// -// float* nodeColoringRGBA = NULL; -// if (surfaceColorFlag) { -// nodeColoringRGBA = m_fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, -// surface, -// colorSourceBrowserTabIndex); -// } -// -// glColor3fv(CaretColorEnum::toRGB(outlineColor)); -// m_fixedPipelineDrawing->setLineWidth(thickness); -// -// /* -// * Examine each triangle to see if it intersects the Plane -// * in which the slice exists. -// */ -// glBegin(GL_LINES); -// for (int it = 0; it < numTriangles; it++) { -// const int32_t* triangleNodes = surface->getTriangle(it); -// const float* c1 = surface->getCoordinate(triangleNodes[0]); -// const float* c2 = surface->getCoordinate(triangleNodes[1]); -// const float* c3 = surface->getCoordinate(triangleNodes[2]); -// -// if (plane.triangleIntersectPlane(c1, c2, c3, -// intersectionPoint1, -// intersectionPoint2)) { -// if (surfaceColorFlag) { -// /* -// * Use coloring assigned to the first node in the triangle -// * but only if Alpha is valid (greater than zero). -// */ -// const int64_t colorIndex = triangleNodes[0] * 4; -// if (nodeColoringRGBA[colorIndex + 3] > 0.0) { -// glColor3fv(&nodeColoringRGBA[triangleNodes[0] * 4]); -// } -// else { -// continue; -// } -// } -// -// /* -// * Draw the line where the triangle intersections the slice -// */ -// glVertex3fv(intersectionPoint1); -// glVertex3fv(intersectionPoint2); -// } -// } -// glEnd(); -// } -// } -// } -// -// m_fixedPipelineDrawing->disableLineAntiAliasing(); -//} - /** * Draw foci on volume slice. * diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index 63a07cbbd..872b05881 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -261,7 +261,7 @@ namespace caret { const Plane& slicePlane, const float sliceCoordinates[3]); - void drawSurfaceOutline(const Plane& plane); +// void drawSurfaceOutline(const Plane& plane); void drawVolumeSliceFoci(const Plane& plane); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 8c68a4ff2..9218da60c 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -51,6 +51,7 @@ #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4f.h" +#include "GraphicsUtilitiesOpenGL.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "IdentificationWithColor.h" @@ -3488,7 +3489,9 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - drawSurfaceOutline(slicePlane); + drawSurfaceOutline(slicePlane, + m_browserTabContent->getVolumeSurfaceOutlineSet(), + m_fixedPipelineDrawing); } if (drawFibersFlag) { @@ -3545,17 +3548,21 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum * Draw surface outlines on the volume slices * * @param plane - * Plane of the volume slice on which surface outlines are drawn. + * Plane of the volume slice on which surface outlines are drawn. + * @param outlineSet + * The surface outline set. + * @param fixedPipelineDrawing + * The fixed pipeline drawing. */ void -BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) +BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing) { glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - VolumeSurfaceOutlineSetModel* outlineSet = m_browserTabContent->getVolumeSurfaceOutlineSet(); - /* * Process each surface outline * As of 24 May, "zero" is on top so draw in reverse order @@ -3590,16 +3597,17 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) float* nodeColoringRGBA = NULL; if (surfaceColorFlag) { - nodeColoringRGBA = m_fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, + nodeColoringRGBA = fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, surface, colorSourceBrowserTabIndex); } + const float thicknessPercentage = GraphicsUtilitiesOpenGL::getPercentageOfViewportHeightFromMillimeters(thickness); SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, nodeColoringRGBA, - thickness); + thicknessPercentage); // thickness); AString errorMessage; if ( ! contour.createContours(contourPrimitives, errorMessage)) { @@ -3607,6 +3615,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) } } } + /** * Draw the contours. */ @@ -3616,15 +3625,14 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane) GraphicsEngineDataOpenGL::draw(primitive); delete primitive; - + glDisable(GL_POLYGON_OFFSET_FILL); } } - glPopAttrib(); } - + /** * Draw foci on volume slice. * diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.h b/src/Brain/BrainOpenGLVolumeSliceDrawing.h index 387701133..bd6251b42 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.h @@ -41,6 +41,7 @@ namespace caret { class PaletteFile; class Plane; class VolumeMappableInterface; + class VolumeSurfaceOutlineSetModel; class BrainOpenGLVolumeSliceDrawing : public CaretObject { @@ -238,7 +239,9 @@ namespace caret { const Plane& slicePlane, const float sliceCoordinates[3]); - void drawSurfaceOutline(const Plane& plane); + static void drawSurfaceOutline(const Plane& plane, + VolumeSurfaceOutlineSetModel* outlineSet, + BrainOpenGLFixedPipeline* fixedPipelineDrawing); void drawVolumeSliceFoci(const Plane& plane); @@ -360,6 +363,8 @@ namespace caret { static const int32_t IDENTIFICATION_INDICES_PER_VOXEL; + friend class BrainOpenGLVolumeObliqueSliceDrawing; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index 2957c0b70..b3b58782a 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -26,6 +26,7 @@ GraphicsPrimitiveV3fC4ub.h GraphicsPrimitiveV3fN3f.h GraphicsPrimitiveV3fT3f.h GraphicsShape.h +GraphicsUtilitiesOpenGL.h EventGraphicsOpenGLCreateBufferObject.cxx EventGraphicsOpenGLCreateTextureName.cxx @@ -45,6 +46,7 @@ GraphicsPrimitiveV3fC4ub.cxx GraphicsPrimitiveV3fN3f.cxx GraphicsPrimitiveV3fT3f.cxx GraphicsShape.cxx +GraphicsUtilitiesOpenGL.cxx ) # diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx new file mode 100644 index 000000000..9c00dc1b1 --- /dev/null +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -0,0 +1,99 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ +#include "GraphicsUtilitiesOpenGL.h" +#undef __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +#include "EventManager.h" +#include "EventOpenGLObjectToWindowTransform.h" +#include "MathFunctions.h" +using namespace caret; + + + +/** + * \class caret::GraphicsUtilitiesOpenGL + * \brief Utility functions for use with OpenGL. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsUtilitiesOpenGL::GraphicsUtilitiesOpenGL() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +GraphicsUtilitiesOpenGL::~GraphicsUtilitiesOpenGL() +{ +} + +/** + * Converts millimeters to a percentage of the viewport height. + * The current transformations must be for drawing in millimeters. + * + * @param millimeters + * The value in millimeters. + * @return + The percentage of height [0.0, 100.0] for the given number of millimeters. + */ +float +GraphicsUtilitiesOpenGL::getPercentageOfViewportHeightFromMillimeters(const float millimeters) +{ + float percentageOfViewportHeight = -1.0f; + + EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); + EventManager::get()->sendEvent(xform.getPointer()); + if (xform.isValid()) { + const std::array viewport = xform.getViewport(); + + const float windowZ = 0.0f; + float bottomWindowXYZ[3] = { viewport[0], viewport[1], windowZ }; + float topWindowXYZ[3] = { viewport[0], viewport[1] + viewport[3], windowZ }; + + float bottomModelXYZ[3]; + float topModelXYZ[3]; + + xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); + xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); + + const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, + topModelXYZ); + const float rangePixels = viewport[3]; + if ((rangePixels > 0) + && (rangeMillimeters > 0)) { + percentageOfViewportHeight = (millimeters / rangeMillimeters) * 100.0f; + } + } + + return percentageOfViewportHeight ; + +} diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h new file mode 100644 index 000000000..89787b17f --- /dev/null +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -0,0 +1,54 @@ +#ifndef __GRAPHICS_UTILITIES_OPEN_G_L_H__ +#define __GRAPHICS_UTILITIES_OPEN_G_L_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +namespace caret { + + class GraphicsUtilitiesOpenGL : public CaretObject { + + public: + + static float getPercentageOfViewportHeightFromMillimeters(const float millimeters); + + private: + GraphicsUtilitiesOpenGL(); + + virtual ~GraphicsUtilitiesOpenGL(); + + GraphicsUtilitiesOpenGL(const GraphicsUtilitiesOpenGL&); + + GraphicsUtilitiesOpenGL& operator=(const GraphicsUtilitiesOpenGL&); + + }; + +#ifdef __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ + // +#endif // __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ + +} // namespace +#endif //__GRAPHICS_UTILITIES_OPEN_G_L_H__ diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index 8dacf46b0..bc273e35f 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -79,11 +79,11 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: "If tab, coloring assigned to selected surface\n" "in the selected tab is used.\n"); this->thicknessSpinBox = new WuQDoubleSpinBox(this); - this->thicknessSpinBox->setRangePercentage(0.0, 100.0); + this->thicknessSpinBox->setRange(0.0, 100.0); + this->thicknessSpinBox->setSingleStep(0.10); + this->thicknessSpinBox->setSuffix("mm"); QObject::connect(this->thicknessSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged); -// QObject::connect(this->thicknessSpinBox, SIGNAL(valueChanged(double)), -// this, SLOT(thicknessSpinBoxValueChanged(double))); this->thicknessSpinBox->setToolTip("Thickness of surface outline as percentage of viewport height"); -- GitLab From ca528e8535fd07d2f8cd99e53873939155c44c2b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 11 Dec 2017 08:53:24 -0600 Subject: [PATCH 541/755] Rename 'thickness' attributes of volume surface outline to 'thickness pixels obsolete' since it will soon be replaced with millimeters or percentage of viewport height. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 4 ++-- src/Brain/VolumeSurfaceOutlineModel.cxx | 18 +++++++++--------- src/Brain/VolumeSurfaceOutlineModel.h | 10 +++++----- src/Brain/VolumeSurfaceOutlineSetModel.cxx | 16 ++++++++-------- src/Graphics/GraphicsUtilitiesOpenGL.cxx | 2 +- src/Graphics/GraphicsUtilitiesOpenGL.h | 4 ++-- .../VolumeSurfaceOutlineViewController.cxx | 4 ++-- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 9218da60c..4fbec4821 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3577,7 +3577,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { - const float thickness = outline->getThickness(); + const float thickness = outline->getThicknessPixelsObsolete(); CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; @@ -3602,7 +3602,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, colorSourceBrowserTabIndex); } - const float thicknessPercentage = GraphicsUtilitiesOpenGL::getPercentageOfViewportHeightFromMillimeters(thickness); + const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(thickness); SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, diff --git a/src/Brain/VolumeSurfaceOutlineModel.cxx b/src/Brain/VolumeSurfaceOutlineModel.cxx index 5ebac6439..919161f02 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineModel.cxx @@ -52,13 +52,13 @@ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() validSurfaceTypes.push_back(SurfaceTypeEnum::VERY_INFLATED); m_displayed = false; - m_thickness = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS; + m_thicknessPixelsObsolete = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; m_surfaceSelectionModel = new SurfaceSelectionModel(validSurfaceTypes); m_colorOrTabModel = new VolumeSurfaceOutlineColorOrTabModel(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayed", &m_displayed); - m_sceneAssistant->add("m_thickness", &m_thickness); + m_sceneAssistant->add("m_thickness", &m_thicknessPixelsObsolete); // NOTE: "m_thickness" is OLD name m_sceneAssistant->add("m_surfaceSelectionModel", "SurfaceSelectionModel", m_surfaceSelectionModel); m_sceneAssistant->add("m_colorOrTabModel", "VolumeSurfaceOutlineColorOrTabModel", m_colorOrTabModel); @@ -84,7 +84,7 @@ void VolumeSurfaceOutlineModel::copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineModel* modelToCopy) { m_displayed = modelToCopy->m_displayed; - m_thickness = modelToCopy->m_thickness; + m_thicknessPixelsObsolete = modelToCopy->m_thicknessPixelsObsolete; m_surfaceSelectionModel->setSurface(modelToCopy->getSurface()); VolumeSurfaceOutlineColorOrTabModel* colorTabToCopy = modelToCopy->getColorOrTabModel(); @@ -122,23 +122,23 @@ VolumeSurfaceOutlineModel::setDisplayed(const bool displayed) } /** - * @return Thickness for drawing surface. + * @return Thickness for drawing surface (OBSOLETE) */ float -VolumeSurfaceOutlineModel::getThickness() const +VolumeSurfaceOutlineModel::getThicknessPixelsObsolete() const { - return m_thickness; + return m_thicknessPixelsObsolete; } /** - * Set the thickness for drawing the surface. + * Set the thickness for drawing the surface (OBSOLETE) * @param thickness * New value for thickness. */ void -VolumeSurfaceOutlineModel::setThickness(const float thickness) +VolumeSurfaceOutlineModel::setThicknessPixelsObsolete(const float thickness) { - m_thickness = thickness; + m_thicknessPixelsObsolete = thickness; } /** diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index 9181376d2..873486f8a 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -45,9 +45,9 @@ namespace caret { void setDisplayed(const bool displayed); - float getThickness() const; + float getThicknessPixelsObsolete() const; - void setThickness(const float thickness); + void setThicknessPixelsObsolete(const float thickness); SurfaceSelectionModel* getSurfaceSelectionModel(); @@ -65,7 +65,7 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); - static const int32_t DEFAULT_LINE_THICKNESS; + static const int32_t DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; private: VolumeSurfaceOutlineModel(const VolumeSurfaceOutlineModel&); @@ -78,7 +78,7 @@ namespace caret { private: bool m_displayed; - float m_thickness; + float m_thicknessPixelsObsolete; SurfaceSelectionModel* m_surfaceSelectionModel; @@ -88,7 +88,7 @@ namespace caret { }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ - const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS = 2.0; + const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ diff --git a/src/Brain/VolumeSurfaceOutlineSetModel.cxx b/src/Brain/VolumeSurfaceOutlineSetModel.cxx index 78f167145..ac03076ef 100644 --- a/src/Brain/VolumeSurfaceOutlineSetModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineSetModel.cxx @@ -233,40 +233,40 @@ VolumeSurfaceOutlineSetModel::selectSurfacesAfterSpecFileLoaded(Brain* brain, for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { m_outlineModels[i]->getColorOrTabModel()->setColor(CaretColorEnum::BLACK); - m_outlineModels[i]->setThickness(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS); + m_outlineModels[i]->setThicknessPixelsObsolete(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE); } int nextOutlineIndex = 0; addSurfaceOutline(leftMidThickSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, leftTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(rightMidThickSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, rightTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(leftWhiteSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(rightWhiteSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(leftPialSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::BLUE, nextOutlineIndex); addSurfaceOutline(rightPialSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS, + VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::BLUE, nextOutlineIndex); @@ -304,7 +304,7 @@ VolumeSurfaceOutlineSetModel::addSurfaceOutline(Surface* surface, if (outlineIndex < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES) { VolumeSurfaceOutlineModel* vsos = m_outlineModels[outlineIndex]; vsos->getSurfaceSelectionModel()->setSurface(surface); - vsos->setThickness(thickness); + vsos->setThicknessPixelsObsolete(thickness); if (browserTabIndex >= 0) { vsos->getColorOrTabModel()->setBrowserTabIndex(browserTabIndex); } diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index 9c00dc1b1..058f7549d 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -66,7 +66,7 @@ GraphicsUtilitiesOpenGL::~GraphicsUtilitiesOpenGL() The percentage of height [0.0, 100.0] for the given number of millimeters. */ float -GraphicsUtilitiesOpenGL::getPercentageOfViewportHeightFromMillimeters(const float millimeters) +GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(const float millimeters) { float percentageOfViewportHeight = -1.0f; diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h index 89787b17f..c3a11b2db 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.h +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -33,8 +33,8 @@ namespace caret { public: - static float getPercentageOfViewportHeightFromMillimeters(const float millimeters); - + static float convertMillimetersToPercentageOfViewportHeight(const float millimeters); + private: GraphicsUtilitiesOpenGL(); diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index bc273e35f..a221bc629 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -181,7 +181,7 @@ void VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged(double value) { if (this->outlineModel != NULL) { - this->outlineModel->setThickness(value); + this->outlineModel->setThicknessPixelsObsolete(value); } this->updateGraphics(); } @@ -204,7 +204,7 @@ VolumeSurfaceOutlineViewController::updateViewController(VolumeSurfaceOutlineMod this->enabledCheckBox->setCheckState(state); this->thicknessSpinBox->blockSignals(true); - this->thicknessSpinBox->setValue(outlineModel->getThickness()); + this->thicknessSpinBox->setValue(outlineModel->getThicknessPixelsObsolete()); this->thicknessSpinBox->blockSignals(false); this->surfaceSelectionViewController->updateControl(outlineModel->getSurfaceSelectionModel()); //this->surfaceSelectionViewController->setSurface(outlineModel->getSurface()); -- GitLab From f6768d9f67ddbc751f926872b6578ea77c933c9f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 11 Dec 2017 14:55:16 -0600 Subject: [PATCH 542/755] Improve polygonal lines to mostly eliminate overlapping drawing when lines are very thick. As lines are converted to polygons, add the join triangle instead of adding the join triangles after all poly-lines have been created. --- .../GraphicsOpenGLPolylineTriangles.cxx | 168 ++++++++++++------ .../GraphicsOpenGLPolylineTriangles.h | 19 +- 2 files changed, 128 insertions(+), 59 deletions(-) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index d9aa0f430..02cddc059 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -303,10 +303,6 @@ GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); if (numWindowPoints >= 2) { convertLineSegmentsToTriangles(); - - joinTriangles(); - - CaretAssert(m_primitive); } restoreOpenGLState(); @@ -718,7 +714,7 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t m_primitiveByteColor->addVertex(p4, rgbaP34); } else { - std::cout << "Flipped Quad" << std::endl; + if (m_debugFlag) std::cout << "Flipped Quad" << std::endl; m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p3, rgbaP34); @@ -749,7 +745,7 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t } else { - std::cout << "Flipped Quad" << std::endl; + if (m_debugFlag) std::cout << "Flipped Quad" << std::endl; m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p3, rgbaP34); @@ -774,21 +770,33 @@ GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t numVertices - 1 }; - m_polyLineInfo.push_back(PolylineInfo(windowVertexOneIndex, - windowVertexTwoIndex, - triangleOneIndices, - triangleTwoIndices)); + PolylineInfo polyLine(windowVertexOneIndex, + windowVertexTwoIndex, + triangleOneIndices, + triangleTwoIndices); + + if (m_lastPolyLineInfo.m_valid) { + joinTwoPolyLines(m_lastPolyLineInfo, polyLine); + } + + m_lastPolyLineInfo = polyLine; } /** - * Join triangles to create connected line segments - * without cracks where the triangles join together. + * Join two polylines by filling in the gaps where the + * polylines meet. + * + * @param polyOne + * The first polyline. + * @param polyTwo + * The two polyline. */ void -GraphicsOpenGLPolylineTriangles::joinTriangles() +GraphicsOpenGLPolylineTriangles::joinTwoPolyLines(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo) { CaretAssert(m_primitive); - + switch (m_joinType) { case JoinType::BEVEL: break; @@ -799,53 +807,35 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() break; } - const int32_t numPolylines = static_cast(m_polyLineInfo.size()); - const int32_t numPolylinesMinusOne = numPolylines - 1; - - int32_t numPolylinesToConnect = 0; switch (m_lineType) { case LineType::LINES: - numPolylinesToConnect = 0; + return; break; case LineType::LINE_LOOP: - numPolylinesToConnect = numPolylinesMinusOne; //numPolylines; break; case LineType::LINE_STRIP: - numPolylinesToConnect = numPolylinesMinusOne; break; } /* - * Perform joins of connected polylines + * Does triangle "i" connect to triangle "i+1" ? */ - for (int32_t i = 0; i < numPolylinesToConnect; i++) { - CaretAssertVectorIndex(m_polyLineInfo, i); - const PolylineInfo& poly = m_polyLineInfo[i]; - - const int32_t nextPolyIndex = ((i < numPolylinesMinusOne) ? (i + 1) : 0); - CaretAssertVectorIndex(m_polyLineInfo, nextPolyIndex); - const PolylineInfo& nextPoly = m_polyLineInfo[nextPolyIndex]; - - /* - * Does triangle "i" connect to triangle "i+1" ? - */ - if (poly.m_windowVertexTwoIndex == nextPoly.m_windowVertexOneIndex) { - switch (m_joinType) { - case JoinType::BEVEL: - performBevelJoin(poly, - nextPoly); - break; - case JoinType::MITER: - performMiterJoin(poly, - nextPoly); - break; - case JoinType::NONE: - break; - } + if (polyOne.m_windowVertexTwoIndex == polyTwo.m_windowVertexOneIndex) { + switch (m_joinType) { + case JoinType::BEVEL: + performBevelJoin(polyOne, + polyTwo); + break; + case JoinType::MITER: + performMiterJoin(polyOne, + polyTwo); + break; + case JoinType::NONE: + break; } } - addMiterJoinTriangles(); + addJoinTriangles(); } /** @@ -860,7 +850,7 @@ GraphicsOpenGLPolylineTriangles::joinTriangles() */ GraphicsOpenGLPolylineTriangles::TurnDirection GraphicsOpenGLPolylineTriangles::getTurnDirection(const PolylineInfo& polyOne, - const PolylineInfo& polyTwo) const + const PolylineInfo& polyTwo) const { TurnDirection turnDirection = TurnDirection::PARALLEL; @@ -1141,9 +1131,9 @@ GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, */ void GraphicsOpenGLPolylineTriangles::createMiterJoinVertex(const float v1[3], - const float v2[3], - const float miterLength, - float xyzOut[3]) + const float v2[3], + const float miterLength, + float xyzOut[3]) { float n2[3]; MathFunctions::subtractVectors(v2, v1, n2); @@ -1157,10 +1147,75 @@ GraphicsOpenGLPolylineTriangles::createMiterJoinVertex(const float v1[3], } /** - * Add triangles to fill in the gaps at limited miter joins. + * Get the average color from two vertices. + * + * @param primitiveVertexOneIndex + * The first primitive vertex index. + * @param primitiveVertexTwoIndex + * The second primitive vertex index. + * @param rgbaOut + * Output with average RGBA. */ void -GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() +GraphicsOpenGLPolylineTriangles::getAverageColorRGBA(const int32_t primitiveVertexOneIndex, + const int32_t primitiveVertexTwoIndex, + float rgbaOut[4]) const +{ + CaretAssert(m_primitiveFloatColor); + + float rgbaOne[4]; + m_primitiveFloatColor->getVertexFloatRGBA(primitiveVertexOneIndex, rgbaOne); + float rgbaTwo[4]; + m_primitiveFloatColor->getVertexFloatRGBA(primitiveVertexTwoIndex, rgbaTwo); + + rgbaOut[0] = (rgbaOne[0] + rgbaTwo[0]) / 2.0f; + rgbaOut[1] = (rgbaOne[1] + rgbaTwo[1]) / 2.0f; + rgbaOut[2] = (rgbaOne[2] + rgbaTwo[2]) / 2.0f; + rgbaOut[3] = (rgbaOne[3] + rgbaTwo[3]) / 2.0f; +} + +/** + * Get the average color from two vertices. + * + * @param primitiveVertexOneIndex + * The first primitive vertex index. + * @param primitiveVertexTwoIndex + * The second primitive vertex index. + * @param rgbaOut + * Output with average RGBA. + */ +void +GraphicsOpenGLPolylineTriangles::getAverageColorRGBA(const int32_t primitiveVertexOneIndex, + const int32_t primitiveVertexTwoIndex, + uint8_t rgbaOut[4]) const +{ + CaretAssert(m_primitiveByteColor); + + /* + * Since byte colors range [0, 255], adding two bytes could + * cause an overflow of the byte. So average using floats + * and then assign to the byte output. + */ + uint8_t rgbaOneByte[4]; + m_primitiveByteColor->getVertexByteRGBA(primitiveVertexOneIndex, rgbaOneByte); + float rgbaOne[4] = { rgbaOneByte[0], rgbaOneByte[1], rgbaOneByte[2], rgbaOneByte[3] }; + + uint8_t rgbaTwoByte[4]; + m_primitiveByteColor->getVertexByteRGBA(primitiveVertexTwoIndex, rgbaTwoByte); + float rgbaTwo[4] = { rgbaTwoByte[0], rgbaTwoByte[1], rgbaTwoByte[2], rgbaTwoByte[3] }; + + rgbaOut[0] = static_cast((rgbaOne[0] + rgbaTwo[0]) / 2.0f); + rgbaOut[1] = static_cast((rgbaOne[1] + rgbaTwo[1]) / 2.0f); + rgbaOut[2] = static_cast((rgbaOne[2] + rgbaTwo[2]) / 2.0f); + rgbaOut[3] = static_cast((rgbaOne[3] + rgbaTwo[3]) / 2.0f); +} + +/** + * Add triangles creating by joins to fill gaps + * at the junctions of the line segments + */ +void +GraphicsOpenGLPolylineTriangles::addJoinTriangles() { for (const auto tj : m_triangleJoins) { CaretAssertVectorIndex(m_vertexWindowXYZ, tj.m_windowVertexIndex * 3 + 2); @@ -1191,7 +1246,7 @@ GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() case GraphicsPrimitive::ColorType::FLOAT_RGBA: { float rgba[4]; - m_primitiveFloatColor->getVertexFloatRGBA(tj.m_primitiveVertexOneIndex, rgba); + getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); m_primitiveFloatColor->addVertex(v1, rgba); m_primitiveFloatColor->addVertex(tv2, rgba); m_primitiveFloatColor->addVertex(tv3, rgba); @@ -1200,7 +1255,7 @@ GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: { uint8_t rgba[4]; - m_primitiveByteColor->getVertexByteRGBA(tj.m_primitiveVertexOneIndex, rgba); + getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); m_primitiveByteColor->addVertex(v1, rgba); m_primitiveByteColor->addVertex(tv2, rgba); m_primitiveByteColor->addVertex(tv3, rgba); @@ -1208,6 +1263,8 @@ GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() break; } } + + m_triangleJoins.clear(); } /** @@ -1219,7 +1276,6 @@ GraphicsOpenGLPolylineTriangles::addMiterJoinTriangles() void GraphicsOpenGLPolylineTriangles::convertLineSegmentsToTriangles() { - const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); /* diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.h b/src/Graphics/GraphicsOpenGLPolylineTriangles.h index ba1bd2cf2..6916cd580 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.h +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.h @@ -104,6 +104,8 @@ namespace caret { */ class PolylineInfo { public: + PolylineInfo() { } + PolylineInfo(const int32_t windowVertexOneIndex, const int32_t windowVertexTwoIndex, const int32_t triangleOnePrimitiveIndices[3], @@ -116,12 +118,14 @@ namespace caret { m_triangleTwoPrimitiveIndices[0] = triangleTwoPrimitiveIndices[0]; m_triangleTwoPrimitiveIndices[1] = triangleTwoPrimitiveIndices[1]; m_triangleTwoPrimitiveIndices[2] = triangleTwoPrimitiveIndices[2]; + m_valid = true; } int32_t m_windowVertexOneIndex; int32_t m_windowVertexTwoIndex; int32_t m_triangleOnePrimitiveIndices[3]; int32_t m_triangleTwoPrimitiveIndices[3]; + bool m_valid = false; }; /** @@ -181,9 +185,10 @@ namespace caret { void performMiterJoin(const PolylineInfo& polyOne, const PolylineInfo& polyTwo); - void joinTriangles(); + void joinTwoPolyLines(const PolylineInfo& polyOne, + const PolylineInfo& polyTwo); - void addMiterJoinTriangles(); + void addJoinTriangles(); void createMiterJoinVertex(const float v1[3], const float v2[3], @@ -193,6 +198,14 @@ namespace caret { TurnDirection getTurnDirection(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) const; + void getAverageColorRGBA(const int32_t primitiveVertexOneIndex, + const int32_t primitiveVertexTwoIndex, + float rgbaOut[4]) const; + + void getAverageColorRGBA(const int32_t primitiveVertexOneIndex, + const int32_t primitiveVertexTwoIndex, + uint8_t rgbaOut[4]) const; + const std::vector& m_inputXYZ; const std::vector& m_inputFloatRGBA; @@ -233,7 +246,7 @@ namespace caret { std::unique_ptr m_primitiveByteColor; - std::vector m_polyLineInfo; + PolylineInfo m_lastPolyLineInfo; std::vector m_triangleJoins; -- GitLab From 5fb0afde152cb47ff3fb2445671c4ef7665c8721 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 11 Dec 2017 14:56:32 -0600 Subject: [PATCH 543/755] Restoring a line-series history item (line chart) incorrectly set the primitive type to an OpenGL line type instead of a polygonal-line-type. As a result, there were gaps at the junctions of the connected line segments. --- src/Charting/ChartTwoLineSeriesHistory.cxx | 19 +++++++++++++++---- src/Charting/ChartTwoLineSeriesHistory.h | 8 ++++++-- src/Files/ChartableTwoFileLineSeriesChart.cxx | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Charting/ChartTwoLineSeriesHistory.cxx b/src/Charting/ChartTwoLineSeriesHistory.cxx index c7021b528..3ad50ee9c 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.cxx +++ b/src/Charting/ChartTwoLineSeriesHistory.cxx @@ -44,9 +44,10 @@ using namespace caret; /** * Constructor. */ -ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory() +ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory(const GraphicsPrimitive::PrimitiveType defaultGraphicsPrimitiveType) : CaretObjectTracksModification(), -SceneableInterface() +SceneableInterface(), +m_defaultGraphicsPrimitiveType(defaultGraphicsPrimitiveType) { initializeInstance(); } @@ -67,7 +68,8 @@ ChartTwoLineSeriesHistory::~ChartTwoLineSeriesHistory() */ ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj) : CaretObjectTracksModification(obj), -SceneableInterface(obj) +SceneableInterface(obj), +m_defaultGraphicsPrimitiveType(obj.m_defaultGraphicsPrimitiveType) { initializeInstance(); this->copyHelperChartTwoLineSeriesHistory(obj); @@ -96,6 +98,15 @@ ChartTwoLineSeriesHistory::isLoadingEnabled() const return m_loadingEnabled; } +/** + * @return Default type of graphics primitive for this line-series history. + */ +GraphicsPrimitive::PrimitiveType +ChartTwoLineSeriesHistory::getDefaultGraphicsPrimitiveType() const +{ + return m_defaultGraphicsPrimitiveType; +} + /** * Set loading line series charts enabled * @@ -589,7 +600,7 @@ ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttribut ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, CaretUnitsTypeEnum::NONE, CaretUnitsTypeEnum::NONE, - GraphicsPrimitive::PrimitiveType::OPENGL_LINES); + m_defaultGraphicsPrimitiveType); historyItem->restoreFromScene(sceneAttributes, historyClass); diff --git a/src/Charting/ChartTwoLineSeriesHistory.h b/src/Charting/ChartTwoLineSeriesHistory.h index 4ea54c062..24231f400 100644 --- a/src/Charting/ChartTwoLineSeriesHistory.h +++ b/src/Charting/ChartTwoLineSeriesHistory.h @@ -26,7 +26,7 @@ #include "BrainConstants.h" #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" - +#include "GraphicsPrimitive.h" #include "SceneableInterface.h" @@ -38,7 +38,7 @@ namespace caret { class ChartTwoLineSeriesHistory : public CaretObjectTracksModification, public SceneableInterface { public: - ChartTwoLineSeriesHistory(); + ChartTwoLineSeriesHistory(const GraphicsPrimitive::PrimitiveType defaultGraphicsPrimitiveType); virtual ~ChartTwoLineSeriesHistory(); @@ -46,6 +46,8 @@ namespace caret { ChartTwoLineSeriesHistory& operator=(const ChartTwoLineSeriesHistory& obj); + GraphicsPrimitive::PrimitiveType getDefaultGraphicsPrimitiveType() const; + bool isLoadingEnabled() const; void setLoadingEnabled(const bool enabled); @@ -116,6 +118,8 @@ namespace caret { void validateDefaultColor(); + const GraphicsPrimitive::PrimitiveType m_defaultGraphicsPrimitiveType; + bool m_loadingEnabled = false; SceneClassAssistant* m_sceneAssistant = NULL; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 77cc70936..c142cd7d0 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -129,7 +129,7 @@ m_lineSeriesContentType(lineSeriesContentType) } break; } - m_lineChartHistory = std::unique_ptr(new ChartTwoLineSeriesHistory()); + m_lineChartHistory = std::unique_ptr(new ChartTwoLineSeriesHistory(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); m_sceneAssistant->add("m_lineChartHistory", "ChartTwoLineSeriesHistory", m_lineChartHistory.get()); @@ -266,7 +266,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, xUnits, CaretUnitsTypeEnum::NONE, - GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN); + m_lineChartHistory->getDefaultGraphicsPrimitiveType()); cartesianData->setMapFileDataSelector(mapFileDataSelector); float x = 0.0f; -- GitLab From 944286be2c582916b1eb4b2ee1991d9ba1a2a9eb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 12 Dec 2017 15:20:21 -0600 Subject: [PATCH 544/755] Fixed new Off Screen Image Capture when used for Scene Preview image. Image size was zero causing the failure. --- src/GuiQt/BrainOpenGLWidget.cxx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 4cb9367f2..0938f87da 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -459,6 +459,8 @@ QImage BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, const int32_t imageHeight) { + makeCurrent(); + QImage image; OffScreenOpenGLRenderer offscreen(this, @@ -1659,8 +1661,8 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) const int captureOffsetY = imageCaptureEvent->getCaptureOffsetY(); const int captureWidth = imageCaptureEvent->getCaptureWidth(); const int captureHeight = imageCaptureEvent->getCaptureHeight(); - const int outputImageWidth = imageCaptureEvent->getOutputWidth(); - const int outputImageHeight = imageCaptureEvent->getOutputHeight(); + int outputImageWidth = imageCaptureEvent->getOutputWidth(); + int outputImageHeight = imageCaptureEvent->getOutputHeight(); /* * Force immediate mode since problems with display lists @@ -1743,8 +1745,21 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) } break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER: + { + /* + * If width/height invalid, capture in size of graphics region + * (Qt's renderPixmap() and grabFrameBuffer() methods accept + * width/height of zero and interpret that as size of graphics + * region (widget) + */ + if ((outputImageWidth < 1) + || (outputImageHeight < 1)) { + outputImageWidth = width(); + outputImageHeight = height(); + } image = performOffScreenImageCapture(outputImageWidth, outputImageHeight); + } break; } -- GitLab From fdc8ef14e8fda12877c5a56badbd2faa043aa393 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Dec 2017 09:26:19 -0600 Subject: [PATCH 545/755] Fixed image capture for grab frame buffer with aspect ratio locked and also cleaned up some code. --- src/GuiQt/BrainBrowserWindow.cxx | 68 ++++++++++++++-------------- src/GuiQt/BrainOpenGLWidget.cxx | 77 +++++++++++++++----------------- src/GuiQt/EventImageCapture.cxx | 3 +- src/GuiQt/EventImageCapture.h | 4 +- src/GuiQt/ImageCaptureDialog.cxx | 59 ------------------------ src/GuiQt/ImageCaptureDialog.h | 2 - 6 files changed, 74 insertions(+), 139 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 6948c90f3..037df6699 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -518,43 +518,45 @@ BrainBrowserWindow::setGraphicsWidgetFixedSize(const int32_t width, /** * Get the graphics widget size. * - * @param xOut - * X-coord of graphics region (may be non-zero when lock aspect applied) - * @param yOut - * Y-coord of graphics region (may be non-zero when lock aspect applied) - * @param widthOut - * Width of the graphics widget. - * @param heightOut - * Height of the graphics widget. - * @param graphicsWidthOut - * True width of graphics region as if no aspect ratio was applied. - * @param graphicsHeightOut - * True height of graphics region as if no aspect ratio was applied. + * @param viewportXOut + * X-coord of viewport in graphics region (may be non-zero when lock aspect applied) + * @param viewportYOut + * Y-coord of viewport in graphics region (may be non-zero when lock aspect applied) + * @param viewportWidthOut + * Width of the viewport into which graphics are drawn (may be less than + * graphicsWidthOut when lock aspect is applied) + * @param viewportHeightOut + * Height of the viewport into which graphics are drawn (may be less than + * graphicsHeightOut when lock aspect is applied) + * @param openGLWidgetWidthOut + * True width of the OpenGL Widget. + * @param openGLWidgetHeightOut + * True height of the OpenGL Widget. * @param applyLockedAspectRatiosFlag * True if locked tab or window aspect ratio should be applied for - * graphics region size. + * viewport but only if lock aspect is enabled by the user. */ void -BrainBrowserWindow::getGraphicsWidgetSize(int32_t& xOut, - int32_t& yOut, - int32_t& widthOut, - int32_t& heightOut, - int32_t& graphicsWidthOut, - int32_t& graphicsHeightOut, +BrainBrowserWindow::getGraphicsWidgetSize(int32_t& viewportXOut, + int32_t& viewportYOut, + int32_t& viewportWidthOut, + int32_t& viewportHeightOut, + int32_t& openGLWidgetWidthOut, + int32_t& openGLWidgetHeightOut, const bool applyLockedAspectRatiosFlag) const { - xOut = 0; - yOut = 0; - graphicsWidthOut = m_openGLWidget->width(); - graphicsHeightOut = m_openGLWidget->height(); - widthOut = m_openGLWidget->width(); - heightOut = m_openGLWidget->height(); + viewportXOut = 0; + viewportYOut = 0; + openGLWidgetWidthOut = m_openGLWidget->width(); + openGLWidgetHeightOut = m_openGLWidget->height(); + viewportWidthOut = m_openGLWidget->width(); + viewportHeightOut = m_openGLWidget->height(); int aspectViewport[4] = { 0, 0, - widthOut, - heightOut + openGLWidgetWidthOut, + openGLWidgetHeightOut }; if (isTileTabsSelected()) { @@ -589,12 +591,12 @@ BrainBrowserWindow::getGraphicsWidgetSize(int32_t& xOut, if ((windowWidth > 0) && (windowHeight > 0)) { - if ((windowWidth != widthOut) - || (windowHeight != heightOut)) { - xOut = windowViewport[0]; - yOut = windowViewport[1]; - widthOut = windowWidth; - heightOut = windowHeight; + if ((windowWidth != viewportWidthOut) + || (windowHeight != viewportHeightOut)) { + viewportXOut = windowViewport[0]; + viewportYOut = windowViewport[1]; + viewportWidthOut = windowWidth; + viewportHeightOut = windowHeight; } } } diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 0938f87da..b82989edf 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1657,13 +1657,31 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) * Note that a size of zero indicates capture graphics in its * current size. */ - const int captureOffsetX = imageCaptureEvent->getCaptureOffsetX(); - const int captureOffsetY = imageCaptureEvent->getCaptureOffsetY(); - const int captureWidth = imageCaptureEvent->getCaptureWidth(); - const int captureHeight = imageCaptureEvent->getCaptureHeight(); + int captureOffsetX = imageCaptureEvent->getCaptureOffsetX(); + int captureOffsetY = imageCaptureEvent->getCaptureOffsetY(); + int captureWidth = imageCaptureEvent->getCaptureWidth(); + int captureHeight = imageCaptureEvent->getCaptureHeight(); int outputImageWidth = imageCaptureEvent->getOutputWidth(); int outputImageHeight = imageCaptureEvent->getOutputHeight(); + if ((outputImageWidth <= 0) + || (outputImageHeight <= 0)) { + BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); + + if (browserWindow != NULL) { + int32_t widgetWidth(0), widgetHeight(0); + browserWindow->getGraphicsWidgetSize(captureOffsetX, + captureOffsetY, + captureWidth, + captureHeight, + widgetWidth, + widgetHeight, + true); // true => apply lock aspect ratio + outputImageWidth = captureWidth; + outputImageHeight = captureHeight; + } + } + /* * Force immediate mode since problems with display lists * in image capture. @@ -1690,36 +1708,22 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) #else image = grabFrameBuffer(); #endif - - if ((captureOffsetX > 0) - || (captureOffsetY > 0)) { - if ((captureWidth > 0) - && (captureHeight > 0)) { - image = image.copy(captureOffsetX, - captureOffsetY, - captureWidth, - captureHeight); - } + if ((captureWidth > 0) + && (captureHeight > 0)) { + image = image.copy(captureOffsetX, + captureOffsetY, + captureWidth, + captureHeight); } - /* - * If image was captured successfully and the caller has - * requested that the image be a specific size, scale - * the image to the requested size. - */ - if ((image.width() > 0) - && (image.height() > 0)) { - if ((outputImageWidth > 0) - && (outputImageHeight > 0)) { - if ((image.width() != outputImageWidth) - || (image.height() != outputImageHeight)) { - image = image.scaled(outputImageWidth, - outputImageHeight, - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation); - } - } + if ((outputImageWidth != image.width()) + || (outputImageHeight != image.height())) { + image = image.scaled(outputImageWidth, + outputImageHeight, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); } + } break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP: @@ -1746,17 +1750,6 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER: { - /* - * If width/height invalid, capture in size of graphics region - * (Qt's renderPixmap() and grabFrameBuffer() methods accept - * width/height of zero and interpret that as size of graphics - * region (widget) - */ - if ((outputImageWidth < 1) - || (outputImageHeight < 1)) { - outputImageWidth = width(); - outputImageHeight = height(); - } image = performOffScreenImageCapture(outputImageWidth, outputImageHeight); } diff --git a/src/GuiQt/EventImageCapture.cxx b/src/GuiQt/EventImageCapture.cxx index 1cc519a23..6ced0e141 100644 --- a/src/GuiQt/EventImageCapture.cxx +++ b/src/GuiQt/EventImageCapture.cxx @@ -37,7 +37,8 @@ using namespace caret; */ /** - * Constructor for capturing image of window without any resizing. + * Constructor for capturing image of window with the image + * dimensions identical to the dimensions of the window. * * @param browserWindowIndex * The browser window index. diff --git a/src/GuiQt/EventImageCapture.h b/src/GuiQt/EventImageCapture.h index fd0a842d3..005be49a4 100644 --- a/src/GuiQt/EventImageCapture.h +++ b/src/GuiQt/EventImageCapture.h @@ -30,6 +30,8 @@ namespace caret { class EventImageCapture : public Event { public: + EventImageCapture(const int32_t browserWindowIndex); + EventImageCapture(const int32_t browserWindowIndex, const int32_t captureOffsetX, const int32_t captureOffsetY, @@ -38,8 +40,6 @@ namespace caret { const int32_t outputWidth, const int32_t outputHeight); - EventImageCapture(const int32_t browserWindowIndex); - virtual ~EventImageCapture(); int32_t getBrowserWindowIndex() const; diff --git a/src/GuiQt/ImageCaptureDialog.cxx b/src/GuiQt/ImageCaptureDialog.cxx index 722ce44d2..ac3a43aaf 100644 --- a/src/GuiQt/ImageCaptureDialog.cxx +++ b/src/GuiQt/ImageCaptureDialog.cxx @@ -134,16 +134,6 @@ ImageCaptureDialog::ImageCaptureDialog(BrainBrowserWindow* parent) EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); updateBrowserWindowWidthAndHeightLabel(); - /* - * Initialize the custom image size - */ -// m_imageDimensionsModel->setPixelWidthAndHeight(512, -// 512); -// updateDialogWithImageDimensionsModel(); - -// m_scaleProportionallyCheckBox->setChecked(true); -// scaleProportionallyCheckBoxClicked(m_scaleProportionallyCheckBox->isChecked()); - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -186,8 +176,6 @@ ImageCaptureDialog::createImageSourceSection() QGroupBox* groupBox = new QGroupBox("Source"); QGridLayout* gridLayout = new QGridLayout(groupBox); -// gridLayout->setColumnStretch(0, 0); -// gridLayout->setColumnStretch(1, 0); gridLayout->addWidget(windowLabel, 0, 0); gridLayout->addWidget(m_windowSelectionSpinBox, 0, 1, Qt::AlignLeft); gridLayout->addWidget(m_windowCropToLockAspectRegionCheckBox, 1, 0, 1, 2, Qt::AlignLeft); @@ -391,9 +379,6 @@ ImageCaptureDialog::createImageDimensionsSection() layout->addWidget(m_customDimensionsWidget, 0, Qt::AlignLeft); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(imageBytesWidget); -// -// m_imageSizeWindowRadioButton->setChecked(true); -// sizeRadioButtonClicked(sizeButtonGroup->checkedButton()); return groupBox; } @@ -416,8 +401,6 @@ ImageCaptureDialog::sizeRadioButtonClicked(QAbstractButton* /*button*/) } updateDimensionsSection(); -// updateDialogWithImageDimensionsModel(); -// updateImageNumberOfBytesLabel(); } /** @@ -583,32 +566,6 @@ ImageCaptureDialog::updateDestinationSection() m_imageFileNameLineEdit->setText(imageCaptureSettings->getImageFileName()); } - -///** -// * Update the dialog with data from the image dimensions model. -// */ -//void -//ImageCaptureDialog::updateDialogWithImageDimensionsModel() -//{ -// ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); -// const ImageCaptureDimensionsModeEnum::Enum captureMode = imageCaptureSettings->getImageCaptureDimensionsMode(); -// switch (captureMode) { -// case ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM: -// m_imageSizeCustomRadioButton->setChecked(true); -// m_customDimensionsWidget->setEnabled(true); -// break; -// case ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE: -// m_imageSizeWindowRadioButton->setChecked(true); -// m_customDimensionsWidget->setEnabled(false); -// break; -// } -// -// m_scaleProportionallyCheckBox->setChecked(imageCaptureSettings->isScaleProportionately()); -// -// -// updateImageNumberOfBytesLabel(); -//} - /** * Update the image number of bytes label. */ @@ -981,22 +938,6 @@ ImageCaptureDialog::getSelectedWindowWidthAndHeight(int32_t& widthOut, graphicsWidth, graphicsHeight, aspectRatioOut); - -// const int selectedBrowserWindowIndex = m_windowSelectionSpinBox->value() - 1; -// BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(selectedBrowserWindowIndex); -// -// if (browserWindow != NULL) { -// browserWindow->getGraphicsWidgetSize(widthOut, -// heightOut, -// m_windowCropToLockAspectRegionCheckBox->isChecked()); -// if ((widthOut > 0) -// && (heightOut > 0)) { -// aspectRatioOut = (static_cast(heightOut) -// / static_cast(widthOut)); -// return true; -// } -// } -// return false; } diff --git a/src/GuiQt/ImageCaptureDialog.h b/src/GuiQt/ImageCaptureDialog.h index c905011d6..66716c08a 100644 --- a/src/GuiQt/ImageCaptureDialog.h +++ b/src/GuiQt/ImageCaptureDialog.h @@ -117,8 +117,6 @@ namespace caret { int32_t& heightOut, float& aspectRatioOut) const; - //void updateDialogWithImageDimensionsModel(); - void updateImageNumberOfBytesLabel(); QCheckBox* m_saveImageToFileCheckBox; -- GitLab From 95f92f77606cf087a9bb21c830c7267f9fe4d79f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Dec 2017 11:00:03 -0600 Subject: [PATCH 546/755] Do not attempt to draw a primitive if it contains zero vertices to fix "Primitive not valid" error message. This may occur when trying to draw a border for a non-matching structure. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 6cc0f7079..2fc6c650a 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -464,6 +464,13 @@ GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) { CaretAssert(primitive); + if (primitive->getNumberOfVertices() <= 0) { + return; + } + if ( ! primitive->isValid()) { + CaretLogWarning("Attempting to draw invalid Graphics Primitive"); + } + GraphicsPrimitive* primitiveToDraw = primitive; /* Conversion to window space creates a new primitive that must be deleted */ -- GitLab From aea466e1b91a7631f77f67f26ad4e287c90d16a8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Dec 2017 11:40:14 -0600 Subject: [PATCH 547/755] When colorbar display mode is Percentile, do not override numeric formatting. Until now, the numeric formatting was set overridden with decimal mode which resulted in it using the Dec/Sci Decimals setting even though it is disabled in Auto formatting mode. This fixes a problem with percentile having incorrect number of digits right of decimal. --- src/Palette/PaletteColorMapping.cxx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index abc0916bb..89c55a528 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -1896,11 +1896,6 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic const float percentile = statistics->getNegativeValuePercentile(*iter); *iter = percentile; } - - /* - * Decimal mode integers for percentile - */ - numericFormatModeForTextFormatting = NumericFormatModeEnum::DECIMAL; break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: CaretAssertMessage(0, "Should never get here. Sign only handled above"); -- GitLab From 9c710eaf58357d0ca3b462b71639957e816ba4a1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 13 Dec 2017 12:28:28 -0600 Subject: [PATCH 548/755] In Scene Preview Dialog, the image was cropped for some scenes. Always enabling scrollbars for the dialog allows display of entire image without any cropping. --- src/GuiQt/ScenePreviewDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/ScenePreviewDialog.cxx b/src/GuiQt/ScenePreviewDialog.cxx index 7353ae9d1..2090196ad 100644 --- a/src/GuiQt/ScenePreviewDialog.cxx +++ b/src/GuiQt/ScenePreviewDialog.cxx @@ -121,7 +121,7 @@ ScenePreviewDialog::ScenePreviewDialog(const Scene* scene, layout->addWidget(descriptionLabel); } - setCentralWidget(widget, SCROLL_AREA_AS_NEEDED); + setCentralWidget(widget, SCROLL_AREA_ALWAYS); } /** -- GitLab From 2ddbc80cd291aa3bf970df7d43788f7b78cfcaf1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Dec 2017 10:28:58 -0600 Subject: [PATCH 549/755] Thickness of volume surface outline is now in millimeters. If an older scene is loaded that contains volume surface outline thickness in pixels, the pixel size is converted to millimeters using the viewport pixel and millimeter dimensions the first time the volume surface outline is drawn. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 18 +++++++- src/Brain/VolumeSurfaceOutlineModel.cxx | 30 +++++++++++++ src/Brain/VolumeSurfaceOutlineModel.h | 9 +++- src/Brain/VolumeSurfaceOutlineSetModel.cxx | 12 +---- src/Brain/VolumeSurfaceOutlineSetModel.h | 1 - src/Graphics/GraphicsUtilitiesOpenGL.cxx | 44 +++++++++++++++++++ src/Graphics/GraphicsUtilitiesOpenGL.h | 2 + .../VolumeSurfaceOutlineViewController.cxx | 9 +++- 8 files changed, 109 insertions(+), 16 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 4fbec4821..0ffed471d 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3577,7 +3577,21 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { - const float thickness = outline->getThicknessPixelsObsolete(); + float thicknessMillimeters = outline->getThicknessMillimeters(); + const float thicknessPixels = outline->getThicknessPixelsObsolete(); + + /* + * Thickness was changed from pixels to millimeters in December 2017 + * If thickness millimeters is negative, it was not present in an old + * scene so convert pixels to millimeters using viewports dimensions + */ + if (thicknessMillimeters < 0.0f) { + thicknessMillimeters = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(thicknessPixels); + if (thicknessMillimeters > 0.0f) { + std::cout << "Converted pixel thickness=" << thicknessPixels << " to millimeters=" << thicknessMillimeters << std::endl; + outline->setThicknessMillimeters(thicknessMillimeters); + } + } CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; @@ -3602,7 +3616,7 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, colorSourceBrowserTabIndex); } - const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(thickness); + const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(thicknessMillimeters); SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, diff --git a/src/Brain/VolumeSurfaceOutlineModel.cxx b/src/Brain/VolumeSurfaceOutlineModel.cxx index 919161f02..288e886a9 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineModel.cxx @@ -62,6 +62,17 @@ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() m_sceneAssistant->add("m_surfaceSelectionModel", "SurfaceSelectionModel", m_surfaceSelectionModel); m_sceneAssistant->add("m_colorOrTabModel", "VolumeSurfaceOutlineColorOrTabModel", m_colorOrTabModel); + /* + * Millimeter thickness was added in December 2017. + * So, we set the millimeter thickness to -1.0f so that when an older + * scene is restored, the value will be -1.0f. The code that draws + * the volume surface outline see this negative value and convert + * the old pixel thickness to this new millimeter thickness. + * After adding to the scene assistant, default the millimeter thickness. + */ + m_thicknessMillimeters = -1.0f; + m_sceneAssistant->add("m_thicknessMillimeters", &m_thicknessMillimeters); + m_thicknessMillimeters = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS; } /** @@ -85,6 +96,7 @@ VolumeSurfaceOutlineModel::copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineMod { m_displayed = modelToCopy->m_displayed; m_thicknessPixelsObsolete = modelToCopy->m_thicknessPixelsObsolete; + m_thicknessMillimeters = modelToCopy->m_thicknessMillimeters; m_surfaceSelectionModel->setSurface(modelToCopy->getSurface()); VolumeSurfaceOutlineColorOrTabModel* colorTabToCopy = modelToCopy->getColorOrTabModel(); @@ -121,6 +133,24 @@ VolumeSurfaceOutlineModel::setDisplayed(const bool displayed) m_displayed = displayed; } +/** + * @return Thickness for drawing surface outline + */ +float +VolumeSurfaceOutlineModel::getThicknessMillimeters() const +{ + return m_thicknessMillimeters; +} + +/** + * Set the thickness for drawing surface outline + */ +void +VolumeSurfaceOutlineModel::setThicknessMillimeters(const float thickness) +{ + m_thicknessMillimeters = thickness; +} + /** * @return Thickness for drawing surface (OBSOLETE) */ diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index 873486f8a..cf2b8a4a8 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -45,6 +45,10 @@ namespace caret { void setDisplayed(const bool displayed); + float getThicknessMillimeters() const; + + void setThicknessMillimeters(const float thickness); + float getThicknessPixelsObsolete() const; void setThicknessPixelsObsolete(const float thickness); @@ -66,6 +70,7 @@ namespace caret { const SceneClass* sceneClass); static const int32_t DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; + static const int32_t DEFAULT_LINE_THICKNESS_MILLIMETERS; private: VolumeSurfaceOutlineModel(const VolumeSurfaceOutlineModel&); @@ -80,6 +85,8 @@ namespace caret { float m_thicknessPixelsObsolete; + float m_thicknessMillimeters; + SurfaceSelectionModel* m_surfaceSelectionModel; VolumeSurfaceOutlineColorOrTabModel* m_colorOrTabModel; @@ -89,7 +96,7 @@ namespace caret { #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; - + const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 0.5; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace diff --git a/src/Brain/VolumeSurfaceOutlineSetModel.cxx b/src/Brain/VolumeSurfaceOutlineSetModel.cxx index ac03076ef..00718ec8c 100644 --- a/src/Brain/VolumeSurfaceOutlineSetModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineSetModel.cxx @@ -239,34 +239,28 @@ VolumeSurfaceOutlineSetModel::selectSurfacesAfterSpecFileLoaded(Brain* brain, int nextOutlineIndex = 0; addSurfaceOutline(leftMidThickSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, leftTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(rightMidThickSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, rightTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(leftWhiteSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(rightWhiteSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(leftPialSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::BLUE, nextOutlineIndex); addSurfaceOutline(rightPialSurface, - VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE, -1, CaretColorEnum::BLUE, nextOutlineIndex); @@ -278,8 +272,6 @@ VolumeSurfaceOutlineSetModel::selectSurfacesAfterSpecFileLoaded(Brain* brain, * * @param surface * Surface that is added. If NULL, no action is taken. - * @param thickness - * Thickness for surface outline. * @param browserTabIndex * If greater than or equal to zero, the color source * is set to this tab index. @@ -294,7 +286,6 @@ VolumeSurfaceOutlineSetModel::selectSurfacesAfterSpecFileLoaded(Brain* brain, */ void VolumeSurfaceOutlineSetModel::addSurfaceOutline(Surface* surface, - const float thickness, const int32_t browserTabIndex, const CaretColorEnum::Enum color, int32_t& outlineIndex) @@ -304,7 +295,8 @@ VolumeSurfaceOutlineSetModel::addSurfaceOutline(Surface* surface, if (outlineIndex < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES) { VolumeSurfaceOutlineModel* vsos = m_outlineModels[outlineIndex]; vsos->getSurfaceSelectionModel()->setSurface(surface); - vsos->setThicknessPixelsObsolete(thickness); + vsos->setThicknessPixelsObsolete(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE); + vsos->setThicknessMillimeters(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS); if (browserTabIndex >= 0) { vsos->getColorOrTabModel()->setBrowserTabIndex(browserTabIndex); } diff --git a/src/Brain/VolumeSurfaceOutlineSetModel.h b/src/Brain/VolumeSurfaceOutlineSetModel.h index 3956eebd6..ccffcea2f 100644 --- a/src/Brain/VolumeSurfaceOutlineSetModel.h +++ b/src/Brain/VolumeSurfaceOutlineSetModel.h @@ -65,7 +65,6 @@ namespace caret { VolumeSurfaceOutlineSetModel& operator=(const VolumeSurfaceOutlineSetModel&); void addSurfaceOutline(Surface* surface, - const float thickness, const int32_t browserTabIndex, const CaretColorEnum::Enum color, int32_t& outlineIndex); diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index 058f7549d..8cbaba87a 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -97,3 +97,47 @@ GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(const fl return percentageOfViewportHeight ; } + +/** + * Convert pixels to millimeters. + * The current transformations must be for drawing in millimeters. + * + * @param pixels + * The pixels size + * @return + * Millimeters value. + */ +float +GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(const float pixels) +{ + float mm = 1.0f; + + EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); + EventManager::get()->sendEvent(xform.getPointer()); + if (xform.isValid()) { + const std::array viewport = xform.getViewport(); + + const float windowZ = 0.0f; + float bottomWindowXYZ[3] = { viewport[0], viewport[1], windowZ }; + float topWindowXYZ[3] = { viewport[0], viewport[1] + viewport[3], windowZ }; + + float bottomModelXYZ[3]; + float topModelXYZ[3]; + + xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); + xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); + + const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, + topModelXYZ); + const float rangePixels = viewport[3]; + if ((rangePixels > 0) + && (rangeMillimeters > 0)) { + const float ratio = rangeMillimeters / rangePixels; + mm = pixels * ratio; + } + } + + return mm; +} + + diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h index c3a11b2db..37d16654e 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.h +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -35,6 +35,8 @@ namespace caret { static float convertMillimetersToPercentageOfViewportHeight(const float millimeters); + static float convertPixelsToMillimeters(const float pixels); + private: GraphicsUtilitiesOpenGL(); diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index a221bc629..6fadc0c8b 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -181,7 +181,7 @@ void VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged(double value) { if (this->outlineModel != NULL) { - this->outlineModel->setThicknessPixelsObsolete(value); + this->outlineModel->setThicknessMillimeters(value); } this->updateGraphics(); } @@ -204,7 +204,12 @@ VolumeSurfaceOutlineViewController::updateViewController(VolumeSurfaceOutlineMod this->enabledCheckBox->setCheckState(state); this->thicknessSpinBox->blockSignals(true); - this->thicknessSpinBox->setValue(outlineModel->getThicknessPixelsObsolete()); + float thickness = outlineModel->getThicknessMillimeters(); + if (thickness < 0.0f) { + /* old scenes will have negative for mm thickness */ + thickness = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS; + } + this->thicknessSpinBox->setValue(thickness); this->thicknessSpinBox->blockSignals(false); this->surfaceSelectionViewController->updateControl(outlineModel->getSurfaceSelectionModel()); //this->surfaceSelectionViewController->setSurface(outlineModel->getSurface()); -- GitLab From 487d8a4e7809b201bc3b7483e3f87a5d9aa44fb8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 14 Dec 2017 11:30:24 -0600 Subject: [PATCH 550/755] After pulling latest source, still having issues due to previous capitalization issue with OffScreenOpenGLRenderer h/cxx. Hopefully now resolved. --- src/GuiQt/OffScreenOpenGLRenderer.h | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/GuiQt/OffScreenOpenGLRenderer.h diff --git a/src/GuiQt/OffScreenOpenGLRenderer.h b/src/GuiQt/OffScreenOpenGLRenderer.h new file mode 100644 index 000000000..2a4441ac7 --- /dev/null +++ b/src/GuiQt/OffScreenOpenGLRenderer.h @@ -0,0 +1,85 @@ +#ifndef __OFF_SCREEN_OPEN_G_L_RENDERER_H__ +#define __OFF_SCREEN_OPEN_G_L_RENDERER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QGLWidget; +class QOpenGLFramebufferObject; +class QOffscreenSurface; +class QOpenGLContext; +class QOpenGLWidget; +class QSurfaceFormat; +class QWidget; + +namespace caret { + + class OffScreenOpenGLRenderer : public QObject { + + Q_OBJECT + + public: +#ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET + OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, +#else + OffScreenOpenGLRenderer(QGLWidget* openglWidget, +#endif + const int32_t width, + const int32_t height); + + virtual ~OffScreenOpenGLRenderer(); + + bool isError() const; + + QString getErrorMessage() const; + + QImage getImage(); + + // ADD_NEW_METHODS_HERE + + private: + OffScreenOpenGLRenderer(const OffScreenOpenGLRenderer&); + + OffScreenOpenGLRenderer& operator=(const OffScreenOpenGLRenderer&); + + std::unique_ptr m_offScreenSurface; + + std::unique_ptr m_frameBuffer; + + QOpenGLContext* m_openglContext; + + QString m_errorMessage; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + // +#endif // __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ + +} // namespace +#endif //__OFF_SCREEN_OPEN_G_L_RENDERER_H__ -- GitLab From b41ad09afea070a08d132f0e531bbb805fc3bba4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 18 Dec 2017 10:25:36 -0600 Subject: [PATCH 551/755] Multisampling was recently enable in OpenGL for anti-aliasing of lines and polygons. Multisampling is now disabled during selection (identification) modes to fix surface vertex identification. Identification is performed by drawing each vertex with its identification in an RGB color and multisampling will alter the colors which prevents proper selection. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 194c2c35e..fa6792dbd 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -964,6 +964,18 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, this->mode = mode; + glPushAttrib(GL_MULTISAMPLE_BIT); + switch (this->mode) { + case MODE_DRAWING: + break; + case MODE_IDENTIFICATION: + glDisable(GL_MULTISAMPLE); + break; + case MODE_PROJECTION: + glDisable(GL_MULTISAMPLE); + break; + } + if (this->browserTabContent != NULL) { m_clippingPlaneGroup = const_cast(this->browserTabContent->getClippingPlaneGroup()); CaretAssert(m_clippingPlaneGroup); @@ -1019,6 +1031,8 @@ BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, drawBackgroundImage(viewportContent); + glPopAttrib(); + glFlush(); this->checkForOpenGLError(model, "At end of drawModelInternal()"); -- GitLab From 7945d8ea37c7b9429a516d61a4253e7f2155093f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 18 Dec 2017 12:53:20 -0600 Subject: [PATCH 552/755] Renamed some enums internal to GraphicsPrimitive to better names and added a enum for the vertex color type. --- src/Graphics/GraphicsEngineDataOpenGL.cxx | 60 ++-- .../GraphicsOpenGLPolylineTriangles.cxx | 16 +- src/Graphics/GraphicsPrimitive.cxx | 256 +++++++++++------- src/Graphics/GraphicsPrimitive.h | 72 +++-- .../GraphicsPrimitiveSelectionHelper.cxx | 12 +- src/Graphics/GraphicsPrimitiveV3f.cxx | 18 +- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 9 +- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 9 +- src/Graphics/GraphicsPrimitiveV3fN3f.cxx | 18 +- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 9 +- 10 files changed, 278 insertions(+), 201 deletions(-) diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 2fc6c650a..0dc974b2e 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -139,8 +139,8 @@ GraphicsEngineDataOpenGL::loadCoordinateBuffer(GraphicsPrimitive* primitive) GLsizei coordinateCount = 0; - switch (primitive->m_vertexType) { - case GraphicsPrimitive::VertexType::FLOAT_XYZ: + switch (primitive->m_vertexDataType) { + case GraphicsPrimitive::VertexDataType::FLOAT_XYZ: m_coordinateDataType = GL_FLOAT; m_coordinatesPerVertex = 3; // X, Y, Z @@ -195,10 +195,10 @@ GraphicsEngineDataOpenGL::loadNormalVectorBuffer(GraphicsPrimitive* primitive) GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeNormals()); - switch (primitive->m_normalVectorType) { - case GraphicsPrimitive::NormalVectorType::NONE: + switch (primitive->m_normalVectorDataType) { + case GraphicsPrimitive::NormalVectorDataType::NONE: break; - case GraphicsPrimitive::NormalVectorType::FLOAT_XYZ: + case GraphicsPrimitive::NormalVectorDataType::FLOAT_XYZ: { m_normalVectorDataType = GL_FLOAT; const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); @@ -233,10 +233,10 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeColors()); - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::NONE: break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); @@ -258,7 +258,7 @@ GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) usageHint); } break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); @@ -297,8 +297,8 @@ GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primiti GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeTextureCoordinates()); - switch (primitive->m_textureType) { - case GraphicsPrimitive::TextureType::FLOAT_STR: + switch (primitive->m_textureDataType) { + case GraphicsPrimitive::TextureDataType::FLOAT_STR: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); @@ -319,7 +319,7 @@ GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primiti } break; - case GraphicsPrimitive::TextureType::NONE: + case GraphicsPrimitive::TextureDataType::NONE: break; } } @@ -356,8 +356,8 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv return; } - switch (primitive->m_textureType) { - case GraphicsPrimitive::TextureType::FLOAT_STR: + switch (primitive->m_textureDataType) { + case GraphicsPrimitive::TextureDataType::FLOAT_STR: { const int32_t imageWidth = primitive->m_textureImageWidth; const int32_t imageHeight = primitive->m_textureImageHeight; @@ -448,7 +448,7 @@ GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitiv glPopClientAttrib(); } break; - case GraphicsPrimitive::TextureType::NONE: + case GraphicsPrimitive::TextureDataType::NONE: break; } } @@ -611,15 +611,15 @@ GraphicsEngineDataOpenGL::drawPointsPrimitiveMillimeters(const GraphicsPrimitive const int32_t i4 = i * 4; uint8_t* rgba = NULL; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssert(0); break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); rgba = const_cast(&primitive->m_unsignedByteRGBA[i4]); break; - case GraphicsPrimitive::ColorType::NONE: + case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; } @@ -658,17 +658,17 @@ GraphicsEngineDataOpenGL::drawSpheresPrimitive(const GraphicsPrimitive* primitiv CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); const int32_t i4 = i * 4; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssert(0); break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); GraphicsShape::drawSphereByteColor(&primitive->m_xyz[i3], &primitive->m_unsignedByteRGBA[i4], sizeValue); break; - case GraphicsPrimitive::ColorType::NONE: + case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; } @@ -954,13 +954,13 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, } bool hasColorFlag = false; - switch (primitive->getColorType()) { - case GraphicsPrimitive::ColorType::NONE: + switch (primitive->getColorDataType()) { + case GraphicsPrimitive::ColorDataType::NONE: break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: hasColorFlag = true; break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: hasColorFlag = true; break; } @@ -1008,10 +1008,10 @@ GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, } bool hasTextureFlag = false; - switch (primitive->getTextureType()) { - case GraphicsPrimitive::TextureType::NONE: + switch (primitive->getTextureDataType()) { + case GraphicsPrimitive::TextureDataType::NONE: break; - case GraphicsPrimitive::TextureType::FLOAT_STR: + case GraphicsPrimitive::TextureDataType::FLOAT_STR: hasTextureFlag = true; break; } diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 02cddc059..a8a6fc2a0 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -145,15 +145,15 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const } ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; - switch (primitive->m_colorType) { - case GraphicsPrimitive::ColorType::NONE: + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::NONE: errorMessageOut = "INVALID color type NONE for graphics primitive"; return NULL; break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: colorType = ColorType::FLOAT_RGBA_PER_VERTEX; break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: colorType = ColorType::BYTE_RGBA_PER_VERTEX; break; } @@ -1239,11 +1239,11 @@ GraphicsOpenGLPolylineTriangles::addJoinTriangles() const float* tv2 = (normalOutFlag ? v2 : v3); const float* tv3 = (normalOutFlag ? v3 : v2); - switch (m_primitive->getColorType()) { - case GraphicsPrimitive::ColorType::NONE: + switch (m_primitive->getColorDataType()) { + case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: { float rgba[4]; getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); @@ -1252,7 +1252,7 @@ GraphicsOpenGLPolylineTriangles::addJoinTriangles() m_primitiveFloatColor->addVertex(tv3, rgba); } break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: { uint8_t rgba[4]; getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index 250a126d2..e7f636f70 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -48,28 +48,32 @@ using namespace caret; /** * Constructs an instance with the given vertex, normal vector, and color type. * - * @param vertexType - * Type of the vertices. - * @param normalVectorType - * Type of the normal vectors. - * @param colorType - * Type of the colors. - * @param textureType - * Type of texture coordinates. + * @param vertexDataType + * Data type of the vertices. + * @param normalVectorDataType + * Data type of the normal vectors. + * @param colorDataType + * Data type of the colors. + * @param vertexColorType + * Type of vertex coloring + * @param textureDataType + * Data type of texture coordinates. * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ -GraphicsPrimitive::GraphicsPrimitive(const VertexType vertexType, - const NormalVectorType normalVectorType, - const ColorType colorType, - const TextureType textureType, - const PrimitiveType primitiveType) +GraphicsPrimitive::GraphicsPrimitive(const VertexDataType vertexDataType, + const NormalVectorDataType normalVectorDataType, + const ColorDataType colorDataType, + const VertexColorType vertexColorType, + const TextureDataType textureDataType, + const PrimitiveType primitiveType) : CaretObject(), EventListenerInterface(), - m_vertexType(vertexType), - m_normalVectorType(normalVectorType), - m_colorType(colorType), - m_textureType(textureType), + m_vertexDataType(vertexDataType), + m_normalVectorDataType(normalVectorDataType), + m_colorDataType(colorDataType), + m_vertexColorType(vertexColorType), + m_textureDataType(textureDataType), m_primitiveType(primitiveType), m_boundingBoxValid(false) { @@ -92,10 +96,11 @@ GraphicsPrimitive::~GraphicsPrimitive() GraphicsPrimitive::GraphicsPrimitive(const GraphicsPrimitive& obj) : CaretObject(obj), EventListenerInterface(), - m_vertexType(obj.m_vertexType), - m_normalVectorType(obj.m_normalVectorType), - m_colorType(obj.m_colorType), - m_textureType(obj.m_textureType), + m_vertexDataType(obj.m_vertexDataType), + m_normalVectorDataType(obj.m_normalVectorDataType), + m_colorDataType(obj.m_colorDataType), + m_vertexColorType(obj.m_vertexColorType), + m_textureDataType(obj.m_textureDataType), m_primitiveType(obj.m_primitiveType), m_boundingBoxValid(false) { @@ -143,35 +148,35 @@ GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) void GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) { - switch (m_vertexType) { - case VertexType::FLOAT_XYZ: + switch (m_vertexDataType) { + case VertexDataType::FLOAT_XYZ: m_xyz.reserve(numberOfVertices * 3); break; } - switch (m_normalVectorType) { - case NormalVectorType::FLOAT_XYZ: + switch (m_normalVectorDataType) { + case NormalVectorDataType::FLOAT_XYZ: m_floatNormalVectorXYZ.reserve(numberOfVertices * 3); break; - case NormalVectorType::NONE: + case NormalVectorDataType::NONE: break; } - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: m_floatRGBA.reserve(numberOfVertices * 4); break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: m_unsignedByteRGBA.reserve(numberOfVertices * 4); break; } - switch (m_textureType) { - case GraphicsPrimitive::TextureType::NONE: + switch (m_textureDataType) { + case GraphicsPrimitive::TextureDataType::NONE: break; - case GraphicsPrimitive::TextureType::FLOAT_STR: + case GraphicsPrimitive::TextureDataType::FLOAT_STR: m_floatTextureSTR.reserve(numberOfVertices * 3); break; } @@ -288,17 +293,17 @@ GraphicsPrimitive::setUsageTypeTextureCoordinates(const UsageType usageType) bool GraphicsPrimitive::isValid() const { - switch (m_vertexType) { - case VertexType::FLOAT_XYZ: + switch (m_vertexDataType) { + case VertexDataType::FLOAT_XYZ: break; } const uint32_t numXYZ = m_xyz.size(); if (numXYZ > 0) { - switch (m_normalVectorType) { - case NormalVectorType::NONE: + switch (m_normalVectorDataType) { + case NormalVectorDataType::NONE: break; - case NormalVectorType::FLOAT_XYZ: + case NormalVectorDataType::FLOAT_XYZ: { const uint32_t numNormalXYZ = m_floatNormalVectorXYZ.size(); if (numNormalXYZ > 0) { @@ -313,15 +318,15 @@ GraphicsPrimitive::isValid() const bool haveRgbaFlag = false; uint32_t numColorRGBA = 0; - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: haveRgbaFlag = false; break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: numColorRGBA = m_floatRGBA.size(); haveRgbaFlag = true; break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: numColorRGBA = m_unsignedByteRGBA.size(); haveRgbaFlag = true; break; @@ -333,12 +338,26 @@ GraphicsPrimitive::isValid() const } } + switch (m_vertexColorType) { + case VertexColorType::NONE: + if (haveRgbaFlag) { + CaretLogWarning("ERROR: GraphicsPrimitive VertexColorType is NONE but have RGBA ColorDataType"); + } + break; + case VertexColorType::PER_VERTEX_RGBA: + case VertexColorType::SOLID_RGBA: + if ( ! haveRgbaFlag) { + CaretLogWarning("ERROR: GraphicsPrimitive VertexColorType is RGBA but have NONE ColorDataType"); + } + break; + } + bool haveTextureFlag = false; uint32_t numTextureSTR = 0; - switch (m_textureType) { - case TextureType::NONE: + switch (m_textureDataType) { + case TextureDataType::NONE: break; - case TextureType::FLOAT_STR: + case TextureDataType::FLOAT_STR: numTextureSTR = m_floatTextureSTR.size(); haveTextureFlag = true; break; @@ -509,6 +528,32 @@ GraphicsPrimitive::getSphereSizeTypeAsText(const SphereSizeType sizeType) const return s; } +/** + * @return Vertex color type as text for the given vertex color type. + * + * @param vertexColorType + * The vertex color type. + */ +AString +GraphicsPrimitive::getVertexColorTypeAsText(const VertexColorType vertexColorType) const +{ + AString s; + + switch (vertexColorType) { + case VertexColorType::NONE: + s = "None"; + break; + case VertexColorType::PER_VERTEX_RGBA: + s = "Per Vertex RGBA"; + break; + case VertexColorType::SOLID_RGBA: + s = "Solid RGBA"; + break; + } + + return s; +} + /** * @return Point size type as text for the given size type. * @@ -571,10 +616,10 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const const int32_t numVertices = getNumberOfVertices(); s.appendWithNewLine("Number of Vertices: " + AString::number(numVertices) + "\n"); - switch (m_textureType) { - case TextureType::NONE: + switch (m_textureDataType) { + case TextureDataType::NONE: break; - case TextureType::FLOAT_STR: + case TextureDataType::FLOAT_STR: s.appendWithNewLine("Texture: " + AString::number(m_floatTextureSTR.size()) + " Float Texture 0.0 to 1.0. "); s.appendWithNewLine(" Width: " + AString::number(m_textureImageWidth) + " Height: " + AString::number(m_textureImageHeight)); @@ -650,13 +695,16 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const + AString::number(m_sphereDiameterValue, 'f', 3)); } + s.appendWithNewLine("Vertex Color Type: " + + getVertexColorTypeAsText(m_vertexColorType)); + s.append("\n"); if (includeAllDataFlag) { for (int32_t i = 0; i < numVertices; i++) { s.append(AString("%1: ").arg(i, 5)); - switch (m_vertexType) { - case VertexType::FLOAT_XYZ: + switch (m_vertexDataType) { + case VertexDataType::FLOAT_XYZ: { CaretAssertVectorIndex(m_xyz, i*3 + 2); const float* xyz = &m_xyz[i * 3]; @@ -665,28 +713,28 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const break; } - switch (m_normalVectorType) { - case NormalVectorType::FLOAT_XYZ: + switch (m_normalVectorDataType) { + case NormalVectorDataType::FLOAT_XYZ: { CaretAssertVectorIndex(m_floatNormalVectorXYZ, i*3 + 2); const float* xyz = &m_floatNormalVectorXYZ[i * 3]; s.append(AString(" N:%1, %2, %3").arg(xyz[0], 7, 'f', 5).arg(xyz[1], 7, 'f', 5).arg(xyz[2], 7, 'f', 5)); } - case NormalVectorType::NONE: + case NormalVectorDataType::NONE: break; } - switch (m_colorType) { - case GraphicsPrimitive::ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: { CaretAssertVectorIndex(m_floatRGBA, i*4 + 3); const float* rgba = &m_floatRGBA[i * 4]; s.append(AString(" RGBAf: %1, %2, %3, %4").arg(rgba[0], 5, 'f', 3).arg(rgba[1], 5, 'f', 3).arg(rgba[2], 5, 'f', 3).arg(rgba[3], 5, 'f', 3)); } break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: { CaretAssertVectorIndex(m_unsignedByteRGBA, i*4 + 3); const uint8_t* rgba = &m_unsignedByteRGBA[i * 4]; @@ -694,10 +742,10 @@ GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const } } - switch (m_textureType) { - case TextureType::NONE: + switch (m_textureDataType) { + case TextureDataType::NONE: break; - case TextureType::FLOAT_STR: + case TextureDataType::FLOAT_STR: { CaretAssertVectorIndex(m_floatTextureSTR, i*3 + 2); const float* str = &m_floatTextureSTR[i * 3]; @@ -734,27 +782,27 @@ GraphicsPrimitive::addVertexProtected(const float xyz[3], m_xyz.insert(m_xyz.end(), xyz, xyz + 3); - switch (m_normalVectorType) { - case NormalVectorType::FLOAT_XYZ: + switch (m_normalVectorDataType) { + case NormalVectorDataType::FLOAT_XYZ: CaretAssert(normalVector); m_floatNormalVectorXYZ.insert(m_floatNormalVectorXYZ.end(), normalVector, normalVector + 3); break; - case NormalVectorType::NONE: + case NormalVectorDataType::NONE: break; } - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssert(rgbaFloat); m_floatRGBA.insert(m_floatRGBA.end(), rgbaFloat, rgbaFloat + 4); break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssert(rgbaByte); m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), rgbaByte, @@ -762,10 +810,10 @@ GraphicsPrimitive::addVertexProtected(const float xyz[3], break; } - switch (m_textureType) { - case TextureType::NONE: + switch (m_textureDataType) { + case TextureDataType::NONE: break; - case TextureType::FLOAT_STR: + case TextureDataType::FLOAT_STR: CaretAssert(textureSTR); m_floatTextureSTR.insert(m_floatTextureSTR.end(), textureSTR, @@ -848,18 +896,18 @@ GraphicsPrimitive::getVertexFloatRGBA(const int32_t vertexIndex, float rgbaOut[4]) const { const int32_t i4 = vertexIndex * 4; - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, i4 + 3); rgbaOut[0] = m_floatRGBA[i4]; rgbaOut[1] = m_floatRGBA[i4 + 1]; rgbaOut[2] = m_floatRGBA[i4 + 2]; rgbaOut[3] = m_floatRGBA[i4 + 3]; break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Getting float RGBA from primitive but coloring type is Byte"); CaretLogWarning("Getting float RGBA from primitive but coloring type is Byte"); break; @@ -879,18 +927,18 @@ GraphicsPrimitive::replaceVertexFloatRGBA(const int32_t vertexIndex, const float rgba[4]) { const int32_t i4 = vertexIndex * 4; - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, i4 + 3); m_floatRGBA[i4] = rgba[0]; m_floatRGBA[i4 + 1] = rgba[1]; m_floatRGBA[i4 + 2] = rgba[2]; m_floatRGBA[i4 + 3] = rgba[3]; break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Replacing float RGBA in primitive but coloring type is Byte"); CaretLogWarning("Replacing float RGBA in primitive but coloring type is Byte"); break; @@ -914,15 +962,15 @@ GraphicsPrimitive::getVertexByteRGBA(const int32_t vertexIndex, uint8_t rgbaOut[4]) const { const int32_t i4 = vertexIndex * 4; - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Getting Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Getting Byte RGBA in primitive but coloring type is Float"); break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); rgbaOut[0] = m_unsignedByteRGBA[i4]; rgbaOut[1] = m_unsignedByteRGBA[i4 + 1]; @@ -945,15 +993,15 @@ GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, const uint8_t rgba[4]) { const int32_t i4 = vertexIndex * 4; - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); m_unsignedByteRGBA[i4] = rgba[0]; m_unsignedByteRGBA[i4 + 1] = rgba[1]; @@ -976,15 +1024,15 @@ GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, void GraphicsPrimitive::replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]) { - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: { const int32_t numRGBA = static_cast(m_unsignedByteRGBA.size() / 4); for (int32_t i = 0; i < numRGBA; i++) { @@ -1012,11 +1060,11 @@ GraphicsPrimitive::replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]) void GraphicsPrimitive::replaceAllVertexSolidFloatRGBA(const float rgba[4]) { - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: CaretAssert(0); break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: { const int32_t numRGBA = static_cast(m_floatRGBA.size() / 4); for (int32_t i = 0; i < numRGBA; i++) { @@ -1029,7 +1077,7 @@ GraphicsPrimitive::replaceAllVertexSolidFloatRGBA(const float rgba[4]) } } break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; @@ -1180,20 +1228,20 @@ GraphicsPrimitive::copyVertex(const int32_t copyFromIndex, CaretAssertVectorIndex(m_xyz, to3 + i); m_xyz[to3 + i] = m_xyz[from3 + i]; - switch (m_normalVectorType) { - case NormalVectorType::FLOAT_XYZ: + switch (m_normalVectorDataType) { + case NormalVectorDataType::FLOAT_XYZ: CaretAssertVectorIndex(m_floatNormalVectorXYZ, from3 + i); CaretAssertVectorIndex(m_floatNormalVectorXYZ, to3 + i); m_floatNormalVectorXYZ[to3 + i] = m_floatNormalVectorXYZ[from3 + i]; break; - case NormalVectorType::NONE: + case NormalVectorDataType::NONE: break; } - switch (m_textureType) { - case TextureType::NONE: + switch (m_textureDataType) { + case TextureDataType::NONE: break; - case TextureType::FLOAT_STR: + case TextureDataType::FLOAT_STR: CaretAssertVectorIndex(m_floatTextureSTR, from3 + i); CaretAssertVectorIndex(m_floatTextureSTR, to3 + i); m_floatTextureSTR[to3 + i] = m_floatTextureSTR[from3 + i]; @@ -1205,15 +1253,15 @@ GraphicsPrimitive::copyVertex(const int32_t copyFromIndex, const int32_t to4 = copyToIndex * 4; for (int32_t i = 0; i < 4; i++) { - switch (m_colorType) { - case ColorType::NONE: + switch (m_colorDataType) { + case ColorDataType::NONE: break; - case ColorType::FLOAT_RGBA: + case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, from4 + i); CaretAssertVectorIndex(m_floatRGBA, to4 + i); m_floatRGBA[to4 + i] = m_floatRGBA[from4 + i]; break; - case ColorType::UNSIGNED_BYTE_RGBA: + case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, from4 + i); CaretAssertVectorIndex(m_unsignedByteRGBA, to4 + i); m_unsignedByteRGBA[to4 + i] = m_unsignedByteRGBA[from4 + i]; diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 37171596d..7f1e0823f 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -44,17 +44,17 @@ namespace caret { public: /** - * Type of vertices + * Data type of vertices */ - enum class VertexType { + enum class VertexDataType { /** Vertices are three float values per vertex containing X, Y, Z */ FLOAT_XYZ }; /** - * Type of normal vectors + * Data type of normal vectors */ - enum class NormalVectorType { + enum class NormalVectorDataType { /** No normal vectors */ NONE, /** Normal vectors are three float values per vertex contain X, Y, Z ranging 0.0 to 1.0 */ @@ -62,9 +62,9 @@ namespace caret { }; /** - * Type of colors + * Data type of colors */ - enum class ColorType { + enum class ColorDataType { /** No color components */ NONE, /** Four float values per vertex containing Red, Green, Blue, Alpha ranging 0.0 to 1.0 */ @@ -72,11 +72,23 @@ namespace caret { /** Four unsigned byte values per vertex containing Red, Green, Blue, Alpha ranging 0 to 255 */ UNSIGNED_BYTE_RGBA }; + + /** + * Coloring for each vertex thype + */ + enum class VertexColorType { + /** No color components */ + NONE, + /** One RGBA for all vertices */ + SOLID_RGBA, + /** Unique RGBA for each vertex */ + PER_VERTEX_RGBA + }; /** - * Type of texture components + * Data type of texture components */ - enum class TextureType { + enum class TextureDataType { /** No texture coordinates */ NONE, /** Three float values per vertex contains S, T, and R texture coordinates */ @@ -231,11 +243,12 @@ namespace caret { }; protected: - GraphicsPrimitive(const VertexType vertexType, - const NormalVectorType normalVectorType, - const ColorType colorType, - const TextureType textureType, - const PrimitiveType primitiveType); + GraphicsPrimitive(const VertexDataType vertexDataType, + const NormalVectorDataType normalVectorDataType, + const ColorDataType colorDataType, + const VertexColorType vertexColorType, + const TextureDataType textureDataType, + const PrimitiveType primitiveType); GraphicsPrimitive(const GraphicsPrimitive& obj); @@ -288,19 +301,24 @@ namespace caret { bool isValid() const; /** - * @return Type of the vertices. + * @return Data type of the vertices. */ - inline VertexType getVertexType() const { return m_vertexType; } + inline VertexDataType getVertexDataType() const { return m_vertexDataType; } /** - * @return Type of the normal vectors. + * @return Data type of the normal vectors. */ - inline NormalVectorType getNormalVectorType () const { return m_normalVectorType; } + inline NormalVectorDataType getNormalVectorDataType () const { return m_normalVectorDataType; } /** - * @return Type of the colors. + * @return Data type of the colors. */ - inline ColorType getColorType() const { return m_colorType; } + inline ColorDataType getColorDataType() const { return m_colorDataType; } + + /** + * @return Type of vertex colors + */ + inline VertexColorType getVertexColorType() const { return m_vertexColorType; } /** * @return Type of primitive. @@ -308,9 +326,9 @@ namespace caret { inline PrimitiveType getPrimitiveType() const { return m_primitiveType; } /** - * @return Type of texture. + * @return Data type of texture. */ - inline TextureType getTextureType() const { return m_textureType; } + inline TextureDataType getTextureDataType() const { return m_textureDataType; } /** * @return The float coordinates. @@ -399,13 +417,17 @@ namespace caret { AString getSphereSizeTypeAsText(const SphereSizeType sizeType) const; - const VertexType m_vertexType; + AString getVertexColorTypeAsText(const VertexColorType vertexColorType) const; + + const VertexDataType m_vertexDataType; + + const NormalVectorDataType m_normalVectorDataType; - const NormalVectorType m_normalVectorType; + const ColorDataType m_colorDataType; - const ColorType m_colorType; + const VertexColorType m_vertexColorType; - const TextureType m_textureType; + const TextureDataType m_textureDataType; const PrimitiveType m_primitiveType; diff --git a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx index f6bf3eae7..e1f2a2d06 100644 --- a/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx +++ b/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx @@ -63,8 +63,8 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() { int32_t numberOfVertices = 0; - switch (m_parentGraphicsPrimitive->getVertexType()) { - case GraphicsPrimitive::VertexType::FLOAT_XYZ: + switch (m_parentGraphicsPrimitive->getVertexDataType()) { + case GraphicsPrimitive::VertexDataType::FLOAT_XYZ: numberOfVertices = m_parentGraphicsPrimitive->getFloatXYZ().size() / 3; break; } @@ -133,7 +133,7 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() const int32_t selectionRgbaSize = numberOfVertices * 4; if (selectionRgbaSize != static_cast(m_selectionEncodedRGBA.size())) { - const GraphicsPrimitive::ColorType colorType = m_parentGraphicsPrimitive->getColorType(); + const GraphicsPrimitive::ColorDataType colorType = m_parentGraphicsPrimitive->getColorDataType(); m_selectionEncodedRGBA.resize(selectionRgbaSize); @@ -160,15 +160,15 @@ GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() uint8_t vertexAlpha = 0; const int32_t vertexAlphaIndex = indexRGBA + 3; switch (colorType) { - case GraphicsPrimitive::ColorType::NONE: + case GraphicsPrimitive::ColorDataType::NONE: vertexAlpha = 255; break; - case GraphicsPrimitive::ColorType::FLOAT_RGBA: + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_floatRGBA, vertexAlphaIndex); vertexAlpha = static_cast(m_parentGraphicsPrimitive->m_floatRGBA[vertexAlphaIndex] * 255); break; - case GraphicsPrimitive::ColorType::UNSIGNED_BYTE_RGBA: + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_unsignedByteRGBA, vertexAlphaIndex); vertexAlpha = m_parentGraphicsPrimitive->m_unsignedByteRGBA[vertexAlphaIndex]; diff --git a/src/Graphics/GraphicsPrimitiveV3f.cxx b/src/Graphics/GraphicsPrimitiveV3f.cxx index c92269446..f9e36fa1e 100644 --- a/src/Graphics/GraphicsPrimitiveV3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3f.cxx @@ -50,10 +50,11 @@ using namespace caret; */ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const float rgba[4]) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::NONE, - ColorType::FLOAT_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::NONE, + ColorDataType::FLOAT_RGBA, + VertexColorType::SOLID_RGBA, + TextureDataType::NONE, primitiveType) { m_floatSolidRGBA[0] = rgba[0]; @@ -72,10 +73,11 @@ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, */ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const uint8_t rgba[4]) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::NONE, - ColorType::UNSIGNED_BYTE_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::NONE, + ColorDataType::UNSIGNED_BYTE_RGBA, + VertexColorType::SOLID_RGBA, + TextureDataType::NONE, primitiveType) { m_unsignedByteSolidRGBA[0] = rgba[0]; diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index f49508068..f108020fa 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -41,10 +41,11 @@ using namespace caret; * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveType) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::NONE, - ColorType::FLOAT_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::NONE, + ColorDataType::FLOAT_RGBA, + VertexColorType::PER_VERTEX_RGBA, + TextureDataType::NONE, primitiveType) { diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index 249c33982..baf145378 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -41,10 +41,11 @@ using namespace caret; * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const PrimitiveType primitiveType) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::NONE, - ColorType::UNSIGNED_BYTE_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::NONE, + ColorDataType::UNSIGNED_BYTE_RGBA, + VertexColorType::PER_VERTEX_RGBA, + TextureDataType::NONE, primitiveType) { diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx index f38566a18..ff9392b3b 100644 --- a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx @@ -50,10 +50,11 @@ using namespace caret; */ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const float rgba[4]) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::FLOAT_XYZ, - ColorType::FLOAT_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::FLOAT_XYZ, + ColorDataType::FLOAT_RGBA, + VertexColorType::SOLID_RGBA, + TextureDataType::NONE, primitiveType) { m_floatSolidRGBA[0] = rgba[0]; @@ -72,10 +73,11 @@ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveTy */ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const uint8_t rgba[4]) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::FLOAT_XYZ, - ColorType::UNSIGNED_BYTE_RGBA, - TextureType::NONE, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::FLOAT_XYZ, + ColorDataType::UNSIGNED_BYTE_RGBA, + VertexColorType::SOLID_RGBA, + TextureDataType::NONE, primitiveType) { m_unsignedByteSolidRGBA[0] = rgba[0]; diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 58acbced7..7b27ab649 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -50,10 +50,11 @@ GraphicsPrimitiveV3fT3f::GraphicsPrimitiveV3fT3f(const PrimitiveType primitiveTy const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) -: GraphicsPrimitive(VertexType::FLOAT_XYZ, - NormalVectorType::NONE, - ColorType::NONE, - TextureType::FLOAT_STR, +: GraphicsPrimitive(VertexDataType::FLOAT_XYZ, + NormalVectorDataType::NONE, + ColorDataType::NONE, + VertexColorType::NONE, + TextureDataType::FLOAT_STR, primitiveType) { setTextureImage(imageBytesRGBA, -- GitLab From e7df92bd03e4a7f388a28943863b38a2e7cc0423 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 18 Dec 2017 15:26:46 -0600 Subject: [PATCH 553/755] Add methods for drawing many spheres or squares in the same color since more efficient than drawing spheres/squares one at a time. --- src/Graphics/GraphicsShape.cxx | 155 +++++++++++++++++++++++++++++++-- src/Graphics/GraphicsShape.h | 10 +++ 2 files changed, 157 insertions(+), 8 deletions(-) diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index a8b3a1c07..4caafc4e5 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -425,7 +425,10 @@ GraphicsShape::drawLineStripMiterJoinByteColor(const std::vector& xyz, } /** - * Draw a sphere at the given XYZ coordinate + * Draw one sphere at the given XYZ coordinate. + * NOTE: if you have multiple spheres to draw + * with the same color and diameter the method + * "drawSpheresByteColor() is much more efficient. * * @param xyz * XYZ-coordinate of sphere @@ -438,6 +441,68 @@ void GraphicsShape::drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], const float diameter) +{ + drawSpheresByteColor(xyz, + 1, + rgba, + diameter); + +// const int32_t numLatLonDivisions = 10; +// +// GraphicsPrimitive* spherePrimitive = NULL; +// for (const auto iter : s_byteSpherePrimitives) { +// const auto& key = iter.first; +// if ((key == numLatLonDivisions)) { +// spherePrimitive = iter.second; +// CaretAssert(spherePrimitive); +// break; +// } +// } +// +// if (spherePrimitive == NULL) { +// const bool useStripsFlag = true; +// if (useStripsFlag) { +// spherePrimitive = createSpherePrimitiveTriangleStrips(numLatLonDivisions); +// } +// else { +// spherePrimitive = createSpherePrimitiveTriangles(numLatLonDivisions); +// } +// /* colors may change but not coordinates/normals */ +// spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); +// spherePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); +// s_byteSpherePrimitives.insert(std::make_pair(numLatLonDivisions, +// spherePrimitive)); +// } +// +// CaretAssert(spherePrimitive); +// +// spherePrimitive->replaceAllVertexSolidByteRGBA(rgba); +// +// glPushMatrix(); +// glTranslatef(xyz[0], xyz[1], xyz[2]); +// glScalef(diameter, diameter, diameter); +// GraphicsEngineDataOpenGL::draw(spherePrimitive); +// glPopMatrix(); +} + +/** + * Draw a spheres at the given XYZ coordinates + * + * @param xyz + * XYZ-coordinates of spheres (must be allocated for + * "numberOfSpheres" + * @param numberOfSpheres + * Number of spheres + * @param rgba + * Color for drawing. + * @param diameter + * Diameter of the spheres. + */ +void +GraphicsShape::drawSpheresByteColor(const float xyz[], + const int32_t numberOfSpheres, + const uint8_t rgba[4], + const float diameter) { const int32_t numLatLonDivisions = 10; @@ -465,18 +530,22 @@ GraphicsShape::drawSphereByteColor(const float xyz[3], s_byteSpherePrimitives.insert(std::make_pair(numLatLonDivisions, spherePrimitive)); } - + CaretAssert(spherePrimitive); spherePrimitive->replaceAllVertexSolidByteRGBA(rgba); - glPushMatrix(); - glTranslatef(xyz[0], xyz[1], xyz[2]); - glScalef(diameter, diameter, diameter); - GraphicsEngineDataOpenGL::draw(spherePrimitive); - glPopMatrix(); + for (int32_t i = 0; i < numberOfSpheres; i++) { + const int32_t i3 = i * 3; + glPushMatrix(); + glTranslatef(xyz[i3], xyz[i3+1], xyz[i3+2]); + glScalef(diameter, diameter, diameter); + GraphicsEngineDataOpenGL::draw(spherePrimitive); + glPopMatrix(); + } } + /** * Draw a filled circle at the given XYZ coordinate * @@ -525,6 +594,77 @@ GraphicsShape::drawCircleFilled(const float xyz[3], glPopMatrix(); } +/** + * Draw a squares at the given XYZ coordinates + * + * @param xyz + * XYZ-coordinates of squares + * @param numberOfSquares + * Number of squares to draw + * @param rgba + * Color for drawing. + * @param diameter + * Diameter of the squares. + */ +void +GraphicsShape::drawSquares(const float xyz[], + const int32_t numberOfSquares, + const uint8_t rgba[4], + const float diameter) +{ + if (numberOfSquares <= 0) { + return; + } + CaretAssert(xyz); + + if ( ! s_byteSquarePrimitive) { + s_byteSquarePrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, + rgba)); + /* + * The square is made up of four triangles + * with two triangles for the 'front' and + * two triangles for the 'back' so that it is + * never culled. + */ + + const float radius = 0.5f; + + /* counter clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + + /* counter clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + s_byteSquarePrimitive->addVertex(-radius, radius); + + /* clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex(-radius, radius); + s_byteSquarePrimitive->addVertex( radius, radius); + + /* clockwise triangle */ + s_byteSquarePrimitive->addVertex(-radius, -radius); + s_byteSquarePrimitive->addVertex( radius, radius); + s_byteSquarePrimitive->addVertex( radius, -radius); + } + + CaretAssert(s_byteSquarePrimitive.get()); + + s_byteSquarePrimitive->replaceAllVertexSolidByteRGBA(rgba); + + for (int32_t i = 0; i < numberOfSquares; i++) { + const int32_t i3 = i * 3; + glPushMatrix(); + glTranslatef(xyz[i3], xyz[i3+1], xyz[i3+2]); + updateModelMatrixToFaceViewer(); + glScalef(diameter, diameter, 1.0f); + GraphicsEngineDataOpenGL::draw(s_byteSquarePrimitive.get()); + glPopMatrix(); + } +} + /** * Draw a square at the given XYZ coordinate * @@ -535,7 +675,6 @@ GraphicsShape::drawCircleFilled(const float xyz[3], * @param diameter * Diameter of the square. */ - void GraphicsShape::drawSquare(const float xyz[3], const uint8_t rgba[4], diff --git a/src/Graphics/GraphicsShape.h b/src/Graphics/GraphicsShape.h index fff1fd122..db9faedbe 100644 --- a/src/Graphics/GraphicsShape.h +++ b/src/Graphics/GraphicsShape.h @@ -97,6 +97,11 @@ namespace caret { const uint8_t rgba[4], const float diameter); + static void drawSpheresByteColor(const float xyz[], + const int32_t numberOfSpheres, + const uint8_t rgba[4], + const float diameter); + static void drawCircleFilled(const float xyz[3], const uint8_t rgba[4], const float diameter); @@ -105,6 +110,11 @@ namespace caret { const uint8_t rgba[4], const float diameter); + static void drawSquares(const float xyz[], + const int32_t numberOfSquares, + const uint8_t rgba[4], + const float diameter); + static void drawRing(const float xyz[3], const uint8_t rgba[4], const double innerRadius, -- GitLab From bad326286180a1b4f2a2071ea7923c2719f72bf0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 18 Dec 2017 15:27:18 -0600 Subject: [PATCH 554/755] Fixed very slow border sphere/square drawing by drawing all at once instead of one at at time. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 113 ++++++++++++++------ src/Graphics/GraphicsEngineDataOpenGL.cxx | 120 +++++++++++++++------- 2 files changed, 164 insertions(+), 69 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index fa6792dbd..eca08ea62 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -103,6 +103,7 @@ #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4ub.h" +#include "GraphicsPrimitiveV3f.h" #include "GraphicsShape.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" @@ -2693,20 +2694,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) const std::vector& nodesBoundaryEdgeCount = th->getNumberOfBoundaryEdgesForAllNodes(); CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); - std::unique_ptr pointsPrimitive; - if (drawSquarePoints) { - pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); - } - if (drawSphericalPoints) { - pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); - } - std::unique_ptr linesPrimitive; - if (drawLines) { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); - } - - const bool featureClippingFlag = isFeatureClippingEnabled(); - const uint8_t highlightFirstPointRGBA[4] = { 0, 255, 0, 1 }; const uint8_t highlightLastPointRGBA[4] = { 0, 192, 0, 1 }; @@ -2717,6 +2704,51 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) borderDrawInfo.rgba[3] * 255.0f }; + std::unique_ptr pointsPrimitive; + std::unique_ptr pointsIdentificationPrimitive; + std::unique_ptr firstPointPrimitive; + std::unique_ptr lastPointPrimitive; + if (drawSquarePoints) { + if (borderDrawInfo.isSelect) { + pointsIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); + } + else { + pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, + solidColorRGBA)); + firstPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, + highlightFirstPointRGBA)); + lastPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, + highlightLastPointRGBA)); + } + } + if (drawSphericalPoints) { + if (borderDrawInfo.isSelect) { + pointsIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); + } + else { + pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, + solidColorRGBA)); + firstPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, + highlightFirstPointRGBA)); + lastPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, + highlightLastPointRGBA)); + } + } + + std::unique_ptr linesPrimitive; + std::unique_ptr linesIdentificationPrimitive; + if (drawLines) { + if (borderDrawInfo.isSelect) { + linesIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); + } + else { + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN, + solidColorRGBA)); + } + } + + const bool featureClippingFlag = isFeatureClippingEnabled(); + bool lastPointForLineValidFlag = false; float lastPointForLineXYZ[3] = { 0.0f, 0.0f, 0.0f }; int32_t lastPointIndex = -1; @@ -2732,6 +2764,9 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) if (linesPrimitive) { linesPrimitive->addPrimitiveRestart(); } + if (linesIdentificationPrimitive) { + linesIdentificationPrimitive->addPrimitiveRestart(); + } } } @@ -2825,12 +2860,13 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) if (linesPrimitive) { linesPrimitive->addPrimitiveRestart(); } + if (linesIdentificationPrimitive) { + linesIdentificationPrimitive->addPrimitiveRestart(); + } } } } - } - } /* @@ -2851,32 +2887,32 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) i); pointRGBA[3] = 255; - if (pointsPrimitive) { - pointsPrimitive->addVertex(xyz, idRGBA); + if (pointsIdentificationPrimitive) { + pointsIdentificationPrimitive->addVertex(xyz, idRGBA); } - if (linesPrimitive) { - linesPrimitive->addVertex(xyz, idRGBA); + if (linesIdentificationPrimitive) { + linesIdentificationPrimitive->addVertex(xyz, idRGBA); } } else { if (pointsPrimitive) { if (isHighlightEndPoints) { if (i == 0) { - pointsPrimitive->addVertex(xyz, highlightFirstPointRGBA); + firstPointPrimitive->addVertex(xyz); } else if (i == (numBorderPoints - 1)) { - pointsPrimitive->addVertex(xyz, highlightLastPointRGBA); + lastPointPrimitive->addVertex(xyz); } else { - pointsPrimitive->addVertex(xyz, solidColorRGBA); + pointsPrimitive->addVertex(xyz); } } else { - pointsPrimitive->addVertex(xyz, solidColorRGBA); + pointsPrimitive->addVertex(xyz); } } if (linesPrimitive) { - linesPrimitive->addVertex(xyz, solidColorRGBA); + linesPrimitive->addVertex(xyz); } } @@ -2893,19 +2929,36 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); - if (pointsPrimitive) { + if (pointsIdentificationPrimitive) { + pointsIdentificationPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, + pointDiameter); + pointsIdentificationPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, + pointDiameter); + GraphicsEngineDataOpenGL::draw(pointsIdentificationPrimitive.get()); + } + else if (pointsPrimitive) { pointsPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, pointDiameter); pointsPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, pointDiameter); if (pointsPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES) { - if ( ! borderDrawInfo.isSelect) { - glEnable(GL_LIGHTING); - } + glEnable(GL_LIGHTING); } GraphicsEngineDataOpenGL::draw(pointsPrimitive.get()); + if (firstPointPrimitive->isValid()) { + GraphicsEngineDataOpenGL::draw(firstPointPrimitive.get()); + } + if (lastPointPrimitive->isValid()) { + GraphicsEngineDataOpenGL::draw(lastPointPrimitive.get()); + } + } + if (linesIdentificationPrimitive) { + glDisable(GL_LIGHTING); + linesIdentificationPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, + lineWidth); + GraphicsEngineDataOpenGL::draw(linesIdentificationPrimitive.get()); } - if (linesPrimitive) { + else if (linesPrimitive) { glDisable(GL_LIGHTING); linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, lineWidth); diff --git a/src/Graphics/GraphicsEngineDataOpenGL.cxx b/src/Graphics/GraphicsEngineDataOpenGL.cxx index 0dc974b2e..79b76e725 100644 --- a/src/Graphics/GraphicsEngineDataOpenGL.cxx +++ b/src/Graphics/GraphicsEngineDataOpenGL.cxx @@ -604,27 +604,48 @@ GraphicsEngineDataOpenGL::drawPointsPrimitiveMillimeters(const GraphicsPrimitive switch (primitive->m_pointSizeType) { case GraphicsPrimitive::PointSizeType::MILLIMETERS: { - for (int32_t i = 0; i < numberOfVertices; i++) { - const int32_t i3 = i * 3; - CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); - const float* xyz = &primitive->m_xyz[i3]; - const int32_t i4 = i * 4; - - uint8_t* rgba = NULL; - switch (primitive->m_colorDataType) { - case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: - CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); - rgba = const_cast(&primitive->m_unsignedByteRGBA[i4]); - break; - case GraphicsPrimitive::ColorDataType::NONE: - CaretAssert(0); - break; + switch (primitive->m_vertexColorType) { + case GraphicsPrimitive::VertexColorType::NONE: + CaretAssert(0); + CaretLogSevere("NONE vertex color type, should never occur when drawing points in millimeters"); + return; + break; + case GraphicsPrimitive::VertexColorType::PER_VERTEX_RGBA: + { + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); + const float* xyz = &primitive->m_xyz[i3]; + const int32_t i4 = i * 4; + + uint8_t* rgba = NULL; + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); + rgba = const_cast(&primitive->m_unsignedByteRGBA[i4]); + break; + case GraphicsPrimitive::ColorDataType::NONE: + CaretAssert(0); + break; + } + + GraphicsShape::drawSquare(xyz, rgba, sizeValue); + } } - - GraphicsShape::drawSquare(xyz, rgba, sizeValue); + break; + case GraphicsPrimitive::VertexColorType::SOLID_RGBA: + { + const int32_t numberOfVertices = primitive->getNumberOfVertices(); + CaretAssertVectorIndex(primitive->m_xyz, (numberOfVertices - 1) * 3 + 1); + GraphicsShape::drawSquares(&primitive->m_xyz[0], + numberOfVertices, + &primitive->m_unsignedByteRGBA[0], + sizeValue); + } + break; } } break; @@ -652,26 +673,47 @@ GraphicsEngineDataOpenGL::drawSpheresPrimitive(const GraphicsPrimitive* primitiv primitive->getSphereDiameter(sizeType, sizeValue); - const int32_t numberOfVertices = primitive->getNumberOfVertices(); - for (int32_t i = 0; i < numberOfVertices; i++) { - const int32_t i3 = i * 3; - CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); - const int32_t i4 = i * 4; - - switch (primitive->m_colorDataType) { - case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: - CaretAssert(0); - break; - case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: - CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); - GraphicsShape::drawSphereByteColor(&primitive->m_xyz[i3], - &primitive->m_unsignedByteRGBA[i4], - sizeValue); - break; - case GraphicsPrimitive::ColorDataType::NONE: - CaretAssert(0); - break; + switch (primitive->m_vertexColorType) { + case GraphicsPrimitive::VertexColorType::NONE: + CaretAssert(0); + CaretLogSevere("NONE vertex color type, should never occur when drawing spheres"); + return; + break; + case GraphicsPrimitive::VertexColorType::PER_VERTEX_RGBA: + { + const int32_t numberOfVertices = primitive->getNumberOfVertices(); + for (int32_t i = 0; i < numberOfVertices; i++) { + const int32_t i3 = i * 3; + CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); + const int32_t i4 = i * 4; + + switch (primitive->m_colorDataType) { + case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: + CaretAssert(0); + break; + case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: + CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); + GraphicsShape::drawSphereByteColor(&primitive->m_xyz[i3], + &primitive->m_unsignedByteRGBA[i4], + sizeValue); + break; + case GraphicsPrimitive::ColorDataType::NONE: + CaretAssert(0); + break; + } + } + } + break; + case GraphicsPrimitive::VertexColorType::SOLID_RGBA: + { + const int32_t numberOfVertices = primitive->getNumberOfVertices(); + CaretAssertVectorIndex(primitive->m_xyz, (numberOfVertices - 1) * 3 + 1); + GraphicsShape::drawSpheresByteColor(&primitive->m_xyz[0], + numberOfVertices, + &primitive->m_unsignedByteRGBA[0], + sizeValue); } + break; } } -- GitLab From 983fd31015c48e1e107ef80da148426c1f8ccf1d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 19 Dec 2017 15:29:22 -0600 Subject: [PATCH 555/755] Log a message if an instance of EventListenerInterface is destroyed but has not removed all of its listeners. --- src/Common/CMakeLists.txt | 1 + src/Common/EventListenerInterface.cxx | 51 ++++++++ src/Common/EventListenerInterface.h | 4 +- src/Common/EventManager.cxx | 120 +++++------------- src/Common/EventManager.h | 4 + src/Files/ChartableTwoFileLineSeriesChart.cxx | 2 + .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 2 + 7 files changed, 95 insertions(+), 89 deletions(-) create mode 100644 src/Common/EventListenerInterface.cxx diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 7a5cc299a..2f344da60 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -201,6 +201,7 @@ EventBrowserTabDelete.cxx EventBrowserTabIndicesGetAll.cxx EventCaretPreferencesGet.cxx EventGetViewportSize.cxx +EventListenerInterface.cxx EventManager.cxx EventPaletteGetByName.cxx EventProgressUpdate.cxx diff --git a/src/Common/EventListenerInterface.cxx b/src/Common/EventListenerInterface.cxx new file mode 100644 index 000000000..2ad316b47 --- /dev/null +++ b/src/Common/EventListenerInterface.cxx @@ -0,0 +1,51 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "EventListenerInterface.h" + +#include "CaretAssert.h" +#include "EventManager.h" +using namespace caret; + + + +/** + * \class caret::EventListenerInterface2 + * \brief Interface for classes that listen for events + * \ingroup Common + */ + +/** + * Constructor. + */ +EventListenerInterface::EventListenerInterface() +{ + +} + +/** + * Destructor. + */ +EventListenerInterface::~EventListenerInterface() +{ + EventManager::get()->verifyAllListenersRemoved(this); +} + diff --git a/src/Common/EventListenerInterface.h b/src/Common/EventListenerInterface.h index d4e798ae9..9031ae654 100644 --- a/src/Common/EventListenerInterface.h +++ b/src/Common/EventListenerInterface.h @@ -37,12 +37,12 @@ namespace caret { /** * Constructor. */ - EventListenerInterface() { } + EventListenerInterface(); /** * Destructor. */ - virtual ~EventListenerInterface() { } + virtual ~EventListenerInterface(); private: EventListenerInterface(const EventListenerInterface&) { } diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index e99ee3259..b49044f06 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -34,6 +34,7 @@ #include "CaretLogger.h" #include "EventAlertUser.h" #include "EventListenerInterface.h" +#include "SystemUtilities.h" using namespace caret; /** @@ -175,12 +176,6 @@ EventManager::addEventListener(EventListenerInterface* eventListener, #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif - - //std::cout << "Adding listener from class " - //<< typeid(*eventListener).name() - //<< " for " - //<< EventTypeEnum::toName(listenForEventType) - //<< std::endl; } /** @@ -205,12 +200,6 @@ EventManager::addProcessedEventListener(EventListenerInterface* eventListener, #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif - - //std::cout << "Adding listener from class " - //<< typeid(*eventListener).name() - //<< " for " - //<< EventTypeEnum::toName(listenForEventType) - //<< std::endl; } /** @@ -248,59 +237,6 @@ EventManager::removeEventFromListener(EventListenerInterface* eventListener, if (processedEventIter != processedListeners.end()) { processedListeners.erase(processedEventIter); } - -// EVENT_LISTENER_CONTAINER listeners = m_eventListeners[listenForEventType]; -// -// /* -// * Remove the listener by creating a new container -// * of non-matching listeners. -// */ -// EVENT_LISTENER_CONTAINER updatedListeners; -// for (EVENT_LISTENER_CONTAINER_ITERATOR iter = listeners.begin(); -// iter != listeners.end(); -// iter++) { -// if (*iter == eventListener) { -// //std::cout << "Removing listener from class " -// //<< typeid(*eventListener).name() -// //<< " for " -// //<< EventTypeEnum::toName(listenForEventType) -// //<< std::endl; -// } -// else { -// updatedListeners.push_back(*iter); -// } -// } -// -// if (updatedListeners.size() != listeners.size()) { -// m_eventListeners[listenForEventType] = updatedListeners; -// } -// -// -// EVENT_LISTENER_CONTAINER processedListeners = m_eventProcessedListeners[listenForEventType]; -// -// /* -// * Remove the listener by creating a new container -// * of non-matching listeners. -// */ -// EVENT_LISTENER_CONTAINER updatedProcessedListeners; -// for (EVENT_LISTENER_CONTAINER_ITERATOR iter = processedListeners.begin(); -// iter != processedListeners.end(); -// iter++) { -// if (*iter == eventListener) { -// //std::cout << "Removing listener from class " -// //<< typeid(*eventListener).name() -// //<< " for " -// //<< EventTypeEnum::toName(listenForEventType) -// //<< std::endl; -// } -// else { -// updatedProcessedListeners.push_back(*iter); -// } -// } -// -// if (updatedProcessedListeners.size() != processedListeners.size()) { -// m_eventProcessedListeners[listenForEventType] = updatedProcessedListeners; -// } #elif CONTAINER_HASH_SET m_eventListeners[listenForEventType].erase(eventListener); m_eventProcessedListeners[listenForEventType].erase(eventListener); @@ -374,11 +310,6 @@ EventManager::sendEvent(Event* event) const AString eventNumberString = AString::number(m_eventIssuedCounter); - // Too many prints (JWH) - //AString msg = (eventMessagePrefix + " SENT."); - //CaretLogFiner(msg); - //std::cout << msg << std::endl; - /* * Send event to each of the listeners. */ @@ -386,14 +317,7 @@ EventManager::sendEvent(Event* event) iter != listeners.end(); iter++) { EventListenerInterface* listener = *iter; - - //std::cout << "Sending event from class " - //<< typeid(*listener).name() - //<< " for " - //<< EventTypeEnum::toName(eventType) - //<< std::endl; - - + listener->receiveEvent(event); if (event->isError()) { @@ -414,14 +338,6 @@ EventManager::sendEvent(Event* event) iter != processedListeners.end(); iter++) { EventListenerInterface* listener = *iter; - - //std::cout << "Sending event from class " - //<< typeid(*listener).name() - //<< " for " - //<< EventTypeEnum::toName(eventType) - //<< std::endl; - - listener->receiveEvent(event); if (event->isError()) { @@ -431,7 +347,6 @@ EventManager::sendEvent(Event* event) } } else { - // Too many prints (JWH) CaretLogFine("Event " + eventNumberString + " not processed: " + event->toString()); } m_eventIssuedCounter++; @@ -611,4 +526,35 @@ EventManager::getEventIssuedCounter() const return m_eventIssuedCounter; } +/** + * Verify that all listeners have been removed from the given event listener. + * + * @param eventListener + * The event listener. + */ +void +EventManager::verifyAllListenersRemoved(EventListenerInterface* eventListener) +{ + AString eventNames; + + for (int32_t i = 0; i < EventTypeEnum::EVENT_COUNT; i++) { + const EventTypeEnum::Enum eventType = static_cast(i); + if ((m_eventListeners[eventType].find(eventListener) != m_eventListeners[eventType].end()) + || (m_eventProcessedListeners[eventType].find(eventListener) != m_eventProcessedListeners[eventType].end())) { + eventNames.appendWithNewLine(" " + + EventTypeEnum::toName(eventType)); + } + } + + if ( ! eventNames.isEmpty()) { + SystemBacktrace myBacktrace; + SystemUtilities::getBackTrace(myBacktrace); + + CaretLogSevere("Failed to remove events from class instance. Event names:\n" + + eventNames + + ":\n" + + myBacktrace.toSymbolString()); + } +} + diff --git a/src/Common/EventManager.h b/src/Common/EventManager.h index 1b4056369..bc295eece 100644 --- a/src/Common/EventManager.h +++ b/src/Common/EventManager.h @@ -99,6 +99,8 @@ namespace caret { virtual ~EventManager(); + void verifyAllListenersRemoved(EventListenerInterface* eventListener); + /** * Define the container */ @@ -137,6 +139,8 @@ namespace caret { static EventManager* s_singletonEventManager; + friend EventListenerInterface; + }; #ifdef __EVENT_MANAGER_MAIN__ diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index c142cd7d0..5ace201c2 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -155,6 +155,8 @@ m_lineSeriesContentType(lineSeriesContentType) */ ChartableTwoFileLineSeriesChart::~ChartableTwoFileLineSeriesChart() { + EventManager::get()->removeEventFromListener(this, + EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA); } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index f11ddbf3b..93d375ee7 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -362,6 +362,8 @@ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(Bra */ BrainBrowserWindowToolBarChartTwoAxes::~BrainBrowserWindowToolBarChartTwoAxes() { + EventManager::get()->removeEventFromListener(this, + EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** -- GitLab From 4e286aa9428942ac751ce7c11e04c69c2d36c086 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 20 Dec 2017 10:39:42 -0600 Subject: [PATCH 556/755] Fixed crash in conversion of lines to polygonal lines. The last point in a border failed to project which caused an out of bounds index. --- src/Graphics/GraphicsOpenGLPolylineTriangles.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index a8a6fc2a0..5d0318a9b 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -1327,7 +1327,14 @@ GraphicsOpenGLPolylineTriangles::convertLineSegmentsToTriangles() std::vector restartVertexFlags(numVertices, false); for (auto index : m_vertexPrimitiveRestartIndices) { - restartVertexFlags[index] = true; + /* + * The caller may add a primtive restart at the last vertex + * which may be equal to numVertices. + */ + if (index < numVertices) { + CaretAssertVectorIndex(restartVertexFlags, index); + restartVertexFlags[index] = true; + } } const bool restartEnabledFlag = true; -- GitLab From 2e991aa9e071839e24e02c7226280c3461db464c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 20 Dec 2017 16:16:16 -0600 Subject: [PATCH 557/755] Updates for content of windows/tabs/viewports that will be used to fix WB-764 Selection in Tab but not aspect ratio Tab and probably for other Jira issues for window margins, tab margins, and titles --- src/Brain/BrainOpenGL.cxx | 15 +- src/Brain/BrainOpenGL.h | 12 +- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 15 +- .../BrainOpenGLChartTwoDrawingFixedPipeline.h | 6 +- .../BrainOpenGLChartTwoDrawingInterface.h | 4 - src/Brain/BrainOpenGLFixedPipeline.cxx | 37 ++- src/Brain/BrainOpenGLFixedPipeline.h | 22 +- src/Brain/BrainOpenGLViewportContent.cxx | 2 +- src/Brain/BrainOpenGLViewportContent.h | 16 +- src/Brain/BrainOpenGLWindowContent.cxx | 232 ++++++++++++++++++ src/Brain/BrainOpenGLWindowContent.h | 83 +++++++ src/Brain/CMakeLists.txt | 2 + src/GuiQt/BrainOpenGLWidget.cxx | 190 ++++++++++---- src/GuiQt/BrainOpenGLWidget.h | 12 +- src/Operations/OperationShowScene.cxx | 7 +- 15 files changed, 545 insertions(+), 110 deletions(-) create mode 100644 src/Brain/BrainOpenGLWindowContent.cxx create mode 100644 src/Brain/BrainOpenGLWindowContent.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 97a8f5a3b..83adb4b2e 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -208,13 +208,20 @@ BrainOpenGL::receiveEvent(Event* event) void BrainOpenGL::drawModels(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - std::vector& viewportContents) + const std::vector& viewportContents) { m_contextSharingGroupPointer = contextSharingGroupPointer; + const std::vector vpContents(viewportContents.begin(), + viewportContents.end()); +// for (const auto& vp : viewportContents) { +// vpContents.push_back(vp); +// } + + drawModelsImplementation(windowIndex, brain, - viewportContents); + vpContents); deleteUnusedOpenGLNames(); @@ -247,7 +254,7 @@ void BrainOpenGL::drawModels(const int32_t windowIndex, void BrainOpenGL::selectModel(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) @@ -290,7 +297,7 @@ void BrainOpenGL::selectModel(const int32_t windowIndex, void BrainOpenGL::projectToModel(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) diff --git a/src/Brain/BrainOpenGL.h b/src/Brain/BrainOpenGL.h index 19be603c1..f95bf5c51 100644 --- a/src/Brain/BrainOpenGL.h +++ b/src/Brain/BrainOpenGL.h @@ -105,12 +105,12 @@ namespace caret { void drawModels(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - std::vector& viewportContents); + const std::vector& viewportContents); void selectModel(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering); @@ -118,7 +118,7 @@ namespace caret { void projectToModel(const int32_t windowIndex, Brain* brain, void* contextSharingGroupPointer, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut); @@ -238,7 +238,7 @@ namespace caret { */ virtual void drawModelsImplementation(const int32_t windowIndex, Brain* brain, - std::vector& viewportContents) = 0; + const std::vector& viewportContents) = 0; /** * Selection on a model. @@ -263,7 +263,7 @@ namespace caret { */ virtual void selectModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) = 0; @@ -289,7 +289,7 @@ namespace caret { */ virtual void projectToModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) = 0; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index d7b687bba..3b9db50eb 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -82,9 +82,13 @@ static bool debugFlag = false; /** * Constructor. + * + * @param viewportContent + * The content of the viewport. */ -BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline() -: BrainOpenGLChartTwoDrawingInterface() +BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLViewportContent* viewportContent) +: BrainOpenGLChartTwoDrawingInterface(), +m_viewportContent(viewportContent) { m_preferences = SessionManager::get()->getCaretPreferences(); @@ -104,8 +108,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin * * @param brain * Brain. - * @param viewportContent - * Content of the viewport * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing @@ -119,7 +121,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipelin */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, - BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, @@ -129,7 +130,8 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, annotationsOut.clear(); m_annotationsForDrawingOutput.clear(); - BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); + CaretAssert(m_viewportContent); + BrowserTabContent* browserTabContent = m_viewportContent->getBrowserTabContent(); CaretAssert(browserTabContent); CaretAssert(brain); CaretAssert(browserTabContent); @@ -137,7 +139,6 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, CaretAssert(fixedPipelineDrawing); m_brain = brain; - m_viewportContent = viewportContent; m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = fixedPipelineDrawing->getTextRenderer(); diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h index 7ad9b7474..807efd64b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h @@ -34,6 +34,7 @@ namespace caret { class Annotation; class AnnotationPercentSizeText; + class BrainOpenGLViewportContent; class BrowserTabContent; class CaretPreferences; class ChartTwoCartesianAxis; @@ -52,12 +53,11 @@ namespace caret { class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { public: - BrainOpenGLChartTwoDrawingFixedPipeline(); + BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLViewportContent* viewportContent); virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, - BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, @@ -274,7 +274,7 @@ namespace caret { Brain* m_brain; - BrainOpenGLViewportContent* m_viewportContent; + const BrainOpenGLViewportContent* m_viewportContent; BrowserTabContent* m_browserTabContent; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h index 47d58a0c5..5ae58d329 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingInterface.h +++ b/src/Brain/BrainOpenGLChartTwoDrawingInterface.h @@ -32,7 +32,6 @@ namespace caret { class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; - class BrainOpenGLViewportContent; class ModelChartTwo; class BrainOpenGLChartTwoDrawingInterface { @@ -47,8 +46,6 @@ namespace caret { * * @param brain * Brain. - * @param browserTabContent - * Content of the browser tab. * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing @@ -62,7 +59,6 @@ namespace caret { * by the Annotation OpenGL Drawing. */ virtual void drawChartOverlaySet(Brain* brain, - BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index eca08ea62..76d380f5e 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -245,7 +245,7 @@ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() void BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) @@ -260,7 +260,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, m_specialCaseGraphicsAnnotations.clear(); - std::vector viewportContentsVector; + std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); setAnnotationColorBarsForDrawing(viewportContentsVector); @@ -323,7 +323,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, void BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) @@ -404,7 +404,7 @@ BrainOpenGLFixedPipeline::loadObjectToWindowTransform(EventOpenGLObjectToWindowT * the given viewport content. */ void -BrainOpenGLFixedPipeline::updateForegroundAndBackgroundColors(BrainOpenGLViewportContent* vpContent) +BrainOpenGLFixedPipeline::updateForegroundAndBackgroundColors(const BrainOpenGLViewportContent* vpContent) { /* * Default to colors for surface @@ -490,7 +490,7 @@ BrainOpenGLFixedPipeline::setTabViewport(const BrainOpenGLViewportContent* vpCon * Output with window color bars in the viewports. */ void -BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vector& /*viewportContents*/) +BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector& /*viewportContents*/) { m_annotationColorBarsForDrawing.clear(); @@ -518,7 +518,7 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(std::vector& viewportContents) + const std::vector& viewportContents) { m_brain = brain; m_windowIndex = windowIndex; @@ -575,7 +575,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, /* * Viewport of window. */ - BrainOpenGLViewportContent* vpContent = viewportContents[i]; + const BrainOpenGLViewportContent* vpContent = viewportContents[i]; setTabViewport(vpContent); glViewport(m_tabViewport[0], m_tabViewport[1], m_tabViewport[2], m_tabViewport[3]); @@ -644,7 +644,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, /* * Viewport of window. */ - BrainOpenGLViewportContent* vpContent = viewportContents[i]; + const BrainOpenGLViewportContent* vpContent = viewportContents[i]; setTabViewport(vpContent); /* @@ -761,7 +761,7 @@ BrainOpenGLFixedPipeline::drawTabHighlighting(const float width, * Viewport content */ void -BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(BrainOpenGLViewportContent* viewportContent) +BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLViewportContent* viewportContent) { glPushAttrib(GL_VIEWPORT_BIT); @@ -826,7 +826,7 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(BrainOpenGLViewpor * Viewport content */ void -BrainOpenGLFixedPipeline::drawTabAnnotations(BrainOpenGLViewportContent* tabContent) +BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* tabContent) { if (tabContent->getBrowserTabContent() == NULL) { return; @@ -949,7 +949,7 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) */ void BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, - BrainOpenGLViewportContent* viewportContent) + const BrainOpenGLViewportContent* viewportContent) { ElapsedTimer et; et.start(); @@ -5337,7 +5337,7 @@ BrainOpenGLFixedPipeline::drawChartOneData(BrowserTabContent* browserTabContent, * The viewport (x, y, width, height) */ void -BrainOpenGLFixedPipeline::drawChartTwoData(BrainOpenGLViewportContent* viewportContent, +BrainOpenGLFixedPipeline::drawChartTwoData(const BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartModel, const int32_t viewport[4]) { @@ -5346,9 +5346,8 @@ BrainOpenGLFixedPipeline::drawChartTwoData(BrainOpenGLViewportContent* viewportC CaretAssert(chartModel); std::vector annotationFromChartDrawing; - BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing; + BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing(viewportContent); chartDrawing.drawChartOverlaySet(m_brain, - viewportContent, chartModel, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, @@ -6196,7 +6195,7 @@ BrainOpenGLFixedPipeline::drawSquare(const uint8_t rgba[4], * Viewport content which image is displayed. */ void -BrainOpenGLFixedPipeline::drawBackgroundImage(BrainOpenGLViewportContent* vpContent) +BrainOpenGLFixedPipeline::drawBackgroundImage(const BrainOpenGLViewportContent* vpContent) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc == NULL) { @@ -6245,9 +6244,9 @@ BrainOpenGLFixedPipeline::drawBackgroundImage(BrainOpenGLViewportContent* vpCont /** * Draw the given image in the given viewport. * - * @param viewport - * The viewport dimensions. - * @param image + * @param vpContent + * The viewport content. + * @param imageFile * The QImage that is drawn. * @param windowZ * Z-position for image. @@ -6261,7 +6260,7 @@ BrainOpenGLFixedPipeline::drawBackgroundImage(BrainOpenGLViewportContent* vpCont * Opacity. */ void -BrainOpenGLFixedPipeline::drawImage(BrainOpenGLViewportContent* vpContent, +BrainOpenGLFixedPipeline::drawImage(const BrainOpenGLViewportContent* vpContent, ImageFile* imageFile, const float windowZ, const float frontZ, diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 02fbccb40..d21a0aefa 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -117,18 +117,18 @@ namespace caret { protected: void drawModelsImplementation(const int32_t windowIndex, Brain* brain, - std::vector& viewportContents) override; + const std::vector& viewportContents) override; void selectModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) override; void projectToModelImplementation(const int32_t windowIndex, Brain* brain, - BrainOpenGLViewportContent* viewportContent, + const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) override; @@ -181,7 +181,7 @@ namespace caret { FiberOrientationDisplayInfo& dispInfo); void drawModelInternal(Mode mode, - BrainOpenGLViewportContent* viewportContent); + const BrainOpenGLViewportContent* viewportContent); void initializeMembersBrainOpenGL(); @@ -189,7 +189,7 @@ namespace caret { ModelChart* chartData, const int32_t viewport[4]); - void drawChartTwoData(BrainOpenGLViewportContent* viewportContent, + void drawChartTwoData(const BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartData, const int32_t viewport[4]); @@ -448,13 +448,13 @@ namespace caret { void drawWindowAnnotations(const int windowViewport[4]); - void drawTabAnnotations(BrainOpenGLViewportContent* tabContent); + void drawTabAnnotations(const BrainOpenGLViewportContent* tabContent); - void drawChartCoordinateSpaceAnnotations(BrainOpenGLViewportContent* viewportContent); + void drawChartCoordinateSpaceAnnotations(const BrainOpenGLViewportContent* viewportContent); - void drawBackgroundImage(BrainOpenGLViewportContent* vpContent); + void drawBackgroundImage(const BrainOpenGLViewportContent* vpContent); - void drawImage(BrainOpenGLViewportContent* vpContent, + void drawImage(const BrainOpenGLViewportContent* vpContent, ImageFile* imageFile, const float windowZ, const float frontZ, @@ -496,11 +496,11 @@ namespace caret { const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex) const; - void updateForegroundAndBackgroundColors(BrainOpenGLViewportContent* vpContent); + void updateForegroundAndBackgroundColors(const BrainOpenGLViewportContent* vpContent); void setTabViewport(const BrainOpenGLViewportContent* vpContent); - void setAnnotationColorBarsForDrawing(std::vector& viewportContents); + void setAnnotationColorBarsForDrawing(const std::vector& viewportContents); void drawTabHighlighting(const float width, const float height, diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index c03e212f3..3ae324660 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -343,7 +343,7 @@ BrainOpenGLViewportContent::getChartDataMatricesAndViewport(Matrix4x4& chartData void BrainOpenGLViewportContent::setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, const Matrix4x4& chartDataModelViewMatrix, - const int chartViewport[4]) + const int chartViewport[4]) const { m_chartDataProjectionMatrix = chartDataProjectionMatrix; m_chartDataModelViewMatrix = chartDataModelViewMatrix; diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index 504623e00..c1e65e43c 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -47,7 +47,7 @@ namespace caret { void setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, const Matrix4x4& chartDataModelViewMatrix, - const int chartViewport[4]); + const int chartViewport[4]) const; void getModelViewport(int modelViewportOut[4]) const; @@ -156,19 +156,19 @@ namespace caret { int m_tabHeight; /** Chart data viewport's X-coordinate */ - int m_chartDataX; + mutable int m_chartDataX; /** Chart data viewport's Y-coordinate */ - int m_chartDataY; + mutable int m_chartDataY; /** Chart data viewport's Width */ - int m_chartDataWidth; + mutable int m_chartDataWidth; /** Chart data viewport's Height */ - int m_chartDataHeight; + mutable int m_chartDataHeight; /** Chart data viewport's validity */ - bool m_chartDataViewportValidFlag = false; + mutable bool m_chartDataViewportValidFlag = false; /** Chart data transformation matrix */ - Matrix4x4 m_chartDataModelViewMatrix; + mutable Matrix4x4 m_chartDataModelViewMatrix; /** Chart data transformation matrix */ - Matrix4x4 m_chartDataProjectionMatrix; + mutable Matrix4x4 m_chartDataProjectionMatrix; /** Model viewport's X-coordinate */ int m_modelX; diff --git a/src/Brain/BrainOpenGLWindowContent.cxx b/src/Brain/BrainOpenGLWindowContent.cxx new file mode 100644 index 000000000..89eebccab --- /dev/null +++ b/src/Brain/BrainOpenGLWindowContent.cxx @@ -0,0 +1,232 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ +#include "BrainOpenGLWindowContent.h" +#undef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::BrainOpenGLWindowContent + * \brief Content of window and its tabs. + * \ingroup Brain + */ + +/** + * Constructor. + */ +BrainOpenGLWindowContent::BrainOpenGLWindowContent() +: CaretObject() +{ + +} + +/** + * Destructor. + */ +BrainOpenGLWindowContent::~BrainOpenGLWindowContent() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +BrainOpenGLWindowContent::BrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj) +: CaretObject(obj) +{ + this->copyHelperBrainOpenGLWindowContent(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +BrainOpenGLWindowContent& +BrainOpenGLWindowContent::operator=(const BrainOpenGLWindowContent& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperBrainOpenGLWindowContent(obj); + } + return *this; +} + +/** + * Clear the content of the window and tabs. + */ +void +BrainOpenGLWindowContent::clear() +{ + m_tabViewports.clear(); + m_windowViewport.reset(); +} + +/** + * Add a tab viewport. + * + * @param tabViewport + * Tab viewport to add. + */ +void +BrainOpenGLWindowContent::addTabViewport(BrainOpenGLViewportContent* tabViewport) +{ + std::unique_ptr ptr(tabViewport); + m_tabViewports.push_back(std::move(ptr)); +} + +/** + * Set the window viewport. + * + * @param windowViewport + * The new window viewport. + */ +void +BrainOpenGLWindowContent::setWindowViewport(BrainOpenGLViewportContent* windowViewport) +{ + m_windowViewport.reset(windowViewport); +} + +/** + * @return Number of tab viewports. + */ +int32_t +BrainOpenGLWindowContent::getNumberOfTabViewports() const +{ + return m_tabViewports.size(); +} + +/** + * Get the viewport content for the tab at the given index. + * + * @param index + * Index of element in viewports BUT IS NOT the TAB INDEX + * @return + * Tab for the given index or NULL if not available. + */ +const BrainOpenGLViewportContent* +BrainOpenGLWindowContent::getTabViewportAtIndex(const int32_t index) const +{ + if ((index >= 0) + && (index < static_cast(m_tabViewports.size()))) { + CaretAssertVectorIndex(m_tabViewports, index); + return m_tabViewports[index].get(); + } + + return NULL; +} + +/** + * Get the tab viewport containing the given X/Y coordinates + * after lock aspect ratio has been performed on the tab viewport. + * + * @param x + * The X-coordinate + * @param y + * The Y-coordinate + * @return + * Tab viewport containing the coordinate or NULL if not found. + */ +const BrainOpenGLViewportContent* +BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, + const int32_t y) const +{ + for (const auto& vp : m_tabViewports) { + int32_t viewport[4]; + vp->getTabViewportBeforeApplyingMargins(viewport); + if ((x >= viewport[0]) + && (x < (viewport[0] + viewport[2])) + && (y >= viewport[1]) + && (y < (viewport[1] + viewport[3]))) { + return vp.get(); + } + } + return NULL; +} + + +/** + * All viewports for all tabs. + */ +std::vector +BrainOpenGLWindowContent::getAllTabViewports() const +{ + std::vector allTabs; + + for (auto& vp : m_tabViewports) { + allTabs.push_back(vp.get()); + } + + return allTabs; +} + + +/** + * @return The viewport for the window (could be NULL). + */ +const BrainOpenGLViewportContent* +BrainOpenGLWindowContent::getWindowViewport() const +{ + return m_windowViewport.get(); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +BrainOpenGLWindowContent::copyHelperBrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj) +{ + clear(); + + if (obj.m_windowViewport) { + setWindowViewport(new BrainOpenGLViewportContent(*obj.m_windowViewport.get())); + } + + for (const auto& tabvp : obj.m_tabViewports) { + BrainOpenGLViewportContent* vp(NULL); + const BrainOpenGLViewportContent* ptr = tabvp.get(); + if (ptr != NULL) { + vp = new BrainOpenGLViewportContent(*ptr); + } + addTabViewport(vp); + } +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +BrainOpenGLWindowContent::toString() const +{ + return "BrainOpenGLWindowContent"; +} + diff --git a/src/Brain/BrainOpenGLWindowContent.h b/src/Brain/BrainOpenGLWindowContent.h new file mode 100644 index 000000000..9109f795d --- /dev/null +++ b/src/Brain/BrainOpenGLWindowContent.h @@ -0,0 +1,83 @@ +#ifndef __BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ +#define __BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2017 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "BrainOpenGLViewportContent.h" +#include "CaretObject.h" + + + +namespace caret { + + class BrainOpenGLWindowContent : public CaretObject { + + public: + BrainOpenGLWindowContent(); + + virtual ~BrainOpenGLWindowContent(); + + BrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj); + + BrainOpenGLWindowContent& operator=(const BrainOpenGLWindowContent& obj); + + void clear(); + + void addTabViewport(BrainOpenGLViewportContent* tabsViewportContent); + + void setWindowViewport(BrainOpenGLViewportContent* windowViewportContent); + + int32_t getNumberOfTabViewports() const; + + const BrainOpenGLViewportContent* getTabViewportAtIndex(const int32_t index) const; + + const BrainOpenGLViewportContent* getTabViewportWithLockAspectXY(const int32_t x, + const int32_t y) const; + + const BrainOpenGLViewportContent* getWindowViewport() const; + + std::vector getAllTabViewports() const; + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperBrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj); + + std::vector> m_tabViewports; + + std::unique_ptr m_windowViewport; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ + // +#endif // __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ + +} // namespace +#endif //__BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index cb789c816..06d09803f 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -48,6 +48,7 @@ BrainOpenGLTextRenderInterface.h BrainOpenGLViewportContent.h BrainOpenGLVolumeObliqueSliceDrawing.h BrainOpenGLVolumeSliceDrawing.h +BrainOpenGLWindowContent.h BrainStructure.h BrainStructureNodeAttributes.h BrowserTabContent.h @@ -195,6 +196,7 @@ BrainOpenGLTextRenderInterface.cxx BrainOpenGLViewportContent.cxx BrainOpenGLVolumeObliqueSliceDrawing.cxx BrainOpenGLVolumeSliceDrawing.cxx +BrainOpenGLWindowContent.cxx BrainStructure.cxx BrainStructureNodeAttributes.cxx BrowserTabContent.cxx diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index b82989edf..ba66d1ee8 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -430,11 +430,7 @@ BrainOpenGLWidget::getBorderBeingDrawn() void BrainOpenGLWidget::clearDrawingViewportContents() { - const int32_t num = static_cast(this->drawingViewportContents.size()); - for (int32_t i = 0; i < num; i++) { - delete this->drawingViewportContents[i]; - } - this->drawingViewportContents.clear(); + m_windowContent.clear(); } /** @@ -473,13 +469,18 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, return image; } - int32_t viewport[4] = { 0, 0, imageWidth, imageHeight }; + const int32_t viewport[4] = { 0, 0, imageWidth, imageHeight }; std::vector viewportContent = getDrawingViewportContent(viewport); + BrainOpenGLWindowContent windowContent; + getDrawingWindowContent(viewport, + windowContent); + s_singletonOpenGL->drawModels(this->windowIndex, GuiManager::get()->getBrain(), m_contextShareGroupPointer, - viewportContent); + windowContent.getAllTabViewports()); + // viewportContent); for (auto vp : viewportContent) { delete vp; @@ -503,7 +504,7 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, * Viewport for drawing */ std::vector -BrainOpenGLWidget::getDrawingViewportContent(int32_t windowViewport[4]) const +BrainOpenGLWidget::getDrawingViewportContent(const int32_t windowViewportIn[4]) const { std::vector viewportContent; @@ -516,6 +517,13 @@ BrainOpenGLWidget::getDrawingViewportContent(int32_t windowViewport[4]) const return viewportContent; } + int32_t windowViewport[4] = { + windowViewportIn[0], + windowViewportIn[1], + windowViewportIn[2], + windowViewportIn[3] + }; + if (bbw->isAspectRatioLocked()) { const float aspectRatio = bbw->getAspectRatio(); if (aspectRatio > 0.0) { @@ -585,6 +593,115 @@ BrainOpenGLWidget::getDrawingViewportContent(int32_t windowViewport[4]) const return viewportContent; } +/** + * Get the content for drawing the window. + * + * @param windowViewport + * Viewport of the window. + * @param windowContent + * Window content that is updated with window and its tabs. + */ +void +BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], + BrainOpenGLWindowContent& windowContent) const +{ + windowContent.clear(); + + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); + + EventBrowserWindowContentGet getModelEvent(this->windowIndex); + EventManager::get()->sendEvent(getModelEvent.getPointer()); + + if (getModelEvent.isError()) { + return; + } + + int32_t windowViewport[4] = { + windowViewportIn[0], + windowViewportIn[1], + windowViewportIn[2], + windowViewportIn[3] + }; + + if (bbw->isAspectRatioLocked()) { + const float aspectRatio = bbw->getAspectRatio(); + if (aspectRatio > 0.0) { + BrainOpenGLViewportContent::adjustViewportForAspectRatio(windowViewport, + aspectRatio); + } + } + + /* + * Highlighting of border points + */ + s_singletonOpenGL->setDrawHighlightedEndPoints(false); + if (this->selectedUserInputProcessor == this->userInputBordersModeProcessor) { + s_singletonOpenGL->setDrawHighlightedEndPoints(this->userInputBordersModeProcessor->isHighlightBorderEndPoints()); + } + + const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); + + const int32_t numToDraw = getModelEvent.getNumberOfItemsToDraw(); + if (numToDraw == 1) { + BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(getModelEvent.getTabContentToDraw(0), + gapsAndMargins, + this->windowIndex, + windowViewport); + windowContent.addTabViewport(vc); + } + else if (numToDraw > 1) { + const int32_t windowWidth = windowViewport[2]; + const int32_t windowHeight = windowViewport[3]; + + std::vector rowHeights; + std::vector columnsWidths; + + /* + * Determine if default configuration for tiles + */ + TileTabsConfiguration* tileTabsConfiguration = getModelEvent.getTileTabsConfiguration(); + CaretAssert(tileTabsConfiguration); + + /* + * Get the sizes of the tab tiles from the tile tabs configuration + */ + if (tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numToDraw, + rowHeights, + columnsWidths)) { + + /* + * Create the viewport drawing contents for all tabs + */ + std::vector allTabs; + for (int32_t i = 0; i < getModelEvent.getNumberOfItemsToDraw(); i++) { + allTabs.push_back(getModelEvent.getTabContentToDraw(i)); + } + + std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, + tileTabsConfiguration, + gapsAndMargins, + windowIndex, + windowViewport, + getModelEvent.getTabIndexForTileTabsHighlighting()); + for (auto tabvp : tabViewportContent) { + windowContent.addTabViewport(tabvp); + } + } + else { + CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); + } + } + + BrainOpenGLViewportContent* windowViewportContent = BrainOpenGLViewportContent::createViewportForSingleTab(NULL, + gapsAndMargins, + windowIndex, + windowViewport); + windowContent.setWindowViewport(windowViewportContent); +} + + /** * Paints the graphics. */ @@ -602,14 +719,15 @@ BrainOpenGLWidget::paintGL() this->clearDrawingViewportContents(); - int windowViewport[4] = { + const int windowViewport[4] = { 0, 0, this->windowWidth[this->windowIndex], this->windowHeight[this->windowIndex] }; - this->drawingViewportContents = getDrawingViewportContent(windowViewport); + getDrawingWindowContent(windowViewport, + m_windowContent); if (this->selectedUserInputProcessor == userInputBordersModeProcessor) { s_singletonOpenGL->setBorderBeingDrawn(this->borderBeingDrawn); @@ -618,9 +736,9 @@ BrainOpenGLWidget::paintGL() s_singletonOpenGL->setBorderBeingDrawn(NULL); } s_singletonOpenGL->drawModels(this->windowIndex, - GuiManager::get()->getBrain(), - m_contextShareGroupPointer, - this->drawingViewportContents); + GuiManager::get()->getBrain(), + m_contextShareGroupPointer, + m_windowContent.getAllTabViewports()); /* * Issue browser window redrawn event @@ -688,7 +806,7 @@ BrainOpenGLWidget::contextMenuEvent(QContextMenuEvent* contextMenuEvent) const int mouseX = contextMenuEvent->x(); const int mouseY = this->height() - contextMenuEvent->y(); - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -730,7 +848,7 @@ BrainOpenGLWidget::wheelEvent(QWheelEvent* we) * out of its viewport without releasing the mouse * button. */ - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(wheelX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(wheelX, wheelY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -881,7 +999,7 @@ BrainOpenGLWidget::mousePressEvent(QMouseEvent* me) this->isMousePressedNearToolBox = true; } - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -946,7 +1064,7 @@ BrainOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) /* * Mouse button RELEASE event */ - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -969,7 +1087,7 @@ BrainOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) * out of its viewport without releasing the mouse * button. */ - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, this->mousePressY); if (viewportContent != NULL) { if ((absDX <= BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE) @@ -1034,7 +1152,7 @@ BrainOpenGLWidget::mouseDoubleClickEvent(QMouseEvent* me) * out of its viewport without releasing the mouse * button. */ - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -1081,23 +1199,12 @@ BrainOpenGLWidget::leaveEvent(QEvent* /*e*/) * @param y * Y-coordinate. */ -BrainOpenGLViewportContent* +const BrainOpenGLViewportContent* BrainOpenGLWidget::getViewportContentAtXY(const int x, const int y) { - BrainOpenGLViewportContent* viewportContent = NULL; - const int32_t num = static_cast(this->drawingViewportContents.size()); - for (int32_t i = 0; i < num; i++) { - int viewport[4]; - this->drawingViewportContents[i]->getTabViewportBeforeApplyingMargins(viewport); - if ((x >= viewport[0]) - && (x < (viewport[0] + viewport[2])) - && (y >= viewport[1]) - && (y < (viewport[1] + viewport[3]))) { - viewportContent = this->drawingViewportContents[i]; - break; - } - } + const BrainOpenGLViewportContent* viewportContent = m_windowContent.getTabViewportWithLockAspectXY(x, y); + return viewportContent; } @@ -1111,8 +1218,7 @@ BrainOpenGLWidget::getViewportContentAtXY(const int x, std::vector BrainOpenGLWidget::getViewportContent() const { - std::vector contentOut(this->drawingViewportContents.begin(), - this->drawingViewportContents.end()); + std::vector contentOut = m_windowContent.getAllTabViewports(); return contentOut; } @@ -1139,7 +1245,7 @@ BrainOpenGLWidget::performIdentification(const int x, const int y, const bool applySelectionBackgroundFiltering) { - BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); + const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); @@ -1194,7 +1300,7 @@ SelectionItemAnnotation* BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int y) { - BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); + const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); @@ -1261,7 +1367,7 @@ BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFi const int x, const int y) { - BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); + const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); @@ -1324,7 +1430,7 @@ BrainOpenGLWidget::performProjection(const int x, const int y, SurfaceProjectedItem& projectionOut) { - BrainOpenGLViewportContent* projectionViewport = this->getViewportContentAtXY(x, y); + const BrainOpenGLViewportContent* projectionViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing projection"); @@ -1404,7 +1510,7 @@ BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) * out of its viewport without releasing the mouse * button. */ - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, this->mousePressY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -1443,7 +1549,7 @@ BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) this->lastMouseY = mouseY; } else if (mouseButtons == Qt::NoButton) { - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, @@ -1468,7 +1574,7 @@ BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) } } - BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, + const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { m_mousePositionEvent.grabNew(new MouseEvent(viewportContent, diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 6cf53b6b4..39698cf52 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -22,6 +22,7 @@ */ /*LICENSE_END*/ +#include #include /* @@ -41,6 +42,7 @@ #include #include "BrainConstants.h" +#include "BrainOpenGLWindowContent.h" #include "CaretPointer.h" #include "EventListenerInterface.h" @@ -145,11 +147,14 @@ namespace caret { private: - std::vector getDrawingViewportContent(int32_t windowViewport[4]) const; + std::vector getDrawingViewportContent(const int32_t windowViewportIn[4]) const; + + void getDrawingWindowContent(const int32_t windowViewportIn[4], + BrainOpenGLWindowContent& windowContent) const; void clearDrawingViewportContents(); - BrainOpenGLViewportContent* getViewportContentAtXY(const int x, + const BrainOpenGLViewportContent* getViewportContentAtXY(const int x, const int y); void checkForMiddleMouseButton(Qt::MouseButtons& mouseButtons, @@ -161,7 +166,8 @@ namespace caret { const int32_t windowIndex; - std::vector drawingViewportContents; + //std::vector tabsViewportContent; + BrainOpenGLWindowContent m_windowContent; int32_t windowWidth[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; int32_t windowHeight[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 4a61c9863..420f4d9f5 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -37,6 +37,7 @@ #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLViewportContent.h" +#include "BrainOpenGLWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" @@ -482,10 +483,12 @@ OperationShowScene::useParameters(OperationParameters* myParams, windowViewport, tabIndexToHighlight); + std::vector constViewports(viewports.begin(), + viewports.end()); brainOpenGL->drawModels(windowIndex, brain, mesaContext, - viewports); + constViewports); const int32_t outputImageIndex = ((numBrowserClasses > 1) ? i @@ -537,7 +540,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, gapsAndMargins, windowIndex, windowViewport)); - std::vector viewportContents; + std::vector viewportContents; viewportContents.push_back(content); brainOpenGL->drawModels(windowIndex, -- GitLab From 3a88b5c972b40167d90d311a5853e803a62a2096 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 21 Dec 2017 09:06:59 -0600 Subject: [PATCH 558/755] A little more cleanup from the last commit, Updates for content of windows/tabs/viewports... --- src/GuiQt/BrainOpenGLWidget.cxx | 111 -------------------------------- 1 file changed, 111 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index ba66d1ee8..c4c689ca8 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -470,7 +470,6 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, } const int32_t viewport[4] = { 0, 0, imageWidth, imageHeight }; - std::vector viewportContent = getDrawingViewportContent(viewport); BrainOpenGLWindowContent windowContent; getDrawingWindowContent(viewport, @@ -480,12 +479,6 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, GuiManager::get()->getBrain(), m_contextShareGroupPointer, windowContent.getAllTabViewports()); - // viewportContent); - - for (auto vp : viewportContent) { - delete vp; - } - viewportContent.clear(); if (offscreen.isError()) { WuQMessageBox::errorOk(this, @@ -497,102 +490,6 @@ BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, return offscreen.getImage(); } -/** - * @return Content of viewport for drawing. - * - * @param windowViewport - * Viewport for drawing - */ -std::vector -BrainOpenGLWidget::getDrawingViewportContent(const int32_t windowViewportIn[4]) const -{ - std::vector viewportContent; - - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); - - EventBrowserWindowContentGet getModelEvent(this->windowIndex); - EventManager::get()->sendEvent(getModelEvent.getPointer()); - - if (getModelEvent.isError()) { - return viewportContent; - } - - int32_t windowViewport[4] = { - windowViewportIn[0], - windowViewportIn[1], - windowViewportIn[2], - windowViewportIn[3] - }; - - if (bbw->isAspectRatioLocked()) { - const float aspectRatio = bbw->getAspectRatio(); - if (aspectRatio > 0.0) { - BrainOpenGLViewportContent::adjustViewportForAspectRatio(windowViewport, - aspectRatio); - } - } - - /* - * Highlighting of border points - */ - s_singletonOpenGL->setDrawHighlightedEndPoints(false); - if (this->selectedUserInputProcessor == this->userInputBordersModeProcessor) { - s_singletonOpenGL->setDrawHighlightedEndPoints(this->userInputBordersModeProcessor->isHighlightBorderEndPoints()); - } - - const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); - - const int32_t numToDraw = getModelEvent.getNumberOfItemsToDraw(); - if (numToDraw == 1) { - BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(getModelEvent.getTabContentToDraw(0), - gapsAndMargins, - this->windowIndex, - windowViewport); - viewportContent.push_back(vc); - } - else if (numToDraw > 1) { - const int32_t windowWidth = windowViewport[2]; - const int32_t windowHeight = windowViewport[3]; - - std::vector rowHeights; - std::vector columnsWidths; - - /* - * Determine if default configuration for tiles - */ - TileTabsConfiguration* tileTabsConfiguration = getModelEvent.getTileTabsConfiguration(); - CaretAssert(tileTabsConfiguration); - - /* - * Get the sizes of the tab tiles from the tile tabs configuration - */ - if ( ! tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numToDraw, - rowHeights, - columnsWidths)) { - CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); - return viewportContent; - } - - /* - * Create the viewport drawing contents for all tabs - */ - std::vector allTabs; - for (int32_t i = 0; i < getModelEvent.getNumberOfItemsToDraw(); i++) { - allTabs.push_back(getModelEvent.getTabContentToDraw(i)); - } - - viewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, - tileTabsConfiguration, - gapsAndMargins, - windowIndex, - windowViewport, - getModelEvent.getTabIndexForTileTabsHighlighting()); - } - return viewportContent; -} - /** * Get the content for drawing the window. * @@ -1436,14 +1333,6 @@ BrainOpenGLWidget::performProjection(const int x, CaretLogFine("Performing projection"); if (projectionViewport != NULL) { - /* - * ID coordinate needs to be relative to the viewport - * - int vp[4]; - idViewport->getViewport(vp); - const int idX = x - vp[0]; - const int idY = y - vp[1]; - */ s_singletonOpenGL->projectToModel(this->windowIndex, GuiManager::get()->getBrain(), m_contextShareGroupPointer, -- GitLab From 1f1d9e19afa4c99647f387385dd5a35440a22cbc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 21 Dec 2017 09:33:23 -0600 Subject: [PATCH 559/755] Resolve WB-764 Selection in tab but not aspect ratio tab: If a selection (mouse click) is not within a tab (due to lock aspect ratio), then use the window's viewport for selection. --- src/GuiQt/BrainOpenGLWidget.cxx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index c4c689ca8..97f15ac8b 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1100,9 +1100,17 @@ const BrainOpenGLViewportContent* BrainOpenGLWidget::getViewportContentAtXY(const int x, const int y) { - const BrainOpenGLViewportContent* viewportContent = m_windowContent.getTabViewportWithLockAspectXY(x, y); + const BrainOpenGLViewportContent* tabViewportContent = m_windowContent.getTabViewportWithLockAspectXY(x, y); + if (tabViewportContent != NULL) { + return tabViewportContent; + } - return viewportContent; + /* + * If not in a tab, then use the window viewport information. + * This allows selection of annotations in window space that are not + * within a tab (tab may be small in height due to lock aspect). + */ + return m_windowContent.getWindowViewport(); } /** -- GitLab From 8d3f743ebf19dca3c7b7d9ab3bdc556d512a6614 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 26 Dec 2017 16:15:43 -0600 Subject: [PATCH 560/755] When the colorbar's Numeric Format is Auto, the number of digits right of the decimal in color bar numbers is determined by an algorithm. In some instances, ALL of the numbers will have only zeros to the right of the decimal point (numbers are integers). In these instances, remove the decimal point and zeros right of the decimal point (Show "-1 0 4" instead of "-1.0 0 4.0"). --- src/Common/NumericTextFormatting.cxx | 139 +++++++++++++++++++++++++++ src/Common/NumericTextFormatting.h | 14 +++ src/Palette/PaletteColorMapping.cxx | 67 +++++++------ 3 files changed, 188 insertions(+), 32 deletions(-) diff --git a/src/Common/NumericTextFormatting.cxx b/src/Common/NumericTextFormatting.cxx index 0e302e1d3..8d82b3ac3 100644 --- a/src/Common/NumericTextFormatting.cxx +++ b/src/Common/NumericTextFormatting.cxx @@ -294,6 +294,145 @@ NumericTextFormatting::getFormatAndPrecision(const float valueIn, } } +/** + * Format the negative and positive values by using the value of the range (min to max) + * to set format and precision for all values. + * + * @param numericFormatIn + * How to format the numbers when converted to text. + * @param numericFormatPrecisionIn + * Precision used the numeric format is not automatic. + * @param negativeValuesIn + * The negative input values array. Must be at least two elements and + * the values must be sorted from smallest to largest. + * @param negativeFormattedValuesOut + * Output containing negativevalues formatted as text. + * @param negativeBumberOfValues + * Number of negativevalues in the arrays and both the input and output + * arrays must sized to this value. + * @param positiveValuesIn + * The positive input values array. Must be at least two elements and + * the values must be sorted from smallest to largest. + * @param positiveFormattedValuesOut + * Output containing positive values formatted as text. + * @param positiveNumberOfValues + * Number of positive values in the arrays and both the input and output + * arrays must sized to this value. + */ +void +NumericTextFormatting::formatValueRangeNegPos(const NumericFormatModeEnum::Enum numericFormatIn, + const int32_t numericFormatPrecisionIn, + const float negativeValuesIn[], + AString negativeFormattedValuesOut[], + const int32_t negativeNumberOfValues, + const float positiveValuesIn[], + AString positiveFormattedValuesOut[], + const int32_t positiveNumberOfValues) +{ + NumericFormatModeEnum::Enum numericFormat = numericFormatIn; + int32_t numericFormatPrecision = numericFormatPrecisionIn; + + + if (negativeNumberOfValues > 0) { + formatValueRange(numericFormat, + numericFormatPrecision, + negativeValuesIn, + negativeFormattedValuesOut, + negativeNumberOfValues); + } + + if (positiveNumberOfValues > 0) { + formatValueRange(numericFormat, + numericFormatPrecision, + positiveValuesIn, + positiveFormattedValuesOut, + positiveNumberOfValues); + } + + switch (numericFormat) { + case NumericFormatModeEnum::AUTO: + removeDotZeroIfAllIntegers(negativeFormattedValuesOut, + negativeNumberOfValues, + positiveFormattedValuesOut, + positiveNumberOfValues); + break; + case NumericFormatModeEnum::DECIMAL: + break; + case NumericFormatModeEnum::SCIENTIFIC: + break; + } +} + +/** + * If all of the positive and negative text values represent integers + * (contain no decimal or end with decimal followed by zeros), + * strip off decimal and trailing zeros. + * + * @param negativeFormattedValues + * Negative values formatted as text. + * @param negativeBumberOfValues + * Number of negative values. + * @param positiveFormattedValues + * Positive values formatted as text. + * @param positiveNumberOfValues + * Number of positive values. + */ +void +NumericTextFormatting::removeDotZeroIfAllIntegers(AString negativeFormattedValues[], + const int32_t negativeNumberOfValues, + AString positiveFormattedValues[], + const int32_t positiveNumberOfValues) +{ + std::vector allValues(negativeFormattedValues, + negativeFormattedValues + negativeNumberOfValues); + allValues.insert(allValues.end(), + positiveFormattedValues, + positiveFormattedValues + positiveNumberOfValues); + + for (auto& text: allValues) { + const int32_t len = text.length(); + + /* + * Does this text end with a decimal followed by all zeros + */ + const int32_t decimalIndex = text.indexOf('.'); + if (decimalIndex >= 0) { + for (int32_t j = decimalIndex + 1; j < len; j++) { + if (text[j] != '0') { + /* + * Non-zero trailing value so not integer value + */ + return; + } + } + + if (decimalIndex >= 0) { + /* + * Chop off decimal and zeros + * "text" is a reference so changes value in allValues vector + */ + text.resize(decimalIndex); + } + else { + /* if no decimal found, then value is already integer */ + } + } + } + + for (int32_t i = 0; i < negativeNumberOfValues; i++) { + CaretAssertArrayIndex(negativeFormattedValues, negativeNumberOfValues, i); + CaretAssertVectorIndex(allValues, i); + negativeFormattedValues[i] = allValues[i]; + } + + for (int32_t i = 0; i < positiveNumberOfValues; i++) { + CaretAssertArrayIndex(positiveFormattedValues, positiveNumberOfValues, i); + const int32_t j = i + negativeNumberOfValues; + CaretAssertVectorIndex(allValues, j); + positiveFormattedValues[i] = allValues[j]; + } +} + /** * Format the values by using the value of the range (min to max) * to set format and precision for all values. diff --git a/src/Common/NumericTextFormatting.h b/src/Common/NumericTextFormatting.h index a7bea9c97..5d0d4b570 100644 --- a/src/Common/NumericTextFormatting.h +++ b/src/Common/NumericTextFormatting.h @@ -44,6 +44,15 @@ namespace caret { AString formattedValuesOut[], const int32_t numberOfValues); + static void formatValueRangeNegPos(const NumericFormatModeEnum::Enum numericFormat, + const int32_t numericFormatPrecision, + const float negativeValuesIn[], + AString negativeFormattedValuesOut[], + const int32_t negativeNumberOfValues, + const float positiveValuesIn[], + AString positiveFormattedValuesOut[], + const int32_t positiveNumberOfValues); + static AString formatValue(const float valueIn); static void formatValuesIndividually(const float valuesIn[], @@ -75,6 +84,11 @@ namespace caret { static void getFormatAndPrecision(const float valueIn, char& formatOut, int& precisionOut); + + static void removeDotZeroIfAllIntegers(AString negativeFormattedValues[], + const int32_t negativeNumberOfValues, + AString positiveFormattedValues[], + const int32_t positiveNumberOfValues); // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Palette/PaletteColorMapping.cxx b/src/Palette/PaletteColorMapping.cxx index 89c55a528..9bc8ddf55 100644 --- a/src/Palette/PaletteColorMapping.cxx +++ b/src/Palette/PaletteColorMapping.cxx @@ -1840,35 +1840,45 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic break; } + /* + * Types of values for display + */ + const bool positiveDataDisplayedFlag = isDisplayPositiveDataFlag(); + const bool negativeDataDisplayedFlag = isDisplayNegativeDataFlag(); + /* * numeric values displayed for negative data */ std::vector negativeValues; - negativeValues.push_back(negMax); - if (this->colorBarNumericSubdivisionCount > 0) { - const float range = negMin - negMax; - const float interval = range / (this->colorBarNumericSubdivisionCount + 1); - for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { - negativeValues.push_back(negMax - + (interval * (i + 1))); + if (negativeDataDisplayedFlag) { + negativeValues.push_back(negMax); + if (this->colorBarNumericSubdivisionCount > 0) { + const float range = negMin - negMax; + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { + negativeValues.push_back(negMax + + (interval * (i + 1))); + } } + negativeValues.push_back(negMin); } - negativeValues.push_back(negMin); /* * numeric values displayed for positive data */ std::vector positiveValues; - positiveValues.push_back(posMin); - if (this->colorBarNumericSubdivisionCount > 0) { - const float range = posMax - posMin; - const float interval = range / (this->colorBarNumericSubdivisionCount + 1); - for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { - positiveValues.push_back(posMin - + (interval * (i + 1))); + if (positiveDataDisplayedFlag) { + positiveValues.push_back(posMin); + if (this->colorBarNumericSubdivisionCount > 0) { + const float range = posMax - posMin; + const float interval = range / (this->colorBarNumericSubdivisionCount + 1); + for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { + positiveValues.push_back(posMin + + (interval * (i + 1))); + } } + positiveValues.push_back(posMax); } - positiveValues.push_back(posMax); /* * Will need to override these values when percentile @@ -1907,32 +1917,25 @@ PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistic */ const int32_t numberOfNegValues = static_cast(negativeValues.size()); std::vector negativeValuesText(numberOfNegValues); - NumericTextFormatting::formatValueRange(numericFormatModeForTextFormatting, - precisionDigitsForTextFormatting, - &negativeValues[0], - &negativeValuesText[0], - numberOfNegValues); /* * Create text representations for positive values */ const int32_t numberOfPosValues = static_cast(positiveValues.size()); std::vector positiveValuesText(numberOfPosValues); - NumericTextFormatting::formatValueRange(numericFormatModeForTextFormatting, - precisionDigitsForTextFormatting, - &positiveValues[0], - &positiveValuesText[0], - numberOfPosValues); + + NumericTextFormatting::formatValueRangeNegPos(numericFormatModeForTextFormatting, + precisionDigitsForTextFormatting, + &negativeValues[0], + &negativeValuesText[0], + numberOfNegValues, + &positiveValues[0], + &positiveValuesText[0], + numberOfPosValues); CaretAssert(negativeValues.size() == negativeValuesText.size()); CaretAssert(positiveValues.size() == positiveValuesText.size()); - /* - * Types of values for display - */ - const bool positiveDataDisplayedFlag = isDisplayPositiveDataFlag(); - const bool negativeDataDisplayedFlag = isDisplayNegativeDataFlag(); - /* * Are both negative and positive values displayed? */ -- GitLab From 28618c38b5ffd82588aa0a593f5fe17da36e9c7f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 28 Dec 2017 14:03:14 -0600 Subject: [PATCH 561/755] Some code with array initializer lists as parameters has been changed to create the array before the function call so that it will compile on Windows. --- .../BrainOpenGLChartTwoDrawingFixedPipeline.cxx | 6 ++++-- src/Graphics/GraphicsPrimitiveV3fC4f.cxx | 6 ++++-- src/Graphics/GraphicsPrimitiveV3fC4ub.cxx | 3 ++- src/Graphics/GraphicsPrimitiveV3fN3f.cxx | 12 ++++++++---- src/Graphics/GraphicsPrimitiveV3fT3f.cxx | 12 +++++++----- src/Graphics/GraphicsShape.cxx | 6 ++++-- src/GuiQt/OffScreenOpenGLRenderer.cxx | 2 ++ 7 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 3b9db50eb..41f4d3298 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -2339,8 +2339,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoo const float v2[3] = { vpX + vpWidth, vpY, 0.0f }; const float v3[3] = { vpX + vpWidth, vpY + vpHeight, 0.0f }; const float v4[3] = { vpX, vpY + vpHeight, 0.0f }; + const uint8_t rgba[4] { 255, 0, 0, 255}; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, - std::move((uint8_t[]){ 255, 0, 0, 255}), + rgba, GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); } @@ -2705,8 +2706,9 @@ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float const float v2[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1], 0.0f }; const float v3[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3], 0.0f }; const float v4[3] = { m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3], 0.0f }; + const uint8_t rgba[4] { 255, 0, 0, 255}; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, - std::move((uint8_t[]){ 255, 0, 0, 255}), + rgba, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } diff --git a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx index f108020fa..7a731e077 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4f.cxx @@ -117,7 +117,8 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float z, const float rgba[4]) { - addVertex(std::move((float[]){ x, y, z}), rgba); + const float xyz[] { x, y, z }; + addVertex(xyz, rgba); } /** @@ -135,7 +136,8 @@ GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float rgba[4]) { - addVertex(std::move((float[]){ x, y, 0.0f}), rgba); + const float xyz[] { x, y, 0.0f }; + addVertex(xyz, rgba); } /** diff --git a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx index baf145378..44a872d83 100644 --- a/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx @@ -117,7 +117,8 @@ GraphicsPrimitiveV3fC4ub::addVertex(const float x, const float z, const uint8_t rgba[4]) { - addVertex(std::move((float[]){x, y, z}), + const float xyz[] { x, y, z }; + addVertex(xyz, rgba); } diff --git a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx index ff9392b3b..2062aef84 100644 --- a/src/Graphics/GraphicsPrimitiveV3fN3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fN3f.cxx @@ -161,8 +161,10 @@ GraphicsPrimitiveV3fN3f::addVertex(const float x, const float normalY, const float normalZ) { - addVertexProtected(std::move((float[]){ x, y, z }), - std::move((float[]){ normalX, normalY, normalZ }), + const float xyz[] { x, y, z }; + const float normalXYZ[] { normalX, normalY, normalZ }; + addVertexProtected(xyz, + normalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); @@ -186,8 +188,10 @@ GraphicsPrimitiveV3fN3f::addVertex(const float x, const float normalX, const float normalY) { - addVertexProtected(std::move((float[]){ x, y, 0.0f }), - std::move((float[]){ normalX, normalY, 0.0f }), + const float xyz[] { x, y, 0.0f }; + const float normalXYZ[] { normalX, normalY, 1.0f }; + addVertexProtected(xyz, + normalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); diff --git a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx index 7b27ab649..c6de78752 100644 --- a/src/Graphics/GraphicsPrimitiveV3fT3f.cxx +++ b/src/Graphics/GraphicsPrimitiveV3fT3f.cxx @@ -103,11 +103,12 @@ void GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], const float st[2]) { + const float str[] { st[0], st[1], 0.0f } ; addVertexProtected(xyz, NULL, NULL, NULL, - std::move((float[]){ st[0], st[1], 0.0f })); + str); } /** @@ -131,8 +132,10 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertex(std::move((float[]){ x, y, z }), - std::move((float[]){ s, t })); + const float xyz[] { x, y, z }; + const float str[] { s, t, 0.0f }; + addVertex(xyz, + str); } /** @@ -153,8 +156,7 @@ GraphicsPrimitiveV3fT3f::addVertex(const float x, const float s, const float t) { - addVertex(std::move((float[]){ x, y, 0.0f }), - std::move((float[]){ s, t })); + addVertex(x, y, 0.0f, s, t); } /** diff --git a/src/Graphics/GraphicsShape.cxx b/src/Graphics/GraphicsShape.cxx index 4caafc4e5..dd58b47cb 100644 --- a/src/Graphics/GraphicsShape.cxx +++ b/src/Graphics/GraphicsShape.cxx @@ -796,8 +796,9 @@ GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, // const int32_t numberOfPoints = 8; const float step = (2.0 * M_PI) / numberOfDivisions; + const uint8_t rgba[] { 255, 255, 255, 255 }; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, - std::move((uint8_t[]) { 255, 255, 255, 255 })); + rgba); primitive->reserveForNumberOfVertices(numberOfDivisions + 2); /* * Generate points around ring @@ -837,8 +838,9 @@ GraphicsShape::createRingPrimitive(const RingKey& ringKey) */ const float step = (2.0 * M_PI) / ringKey.m_numberOfDivisions; + const uint8_t rgba[] { 255, 255, 255, 255 }; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, - std::move((uint8_t[]) { 255, 255, 255, 255 })); + rgba); primitive->reserveForNumberOfVertices((ringKey.m_numberOfDivisions + 1) * 2); /* * Generate points around ring diff --git a/src/GuiQt/OffScreenOpenGLRenderer.cxx b/src/GuiQt/OffScreenOpenGLRenderer.cxx index 37cec1b14..d2a4d891d 100644 --- a/src/GuiQt/OffScreenOpenGLRenderer.cxx +++ b/src/GuiQt/OffScreenOpenGLRenderer.cxx @@ -19,6 +19,8 @@ */ /*LICENSE_END*/ +#include "CaretOpenGLInclude.h" + #define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ #include "OffScreenOpenGLRenderer.h" #undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ -- GitLab From 66fd05dc69b0ddafccffda4d65955698e75f33d9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 2 Jan 2018 16:09:37 -0600 Subject: [PATCH 562/755] Resolve WB-733, Border draw mode sphere size modification: When drawing a new border, the spheres are now 3% of the maximum dimension of the surface. For a human, this is about 5mm. This should make the spheres a reasonable size for not just humans, but other species as well. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 76d380f5e..e754ab87f 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2658,6 +2658,18 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) this->windowTabIndex); } + if (borderDrawInfo.border == this->borderBeingDrawn) { + if (borderDrawInfo.surface != NULL) { + const BoundingBox* bb = borderDrawInfo.surface->getBoundingBox(); + const float maxSize = std::max(bb->getDifferenceX(), + std::max(bb->getDifferenceY(), bb->getDifferenceZ())); + if (maxSize > 0.0f) { + const float percentSize = 0.03f; + pointDiameter = maxSize * percentSize; + } + } + } + bool drawSphericalPoints = false; bool drawSquarePoints = false; bool drawLines = false; -- GitLab From afe0fee0548388a4e641778d3b0b7dc3e348a1cb Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 2 Jan 2018 16:11:11 -0600 Subject: [PATCH 563/755] Update for WB-633: Improved ToolTip for "Layer" checkbox on Overlay ToolBox --> Connectivity Tab. Also added tooltip to the corresponding default on Preferences. --- src/GuiQt/CiftiConnectivityMatrixViewController.cxx | 10 ++++++++-- src/GuiQt/PreferencesDialog.cxx | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/CiftiConnectivityMatrixViewController.cxx b/src/GuiQt/CiftiConnectivityMatrixViewController.cxx index 0d6938982..1780d2ad4 100644 --- a/src/GuiQt/CiftiConnectivityMatrixViewController.cxx +++ b/src/GuiQt/CiftiConnectivityMatrixViewController.cxx @@ -177,9 +177,15 @@ CiftiConnectivityMatrixViewController::updateViewController() "an identification operation"); m_fileEnableCheckBoxes.push_back(checkBox); + const AString dynToolTip("This option is enabled only for .dynconn.nii (dynamic connectivity) files. " + "When checked, this dynamic connectivity file will appear in the Overlay Layers' File selection combo box. " + "Dynamic connectivity files do not explicitly exist but allow dynamic " + "computation of connectivity from a dense data series (.dtseries) file. " + "Dynamic connectivity allows one to view connectivity for a brainordinate without creation of an " + "extremely large dense connectivity (.dconn.nii) file. " + "In Preferences, one may set the default to show/hide .dynconn.nii files."); layerCheckBox = new QCheckBox(""); - layerCheckBox->setToolTip("When selected, allow selection of this\n" - "file as an overlay in the Layers tab"); + WuQtUtilities::setWordWrappedToolTip(layerCheckBox, dynToolTip); m_layerCheckBoxes.push_back(layerCheckBox); lineEdit = new QLineEdit(); diff --git a/src/GuiQt/PreferencesDialog.cxx b/src/GuiQt/PreferencesDialog.cxx index 13e2d6e9a..7e696c33c 100644 --- a/src/GuiQt/PreferencesDialog.cxx +++ b/src/GuiQt/PreferencesDialog.cxx @@ -341,6 +341,8 @@ PreferencesDialog::createMiscellaneousWidget() QObject::connect(m_dynamicConnectivityComboBox, SIGNAL(statusChanged(bool)), this, SLOT(miscDynamicConnectivityComboBoxChanged(bool))); m_allWidgets->add(m_dynamicConnectivityComboBox); + m_dynamicConnectivityComboBox->setToolTip("Sets default (checked or unchecked) for dynamic connectivity files " + "on the Overlay ToolBox --> Connectivity tab."); /* * Logging Level @@ -400,7 +402,7 @@ PreferencesDialog::createMiscellaneousWidget() QGridLayout* gridLayout = new QGridLayout(); addWidgetToLayout(gridLayout, - "Show Dynconn By Default: ", + "Dynconn As Layer Default: ", m_dynamicConnectivityComboBox->getWidget()); addWidgetToLayout(gridLayout, "Logging Level: ", -- GitLab From f4caa3e2fc41c43835cba1eeec14ec85e04a1bd3 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 Jan 2018 12:33:58 -0600 Subject: [PATCH 564/755] Re-resolve WB-671 Smooth Histogram Envelopes: Envelope has been smoothed in the Map Settings Dialog's histogram. --- .../MapSettingsPaletteColorMappingWidget.cxx | 75 ++++++------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 4eed07a9b..64287cb1f 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -2055,33 +2055,7 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } } - // if (histogramColor != CaretColorEnum::CUSTOM) { - // /* - // * DO NOT override RGBA - // */ - // float colorRGBA[4]; - // CaretColorEnum::toRGBAFloat(histogramColor, - // colorRGBA); - // for (int64_t i = 0; i < numDataValues; i++) { - // const int64_t i4 = i * 4; - // dataRGBA[i4] = colorRGBA[0]; - // dataRGBA[i4+1] = colorRGBA[1]; - // dataRGBA[i4+2] = colorRGBA[2]; - // } - // } - } - - // const bool drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); - // bool drawEnvelopeFlag = false; - // const bool allowEnvelopeChartTypeFlag = true; - // if (allowEnvelopeChartTypeFlag) { - // drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); - // } - - // const QPalette palette = this->thresholdPlot->palette(); - // const QPalette::ColorRole foregroundRole = this->thresholdPlot->foregroundRole(); - // const QBrush foregroundBrush = palette.brush(foregroundRole); - // const QColor foregroundColor = foregroundBrush.color(); + } float z = 0.0; float maxDataFrequency = 0.0; @@ -2149,13 +2123,17 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() * set its frequncey value to a small value so that the plot * retains its shape and color is still slightly visible */ - //Qt::BrushStyle brushStyle = Qt::SolidPattern; if (dataRGBA[ix4+3] <= 0.0) { displayIt = false; } - if (displayIt == false) { - color.setAlpha(0); + if ( ! displayIt) { + if (drawBarsFlag) { + color.setAlpha(0); + } + if (drawEnvelopeFlag) { + dataFrequency = 0.0f; + } } QVector samples; @@ -2174,7 +2152,9 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() } if (drawEnvelopeFlag) { curve->setStyle(QwtPlotCurve::Lines); - //curve->setBrush(QBrush(color)); + + static float lastX = 0.0f; + static float lastY = 0.0f; /* * Left side @@ -2182,48 +2162,39 @@ MapSettingsPaletteColorMappingWidget::updateHistogramPlot() if (ix == 0) { samples.push_back(QPointF(startValue, 0.0)); samples.push_back(QPointF(startValue, dataFrequency)); + lastX = startValue; + lastY = dataFrequency; } else { CaretAssertVectorIndex(displayData, ix - 1); - const float lastFrequency = displayData[ix - 1]; - if (dataFrequency > lastFrequency) { - samples.push_back(QPointF(startValue, lastFrequency)); - samples.push_back(QPointF(startValue, dataFrequency)); - } + const float lastValue = dataValues[ix - 1]; + const float halfX = (startValue - lastValue) / 2.0f; + const float x = startValue + halfX; + const float y = dataFrequency; + samples.push_back(QPointF(lastX, lastY)); + samples.push_back(QPointF(x, y)); + lastX = x; + lastY = y; } - /* - * Horizontal Bar - */ - samples.push_back(QPointF(startValue, dataFrequency)); - samples.push_back(QPointF(stopValue, dataFrequency)); - /* * Right side */ if (ix == lastIndex) { samples.push_back(QPointF(stopValue, dataFrequency)); samples.push_back(QPointF(stopValue, 0.0)); - } - else { - CaretAssertVectorIndex(displayData, ix + 1); - const float nextFrequency = displayData[ix + 1]; - if (dataFrequency > nextFrequency) { - samples.push_back(QPointF(stopValue, dataFrequency)); - samples.push_back(QPointF(stopValue, nextFrequency)); - } + lastX = stopValue; + lastY = 0.0f; } } curve->setSamples(samples); - curve->attach(this->thresholdPlot); if (ix == 0) { z = curve->z(); } } - } z--; -- GitLab From cbbdc671a62c578adafda6b4b002744f4c82975b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 Jan 2018 14:56:43 -0600 Subject: [PATCH 565/755] The datatype was incorrect (integer) for the volume surface outline thicknesses (obsolete pixel and new millimeters). This has been corrected to float and fixes an issues with the outlines being "too thin" as part of WB-723 volume surface outline should scale with viewport height. --- src/Brain/VolumeSurfaceOutlineModel.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index cf2b8a4a8..180d03195 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -69,8 +69,8 @@ namespace caret { virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); - static const int32_t DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; - static const int32_t DEFAULT_LINE_THICKNESS_MILLIMETERS; + static const float DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; + static const float DEFAULT_LINE_THICKNESS_MILLIMETERS; private: VolumeSurfaceOutlineModel(const VolumeSurfaceOutlineModel&); @@ -95,8 +95,8 @@ namespace caret { }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ - const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; - const int32_t VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 0.5; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 0.5; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace -- GitLab From 50d921bfffc4ceba685396bd5581dfae2f9a59d2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 3 Jan 2018 15:12:59 -0600 Subject: [PATCH 566/755] Default the volume surface outline width to 1.0mm. --- src/Brain/VolumeSurfaceOutlineModel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index 180d03195..374b8be9a 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -96,7 +96,7 @@ namespace caret { #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; - const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 0.5; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 1.0; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace -- GitLab From 12dc97e20baffe06d6ff1aa53eefb0dc1b32bce6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 4 Jan 2018 09:00:57 -0600 Subject: [PATCH 567/755] Fixed flashing of graphics on Mac when in Annotate Mode, noticed mostly with viewing of a line chart. --- src/GuiQt/BrainOpenGLWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 97f15ac8b..e34ce031f 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1247,7 +1247,7 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, this->doneCurrent(); #else //updateCursor(); - //this->repaint(); + this->repaint(); //updateGL(); #endif -- GitLab From e2409a56960bf3035e4f6b39e41d8b976e489a9b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 4 Jan 2018 16:09:59 -0600 Subject: [PATCH 568/755] Preliminary implementation of WB-651 Cycle through sdseries without needing yoking layer: User can select by index or map name in chart overlay. --- src/Brain/ChartTwoOverlay.cxx | 192 +++++++++++++----- src/Files/ChartableTwoFileLineSeriesChart.cxx | 25 +++ src/Files/ChartableTwoFileLineSeriesChart.h | 2 + 3 files changed, 173 insertions(+), 46 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 4722bd658..35833ba0f 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -793,6 +793,8 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma if (m_selectedMapFile != NULL) { int32_t numMaps = 0; + ChartableTwoFileMatrixChart* matrixChart = NULL; + switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -815,57 +817,123 @@ ChartTwoOverlay::getSelectionDataPrivate(std::vector& ma } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { + /* + * Row/Column Scalar files use the matrix for line chart tracking + */ + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); + CaretAssert(lineChart); + + switch (lineChart->getLineSeriesContentType()) { + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + matrixChart = chartDelegate->getMatrixCharting(); + break; + } + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { - ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); - const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); - CaretAssert(matrixChart); - int32_t numRows = 0; - int32_t numCols = 0; - matrixChart->getMatrixDimensions(numRows, numCols); - - ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; - std::vector columnIndices; - std::vector rowIndices; - matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, - rowColumnDimension, - rowIndices, - columnIndices); - - switch (rowColumnDimension) { - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: - numMaps = numCols; - if ( ! columnIndices.empty()) { - selectedIndexTypeOut = SelectedIndexType::COLUMN; - selectedIndexOut = columnIndices[0]; - } - if (matrixChart->hasColumnSelection()) { - if (selectedFileMapNamesOut != NULL) { - for (int32_t i = 0; i < numMaps; i++) { - selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); - } + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + matrixChart = chartDelegate->getMatrixCharting(); +// const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); +// CaretAssert(matrixChart); +// int32_t numRows = 0; +// int32_t numCols = 0; +// matrixChart->getMatrixDimensions(numRows, numCols); +// +// ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; +// std::vector columnIndices; +// std::vector rowIndices; +// matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, +// rowColumnDimension, +// rowIndices, +// columnIndices); +// +// switch (rowColumnDimension) { +// case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: +// numMaps = numCols; +// if ( ! columnIndices.empty()) { +// selectedIndexTypeOut = SelectedIndexType::COLUMN; +// selectedIndexOut = columnIndices[0]; +// } +// if (matrixChart->hasColumnSelection()) { +// if (selectedFileMapNamesOut != NULL) { +// for (int32_t i = 0; i < numMaps; i++) { +// selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); +// } +// } +// } +// break; +// case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: +// numMaps = numRows; +// if ( ! rowIndices.empty()) { +// selectedIndexTypeOut = SelectedIndexType::ROW; +// selectedIndexOut = rowIndices[0]; +// } +// if (matrixChart->hasRowSelection()) { +// if (selectedFileMapNamesOut != NULL) { +// for (int32_t i = 0; i < numMaps; i++) { +// selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); +// } +// } +// } +// break; +// } + } + break; + } + + if (matrixChart != NULL) { + CaretAssert(matrixChart); + int32_t numRows = 0; + int32_t numCols = 0; + matrixChart->getMatrixDimensions(numRows, numCols); + + ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; + std::vector columnIndices; + std::vector rowIndices; + matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, + rowColumnDimension, + rowIndices, + columnIndices); + + switch (rowColumnDimension) { + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: + numMaps = numCols; + if ( ! columnIndices.empty()) { + selectedIndexTypeOut = SelectedIndexType::COLUMN; + selectedIndexOut = columnIndices[0]; + } + if (matrixChart->hasColumnSelection()) { + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); } } - break; - case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: - numMaps = numRows; - if ( ! rowIndices.empty()) { - selectedIndexTypeOut = SelectedIndexType::ROW; - selectedIndexOut = rowIndices[0]; - } - if (matrixChart->hasRowSelection()) { - if (selectedFileMapNamesOut != NULL) { - for (int32_t i = 0; i < numMaps; i++) { - selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); - } + } + break; + case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: + numMaps = numRows; + if ( ! rowIndices.empty()) { + selectedIndexTypeOut = SelectedIndexType::ROW; + selectedIndexOut = rowIndices[0]; + } + if (matrixChart->hasRowSelection()) { + if (selectedFileMapNamesOut != NULL) { + for (int32_t i = 0; i < numMaps; i++) { + selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); } } - break; - } + } + break; } - break; } + } selectedMapFileOut = m_selectedMapFile; @@ -905,6 +973,9 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, { m_selectedMapFile = selectedMapFile; if (m_selectedMapFile != NULL) { + ChartableTwoFileLineSeriesChart* lineSeriesChart = NULL; + ChartableTwoFileMatrixChart* matrixChart = NULL; + switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; @@ -914,19 +985,48 @@ ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + { + /* + * Row/Column Scalar files use the matrix for line chart tracking + */ + ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); + ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); + CaretAssert(lineChart); + + switch (lineChart->getLineSeriesContentType()) { + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: + break; + case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: + lineSeriesChart = lineChart; + matrixChart = chartDelegate->getMatrixCharting(); + break; + } + } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartDelegate); - ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); - CaretAssert(matrixChart); - matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, - selectedMapIndex); + matrixChart = chartDelegate->getMatrixCharting(); +// ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); +// CaretAssert(matrixChart); +// matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, +// selectedMapIndex); } break; } + if (matrixChart != NULL) { + matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, + selectedMapIndex); + if (lineSeriesChart) { + lineSeriesChart->loadDataForRowOrColumn(m_tabIndex, + selectedMapIndex); + } + } + if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (m_selectedMapFile == NULL) { m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index 5ace201c2..cc7abe2a3 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -292,6 +292,31 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie } } +/** + * Load data for the given row or column. + * + * @param tabIndex + * Index of tab. + * @param rowOrColumnIndex + * Index of row/column for loading. + */ +void +ChartableTwoFileLineSeriesChart::loadDataForRowOrColumn(const int32_t tabIndex, + const int32_t rowOrColumnIndex) +{ + std::vector tabIndices; + tabIndices.push_back(tabIndex); + + MapFileDataSelector mapFileSelector; + mapFileSelector.setRowIndex(getCaretMappableDataFile(), + "", + rowOrColumnIndex); + + EventChartTwoLoadLineSeriesData lineSeriesDataEvent(tabIndices, + mapFileSelector); + loadLineCharts(&lineSeriesDataEvent); +} + /** * Find tab indices for which user has loading of data enabled in the given valid tab indices. * diff --git a/src/Files/ChartableTwoFileLineSeriesChart.h b/src/Files/ChartableTwoFileLineSeriesChart.h index ce13d036f..aaf86e24e 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.h +++ b/src/Files/ChartableTwoFileLineSeriesChart.h @@ -53,6 +53,8 @@ namespace caret { virtual void receiveEvent(Event* event) override; + void loadDataForRowOrColumn(const int32_t tabIndex, + const int32_t rowOrColumnIndex); // ADD_NEW_METHODS_HERE -- GitLab From 8cd0a152290dadb293fbf5d36f16345b65b0a00b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 9 Jan 2018 12:02:48 -0600 Subject: [PATCH 569/755] Update for WB-765: Upload Scene File to BALSA Dialog Updates: When finding the base path for a scene file, verify that each data file in the scene exists. When the user presses with the "Zip" or "Upload" buttons on the Scene Dialog, find the base path and test for missing data files. If there are missing data files, display a warning dialog listing the missing data files and allow the user to continue or cancel. --- src/Files/SceneFile.cxx | 42 ++++++++++++---- src/Files/SceneFile.h | 2 +- src/GuiQt/BalsaDatabaseManager.cxx | 5 +- src/GuiQt/SceneBasePathWidget.cxx | 3 +- src/GuiQt/SceneDialog.cxx | 64 ++++++++++++++++++++++++ src/GuiQt/SceneDialog.h | 8 +++ src/Operations/OperationZipSceneFile.cxx | 3 +- 7 files changed, 113 insertions(+), 14 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 49fde7dbc..ba8d83eef 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -867,13 +867,20 @@ SceneFile::setBalsaExtractToDirectoryName(const AString& extractToDirectoryName) } /** - * return Base directory for data files. - * The base directory is a directory that is parent to all loaded data files. + * Find the base directory that is a directory that is parent to all loaded data files. + * + * @param missingFileNamesOut + * Will contain data files that are in scenes but do not exist. + * @return + * Base directory for data files. */ AString -SceneFile::findBaseDirectoryForDataFiles() const +SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesOut) const { + missingFileNamesOut.clear(); + std::set directoryNames; + std::set missingFileNames; const bool includeSpecFileFlag = false; @@ -909,11 +916,19 @@ SceneFile::findBaseDirectoryForDataFiles() const /* * Need to ignore file on the network */ - if ( ! DataFile::isFileOnNetwork(pathName)) { + if (DataFile::isFileOnNetwork(pathName)) { + /* assume file on network are valid */ + } + else { FileInformation fileInfo(pathName); - const AString dirName = fileInfo.getAbsolutePath().trimmed(); - if ( ! dirName.isEmpty()) { - directoryNames.insert(dirName); + if (fileInfo.exists()) { + const AString dirName = fileInfo.getAbsolutePath().trimmed(); + if ( ! dirName.isEmpty()) { + directoryNames.insert(dirName); + } + } + else { + missingFileNames.insert(pathName); } } } @@ -932,6 +947,11 @@ SceneFile::findBaseDirectoryForDataFiles() const baseDirectoryName = fileInfo.getAbsolutePath(); } + missingFileNamesOut.clear(); + missingFileNamesOut.insert(missingFileNamesOut.end(), + missingFileNames.begin(), + missingFileNames.end()); + return baseDirectoryName; } @@ -948,7 +968,8 @@ SceneFile::getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCo { std::vector names; - AString baseDirectoryName = findBaseDirectoryForDataFiles(); + std::vector missingFileNames; + AString baseDirectoryName = findBaseDirectoryForDataFiles(missingFileNames); if ( ! baseDirectoryName.isEmpty()) { QDir dir(baseDirectoryName); @@ -986,8 +1007,9 @@ AString SceneFile::getDefaultExtractToDirectoryName() const { AString directoryName; - - FileInformation fileInfo(findBaseDirectoryForDataFiles()); + + std::vector missingFileNames; + FileInformation fileInfo(findBaseDirectoryForDataFiles(missingFileNames)); AString baseDirectory = fileInfo.getAbsoluteFilePath(); if ( ! baseDirectory.isEmpty()) { QDir dir(baseDirectory); diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index dc4bc2d55..57d906f1e 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -100,7 +100,7 @@ namespace caret { void setBalsaBaseDirectory(const AString& balsaBaseDirectory); - AString findBaseDirectoryForDataFiles() const; + AString findBaseDirectoryForDataFiles(std::vector& missingFileNamesOut) const; std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 15); diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 4214d3cc9..7a7d792a4 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -474,13 +474,16 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, switch (sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: - basePathName = sceneFile->findBaseDirectoryForDataFiles(); + { + std::vector missingFileNames; + basePathName = sceneFile->findBaseDirectoryForDataFiles(missingFileNames); if ( ! FileInformation(basePathName).exists()) { errorMessageOut = ("AUTOMATIC base path mode produced an invalid base path (directory does not exist): \"" + basePathName + "\""); return false; } + } break; case SceneFileBasePathTypeEnum::CUSTOM: if (basePathName.isEmpty()) { diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index 4be5f0181..661c08fb6 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -189,7 +189,8 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) break; } - m_automaticBasePathLineEdit->setText(m_sceneFile->findBaseDirectoryForDataFiles()); + std::vector missingFileNames; + m_automaticBasePathLineEdit->setText(m_sceneFile->findBaseDirectoryForDataFiles(missingFileNames)); setEnabled(true); } else { diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index d4c8d3449..40610ed06 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -970,6 +970,60 @@ SceneDialog::warnIfSceneFileIsModified(const ModifiedWarningType warningType) return successFlag; } +/** + * Display a message if there are missing files in the Scene File. + * + * @param missingFilesMode + * The missing file mode. + * @return + * True if there are no missing files, else false. + */ +bool +SceneDialog::warnIfMissingFilesInSceneFile(SceneFile* sceneFile, + const MissingFilesMode missingFilesMode) +{ + CaretAssert(sceneFile); + + std::vector filenames; + (void)sceneFile->findBaseDirectoryForDataFiles(filenames); + + if (filenames.empty()) { + return true; + } + + AString messageText; + AString acceptButtonText; + switch (missingFilesMode) { + case MissingFilesMode::UPLOAD: + acceptButtonText = "Upload"; + messageText = "uploading to BALSA"; + break; + case MissingFilesMode::ZIP: + acceptButtonText = "Zip"; + messageText = "zipping the scene file"; + break; + } + + AString text("" + "Do you want to continue " + + messageText + + "?" + "

" + "These files are in the scene file but do not exist:"); + for (auto name : filenames) { + text.append("
" + name); + } + text.append("

Use the Test All button to find scenes with invalid files"); + text.append(""); + + const bool result = WuQMessageBox::warningAcceptReject(this, + text, + acceptButtonText, + "Cancel"); + + return result; +} + /** * Called when upload scene file is selected. @@ -983,6 +1037,11 @@ SceneDialog::uploadSceneFileButtonClicked() SceneFile* sceneFile = getSelectedSceneFile(); + if ( ! warnIfMissingFilesInSceneFile(sceneFile, + MissingFilesMode::UPLOAD)) { + return; + } + BalsaDatabaseUploadSceneFileDialog uploadDialog(sceneFile, this); uploadDialog.exec(); @@ -1006,6 +1065,11 @@ SceneDialog::zipSceneFileButtonClicked() SceneFile* sceneFile = getSelectedSceneFile(); + if ( ! warnIfMissingFilesInSceneFile(sceneFile, + MissingFilesMode::ZIP)) { + return; + } + ZipSceneFileDialog zipDialog(sceneFile, this); zipDialog.exec(); diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index 13bac6f62..d5ac7add5 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -176,12 +176,20 @@ namespace caret { ZIP_FILE_BUTTON }; + enum class MissingFilesMode { + UPLOAD, + ZIP + }; + bool warnIfSceneFileIsModified(const ModifiedWarningType warningType); bool saveSelectedSceneFile(); bool saveAsSelectedSceneFile(); + bool warnIfMissingFilesInSceneFile(SceneFile* sceneFile, + const MissingFilesMode missingFilesMode); + // ADD_NEW_MEMBERS_HERE QLabel* m_sceneFileModifiedStatusLabel; diff --git a/src/Operations/OperationZipSceneFile.cxx b/src/Operations/OperationZipSceneFile.cxx index 54885d76d..d56ad17e6 100644 --- a/src/Operations/OperationZipSceneFile.cxx +++ b/src/Operations/OperationZipSceneFile.cxx @@ -124,7 +124,8 @@ void OperationZipSceneFile::createZipFile(const AString& sceneFileName, myBaseDir = QDir::cleanPath(QDir(baseDirectory).absolutePath()); } else { - myBaseDir = QDir::cleanPath(sceneFile.findBaseDirectoryForDataFiles()); + std::vector missingFileNames; + myBaseDir = QDir::cleanPath(sceneFile.findBaseDirectoryForDataFiles(missingFileNames)); } if (!myBaseDir.endsWith('/'))//root is a special case, if we didn't handle it differently it would end up looking for "//somefile" {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" -- GitLab From ebb4aeafaf51091d6dad89bfcf4b96c7d1a9b205 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 09:04:59 -0600 Subject: [PATCH 570/755] Resolve invalid base path as part of WB-765 Upload Scene File to BALSA Dialog Updates: Code that computed automatic base path just found the longest "string" prefix in the paths to all data files. If two files were in sibling directories whose directory names started with the same characters (/user/files/bill /usr/files/bob) the path was "/usr/files/b" (longest string match but not a directory). So, use the longest string match, but it if is an invalid directory, use the parent directory as the base path and in this example is "/usr/files". Also renamed some methods and a member to indicate that they are only used for the custom base bath. --- src/Files/SceneFile.cxx | 43 ++++++++++++++----- src/Files/SceneFile.h | 10 ++--- src/Files/SceneFileSaxReader.cxx | 10 ++--- src/GuiQt/BalsaDatabaseManager.cxx | 3 +- .../BalsaDatabaseUploadSceneFileDialog.cxx | 4 +- src/GuiQt/SceneBasePathWidget.cxx | 18 ++++---- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index ba8d83eef..b8438e11d 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -68,7 +68,7 @@ SceneFile::SceneFile() { m_balsaStudyID = ""; m_balsaStudyTitle = ""; - m_balsaBaseDirectory = ""; + m_balsaCustomBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; m_metadata = new GiftiMetaData(); @@ -101,7 +101,7 @@ SceneFile::clear() m_balsaStudyID = ""; m_balsaStudyTitle = ""; - m_balsaBaseDirectory = ""; + m_balsaCustomBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; @@ -524,25 +524,25 @@ SceneFile::setBalsaStudyTitle(const AString& balsaStudyTitle) } /** - * @return The Base Directory + * @return The Custom Base Directory */ AString -SceneFile::getBalsaBaseDirectory() const +SceneFile::getBalsaCustomBaseDirectory() const { - return m_balsaBaseDirectory; + return m_balsaCustomBaseDirectory; } /** - * Set the Base Directory. + * Set the Custom Base Directory. * * @param baseDirectory * New value for Base Directory. */ void -SceneFile::setBalsaBaseDirectory(const AString& balsaBaseDirectory) +SceneFile::setBalsaCustomBaseDirectory(const AString& balsaBaseDirectory) { - if (balsaBaseDirectory != m_balsaBaseDirectory) { - m_balsaBaseDirectory = balsaBaseDirectory; + if (balsaBaseDirectory != m_balsaCustomBaseDirectory) { + m_balsaCustomBaseDirectory = balsaBaseDirectory; setModified(); } } @@ -721,8 +721,8 @@ SceneFile::writeFile(const AString& filename) * and this may occur since the file may be new and has not * been closed. */ - if ( ! getBalsaBaseDirectory().isEmpty()) { - const AString baseDirAbsPath = FileInformation(getBalsaBaseDirectory()).getAbsoluteFilePath(); + if ( ! getBalsaCustomBaseDirectory().isEmpty()) { + const AString baseDirAbsPath = FileInformation(getBalsaCustomBaseDirectory()).getAbsoluteFilePath(); const AString sceneFileAbsPath = FileInformation(filename).getAbsoluteFilePath(); ScenePathName basePathName("basePathName", baseDirAbsPath); @@ -940,12 +940,33 @@ SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesO const std::vector stringVector(directoryNames.begin(), directoryNames.end()); + + /* + * AString::findLongestCommonPrefix finds the longest common prefix of strings (not directories). + * If there are sub-directories beginning with the same characters, the result is not a valid + * directory. + * + * Consider these two files for example: + * /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_SURFACES/Q1-Q6_R440.R.midthickness.32k_fs_LR.surf.gii + * /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_VOLUME/Q1-Q6_R440_AverageT1w_restore.nii.gz + * + * The longest common prefix is: /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_ + * but it is not a valid directory as the two right-most sub-directories begin with the same text (SUB_DIR_). + * Taking the parent of this directory results in a valid directory and valid base path: + * /Users/joe/data_workbench/volume_surface_outline_testing + */ AString baseDirectoryName = AString::findLongestCommonPrefix(stringVector); if (baseDirectoryName.isEmpty()) { FileInformation fileInfo(getFileName()); baseDirectoryName = fileInfo.getAbsolutePath(); } + else { + FileInformation fileInfo(baseDirectoryName); + if ( ! fileInfo.exists()) { + baseDirectoryName = fileInfo.getAbsolutePath().trimmed(); + } + } missingFileNamesOut.clear(); missingFileNamesOut.insert(missingFileNamesOut.end(), diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 57d906f1e..aa3fb38d5 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -96,13 +96,13 @@ namespace caret { void setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathType); - AString getBalsaBaseDirectory() const; + AString getBalsaCustomBaseDirectory() const; - void setBalsaBaseDirectory(const AString& balsaBaseDirectory); + void setBalsaCustomBaseDirectory(const AString& balsaBaseDirectory); AString findBaseDirectoryForDataFiles(std::vector& missingFileNamesOut) const; - std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 15); + std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 25); void reorderScenes(std::vector& orderedScenes); @@ -155,8 +155,8 @@ namespace caret { /** the Base Path Type */ SceneFileBasePathTypeEnum::Enum m_basePathType; - /** the Base Directory */ - AString m_balsaBaseDirectory; + /** the Custom Base Directory */ + AString m_balsaCustomBaseDirectory; /** The "extract to" directory name */ AString m_balsaExtractToDirectoryName; diff --git a/src/Files/SceneFileSaxReader.cxx b/src/Files/SceneFileSaxReader.cxx index 0630c03ae..ed8f8a27d 100644 --- a/src/Files/SceneFileSaxReader.cxx +++ b/src/Files/SceneFileSaxReader.cxx @@ -253,7 +253,7 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, m_sceneFile->setBalsaStudyTitle(m_elementText); break; case STATE_SCENE_INFO_BALSA_BASE_DIRECTORY: - m_sceneFile->setBalsaBaseDirectory(m_elementText); + m_sceneFile->setBalsaCustomBaseDirectory(m_elementText); break; case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: m_sceneFile->setBalsaExtractToDirectoryName(m_elementText); @@ -314,11 +314,11 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, if (m_baseBathTypeWasFoundFlag) { switch (m_sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: - m_sceneFile->setBalsaBaseDirectory(""); + m_sceneFile->setBalsaCustomBaseDirectory(""); break; case SceneFileBasePathTypeEnum::CUSTOM: { - AString basePath = m_sceneFile->getBalsaBaseDirectory(); + AString basePath = m_sceneFile->getBalsaCustomBaseDirectory(); if ( ! basePath.isEmpty()) { FileInformation basePathInfo(basePath); if (basePathInfo.isRelative()) { @@ -331,7 +331,7 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, basePath = basePathName.stringValue(); } } - m_sceneFile->setBalsaBaseDirectory(basePath); + m_sceneFile->setBalsaCustomBaseDirectory(basePath); } break; } @@ -344,7 +344,7 @@ SceneFileSaxReader::endElement(const AString& namespaceURI, * use AUTOMATIC mode. If there is a base path assume it is valid * and use CUSTOM mode. */ - if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { + if (m_sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); } else { diff --git a/src/GuiQt/BalsaDatabaseManager.cxx b/src/GuiQt/BalsaDatabaseManager.cxx index 7a7d792a4..39a60cd13 100644 --- a/src/GuiQt/BalsaDatabaseManager.cxx +++ b/src/GuiQt/BalsaDatabaseManager.cxx @@ -470,7 +470,7 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, return false; } - AString basePathName = sceneFile->getBalsaBaseDirectory(); + AString basePathName; switch (sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: @@ -486,6 +486,7 @@ BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, } break; case SceneFileBasePathTypeEnum::CUSTOM: + basePathName = sceneFile->getBalsaCustomBaseDirectory(); if (basePathName.isEmpty()) { errorMessageOut = ("CUSTOM base path is empty"); return false; diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index 677c70bed..e165f8636 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -766,12 +766,12 @@ BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() break; case SceneFileBasePathTypeEnum::CUSTOM: { - if (m_sceneFile->getBalsaBaseDirectory().isEmpty()) { + if (m_sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { msg.appendWithNewLine("CUSTOM Base Path (on Advanced Tab) is invalid. " "Select Base Path or use AUTOMATIC.

"); } else { - if ( ! FileInformation(m_sceneFile->getBalsaBaseDirectory()).exists()) { + if ( ! FileInformation(m_sceneFile->getBalsaCustomBaseDirectory()).exists()) { msg.appendWithNewLine("CUSTOM Base Directory (on Advanced Tab) is not a valid directory on this computer. " "Select a valid Base Path or use AUTOMATIC.

"); } diff --git a/src/GuiQt/SceneBasePathWidget.cxx b/src/GuiQt/SceneBasePathWidget.cxx index 661c08fb6..b3555cab2 100644 --- a/src/GuiQt/SceneBasePathWidget.cxx +++ b/src/GuiQt/SceneBasePathWidget.cxx @@ -147,11 +147,11 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) QSignalBlocker customPathSignalBlocker(m_customBasePathComboBox); if (m_sceneFile != NULL) { - AString baseDirectoryName = m_sceneFile->getBalsaBaseDirectory(); + AString customBaseDirectoryName = m_sceneFile->getBalsaCustomBaseDirectory(); m_customBasePathComboBox->clear(); const std::vector dirNames = m_sceneFile->getBaseDirectoryHierarchyForDataFiles(); - if ( ! baseDirectoryName.isEmpty()) { + if ( ! customBaseDirectoryName.isEmpty()) { /* * If the base directory is in neither the base path hierarchy * nor the user custom paths, add it to the user custom paths @@ -159,11 +159,11 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) */ if (std::find(dirNames.begin(), dirNames.end(), - baseDirectoryName) == dirNames.end()) { + customBaseDirectoryName) == dirNames.end()) { if (std::find(s_userCustomBasePaths.begin(), s_userCustomBasePaths.end(), - baseDirectoryName) == s_userCustomBasePaths.end()) { - s_userCustomBasePaths.push_back(baseDirectoryName); + customBaseDirectoryName) == s_userCustomBasePaths.end()) { + s_userCustomBasePaths.push_back(customBaseDirectoryName); } } } @@ -174,8 +174,8 @@ SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) m_customBasePathComboBox->addItem(name); } - if ( ! baseDirectoryName.isEmpty()) { - m_customBasePathComboBox->setCurrentText(baseDirectoryName); + if ( ! customBaseDirectoryName.isEmpty()) { + m_customBasePathComboBox->setCurrentText(customBaseDirectoryName); } switch (m_sceneFile->getBasePathType()) { @@ -224,7 +224,7 @@ SceneBasePathWidget::customPathComboBoxActivated(int index) { const AString text = m_customBasePathComboBox->itemText(index); if ( ! text.isEmpty()) { - m_sceneFile->setBalsaBaseDirectory(text); + m_sceneFile->setBalsaCustomBaseDirectory(text); } } @@ -272,7 +272,7 @@ SceneBasePathWidget::customBrowseButtonClicked() s_userCustomBasePaths.push_back(newDirectoryName); } m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); - m_sceneFile->setBalsaBaseDirectory(newDirectoryName); + m_sceneFile->setBalsaCustomBaseDirectory(newDirectoryName); updateWithSceneFile(m_sceneFile); } -- GitLab From 9d8b57b504d45276d615d0dee7ae481dd33a1564 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 11:02:57 -0600 Subject: [PATCH 571/755] When the user presses either of the Upload or Zip buttons on the Scene Dialog, a test is performed to verify that all data files are valid (exist) that are listed in the scene file. The dialog has been replaced as the previous dialog was often taller than the screen when many data files were not valid. --- src/GuiQt/SceneDialog.cxx | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 40610ed06..afbfcc10e 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -991,37 +991,38 @@ SceneDialog::warnIfMissingFilesInSceneFile(SceneFile* sceneFile, return true; } - AString messageText; + AString verbText; AString acceptButtonText; switch (missingFilesMode) { case MissingFilesMode::UPLOAD: acceptButtonText = "Upload"; - messageText = "uploading to BALSA"; + verbText = "uploading to BALSA"; break; case MissingFilesMode::ZIP: acceptButtonText = "Zip"; - messageText = "zipping the scene file"; + verbText = "zipping the scene file"; break; } - AString text("" - "Do you want to continue " - + messageText - + "?" - "

" - "These files are in the scene file but do not exist:"); + const AString labelText("Do you want to continue " + verbText + " ?"); + AString text; for (auto name : filenames) { - text.append("
" + name); + text.append(name + "\n"); } - text.append("

Use the Test All button to find scenes with invalid files"); - text.append(""); - const bool result = WuQMessageBox::warningAcceptReject(this, - text, - acceptButtonText, - "Cancel"); + WuQDataEntryDialog dialog("Data Files Not Found", + this, + false); + dialog.setTextAtTop("These data files were not found but are used by scenes in the scene file. Scenes may not display correctly. " + + labelText, + true); + dialog.addTextEdit("", text, true); + dialog.setMinimumWidth(500); - return result; + if (dialog.exec() == WuQDataEntryDialog::Accepted) { + return true; + } + return false; } -- GitLab From c812149daced1dc137e49444632ee4408bbe81fd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 5 Jan 2018 09:52:54 -0600 Subject: [PATCH 572/755] Finish resolving WB-651 Cycle through sdseries without needing yoking to layer --- src/Files/ChartableTwoFileLineSeriesChart.cxx | 14 ++++++++++++++ src/Files/CiftiScalarDataSeriesFile.cxx | 11 ++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Files/ChartableTwoFileLineSeriesChart.cxx b/src/Files/ChartableTwoFileLineSeriesChart.cxx index cc7abe2a3..7aec0abaa 100644 --- a/src/Files/ChartableTwoFileLineSeriesChart.cxx +++ b/src/Files/ChartableTwoFileLineSeriesChart.cxx @@ -27,6 +27,7 @@ #include "ChartTwoDataCartesian.h" #include "ChartTwoLineSeriesHistory.h" #include "CiftiMappableDataFile.h" +#include "CiftiScalarDataSeriesFile.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "SceneClass.h" @@ -198,6 +199,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie { const MapFileDataSelector mapFileDataSelector = lineSeriesDataEvent->getMapFileDataSelector(); + int32_t scalarRowIndex = -1; bool loadDataFlag = false; switch (m_lineSeriesContentType) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: @@ -246,6 +248,7 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie if (mapFile == getCaretMappableDataFile()) { loadDataFlag = true; } + scalarRowIndex = rowIndex; } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: @@ -288,6 +291,17 @@ ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSerie } m_lineChartHistory->addHistoryItem(cartesianData); + + if (scalarRowIndex >= 0) { + CaretMappableDataFile* mapFile = getCaretMappableDataFile(); + CaretAssert(mapFile); + CiftiScalarDataSeriesFile* scalarFile = dynamic_cast(mapFile); + if (scalarFile != NULL) { + for (auto tabIndex : lineSeriesDataEvent->getValidTabIndices()) { + scalarFile->setSelectedMapIndex(tabIndex, scalarRowIndex); + } + } + } } } } diff --git a/src/Files/CiftiScalarDataSeriesFile.cxx b/src/Files/CiftiScalarDataSeriesFile.cxx index a68911a9a..7e86f58a9 100644 --- a/src/Files/CiftiScalarDataSeriesFile.cxx +++ b/src/Files/CiftiScalarDataSeriesFile.cxx @@ -200,11 +200,16 @@ CiftiScalarDataSeriesFile::getSelectedMapIndex(const int32_t tabIndex) const * New value for selected map index. */ void -CiftiScalarDataSeriesFile::setSelectedMapIndex(const int32_t tabIndex, +CiftiScalarDataSeriesFile::setSelectedMapIndex(const int32_t /*tabIndex*/, const int32_t mapIndex) { - CaretAssertArrayIndex(m_selectedMapIndices, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); - m_selectedMapIndices[tabIndex] = mapIndex; + /* + * One map selection for all tabs + */ + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { + CaretAssertArrayIndex(m_selectedMapIndices, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, i); + m_selectedMapIndices[i] = mapIndex; + } } -- GitLab From 96f8c7468d01ba93d91caeff8c3f84b09866f694 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 5 Jan 2018 09:56:33 -0600 Subject: [PATCH 573/755] Fixed loss of focus on index spin box and name combo box when user uses the mouse to change one of them. --- src/GuiQt/ChartTwoOverlayViewController.cxx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/GuiQt/ChartTwoOverlayViewController.cxx b/src/GuiQt/ChartTwoOverlayViewController.cxx index 84d03ea32..2abfb3d4e 100644 --- a/src/GuiQt/ChartTwoOverlayViewController.cxx +++ b/src/GuiQt/ChartTwoOverlayViewController.cxx @@ -330,6 +330,9 @@ ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indxIn //TSC: not sure how to put the displayed integer back to 0 where it starts when opening without data files return; } + + const bool focusFlag = m_mapRowOrColumnIndexSpinBox->hasFocus(); + /* * Get the file that is selected from the file combo box */ @@ -366,6 +369,13 @@ ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indxIn this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); + + /* + * User interface update may cause loss of focus so restore it + */ + if (focusFlag) { + m_mapRowOrColumnIndexSpinBox->setFocus(); + } } /** @@ -411,6 +421,11 @@ ChartTwoOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); + + /* + * User interface update may cause loss of focus so restore it + */ + m_mapRowOrColumnNameComboBox->setFocus(); } /** -- GitLab From 5dc61dbe7bf750ccd6fe5b8f697d2ef02a6e11dd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 5 Jan 2018 15:26:19 -0600 Subject: [PATCH 574/755] When text gets very small, the FTGL font renderer may cause an OpenGL error to occur many times and potentially, fill up a user's log file. So, immediately after the glTexSubImage2D function call that causes, the error, simply call glGetError() to reset the error status and prevent printing of an error message during a later test for an OpenGL error. --- src/FtglFont/FTGlyph/FTTextureGlyph.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp index e1753700b..67b3cecca 100644 --- a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp +++ b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp @@ -96,6 +96,14 @@ FTTextureGlyphImpl::FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, glBindTexture(GL_TEXTURE_2D, glTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); + /* + * When the font is too small, the above call to glTexSubImage2D() may + * cause an OpenGL "invalid value" error. These error messages may + * be frequent so just ignore them. Calling "glGetError()" will + * clear any error has been triggered. + */ + glGetError(); + glPopClientAttrib(); } -- GitLab From 31107a1769f1a06416a967ce751f654577d882d6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 5 Jan 2018 15:26:46 -0600 Subject: [PATCH 575/755] Prevent a crash if the chart two model is invalid. --- src/GuiQt/GuiManager.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 522daebb1..613b775e4 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -2831,9 +2831,11 @@ GuiManager::processIdentification(const int32_t tabIndex, BrowserTabContent* tabContent = eventBrowserTab.getBrowserTab(); if (tabContent != NULL) { ModelChartTwo* chartTwoModel = tabContent->getDisplayedChartTwoModel(); - if (chartTwoModel->getSelectedChartTwoDataType(tabIndex) == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { - ChartTwoOverlaySet* chartOverlaySet = tabContent->getChartTwoOverlaySet(); - chartOverlayContainingDataFile = chartOverlaySet->getDisplayedOverlayContainingDataFile(cmdf); + if (chartTwoModel != NULL) { + if (chartTwoModel->getSelectedChartTwoDataType(tabIndex) == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { + ChartTwoOverlaySet* chartOverlaySet = tabContent->getChartTwoOverlaySet(); + chartOverlayContainingDataFile = chartOverlaySet->getDisplayedOverlayContainingDataFile(cmdf); + } } } -- GitLab From 9f285a3fdebb4c8b3969e98b616daa7b5f84552b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 12:41:28 -0600 Subject: [PATCH 576/755] Initial implementation of WB-766 Lock Window/Tab Aspect Ratio Popup: When the presses the Annotate mode and the neither the selected tab nor the window have their aspect locked, display a dialog advising the user to lock tab and window aspects. --- src/GuiQt/BrainBrowserWindow.cxx | 36 +++ src/GuiQt/BrainBrowserWindow.h | 2 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 22 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/LockAspectWarningDialog.cxx | 292 ++++++++++++++++++++++++ src/GuiQt/LockAspectWarningDialog.h | 102 +++++++++ 6 files changed, 444 insertions(+), 13 deletions(-) create mode 100644 src/GuiQt/LockAspectWarningDialog.cxx create mode 100644 src/GuiQt/LockAspectWarningDialog.h diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 037df6699..f0427203a 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -77,6 +77,7 @@ #include "FociProjectionDialog.h" #include "GapsAndMargins.h" #include "GuiManager.h" +#include "LockAspectWarningDialog.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelWholeBrain.h" @@ -785,6 +786,41 @@ BrainBrowserWindow::createActionsUsedByToolBar() } } +/** + * Is called by toolbar when the user changes input mode to annotations. + * + * @param parent + * The parent widget. + * @return + * True if it is okay to change to annotations mode, else false. + */ +bool +BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog(QWidget* parent) +{ + LockAspectWarningDialog::Result result = + LockAspectWarningDialog::runDialog(m_browserWindowIndex, + parent); + + bool okFlag = true; + + switch (result) { + case LockAspectWarningDialog::Result::CANCEL: + okFlag = false; + break; + case LockAspectWarningDialog::Result::LOCK_WINDOW_ASPECT: + processWindowAspectRatioLockedToggled(true); + break; + case LockAspectWarningDialog::Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS: + processWindowAspectRatioLockedToggled(true); + processLockAllTabsAspectRatioTriggered(); + break; + case LockAspectWarningDialog::Result::NO_CHANGES: + break; + } + + return okFlag; +} + /** * Called when Lock Aspect Ratio for All Tabs is selected. */ diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 2477b9b47..7cc45ee72 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -137,6 +137,8 @@ namespace caret { float getOpenGLWidgetAspectRatio() const; + bool changeInputModeToAnnotationsWarningDialog(QWidget* parent); + bool isAspectRatioLocked() const; void setAspectRatioLocked(const bool locked); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 5860b67c1..280292f3a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -95,6 +95,7 @@ #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateYokedWindows.h" #include "GuiManager.h" +#include "LockAspectWarningDialog.h" #include "Model.h" #include "ModelChart.h" #include "ModelChartTwo.h" @@ -2702,19 +2703,14 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) if (action == this->modeInputModeAnnotationsAction) { if (currentMode != UserInputModeAbstract::ANNOTATIONS) { - if ( ( ! m_windowAspectRatioLockedAction->isChecked()) - && ( ! m_tabAspectRatioLockedAction->isChecked()) ) { - const QString msg("" - "Neither Lock Window Aspect nor Lock Tab Aspect " - "are selected. Tab and Window annotations are displayed " - "in percentage coordinates of the tab/window " - "width and height. Locking tab/window aspect ensures that " - "the shape of the tab/window maintains its aspect ratio so " - "that tab/window annotations remain in the correct location. " - ""); - WuQMessageBox::warningOkWithDoNotShowAgain(this, - "lockAspectDoNotShowAgainIdentifier", - msg); + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); + CaretAssert(bbw); + if ( ! bbw->changeInputModeToAnnotationsWarningDialog(this)) { + /* + * Since mode is rejected, need to update toolbar + */ + updateModeWidget(getTabContentFromSelectedTab()); + return; } } inputMode = UserInputModeAbstract::ANNOTATIONS; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 312d129d6..59fa6b533 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -133,6 +133,7 @@ ELSE() InformationDisplayDialog.h InformationDisplayPropertiesDialog.h LabelSelectionViewController.h + LockAspectWarningDialog.h MacApplication.h MacDockMenu.h MapSettingsChartTwoLineHistoryWidget.h @@ -355,6 +356,7 @@ InformationDisplayDialog.h InformationDisplayPropertiesDialog.h KeyEvent.h LabelSelectionViewController.h +LockAspectWarningDialog.h MacApplication.h MacDockMenu.h MapSettingsChartTwoLineHistoryWidget.h @@ -574,6 +576,7 @@ InformationDisplayDialog.cxx InformationDisplayPropertiesDialog.cxx KeyEvent.cxx LabelSelectionViewController.cxx +LockAspectWarningDialog.cxx MacApplication.cxx MacDockMenu.cxx MapSettingsChartTwoLineHistoryWidget.cxx diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx new file mode 100644 index 000000000..feca49306 --- /dev/null +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -0,0 +1,292 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ +#include "LockAspectWarningDialog.h" +#undef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "GuiManager.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::LockAspectWarningDialog + * \brief Dialog that warns and allows user to lock tab/window aspect. + * \ingroup GuiQt + */ + +/** + * Run the lock aspect warning dialog and return the result. + * + * @param browserWindowIndex + * Index of the browser window. + * @param parent + * The parent widget. + * @return + * Result of user interaction with dialog. + */ +LockAspectWarningDialog::Result +LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, + QWidget* parent) +{ + const LockAspectWarningDialog::TabMode tabMode = LockAspectWarningDialog::TabMode::SELECTED_TAB; + + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); + CaretAssert(bbw); + + BrowserTabContent* selectedTab = bbw->getBrowserTabContent(); + if (selectedTab == NULL) { + return Result::NO_CHANGES; + } + + /* + * Determine lock status for window and tabs in the window + */ + const bool selectedTabLockedFlag = selectedTab->isAspectRatioLocked(); + + std::vector allTabs; + bbw->getAllTabContent(allTabs); + const int32_t tabCount = static_cast(allTabs.size()); + const int32_t tabLockedCount = std::count_if(allTabs.begin(), + allTabs.end(), + [](BrowserTabContent* btc) { return btc->isAspectRatioLocked(); }); + const bool allTabsLockedFlag = (tabCount == tabLockedCount); + + + /* + * Check either selected tab for lock status or all tabs + */ + bool tabLockStatus = false; + switch (tabMode) { + case LockAspectWarningDialog::TabMode::ALL_TABS: + tabLockStatus = allTabsLockedFlag; + break; + case LockAspectWarningDialog::TabMode::SELECTED_TAB: + tabLockStatus = selectedTabLockedFlag; + break; + } + + const bool windowApectLockedFlag = bbw->isAspectRatioLocked(); + if (windowApectLockedFlag + || tabLockStatus) { + return Result::NO_CHANGES; + } + + LockAspectWarningDialog dialog(tabMode, + windowApectLockedFlag, + tabLockedCount, + tabCount, + parent); + + if (dialog.exec() == LockAspectWarningDialog::Accepted) { + return dialog.getResult(); + } + + return Result::CANCEL; +} + +/** + * Constructor. + * + * @param tabMode + * The mode for tabs (selected or all) + * @param browserWindowAspectLocked + * True if window aspect is locked. + * @param tabAspectLockedCount + * Count of tabs with aspect locked. + * @param tabCount + * Count of tabs. + * @param parent + * The parent widget. + */ +LockAspectWarningDialog::LockAspectWarningDialog(const TabMode tabMode, + const bool browserWindowAspectLocked, + const int32_t tabAspectLockedCount, + const int32_t tabCount, + QWidget* parent) +: QDialog(parent), + m_tabMode(tabMode), + m_browserWindowAspectLocked(browserWindowAspectLocked), +m_tabAspectLockedCount(tabAspectLockedCount), +m_tabCount(tabCount) +{ + AString tabText; + switch (m_tabMode) { + case TabMode::ALL_TABS: + tabText = "all Tab Aspect Ratios"; + break; + case TabMode::SELECTED_TAB: + tabText = "the Selected Tab Aspect Ratio"; + break; + } + + const AString msg("" + "Neither the Window Aspect Ratio nor " + tabText + " are locked. " + "Prior to entering Annotations Mode and creating annotations, " + "it is recommended that the user adjust the window " + "to the desired size, enter Tile Tabs (if desired), " + "and then lock the aspect ratio for the Window and All Tabs. " + "

" + "Tab and Window annotations are displayed " + "in percentage coordinates of the tab/window " + "width and height (0% is at bottom/left and 100% " + "is at top/right). Locking the aspect ratio ensures that these " + "annotations remain in the correct location when the window " + "size changes. " + ""); + QLabel* warningLabel = new QLabel(msg); + warningLabel->setWordWrap(true); + + //QLabel* lockedStatusLabel = new QLabel(getLockedStatusText()); + + QLabel* buttonsLabel = new QLabel("Continue to Annotations Mode?"); + + QPushButton* lockWindowAndTabButton = new QPushButton("OK - Lock Window and All Tab Aspects"); + QObject::connect(lockWindowAndTabButton, &QPushButton::clicked, + this, &LockAspectWarningDialog::lockWindowAndTabsClicked); + + QPushButton* lockWindowButton = new QPushButton("OK - Lock Window Aspect"); + QObject::connect(lockWindowButton, &QPushButton::clicked, + this, &LockAspectWarningDialog::lockWindowClicked); + + QPushButton* noChangesButton = new QPushButton("OK - No Lock Aspect Changes"); + QObject::connect(noChangesButton, &QPushButton::clicked, + this, &LockAspectWarningDialog::noChangesClicked); + + QPushButton* cancelButton = new QPushButton("Cancel"); + QObject::connect(cancelButton, &QPushButton::clicked, + this, &LockAspectWarningDialog::cancelClicked); + + + QVBoxLayout* labelLayout = new QVBoxLayout(); + labelLayout->addWidget(warningLabel); + labelLayout->addStretch(); + + QBoxLayout* dialogLayout = new QHBoxLayout(this); + + WuQtUtilities::matchWidgetWidths(lockWindowAndTabButton, + lockWindowButton, + noChangesButton, + cancelButton); + + QBoxLayout* buttonLayout = new QVBoxLayout(); + buttonLayout->addWidget(buttonsLabel); + buttonLayout->addWidget(lockWindowAndTabButton); + buttonLayout->addWidget(lockWindowButton); + buttonLayout->addWidget(noChangesButton); + buttonLayout->addWidget(cancelButton); + buttonLayout->addStretch(); + + dialogLayout->addLayout(labelLayout); + dialogLayout->addLayout(buttonLayout); +} + +/** + * Destructor. + */ +LockAspectWarningDialog::~LockAspectWarningDialog() +{ +} + +/** + * @return The selected lock status + */ +LockAspectWarningDialog::Result +LockAspectWarningDialog::getResult() const +{ + return m_result; +} + +/** + * @return Message with current locked status + */ +QString +LockAspectWarningDialog::getLockedStatusText() const +{ + AString windowMessage("Window Aspect: " + + AString((m_browserWindowAspectLocked ? "Locked" : "Unlocked"))); + + AString tabMessage("Tab Aspect: "); + if (m_tabAspectLockedCount == 0) { + tabMessage.append("All Unlocked"); + } + else if (m_tabAspectLockedCount == m_tabCount) { + tabMessage.append("All Locked"); + } + else { + tabMessage.append(AString::number(m_tabAspectLockedCount) + + " of " + + AString::number(m_tabCount) + + " Locked"); + } + + AString lockedMessage(windowMessage + + "\n" + + tabMessage); + + return lockedMessage; +} + + +void +LockAspectWarningDialog::lockWindowAndTabsClicked() +{ + m_result = Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS; + accept(); +} + +void +LockAspectWarningDialog::lockWindowClicked() +{ + m_result = Result::LOCK_WINDOW_ASPECT; + accept(); +} + +void +LockAspectWarningDialog::noChangesClicked() +{ + m_result = Result::NO_CHANGES; + accept(); +} + +void +LockAspectWarningDialog::cancelClicked() +{ + m_result = Result::CANCEL; + reject(); +} + diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h new file mode 100644 index 000000000..361bdee07 --- /dev/null +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -0,0 +1,102 @@ +#ifndef __LOCK_ASPECT_WARNING_DIALOG_H__ +#define __LOCK_ASPECT_WARNING_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + + + +namespace caret { + + class LockAspectWarningDialog : public QDialog { + + Q_OBJECT + + public: + enum class Result { + LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS, + LOCK_WINDOW_ASPECT, + NO_CHANGES, + CANCEL + }; + + enum class TabMode { + ALL_TABS, + SELECTED_TAB + }; + + static Result runDialog(const int32_t browserWindowIndex, + QWidget* parent); + + LockAspectWarningDialog(const TabMode tabMode, + const bool browserWindowAspectLocked, + const int32_t tabAspectLockedCount, + const int32_t tabCount, + QWidget* parent = 0); + + virtual ~LockAspectWarningDialog(); + + Result getResult() const; + + // ADD_NEW_METHODS_HERE + + private slots: + void lockWindowAndTabsClicked(); + + void lockWindowClicked(); + + void noChangesClicked(); + + void cancelClicked(); + + private: + LockAspectWarningDialog(const LockAspectWarningDialog&); + + LockAspectWarningDialog& operator=(const LockAspectWarningDialog&); + + QString getLockedStatusText() const; + + const TabMode m_tabMode; + + const bool m_browserWindowAspectLocked; + + const int32_t m_tabAspectLockedCount; + + const int32_t m_tabCount; + + Result m_result = Result::CANCEL; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ + // +#endif // __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ + +} // namespace +#endif //__LOCK_ASPECT_WARNING_DIALOG_H__ -- GitLab From f538b743b6125e0717f6359dc52c88473640262b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 12:48:43 -0600 Subject: [PATCH 577/755] Changed minimum width for polygonal lines (used by volume surface outline from 1.0 pixels to 0.001 pixels. --- src/Graphics/GraphicsOpenGLPolylineTriangles.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 5d0318a9b..3a241abf3 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -124,14 +124,14 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const return NULL; } - float lineWidth = primitive->m_lineWidthValue; + float lineWidthPixels = primitive->m_lineWidthValue; switch (primitive->m_lineWidthType) { case GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - lineWidth = (lineWidth / 100.0) * viewport[3]; + lineWidthPixels = (lineWidthPixels / 100.0) * viewport[3]; } break; case GraphicsPrimitive::LineWidthType::PIXELS: @@ -139,9 +139,9 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const } /* enforce a minimum line width */ - const float minimumLineWidth = 1.0f; - if (lineWidth < minimumLineWidth) { - lineWidth = minimumLineWidth; + const float minimumLineWidthPixels = 0.001f; + if (lineWidthPixels < minimumLineWidthPixels) { + lineWidthPixels = minimumLineWidthPixels; } ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; @@ -214,7 +214,7 @@ GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, - lineWidth, + lineWidthPixels, colorType, lineType, joinType); -- GitLab From 702d2e26952d437996151c0a3a3dc155ec6ff497 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 15:25:44 -0600 Subject: [PATCH 578/755] Initial implementation of WB-768: Add a button to the scene file dialog that shows all data files in selected scene file. For now, a button containing the text "List Files..." has been added near the top of the Scene Dialog, just to the left of the "Open" button. When the "List Files..." button is clicked, a dialog is displayed listing all data files for all scenes in the scene file. If any data files are missing, the path of the file is prefixed with "MISSING:". --- src/Files/SceneFile.cxx | 123 ++++++++++++++++++++++---------------- src/Files/SceneFile.h | 2 + src/GuiQt/SceneDialog.cxx | 62 ++++++++++++++++--- src/GuiQt/SceneDialog.h | 4 ++ 4 files changed, 132 insertions(+), 59 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index b8438e11d..4e31770f3 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -879,65 +879,32 @@ SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesO { missingFileNamesOut.clear(); + const std::vector allFileNames = getAllDataFileNamesFromAllScenes(); + std::set directoryNames; std::set missingFileNames; - - const bool includeSpecFileFlag = false; - - /** - * Find all 'path name' elements from ALL scenes - */ - for (Scene* scene: m_scenes) { - CaretAssert(scene); - std::vector children = scene->getDescendants(); - for (SceneObject* sceneObject : children) { - CaretAssert(sceneObject); - if (sceneObject->getDataType() == SceneObjectDataTypeEnum::SCENE_PATH_NAME) { - const ScenePathName* scenePathName = dynamic_cast(sceneObject); - /* - * Will be NULL for 'path name arrays' which we ignore - */ - if (scenePathName != NULL) { - /* - * files in spec file are named "fileName" in the scene - * specFile is named "specFileName" - * and these names are unique to name of files in the spec file - */ - bool useNameFlag = false; - if (sceneObject->getName() == "fileName") { - useNameFlag = true; - } - else if (sceneObject->getName() == "specFileName") { - useNameFlag = includeSpecFileFlag; - } - if (useNameFlag) { - const AString pathName = scenePathName->stringValue().trimmed(); - if ( ! pathName.isEmpty()) { - /* - * Need to ignore file on the network - */ - if (DataFile::isFileOnNetwork(pathName)) { - /* assume file on network are valid */ - } - else { - FileInformation fileInfo(pathName); - if (fileInfo.exists()) { - const AString dirName = fileInfo.getAbsolutePath().trimmed(); - if ( ! dirName.isEmpty()) { - directoryNames.insert(dirName); - } - } - else { - missingFileNames.insert(pathName); - } - } - } - } + for (auto name : allFileNames) { + if (DataFile::isFileOnNetwork(name)) { + /* assume file on network are valid */ + } + else { + FileInformation fileInfo(name); + if (fileInfo.exists()) { + const AString dirName = fileInfo.getAbsolutePath().trimmed(); + if ( ! dirName.isEmpty()) { + directoryNames.insert(dirName); } } + else { + missingFileNames.insert(name); + } } } + missingFileNamesOut.insert(missingFileNamesOut.end(), + missingFileNames.begin(), + missingFileNames.end()); + const std::vector stringVector(directoryNames.begin(), directoryNames.end()); @@ -1011,6 +978,58 @@ SceneFile::getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCo return names; } +/** + * @return A vector containing the names of all data files from all scenes. + */ +std::vector +SceneFile::getAllDataFileNamesFromAllScenes() const +{ + const bool includeSpecFileFlag = false; + + std::set filenamesSet; + + /** + * Find all 'path name' elements from ALL scenes + */ + for (Scene* scene: m_scenes) { + CaretAssert(scene); + std::vector children = scene->getDescendants(); + for (SceneObject* sceneObject : children) { + CaretAssert(sceneObject); + if (sceneObject->getDataType() == SceneObjectDataTypeEnum::SCENE_PATH_NAME) { + const ScenePathName* scenePathName = dynamic_cast(sceneObject); + /* + * Will be NULL for 'path name arrays' which we ignore + */ + if (scenePathName != NULL) { + /* + * files in spec file are named "fileName" in the scene + * specFile is named "specFileName" + * and these names are unique to name of files in the spec file + */ + bool useNameFlag = false; + if (sceneObject->getName() == "fileName") { + useNameFlag = true; + } + else if (sceneObject->getName() == "specFileName") { + useNameFlag = includeSpecFileFlag; + } + if (useNameFlag) { + const AString pathName = scenePathName->stringValue().trimmed(); + if ( ! pathName.isEmpty()) { + filenamesSet.insert(pathName); + } + } + } + } + } + } + + std::vector filenamesOut(filenamesSet.begin(), + filenamesSet.end()); + + return filenamesOut; +} /** * @return Default name for a ZIP file containing the scene file and its data files. diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index aa3fb38d5..1207faaa1 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -104,6 +104,8 @@ namespace caret { std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 25); + std::vector getAllDataFileNamesFromAllScenes() const; + void reorderScenes(std::vector& orderedScenes); int32_t getSceneIndexFromNumberOrName(const AString& numberOrName); diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index afbfcc10e..6f504d2db 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1800,6 +1800,44 @@ SceneDialog::checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, return result; } +/** + * Show the data file structure in a dialog. + */ +void +SceneDialog::showFileStructure() +{ + SceneFile* sceneFile = getSelectedSceneFile(); + CaretAssert(sceneFile); + + std::vector filenames = sceneFile->getAllDataFileNamesFromAllScenes(); + + if (filenames.empty()) { + WuQMessageBox::errorOk(m_showFileStructurePushButton, + "Scene file is empty."); + return; + } + + AString text; + for (auto name : filenames) { + FileInformation fileInfo(name); + AString missingText; + if ( ! fileInfo.exists()) { + missingText = "MISSING: "; + } + text.appendWithNewLine(missingText + + name); + } + + WuQDataEntryDialog dialog("All Data Files in Scene File", + this, + false); + dialog.addTextEdit("", text, true); + dialog.setMinimumWidth(500); + + dialog.setCancelButtonText(""); + dialog.exec(); +} + /** * @return The Scenes widget. */ @@ -2031,6 +2069,14 @@ SceneDialog::createSceneFileWidget() QLabel* modifiedLabel = new QLabel("Modified"); m_sceneFileModifiedStatusLabel = new QLabel(""); + /* + * File structure buttons + */ + m_showFileStructurePushButton = new QPushButton("List Files..."); + m_showFileStructurePushButton->setToolTip("In a dialog, show data files from all scenes"); + QObject::connect(m_showFileStructurePushButton, &QPushButton::clicked, + this, &SceneDialog::showFileStructure); + /* * New File button */ @@ -2103,18 +2149,20 @@ SceneDialog::createSceneFileWidget() gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); + gridLayout->setColumnStretch(5, 0); int row = 0; gridLayout->addWidget(sceneFileLabel, row, 0, Qt::AlignRight); - gridLayout->addWidget(m_sceneFileSelectionComboBox, row, 1); - gridLayout->addWidget(m_newSceneFilePushButton, row, 2); - gridLayout->addWidget(m_saveSceneFilePushButton, row, 3); - gridLayout->addWidget(m_zipSceneFilePushButton, row, 4); + gridLayout->addWidget(m_sceneFileSelectionComboBox, row, 1, 1, 2); + gridLayout->addWidget(m_newSceneFilePushButton, row, 3); + gridLayout->addWidget(m_saveSceneFilePushButton, row, 4); + gridLayout->addWidget(m_zipSceneFilePushButton, row, 5); row++; gridLayout->addWidget(modifiedLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_sceneFileModifiedStatusLabel, row, 1, Qt::AlignLeft); - gridLayout->addWidget(m_openSceneFilePushButton, row, 2); - gridLayout->addWidget(m_saveAsSceneFilePushButton, row, 3); - gridLayout->addWidget(m_uploadSceneFilePushButton, row, 4); + gridLayout->addWidget(m_showFileStructurePushButton, row, 2); + gridLayout->addWidget(m_openSceneFilePushButton, row, 3); + gridLayout->addWidget(m_saveAsSceneFilePushButton, row, 4); + gridLayout->addWidget(m_uploadSceneFilePushButton, row, 5); row++; return widget; diff --git a/src/GuiQt/SceneDialog.h b/src/GuiQt/SceneDialog.h index d5ac7add5..307fe98f4 100644 --- a/src/GuiQt/SceneDialog.h +++ b/src/GuiQt/SceneDialog.h @@ -120,6 +120,8 @@ namespace caret { void replaceAllScenesPushButtonClicked(); + void showFileStructure(); + public: // ADD_NEW_METHODS_HERE @@ -196,6 +198,8 @@ namespace caret { QComboBox* m_sceneFileSelectionComboBox; + QPushButton* m_showFileStructurePushButton; + QPushButton* m_newSceneFilePushButton; QPushButton* m_openSceneFilePushButton; -- GitLab From cc4886e6ad21848f76df852d14352d7f9fcb8384 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 10 Jan 2018 16:24:25 -0600 Subject: [PATCH 579/755] Update to WB-768 Scene Data Flies Listing: Now show scene file, automatic base path, and show the data files with paths relative to the scene file. --- src/GuiQt/SceneDialog.cxx | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 6f504d2db..85ba2208f 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1817,14 +1817,43 @@ SceneDialog::showFileStructure() return; } + const AString sceneFileName = sceneFile->getFileName(); AString text; + + std::vector missingFiles; + text.appendWithNewLine("Automatic Base Path: " + + sceneFile->findBaseDirectoryForDataFiles(missingFiles)); + text.appendWithNewLine("Scene File: " + + sceneFileName); + text.append("\n"); + text.appendWithNewLine("Data File paths relative to Scene File:"); + + for (auto name : filenames) { FileInformation fileInfo(name); AString missingText; if ( ! fileInfo.exists()) { missingText = "MISSING: "; } - text.appendWithNewLine(missingText + + if (fileInfo.isAbsolute()) { + FileInformation specFileInfo(sceneFileName); + if (specFileInfo.isAbsolute()) { + const AString newPath = SystemUtilities::relativePath(fileInfo.getPathName(), + specFileInfo.getPathName()); + if (newPath.isEmpty()) { + name = fileInfo.getFileName(); + } + else { + name = (newPath + + "/" + + fileInfo.getFileName()); + } + } + } + + text.appendWithNewLine(" " + + missingText + name); } -- GitLab From 834149bab14227948c9874ed6c69d3a9feab91e5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 10:37:21 -0600 Subject: [PATCH 580/755] Added a text editor dialog that, when displayed, is sized to show all text. --- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/WuQTextEditorDialog.cxx | 169 ++++++++++++++++++++++++++++++ src/GuiQt/WuQTextEditorDialog.h | 88 ++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 src/GuiQt/WuQTextEditorDialog.cxx create mode 100644 src/GuiQt/WuQTextEditorDialog.h diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 59fa6b533..52bfea334 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -202,6 +202,7 @@ ELSE() WuQSpinBoxGroup.h WuQSpinBoxOddValue.h WuQTabWidget.h + WuQTextEditorDialog.h WuQTimedMessageDisplay.h WuQTreeWidget.h WuQTrueFalseComboBox.h @@ -437,6 +438,7 @@ WuQSpecialIncrementDoubleSpinBox.h WuQSpinBoxGroup.h WuQSpinBoxOddValue.h WuQTabWidget.h +WuQTextEditorDialog.h WuQTimedMessageDisplay.h WuQTreeWidget.h WuQTrueFalseComboBox.h @@ -657,6 +659,7 @@ WuQSpecialIncrementDoubleSpinBox.cxx WuQSpinBoxGroup.cxx WuQSpinBoxOddValue.cxx WuQTabWidget.cxx +WuQTextEditorDialog.cxx WuQTimedMessageDisplay.cxx WuQTreeWidget.cxx WuQTrueFalseComboBox.cxx diff --git a/src/GuiQt/WuQTextEditorDialog.cxx b/src/GuiQt/WuQTextEditorDialog.cxx new file mode 100644 index 000000000..46464aee2 --- /dev/null +++ b/src/GuiQt/WuQTextEditorDialog.cxx @@ -0,0 +1,169 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ +#include "WuQTextEditorDialog.h" +#undef __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ + +#include +#include +#include +#include + + +#include "CaretAssert.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::WuQTextEditorDialog + * \brief Dialog that shows a text editor. + * \ingroup GuiQt + */ + +/** + * Run the dialog in non-modal (non-blocking) mode. + * Since non-modal and no way to retrieve text, the + * text is not editable. + * + * @param dialogTitle + * Title for dialog. + * @param text + * Text displayed in text editor. + * @param textMode + * Text mode (html or plain) + * @param wrapMode + * Text wrapping (no, yes) + * @param parent + * The parent widget on which dialog is displayed. + */ +void +WuQTextEditorDialog::runNonModal(const QString& dialogTitle, + const QString& text, + const TextMode textMode, + const WrapMode wrapMode, + QWidget* parent) +{ + WuQTextEditorDialog* dialog = new WuQTextEditorDialog(dialogTitle, + text, + TextReadOnlyMode::YES, + textMode, + wrapMode, + parent); + dialog->setAttribute(Qt::WA_DeleteOnClose); + + dialog->show(); + dialog->raise(); +} + +/** + * Constructor. + * + * @param dialogTitle + * Title for dialog. + * @param text + * Text displayed in text editor. + * @param readOnlyMode + * Read only mode (no, yes) + * @param textMode + * Text mode (html or plain) + * @param wrapMode + * Text wrapping (no, yes) + * @param parent + * The parent widget on which dialog is displayed. + */ +WuQTextEditorDialog::WuQTextEditorDialog(const QString& dialogTitle, + const QString& text, + const TextReadOnlyMode readOnlyMode, + const TextMode textMode, + const WrapMode wrapMode, + QWidget* parent) +: QDialog(parent) +{ + setWindowTitle(dialogTitle); + + m_textEdit = new QTextEdit(); + switch (textMode) { + case TextMode::HTML: + m_textEdit->setHtml(text); + break; + case TextMode::PLAIN: + m_textEdit->setPlainText(text); + break; + } + + switch (readOnlyMode) { + case TextReadOnlyMode::NO: + m_textEdit->setReadOnly(false); + break; + case TextReadOnlyMode::YES: + m_textEdit->setReadOnly(true); + break; + } + + QPushButton* closeButton = new QPushButton("Close"); + QObject::connect(closeButton, &QPushButton::clicked, + this, &QDialog::accept); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(m_textEdit, 100); + layout->addWidget(closeButton, 0, Qt::AlignCenter); + + + QTextDocument* document = m_textEdit->document(); + + QTextOption textOption = document->defaultTextOption(); + switch (wrapMode) { + case WrapMode::NO: + textOption.setWrapMode(QTextOption::NoWrap); + break; + case WrapMode::YES: + textOption.setWrapMode(QTextOption::WordWrap); + break; + } + + document->setDefaultTextOption(textOption); + + document->adjustSize(); + m_textEdit->adjustSize(); + + int32_t dialogWidth = document->size().width() + 70; + if (dialogWidth < 300) { + dialogWidth = 300; + } + const int32_t dialogHeight = document->size().height() + 100; + + WuQtUtilities::resizeWindow(this, + dialogWidth, + dialogHeight); + +} + +/** + * Destructor. + */ +WuQTextEditorDialog::~WuQTextEditorDialog() +{ +} + diff --git a/src/GuiQt/WuQTextEditorDialog.h b/src/GuiQt/WuQTextEditorDialog.h new file mode 100644 index 000000000..ef8802db5 --- /dev/null +++ b/src/GuiQt/WuQTextEditorDialog.h @@ -0,0 +1,88 @@ +#ifndef __WU_Q_TEXT_EDITOR_DIALOG_H__ +#define __WU_Q_TEXT_EDITOR_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QTextEdit; + + +namespace caret { + class WuQTextEditorDialog : public QDialog { + + Q_OBJECT + + public: + enum class TextMode { + HTML, + PLAIN + }; + + enum class WrapMode { + NO, + YES + }; + + enum class TextReadOnlyMode { + NO, + YES + }; + + static void runNonModal(const QString& dialogTitle, + const QString& text, + const TextMode textMode, + const WrapMode wrapMode, + QWidget* parent); + + WuQTextEditorDialog(const QString& dialogTitle, + const QString& text, + const TextReadOnlyMode readOnlyMode, + const TextMode textMode, + const WrapMode wrapMode, + QWidget* parent = 0); + + virtual ~WuQTextEditorDialog(); + + + // ADD_NEW_METHODS_HERE + + private: + WuQTextEditorDialog(const WuQTextEditorDialog&); + + WuQTextEditorDialog& operator=(const WuQTextEditorDialog&); + + QTextEdit* m_textEdit; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ + // +#endif // __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ + +} // namespace +#endif //__WU_Q_TEXT_EDITOR_DIALOG_H__ -- GitLab From 3a5cacc09c5c691958617f3bdd30bb58f777b65c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 10:38:52 -0600 Subject: [PATCH 581/755] Tooltip has been updated for "List Files..." button; dialog that lists files is resized to show all files (not too narrow); and text in dialog has been reformatted to improve readability. --- src/GuiQt/SceneDialog.cxx | 42 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 85ba2208f..f2f0a075d 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -82,6 +84,7 @@ #include "WuQDataEntryDialog.h" #include "WuQDialogNonModal.h" #include "WuQMessageBox.h" +#include "WuQTextEditorDialog.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" #include "ZipSceneFileDialog.h" @@ -1818,16 +1821,17 @@ SceneDialog::showFileStructure() } const AString sceneFileName = sceneFile->getFileName(); - AString text; + AString text(""); std::vector missingFiles; - text.appendWithNewLine("Automatic Base Path: " - + sceneFile->findBaseDirectoryForDataFiles(missingFiles)); - text.appendWithNewLine("Scene File: " - + sceneFileName); - text.append("\n"); - text.appendWithNewLine("Data File paths relative to Scene File:"); - + text.appendWithNewLine("Automatic Base Path: " + + sceneFile->findBaseDirectoryForDataFiles(missingFiles) + + "

"); + text.appendWithNewLine("Scene File: " + + sceneFileName + + "

"); + text.append("Data File paths relative to Scene File:"); + text.append("

    "); for (auto name : filenames) { FileInformation fileInfo(name); @@ -1852,19 +1856,18 @@ SceneDialog::showFileStructure() } } - text.appendWithNewLine(" " + text.append("
  • " + missingText + name); } - - WuQDataEntryDialog dialog("All Data Files in Scene File", - this, - false); - dialog.addTextEdit("", text, true); - dialog.setMinimumWidth(500); - - dialog.setCancelButtonText(""); - dialog.exec(); + text.append("
"); + text.append(""); + + WuQTextEditorDialog::runNonModal("Scene File Paths", + text, + WuQTextEditorDialog::TextMode::HTML, + WuQTextEditorDialog::WrapMode::NO, + this); } /** @@ -2102,7 +2105,8 @@ SceneDialog::createSceneFileWidget() * File structure buttons */ m_showFileStructurePushButton = new QPushButton("List Files..."); - m_showFileStructurePushButton->setToolTip("In a dialog, show data files from all scenes"); + WuQtUtilities::setWordWrappedToolTip(m_showFileStructurePushButton, + "In a dialog, show data files from all scenes with paths relative to the scene file"); QObject::connect(m_showFileStructurePushButton, &QPushButton::clicked, this, &SceneDialog::showFileStructure); -- GitLab From 0dc00da4110304a43cb9cd3a9468f1f9ad9712f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 11:00:17 -0600 Subject: [PATCH 582/755] Update for non-modal text editor dialog. --- src/GuiQt/SceneDialog.cxx | 8 ++++---- src/GuiQt/WuQTextEditorDialog.cxx | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index f2f0a075d..2003b62fa 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1855,14 +1855,14 @@ SceneDialog::showFileStructure() } } } - + text.append("
  • " - + missingText - + name); + + missingText + + name); } text.append(""); text.append(""); - + WuQTextEditorDialog::runNonModal("Scene File Paths", text, WuQTextEditorDialog::TextMode::HTML, diff --git a/src/GuiQt/WuQTextEditorDialog.cxx b/src/GuiQt/WuQTextEditorDialog.cxx index 46464aee2..7c974163d 100644 --- a/src/GuiQt/WuQTextEditorDialog.cxx +++ b/src/GuiQt/WuQTextEditorDialog.cxx @@ -71,6 +71,12 @@ WuQTextEditorDialog::runNonModal(const QString& dialogTitle, textMode, wrapMode, parent); + + /* + * Since dialog is non-modal, setting this attribute + * will destroy the dialog when the dialog is closed + * and prevent a memory leak. + */ dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); -- GitLab From e827c1009eef96db8e7144f36956fbc940298596 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 11:50:16 -0600 Subject: [PATCH 583/755] Again resolving WB-651 Cycle through sdseries without needing yoking to layer: In Chart Overlay Layers, the Spin box was 1..N and the rows in the combo box were 0..N-1. This has been corrected to that both are 1..N. --- src/Files/ChartableTwoFileMatrixChart.cxx | 16 ++++++++-------- src/Files/ChartableTwoFileMatrixChart.h | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Files/ChartableTwoFileMatrixChart.cxx b/src/Files/ChartableTwoFileMatrixChart.cxx index 64b029030..cfdc0bb97 100644 --- a/src/Files/ChartableTwoFileMatrixChart.cxx +++ b/src/Files/ChartableTwoFileMatrixChart.cxx @@ -198,7 +198,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) CaretAssert(numRowParcels == m_numberOfRows); for (int32_t i = 0; i < numRowParcels; i++) { m_rowNames.push_back(rowParcelsMap->getIndexName(i)); - m_rowNumberAndNames.push_back("Row " + AString::number(i + 1) + ": " + rowParcelsMap->getIndexName(i)); + m_rowNumberAndNames.push_back("Row " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + rowParcelsMap->getIndexName(i)); } } else { @@ -218,7 +218,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) else if (hasRowNumbersFlag) { for (int32_t i = 0; i < m_numberOfRows; i++) { m_rowNames.push_back(AString::number(i)); - m_rowNumberAndNames.push_back("Row " + AString::number(i + 1) + ": " + AString::number(i + 1)); + m_rowNumberAndNames.push_back("Row " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + AString::number(i + 1)); } } } @@ -231,7 +231,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) CaretAssert(numColParcels == m_numberOfColumns); for (int32_t i = 0; i < numColParcels; i++) { m_columnNames.push_back(colParcelsMap->getIndexName(i)); - m_columnNumberAndNames.push_back("Column " + AString::number(i + 1) + ": " + colParcelsMap->getIndexName(i)); + m_columnNumberAndNames.push_back("Column " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + colParcelsMap->getIndexName(i)); } } else { @@ -253,7 +253,7 @@ m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) CaretAssert(m_numberOfColumns == numMaps); for (int32_t i = 0; i < numMaps; i++) { m_columnNames.push_back(ciftiMapFile->getMapName(i)); - m_columnNumberAndNames.push_back("Column " + AString::number(i + 1) + ": " + ciftiMapFile->getMapName(i)); + m_columnNumberAndNames.push_back("Column " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + ciftiMapFile->getMapName(i)); } } @@ -766,7 +766,7 @@ ChartableTwoFileMatrixChart::getRowName(const int32_t rowIndex) const CaretAssertVectorIndex(m_rowNames, rowIndex); return m_rowNames[rowIndex]; } - return ("Row: " + AString::number(rowIndex)); + return ("Row: " + AString::number(rowIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; @@ -787,7 +787,7 @@ ChartableTwoFileMatrixChart::getColumnName(const int32_t columnIndex) const CaretAssertVectorIndex(m_columnNames, columnIndex); return m_columnNames[columnIndex]; } - return ("Column: " + AString::number(columnIndex)); + return ("Column: " + AString::number(columnIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; @@ -808,7 +808,7 @@ ChartableTwoFileMatrixChart::getRowNumberAndName(const int32_t rowIndex) const CaretAssertVectorIndex(m_rowNumberAndNames, rowIndex); return m_rowNumberAndNames[rowIndex]; } - return ("Row: " + AString::number(rowIndex)); + return ("Row: " + AString::number(rowIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; @@ -829,7 +829,7 @@ ChartableTwoFileMatrixChart::getColumnNumberAndName(const int32_t columnIndex) c CaretAssertVectorIndex(m_columnNumberAndNames, columnIndex); return m_columnNumberAndNames[columnIndex]; } - return ("Column: " + AString::number(columnIndex)); + return ("Column: " + AString::number(columnIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; diff --git a/src/Files/ChartableTwoFileMatrixChart.h b/src/Files/ChartableTwoFileMatrixChart.h index bdffb709e..b8da84f81 100644 --- a/src/Files/ChartableTwoFileMatrixChart.h +++ b/src/Files/ChartableTwoFileMatrixChart.h @@ -153,6 +153,8 @@ namespace caret { int32_t m_parcelScalarFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; int32_t m_parcelSeriesFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + static const int32_t ROW_COLUMN_INDEX_BASE_OFFSET = 1; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From 287ea73b5c1d99a09b9f635f41a245590084acc0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 15:42:34 -0600 Subject: [PATCH 584/755] Added several static methods to AString for conversion of QStringList to a vector, joining AStrings, and counting matches in vectors of AStrings. --- src/Common/AString.cxx | 80 ++++++++++++++++++++++++++++++++++++++++++ src/Common/AString.h | 8 +++++ 2 files changed, 88 insertions(+) diff --git a/src/Common/AString.cxx b/src/Common/AString.cxx index e1d844330..c97ea0bc8 100644 --- a/src/Common/AString.cxx +++ b/src/Common/AString.cxx @@ -989,3 +989,83 @@ AString::findLongestCommonPrefix(const std::vector& stringVector) return longestPrefix; } +/** + * Convert a QStringList to an std::vector of AStrings. + * + * @param stringList + * The QStringList + * @return + * Vector with elements copied from the string list. + */ +std::vector +AString::stringListToVector(const QStringList& stringList) +{ + std::vector sv(stringList.begin(), + stringList.end()); + return sv; +} + +/** + * Join the elements from the string vector adding 'separator' + * between each of the elements. + * + * @param elements + * Elements joined to form a string. + * @param separtor + * Characters added between each pair of elements. + */ +AString +AString::join(const std::vector& elements, + const AString& separator) +{ + AString joinedString; + + const int32_t numElements = static_cast(elements.size()); + for (int32_t i = 0; i < numElements; i++) { + if (i > 0) { + joinedString.append(separator); + } + CaretAssertVectorIndex(elements, i); + joinedString.append(elements[i]); + } + + return joinedString; +} + +/** + * Count the number of corresponding matching elements from the two vectors. + * Compares first element in each, second element in each, etc and stops + * when the elements at the same index are different or no more + * elements in one of the vectors. + * + * @param v1 + * The first vector. + * @param v2 + * The second vector. + * @return + * Number of matching elements. + */ +int32_t +AString::matchingCount(const std::vector& v1, + const std::vector& v2) +{ + const int32_t count = std::min(v1.size(), + v2.size()); + if (count <= 0) { + return 0; + } + + int32_t matchCount = count; + + for (int32_t i = 0; i < count; i++) { + CaretAssertVectorIndex(v1, i); + CaretAssertVectorIndex(v2, i); + if (v1[i] != v2[i]) { + matchCount = i; + break; + } + } + + return matchCount; +} + diff --git a/src/Common/AString.h b/src/Common/AString.h index 3be009fdd..f7fdd49d2 100644 --- a/src/Common/AString.h +++ b/src/Common/AString.h @@ -134,6 +134,14 @@ namespace caret { static AString findLongestCommonPrefix(const std::vector& v); + static std::vector stringListToVector(const QStringList& stringList); + + static AString join(const std::vector& elements, + const AString& separator); + + static int32_t matchingCount(const std::vector& v1, + const std::vector& v2); + }; } -- GitLab From 05d2018de81e4974ce25ae7c270ccf34021c6e67 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 15:51:26 -0600 Subject: [PATCH 585/755] WB-765 Upload Scene File to BALSA Updates: Revised algorithm for finding the base directory to split up directories into components and compare the directory components to find the base path. --- src/Files/SceneFile.cxx | 91 ++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/Files/SceneFile.cxx b/src/Files/SceneFile.cxx index 4e31770f3..31d72fe56 100644 --- a/src/Files/SceneFile.cxx +++ b/src/Files/SceneFile.cxx @@ -877,11 +877,17 @@ SceneFile::setBalsaExtractToDirectoryName(const AString& extractToDirectoryName) AString SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesOut) const { + const AString directorySeparator("/"); + missingFileNamesOut.clear(); const std::vector allFileNames = getAllDataFileNamesFromAllScenes(); - std::set directoryNames; + /* + * Find a unique set of directory names used by the data files and + * also verify that all files exist. + */ + std::set directoryNamesUniqueSet; std::set missingFileNames; for (auto name : allFileNames) { if (DataFile::isFileOnNetwork(name)) { @@ -890,9 +896,17 @@ SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesO else { FileInformation fileInfo(name); if (fileInfo.exists()) { - const AString dirName = fileInfo.getAbsolutePath().trimmed(); + AString dirName = fileInfo.getAbsolutePath().trimmed(); if ( ! dirName.isEmpty()) { - directoryNames.insert(dirName); + /* + * QDir::cleanPath() removes multiple separators and resolves "." or ".." + * QDir::fromNativeSeparators() ensures "/" is used for the directory separator. + */ + dirName = QDir::cleanPath(dirName); + dirName = QDir::fromNativeSeparators(dirName); + if ( ! dirName.isEmpty()) { + directoryNamesUniqueSet.insert(dirName); + } } } else { @@ -901,45 +915,50 @@ SceneFile::findBaseDirectoryForDataFiles(std::vector& missingFileNamesO } } + const FileInformation fileInfo(getFileName()); + const AString sceneFilePath = fileInfo.getAbsolutePath().trimmed(); + missingFileNamesOut.insert(missingFileNamesOut.end(), missingFileNames.begin(), missingFileNames.end()); - const std::vector stringVector(directoryNames.begin(), - directoryNames.end()); + const int32_t numDirs = static_cast(directoryNamesUniqueSet.size()); + if (numDirs <= 0) { + /* + * if no valid files in scene, user path of scene file. + */ + return sceneFilePath; + } /* - * AString::findLongestCommonPrefix finds the longest common prefix of strings (not directories). - * If there are sub-directories beginning with the same characters, the result is not a valid - * directory. - * - * Consider these two files for example: - * /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_SURFACES/Q1-Q6_R440.R.midthickness.32k_fs_LR.surf.gii - * /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_VOLUME/Q1-Q6_R440_AverageT1w_restore.nii.gz - * - * The longest common prefix is: /Users/joe/data_workbench/volume_surface_outline_testing/SUB_DIR_ - * but it is not a valid directory as the two right-most sub-directories begin with the same text (SUB_DIR_). - * Taking the parent of this directory results in a valid directory and valid base path: - * /Users/joe/data_workbench/volume_surface_outline_testing + * Compare the first directory with all other directories + * to find longest common directory path. + * Each directory is split into its path components and they + * are compared. */ - AString baseDirectoryName = AString::findLongestCommonPrefix(stringVector); - - if (baseDirectoryName.isEmpty()) { - FileInformation fileInfo(getFileName()); - baseDirectoryName = fileInfo.getAbsolutePath(); - } - else { - FileInformation fileInfo(baseDirectoryName); - if ( ! fileInfo.exists()) { - baseDirectoryName = fileInfo.getAbsolutePath().trimmed(); + bool firstFlag = true; + std::vector longestPathMatch; + for (const auto dirName : directoryNamesUniqueSet) { + if (firstFlag) { + firstFlag = false; + longestPathMatch = AString::stringListToVector(dirName.split(directorySeparator)); + } + else { + const std::vector otherPath = AString::stringListToVector(dirName.split(directorySeparator)); + const int32_t matchCount = AString::matchingCount(longestPathMatch, + otherPath); + longestPathMatch.resize(matchCount); } } - missingFileNamesOut.clear(); - missingFileNamesOut.insert(missingFileNamesOut.end(), - missingFileNames.begin(), - missingFileNames.end()); - + AString baseDirectoryName = sceneFilePath; + if ( ! longestPathMatch.empty()) { + /* + * Assemble the path components into a directory. + */ + baseDirectoryName = AString::join(longestPathMatch, + directorySeparator); + } return baseDirectoryName; } @@ -1015,8 +1034,13 @@ SceneFile::getAllDataFileNamesFromAllScenes() const useNameFlag = includeSpecFileFlag; } if (useNameFlag) { - const AString pathName = scenePathName->stringValue().trimmed(); + AString pathName = scenePathName->stringValue().trimmed(); if ( ! pathName.isEmpty()) { + QFileInfo fileInfo(pathName); + const QString absPathName = fileInfo.absoluteFilePath(); + if ( ! absPathName.isEmpty()) { + pathName = absPathName; + } filenamesSet.insert(pathName); } } @@ -1093,4 +1117,3 @@ SceneFile::clearModified() scene->clearModified(); } } - -- GitLab From 9dccfd4c116560d4c4e4008a9cdc252fcabe1da5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 17:25:07 -0600 Subject: [PATCH 586/755] Changed volume crosshairs thickness from percentage of viewport height to 2.0 pixels for thickness. --- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 46 +++++++-------- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 58 +++++++++---------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 71cb53b8b..35a724d55 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -1329,9 +1329,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlan }; const float voxelCenter[3] = { - (bottomLeftVoxelCoord[0] + topRightVoxelCoord[0]) * 0.5, - (bottomLeftVoxelCoord[1] + topRightVoxelCoord[1]) * 0.5, - (bottomLeftVoxelCoord[2] + topRightVoxelCoord[2]) * 0.5 + (float)((bottomLeftVoxelCoord[0] + topRightVoxelCoord[0]) * 0.5), + (float)((bottomLeftVoxelCoord[1] + topRightVoxelCoord[1]) * 0.5), + (float)((bottomLeftVoxelCoord[2] + topRightVoxelCoord[2]) * 0.5) }; @@ -2095,9 +2095,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrthogonalSlice(const VolumeSliceViewP * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { - originX - (voxelStepX / 2.0), - originY - (voxelStepY / 2.0), - originZ - (voxelStepZ / 2.0) + originX - (voxelStepX / 2.0f), + originY - (voxelStepY / 2.0f), + originZ - (voxelStepZ / 2.0f) }; float rowStep[3] = { @@ -2402,9 +2402,9 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrthogonalSliceWithCulling(const Volum * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { - firstVoxelXYZ[0] - (voxelStepX / 2.0), - firstVoxelXYZ[1] - (voxelStepY / 2.0), - firstVoxelXYZ[2] - (voxelStepZ / 2.0) + firstVoxelXYZ[0] - (voxelStepX / 2.0f), + firstVoxelXYZ[1] - (voxelStepY / 2.0f), + firstVoxelXYZ[2] - (voxelStepZ / 2.0f) }; float rowStep[3] = { @@ -3295,7 +3295,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); horizHairPrimitive->addVertex(horizontalAxisStartXYZ, horizontalAxisRGBA); horizHairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); - horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); @@ -3304,7 +3304,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const Vo std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); vertHairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); vertHairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); - vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); } @@ -3691,20 +3691,20 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) const double textMinCoord = -textMaxCoord; - const float axialPlaneMin[3] = { 0.0, 0.0, axisMinCoord }; - const float axialPlaneMax[3] = { 0.0, 0.0, axisMaxCoord }; - const double axialTextMin[3] = { 0.0, 0.0, textMinCoord }; - const double axialTextMax[3] = { 0.0, 0.0, textMaxCoord }; + const float axialPlaneMin[3] = { 0.0, 0.0, (float)axisMinCoord }; + const float axialPlaneMax[3] = { 0.0, 0.0, (float)axisMaxCoord }; + const double axialTextMin[3] = { 0.0, 0.0, (float)textMinCoord }; + const double axialTextMax[3] = { 0.0, 0.0, (float)textMaxCoord }; - const float coronalPlaneMin[3] = { axisMinCoord, 0.0, 0.0 }; - const float coronalPlaneMax[3] = { axisMaxCoord, 0.0, 0.0 }; - const double coronalTextMin[3] = { textMinCoord, 0.0, 0.0 }; - const double coronalTextMax[3] = { textMaxCoord, 0.0, 0.0 }; + const float coronalPlaneMin[3] = { (float)axisMinCoord, 0.0, 0.0 }; + const float coronalPlaneMax[3] = { (float)axisMaxCoord, 0.0, 0.0 }; + const double coronalTextMin[3] = { (float)textMinCoord, 0.0, 0.0 }; + const double coronalTextMax[3] = { (float)textMaxCoord, 0.0, 0.0 }; - const float paraPlaneMin[3] = { 0.0, axisMinCoord, 0.0 }; - const float paraPlaneMax[3] = { 0.0, axisMaxCoord, 0.0 }; - const double paraTextMin[3] = { 0.0, textMinCoord, 0.0 }; - const double paraTextMax[3] = { 0.0, textMaxCoord, 0.0 }; + const float paraPlaneMin[3] = { 0.0, (float)axisMinCoord, 0.0 }; + const float paraPlaneMax[3] = { 0.0, (float)axisMaxCoord, 0.0 }; + const double paraTextMin[3] = { 0.0, (float)textMinCoord, 0.0 }; + const double paraTextMax[3] = { 0.0, (float)textMaxCoord, 0.0 }; /* * Set radius as percentage of viewport height diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 0ffed471d..ee3dbaa0d 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -1343,9 +1343,9 @@ BrainOpenGLVolumeSliceDrawing::drawObliqueSlice(const VolumeSliceViewPlaneEnum:: }; const float voxelCenter[3] = { - (bottomLeftVoxelCoord[0] + topRightVoxelCoord[0]) * 0.5, - (bottomLeftVoxelCoord[1] + topRightVoxelCoord[1]) * 0.5, - (bottomLeftVoxelCoord[2] + topRightVoxelCoord[2]) * 0.5 + (float)((bottomLeftVoxelCoord[0] + topRightVoxelCoord[0]) * 0.5), + (float)((bottomLeftVoxelCoord[1] + topRightVoxelCoord[1]) * 0.5), + (float)((bottomLeftVoxelCoord[2] + topRightVoxelCoord[2]) * 0.5) }; @@ -1990,21 +1990,21 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice_LPI_ONLY(const VolumeSliceVie * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { - originX - (voxelStepX / 2.0), - originY - (voxelStepY / 2.0), - originZ - (voxelStepZ / 2.0) + originX - (voxelStepX / 2.0f), + originY - (voxelStepY / 2.0f), + originZ - (voxelStepZ / 2.0f) }; float rowStep[3] = { - 0.0, - 0.0, - 0.0 + 0.0f, + 0.0f, + 0.0f }; float columnStep[3] = { - 0.0, - 0.0, - 0.0 + 0.0f, + 0.0f, + 0.0f }; @@ -3112,9 +3112,9 @@ BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceWithCulling(const VolumeSliceV * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { - firstVoxelXYZ[0] - (voxelStepX / 2.0), - firstVoxelXYZ[1] - (voxelStepY / 2.0), - firstVoxelXYZ[2] - (voxelStepZ / 2.0) + firstVoxelXYZ[0] - (voxelStepX / 2.0f), + firstVoxelXYZ[1] - (voxelStepY / 2.0f), + firstVoxelXYZ[2] - (voxelStepZ / 2.0f) }; float rowStep[3] = { @@ -4144,7 +4144,7 @@ BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrthoAndOblique(const VolumeSli xhairPrimitive->addVertex(horizontalAxisEndXYZ, horizontalAxisRGBA); xhairPrimitive->addVertex(verticalAxisStartXYZ, verticalAxisRGBA); xhairPrimitive->addVertex(verticalAxisEndXYZ, verticalAxisRGBA); - xhairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, 1.0f); + xhairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(xhairPrimitive.get()); } @@ -4426,22 +4426,22 @@ BrainOpenGLVolumeSliceDrawing::drawOrientationAxes(const int viewport[4]) const double textMinCoord = -textMaxCoord; - const float axialPlaneMin[3] = { 0.0, 0.0, axisMinCoord }; - const float axialPlaneMax[3] = { 0.0, 0.0, axisMaxCoord }; - const double axialTextMin[3] = { 0.0, 0.0, textMinCoord }; - const double axialTextMax[3] = { 0.0, 0.0, textMaxCoord }; + const float axialPlaneMin[3] = { 0.0, 0.0, (float)axisMinCoord }; + const float axialPlaneMax[3] = { 0.0, 0.0, (float)axisMaxCoord }; + const double axialTextMin[3] = { 0.0, 0.0, (float)textMinCoord }; + const double axialTextMax[3] = { 0.0, 0.0, (float)textMaxCoord }; - const float coronalPlaneMin[3] = { axisMinCoord, 0.0, 0.0 }; - const float coronalPlaneMax[3] = { axisMaxCoord, 0.0, 0.0 }; - const double coronalTextMin[3] = { textMinCoord, 0.0, 0.0 }; - const double coronalTextMax[3] = { textMaxCoord, 0.0, 0.0 }; + const float coronalPlaneMin[3] = { (float)axisMinCoord, 0.0, 0.0 }; + const float coronalPlaneMax[3] = { (float)axisMaxCoord, 0.0, 0.0 }; + const double coronalTextMin[3] = { (float)textMinCoord, 0.0, 0.0 }; + const double coronalTextMax[3] = { (float)textMaxCoord, 0.0, 0.0 }; - const float paraPlaneMin[3] = { 0.0, axisMinCoord, 0.0 }; - const float paraPlaneMax[3] = { 0.0, axisMaxCoord, 0.0 }; - const double paraTextMin[3] = { 0.0, textMinCoord, 0.0 }; - const double paraTextMax[3] = { 0.0, textMaxCoord, 0.0 }; + const float paraPlaneMin[3] = { 0.0, (float)axisMinCoord, 0.0 }; + const float paraPlaneMax[3] = { 0.0, (float)axisMaxCoord, 0.0 }; + const double paraTextMin[3] = { 0.0, (float)textMinCoord, 0.0 }; + const double paraTextMax[3] = { 0.0, (float)textMaxCoord, 0.0 }; - const float axesCrosshairRadius = 1.0; + const float axesCrosshairRadius = 1.0f; if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(blue, -- GitLab From 1415ab2647b3655e180cf445c1a53ebf91a775d2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 17:25:49 -0600 Subject: [PATCH 587/755] Fixed some "narrowing" compilation warnings. --- .../AnnotationOneDimensionalShape.cxx | 18 +-- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 122 +++++++++--------- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 14 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 38 +++--- src/Brain/BrowserTabContent.cxx | 12 +- src/Files/ImageFile.cxx | 8 +- src/Operations/OperationShowScene.cxx | 2 +- 7 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index f7bb1328d..f3a976aee 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -290,14 +290,14 @@ AnnotationOneDimensionalShape::setRotationAngle(const float viewportWidth, getEndCoordinate()->getViewportXY(viewportWidth, viewportHeight, annTwoX, annTwoY); const float midPointXYZ[3] = { - (annOneX + annTwoX) / 2.0, - (annOneY + annTwoY) / 2.0, - 0.0 + (annOneX + annTwoX) / 2.0f, + (annOneY + annTwoY) / 2.0f, + 0.0f }; - const float vpOneXYZ[3] = { annOneX, annOneY, 0.0 }; + const float vpOneXYZ[3] = { annOneX, annOneY, 0.0f }; const float lengthMidToOne = MathFunctions::distance3D(midPointXYZ, vpOneXYZ); - const float newRotationAngle = 180.0 - rotationAngle; + const float newRotationAngle = 180.0f - rotationAngle; const float angleRadians = MathFunctions::toRadians(newRotationAngle); const float dy = lengthMidToOne * std::sin(angleRadians); @@ -496,12 +496,12 @@ AnnotationOneDimensionalShape::applySpatialModificationTabOrWindowSpace(const An float newX2 = xyz2[0]; float newY2 = xyz2[1]; - const float spaceDX = 100.0 * ((spatialModification.m_viewportWidth != 0.0) + const float spaceDX = 100.0f * ((spatialModification.m_viewportWidth != 0.0f) ? (spatialModification.m_mouseDX / spatialModification.m_viewportWidth) - : 0.0); - const float spaceDY = 100.0 * ((spatialModification.m_viewportHeight != 0.0) + : 0.0f); + const float spaceDY = 100.0f * ((spatialModification.m_viewportHeight != 0.0f) ? (spatialModification.m_mouseDY / spatialModification.m_viewportHeight) - : 0.0); + : 0.0f); bool validFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 0177e8367..1be5ce2b4 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1137,12 +1137,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil } const float selectionCenterXYZ[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; - if (box->getLineWidthPercentage() <= 0.0) { + if (box->getLineWidthPercentage() <= 0.0f) { convertObsoleteLineWidthPixelsToPercentageWidth(box); } @@ -1154,8 +1154,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil uint8_t foregroundRGBA[4]; box->getLineColorRGBA(foregroundRGBA); - const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0); - const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; @@ -1267,9 +1267,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati } const float selectionCenterXYZ[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(colorBar); @@ -1280,7 +1280,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati float foregroundRGBA[4]; colorBar->getLineColorRGBA(foregroundRGBA); - const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0); + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0f); if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; @@ -1330,8 +1330,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati float ticksMarksHeightPercent = totalHeightPercent * 0.10; float sectionsHeightPercent = totalHeightPercent - (ticksMarksHeightPercent - textHeightPercent); - if (sectionsHeightPercent <= 0.0) { - sectionsHeightPercent = totalHeightPercent * 0.10; + if (sectionsHeightPercent <= 0.0f) { + sectionsHeightPercent = totalHeightPercent * 0.10f; textHeightPercent = totalHeightPercent - sectionsHeightPercent; } @@ -1341,12 +1341,12 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati * Text is aligned at the top of the characters */ const float totalHeightPixels = (viewportHeight - * (totalHeightPercent / 100.0)); + * (totalHeightPercent / 100.0f)); const float textOffsetFromTopPixels = 2; const float textHeightPixels = (viewportHeight - * (textHeightPercent / 100.0)); + * (textHeightPercent / 100.0f)); const float tickMarksHeightPixels = (viewportHeight - * (ticksMarksHeightPercent / 100.0)); + * (ticksMarksHeightPercent / 100.0f)); const float sectionsHeightPixels = (totalHeightPixels - (textHeightPixels + textOffsetFromTopPixels @@ -1570,8 +1570,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation const float xBottomLeft = bottomLeft[0]; const float yBottomLeft = bottomLeft[1]; - float minScalar = 0.0; - float maxScalar = 0.0; + float minScalar = 0.0f; + float maxScalar = 0.0f; colorBar->getScalarMinimumAndMaximumValues(minScalar, maxScalar); const float dScalar = maxScalar - minScalar; @@ -1581,7 +1581,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const Annotation std::cout << qPrintable(QString("minScalar %1, maxScalar %2, dScalar %3").arg(minScalar).arg(maxScalar).arg(dScalar)) << std::endl; } - const float z = 0.0; + const float z = 0.0f; std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); @@ -1784,8 +1784,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi return false; } - const float majorAxis = ((oval->getWidth() / 100.0) * (m_modelSpaceViewport[2] / 2.0)); - const float minorAxis = ((oval->getHeight() / 100.0) * (m_modelSpaceViewport[3] / 2.0)); + const float majorAxis = ((oval->getWidth() / 100.0f) * (m_modelSpaceViewport[2] / 2.0f)); + const float minorAxis = ((oval->getHeight() / 100.0f) * (m_modelSpaceViewport[3] / 2.0f)); const float rotationAngle = oval->getRotationAngle(); if (oval->getLineWidthPercentage() <= 0.0) { @@ -1793,9 +1793,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi } const float selectionCenterXYZ[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(oval); @@ -1806,8 +1806,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi uint8_t foregroundRGBA[4]; oval->getLineColorRGBA(foregroundRGBA); - const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0); - const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; @@ -1816,7 +1816,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi glPushMatrix(); glTranslatef(annXYZ[0], annXYZ[1], annXYZ[2]); if (rotationAngle != 0.0) { - glRotatef(-rotationAngle, 0.0, 0.0, 1.0); + glRotatef(-rotationAngle, 0.0f, 0.0f, 1.0f); } if (m_selectionModeFlag) { @@ -2143,9 +2143,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi bottomLeft, bottomRight, topRight, topLeft); const float selectionCenterXYZ[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(text); @@ -2158,8 +2158,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi uint8_t textColorRGBA[4]; text->getTextColorRGBA(textColorRGBA); - const bool drawTextFlag = (textColorRGBA[3] > 0.0); - const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0); + const bool drawTextFlag = (textColorRGBA[3] > 0); + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0f); const bool drawAnnotationFlag = (drawBackgroundFlag || drawTextFlag); bool drawnFlag = false; @@ -2270,7 +2270,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi */ const bool drawCrossFlag = false; if (drawCrossFlag) { - const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; + const float redRGBA[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); crossShape->addVertex(annXYZ[0], @@ -2288,7 +2288,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi } if (percentSizeText != NULL) { - if (savedFontPercentViewportHeight > 0.0) { + if (savedFontPercentViewportHeight > 0.0f) { percentSizeText->setFontPercentViewportSize(savedFontPercentViewportHeight); if ( ! modifiedStatus) { percentSizeText->clearModified(); @@ -2350,9 +2350,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } const float selectionCenterXYZ[3] = { - (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0, - (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0, - (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0 + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(image); @@ -2402,7 +2402,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF } if (drawForegroundFlag) { - if (image->getLineWidthPercentage() <= 0.0) { + if (image->getLineWidthPercentage() <= 0.0f) { convertObsoleteLineWidthPixelsToPercentageWidth(image); } GraphicsShape::drawBoxOutlineFloatColor(bottomLeft, bottomRight, topRight, topLeft, @@ -2598,9 +2598,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPercentage()); const float selectionCenterXYZ[3] = { - (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0, - (lineHeadXYZ[1] + lineTailXYZ[1]) / 2.0, - (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0 + (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0f, + (lineHeadXYZ[1] + lineTailXYZ[1]) / 2.0f, + (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(line); @@ -2621,7 +2621,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi uint8_t foregroundRGBA[4]; line->getLineColorRGBA(foregroundRGBA); - const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0f); bool drawnFlag = false; @@ -2794,11 +2794,11 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi else if (drawOutlineCircleFlag) { const float diameter = halfWidthHeight; glPushMatrix(); - glScaled(diameter, diameter, 1.0); + glScaled(diameter, diameter, 1.0f); GraphicsShape::drawRing(NULL, m_selectionBoxRGBA, - 0.7, - 1.0); + 0.7f, + 1.0f); glPopMatrix(); } } @@ -2882,9 +2882,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { const float midPointXYZ[3] = { - (firstPoint[0] + secondPoint[0]) / 2.0, - (firstPoint[1] + secondPoint[1]) / 2.0, - (firstPoint[2] + secondPoint[2]) / 2.0 + (firstPoint[0] + secondPoint[0]) / 2.0f, + (firstPoint[1] + secondPoint[1]) / 2.0f, + (firstPoint[2] + secondPoint[2]) / 2.0f }; drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, @@ -2981,7 +2981,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); MathFunctions::normalizeVector(heightVector); - const float innerSpacing = 2.0 + (lineThickness / 2.0); + const float innerSpacing = 2.0f + (lineThickness / 2.0f); float handleTopLeft[3]; float handleTopRight[3]; float handleBottomRight[3]; @@ -3000,27 +3000,27 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann } const float handleLeft[3] = { - (handleBottomLeft[0] + handleTopLeft[0]) / 2.0, - (handleBottomLeft[1] + handleTopLeft[1]) / 2.0, - (handleBottomLeft[2] + handleTopLeft[2]) / 2.0, + (handleBottomLeft[0] + handleTopLeft[0]) / 2.0f, + (handleBottomLeft[1] + handleTopLeft[1]) / 2.0f, + (handleBottomLeft[2] + handleTopLeft[2]) / 2.0f, }; const float handleRight[3] = { - (handleBottomRight[0] + handleTopRight[0]) / 2.0, - (handleBottomRight[1] + handleTopRight[1]) / 2.0, - (handleBottomRight[2] + handleTopRight[2]) / 2.0, + (handleBottomRight[0] + handleTopRight[0]) / 2.0f, + (handleBottomRight[1] + handleTopRight[1]) / 2.0f, + (handleBottomRight[2] + handleTopRight[2]) / 2.0f, }; const float handleBottom[3] = { - (handleBottomLeft[0] + handleBottomRight[0]) / 2.0, - (handleBottomLeft[1] + handleBottomRight[1]) / 2.0, - (handleBottomLeft[2] + handleBottomRight[2]) / 2.0, + (handleBottomLeft[0] + handleBottomRight[0]) / 2.0f, + (handleBottomLeft[1] + handleBottomRight[1]) / 2.0f, + (handleBottomLeft[2] + handleBottomRight[2]) / 2.0f, }; const float handleTop[3] = { - (handleTopLeft[0] + handleTopRight[0]) / 2.0, - (handleTopLeft[1] + handleTopRight[1]) / 2.0, - (handleTopLeft[2] + handleTopRight[2]) / 2.0, + (handleTopLeft[0] + handleTopRight[0]) / 2.0f, + (handleTopLeft[1] + handleTopRight[1]) / 2.0f, + (handleTopLeft[2] + handleTopRight[2]) / 2.0f, }; const float sizeHandleSize = 5.0; @@ -3201,7 +3201,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() * True if the annotation is drawn with depth testing, else false. */ bool -BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* annotation) +BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* /*annotation*/) { return true; /* diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index 41f4d3298..baba23b0b 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -945,26 +945,26 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const Ch if (applyTransformationsFlag) { glTranslatef(m_translation[0], m_translation[1], - 0.0); + 0.0f); const float chartWidth = chartGraphicsDrawingViewport[2]; const float chartHeight = chartGraphicsDrawingViewport[3]; - const float halfWidth = chartWidth / 2.0; - const float halfHeight = chartHeight / 2.0; + const float halfWidth = chartWidth / 2.0f; + const float halfHeight = chartHeight / 2.0f; glTranslatef(halfWidth, halfHeight, - 0.0); + 0.0f); glScalef(m_zooming, m_zooming, - 1.0); + 1.0f); glTranslatef(-halfWidth, -halfHeight, - 0.0); + 0.0f); } if (m_identificationModeFlag) { int32_t primitiveIndex = -1; - float primitiveDepth = 0.0; + float primitiveDepth = 0.0f; GraphicsEngineDataOpenGL::drawWithSelection(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), m_fixedPipelineDrawing->mouseX, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index e754ab87f..8301bd69d 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2206,8 +2206,8 @@ BrainOpenGLFixedPipeline::drawSurfaceTriangles(Surface* surface, * Determine position in triangle using barycentric coordinates */ double displayXYZ[3] = { - this->mouseX, - this->mouseY, + (double)this->mouseX, + (double)this->mouseY, 0.0 }; @@ -2229,15 +2229,15 @@ BrainOpenGLFixedPipeline::drawSurfaceTriangles(Surface* surface, * Convert to surface coordinates */ const float projectedXYZ[3] = { - (dc1[0]*areaU + dc2[0]*areaV + dc3[0]*areaW) / totalArea, - (dc1[1]*areaU + dc2[1]*areaV + dc3[1]*areaW) / totalArea, - (dc1[2]*areaU + dc2[2]*areaV + dc3[2]*areaW) / totalArea + (float)((dc1[0]*areaU + dc2[0]*areaV + dc3[0]*areaW) / totalArea), + (float)((dc1[1]*areaU + dc2[1]*areaV + dc3[1]*areaW) / totalArea), + (float)((dc1[2]*areaU + dc2[2]*areaV + dc3[2]*areaW) / totalArea) }; const float barycentricAreas[3] = { - areaU, - areaV, - areaW + (float)areaU, + (float)areaV, + (float)areaW }; const int32_t barycentricNodes[3] = { @@ -2710,10 +2710,10 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) const uint8_t highlightLastPointRGBA[4] = { 0, 192, 0, 1 }; const uint8_t solidColorRGBA[4] = { - borderDrawInfo.rgba[0] * 255.0f, - borderDrawInfo.rgba[1] * 255.0f, - borderDrawInfo.rgba[2] * 255.0f, - borderDrawInfo.rgba[3] * 255.0f + static_cast(borderDrawInfo.rgba[0] * 255.0f), + static_cast(borderDrawInfo.rgba[1] * 255.0f), + static_cast(borderDrawInfo.rgba[2] * 255.0f), + static_cast(borderDrawInfo.rgba[3] * 255.0f) }; std::unique_ptr pointsPrimitive; @@ -3210,10 +3210,10 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) } else { const uint8_t rgbaByte[4] = { - rgbaFloat[0] * 255, - rgbaFloat[1] * 255, - rgbaFloat[2] * 255, - rgbaFloat[3] * 255, + static_cast(rgbaFloat[0] * 255), + static_cast(rgbaFloat[1] * 255), + static_cast(rgbaFloat[2] * 255), + static_cast(rgbaFloat[3] * 255) }; fociPrimitive->addVertex(xyz, rgbaByte); } @@ -4206,9 +4206,9 @@ BrainOpenGLFixedPipeline::drawAllFiberOrientations(const FiberOrientationDisplay }; const float halfMagnitudeVector[3] = { - magnitudeVector[0] * 0.5, - magnitudeVector[1] * 0.5, - magnitudeVector[2] * 0.5, + magnitudeVector[0] * 0.5f, + magnitudeVector[1] * 0.5f, + magnitudeVector[2] * 0.5f, }; /* diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 13b215ecd..45b38efbb 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -2386,20 +2386,20 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten * Need to account for the quadrants!!!! */ const float viewportCenter[3] = { - sliceViewport[0] + sliceViewport[2] / 2, - sliceViewport[1] + sliceViewport[3] / 2, + (float)(sliceViewport[0] + sliceViewport[2] / 2), + ((float)sliceViewport[1] + sliceViewport[3] / 2), 0.0 }; const float oldPos[3] = { - previousMouseX, - previousMouseY, + (float)previousMouseX, + (float)previousMouseY, 0.0 }; const float newPos[3] = { - mouseX, - mouseY, + (float)mouseX, + (float)mouseY, 0.0 }; diff --git a/src/Files/ImageFile.cxx b/src/Files/ImageFile.cxx index 442e1db04..31ea0cf9c 100644 --- a/src/Files/ImageFile.cxx +++ b/src/Files/ImageFile.cxx @@ -1458,7 +1458,7 @@ ImageFile::convertToVolumeFile(const CONVERT_TO_VOLUME_COLOR_MODE colorMode, transformationMatrix->multiplyPoint3(firstPixel); std::cout << "First pixel coord: " << AString::fromNumbers(firstPixel, 3, ",") << std::endl; - float lastPixel[3] = { width - 1, height - 1, 0 }; + float lastPixel[3] = { (float)(width - 1), (float)(height - 1), 0.0f }; transformationMatrix->multiplyPoint3(lastPixel); std::cout << "Last pixel coord: " << AString::fromNumbers(lastPixel, 3, ",") << std::endl; @@ -1467,13 +1467,13 @@ ImageFile::convertToVolumeFile(const CONVERT_TO_VOLUME_COLOR_MODE colorMode, transformationMatrix->multiplyPoint3(bl); ControlPoint3D bottomLeft(0, 0, 0, bl[0], bl[1], bl[2]); - float br[3] = { width - 1.0, 0.0, 0.0 }; + float br[3] = { (float)(width - 1.0), 0.0, 0.0 }; transformationMatrix->multiplyPoint3(br); ControlPoint3D bottomRight(width - 1.0, 0.0, 0.0, br[0], br[1], br[2]); - float tr[3] = { width - 1.0, height - 1.0, 0.0 }; + float tr[3] = { (float)(width - 1.0), (float)(height - 1.0), 0.0 }; transformationMatrix->multiplyPoint3(tr); - ControlPoint3D topRight(width - 1.0, height - 1.0, 0.0, tr[0], tr[1], tr[2]); + ControlPoint3D topRight((float)(width - 1.0), (float)(height - 1.0), 0.0, tr[0], tr[1], tr[2]); ControlPointFile volumeControlPointFile; volumeControlPointFile.addControlPoint(bottomLeft); diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 420f4d9f5..a6ea8067a 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -373,7 +373,7 @@ OperationShowScene::useParameters(OperationParameters* myParams, + QString::number(imageHeight)); } - int windowViewport[4] = { 0.0, 0.0, imageWidth, imageHeight }; + int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; float aspectRatio = -1.0; const bool windowAspectRatioLocked = browserClass->getBooleanValue("m_aspectRatioLockedStatus"); -- GitLab From 0554399298472181062f6df2704dc484ea1534f9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 12 Jan 2018 15:11:19 -0600 Subject: [PATCH 588/755] Resolve WB-769 Surface ID node creates 'notch' in volume/surface contour outline: This problem occurred when the volume slice had the same coordinate as a vertex which causes an intersection problem. Code to prevent the intersection problem moved the vertex slightly away from the plane and this code was mistakenly assigning the Y value to the Z value causing the 'notch'. --- src/Files/SurfacePlaneIntersectionToContour.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Files/SurfacePlaneIntersectionToContour.cxx b/src/Files/SurfacePlaneIntersectionToContour.cxx index 73637d914..8f37912ba 100644 --- a/src/Files/SurfacePlaneIntersectionToContour.cxx +++ b/src/Files/SurfacePlaneIntersectionToContour.cxx @@ -202,12 +202,12 @@ SurfacePlaneIntersectionToContour::prepareVertices() if (signedDistanceToPlane >= 0) { xyz[0] = projectedXYZ[0] + abovePlaneOffset[0]; xyz[1] = projectedXYZ[1] + abovePlaneOffset[1]; - xyz[2] = projectedXYZ[1] + abovePlaneOffset[2]; + xyz[2] = projectedXYZ[2] + abovePlaneOffset[2]; } else { xyz[0] = projectedXYZ[0] - abovePlaneOffset[0]; xyz[1] = projectedXYZ[1] - abovePlaneOffset[1]; - xyz[2] = projectedXYZ[1] - abovePlaneOffset[2]; + xyz[2] = projectedXYZ[2] - abovePlaneOffset[2]; } } -- GitLab From 8352b60e33702f1eb9458136abb857768b215975 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 11 Jan 2018 17:33:32 -0600 Subject: [PATCH 589/755] Fix some "narrowing" compilation warnings. --- src/Annotations/AnnotationOneDimensionalShape.cxx | 12 +++--------- .../BrainOpenGLAnnotationDrawingFixedPipeline.cxx | 6 +++--- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Annotations/AnnotationOneDimensionalShape.cxx b/src/Annotations/AnnotationOneDimensionalShape.cxx index f3a976aee..30416ca2d 100644 --- a/src/Annotations/AnnotationOneDimensionalShape.cxx +++ b/src/Annotations/AnnotationOneDimensionalShape.cxx @@ -325,25 +325,19 @@ AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp { bool chartFlag = false; bool tabWindowFlag = false; - bool stereotaxicFlag = false; - bool surfaceFlag = false; - bool viewportFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: chartFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - stereotaxicFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: - surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: tabWindowFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: - viewportFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: tabWindowFlag = true; @@ -551,9 +545,9 @@ AnnotationOneDimensionalShape::applySpatialModificationTabOrWindowSpace(const An vpTwoXYZ); float vpXYZ[3] = { - (vpOneXYZ[0] + vpTwoXYZ[0]) / 2.0, - (vpOneXYZ[1] + vpTwoXYZ[1]) / 2.0, - (vpOneXYZ[2] + vpTwoXYZ[2]) / 2.0 + (vpOneXYZ[0] + vpTwoXYZ[0]) / 2.0f, + (vpOneXYZ[1] + vpTwoXYZ[1]) / 2.0f, + (vpOneXYZ[2] + vpTwoXYZ[2]) / 2.0f }; /* diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 1be5ce2b4..7dc3bf839 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -3130,9 +3130,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann }; const float handleRotationLineEnd[3] = { - handleOffset[0] + (rotationOffset * 0.75 * heightVector[0] ), - handleOffset[1] + (rotationOffset * 0.75 * heightVector[1]), - handleOffset[2] + (rotationOffset * 0.75 * heightVector[2]) + handleOffset[0] + (rotationOffset * 0.75f * heightVector[0] ), + handleOffset[1] + (rotationOffset * 0.75f * heightVector[1]), + handleOffset[2] + (rotationOffset * 0.75f * heightVector[2]) }; /* -- GitLab From 05b22cfa26025bec9706b01ae1021308c0b5fb84 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 12 Jan 2018 09:42:52 -0600 Subject: [PATCH 590/755] Fix a number of compilation warnings, most of them due to "narrowing". --- src/Annotations/Annotation.cxx | 3 +-- .../BrainOpenGLChartDrawingFixedPipeline.cxx | 6 +++--- ...rainOpenGLChartTwoDrawingFixedPipeline.cxx | 2 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 12 ------------ src/Brain/ChartTwoOverlaySet.cxx | 4 ++-- src/Brain/DisplayPropertiesAnnotation.cxx | 4 ---- src/Brain/FtglFontTextRenderer.cxx | 8 ++++---- src/Brain/SurfaceNodeColoring.cxx | 2 +- src/Commands/CommandClassAddMember.cxx | 4 ++-- src/Common/MathFunctions.cxx | 19 +++---------------- src/Files/AnnotationFile.cxx | 11 +++++++++++ src/Files/BorderFile.cxx | 3 +-- src/Files/SurfaceProjectionVanEssen.cxx | 6 +++--- src/Files/VolumeFileEditorDelegate.cxx | 2 +- .../GraphicsOpenGLPolylineTriangles.cxx | 7 ++----- src/Graphics/GraphicsPrimitive.cxx | 2 +- src/Graphics/GraphicsPrimitive.h | 2 +- src/Graphics/GraphicsUtilitiesOpenGL.cxx | 8 ++++---- src/GuiQt/AnnotationCoordinateInformation.cxx | 12 ++++++------ src/GuiQt/AnnotationCoordinateWidget.cxx | 6 +++--- src/GuiQt/AnnotationFontWidget.cxx | 4 ++-- src/GuiQt/AnnotationLineArrowTipsWidget.cxx | 5 ----- .../BrainBrowserWindowToolBarChartTwoAxes.cxx | 3 +-- ...rainBrowserWindowToolBarSliceSelection.cxx | 6 +++--- src/GuiQt/ClippingPlanesDialog.cxx | 18 +++++++++--------- src/GuiQt/DataFileContentCopyMoveDialog.cxx | 3 +-- src/GuiQt/FociPropertiesEditorDialog.cxx | 6 +++--- src/GuiQt/GuiManager.cxx | 6 +++--- .../UserInputModeAnnotationsContextMenu.cxx | 2 -- src/Operations/OperationShowScene.cxx | 10 +++++----- 30 files changed, 77 insertions(+), 109 deletions(-) diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index 4e9753ae8..a3aa84b51 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -1144,8 +1144,7 @@ Annotation::initializeProperties() /* * Initialize all properties on/supported */ - const int32_t propertyCount = static_cast::type>(Property::COUNT_FOR_BITSET); - CaretAssert(m_properties.size() >= propertyCount); + CaretAssert(m_properties.size() >= static_cast::type>(Property::COUNT_FOR_BITSET)); m_properties.set(); bool colorBarFlag = false; diff --git a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx index b4f539076..961e662fe 100644 --- a/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx @@ -943,9 +943,9 @@ BrainOpenGLChartDrawingFixedPipeline::drawChartGraphicsMatrix(const int32_t view uint8_t highlightRGBByte[3]; prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); const float highlightRGB[3] = { - highlightRGBByte[0] / 255.0, - highlightRGBByte[1] / 255.0, - highlightRGBByte[2] / 255.0 + highlightRGBByte[0] / 255.0f, + highlightRGBByte[1] / 255.0f, + highlightRGBByte[2] / 255.0f }; int32_t numberOfRows = 0; diff --git a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx index baba23b0b..159655f6e 100644 --- a/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx @@ -1240,7 +1240,7 @@ BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableT const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, - const float zooming, + const float /*zooming*/, std::vector& rowColumnHighlightingOut) { GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 8301bd69d..3fac5c379 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2763,7 +2763,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) bool lastPointForLineValidFlag = false; float lastPointForLineXYZ[3] = { 0.0f, 0.0f, 0.0f }; - int32_t lastPointIndex = -1; /* * Find points valid for this surface */ @@ -2881,15 +2880,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } - /* - * Color for point - */ - uint8_t pointRGBA[4] = { - solidColorRGBA[0], - solidColorRGBA[1], - solidColorRGBA[2], - solidColorRGBA[3], - }; if (borderDrawInfo.isSelect) { uint8_t idRGBA[4]; this->colorIdentification->addItem(idRGBA, @@ -2897,7 +2887,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) borderDrawInfo.borderFileIndex, borderDrawInfo.borderIndex, i); - pointRGBA[3] = 255; if (pointsIdentificationPrimitive) { pointsIdentificationPrimitive->addVertex(xyz, idRGBA); @@ -2934,7 +2923,6 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) lastPointForLineXYZ[0] = xyz[0]; lastPointForLineXYZ[1] = xyz[1]; lastPointForLineXYZ[2] = xyz[2]; - lastPointIndex = i; lastPointForLineValidFlag = true; } diff --git a/src/Brain/ChartTwoOverlaySet.cxx b/src/Brain/ChartTwoOverlaySet.cxx index 10f1cc6d8..6a44acb52 100644 --- a/src/Brain/ChartTwoOverlaySet.cxx +++ b/src/Brain/ChartTwoOverlaySet.cxx @@ -785,8 +785,8 @@ ChartTwoOverlaySet::receiveEvent(Event* event) * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ - EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); - CaretAssert(chartLabelEvent); + //EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); + //CaretAssert(chartLabelEvent); //chartLabelEvent->addAnnotationChartLabel(m_chartTitle.get()); } diff --git a/src/Brain/DisplayPropertiesAnnotation.cxx b/src/Brain/DisplayPropertiesAnnotation.cxx index ff0f1fed6..71389ade5 100644 --- a/src/Brain/DisplayPropertiesAnnotation.cxx +++ b/src/Brain/DisplayPropertiesAnnotation.cxx @@ -364,10 +364,6 @@ DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) surfaceStatusInTab[i] = true; tabStatusInTab[i] = true; } - bool windowStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; - for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { - windowStatusInTab[i] = true; - } /* * Look for version one selections in the scene diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 8859a59ee..f8218bf49 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -576,10 +576,10 @@ FtglFontTextRenderer::drawOutline(const double minX, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - float bottomLeft[3] = { minX, minY, z }; - float bottomRight[3] = { maxX, minY, z }; - float topRight[3] = { maxX, maxY, z }; - float topLeft[3] = { minX, maxY, z }; + float bottomLeft[3] = { (float)minX, (float)minY, (float)z }; + float bottomRight[3] = { (float)maxX, (float)minY, (float)z }; + float topRight[3] = { (float)maxX, (float)maxY, (float)z }; + float topLeft[3] = { (float)minX, (float)maxY, (float)z }; expandBox(bottomLeft, bottomRight, topRight, topLeft, outlineThickness, outlineThickness); diff --git a/src/Brain/SurfaceNodeColoring.cxx b/src/Brain/SurfaceNodeColoring.cxx index ece3087dc..0b3915314 100644 --- a/src/Brain/SurfaceNodeColoring.cxx +++ b/src/Brain/SurfaceNodeColoring.cxx @@ -253,7 +253,7 @@ SurfaceNodeColoring::showBrainordinateHighlightRegionOfInterest(const Brain* bra const float foregroundColor[4] = { static_cast(foregroundColorByte[0]) / 255.0f, static_cast(foregroundColorByte[1]) / 255.0f, - static_cast(foregroundColorByte[2]) / 255.0, + static_cast(foregroundColorByte[2]) / 255.0f, 1.0f }; diff --git a/src/Commands/CommandClassAddMember.cxx b/src/Commands/CommandClassAddMember.cxx index f2773bc0b..04d741124 100644 --- a/src/Commands/CommandClassAddMember.cxx +++ b/src/Commands/CommandClassAddMember.cxx @@ -162,7 +162,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) * is a class and use a pointer for the class. However, * treat AString and QString as primitive types. */ - bool isEnum = false; + //bool isEnum = false; bool isString = false; bool isClass = false; const QChar firstDataTypeChar = dataType[0]; @@ -172,7 +172,7 @@ CommandClassAddMember::executeOperation(ProgramParameters& parameters) isString = true; } else if (dataType.endsWith("Enum")) { - isEnum = true; + //isEnum = true; } else { isClass = true; diff --git a/src/Common/MathFunctions.cxx b/src/Common/MathFunctions.cxx index bf2f76995..f741aebcd 100644 --- a/src/Common/MathFunctions.cxx +++ b/src/Common/MathFunctions.cxx @@ -1479,10 +1479,10 @@ MathFunctions::vectorIntersection2D( const float p2[2], const float q1[2], const float q2[2], - const float tolerance, + const float /*tolerance*/, float intersectionOut[2]) { - double tol = tolerance; +// double tol = tolerance; double x1 = p1[0]; double y1 = p1[1]; double x2 = p2[0]; @@ -1501,22 +1501,9 @@ MathFunctions::vectorIntersection2D( double x = ((a * (x3 - x4)) - (c * (x1 - x2))) / denom; double y = ((a * (y3 - y4)) - (c * (y1 - y2))) / denom; -// double pxMax = std::max(x1, x2) + tol; -// double pxMin = std::min(x1, x2) - tol; -// double pyMax = std::max(y1, y2) + tol; -// double pyMin = std::min(y1, y2) - tol; -// -// double qxMax = std::max(x3, x4) + tol; -// double qxMin = std::min(x3, x4) - tol; -// double qyMax = std::max(y3, y4) + tol; -// double qyMin = std::min(y3, y4) - tol; - intersectionOut[0] = (float)x; intersectionOut[1] = (float)y; -// if ((x >= pxMin) && (x <= pxMax) && (x >= qxMin) && (x <= qxMax) && -// (y >= pyMin) && (y <= pyMax) && (y >= qyMin) && (y <= qyMax)) { - return true; -// } + return true; } return false; diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index d5e0728c3..c21e827f1 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -1241,6 +1241,17 @@ AnnotationFile::processRegroupingAnnotations(EventAnnotationGrouping* groupingEv } } + if ( ! allValidFlag) { + for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); + annPtrIter != movedAnnotations.end(); + annPtrIter++) { + spaceGroup->addAnnotationPrivateSharedPointer(*annPtrIter); + } + + groupingEvent->setErrorMessage("PROGRAM ERROR: Failed to remove an anntotation from its space group."); + return; + } + for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); annPtrIter++) { diff --git a/src/Files/BorderFile.cxx b/src/Files/BorderFile.cxx index a8b470cbd..13c0bb791 100644 --- a/src/Files/BorderFile.cxx +++ b/src/Files/BorderFile.cxx @@ -888,8 +888,7 @@ BorderFile::findBordersInsideRegionOfInterest(const DisplayGroupEnum::Enum displ std::vector >& insideCountAndBorderOut) const { CaretAssert(surfaceFile); - const int32_t surfaceNumberOfNodes = surfaceFile->getNumberOfNodes(); - CaretAssert(surfaceNumberOfNodes == static_cast(nodesInROI.size())); + CaretAssert(surfaceFile->getNumberOfNodes() == static_cast(nodesInROI.size())); insideCountAndBorderOut.clear(); diff --git a/src/Files/SurfaceProjectionVanEssen.cxx b/src/Files/SurfaceProjectionVanEssen.cxx index ef35a0c22..ac0743261 100644 --- a/src/Files/SurfaceProjectionVanEssen.cxx +++ b/src/Files/SurfaceProjectionVanEssen.cxx @@ -236,9 +236,9 @@ SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, const float* normalJ = surfaceFile.getNormalVector(pjs); float avgNormal[3] = { - ((normalI[0] + normalJ[0]) / 2.0), - ((normalI[1] + normalJ[1]) / 2.0), - ((normalI[2] + normalJ[2]) / 2.0), + ((normalI[0] + normalJ[0]) / 2.0f), + ((normalI[1] + normalJ[1]) / 2.0f), + ((normalI[2] + normalJ[2]) / 2.0f), }; MathFunctions::normalizeVector(avgNormal); diff --git a/src/Files/VolumeFileEditorDelegate.cxx b/src/Files/VolumeFileEditorDelegate.cxx index 906bcd5b7..b1e244f47 100644 --- a/src/Files/VolumeFileEditorDelegate.cxx +++ b/src/Files/VolumeFileEditorDelegate.cxx @@ -605,7 +605,7 @@ VolumeFileEditorDelegate::performTurnOnOrOffOblique(const EditInfo& editInfo, float ijkFloat[3]; m_volumeFile->spaceToIndex(brushXYZ, ijkFloat); - int64_t ijk[3] = { ijkFloat[0], ijkFloat[1], ijkFloat[2] }; + int64_t ijk[3] = { (int64_t)ijkFloat[0], (int64_t)ijkFloat[1], (int64_t)ijkFloat[2] }; modifiedVoxels->addVoxelRedoUndo(ijk, redoVoxelValue, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); diff --git a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx index 3a241abf3..533424393 100644 --- a/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx +++ b/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx @@ -923,10 +923,8 @@ GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, int32_t quadOneSideEndVertexIndex = -1; int32_t quadTwoSideBeginVertexIndex = -1; - bool leftTurnFlag = false; switch (turnDirection) { case TurnDirection::LEFT: - leftTurnFlag = true; if (m_debugFlag) std::cout << " Left Turn" << std::endl; /* @@ -940,7 +938,6 @@ GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, return; break; case TurnDirection::RIGHT: - leftTurnFlag = false; if (m_debugFlag) std::cout << " Right Turn" << std::endl; /* @@ -1198,11 +1195,11 @@ GraphicsOpenGLPolylineTriangles::getAverageColorRGBA(const int32_t primitiveVert */ uint8_t rgbaOneByte[4]; m_primitiveByteColor->getVertexByteRGBA(primitiveVertexOneIndex, rgbaOneByte); - float rgbaOne[4] = { rgbaOneByte[0], rgbaOneByte[1], rgbaOneByte[2], rgbaOneByte[3] }; + float rgbaOne[4] = { (float)rgbaOneByte[0], (float)rgbaOneByte[1], (float)rgbaOneByte[2], (float)rgbaOneByte[3] }; uint8_t rgbaTwoByte[4]; m_primitiveByteColor->getVertexByteRGBA(primitiveVertexTwoIndex, rgbaTwoByte); - float rgbaTwo[4] = { rgbaTwoByte[0], rgbaTwoByte[1], rgbaTwoByte[2], rgbaTwoByte[3] }; + float rgbaTwo[4] = { (float)rgbaTwoByte[0], (float)rgbaTwoByte[1], (float)rgbaTwoByte[2], (float)rgbaTwoByte[3] }; rgbaOut[0] = static_cast((rgbaOne[0] + rgbaTwo[0]) / 2.0f); rgbaOut[1] = static_cast((rgbaOne[1] + rgbaTwo[1]) / 2.0f); diff --git a/src/Graphics/GraphicsPrimitive.cxx b/src/Graphics/GraphicsPrimitive.cxx index e7f636f70..4b9b44a79 100644 --- a/src/Graphics/GraphicsPrimitive.cxx +++ b/src/Graphics/GraphicsPrimitive.cxx @@ -1376,7 +1376,7 @@ GraphicsPrimitive::setPointDiameter(const PointSizeType sizeType, */ void GraphicsPrimitive::getLineWidth(LineWidthType& widthTypeOut, - float lineWidthOut) const + float& lineWidthOut) const { widthTypeOut = m_lineWidthType; lineWidthOut = m_lineWidthValue; diff --git a/src/Graphics/GraphicsPrimitive.h b/src/Graphics/GraphicsPrimitive.h index 7f1e0823f..b8374dcc2 100644 --- a/src/Graphics/GraphicsPrimitive.h +++ b/src/Graphics/GraphicsPrimitive.h @@ -372,7 +372,7 @@ namespace caret { const float pointDiameter) const; void getLineWidth(LineWidthType& widthTypeOut, - float lineWidthOut) const; + float& lineWidthOut) const; void setLineWidth(const LineWidthType widthType, const float lineWidth) const; diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index 8cbaba87a..10cd5cc32 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -76,8 +76,8 @@ GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(const fl const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; - float bottomWindowXYZ[3] = { viewport[0], viewport[1], windowZ }; - float topWindowXYZ[3] = { viewport[0], viewport[1] + viewport[3], windowZ }; + float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; + float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; @@ -118,8 +118,8 @@ GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(const float pixels) const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; - float bottomWindowXYZ[3] = { viewport[0], viewport[1], windowZ }; - float topWindowXYZ[3] = { viewport[0], viewport[1] + viewport[3], windowZ }; + float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; + float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; diff --git a/src/GuiQt/AnnotationCoordinateInformation.cxx b/src/GuiQt/AnnotationCoordinateInformation.cxx index c0e8ea79f..0fa8a6f4a 100644 --- a/src/GuiQt/AnnotationCoordinateInformation.cxx +++ b/src/GuiQt/AnnotationCoordinateInformation.cxx @@ -649,9 +649,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_chartXYZValid) { float centerXYZ[3] = { - (coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, - (coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, - (coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f + (float)(coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, + (float)(coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, + (float)(coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; @@ -669,9 +669,9 @@ AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(Annotati if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_modelXYZValid) { float centerXYZ[3] = { - (coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, - (coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, - (coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f + (float)(coordInfoOne->m_modelXYZ[0] + optionalCoordInfoTwo->m_modelXYZ[0]) / 2.0f, + (float)(coordInfoOne->m_modelXYZ[1] + optionalCoordInfoTwo->m_modelXYZ[1]) / 2.0f, + (float)(coordInfoOne->m_modelXYZ[2] + optionalCoordInfoTwo->m_modelXYZ[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index b7befba5e..3ce4baf43 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -470,9 +470,9 @@ AnnotationCoordinateWidget::valueChanged() } else { float xyz[3] = { - m_xCoordSpinBox->value(), - m_yCoordSpinBox->value(), - m_zCoordSpinBox->value() + (float)m_xCoordSpinBox->value(), + (float)m_yCoordSpinBox->value(), + (float)m_zCoordSpinBox->value() }; coordinateCopy.setXYZ(xyz); } diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index bd56e2932..08380cabc 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -293,7 +293,7 @@ AnnotationFontWidget::updateFontNameControls() { if ( ! m_annotationsFontName.empty()) { AnnotationTextFontNameEnum::Enum fontName = AnnotationTextFontNameEnum::VERA; - bool fontNameValid = true; + //bool fontNameValid = true; const int32_t numAnn = static_cast(m_annotationsFontName.size()); for (int32_t i = 0; i < numAnn; i++) { @@ -306,7 +306,7 @@ AnnotationFontWidget::updateFontNameControls() } else { if (annText->getFont() != fontName) { - fontNameValid = false; + //fontNameValid = false; } } } diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index 2d218a7be..081af4789 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -121,11 +121,6 @@ AnnotationLineArrowTipsWidget::updateContent(std::vector& annot } } - AnnotationLine* line = NULL; - if ( ! annotationLines.empty()) { - line = annotationLines[0]; - } - bool allStartOnFlag = true; bool allEndOnFlag = true; diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx index 93d375ee7..65572ff77 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx @@ -376,8 +376,7 @@ void BrainBrowserWindowToolBarChartTwoAxes::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { - EventBrowserWindowGraphicsRedrawn* redrawEvent = dynamic_cast(event); - CaretAssert(redrawEvent); + CaretAssert(dynamic_cast(event)); updateContent(getTabContentFromSelectedTab()); } else { diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index fb897c3df..d32db99fd 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -662,9 +662,9 @@ BrainBrowserWindowToolBarSliceSelection::readVolumeSliceCoordinatesAndUpdateSlic if (underlayVolumeFile != NULL) { float sliceCoords[3] = { - m_volumeIndicesXcoordSpinBox->value(), - m_volumeIndicesYcoordSpinBox->value(), - m_volumeIndicesZcoordSpinBox->value() + (float)m_volumeIndicesXcoordSpinBox->value(), + (float)m_volumeIndicesYcoordSpinBox->value(), + (float)m_volumeIndicesZcoordSpinBox->value() }; btc->selectSlicesAtCoordinate(sliceCoords); diff --git a/src/GuiQt/ClippingPlanesDialog.cxx b/src/GuiQt/ClippingPlanesDialog.cxx index ccbe347d8..c45140daa 100644 --- a/src/GuiQt/ClippingPlanesDialog.cxx +++ b/src/GuiQt/ClippingPlanesDialog.cxx @@ -367,21 +367,21 @@ void ClippingPlanesDialog::clippingValueChanged() { const float panning[3] = { - m_xPanDoubleSpinBox->value(), - m_yPanDoubleSpinBox->value(), - m_zPanDoubleSpinBox->value() + (float)m_xPanDoubleSpinBox->value(), + (float)m_yPanDoubleSpinBox->value(), + (float)m_zPanDoubleSpinBox->value() }; const float rotation[3] = { - m_xRotateDoubleSpinBox->value(), - m_yRotateDoubleSpinBox->value(), - m_zRotateDoubleSpinBox->value() + (float)m_xRotateDoubleSpinBox->value(), + (float)m_yRotateDoubleSpinBox->value(), + (float)m_zRotateDoubleSpinBox->value() }; const float thickness[3] ={ - m_xThicknessDoubleSpinBox->value(), - m_yThicknessDoubleSpinBox->value(), - m_zThicknessDoubleSpinBox->value() + (float)m_xThicknessDoubleSpinBox->value(), + (float)m_yThicknessDoubleSpinBox->value(), + (float)m_zThicknessDoubleSpinBox->value() }; /* diff --git a/src/GuiQt/DataFileContentCopyMoveDialog.cxx b/src/GuiQt/DataFileContentCopyMoveDialog.cxx index b29715d71..86aa98327 100644 --- a/src/GuiQt/DataFileContentCopyMoveDialog.cxx +++ b/src/GuiQt/DataFileContentCopyMoveDialog.cxx @@ -262,8 +262,7 @@ DataFileContentCopyMoveDialog::okButtonClicked() if (m_newDestinationFileName.isEmpty()) { throw DataFileException("New file name is empty."); } - const CaretDataFile* caretDataFile = dynamic_cast(m_sourceDataFileInterface); - CaretAssert(caretDataFile); + CaretAssert(dynamic_cast(m_sourceDataFileInterface)); destinationFile = m_sourceDataFileInterface->newInstanceOfDataFile(); if (destinationFile == NULL) { throw DataFileException("Failed to created new file."); diff --git a/src/GuiQt/FociPropertiesEditorDialog.cxx b/src/GuiQt/FociPropertiesEditorDialog.cxx index bb9f7cb3a..f3d71332e 100644 --- a/src/GuiQt/FociPropertiesEditorDialog.cxx +++ b/src/GuiQt/FociPropertiesEditorDialog.cxx @@ -652,9 +652,9 @@ FociPropertiesEditorDialog::loadFromDialogIntoFocusData(Focus* focus) const focus->setName(m_nameComboBox->getSelectedLabelName()); focus->setClassName(m_classComboBox->getSelectedLabelName()); const float xyz[3] = { - m_xCoordSpinBox->value(), - m_yCoordSpinBox->value(), - m_zCoordSpinBox->value() + (float)m_xCoordSpinBox->value(), + (float)m_yCoordSpinBox->value(), + (float)m_zCoordSpinBox->value() }; CaretAssert(focus->getNumberOfProjections() > 0); focus->getProjection(0)->setStereotaxicXYZ(xyz); diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 613b775e4..ac3406d00 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -2635,9 +2635,9 @@ GuiManager::processIdentification(const int32_t tabIndex, double doubleXYZ[3]; idVoxel->getModelXYZ(doubleXYZ); const float voxelXYZ[3] = { - doubleXYZ[0], - doubleXYZ[1], - doubleXYZ[2] + (float)doubleXYZ[0], + (float)doubleXYZ[1], + (float)doubleXYZ[2] }; Surface* surface = brain->getPrimaryAnatomicalSurfaceNearestCoordinate(voxelXYZ, 3.0); diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 1f857bf35..78158b914 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -138,13 +138,11 @@ m_newAnnotationCreatedByContextMenu(NULL) } const bool haveThreeDimCoordAnnotationsFlag = ( ! m_threeDimCoordAnnotations.empty()); - bool oneAnnotationSelectedFlag = false; bool oneDeletableAnnotationSelectedFlag = false; if (selectedAnnotations.size() == 1) { CaretAssertVectorIndex(selectedAnnotations, 0); m_annotationFile = selectedAnnotations[0].second; m_annotation = selectedAnnotations[0].first; - oneAnnotationSelectedFlag = true; if (m_annotation->testProperty(Annotation::Property::DELETION)) { oneDeletableAnnotationSelectedFlag = true; } diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index a6ea8067a..289703756 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -375,11 +375,11 @@ OperationShowScene::useParameters(OperationParameters* myParams, int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; - float aspectRatio = -1.0; - const bool windowAspectRatioLocked = browserClass->getBooleanValue("m_aspectRatioLockedStatus"); - if (windowAspectRatioLocked) { - aspectRatio = browserClass->getFloatValue("m_aspectRatio", -1.0); - } +// float aspectRatio = -1.0; +// const bool windowAspectRatioLocked = browserClass->getBooleanValue("m_aspectRatioLockedStatus"); +// if (windowAspectRatioLocked) { +// aspectRatio = browserClass->getFloatValue("m_aspectRatio", -1.0); +// } const int windowWidth = windowViewport[2]; const int windowHeight = windowViewport[3]; -- GitLab From 77dc9c2e74ae36ee0080f9b2e792f0c25c5851e2 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 16 Jan 2018 15:29:21 -0600 Subject: [PATCH 591/755] Move some OpenGL error processing out of Brain module and into Graphics so other modules may test for OpenGL errors. --- src/Brain/BrainOpenGL.cxx | 67 +++------- src/Brain/FtglFontTextRenderer.cxx | 33 ++--- src/FtglFont/CMakeLists.txt | 4 + src/FtglFont/FTGlyph/FTTextureGlyph.cpp | 23 +++- src/Graphics/CMakeLists.txt | 2 + src/Graphics/CaretOpenGLInclude.h | 2 +- src/Graphics/GraphicsOpenGLError.cxx | 163 +++++++++++++++++++++++ src/Graphics/GraphicsOpenGLError.h | 92 +++++++++++++ src/Graphics/GraphicsUtilitiesOpenGL.cxx | 39 ++++++ src/Graphics/GraphicsUtilitiesOpenGL.h | 6 + 10 files changed, 357 insertions(+), 74 deletions(-) create mode 100644 src/Graphics/GraphicsOpenGLError.cxx create mode 100644 src/Graphics/GraphicsOpenGLError.h diff --git a/src/Brain/BrainOpenGL.cxx b/src/Brain/BrainOpenGL.cxx index 83adb4b2e..8ba370ccc 100644 --- a/src/Brain/BrainOpenGL.cxx +++ b/src/Brain/BrainOpenGL.cxx @@ -40,7 +40,9 @@ #include "EventOpenGLObjectToWindowTransform.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" +#include "GraphicsOpenGLError.h" #include "GraphicsOpenGLTextureName.h" +#include "GraphicsUtilitiesOpenGL.h" #include "Model.h" #include "SessionManager.h" @@ -1225,7 +1227,7 @@ AString BrainOpenGL::getOpenGLEnabledEnumAsText(const AString& enumName, /* * Reset error status */ - glGetError(); + GraphicsUtilitiesOpenGL::resetOpenGLError(); GLboolean boolValue= glIsEnabled(enumValue); @@ -1234,7 +1236,7 @@ AString BrainOpenGL::getOpenGLEnabledEnumAsText(const AString& enumName, if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { - errorText = ("ERROR = " + errorText = ("ERROR failed to glIsEnabled() value. Reason: " + AString((char*)errorChars)); } } @@ -1264,7 +1266,7 @@ AString BrainOpenGL::getOpenGLBooleanAsText(const AString& enumName, /* * Reset error status */ - glGetError(); + GraphicsUtilitiesOpenGL::resetOpenGLError(); GLboolean boolValue = GL_FALSE; glGetBooleanv(enumValue, &boolValue); @@ -1274,7 +1276,7 @@ AString BrainOpenGL::getOpenGLBooleanAsText(const AString& enumName, if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { - errorText = ("ERROR = " + errorText = ("ERROR failed to glGetBooleanv() value. Reason: " + AString((char*)errorChars)); } } @@ -1307,7 +1309,7 @@ AString BrainOpenGL::getOpenGLFloatAsText(const AString& enumName, /* * Reset error status */ - glGetError(); + GraphicsUtilitiesOpenGL::resetOpenGLError(); AString valuesString; @@ -1321,7 +1323,7 @@ AString BrainOpenGL::getOpenGLFloatAsText(const AString& enumName, if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { - valuesString = ("ERROR = " + valuesString = ("ERROR failed to glGetFloatv() value. Reason: " + AString((char*)errorChars)); } } @@ -1361,7 +1363,7 @@ AString BrainOpenGL::getOpenGLLightAsText(const AString& enumName, /* * Reset error status */ - glGetError(); + GraphicsUtilitiesOpenGL::resetOpenGLError(); AString valuesString; @@ -1377,7 +1379,7 @@ AString BrainOpenGL::getOpenGLLightAsText(const AString& enumName, if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { - valuesString = ("ERROR = " + valuesString = ("ERROR failed to get glGetLightfv() value. Reason " + AString((char*)errorChars)); } } @@ -1438,61 +1440,24 @@ BrainOpenGL::testForOpenGLError(const AString& message, const int32_t windowIndex, const int32_t tabIndex) { - GLenum errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { + std::unique_ptr openglError = GraphicsUtilitiesOpenGL::getOpenGLError(); + if (openglError) { AString msg; if ( ! message.isEmpty()) { msg.appendWithNewLine(message); } - msg += ("OpenGL Error: " + AString((char*)gluErrorString(errorCode)) + "\n"); - msg += ("OpenGL Version: " + AString((char*)glGetString(GL_VERSION)) + "\n"); - msg += ("OpenGL Vendor: " + AString((char*)glGetString(GL_VENDOR)) + "\n"); if (model != NULL) { - msg += ("While drawing brain model " + model->getNameForGUI(true) + "\n"); + msg.appendWithNewLine("While drawing brain model " + model->getNameForGUI(true)); } if (windowIndex >= 0) { - msg += ("In window number " + AString::number(windowIndex) + "\n"); + msg.appendWithNewLine("In window number " + AString::number(windowIndex)); } if (tabIndex >= 0) { - msg += ("In tab number " + AString::number(tabIndex) + "\n"); + msg.appendWithNewLine("In tab number " + AString::number(tabIndex)); } - GLint maxNameStackDepth, maxModelStackDepth, maxProjStackDepth; - glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, - &maxProjStackDepth); - glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, - &maxModelStackDepth); - glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, - &maxNameStackDepth); - - GLint nameStackDepth, modelStackDepth, projStackDepth; - glGetIntegerv(GL_PROJECTION_STACK_DEPTH, - &projStackDepth); - glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, - &modelStackDepth); - glGetIntegerv(GL_NAME_STACK_DEPTH, - &nameStackDepth); + msg.appendWithNewLine(openglError->getVerboseDescription()); - msg += ("Projection Matrix Stack Depth " - + AString::number(projStackDepth) - + " Max Depth " - + AString::number(maxProjStackDepth) - + "\n"); - msg += ("Model Matrix Stack Depth " - + AString::number(modelStackDepth) - + " Max Depth " - + AString::number(maxModelStackDepth) - + "\n"); - msg += ("Name Matrix Stack Depth " - + AString::number(nameStackDepth) - + " Max Depth " - + AString::number(maxNameStackDepth) - + "\n"); - SystemBacktrace myBacktrace; - SystemUtilities::getBackTrace(myBacktrace); - msg += ("Backtrace:\n" - + myBacktrace.toSymbolString() - + "\n"); CaretLogSevere(msg); } } diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index f8218bf49..14d81a601 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -80,7 +80,9 @@ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" +#include "GraphicsOpenGLError.h" #include "GraphicsShape.h" +#include "GraphicsUtilitiesOpenGL.h" #include "MathFunctions.h" #include "Matrix4x4.h" @@ -801,11 +803,8 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann return; } - GLenum errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { - CaretLogWarning("OpenGL Error at begininng of FtglFontTextRenderer::getBoundsForTextAtViewportCoords(): " - + AString((char*)gluErrorString(errorCode))); - } + BrainOpenGL::testForOpenGLError("At begininng of FtglFontTextRenderer::getBoundsForTextAtViewportCoords() while " + "drawing text " + annotationText.getText()); if (annotationText.getLineWidthPercentage() <= 0.0f) { annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); @@ -828,15 +827,20 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann topLeftOut, rotationPointXYZ); - errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { + std::unique_ptr openglError = GraphicsUtilitiesOpenGL::getOpenGLError(); + if (openglError) { AString sizeMessage; + sizeMessage.appendWithNewLine("At end of FtglFontTextRenderer::getBoundsForTextAtViewportCoords()."); + sizeMessage.appendWithNewLine(" Error may be caused by font size that is too small."); + sizeMessage.appendWithNewLine(" Error may also occur with particular characters in a font."); + sizeMessage.appendWithNewLine(" Text that caused error: \"" + annotationText.getText() + "\""); + switch (annotationText.getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportHeight; - sizeMessage = ("Percent of viewport height=" + sizeMessage.appendWithNewLine(" Percent of viewport height=" + AString::number(percentSize, 'f', 2) + "%, viewport height=" + AString::number(viewportHeight) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); @@ -846,24 +850,21 @@ FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& ann { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportWidth; - sizeMessage = ("Percent of viewport width=" + sizeMessage.appendWithNewLine(" Percent of viewport width=" + AString::number(percentSize, 'f', 2) + "%, viewport width=" + AString::number(viewportWidth) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); } break; case AnnotationTextFontSizeTypeEnum::POINTS: - sizeMessage = ("Font Size=" + sizeMessage.appendWithNewLine(" Font Size=" + AnnotationTextFontNameEnum::toGuiName(annotationText.getFont())); break; } - CaretLogWarning("OpenGL error at end of FtglFontTextRenderer::getBoundsForTextAtViewportCoords(), " - "error may be caused by font size that is too small. Error may also occur with " - "particular characters in a font.\n" - " Rendering text: " + annotationText.getText() + "\n" - " " + sizeMessage + "\n" - " OpenGL Error=" + AString((char*)gluErrorString(errorCode))); + sizeMessage.appendWithNewLine(openglError->getVerboseDescription()); + + CaretLogWarning(sizeMessage); } } diff --git a/src/FtglFont/CMakeLists.txt b/src/FtglFont/CMakeLists.txt index 2ab7ff102..27afc4937 100644 --- a/src/FtglFont/CMakeLists.txt +++ b/src/FtglFont/CMakeLists.txt @@ -6,6 +6,9 @@ PROJECT (Ftgl) # # Add QT for includes # +if(Qt5_FOUND) + include_directories(${Qt5Core_INCLUDE_DIRS}) +endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) @@ -106,6 +109,7 @@ FTVectoriser.cpp # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common +${CMAKE_SOURCE_DIR}/Graphics ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2} ${CMAKE_SOURCE_DIR}/FtglFont diff --git a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp index 67b3cecca..9b6bfa8b9 100644 --- a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp +++ b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp @@ -34,6 +34,9 @@ #include "FTInternals.h" #include "FTTextureGlyphImpl.h" +#include "CaretLogger.h" +#include "GraphicsOpenGLError.h" +#include "GraphicsUtilitiesOpenGL.h" // // FTGLTextureGlyph @@ -94,15 +97,23 @@ FTTextureGlyphImpl::FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, glTextureID); + + /* + * Check for an OpenGL error. + * We will ignore errors caused by glTexSubImage2D() as it will cause + * OpenGL "Invalid Value" errors when some text characters get too small. + */ + std::unique_ptr openglError = caret::GraphicsUtilitiesOpenGL::getOpenGLError("FTGL before call to glTexSubImage2D()"); + if (openglError) { + CaretLogWarning(openglError->getVerboseDescription()); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); - /* - * When the font is too small, the above call to glTexSubImage2D() may - * cause an OpenGL "invalid value" error. These error messages may - * be frequent so just ignore them. Calling "glGetError()" will - * clear any error has been triggered. + /** + * Reset and ignore any OpenGL errors generated by glTexSubImage2D. */ - glGetError(); + caret::GraphicsUtilitiesOpenGL::resetOpenGLError(); glPopClientAttrib(); } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index b3b58782a..53cac7b7a 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -16,6 +16,7 @@ EventOpenGLObjectToWindowTransform.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h +GraphicsOpenGLError.h GraphicsOpenGLPolylineTriangles.h GraphicsOpenGLTextureName.h GraphicsPrimitive.h @@ -36,6 +37,7 @@ EventOpenGLObjectToWindowTransform.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx +GraphicsOpenGLError.cxx GraphicsOpenGLPolylineTriangles.cxx GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx diff --git a/src/Graphics/CaretOpenGLInclude.h b/src/Graphics/CaretOpenGLInclude.h index 4a35db9f2..16536c203 100644 --- a/src/Graphics/CaretOpenGLInclude.h +++ b/src/Graphics/CaretOpenGLInclude.h @@ -24,7 +24,7 @@ /** * \file CaretOpenGLInclude.h * \brief Contains OpenGL include declarations that work for all operating systems. - * \ingroup Brain + * \ingroup Common */ /* diff --git a/src/Graphics/GraphicsOpenGLError.cxx b/src/Graphics/GraphicsOpenGLError.cxx new file mode 100644 index 000000000..ed84b72c8 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLError.cxx @@ -0,0 +1,163 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ +#include "GraphicsOpenGLError.h" +#undef __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::GraphicsOpenGLError + * \brief Contains information about OpenGL Errors. + * \ingroup Graphics + */ + +/** + * Constructor. + */ +GraphicsOpenGLError::GraphicsOpenGLError(const AString& userMessage) +: CaretObject(), +m_userMessage(userMessage) +{ + glGetIntegerv(GL_PROJECTION_STACK_DEPTH, + &m_projectionStackDepth); + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, + &m_modelviewStackDepth); + glGetIntegerv(GL_NAME_STACK_DEPTH, + &m_nameStackDepth); + + SystemUtilities::getBackTrace(m_backtrace); +} + +/** + * Destructor. + */ +GraphicsOpenGLError::~GraphicsOpenGLError() +{ +} + +/** + * Add an error code. + * + * @param errorCode + */ +void +GraphicsOpenGLError::addError(const GLenum errorCode) +{ + m_errorCodes.push_back(errorCode); +} + +/** + * @return Number of errors. OpenGL may have more than one error + * available. Set the man page for glGetError(). + */ +int32_t +GraphicsOpenGLError::getNumberOfErrors() const +{ + return m_errorCodes.size(); +} + +/** + * @return Error code for the given error index. + * + * @param errorIndex + * Error index. + */ +GLenum +GraphicsOpenGLError::getErrorCode(const int32_t errorIndex) const +{ + CaretAssertVectorIndex(m_errorCodes, errorIndex); + return m_errorCodes[errorIndex]; +} + +/** + * @return Description for the given error index. + * + * @param errorIndex + * Error index. + */ +AString +GraphicsOpenGLError::getErrorDescription(const int32_t errorIndex) const +{ + CaretAssertVectorIndex(m_errorCodes, errorIndex); + AString description((char*)gluErrorString(m_errorCodes[errorIndex])); + + return description; +} + +/** + * @return String with verbose description of error information. + * An empty string is returned if there are no errors. + */ +AString +GraphicsOpenGLError::getVerboseDescription() const +{ + if (m_errorCodes.empty()) { + return ""; + } + + AString msg; + + if ( ! m_userMessage.isEmpty()) { + msg.appendWithNewLine(m_userMessage); + } + + for (auto errorCode : m_errorCodes) { + msg.appendWithNewLine("OpenGL Error: " + + AString((char*)gluErrorString(errorCode)) + + " (" + + AString::number(static_cast(errorCode)) + + ")"); + } + + msg.appendWithNewLine("OpenGL Version: " + AString((char*)glGetString(GL_VERSION))); + msg.appendWithNewLine("OpenGL Vendor: " + AString((char*)glGetString(GL_VENDOR))); + + GLint maxNameStackDepth, maxModelStackDepth, maxProjStackDepth; + glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, + &maxProjStackDepth); + glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, + &maxModelStackDepth); + glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, + &maxNameStackDepth); + + msg.appendWithNewLine("Projection Matrix Stack Depth " + + AString::number(m_projectionStackDepth) + + " Max Depth " + + AString::number(maxProjStackDepth)); + msg.appendWithNewLine("Model Matrix Stack Depth " + + AString::number(m_modelviewStackDepth) + + " Max Depth " + + AString::number(maxModelStackDepth)); + msg.appendWithNewLine("Name Matrix Stack Depth " + + AString::number(m_nameStackDepth) + + " Max Depth " + + AString::number(maxNameStackDepth)); + msg.appendWithNewLine("Backtrace: " + + m_backtrace.toSymbolString()); + + return msg; +} + diff --git a/src/Graphics/GraphicsOpenGLError.h b/src/Graphics/GraphicsOpenGLError.h new file mode 100644 index 000000000..5c7e37122 --- /dev/null +++ b/src/Graphics/GraphicsOpenGLError.h @@ -0,0 +1,92 @@ +#ifndef __GRAPHICS_OPEN_G_L_ERROR_H__ +#define __GRAPHICS_OPEN_G_L_ERROR_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" +#include "CaretOpenGLInclude.h" + + +namespace caret { + + class GraphicsOpenGLError : public CaretObject { + + public: + GraphicsOpenGLError(const AString& userMessage); + + virtual ~GraphicsOpenGLError(); + + int32_t getNumberOfErrors() const; + + GLenum getErrorCode(const int32_t errorIndex) const; + + AString getErrorDescription(const int32_t errorIndex) const; + + // ADD_NEW_METHODS_HERE + + AString getVerboseDescription() const; + + private: +// class ErrorInfo { +// public: +// ErrorInfo(const GLenum errorCode, +// const AString errorDescription) +// : m_errorCode(errorCode), +// m_errorDescription(errorDescription) { } +// +// const GLenum m_errorCode; +// +// const AString m_errorDescription; +// }; + + GraphicsOpenGLError(const GraphicsOpenGLError& obj); + + GraphicsOpenGLError& operator=(const GraphicsOpenGLError& obj); + + const AString m_userMessage; + + void addError(const GLenum errorCode); + + std::vector m_errorCodes; + + SystemBacktrace m_backtrace; + + int32_t m_projectionStackDepth = 0; + + int32_t m_modelviewStackDepth = 0; + + int32_t m_nameStackDepth = 0; + + // ADD_NEW_MEMBERS_HERE + + friend class GraphicsUtilitiesOpenGL; + }; + +#ifdef __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ + // +#endif // __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ + +} // namespace +#endif //__GRAPHICS_OPEN_G_L_ERROR_H__ diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index 10cd5cc32..f93f9b3d9 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -27,6 +27,8 @@ #include #include "CaretAssert.h" +#include "CaretOpenGLInclude.h" +#include "GraphicsOpenGLError.h" #include "EventManager.h" #include "EventOpenGLObjectToWindowTransform.h" #include "MathFunctions.h" @@ -140,4 +142,41 @@ GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(const float pixels) return mm; } +/** + * Reset and ignore any OpenGL errors. + */ +void +GraphicsUtilitiesOpenGL::resetOpenGLError() +{ + GLenum errorCode = glGetError(); + while (errorCode != GL_NO_ERROR) { + errorCode = glGetError(); + } +} + +/** + * @return Pointer to OpenGL Error Information. + * If the pointer is not valid, there is no error. + * + * @param message + * Optional message added to the OpenGL error + */ +std::unique_ptr +GraphicsUtilitiesOpenGL::getOpenGLError(const AString& message) +{ + std::unique_ptr errorInfo; + + GLenum errorCode = glGetError(); + while (errorCode != GL_NO_ERROR) { + if ( ! errorInfo) { + errorInfo.reset(new GraphicsOpenGLError(message)); + } + errorInfo->addError(errorCode); + + errorCode = glGetError(); + } + + return errorInfo; +} + diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h index 37d16654e..d1d7269e9 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.h +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -29,6 +29,8 @@ namespace caret { + class GraphicsOpenGLError; + class GraphicsUtilitiesOpenGL : public CaretObject { public: @@ -37,6 +39,10 @@ namespace caret { static float convertPixelsToMillimeters(const float pixels); + static void resetOpenGLError(); + + static std::unique_ptr getOpenGLError(const AString& message = ""); + private: GraphicsUtilitiesOpenGL(); -- GitLab From 9a8b5717eea30d714d9ad83315f286802f4859ba Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 16 Jan 2018 15:32:00 -0600 Subject: [PATCH 592/755] Added SET(CMAKE_POSITION_INDEPENDENT_CODE ON) to src/CMakeLists.txt. After the previous commit with changes for processing of OpenGL errors, FTGL code failed to compile on both Ubuntu and RedHat Linux with a 'position independent code' issue in Qt. Adding the property fixed compilation on both Linux operating systems. --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82f67adf2..edf0aba96 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ IF(APPLE) ELSEIF(UNIX) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ADD_DEFINITIONS(-DCARET_OS_LINUX) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ELSEIF(WIN32) ADD_DEFINITIONS(-DCARET_OS_WINDOWS) -- GitLab From 4fc75179aabdc48768f67fb648529bc24388d9b8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 17 Jan 2018 12:38:35 -0600 Subject: [PATCH 593/755] When the font height in pixels of the selected text annotations becomes "too small" (8 pixels), the numerical value in the font size spin box will become red. --- src/Annotations/AnnotationText.cxx | 18 ++++++++ src/Annotations/AnnotationText.h | 14 ++++++ src/Brain/FtglFontTextRenderer.cxx | 21 +++++++++ src/GuiQt/AnnotationFontWidget.cxx | 69 ++++++++++++++++++++++++++++-- src/GuiQt/AnnotationFontWidget.h | 7 ++- 5 files changed, 125 insertions(+), 4 deletions(-) diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index 59beaa572..4b384acce 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -878,6 +878,24 @@ AnnotationText::setFontPercentViewportSizeProtected(const float fontPercentViewp } } +/** + * @return Is the font too small when it is last drawn + * that may cause an OpenGL error and, as a result, + * the text is not seen by the user. + */ +bool +AnnotationText::isFontTooSmallWhenLastDrawn() const +{ + return m_fontTooSmallWhenLastDrawnFlag; +} + +void +AnnotationText::setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const +{ + m_fontTooSmallWhenLastDrawnFlag = tooSmallFontFlag; +} + + /** * Apply a spatial modification to an annotation. * diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index f284eeb2f..78eeea655 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -36,6 +36,14 @@ namespace caret { class AnnotationText : public AnnotationTwoDimensionalShape, public AnnotationFontAttributesInterface { public: + /** + * @return The "too small" text size. + * + * When the text is smaller than this font height, either all of the + * text string may not be drawn or just particular characters + */ + static uint32_t getTooSmallTextHeight() { return 8; } + virtual ~AnnotationText(); AnnotationText(const AnnotationText& obj); @@ -71,6 +79,10 @@ namespace caret { int32_t getFontSizeForDrawing(const int32_t drawingViewportWidth, const int32_t drawingViewportHeight) const; + + bool isFontTooSmallWhenLastDrawn() const; + + void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const; AnnotationTextFontSizeTypeEnum::Enum getFontSizeType() const; @@ -211,6 +223,8 @@ namespace caret { bool m_underlineEnabled; + mutable bool m_fontTooSmallWhenLastDrawnFlag = false; + // Defaults static AnnotationTextAlignHorizontalEnum::Enum s_userDefaultAlignmentHorizontal; diff --git a/src/Brain/FtglFontTextRenderer.cxx b/src/Brain/FtglFontTextRenderer.cxx index 14d81a601..8428ea1de 100644 --- a/src/Brain/FtglFontTextRenderer.cxx +++ b/src/Brain/FtglFontTextRenderer.cxx @@ -217,6 +217,13 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, if (fontIter != m_fontNameToFontMap.end()) { FontData* fontData = fontIter->second; CaretAssert(fontData); + + /* + * Set font "too small" status + */ + const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); + annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); + return fontData->m_font; } @@ -234,6 +241,13 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, fontData)); CaretLogFine("Created font with encoded name " + fontName); + + /* + * Set font "too small" status + */ + const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); + annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); + return fontData->m_font; } else { @@ -266,6 +280,7 @@ FtglFontTextRenderer::getFont(const AnnotationText& annotationText, /* * Failed so use the default font. */ + annotationText.setFontTooSmallWhenLastDrawn(false); return m_defaultFont; #else // HAVE_FREETYPE @@ -316,6 +331,9 @@ FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText if (! font) { return; } + +// const bool tooSmallFlag = (font->FaceSize() <= s_tooSmallFontSize); +// annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); if (annotationText.getText().isEmpty()) { return; @@ -734,6 +752,9 @@ FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depth return; } +// const bool tooSmallFlag = (font->FaceSize() < s_tooSmallFontSize); +// annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag); + m_depthTestingStatus = depthTesting; if (annotationText.getLineWidthPercentage() <= 0.0f) { diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 08380cabc..31598db8d 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -93,12 +93,37 @@ m_browserWindowIndex(browserWindowIndex) /* * Combo box for font size */ + const AString fontSizeToolTop("" + "Adjusts font height (size), as a percentage of the viewport height, that is " + "converted to a pixel height when the text is drawn. " + "

    " + "The numeric value in this control will be RED " + "when the pixel height is estimated to be too small and some or all " + "characters may not be drawn. " + "Reducing the height of the text and/or the height of the window may cause " + "too small text. " + ""); m_fontSizeSpinBox = new WuQDoubleSpinBox(this); m_fontSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_fontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(fontSizeChanged())); WuQtUtilities::setToolTipAndStatusTip(m_fontSizeSpinBox->getWidget(), - "Change font size (height) as percentage, zero to one-hundred, of viewport height"); + fontSizeToolTop); + + /* + * Default palette for size spin box + */ + m_fontSizeSpinBoxDefaultPalette = m_fontSizeSpinBox->getWidget()->palette(); + + /* + * Palette for spin box that colors text in red when the font height is "too small" + */ + m_fontSizeSpinBoxRedTextPalette = m_fontSizeSpinBoxDefaultPalette; + QBrush brush = m_fontSizeSpinBoxRedTextPalette.brush(QPalette::Active, QPalette::Text); + brush.setColor(Qt::red); + m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::Text, brush); + m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::WindowText, brush); + m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::HighlightedText, brush); /* * Text color menu @@ -329,6 +354,7 @@ AnnotationFontWidget::updateFontSizeControls() const float surfaceMontageRowCount = getSurfaceMontageRowCount(); + bool tooSmallFlag = false; const int32_t numAnn = static_cast(m_annotationsFontSize.size()); for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationsFontSize, i); @@ -366,10 +392,18 @@ AnnotationFontWidget::updateFontSizeControls() sizeValue); } } + + const AnnotationText* textAnnotation = dynamic_cast(annText); + if (textAnnotation != NULL) { + if (textAnnotation->isFontTooSmallWhenLastDrawn()) { + tooSmallFlag = true; + } + } } updateFontSizeSpinBox(fontSizeValue, - haveMultipleFontSizeValues); + haveMultipleFontSizeValues, + tooSmallFlag); AnnotationText::setUserDefaultFontPercentViewportSize(fontSizeValue); } @@ -442,16 +476,39 @@ AnnotationFontWidget::updateFontStyleControls() * @param haveMultipleValuesFlag * If true, there are multiple font size values so indicate * this with a '+' sign as a suffix + * @param tooSmallFontFlag + * If true, the font may be too small as detected by the + * graphics drawing code. */ void AnnotationFontWidget::updateFontSizeSpinBox(const float value, - const bool haveMultipleValuesFlag) + const bool haveMultipleValuesFlag, + const bool tooSmallFontFlag) { + QSignalBlocker blocker(m_fontSizeSpinBox->getWidget()); m_fontSizeSpinBox->setValue(value); + + if (tooSmallFontFlag) { + m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxRedTextPalette); + } + else { + m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxDefaultPalette); + } + QString fontSizeSuffix("%"); if (haveMultipleValuesFlag) { fontSizeSuffix = "%+"; } + m_fontSizeSpinBox->setValue(value); + m_fontSizeSpinBox->setSuffix(fontSizeSuffix); + +// if (tooSmallFontFlag) { +// m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxRedTextPalette); +// } +// else { +// m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxDefaultPalette); +// } +// m_fontSizeSpinBox->setValue(value); } /** @@ -729,6 +786,12 @@ AnnotationFontWidget::fontSizeChanged() } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + + /* + * "Font too small" status is set while drawing so need + * to update the size spin box AFTER the graphics update + */ + updateFontSizeControls(); } /** diff --git a/src/GuiQt/AnnotationFontWidget.h b/src/GuiQt/AnnotationFontWidget.h index a7efd389b..6f1de80c1 100644 --- a/src/GuiQt/AnnotationFontWidget.h +++ b/src/GuiQt/AnnotationFontWidget.h @@ -74,7 +74,8 @@ namespace caret { AnnotationFontWidget& operator=(const AnnotationFontWidget&); void updateFontSizeSpinBox(const float value, - const bool haveMultipleValuesFlag); + const bool haveMultipleValuesFlag, + const bool tooSmallFontFlag); void updateTextColorButton(); @@ -96,6 +97,10 @@ namespace caret { WuQDoubleSpinBox* m_fontSizeSpinBox; + QPalette m_fontSizeSpinBoxDefaultPalette; + + QPalette m_fontSizeSpinBoxRedTextPalette; + QToolButton* m_textColorToolButton; QAction* m_textColorAction; -- GitLab From c6ef139f3b06dce7868a2782407df7ef598fe0cd Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 17 Jan 2018 14:34:50 -0600 Subject: [PATCH 594/755] Resolve WB-715 Too small font size warning: Text Annotations are drawn using a "font height" that is a "percentage of the viewport's height". When the text annotation is drawn, the "percentage of viewport height" is converted to a "pixel height" and a font with the desired pixel height is requested and the text is drawn. However, when the font pixel height gets too small, FTGL may generated an OpenGL error and some or all characters fail to draw. These font drawing errors have been found to occur when the pixel height is 6 to 7. So, a "font too small height" has been set to 8. If when drawing text the height of the font is 8 or less, set a "text too small" property on the text annotation. In Annotation Toolbar's font height control, draw the numeric height value in red if one or more of the selected text annotations has its "text too small" property set. --- src/GuiQt/AnnotationFontWidget.cxx | 25 +++++++++++++++++++++++++ src/GuiQt/AnnotationFontWidget.h | 5 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 31598db8d..0340a2a82 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -42,6 +42,7 @@ #include "CaretAssert.h" #include "CaretColorEnumMenu.h" #include "EnumComboBoxTemplate.h" +#include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" @@ -256,6 +257,8 @@ m_browserWindowIndex(browserWindowIndex) setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** @@ -263,6 +266,28 @@ m_browserWindowIndex(browserWindowIndex) */ AnnotationFontWidget::~AnnotationFontWidget() { + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event. + * + * @param event + * The event that the receive can respond to. + */ +void +AnnotationFontWidget::receiveEvent(Event* event) +{ + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { + EventBrowserWindowGraphicsRedrawn* redrawEvent = dynamic_cast(event); + CaretAssert(redrawEvent); + + if (m_browserWindowIndex == redrawEvent->getBrowserWindowIndex()) { + if (isVisible()) { + updateFontSizeControls(); + } + } + } } /** diff --git a/src/GuiQt/AnnotationFontWidget.h b/src/GuiQt/AnnotationFontWidget.h index 6f1de80c1..ad9a3e8e0 100644 --- a/src/GuiQt/AnnotationFontWidget.h +++ b/src/GuiQt/AnnotationFontWidget.h @@ -28,6 +28,7 @@ #include "AnnotationWidgetParentEnum.h" #include "CaretColorEnum.h" +#include "EventListenerInterface.h" class QToolButton; @@ -40,7 +41,7 @@ namespace caret { class EnumComboBoxTemplate; class WuQDoubleSpinBox; - class AnnotationFontWidget : public QWidget { + class AnnotationFontWidget : public QWidget, public EventListenerInterface { Q_OBJECT @@ -53,6 +54,8 @@ namespace caret { void updateContent(std::vector& annotations); + virtual void receiveEvent(Event* event) override; + // ADD_NEW_METHODS_HERE private slots: -- GitLab From d0d13fac84a94f2d9dd27b5cdcbd99cfe571bd48 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 17 Jan 2018 16:29:45 -0600 Subject: [PATCH 595/755] Correct some more compilation warnings. Added some additional Caret Assert Macros, CaretAssertDebugCompileOnly() and CaretAssertParameterDebugCompileOnly() that can be used to 'disable' variables and parameters that are only use in other CaretAssert() statements. --- src/Algorithms/AlgorithmNodesInsideBorder.cxx | 6 +-- src/Common/CaretAssert.h | 41 +++++++++++++++++++ src/Common/CaretObject.cxx | 11 +++-- src/Common/Logger.cxx | 2 +- src/Files/VolumeFileVoxelColorizer.cxx | 8 ++-- src/Files/VolumeFileVoxelColorizer.h | 2 +- src/GuiQt/CMakeLists.txt | 1 - src/GuiQt/WuQEventBlockingFilter.cxx | 6 ++- src/GuiQt/WuQtUtilities.cxx | 12 +++--- 9 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/Algorithms/AlgorithmNodesInsideBorder.cxx b/src/Algorithms/AlgorithmNodesInsideBorder.cxx index 3c6ba35c6..397fb39e4 100644 --- a/src/Algorithms/AlgorithmNodesInsideBorder.cxx +++ b/src/Algorithms/AlgorithmNodesInsideBorder.cxx @@ -763,9 +763,9 @@ AlgorithmNodesInsideBorder::findNodeFurthestFromConnectedPathCenterOfGravity(con if (sumCount >= 1.0) { const float cog[3] = { - sumX / sumCount, - sumY / sumCount, - sumZ / sumCount + (float)(sumX / sumCount), + (float)(sumY / sumCount), + (float)(sumZ / sumCount) }; /* diff --git a/src/Common/CaretAssert.h b/src/Common/CaretAssert.h index d8a14a089..3d5e97a9b 100644 --- a/src/Common/CaretAssert.h +++ b/src/Common/CaretAssert.h @@ -34,8 +34,49 @@ #define CaretAssertArrayIndex(a, n, i) ((void) 0) #define CaretAssertVectorIndex(v, i) ((void) 0) + #define CaretAssertDebugCompileOnly(e) ((void) 0) + #define CaretAssertParameterDebugCompileOnly(e) #else // NDEBUG + + /** + * \def CaretAssertDebugCompileOnly + * + * The code within the expression is compiled ONLY + * if the compiler's "debug" option is enabled. It + * can be used to eliminate "unused" compilation warnings + * when debug is off for variables that are only + * used in one of the CaretAssert() macros. + * + * Example: + * std::vector v; + * CaretAssertDebugCompileOnly(const int index = 5 * x + y); + * CaretAssertVectorIndex(v, index); + * + * @param e + * Expression that is only present if compiled with debug on. + */ + #define CaretAssertDebugCompileOnly(e) e + + /** + * \def CaretAssertParameterDebugCompileOnly + * + * The code within the expression is compiled ONLY + * if the compiler's "debug" option is enabled. It + * is used when a function parameter is only used + * within a CaretAssert() macro. + * + * Example: + * void function(const float a, + * const int CaretAssertParameterDebugCompileOnly(index)) { + * CaretAssertVectorIndex(v, index); + * } + * + * @param e + * Expression that is only present if compiled with debug on. + */ + #define CaretAssertParameterDebugCompileOnly(e) e + /** * \def CaretAssert * diff --git a/src/Common/CaretObject.cxx b/src/Common/CaretObject.cxx index 2082debed..292c9dfa5 100644 --- a/src/Common/CaretObject.cxx +++ b/src/Common/CaretObject.cxx @@ -120,13 +120,18 @@ CaretObject::className() const return name; } +#ifdef NDEBUG + /** + * Do not print objects not deleted if NOT debug + */ + void CaretObject::printListOfObjectsNotDeleted(const bool) { } +#else /** * Print a list of CaretObjects that were not deleted. */ -void +void CaretObject::printListOfObjectsNotDeleted(const bool showCallStack) { -#ifndef NDEBUG int count = 0; if (CaretObject::allocatedObjects.empty() == false) { @@ -152,8 +157,8 @@ CaretObject::printListOfObjectsNotDeleted(const bool showCallStack) if (count > 0) { std::cout << std::dec << count << " objects were not deleted." << std::endl; } -#endif } +#endif /** * Constructor. diff --git a/src/Common/Logger.cxx b/src/Common/Logger.cxx index a142d48a0..4aba4349d 100644 --- a/src/Common/Logger.cxx +++ b/src/Common/Logger.cxx @@ -74,7 +74,7 @@ Logger::getLogger(const AString& name) } Logger* logger = new Logger(name); - bool exists = LogManager::getLogManager()->addLogger(logger); + CaretAssertDebugCompileOnly(bool exists = LogManager::getLogManager()->addLogger(logger)); CaretAssertMessage(exists, "Trying to add logger and logger with name exists."); return logger; } diff --git a/src/Files/VolumeFileVoxelColorizer.cxx b/src/Files/VolumeFileVoxelColorizer.cxx index ccf5d95aa..d13af6d6f 100644 --- a/src/Files/VolumeFileVoxelColorizer.cxx +++ b/src/Files/VolumeFileVoxelColorizer.cxx @@ -486,7 +486,7 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], - const int64_t voxelCountIJK[3], + const int64_t* CaretAssertParameterDebugCompileOnly(voxelCountIJK), const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const @@ -544,8 +544,8 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, CaretAssert(false); } - const int64_t voxelCount = (voxelCountIJK[0] * voxelCountIJK[1] * voxelCountIJK[2]); - const int64_t rgbaCount = voxelCount * 4; + CaretAssertDebugCompileOnly(const int64_t voxelCount = (voxelCountIJK[0] * voxelCountIJK[1] * voxelCountIJK[2])); + CaretAssertDebugCompileOnly(const int64_t rgbaCount = voxelCount * 4); /* * Pointer to maps RGBA values @@ -561,7 +561,7 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, int64_t validVoxelCount = 0; - int64_t innerCount = std::abs(lastCornerVoxelIndex[innerLoop] - firstCornerVoxelIndex[innerLoop]) + 1;//to check validity of index + CaretAssertDebugCompileOnly(int64_t innerCount = std::abs(lastCornerVoxelIndex[innerLoop] - firstCornerVoxelIndex[innerLoop]) + 1);//to check validity of index int64_t rgbaOutIndex = 0; for (iterijk[outerLoop] = firstCornerVoxelIndex[outerLoop]; diff --git a/src/Files/VolumeFileVoxelColorizer.h b/src/Files/VolumeFileVoxelColorizer.h index 544b01e0b..265c39211 100644 --- a/src/Files/VolumeFileVoxelColorizer.h +++ b/src/Files/VolumeFileVoxelColorizer.h @@ -65,7 +65,7 @@ namespace caret { const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], - const int64_t voxelCountIJK[3], + const int64_t* voxelCountIJK, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 52bfea334..d9d9fbc55 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -208,7 +208,6 @@ ELSE() WuQTrueFalseComboBox.h #WuQWebView.h WuQWidget.h - WuQWidgetDisabler.h WuQWidgetObjectGroup.h ZipSceneFileDialog.h ) diff --git a/src/GuiQt/WuQEventBlockingFilter.cxx b/src/GuiQt/WuQEventBlockingFilter.cxx index 6745bb8cd..2a1dcfe1d 100644 --- a/src/GuiQt/WuQEventBlockingFilter.cxx +++ b/src/GuiQt/WuQEventBlockingFilter.cxx @@ -69,10 +69,10 @@ WuQEventBlockingFilter::WuQEventBlockingFilter(QObject* parent) * @param comboBox * Combo box that has its wheel event blocked. */ +#ifdef CARET_OS_MACOSX void WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(QComboBox* comboBox) { -#ifdef CARET_OS_MACOSX /* * Attach an event filter that blocks wheel events in the combo box if Mac */ @@ -80,8 +80,10 @@ WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(QComboBox* comboBox) comboBoxWheelEventBlockingFilter->setEventBlocked(QEvent::Wheel, true); comboBox->installEventFilter(comboBoxWheelEventBlockingFilter); -#endif // CARET_OS_MACOSX } +#else + void WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(QComboBox*) { } +#endif // CARET_OS_MACOSX /** * Destructor. diff --git a/src/GuiQt/WuQtUtilities.cxx b/src/GuiQt/WuQtUtilities.cxx index 1332b5dd3..481bd46ca 100644 --- a/src/GuiQt/WuQtUtilities.cxx +++ b/src/GuiQt/WuQtUtilities.cxx @@ -1472,11 +1472,11 @@ WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, * @param toolButton * toolButton ToolButton that needs style updated. */ +#ifdef CARET_OS_MACOSX +#if QT_VERSION >= 0x050000 void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) { -#ifdef CARET_OS_MACOSX -#if QT_VERSION >= 0x050000 CaretAssert(toolButton); bool hasMenuFlag = false; @@ -1545,11 +1545,13 @@ WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) } toolButton->setStyleSheet(toolButtonStyleSheet); - - //std::cout << qPrintable(toolButton->text() + " " + toolButtonStyleSheet + "\n\n"); +} +#else + void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton*) { } #endif +#else + void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton*) { } #endif -} -- GitLab From 396dea09cc5f050bd27b90c6f9c986fa49002a76 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 18 Jan 2018 10:56:18 -0600 Subject: [PATCH 596/755] Resolved some additional compilation warnings and fixed a compile error on windows for including OpenGL in FTGL. --- src/Common/CaretAssert.h | 16 ++++++++-------- src/Common/Logger.cxx | 2 +- src/Files/CaretDataFileHelper.cxx | 4 ++-- src/Files/VolumeFileVoxelColorizer.cxx | 8 ++++---- src/FtglFont/FTGlyph/FTBufferGlyph.cpp | 4 ++-- src/FtglFont/FTGlyph/FTTextureGlyph.cpp | 2 ++ src/GuiQt/FiberSamplesOpenGLWidget.cxx | 8 ++++---- src/GuiQt/SceneCreateReplaceDialog.cxx | 4 ++-- src/Qwt/qwt_plot_canvas.cpp | 3 ++- 9 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Common/CaretAssert.h b/src/Common/CaretAssert.h index 3d5e97a9b..b75b919b1 100644 --- a/src/Common/CaretAssert.h +++ b/src/Common/CaretAssert.h @@ -34,13 +34,13 @@ #define CaretAssertArrayIndex(a, n, i) ((void) 0) #define CaretAssertVectorIndex(v, i) ((void) 0) - #define CaretAssertDebugCompileOnly(e) ((void) 0) - #define CaretAssertParameterDebugCompileOnly(e) + #define CaretUsedInDebugCompileOnly(e) ((void) 0) + #define CaretParameterUsedInDebugCompileOnly(e) #else // NDEBUG /** - * \def CaretAssertDebugCompileOnly + * \def CaretUsedInDebugCompileOnly * * The code within the expression is compiled ONLY * if the compiler's "debug" option is enabled. It @@ -50,16 +50,16 @@ * * Example: * std::vector v; - * CaretAssertDebugCompileOnly(const int index = 5 * x + y); + * CaretUsedInDebugCompileOnly(const int index = 5 * x + y); * CaretAssertVectorIndex(v, index); * * @param e * Expression that is only present if compiled with debug on. */ - #define CaretAssertDebugCompileOnly(e) e + #define CaretUsedInDebugCompileOnly(e) e /** - * \def CaretAssertParameterDebugCompileOnly + * \def CaretParameterUsedInDebugCompileOnly * * The code within the expression is compiled ONLY * if the compiler's "debug" option is enabled. It @@ -68,14 +68,14 @@ * * Example: * void function(const float a, - * const int CaretAssertParameterDebugCompileOnly(index)) { + * const int CaretParameterUsedInDebugCompileOnly(index)) { * CaretAssertVectorIndex(v, index); * } * * @param e * Expression that is only present if compiled with debug on. */ - #define CaretAssertParameterDebugCompileOnly(e) e + #define CaretParameterUsedInDebugCompileOnly(e) e /** * \def CaretAssert diff --git a/src/Common/Logger.cxx b/src/Common/Logger.cxx index 4aba4349d..2836a17f6 100644 --- a/src/Common/Logger.cxx +++ b/src/Common/Logger.cxx @@ -74,7 +74,7 @@ Logger::getLogger(const AString& name) } Logger* logger = new Logger(name); - CaretAssertDebugCompileOnly(bool exists = LogManager::getLogManager()->addLogger(logger)); + CaretUsedInDebugCompileOnly(bool exists = LogManager::getLogManager()->addLogger(logger)); CaretAssertMessage(exists, "Trying to add logger and logger with name exists."); return logger; } diff --git a/src/Files/CaretDataFileHelper.cxx b/src/Files/CaretDataFileHelper.cxx index 607ea0ec6..734d86059 100644 --- a/src/Files/CaretDataFileHelper.cxx +++ b/src/Files/CaretDataFileHelper.cxx @@ -239,7 +239,7 @@ CaretDataFileHelper::readCaretDataFile(CaretDataFile* caretDataFile, try { caretDataFile->readFile(filename); } - catch (const std::bad_alloc& badAlloc) { + catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will @@ -465,7 +465,7 @@ CaretDataFileHelper::getDataFileTypeFromFileContent(const AString& filename) break; } } - catch (const DataFileException& dfe) { + catch (const DataFileException&) { CaretLogInfo(filename + " could not be read as a CIFTI file"); } diff --git a/src/Files/VolumeFileVoxelColorizer.cxx b/src/Files/VolumeFileVoxelColorizer.cxx index d13af6d6f..06adff2f9 100644 --- a/src/Files/VolumeFileVoxelColorizer.cxx +++ b/src/Files/VolumeFileVoxelColorizer.cxx @@ -486,7 +486,7 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], - const int64_t* CaretAssertParameterDebugCompileOnly(voxelCountIJK), + const int64_t* CaretParameterUsedInDebugCompileOnly(voxelCountIJK), const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const @@ -544,8 +544,8 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, CaretAssert(false); } - CaretAssertDebugCompileOnly(const int64_t voxelCount = (voxelCountIJK[0] * voxelCountIJK[1] * voxelCountIJK[2])); - CaretAssertDebugCompileOnly(const int64_t rgbaCount = voxelCount * 4); + CaretUsedInDebugCompileOnly(const int64_t voxelCount = (voxelCountIJK[0] * voxelCountIJK[1] * voxelCountIJK[2])); + CaretUsedInDebugCompileOnly(const int64_t rgbaCount = voxelCount * 4); /* * Pointer to maps RGBA values @@ -561,7 +561,7 @@ VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, int64_t validVoxelCount = 0; - CaretAssertDebugCompileOnly(int64_t innerCount = std::abs(lastCornerVoxelIndex[innerLoop] - firstCornerVoxelIndex[innerLoop]) + 1);//to check validity of index + CaretUsedInDebugCompileOnly(int64_t innerCount = std::abs(lastCornerVoxelIndex[innerLoop] - firstCornerVoxelIndex[innerLoop]) + 1);//to check validity of index int64_t rgbaOutIndex = 0; for (iterijk[outerLoop] = firstCornerVoxelIndex[outerLoop]; diff --git a/src/FtglFont/FTGlyph/FTBufferGlyph.cpp b/src/FtglFont/FTGlyph/FTBufferGlyph.cpp index 8fb81310c..5a9a6cbc0 100644 --- a/src/FtglFont/FTGlyph/FTBufferGlyph.cpp +++ b/src/FtglFont/FTGlyph/FTBufferGlyph.cpp @@ -98,12 +98,12 @@ const FTPoint& FTBufferGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMod int dy = buffer->Height() - (int)(pos.Yf() + 0.5f); unsigned char * dest = buffer->Pixels() + dx + dy * buffer->Width(); - for(int y = 0; y < bitmap.rows; y++) + for(int y = 0; y < ((int)bitmap.rows); y++) { // FIXME: change the loop bounds instead of doing this test if(y + dy < 0 || y + dy >= buffer->Height()) continue; - for(int x = 0; x < bitmap.width; x++) + for(int x = 0; x < ((int)bitmap.width); x++) { if(x + dx < 0 || x + dx >= buffer->Width()) continue; diff --git a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp index 9b6bfa8b9..3c1b332c6 100644 --- a/src/FtglFont/FTGlyph/FTTextureGlyph.cpp +++ b/src/FtglFont/FTGlyph/FTTextureGlyph.cpp @@ -25,6 +25,8 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "CaretOpenGLInclude.h" // Must be here to prevent GLEW error on Windows + #include "FtglConfig.h" #include diff --git a/src/GuiQt/FiberSamplesOpenGLWidget.cxx b/src/GuiQt/FiberSamplesOpenGLWidget.cxx index 834b02ed5..88738a4fd 100644 --- a/src/GuiQt/FiberSamplesOpenGLWidget.cxx +++ b/src/GuiQt/FiberSamplesOpenGLWidget.cxx @@ -307,10 +307,10 @@ FiberSamplesOpenGLWidget::paintGL() // 0.7); const float rgba[4] = { - 0.7, - 0.7, - 0.7, - 1.0 + 0.7f, + 0.7f, + 0.7f, + 1.0f }; m_sphereBig->draw(rgba); diff --git a/src/GuiQt/SceneCreateReplaceDialog.cxx b/src/GuiQt/SceneCreateReplaceDialog.cxx index 4fe6cb7c5..969dee617 100644 --- a/src/GuiQt/SceneCreateReplaceDialog.cxx +++ b/src/GuiQt/SceneCreateReplaceDialog.cxx @@ -512,8 +512,8 @@ SceneCreateReplaceDialog::createSceneImage(QImage& imageOut, imageOut = *compositeImageFile.getAsQImage(); validImageFlag = true; } - catch (const DataFileException& dfe) { - errorMessageOut.appendWithNewLine("Even though image failed, scene was created."); + catch (const DataFileException&) { + errorMessageOut.appendWithNewLine("Even though image generation failed, scene was created."); } } diff --git a/src/Qwt/qwt_plot_canvas.cpp b/src/Qwt/qwt_plot_canvas.cpp index 0271713a8..a1dc6e507 100644 --- a/src/Qwt/qwt_plot_canvas.cpp +++ b/src/Qwt/qwt_plot_canvas.cpp @@ -937,7 +937,8 @@ void QwtPlotCanvas::drawBorder( QPainter *painter ) else { #if QT_VERSION >= 0x040500 - QStyleOptionFrameV3 opt; + //QStyleOptionFrameV3 opt; + QStyleOptionFrame opt; // Note QStyleOptionFrameV3 is typedef to QStyleOptionFrame opt.init(this); int frameShape = frameStyle() & QFrame::Shape_Mask; -- GitLab From 357c66f0ff7d8685c72083f545b12902e3defea0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 18 Jan 2018 16:17:15 -0600 Subject: [PATCH 597/755] Resolve WB-696 Warning if NIFTI has both qform and sform invalid. A "file warning message" (with methods to 'add' and 'get' warnings and the 'get' method will clear the file's warnings) has been added to the DataFile class. At the end of VolumeFile::readFile, hasGoodSpatialInformation() is called and if it returns false, the 'add warning' method is called with a string indicating that both sform and qform are invalid. After any type of file reading (load file, read spec file, show scene, etc.), all data files are queried for file read warnings. If there are any file warnings, a dialog is displayed listing the file(s) and warnings(s). Note: If the user requests loading of a Scene and a data file in the Scene is already in memory, the data file is NOT reloaded to save time. In this case, no warning will be scene since the file remains in memory and is not read from disk. --- src/Common/DataFile.cxx | 29 +++++++ src/Common/DataFile.h | 7 ++ src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/Files/VolumeFile.cxx | 4 + src/GuiQt/BrainBrowserWindow.cxx | 46 ++++++++++++ src/GuiQt/BrainBrowserWindow.h | 2 + src/GuiQt/CMakeLists.txt | 2 + .../EventShowDataFileReadWarningsDialog.cxx | 75 +++++++++++++++++++ .../EventShowDataFileReadWarningsDialog.h | 61 +++++++++++++++ src/GuiQt/GuiManager.cxx | 20 ++++- src/GuiQt/SceneDialog.cxx | 5 ++ src/GuiQt/SpecFileManagementDialog.cxx | 3 + src/GuiQt/WuQTextEditorDialog.cxx | 2 + 15 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 src/GuiQt/EventShowDataFileReadWarningsDialog.cxx create mode 100644 src/GuiQt/EventShowDataFileReadWarningsDialog.h diff --git a/src/Common/DataFile.cxx b/src/Common/DataFile.cxx index 53288498d..bcec1826e 100644 --- a/src/Common/DataFile.cxx +++ b/src/Common/DataFile.cxx @@ -79,6 +79,7 @@ void DataFile::copyHelperDataFile(const DataFile& df) { m_filename = df.m_filename; + m_fileReadWarnings = df.m_fileReadWarnings; m_modifiedFlag = false; } @@ -89,6 +90,7 @@ void DataFile::initializeMembersDataFile() { m_filename = ""; + m_fileReadWarnings.clear(); m_modifiedFlag = false; } @@ -290,3 +292,30 @@ DataFile::checkFileWritability(const AString& filename) } } +/** + * Add a warning (non-fatal) message about some issue while reading file file. + * + * @param warning + * Warning message about some issue. + */ +void +DataFile::addFileReadWarning(const AString& warning) +{ + m_fileReadWarnings.appendWithNewLine(warning); +} + +/** + * @return Any warning message from reading the data file. + * + * NOTE: When this method is called, the warning message + * is cleared for this file. + */ +AString +DataFile::getFileReadWarnings() const +{ + const AString warningMessage = m_fileReadWarnings; + m_fileReadWarnings.clear(); + return warningMessage; +} + + diff --git a/src/Common/DataFile.h b/src/Common/DataFile.h index 13ec67b2a..6eca1d879 100644 --- a/src/Common/DataFile.h +++ b/src/Common/DataFile.h @@ -94,6 +94,10 @@ namespace caret { bool exists() const; + void addFileReadWarning(const AString& warning); + + AString getFileReadWarnings() const; + private: void copyHelperDataFile(const DataFile& df); @@ -102,6 +106,9 @@ namespace caret { /** name of data file */ AString m_filename; + /** warnings set when file was read */ + mutable AString m_fileReadWarnings; + /** modification status */ bool m_modifiedFlag; diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index b49044f06..2031cfd9e 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -446,6 +446,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW: case EventTypeEnum::EVENT_PALETTE_GET_BY_NAME: + case EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG: case EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES: case EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE: case EventTypeEnum::EVENT_SURFACES_GET: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index ae1e2bf4f..73fc7550a 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -326,6 +326,10 @@ EventTypeEnum::initialize() "EVENT_PALETTE_GET_BY_NAME", "Read the selected files in a spec file")); + enumData.push_back(EventTypeEnum(EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, + "EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG", + "Show a dialog with warnings encountered reading data files")); + enumData.push_back(EventTypeEnum(EVENT_SPEC_FILE_READ_DATA_FILES, "EVENT_SPEC_FILE_READ_DATA_FILES", "Read the selected data files in a spec file")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index ede8246bb..4c11a24c2 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -170,6 +170,8 @@ public: EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW, /** Get a palette by name from a palette file */ EVENT_PALETTE_GET_BY_NAME, + /** Show a dialog containing warnings encountered when reading data files */ + EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, /** Read the selected files in a spec file */ EVENT_SPEC_FILE_READ_DATA_FILES, /** Invalidate surface coloring */ diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index 44cd890b9..e8dded5d6 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -299,6 +299,10 @@ void VolumeFile::readFile(const AString& filename) getGroupAndNameHierarchyModel(); } + if ( ! hasGoodSpatialInformation()) { + addFileReadWarning("No spatial information in file (in NIFTI header, both qform and sform are invalid)."); + } + CaretLogFine("Total Time to read and process volume is " + AString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds."); diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index f0427203a..be8692125 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -102,6 +102,7 @@ #include "WuQDoubleSpinBox.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" +#include "WuQTextEditorDialog.h" #include "VtkFileExporter.h" using namespace caret; @@ -3119,6 +3120,8 @@ BrainBrowserWindow::loadSceneFromCommandLine(const AString& sceneFileName, + "\" found in scene file."); WuQMessageBox::errorOk(this, msg); } + + /* NOTE: File warning dialog is performed by scene dialog */ } @@ -3463,6 +3466,8 @@ BrainBrowserWindow::loadFiles(QWidget* parentForDialogs, EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); + showDataFileReadWarningsDialog(); + return successFlag; } @@ -4554,3 +4559,44 @@ BrainBrowserWindow::hasValidOpenGL() return m_openGLWidget->isValid(); } +/** + * Show the data file read warnings dialog but only + * if warnings are found in any files. + */ +void +BrainBrowserWindow::showDataFileReadWarningsDialog() +{ + Brain* brain = GuiManager::get()->getBrain(); + if (brain == NULL) { + return; + } + + std::vector dataFiles; + brain->getAllDataFiles(dataFiles); + + AString messages; + for (auto file : dataFiles) { + const AString msg = file->getFileReadWarnings(); + if ( ! msg.isEmpty()) { + messages.append("

  • " + + file->getFileName() + + "
    " + + msg + + "
  • "); + } + } + + if ( ! messages.isEmpty()) { + messages.insert(0, + "
      "); + messages.append("
    "); + + WuQTextEditorDialog::runNonModal("Data File Warnings", + messages, + WuQTextEditorDialog::TextMode::HTML, + WuQTextEditorDialog::WrapMode::NO, + this); + } +} + + diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 7cc45ee72..0553751e8 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -307,6 +307,8 @@ namespace caret { bool isMacOptionKeyDown() const; + void showDataFileReadWarningsDialog(); + /** Index of this window */ int32_t m_browserWindowIndex; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index d9d9fbc55..1e24fd2e7 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -331,6 +331,7 @@ EventMacDockMenuUpdate.h EventOperatingSystemRequestOpenDataFile.h EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h +EventShowDataFileReadWarningsDialog.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h EventUpdateYokedWindows.h @@ -552,6 +553,7 @@ EventMacDockMenuUpdate.cxx EventOperatingSystemRequestOpenDataFile.cxx EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx +EventShowDataFileReadWarningsDialog.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx EventUpdateYokedWindows.cxx diff --git a/src/GuiQt/EventShowDataFileReadWarningsDialog.cxx b/src/GuiQt/EventShowDataFileReadWarningsDialog.cxx new file mode 100644 index 000000000..7bdbb3e4e --- /dev/null +++ b/src/GuiQt/EventShowDataFileReadWarningsDialog.cxx @@ -0,0 +1,75 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ +#include "EventShowDataFileReadWarningsDialog.h" +#undef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventShowDataFileReadWarningsDialog + * \brief This event is sent after files are read to show any warnings during file reading + * \ingroup GuiQt + * + * All data files are tested for the prescence of warnings from reading of the files. + * If there are warnings, a dialog is displayed listing the file read warnings. + * If there are no file read warnings, no dialog is displayed. + */ + +/** + * Constructor. + * + * @param browserWindowIndex + * Index of browser window on which dialog is displayed. + * If the window index is invalid, the warning + * will be displayed on an open browser window. + */ +EventShowDataFileReadWarningsDialog::EventShowDataFileReadWarningsDialog(const int32_t browserWindowIndex) +: Event(EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG), +m_browserWindowIndex(browserWindowIndex) +{ + +} + +/** + * Destructor. + */ +EventShowDataFileReadWarningsDialog::~EventShowDataFileReadWarningsDialog() +{ +} + +/** + * @return Index of window on which the dialog is displayed. If + * the index is not a valid window, the dialog is dispalayed over + * any available browser window. + */ +int32_t +EventShowDataFileReadWarningsDialog::getBrowserWindowIndex() const +{ + return m_browserWindowIndex; +} + diff --git a/src/GuiQt/EventShowDataFileReadWarningsDialog.h b/src/GuiQt/EventShowDataFileReadWarningsDialog.h new file mode 100644 index 000000000..a81ee8f75 --- /dev/null +++ b/src/GuiQt/EventShowDataFileReadWarningsDialog.h @@ -0,0 +1,61 @@ +#ifndef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ +#define __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class EventShowDataFileReadWarningsDialog : public Event { + + public: + EventShowDataFileReadWarningsDialog(const int32_t browserWindowIndex = -1); + + virtual ~EventShowDataFileReadWarningsDialog(); + + int32_t getBrowserWindowIndex() const; + + // ADD_NEW_METHODS_HERE + + private: + EventShowDataFileReadWarningsDialog(const EventShowDataFileReadWarningsDialog&); + + EventShowDataFileReadWarningsDialog& operator=(const EventShowDataFileReadWarningsDialog&); + + const int32_t m_browserWindowIndex; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ + // +#endif // __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ + +} // namespace +#endif //__EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index ac3406d00..2b775e95a 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -63,6 +63,7 @@ #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserWindowNew.h" +#include "EventShowDataFileReadWarningsDialog.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" @@ -293,6 +294,7 @@ GuiManager::initializeGuiManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } @@ -542,7 +544,8 @@ GuiManager::getActiveBrowserWindow() const BrainBrowserWindow* GuiManager::getBrowserWindowByWindowIndex(const int32_t browserWindowIndex) { - if (browserWindowIndex < static_cast(m_brainBrowserWindows.size())) { + if ((browserWindowIndex >= 0) + && (browserWindowIndex < static_cast(m_brainBrowserWindows.size()))) { return m_brainBrowserWindows[browserWindowIndex]; } return NULL; @@ -1456,6 +1459,21 @@ GuiManager::receiveEvent(Event* event) showHideHelpDialog(true, helpEvent->getBrainBrowserWindow()); m_helpViewerDialog->showHelpPageWithName(helpEvent->getHelpPageName()); + + helpEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG) { + EventShowDataFileReadWarningsDialog* warningEvent = dynamic_cast(event); + CaretAssert(warningEvent); + + BrainBrowserWindow* bbw = getBrowserWindowByWindowIndex(warningEvent->getBrowserWindowIndex()); + if (bbw == NULL) { + bbw = getActiveBrowserWindow(); + } + CaretAssert(bbw); + bbw->showDataFileReadWarningsDialog(); + + warningEvent->setEventProcessed(); } } diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 2003b62fa..17589dfdf 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -67,6 +67,7 @@ #include "EventManager.h" #include "EventModelGetAll.h" #include "EventUserInterfaceUpdate.h" +#include "EventShowDataFileReadWarningsDialog.h" #include "FileInformation.h" #include "GuiManager.h" #include "ImageFile.h" @@ -639,6 +640,8 @@ SceneDialog::openSceneFileButtonClicked() EventDataFileRead dataFileEvent(GuiManager::get()->getBrain()); dataFileEvent.addDataFile(DataFileTypeEnum::SCENE, openSceneFileName); EventManager::get()->sendEvent(dataFileEvent.getPointer()); + + EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); } @@ -2533,6 +2536,8 @@ SceneDialog::displayScenePrivateWithErrorMessageDialog(SceneFile* sceneFile, errorMessage); } + EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); + return successFlag; } diff --git a/src/GuiQt/SpecFileManagementDialog.cxx b/src/GuiQt/SpecFileManagementDialog.cxx index 4928a29ce..b26860f8f 100644 --- a/src/GuiQt/SpecFileManagementDialog.cxx +++ b/src/GuiQt/SpecFileManagementDialog.cxx @@ -62,6 +62,7 @@ #include "EventGetDisplayedDataFiles.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" +#include "EventShowDataFileReadWarningsDialog.h" #include "EventSpecFileReadDataFiles.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" @@ -2169,6 +2170,8 @@ SpecFileManagementDialog::fileReloadOrOpenFileActionSelected(int rowIndex) WuQMessageBox::errorOk(toolButtonWidget, errorMessage); } + + EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); } /** diff --git a/src/GuiQt/WuQTextEditorDialog.cxx b/src/GuiQt/WuQTextEditorDialog.cxx index 7c974163d..3a08e0300 100644 --- a/src/GuiQt/WuQTextEditorDialog.cxx +++ b/src/GuiQt/WuQTextEditorDialog.cxx @@ -79,7 +79,9 @@ WuQTextEditorDialog::runNonModal(const QString& dialogTitle, */ dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setVisible(true); dialog->show(); + dialog->activateWindow(); dialog->raise(); } -- GitLab From 66fe5e1729af233aff9f3192369f1b5eb79f7309 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 19 Jan 2018 15:06:10 -0600 Subject: [PATCH 598/755] Resolve WB-770 Histogram envelope is a straight line: In the Matrix4x4 implementation, logic was present to 'fix numerical error' which changed 'near zero' values to zero and this caused the polyline algorithm (converts line segments to triangle) to fail when a axis/dimension was large. By making the value zero, it caused an incorrect conversion (matrix multiplication) of model coordinates to window coordinates. Usage of the 'fix numerical error' code has been removed and resolves this issue. --- src/Nifti/Matrix4x4.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Nifti/Matrix4x4.cxx b/src/Nifti/Matrix4x4.cxx index 00f664857..a4c4f86b4 100644 --- a/src/Nifti/Matrix4x4.cxx +++ b/src/Nifti/Matrix4x4.cxx @@ -895,11 +895,9 @@ Matrix4x4::rotate( m.matrix[0][2] = (xz + wy)*2; m.matrix[1][2] = (yz - wx)*2; m.matrix[2][2] = zz*2.0 + s; - m.fixNumericalError(); postmultiply(m); - this->fixNumericalError(); this->setModified(); } @@ -1206,7 +1204,6 @@ Matrix4x4::premultiply(const Matrix4x4& tm) + matrix[row][3] * tm.matrix[3][3]; } setMatrix(matrixOut); - this->fixNumericalError(); this->setModified(); } @@ -1239,7 +1236,6 @@ Matrix4x4::postmultiply(const Matrix4x4& tm) + tm.matrix[row][3] * matrix[3][3]; } setMatrix(matrixOut); - this->fixNumericalError(); this->setModified(); } -- GitLab From b7a3fb473d5fbbe1a1362109efa34119b1139ce6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 22 Jan 2018 11:49:30 -0600 Subject: [PATCH 599/755] Fixed problem with surface space and stereotaxic space annotations disappearing (going behind) a flat surface when the surface view zooming value is less than one. The solution is to disable depth testing when drawing an annotation in surface/stereotaxic space on a flat surface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An alternative that also fixed the problem is when scaling the view of a flat surface, always use a value of one for scaling in Z in BrainOpenGLFixedPipeline::applyViewingTransformations(). This solution might affect the ‘3D’ view of some shapes. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 47 +++++++++++++------ ...rainOpenGLAnnotationDrawingFixedPipeline.h | 3 +- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 7dc3bf839..96853332b 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1146,7 +1146,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil convertObsoleteLineWidthPixelsToPercentageWidth(box); } - const bool depthTestFlag = isDrawnWithDepthTesting(box); + const bool depthTestFlag = isDrawnWithDepthTesting(box, + surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); uint8_t backgroundRGBA[4]; @@ -1272,7 +1273,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; - const bool depthTestFlag = isDrawnWithDepthTesting(colorBar); + const bool depthTestFlag = isDrawnWithDepthTesting(colorBar, + NULL); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); float backgroundRGBA[4]; @@ -1798,7 +1800,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; - const bool depthTestFlag = isDrawnWithDepthTesting(oval); + const bool depthTestFlag = isDrawnWithDepthTesting(oval, + surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); uint8_t backgroundRGBA[4]; @@ -2148,7 +2151,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; - const bool depthTestFlag = isDrawnWithDepthTesting(text); + const bool depthTestFlag = isDrawnWithDepthTesting(text, + surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); float backgroundRGBA[4]; @@ -2355,7 +2359,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; - const bool depthTestFlag = isDrawnWithDepthTesting(image); + const bool depthTestFlag = isDrawnWithDepthTesting(image, + surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); const bool drawAnnotationFlag = true; @@ -2603,7 +2608,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0f }; - const bool depthTestFlag = isDrawnWithDepthTesting(line); + const bool depthTestFlag = isDrawnWithDepthTesting(line, + surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); std::vector lineCoordinates; @@ -3197,31 +3203,44 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() * * @param annotation * Annotation that will be drawn. + * @param surface + * Surface that is being drawn. * @return * True if the annotation is drawn with depth testing, else false. */ bool -BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* /*annotation*/) +BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* annotation, + const Surface* surface) { - return true; -/* - bool depthTestFlag = false; - + bool testFlatSurfaceFlag = false; switch (annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - depthTestFlag = true; + testFlatSurfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: - depthTestFlag = true; + testFlatSurfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } + bool depthTestFlag = true; + + if (testFlatSurfaceFlag) { + if (surface != NULL) { + if (surface->getSurfaceType() == SurfaceTypeEnum::FLAT) { + depthTestFlag = false; + } + } + } + return depthTestFlag; -*/ } /** diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index beb1db1ed..4280d5195 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -253,7 +253,8 @@ namespace caret { const float secondPoint[3], const float lineThickness); - bool isDrawnWithDepthTesting(const Annotation* annotation); + bool isDrawnWithDepthTesting(const Annotation* annotation, + const Surface* surface); bool setDepthTestingStatus(const bool newDepthTestingStatus); -- GitLab From 98b4acc982b419693fc452091c2bb21fad9824d9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 22 Jan 2018 14:08:04 -0600 Subject: [PATCH 600/755] Re-resolve WB-715 Too small font size warning: Added warning for color bar font size. --- src/Annotations/AnnotationColorBar.cxx | 20 +++++++++++++++++++ src/Annotations/AnnotationColorBar.h | 6 ++++++ .../AnnotationFontAttributesInterface.h | 4 ++++ src/Annotations/AnnotationText.cxx | 1 + src/Annotations/AnnotationText.h | 4 ++-- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 7 +++++++ src/GuiQt/AnnotationFontWidget.cxx | 13 +++++++----- 7 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/Annotations/AnnotationColorBar.cxx b/src/Annotations/AnnotationColorBar.cxx index 1154148d3..6f6ea1d1d 100644 --- a/src/Annotations/AnnotationColorBar.cxx +++ b/src/Annotations/AnnotationColorBar.cxx @@ -138,6 +138,7 @@ AnnotationColorBar::copyHelperAnnotationColorBar(const AnnotationColorBar& obj) m_customColorText[1] = obj.m_customColorText[1]; m_customColorText[2] = obj.m_customColorText[2]; m_customColorText[3] = obj.m_customColorText[3]; + m_fontTooSmallWhenLastDrawnFlag = obj.m_fontTooSmallWhenLastDrawnFlag; } /** @@ -165,6 +166,8 @@ AnnotationColorBar::reset() clearSections(); clearNumericText(); + + m_fontTooSmallWhenLastDrawnFlag = false; } /** @@ -759,4 +762,21 @@ AnnotationColorBar::getScalarMinimumAndMaximumValues(float& minimumScalarOut, } } +/** + * @return Is the font too small when it is last drawn + * that may cause an OpenGL error and, as a result, + * the text is not seen by the user. + */ +bool +AnnotationColorBar::isFontTooSmallWhenLastDrawn() const +{ + return m_fontTooSmallWhenLastDrawnFlag; +} + +void +AnnotationColorBar::setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const +{ + m_fontTooSmallWhenLastDrawnFlag = tooSmallFontFlag; +} + diff --git a/src/Annotations/AnnotationColorBar.h b/src/Annotations/AnnotationColorBar.h index 8caf992be..7edec95b3 100644 --- a/src/Annotations/AnnotationColorBar.h +++ b/src/Annotations/AnnotationColorBar.h @@ -123,6 +123,10 @@ namespace caret { void setShowTickMarksSelected(const bool selected); + bool isFontTooSmallWhenLastDrawn() const override; + + void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const override; + // ADD_NEW_METHODS_HERE protected: @@ -157,6 +161,8 @@ namespace caret { bool m_showTickMarksSelected; + mutable bool m_fontTooSmallWhenLastDrawnFlag = false; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Annotations/AnnotationFontAttributesInterface.h b/src/Annotations/AnnotationFontAttributesInterface.h index 022fbf0b8..9e1332c8e 100644 --- a/src/Annotations/AnnotationFontAttributesInterface.h +++ b/src/Annotations/AnnotationFontAttributesInterface.h @@ -72,6 +72,10 @@ namespace caret { virtual void setUnderlineStyleEnabled(const bool enabled) = 0; + virtual bool isFontTooSmallWhenLastDrawn() const = 0; + + virtual void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const = 0; + // ADD_NEW_METHODS_HERE private: diff --git a/src/Annotations/AnnotationText.cxx b/src/Annotations/AnnotationText.cxx index 4b384acce..74ea28c96 100644 --- a/src/Annotations/AnnotationText.cxx +++ b/src/Annotations/AnnotationText.cxx @@ -807,6 +807,7 @@ AnnotationText::copyHelperAnnotationText(const AnnotationText& obj) m_underlineEnabled = obj.m_underlineEnabled; m_connectToBrainordinate = obj.m_connectToBrainordinate; m_fontPercentViewportSize = obj.m_fontPercentViewportSize; + m_fontTooSmallWhenLastDrawnFlag = obj.m_fontTooSmallWhenLastDrawnFlag; } /** diff --git a/src/Annotations/AnnotationText.h b/src/Annotations/AnnotationText.h index 78eeea655..219995541 100644 --- a/src/Annotations/AnnotationText.h +++ b/src/Annotations/AnnotationText.h @@ -80,9 +80,9 @@ namespace caret { int32_t getFontSizeForDrawing(const int32_t drawingViewportWidth, const int32_t drawingViewportHeight) const; - bool isFontTooSmallWhenLastDrawn() const; + bool isFontTooSmallWhenLastDrawn() const override; - void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const; + void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const override; AnnotationTextFontSizeTypeEnum::Enum getFontSizeType() const; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 96853332b..6a85693b5 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1730,6 +1730,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarText(const AnnotationColo const float windowZ = (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0; const int32_t numText = colorBar->getNumberOfNumericText(); + bool fontTooSmallFlag = false; for (int32_t i = 0; i < numText; i++) { const AnnotationColorBarNumericText* numericText = colorBar->getNumericText(i); const float scalar = numericText->getScalar(); @@ -1744,7 +1745,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarText(const AnnotationColo windowY, windowZ, annText); + + if (annText.isFontTooSmallWhenLastDrawn()) { + fontTooSmallFlag = true; + } } + + colorBar->setFontTooSmallWhenLastDrawn(fontTooSmallFlag); } diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 0340a2a82..14509e044 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -418,12 +418,15 @@ AnnotationFontWidget::updateFontSizeControls() } } - const AnnotationText* textAnnotation = dynamic_cast(annText); - if (textAnnotation != NULL) { - if (textAnnotation->isFontTooSmallWhenLastDrawn()) { - tooSmallFlag = true; - } + if (annText->isFontTooSmallWhenLastDrawn()) { + tooSmallFlag = true; } +// const AnnotationText* textAnnotation = dynamic_cast(annText); +// if (textAnnotation != NULL) { +// if (textAnnotation->isFontTooSmallWhenLastDrawn()) { +// tooSmallFlag = true; +// } +// } } updateFontSizeSpinBox(fontSizeValue, -- GitLab From 43a10c7b878f217e34cf780e114cee40a74c5837 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 22 Jan 2018 14:19:38 -0600 Subject: [PATCH 601/755] On the scene dialog: When the selected scene file is empty (contains zero scenes), disable the "List Files", "Zip", and "Upload" buttons. --- src/GuiQt/SceneDialog.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 17589dfdf..9dc125e60 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2801,6 +2801,7 @@ SceneDialog::updateSceneFileModifiedStatusLabel() * (1) The scene file is modified * (2) The filename is not the untitled file name */ + bool haveScenesFlag = false; bool saveButtonEnabledFlag = false; SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { @@ -2813,10 +2814,18 @@ SceneDialog::updateSceneFileModifiedStatusLabel() else { statusText = "NO"; } + + if (sceneFile->getNumberOfScenes() > 0) { + haveScenesFlag = true; + } } m_sceneFileModifiedStatusLabel->setText(statusText); m_saveSceneFilePushButton->setEnabled(saveButtonEnabledFlag); + + m_showFileStructurePushButton->setEnabled(haveScenesFlag); + m_zipSceneFilePushButton->setEnabled(haveScenesFlag); + m_uploadSceneFilePushButton->setEnabled(haveScenesFlag); } -- GitLab From 58933726307f008ec46edaa47ed846ec26a16883 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 22 Jan 2018 14:48:46 -0600 Subject: [PATCH 602/755] Added method to set the enabled status for any dialog "standard button" to WuQDialog. Added method to set the enabled status for the OK button to WuQDialogModal. --- src/GuiQt/WuQDialog.cxx | 23 +++++++++++++++++++++++ src/GuiQt/WuQDialog.h | 3 +++ src/GuiQt/WuQDialogModal.cxx | 13 +++++++++++++ src/GuiQt/WuQDialogModal.h | 2 ++ 4 files changed, 41 insertions(+) diff --git a/src/GuiQt/WuQDialog.cxx b/src/GuiQt/WuQDialog.cxx index 287ea51f1..34f2fe439 100644 --- a/src/GuiQt/WuQDialog.cxx +++ b/src/GuiQt/WuQDialog.cxx @@ -231,6 +231,29 @@ WuQDialog::setStandardButtonText(QDialogButtonBox::StandardButton button, } } +/** + * Set the enabled status of a standard button. + * If the button is invalid, a sever message is logged. + * + * @param button + * Standard button enum identifying button. + * @param enabled + * New enabled status for button. + */ +void +WuQDialog::setStandardButtonEnabled(QDialogButtonBox::StandardButton button, + const bool enabled) +{ + QPushButton* pushButton = this->buttonBox->button(button); + if (pushButton != NULL) { + pushButton->setEnabled(enabled); + } + else { + CaretLogSevere("PROGRAM ERROR: Attempted to set enabled status for an invalid Dialog Standard Button, id=" + + AString::number((int)button)); + } +} + /** * called to capture image after timeout so nothing obscures window. */ diff --git a/src/GuiQt/WuQDialog.h b/src/GuiQt/WuQDialog.h index e4552c873..ed9602046 100644 --- a/src/GuiQt/WuQDialog.h +++ b/src/GuiQt/WuQDialog.h @@ -83,6 +83,9 @@ namespace caret { void setStandardButtonText(QDialogButtonBox::StandardButton button, const AString& text); + void setStandardButtonEnabled(QDialogButtonBox::StandardButton button, + const bool enabled); + QPushButton* addUserPushButton(const AString& text, const QDialogButtonBox::ButtonRole buttonRole); diff --git a/src/GuiQt/WuQDialogModal.cxx b/src/GuiQt/WuQDialogModal.cxx index 234746289..855ee3bad 100644 --- a/src/GuiQt/WuQDialogModal.cxx +++ b/src/GuiQt/WuQDialogModal.cxx @@ -130,6 +130,19 @@ WuQDialogModal::setOkButtonText(const AString& text) */ } +/** + * Set the enabled status for the OK button. + * + * @param enabled + * New enabled status for the button. + */ +void +WuQDialogModal::setOkButtonEnabled(const bool enabled) +{ + this->setStandardButtonEnabled(QDialogButtonBox::Ok, + enabled); +} + /** * Set the Cancel button to the given text. If the text * is zero length, the Cancel button is removed. diff --git a/src/GuiQt/WuQDialogModal.h b/src/GuiQt/WuQDialogModal.h index 91d90f92e..a55e25c4c 100644 --- a/src/GuiQt/WuQDialogModal.h +++ b/src/GuiQt/WuQDialogModal.h @@ -43,6 +43,8 @@ namespace caret { void setOkButtonText(const AString& text); + void setOkButtonEnabled(const bool enabled); + void setCancelButtonText(const AString& text); void setSaveWindowPositionForNextTime(const AString& savePositionName = ""); -- GitLab From 95bb72889cdaca20695d08f12368027a739ead1d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 22 Jan 2018 14:49:07 -0600 Subject: [PATCH 603/755] Re-resolve WB-765 Upload Scene File to BALSA Updates: Moved "Upload" button to bottom of dialog (actually uses the OK button). --- .../BalsaDatabaseUploadSceneFileDialog.cxx | 34 +++++++++---------- .../BalsaDatabaseUploadSceneFileDialog.h | 4 +-- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx index e165f8636..3ff8ee89f 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx @@ -111,7 +111,7 @@ m_sceneFile(sceneFile) setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); - setOkButtonText(""); + setOkButtonText("Upload"); setCancelButtonText("Close"); m_basePathWidget->updateWithSceneFile(m_sceneFile); @@ -262,7 +262,7 @@ void BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() { m_balsaDatabaseManager->logout(); - m_uploadPushButton->setEnabled(false); + setOkButtonEnabled(false); m_selectStudyTitlePushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateAllLabels(); @@ -349,15 +349,7 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() m_autoSaveSceneFileCheckBox->setChecked(true); QObject::connect(m_autoSaveSceneFileCheckBox, &QCheckBox::clicked, this, &BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked); - - /* - * Upload push button - */ - m_uploadPushButton = new QPushButton("Upload"); - QObject::connect(m_uploadPushButton, &QPushButton::clicked, - this, &BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked); - - + int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_DATA_WIDGET = columnCounter++; @@ -387,8 +379,6 @@ BalsaDatabaseUploadSceneFileDialog::createUploadTab() row++; gridLayout->setRowMinimumHeight(row, 15); // empty row row++; - gridLayout->addWidget(m_uploadPushButton, row, COLUMN_DATA_WIDGET, 1, 1, Qt::AlignHCenter); - row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); @@ -623,9 +613,19 @@ void BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() { const AString username = m_usernameLineEdit->text().trimmed(); + if (username.isEmpty()) { + WuQMessageBox::errorOk(this, + "Username is empty"); + return; + } const AString password = m_passwordLineEdit->text().trimmed(); + if (password.isEmpty()) { + WuQMessageBox::errorOk(this, + "Password is empty"); + return; + } - m_uploadPushButton->setEnabled(false); + setOkButtonEnabled(false); m_selectStudyTitlePushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateUserRolesLabel(); @@ -680,7 +680,7 @@ BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() updateUserRolesLabel(); - m_uploadPushButton->setEnabled(true); + setOkButtonEnabled(true); m_selectStudyTitlePushButton->setEnabled(true); SessionManager::get()->getCaretPreferences()->setBalsaUserName(username); @@ -724,10 +724,10 @@ BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword() /** - * Gets called when the upload button is clicked. + * Gets called when the Upload button is clicked. */ void -BalsaDatabaseUploadSceneFileDialog::uploadButtonClicked() +BalsaDatabaseUploadSceneFileDialog::okButtonClicked() { CaretAssert(m_sceneFile); diff --git a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h index 0dbcde011..8f372d7ed 100644 --- a/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h +++ b/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h @@ -62,8 +62,6 @@ namespace caret { void returnPressedUsernameOrPassword(); - void uploadButtonClicked(); - void labelHtmlLinkClicked(const QString&); void validateUploadData(); @@ -87,6 +85,7 @@ namespace caret { void whatsThisDatabase(); protected: + virtual void okButtonClicked(); private: enum class LabelName { @@ -167,7 +166,6 @@ namespace caret { QPushButton* m_selectStudyTitlePushButton; QCheckBox* m_autoSaveSceneFileCheckBox; - QPushButton* m_uploadPushButton; SceneBasePathWidget* m_basePathWidget; -- GitLab From d98d9b10f43aab47d30dda354688e4905cc7a930 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 Jan 2018 11:52:37 -0600 Subject: [PATCH 604/755] Changed border "Lines" drawing to use OpenGL line strip since it is faster than the new "Polyline" drawing and added a new border drawing type "Polylines" that uses the new Polyline drawing. While the OpenGL line drawing is faster, the line width is limited by OpenGL the quality of the lines may be lower (no joins where line segments meet). The polyline drawning is slower but it is of higher quality (joins ends of line segments) and is not limited in width. --- src/Brain/BorderDrawingTypeEnum.cxx | 11 +++--- src/Brain/BorderDrawingTypeEnum.h | 2 ++ src/Brain/BrainOpenGLFixedPipeline.cxx | 47 ++++++++++++++++++-------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/Brain/BorderDrawingTypeEnum.cxx b/src/Brain/BorderDrawingTypeEnum.cxx index 429316665..71f3ca3b0 100644 --- a/src/Brain/BorderDrawingTypeEnum.cxx +++ b/src/Brain/BorderDrawingTypeEnum.cxx @@ -31,10 +31,9 @@ using namespace caret; /** * \class caret::BorderDrawingTypeEnum - * \brief - * - * + * \brief Enumerated type for border drawing */ + /** * Constructor. * @@ -78,7 +77,11 @@ BorderDrawingTypeEnum::initialize() "DRAW_AS_LINES", "Lines")); - enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POINTS_SPHERES, + enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POLYLINES, + "DRAW_AS_POLYLINES", + "Polylines")); + + enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POINTS_SPHERES, "DRAW_AS_POINTS_SPHERES", "Spheres")); diff --git a/src/Brain/BorderDrawingTypeEnum.h b/src/Brain/BorderDrawingTypeEnum.h index c5d565322..884f139fc 100644 --- a/src/Brain/BorderDrawingTypeEnum.h +++ b/src/Brain/BorderDrawingTypeEnum.h @@ -37,6 +37,8 @@ public: enum Enum { /** draw as lines */ DRAW_AS_LINES, + /** draw as lines but thicker and slower */ + DRAW_AS_POLYLINES, /** draw as spherical points */ DRAW_AS_POINTS_SPHERES, /** draw as square points */ diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 3fac5c379..c631dd051 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2673,10 +2673,14 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) bool drawSphericalPoints = false; bool drawSquarePoints = false; bool drawLines = false; + bool drawPolylines = false; switch (drawType) { case BorderDrawingTypeEnum::DRAW_AS_LINES: drawLines = true; break; + case BorderDrawingTypeEnum::DRAW_AS_POLYLINES: + drawPolylines = true; + break; case BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES: drawSphericalPoints = true; break; @@ -2747,14 +2751,21 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } + GraphicsPrimitive::PrimitiveType lineType = GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP; + bool allowPrimitiveRestartFlag = false; + if (drawPolylines) { + lineType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN; + allowPrimitiveRestartFlag = true; + } std::unique_ptr linesPrimitive; std::unique_ptr linesIdentificationPrimitive; - if (drawLines) { + if (drawLines + || drawPolylines) { if (borderDrawInfo.isSelect) { - linesIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); + linesIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(lineType)); } else { - linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN, + linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(lineType, solidColorRGBA)); } } @@ -2772,11 +2783,13 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) */ if (i > 0) { if ( ! lastPointForLineValidFlag) { - if (linesPrimitive) { - linesPrimitive->addPrimitiveRestart(); - } - if (linesIdentificationPrimitive) { - linesIdentificationPrimitive->addPrimitiveRestart(); + if (allowPrimitiveRestartFlag) { + if (linesPrimitive) { + linesPrimitive->addPrimitiveRestart(); + } + if (linesIdentificationPrimitive) { + linesIdentificationPrimitive->addPrimitiveRestart(); + } } } } @@ -2868,11 +2881,13 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) anatXYZ, lastAnatXYZ, unstretchedLinesLength)) { - if (linesPrimitive) { - linesPrimitive->addPrimitiveRestart(); - } - if (linesIdentificationPrimitive) { - linesIdentificationPrimitive->addPrimitiveRestart(); + if (allowPrimitiveRestartFlag) { + if (linesPrimitive) { + linesPrimitive->addPrimitiveRestart(); + } + if (linesIdentificationPrimitive) { + linesIdentificationPrimitive->addPrimitiveRestart(); + } } } } @@ -2966,7 +2981,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } glPopAttrib(); -} +}//p-> /** @@ -5530,6 +5545,10 @@ BrainOpenGLFixedPipeline::setOrthographicProjectionWithHeight(const int32_t view this->orthographicFar, this->orthographicNear); break; } + +// std::cout << "Viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; +// std::cout << " Ortho Left/Bottom: " << this->orthographicLeft << ", " << this->orthographicBottom << std::endl; +// std::cout << " Ortho Right/Top: " << this->orthographicRight << ", " << this->orthographicTop << std::endl; } /** -- GitLab From 3a4e7c4a8bb2445923e410466d5bb7c9246a9328 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 Jan 2018 15:07:46 -0600 Subject: [PATCH 605/755] Improve performance of border drawing by minimizing calls to Surface::getTopologyHelper(). When drawing borders, the border point coordinates are converted from barycentric to cartesian coordinates and Surface::getTopologyHelper() was called for each point in the border. This has been changed so that Surface::getTopologyHelper() is called once for each border and the topology helper is then passed as a parameter to the conversion process for each point. On my Mac, this resulted in about a 20% reduction in time required to draw a large number of surfaces with many borders. Apple's Instruments Tool had indicated that significant time was spent in locking and unlocking of the mutex in Surface::getTopologyHelper. Also, fixed drawing of 'Lines' border drawing so that it uses OpenGL line segments so that when 'unstretched lines' is enabled, segments can be skipped. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 63 ++++++++--- src/Brain/BrainOpenGLFixedPipeline.h | 1 + src/Files/SurfaceProjectedItem.cxx | 11 +- src/Files/SurfaceProjectedItem.h | 2 + src/Files/SurfaceProjection.h | 28 +++++ src/Files/SurfaceProjectionBarycentric.cxx | 126 +++++++++++++++++++++ src/Files/SurfaceProjectionBarycentric.h | 7 ++ src/Files/SurfaceProjectionVanEssen.cxx | 39 ++++++- src/Files/SurfaceProjectionVanEssen.h | 8 ++ 9 files changed, 263 insertions(+), 22 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c631dd051..f1c7ab186 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -2635,6 +2635,7 @@ void BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) { CaretAssert(borderDrawInfo.surface); + CaretAssert(borderDrawInfo.topologyHelper); CaretAssert(borderDrawInfo.border); const StructureEnum::Enum surfaceStructure = borderDrawInfo.surface->getStructure(); @@ -2672,11 +2673,11 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) bool drawSphericalPoints = false; bool drawSquarePoints = false; - bool drawLines = false; + bool drawLineSegments = false; bool drawPolylines = false; switch (drawType) { case BorderDrawingTypeEnum::DRAW_AS_LINES: - drawLines = true; + drawLineSegments = true; break; case BorderDrawingTypeEnum::DRAW_AS_POLYLINES: drawPolylines = true; @@ -2688,7 +2689,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) drawSquarePoints = true; break; case BorderDrawingTypeEnum::DRAW_AS_POINTS_AND_LINES: - drawLines = true; + drawLineSegments = true; drawSphericalPoints = true; break; } @@ -2706,8 +2707,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) const float drawAtDistanceAboveSurface = 0.0; - const CaretPointer th = borderDrawInfo.surface->getTopologyHelper(); - const std::vector& nodesBoundaryEdgeCount = th->getNumberOfBoundaryEdgesForAllNodes(); + const std::vector& nodesBoundaryEdgeCount = borderDrawInfo.topologyHelper->getNumberOfBoundaryEdgesForAllNodes(); CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); const uint8_t highlightFirstPointRGBA[4] = { 0, 255, 0, 1 }; @@ -2751,7 +2751,12 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } - GraphicsPrimitive::PrimitiveType lineType = GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP; + /* + * Due to the possibility of 'unstretched lines' not being drawn + * must OPENGL_LINES must be used since there is no way to skip + * a line segment in a line strip + */ + GraphicsPrimitive::PrimitiveType lineType = GraphicsPrimitive::PrimitiveType::OPENGL_LINES; bool allowPrimitiveRestartFlag = false; if (drawPolylines) { lineType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN; @@ -2759,7 +2764,7 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } std::unique_ptr linesPrimitive; std::unique_ptr linesIdentificationPrimitive; - if (drawLines + if (drawLineSegments || drawPolylines) { if (borderDrawInfo.isSelect) { linesIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(lineType)); @@ -2819,8 +2824,9 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) */ float xyz[3]; bool projectionValidFlag = p->getProjectedPositionAboveSurface(*borderDrawInfo.surface, - xyz, - drawAtDistanceAboveSurface); + borderDrawInfo.topologyHelper, + xyz, + drawAtDistanceAboveSurface); if ( ! projectionValidFlag) { lastPointForLineValidFlag = false; continue; @@ -2868,13 +2874,15 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) if (lastPointForLineValidFlag) { float anatXYZ[3]; const bool anatXyzValid = p->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, - anatXYZ, - drawAtDistanceAboveSurface); + borderDrawInfo.topologyHelper, + anatXYZ, + drawAtDistanceAboveSurface); const SurfaceProjectedItem* lastP = borderDrawInfo.border->getPoint(i - 1); float lastAnatXYZ[3]; const bool lastAnatXyzValid = lastP->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, - lastAnatXYZ, - drawAtDistanceAboveSurface); + borderDrawInfo.topologyHelper, + lastAnatXYZ, + drawAtDistanceAboveSurface); if (anatXyzValid && lastAnatXyzValid) { if (unstretchedBorderLineTest(xyz, lastPointForLineXYZ, @@ -2907,7 +2915,15 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) pointsIdentificationPrimitive->addVertex(xyz, idRGBA); } if (linesIdentificationPrimitive) { - linesIdentificationPrimitive->addVertex(xyz, idRGBA); + if (drawLineSegments) { + if (lastPointForLineValidFlag) { + linesIdentificationPrimitive->addVertex(lastPointForLineXYZ, idRGBA); + linesIdentificationPrimitive->addVertex(xyz, idRGBA); + } + } + else { + linesIdentificationPrimitive->addVertex(xyz, idRGBA); + } } } else { @@ -2928,7 +2944,15 @@ BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) } } if (linesPrimitive) { - linesPrimitive->addVertex(xyz); + if (drawLineSegments) { + if (lastPointForLineValidFlag) { + linesPrimitive->addVertex(lastPointForLineXYZ); + linesPrimitive->addVertex(xyz); + } + } + else { + linesPrimitive->addVertex(xyz); + } } } @@ -3281,6 +3305,8 @@ BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) void BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) { + CaretAssert(surface); + SelectionItemBorderSurface* idBorder = m_brain->getSelectionManager()->getSurfaceBorderIdentification(); /* @@ -3328,6 +3354,10 @@ BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); const bool isContralateralEnabled = borderDisplayProperties->isContralateralDisplayed(displayGroup, this->windowTabIndex); + BorderDrawInfo borderDrawInfo; + borderDrawInfo.surface = surface; + borderDrawInfo.topologyHelper = surface->getTopologyHelper().getPointer(); + const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* borderFile = brain->getBorderFile(i); @@ -3387,8 +3417,6 @@ BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) } glColor3fv(rgba); - BorderDrawInfo borderDrawInfo; - borderDrawInfo.surface = surface; borderDrawInfo.border = border; borderDrawInfo.rgba[0] = rgba[0]; borderDrawInfo.rgba[1] = rgba[1]; @@ -3459,6 +3487,7 @@ BrainOpenGLFixedPipeline::drawSurfaceBorderBeingDrawn(const Surface* surface) if (this->borderBeingDrawn != NULL) { BorderDrawInfo borderDrawInfo; borderDrawInfo.surface = const_cast(surface); + borderDrawInfo.topologyHelper = surface->getTopologyHelper().getPointer(); borderDrawInfo.border = this->borderBeingDrawn; borderDrawInfo.rgba[0] = 1.0; borderDrawInfo.rgba[1] = 0.0; diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index d21a0aefa..a7c5d2267 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -218,6 +218,7 @@ namespace caret { struct BorderDrawInfo { Surface* anatomicalSurface; Surface* surface; + TopologyHelper* topologyHelper; Border* border; int32_t borderFileIndex; int32_t borderIndex; diff --git a/src/Files/SurfaceProjectedItem.cxx b/src/Files/SurfaceProjectedItem.cxx index 4416191d4..1191d78d4 100644 --- a/src/Files/SurfaceProjectedItem.cxx +++ b/src/Files/SurfaceProjectedItem.cxx @@ -226,7 +226,7 @@ SurfaceProjectedItem::getProjectedPosition(const SurfaceFile& surfaceFile, if (valid == false) { if (this->vanEssenProjection->isValid()) { - valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, + valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, xyzOut, 0.0, isUnprojectedOntoSurface); @@ -253,6 +253,8 @@ SurfaceProjectedItem::getProjectedPosition(const SurfaceFile& surfaceFile, * * @param surfaceFile * Surface File for positioning. + * @param topologyHelper + * The topology helper. This value * @param xyzOut * Output containing the projected position. * @param distanceAboveSurface @@ -262,6 +264,7 @@ SurfaceProjectedItem::getProjectedPosition(const SurfaceFile& surfaceFile, */ bool SurfaceProjectedItem::getProjectedPositionAboveSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelper, float xyzOut[3], const float distanceAboveSurface) const { @@ -269,7 +272,8 @@ SurfaceProjectedItem::getProjectedPositionAboveSurface(const SurfaceFile& surfac if (valid == false) { if (this->barycentricProjection->isValid()) { - valid = this->barycentricProjection->unprojectToSurface(surfaceFile, + valid = this->barycentricProjection->unprojectToSurface(surfaceFile, + topologyHelper, xyzOut, distanceAboveSurface, true); @@ -278,7 +282,8 @@ SurfaceProjectedItem::getProjectedPositionAboveSurface(const SurfaceFile& surfac if (valid == false) { if (this->vanEssenProjection->isValid()) { - valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, + valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, + topologyHelper, xyzOut, distanceAboveSurface, true); diff --git a/src/Files/SurfaceProjectedItem.h b/src/Files/SurfaceProjectedItem.h index cc43fca90..33d747e1a 100644 --- a/src/Files/SurfaceProjectedItem.h +++ b/src/Files/SurfaceProjectedItem.h @@ -33,6 +33,7 @@ namespace caret { class SurfaceFile; class SurfaceProjectionBarycentric; class SurfaceProjectionVanEssen; + class TopologyHelper; class XmlWriter; class SurfaceProjectedItem : public CaretObjectTracksModification { @@ -67,6 +68,7 @@ namespace caret { const bool isUnprojectedOntoSurface) const; bool getProjectedPositionAboveSurface(const SurfaceFile& sf, + const TopologyHelper* th, float xyzOut[3], const float distanceAboveSurface) const; diff --git a/src/Files/SurfaceProjection.h b/src/Files/SurfaceProjection.h index 4ffcd0e51..d57b0def2 100644 --- a/src/Files/SurfaceProjection.h +++ b/src/Files/SurfaceProjection.h @@ -28,6 +28,7 @@ namespace caret { class SurfaceFile; + class TopologyHelper; class XmlWriter; class SurfaceProjection : public CaretObjectTracksModification { @@ -80,6 +81,33 @@ namespace caret { const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const = 0; + /** + * Unproject to the surface using 'this' projection. + * + * @param surfaceFile + * Surface file used for unprojecting. + * @param topologyHelperIn + * Topology helper. If NULL, topology helper from surfaceFile + * will be used but frequent calls to get the topology helper + * may be slow. + * @param xyzOut + * Output containing coordinate created by unprojecting. + * @param offsetFromSurface + * If 'unprojectWithOffsetFromSurface' is true, unprojected + * position will be this distance above (negative=below) + * the surface. + * @param unprojectWithOffsetFromSurface + * If true, ouput coordinate will be offset 'offsetFromSurface' + * distance from the surface. + * @return + * True if unprojection is successful, else false. + */ + virtual bool unprojectToSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelperIn, + float xyzOut[3], + const float offsetFromSurface, + const bool unprojectWithOffsetFromSurface) const = 0; + int32_t getProjectionSurfaceNumberOfNodes() const; void setProjectionSurfaceNumberOfNodes(const int surfaceNumberOfNodes); diff --git a/src/Files/SurfaceProjectionBarycentric.cxx b/src/Files/SurfaceProjectionBarycentric.cxx index 35b923164..b8d2b1418 100644 --- a/src/Files/SurfaceProjectionBarycentric.cxx +++ b/src/Files/SurfaceProjectionBarycentric.cxx @@ -222,6 +222,132 @@ SurfaceProjectionBarycentric::setTriangleAreas(const float triangleAreas[3]) this->setModified(); } +/** + * Unproject to the surface using 'this' projection. + * + * @param surfaceFile + * Surface file used for unprojecting. + * @param topologyHelperIn + * Topology helper. If NULL, topology helper from surfaceFile + * will be used but frequent calls to get the topology helper + * may be slow. + * @param xyzOut + * Output containing coordinate created by unprojecting. + * @param offsetFromSurface + * If 'unprojectWithOffsetFromSurface' is true, unprojected + * position will be this distance above (negative=below) + * the surface. + * @param unprojectWithOffsetFromSurface + * If true, ouput coordinate will be offset 'offsetFromSurface' + * distance from the surface. + * @return + * True if unprojection was successful. + */ +bool +SurfaceProjectionBarycentric::unprojectToSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelperIn, + float xyzOut[3], + const float offsetFromSurface, + const bool unprojectWithOffsetFromSurface) const +{ + /* + * Make sure projection surface number of nodes matches surface. + */ + if (this->projectionSurfaceNumberOfNodes > 0) { + if (surfaceFile.getNumberOfNodes() != this->projectionSurfaceNumberOfNodes) { + return false; + } + } + + const int32_t n1 = this->triangleNodes[0]; + const int32_t n2 = this->triangleNodes[1]; + const int32_t n3 = this->triangleNodes[2]; + + CaretAssert(n1 < surfaceFile.getNumberOfNodes()); + CaretAssert(n2 < surfaceFile.getNumberOfNodes()); + CaretAssert(n3 < surfaceFile.getNumberOfNodes()); + + /* + * All nodes MUST have neighbors (connected) + */ + const TopologyHelper* topologyHelper = ((topologyHelperIn != NULL) + ? topologyHelperIn + : surfaceFile.getTopologyHelper().getPointer()); + if ((topologyHelper->getNodeHasNeighbors(n1) == false) + || (topologyHelper->getNodeHasNeighbors(n2) == false) + || (topologyHelper->getNodeHasNeighbors(n3) == false)) { + return false; + } + + const float* c1 = surfaceFile.getCoordinate(n1); + const float* c2 = surfaceFile.getCoordinate(n2); + const float* c3 = surfaceFile.getCoordinate(n3); + + float barycentricXYZ[3]; + float barycentricNormal[3]; + + /* + * If all the nodes are the same (object projects to a single node, not triangle) + */ + if ((n1 == n2) && + (n2 == n3)) { + /* + * Use node's normal vector and position + */ + barycentricXYZ[0] = c1[0]; + barycentricXYZ[1] = c1[1]; + barycentricXYZ[2] = c1[2]; + const float* nodeNormal = surfaceFile.getNormalVector(n1); + barycentricNormal[0] = nodeNormal[0]; + barycentricNormal[1] = nodeNormal[1]; + barycentricNormal[2] = nodeNormal[2]; + } + else { + /* + * Compute position using barycentric coordinates + */ + float t1[3]; + float t2[3]; + float t3[3]; + for (int i = 0; i < 3; i++) { + t1[i] = triangleAreas[0] * c1[i]; + t2[i] = triangleAreas[1] * c2[i]; + t3[i] = triangleAreas[2] * c3[i]; + } + float area = (triangleAreas[0] + + triangleAreas[1] + + triangleAreas[2]); + if (area != 0) { + for (int i = 0; i < 3; i++) { + barycentricXYZ[i] = (t1[i] + t2[i] + t3[i]) / area; + } + } + else { + return false; + } + + if (MathFunctions::normalVector(c1, c2, c3, barycentricNormal) == false) { + return false; + } + } + + /* + * Set output coordinate, possibly offsetting from surface. + */ + for (int j = 0; j < 3; j++) { + if (unprojectWithOffsetFromSurface) { + xyzOut[j] = (barycentricXYZ[j] + + (barycentricNormal[j] * offsetFromSurface)); + } + else { + xyzOut[j] = (barycentricXYZ[j] + + (barycentricNormal[j] * signedDistanceAboveSurface)); + } + } + + return true; +} + /** * Unproject to the surface using 'this' projection. * diff --git a/src/Files/SurfaceProjectionBarycentric.h b/src/Files/SurfaceProjectionBarycentric.h index abf20ea3c..6b99b4c8b 100644 --- a/src/Files/SurfaceProjectionBarycentric.h +++ b/src/Files/SurfaceProjectionBarycentric.h @@ -28,6 +28,7 @@ class QXmlStreamReader; namespace caret { + class TopologyHelper; class SurfaceProjectionBarycentric : public SurfaceProjection { public: @@ -64,6 +65,12 @@ namespace caret { const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const; + bool unprojectToSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelper, + float xyzOut[3], + const float offsetFromSurface, + const bool unprojectWithOffsetFromSurface) const; + void reset(); bool isValid() const; diff --git a/src/Files/SurfaceProjectionVanEssen.cxx b/src/Files/SurfaceProjectionVanEssen.cxx index ac0743261..4c6fcfe75 100644 --- a/src/Files/SurfaceProjectionVanEssen.cxx +++ b/src/Files/SurfaceProjectionVanEssen.cxx @@ -160,11 +160,43 @@ SurfaceProjectionVanEssen::copyHelperSurfaceProjectionVanEssen(const SurfaceProj this->projectionValid = obj.projectionValid; } +/** + * Unproject to the surface using 'this' projection. + * + * @param surfaceFile + * Surface file used for unprojecting. + * @param xyzOut + * Output containing coordinate created by unprojecting. + * @param offsetFromSurface + * If 'unprojectWithOffsetFromSurface' is true, unprojected + * position will be this distance above (negative=below) + * the surface. + * @param unprojectWithOffsetFromSurface + * If true, ouput coordinate will be offset 'offsetFromSurface' + * distance from the surface. + */ +bool +SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, + float xyzOut[3], + const float offsetFromSurface, + const bool unprojectWithOffsetFromSurface) const +{ + return unprojectToSurface(surfaceFile, + NULL, + xyzOut, + offsetFromSurface, + unprojectWithOffsetFromSurface); +} + /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. + * @param topologyHelperIn + * Topology helper. If NULL, topology helper from surfaceFile + * will be used but frequent calls to get the topology helper + * may be slow. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface @@ -177,6 +209,7 @@ SurfaceProjectionVanEssen::copyHelperSurfaceProjectionVanEssen(const SurfaceProj */ bool SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelperIn, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const @@ -202,8 +235,10 @@ SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, /* * All nodes MUST have neighbors (connected) */ - const TopologyHelper* topologyHelper = surfaceFile.getTopologyHelper().getPointer(); - if ((topologyHelper->getNodeHasNeighbors(n1) == false) + const TopologyHelper* topologyHelper = ((topologyHelperIn != NULL) + ? topologyHelperIn + : surfaceFile.getTopologyHelper().getPointer()); + if ((topologyHelper->getNodeHasNeighbors(n1) == false) || (topologyHelper->getNodeHasNeighbors(n2) == false)) { return false; } diff --git a/src/Files/SurfaceProjectionVanEssen.h b/src/Files/SurfaceProjectionVanEssen.h index e8052a662..ad4499503 100644 --- a/src/Files/SurfaceProjectionVanEssen.h +++ b/src/Files/SurfaceProjectionVanEssen.h @@ -26,6 +26,8 @@ namespace caret { + class TopologyHelper; + class SurfaceProjectionVanEssen : public SurfaceProjection { public: @@ -41,6 +43,12 @@ namespace caret { bool operator!=(const SurfaceProjectionVanEssen& rhs) { return !(*this == rhs); } + bool unprojectToSurface(const SurfaceFile& surfaceFile, + const TopologyHelper* topologyHelper, + float xyzOut[3], + const float offsetFromSurface, + const bool unprojectWithOffsetFromSurface) const; + bool unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, -- GitLab From b865bf86d19ff687577070ac2f48c87a7a12459d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 Jan 2018 16:16:32 -0600 Subject: [PATCH 606/755] Resolve WB-772 Apply data normalization status when using Apply to Files: the normalization status (a file property) is now copied to the selected files. --- .../MapSettingsPaletteColorMappingWidget.cxx | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx index 64287cb1f..0605b22de 100644 --- a/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx +++ b/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx @@ -2672,21 +2672,29 @@ MapSettingsPaletteColorMappingWidget::applyToMultipleFilesPushbuttonClicked() iter != mappableFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; - if (cmdf->isMappedWithPalette()) { - QCheckBox* cb = ded.addCheckBox(cmdf->getFileNameNoPath()); - cb->setProperty(filePointerPropertyName.toLatin1().constData(), - qVariantFromValue((void*)cmdf)); - mapFileCheckBoxes.push_back(cb); - - if (previousApplyPaletteToMapFilesSelected.find(cmdf) != previousApplyPaletteToMapFilesSelected.end()) { - cb->setChecked(true); + if (cmdf != this->caretMappableDataFile) { + if (cmdf->isMappedWithPalette()) { + QCheckBox* cb = ded.addCheckBox(cmdf->getFileNameNoPath()); + cb->setProperty(filePointerPropertyName.toLatin1().constData(), + qVariantFromValue((void*)cmdf)); + mapFileCheckBoxes.push_back(cb); + + if (previousApplyPaletteToMapFilesSelected.find(cmdf) != previousApplyPaletteToMapFilesSelected.end()) { + cb->setChecked(true); + } } } } + if (mapFileCheckBoxes.empty()) { + WuQMessageBox::errorOk(this, "There are no other files loaded that accept application of palette settings"); + return; + } + previousApplyPaletteToMapFilesSelected.clear(); if (ded.exec() == WuQDataEntryDialog::Accepted) { + PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); for (std::vector::iterator iter = mapFileCheckBoxes.begin(); @@ -2696,6 +2704,14 @@ MapSettingsPaletteColorMappingWidget::applyToMultipleFilesPushbuttonClicked() if (cb->isChecked()) { void* pointer = cb->property(filePointerPropertyName.toLatin1().constData()).value(); CaretMappableDataFile* cmdf = (CaretMappableDataFile*)pointer; + + /* + * Copy the palette normalization mode from the file active in the dialog + * to the 'apply to file' + */ + if (this->caretMappableDataFile != NULL) { + cmdf->setPaletteNormalizationMode(this->caretMappableDataFile->getPaletteNormalizationMode()); + } const int32_t numMaps = cmdf->getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { -- GitLab From f63c766f0701207cd72be12370b810a7f94b8836 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 25 Jan 2018 08:57:48 -0600 Subject: [PATCH 607/755] Resolve WB-773: Change default location of colorbar to tab not window: Default location for colorbar is now TAB for overlays including the chart overlays. --- src/Brain/ChartTwoOverlay.cxx | 2 +- src/Brain/Overlay.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Brain/ChartTwoOverlay.cxx b/src/Brain/ChartTwoOverlay.cxx index 35833ba0f..f10b7977c 100644 --- a/src/Brain/ChartTwoOverlay.cxx +++ b/src/Brain/ChartTwoOverlay.cxx @@ -79,7 +79,7 @@ m_overlayIndex(overlayIndex) m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_colorBar = std::unique_ptr(new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL)); - m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); + m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; diff --git a/src/Brain/Overlay.cxx b/src/Brain/Overlay.cxx index 0d1bdab9b..2144afe10 100644 --- a/src/Brain/Overlay.cxx +++ b/src/Brain/Overlay.cxx @@ -73,7 +73,7 @@ m_includeVolumeFiles(includeVolumeFiles) m_wholeBrainVoxelDrawingMode = WholeBrainVoxelDrawingMode::DRAW_VOXELS_ON_TWO_D_SLICES; m_colorBar = new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL); - m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); + m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_opacity", &m_opacity); -- GitLab From 79cc3722c4fcb0ab5e24ed3c66adf86ae15659b4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 Jan 2018 09:27:57 -0600 Subject: [PATCH 608/755] Updated a tooltip for the border drawing types. --- src/GuiQt/BorderSelectionViewController.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/BorderSelectionViewController.cxx b/src/GuiQt/BorderSelectionViewController.cxx index ed9de06a5..d669b71ee 100644 --- a/src/GuiQt/BorderSelectionViewController.cxx +++ b/src/GuiQt/BorderSelectionViewController.cxx @@ -151,7 +151,9 @@ BorderSelectionViewController::createAttributesWidget() m_drawTypeComboBox->addItem(BorderDrawingTypeEnum::toGuiName(drawType), (int)drawType); } - m_drawTypeComboBox->setToolTip("Select the drawing style of borders"); + m_drawTypeComboBox->setToolTip("Select the drawing style of borders\n" + "Lines are faster but have limited width\n" + "Polylines are slower but have unlimited width"); QObject::connect(m_drawTypeComboBox, SIGNAL(activated(int)), this, SLOT(processAttributesChanges())); -- GitLab From e41ee4001cb949c97e9d54c45b4c96b7bf532d37 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 30 Jan 2018 11:39:46 -0600 Subject: [PATCH 609/755] Updates for WB-766 Lock Window/Tab Aspect Ratio Popup: Dialog has been updated to include a "do not show again" checkbox. --- src/Common/EventManager.cxx | 1 + src/Common/EventTypeEnum.cxx | 4 + src/Common/EventTypeEnum.h | 2 + src/GuiQt/CMakeLists.txt | 2 + ...EventTabAndWindowLockAspectRatioStatus.cxx | 161 ++++++++++++++++++ .../EventTabAndWindowLockAspectRatioStatus.h | 145 ++++++++++++++++ src/GuiQt/GuiManager.cxx | 38 +++++ src/GuiQt/GuiManager.h | 3 + src/GuiQt/LockAspectWarningDialog.cxx | 125 ++++++++------ src/GuiQt/LockAspectWarningDialog.h | 17 +- 10 files changed, 435 insertions(+), 63 deletions(-) create mode 100644 src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx create mode 100644 src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 2031cfd9e..87498f4e5 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -451,6 +451,7 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE: case EventTypeEnum::EVENT_SURFACES_GET: case EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET: + case EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS: case EventTypeEnum::EVENT_TOOLBOX_SELECTION_DISPLAY: case EventTypeEnum::EVENT_USER_INTERFACE_UPDATE: case EventTypeEnum::EVENT_PROGRESS_UPDATE: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 73fc7550a..41990c6a5 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -346,6 +346,10 @@ EventTypeEnum::initialize() "EVENT_SURFACE_STRUCTURES_VALID_GET", "GGet valid surface strucutures and their number of node")); + enumData.push_back(EventTypeEnum(EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS, + "EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS", + "Get lock aspect and related information for all tabs and windows")); + enumData.push_back(EventTypeEnum(EVENT_TOOLBOX_SELECTION_DISPLAY, "EVENT_TOOLBOX_SELECTION_DISPLAY", "Display or hide the selection toolbox")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 4c11a24c2..773d6aef2 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -180,6 +180,8 @@ public: EVENT_SURFACES_GET, /** Get valid surface strucutures and their number of nodes */ EVENT_SURFACE_STRUCTURES_VALID_GET, + /** Get the lock aspect and related information for tabs and windows */ + EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS, /** Display/Hide the selection toolbox */ EVENT_TOOLBOX_SELECTION_DISPLAY, /** Update the User-Interface */ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 1e24fd2e7..3e7c7772d 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -332,6 +332,7 @@ EventOperatingSystemRequestOpenDataFile.h EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h EventShowDataFileReadWarningsDialog.h +EventTabAndWindowLockAspectRatioStatus.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h EventUpdateYokedWindows.h @@ -554,6 +555,7 @@ EventOperatingSystemRequestOpenDataFile.cxx EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx EventShowDataFileReadWarningsDialog.cxx +EventTabAndWindowLockAspectRatioStatus.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx EventUpdateYokedWindows.cxx diff --git a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx new file mode 100644 index 000000000..c9e8566d7 --- /dev/null +++ b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx @@ -0,0 +1,161 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ +#include "EventTabAndWindowLockAspectRatioStatus.h" +#undef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ + +#include "Annotation.h" +#include "BrainBrowserWindow.h" +#include "BrainConstants.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventTabAndWindowLockAspectRatioStatus + * \brief Event that gets lock aspect and related information for tabs and windows + * \ingroup GuiQt + */ + +/** + * Constructor. + */ +EventTabAndWindowLockAspectRatioStatus::EventTabAndWindowLockAspectRatioStatus() +: Event(EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS) +{ + m_tabStatus.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); + m_windowStatus.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS); +} + +/** + * Destructor. + */ +EventTabAndWindowLockAspectRatioStatus::~EventTabAndWindowLockAspectRatioStatus() +{ +} + +/** + * @return Tab status for the given tab index, even if the tab is invalid. + * + * @param tabIndex + * Index of the tab. + * Must be in the range [0, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS - 1] + */ +EventTabAndWindowLockAspectRatioStatus::TabStatus* +EventTabAndWindowLockAspectRatioStatus::getTabStatus(const int32_t tabIndex) +{ + CaretAssertVectorIndex(m_tabStatus, tabIndex); + return &m_tabStatus[tabIndex]; +} + +/** + * @return Window status for the given window index, even if the window is invalid. + * + * @param windowIndex + * Index of the window. + * Must be in the range [0, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS - 1] + */ +EventTabAndWindowLockAspectRatioStatus::WindowStatus* +EventTabAndWindowLockAspectRatioStatus::getWindowStatus(const int32_t windowIndex) +{ + CaretAssertVectorIndex(m_windowStatus, windowIndex); + return &m_windowStatus[windowIndex]; +} + + +/** + * Setup this instance with the given windows, the tabs in the windows, and + * the given annotations. + * + * @param windows + * Open browser windows. + * @param annotations + * All annotations. + */ +void +EventTabAndWindowLockAspectRatioStatus::setup(const std::vector& windows, + const std::vector& annotations) +{ + /* + * Find tab and window annotations + */ + std::vector tabAnnotationFlag(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, false); + std::vector windowAnnotationFlag(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, false); + + for (const auto ann : annotations) { + switch (ann->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + CaretAssertVectorIndex(tabAnnotationFlag, ann->getTabIndex()); + tabAnnotationFlag[ann->getTabIndex()] = true; + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + CaretAssertVectorIndex(windowAnnotationFlag, ann->getWindowIndex()); + windowAnnotationFlag[ann->getWindowIndex()] = true; + break; + } + } + + /* + * Set tab/window status. + */ + for (const auto bbw : windows) { + if (bbw != NULL) { + const int32_t windowIndex = bbw->getBrowserWindowIndex(); + const bool windowAspectLocked = bbw->isAspectRatioLocked(); + const bool tileTabsEnabled = bbw->isTileTabsSelected(); + CaretAssertVectorIndex(windowAnnotationFlag, windowIndex); + WindowStatus* windowStatus = getWindowStatus(windowIndex); + windowStatus->setStatus(windowIndex, + windowAspectLocked, + tileTabsEnabled, + windowAnnotationFlag[windowIndex]); + + std::vector allTabs; + bbw->getAllTabContent(allTabs); + + for (const auto tab : allTabs) { + const int32_t tabIndex = tab->getTabNumber(); + const bool tabAspectLocked = tab->isAspectRatioLocked(); + + CaretAssertVectorIndex(tabAnnotationFlag, tabIndex); + TabStatus* tabStatus = getTabStatus(tabIndex); + tabStatus->setStatus(tabIndex, + windowIndex, + tabAspectLocked, + tabAnnotationFlag[tabIndex]); + } + } + } +} + diff --git a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h new file mode 100644 index 000000000..92b30f11e --- /dev/null +++ b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h @@ -0,0 +1,145 @@ +#ifndef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ +#define __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class Annotation; + class BrainBrowserWindow; + + class EventTabAndWindowLockAspectRatioStatus : public Event { + + public: + class TabStatus { + public: + TabStatus() { } + + void setStatus(const int32_t tabIndex, + const int32_t windowIndex, + const bool lockAspectRatioStatus, + const bool containsTabSpaceAnnotationsFlag) { + m_tabIndex = tabIndex; + m_windowIndex = windowIndex; + m_lockAspectRatioStatus = lockAspectRatioStatus; + m_containsTabSpaceAnnotationsFlag = containsTabSpaceAnnotationsFlag; + } + + bool isValid() { return (m_tabIndex >= 0); } + + int32_t getTabIndex() const { return m_tabIndex; } + + int32_t getWindowIndex() const { return m_windowIndex; } + + bool isAspectRatioLocked() const { return m_lockAspectRatioStatus; } + + bool hasTabSpaceAnnotations() const { return m_containsTabSpaceAnnotationsFlag; } + + private: + int32_t m_tabIndex = -1; + int32_t m_windowIndex = -1; + bool m_lockAspectRatioStatus = false; + bool m_containsTabSpaceAnnotationsFlag = false; + }; + + class WindowStatus { + public: + WindowStatus() { } + + void setStatus(const int32_t windowIndex, + const bool lockAspectRatioStatus, + const bool tileTabsEnabled, + const bool containsWindowSpaceAnnotationsFlag) { + m_windowIndex = windowIndex; + m_lockAspectRatioStatus = lockAspectRatioStatus; + m_tileTabsEnabled = tileTabsEnabled; + m_containsWindowSpaceAnnotationsFlag = containsWindowSpaceAnnotationsFlag; + } + + bool isValid() { return (m_windowIndex >= 0); } + + int32_t getWindowIndex() const { return m_windowIndex; } + + bool isAspectRatioLocked() const { return m_lockAspectRatioStatus; } + + bool isTileTabsEnabled() const { return m_tileTabsEnabled; } + + bool hasWindowSpaceAnnotations() const { return m_containsWindowSpaceAnnotationsFlag; } + + void addTabStatus(const TabStatus* tabStatus) { m_tabs.push_back(tabStatus); } + + int32_t getTabCount() const { return m_tabs.size(); } + + int32_t getTabLockedCount() const { + const int32_t tabLockedCount = std::count_if(m_tabs.begin(), + m_tabs.end(), + [](const TabStatus* ts) { return ts->isAspectRatioLocked(); }); + return tabLockedCount; + } + + private: + int32_t m_windowIndex = -1; + bool m_lockAspectRatioStatus = false; + bool m_tileTabsEnabled = false; + bool m_containsWindowSpaceAnnotationsFlag = false; + std::vector m_tabs; + }; + + EventTabAndWindowLockAspectRatioStatus(); + + virtual ~EventTabAndWindowLockAspectRatioStatus(); + + void setup(const std::vector& windows, + const std::vector& annotations); + + TabStatus* getTabStatus(const int32_t tabIndex); + + WindowStatus* getWindowStatus(const int32_t windowIndex); + + // ADD_NEW_METHODS_HERE + + private: + EventTabAndWindowLockAspectRatioStatus(const EventTabAndWindowLockAspectRatioStatus&); + + EventTabAndWindowLockAspectRatioStatus& operator=(const EventTabAndWindowLockAspectRatioStatus&); + + std::vector m_tabStatus; + + std::vector m_windowStatus; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ + // +#endif // __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ + +} // namespace +#endif //__EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 2b775e95a..c0ef3e5d5 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -33,7 +33,9 @@ #include "GuiManager.h" #undef __GUI_MANAGER_DEFINE__ +#include "Annotation.h" #include "AnnotationFile.h" +#include "AnnotationManager.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGL.h" @@ -77,6 +79,7 @@ #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventProgressUpdate.h" #include "EventSurfaceColoringInvalidate.h" +#include "EventTabAndWindowLockAspectRatioStatus.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "FociPropertiesEditorDialog.h" @@ -295,6 +298,7 @@ GuiManager::initializeGuiManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } @@ -1475,8 +1479,42 @@ GuiManager::receiveEvent(Event* event) warningEvent->setEventProcessed(); } + else if (event->getEventType() == EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS) { + EventTabAndWindowLockAspectRatioStatus* lockStatusEvent = dynamic_cast(event); + CaretAssert(lockStatusEvent); + + loadLockStatusEvent(lockStatusEvent); + + lockStatusEvent->setEventProcessed(); + } +} + +/** + * Load the lock aspect status event. + * + * @param lockStatusEvent + * The lock status event. + */ +void +GuiManager::loadLockStatusEvent(EventTabAndWindowLockAspectRatioStatus* lockStatusEvent) +{ + CaretAssert(lockStatusEvent); + + const std::vector annotations = getBrain()->getAnnotationManager()->getAllAnnotations(); + + std::vector openWindows; + for (const auto bbw : m_brainBrowserWindows) { + if (bbw != NULL) { + openWindows.push_back(bbw); + } + } + + lockStatusEvent->setup(openWindows, + annotations); } + + /** * Remove the tab content from all browser windows except for the given * browser windows, close the other browser windows, and then return diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index 2a79a8cc2..d4f832ce7 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -49,6 +49,7 @@ namespace caret { class ClippingPlanesDialog; class CursorManager; class CustomViewDialog; + class EventTabAndWindowLockAspectRatioStatus; class GapsAndMarginsDialog; class HelpViewerDialog; class IdentifyBrainordinateDialog; @@ -230,6 +231,8 @@ namespace caret { void addParentLessNonModalDialog(QWidget* dialog); + void loadLockStatusEvent(EventTabAndWindowLockAspectRatioStatus* lockStatusEvent); + /** One instance of the GuiManager */ static GuiManager* singletonGuiManager; diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index feca49306..c33f0dc59 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -30,12 +30,13 @@ #include #include #include -#include #include #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" +#include "EventManager.h" +#include "EventTabAndWindowLockAspectRatioStatus.h" #include "GuiManager.h" #include "WuQtUtilities.h" @@ -73,46 +74,35 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, return Result::NO_CHANGES; } - /* - * Determine lock status for window and tabs in the window - */ - const bool selectedTabLockedFlag = selectedTab->isAspectRatioLocked(); - - std::vector allTabs; - bbw->getAllTabContent(allTabs); - const int32_t tabCount = static_cast(allTabs.size()); - const int32_t tabLockedCount = std::count_if(allTabs.begin(), - allTabs.end(), - [](BrowserTabContent* btc) { return btc->isAspectRatioLocked(); }); - const bool allTabsLockedFlag = (tabCount == tabLockedCount); + if (s_doNotShowAgainStatusFlag) { + return Result::NO_CHANGES; + } + EventTabAndWindowLockAspectRatioStatus lockEvent; + EventManager::get()->sendEvent(lockEvent.getPointer()); + CaretAssert(lockEvent.getEventProcessCount() > 0); /* - * Check either selected tab for lock status or all tabs + * Determine lock status for window and tabs in the window */ - bool tabLockStatus = false; - switch (tabMode) { - case LockAspectWarningDialog::TabMode::ALL_TABS: - tabLockStatus = allTabsLockedFlag; - break; - case LockAspectWarningDialog::TabMode::SELECTED_TAB: - tabLockStatus = selectedTabLockedFlag; - break; - } + const bool tileTabsEnabledFlag = lockEvent.getWindowStatus(browserWindowIndex)->isTileTabsEnabled(); + const bool windowAspectLockedFlag = lockEvent.getWindowStatus(browserWindowIndex)->isAspectRatioLocked(); + const bool selectedTabLockedFlag = lockEvent.getTabStatus(selectedTab->getTabNumber())->isAspectRatioLocked(); - const bool windowApectLockedFlag = bbw->isAspectRatioLocked(); - if (windowApectLockedFlag - || tabLockStatus) { + if (windowAspectLockedFlag + || selectedTabLockedFlag) { return Result::NO_CHANGES; } LockAspectWarningDialog dialog(tabMode, - windowApectLockedFlag, - tabLockedCount, - tabCount, + tileTabsEnabledFlag, + windowAspectLockedFlag, + lockEvent.getWindowStatus(browserWindowIndex)->getTabLockedCount(), + lockEvent.getWindowStatus(browserWindowIndex)->getTabCount(), parent); if (dialog.exec() == LockAspectWarningDialog::Accepted) { + s_doNotShowAgainStatusFlag = dialog.isDoNotShowAgainChecked(); return dialog.getResult(); } @@ -124,6 +114,8 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, * * @param tabMode * The mode for tabs (selected or all) + * @param tileTabsEnabled + * True if tile tabs is enabled. * @param browserWindowAspectLocked * True if window aspect is locked. * @param tabAspectLockedCount @@ -134,6 +126,7 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, * The parent widget. */ LockAspectWarningDialog::LockAspectWarningDialog(const TabMode tabMode, + const bool tileTabsEnabled, const bool browserWindowAspectLocked, const int32_t tabAspectLockedCount, const int32_t tabCount, @@ -171,26 +164,26 @@ m_tabCount(tabCount) QLabel* warningLabel = new QLabel(msg); warningLabel->setWordWrap(true); - //QLabel* lockedStatusLabel = new QLabel(getLockedStatusText()); - QLabel* buttonsLabel = new QLabel("Continue to Annotations Mode?"); QPushButton* lockWindowAndTabButton = new QPushButton("OK - Lock Window and All Tab Aspects"); QObject::connect(lockWindowAndTabButton, &QPushButton::clicked, - this, &LockAspectWarningDialog::lockWindowAndTabsClicked); + [=] { this->buttonClicked(Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS); }); QPushButton* lockWindowButton = new QPushButton("OK - Lock Window Aspect"); QObject::connect(lockWindowButton, &QPushButton::clicked, - this, &LockAspectWarningDialog::lockWindowClicked); + [=] { this->buttonClicked(Result::LOCK_WINDOW_ASPECT); }); QPushButton* noChangesButton = new QPushButton("OK - No Lock Aspect Changes"); QObject::connect(noChangesButton, &QPushButton::clicked, - this, &LockAspectWarningDialog::noChangesClicked); + [=] { this->buttonClicked(Result::NO_CHANGES); }); QPushButton* cancelButton = new QPushButton("Cancel"); QObject::connect(cancelButton, &QPushButton::clicked, - this, &LockAspectWarningDialog::cancelClicked); + [=] { this->buttonClicked(Result::CANCEL); }); + m_doNotShowAgainCheckBox = new QCheckBox("Do not show again and user will be\n" + "responsible for aspect locking/unlocking"); QVBoxLayout* labelLayout = new QVBoxLayout(); labelLayout->addWidget(warningLabel); @@ -209,10 +202,21 @@ m_tabCount(tabCount) buttonLayout->addWidget(lockWindowButton); buttonLayout->addWidget(noChangesButton); buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); + buttonLayout->addWidget(m_doNotShowAgainCheckBox); buttonLayout->addStretch(); dialogLayout->addLayout(labelLayout); dialogLayout->addLayout(buttonLayout); + + /* + * Highlighted button + */ + QPushButton* defaultPushButton = (tileTabsEnabled + ? lockWindowAndTabButton + : lockWindowButton); + defaultPushButton->setAutoDefault(true); + defaultPushButton->setDefault(true); } /** @@ -261,32 +265,43 @@ LockAspectWarningDialog::getLockedStatusText() const return lockedMessage; } - +/** + * Called when one of the buttons is clicked. + * + * @param buttonClicked + * Button that was clicked. + */ void -LockAspectWarningDialog::lockWindowAndTabsClicked() +LockAspectWarningDialog::buttonClicked(const Result buttonClicked) { - m_result = Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS; - accept(); + switch (buttonClicked) { + case Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS: + m_result = Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS; + accept(); + break; + case Result::LOCK_WINDOW_ASPECT: + m_result = Result::LOCK_WINDOW_ASPECT; + accept(); + break; + case Result::NO_CHANGES: + m_result = Result::NO_CHANGES; + accept(); + break; + case Result::CANCEL: + m_result = Result::CANCEL; + reject(); + break; + } } -void -LockAspectWarningDialog::lockWindowClicked() -{ - m_result = Result::LOCK_WINDOW_ASPECT; - accept(); -} -void -LockAspectWarningDialog::noChangesClicked() +/** + * @return True if the "do not show again" checkbox is checked. + */ +bool +LockAspectWarningDialog::isDoNotShowAgainChecked() const { - m_result = Result::NO_CHANGES; - accept(); + return m_doNotShowAgainCheckBox->isChecked(); } -void -LockAspectWarningDialog::cancelClicked() -{ - m_result = Result::CANCEL; - reject(); -} diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h index 361bdee07..0f0f4ed61 100644 --- a/src/GuiQt/LockAspectWarningDialog.h +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -27,6 +27,7 @@ #include +class QCheckBox; namespace caret { @@ -52,6 +53,7 @@ namespace caret { QWidget* parent); LockAspectWarningDialog(const TabMode tabMode, + const bool tileTabsEnabled, const bool browserWindowAspectLocked, const int32_t tabAspectLockedCount, const int32_t tabCount, @@ -61,16 +63,12 @@ namespace caret { Result getResult() const; + bool isDoNotShowAgainChecked() const; + // ADD_NEW_METHODS_HERE private slots: - void lockWindowAndTabsClicked(); - - void lockWindowClicked(); - - void noChangesClicked(); - - void cancelClicked(); + void buttonClicked(const Result buttonClicked); private: LockAspectWarningDialog(const LockAspectWarningDialog&); @@ -89,13 +87,16 @@ namespace caret { Result m_result = Result::CANCEL; + QCheckBox* m_doNotShowAgainCheckBox; + + static bool s_doNotShowAgainStatusFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ - // + bool LockAspectWarningDialog::s_doNotShowAgainStatusFlag = false; #endif // __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ } // namespace -- GitLab From 75918e02931dfadc6e9bb316a7e5f44be8707bad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 31 Jan 2018 15:01:59 -0600 Subject: [PATCH 610/755] Fixed drawing of volume surface outline on volume slices in "All" view so that outlines "behind" the slices are not visible. Solution was to enable depth testing. Also fixed crash when switching to oblique slice drawing in ALL vlew by calling oblique slice drawing instead of orthogonal slice drawing. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 33 ++++++++++++---- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 8 +++- .../BrainOpenGLVolumeObliqueSliceDrawing.h | 3 ++ src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 38 +++++++++++++++++-- src/Brain/BrainOpenGLVolumeSliceDrawing.h | 6 ++- 5 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index f1c7ab186..7ad2029dc 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -5181,13 +5181,32 @@ BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabConte VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); - BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; - volumeSliceDrawing.draw(this, - browserTabContent, - twoDimSliceDrawVolumeDrawInfo, - sliceDrawingType, - sliceProjectionType, - viewport); + switch (sliceProjectionType) { + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: + { + VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); + BrainOpenGLVolumeObliqueSliceDrawing volumeSliceDrawing; + volumeSliceDrawing.draw(this, + browserTabContent, + twoDimSliceDrawVolumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + obliqueMaskType, + viewport); + } + break; + case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: + { + BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; + volumeSliceDrawing.draw(this, + browserTabContent, + twoDimSliceDrawVolumeDrawInfo, + sliceDrawingType, + sliceProjectionType, + viewport); + } + break; + } } } } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 35a724d55..793141bac 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -146,19 +146,22 @@ BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipeli m_brain = NULL; m_modelVolume = NULL; m_modelWholeBrain = NULL; + m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); m_brain = m_modelVolume->getBrain(); + m_modelType = m_modelVolume->getModelType(); } else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); m_brain = m_modelWholeBrain->getBrain(); + m_modelType = m_modelWholeBrain->getModelType(); } else { CaretAssertMessage(0, "Invalid model for volume slice drawing."); } CaretAssert(m_brain); - + CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); m_volumeDrawInfo = volumeDrawInfo; if (m_volumeDrawInfo.empty()) { @@ -2721,7 +2724,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnu glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(slicePlane, + BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_modelType, + slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing); } diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h index 872b05881..4e68fc801 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h @@ -24,6 +24,7 @@ #include "BrainOpenGLFixedPipeline.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" +#include "ModelTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" @@ -347,6 +348,8 @@ namespace caret { ModelWholeBrain* m_modelWholeBrain; + ModelTypeEnum::Enum m_modelType; + VolumeMappableInterface* m_underlayVolume; Brain* m_brain; diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index ee3dbaa0d..de5f0567b 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -147,18 +147,22 @@ BrainOpenGLVolumeSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawi m_brain = NULL; m_modelVolume = NULL; m_modelWholeBrain = NULL; + m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); m_brain = m_modelVolume->getBrain(); + m_modelType = m_modelVolume->getModelType(); } else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); m_brain = m_modelWholeBrain->getBrain(); + m_modelType = m_modelWholeBrain->getModelType(); } else { CaretAssertMessage(0, "Invalid model for volume slice drawing."); } CaretAssert(m_brain); + CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); m_volumeDrawInfo = volumeDrawInfo; if (m_volumeDrawInfo.empty()) { @@ -3489,7 +3493,8 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { - drawSurfaceOutline(slicePlane, + drawSurfaceOutline(m_modelType, + slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing); } @@ -3547,6 +3552,8 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum /** * Draw surface outlines on the volume slices * + * @param modelType + * Type of model being drawn. * @param plane * Plane of the volume slice on which surface outlines are drawn. * @param outlineSet @@ -3555,14 +3562,39 @@ BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum * The fixed pipeline drawing. */ void -BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const Plane& plane, +BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum modelType, + const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing) { glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - + + switch (modelType) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + /* + * Enable depth so outlines in front or in back + * of the slices. Without this the volume surface + * outlines "behind" the slices are visible and + * it looks weird + */ + glEnable(GL_DEPTH_TEST); + break; + } + /* * Process each surface outline * As of 24 May, "zero" is on top so draw in reverse order diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.h b/src/Brain/BrainOpenGLVolumeSliceDrawing.h index bd6251b42..445f6dd01 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.h +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.h @@ -24,6 +24,7 @@ #include "BrainOpenGLFixedPipeline.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" +#include "ModelTypeEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" @@ -239,7 +240,8 @@ namespace caret { const Plane& slicePlane, const float sliceCoordinates[3]); - static void drawSurfaceOutline(const Plane& plane, + static void drawSurfaceOutline(const ModelTypeEnum::Enum modelType, + const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing); @@ -329,6 +331,8 @@ namespace caret { void resetIdentification(); + ModelTypeEnum::Enum m_modelType; + ModelVolume* m_modelVolume; ModelWholeBrain* m_modelWholeBrain; -- GitLab From 78d9439ba940e9b4ed7f7950239daa19cb7c072f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 2 Feb 2018 10:40:16 -0600 Subject: [PATCH 611/755] Resolve WB-723 Volume surface outline height should scale with tab height: Thickness of the line is now a percentage of the viewport height. --- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 22 ++++++------- src/Brain/VolumeSurfaceOutlineModel.cxx | 24 +++++++------- src/Brain/VolumeSurfaceOutlineModel.h | 10 +++--- src/Brain/VolumeSurfaceOutlineSetModel.cxx | 4 +-- src/Graphics/GraphicsUtilitiesOpenGL.cxx | 31 ++++++++++++++++++- src/Graphics/GraphicsUtilitiesOpenGL.h | 2 ++ .../VolumeSurfaceOutlineViewController.cxx | 9 +++--- 7 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index de5f0567b..ae76a967a 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -3609,19 +3609,19 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { - float thicknessMillimeters = outline->getThicknessMillimeters(); + float thicknessPercentage = outline->getThicknessPercentageViewportHeight(); const float thicknessPixels = outline->getThicknessPixelsObsolete(); /* - * Thickness was changed from pixels to millimeters in December 2017 - * If thickness millimeters is negative, it was not present in an old - * scene so convert pixels to millimeters using viewports dimensions + * Thickness was changed from pixels to percentage viewport height on Feb 02, 2018 + * If thickness percentage is negative, it was not present in an old + * scene so convert pixels to percentage using viewports dimensions */ - if (thicknessMillimeters < 0.0f) { - thicknessMillimeters = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(thicknessPixels); - if (thicknessMillimeters > 0.0f) { - std::cout << "Converted pixel thickness=" << thicknessPixels << " to millimeters=" << thicknessMillimeters << std::endl; - outline->setThicknessMillimeters(thicknessMillimeters); + if (thicknessPercentage < 0.0f) { + thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessPixels); + if (thicknessPercentage > 0.0f) { + //std::cout << "Converted pixel thickness=" << thicknessPixels << " to millimeters=" << thicknessMillimeters << std::endl; + outline->setThicknessPercentageViewportHeight(thicknessPercentage); } } @@ -3648,12 +3648,12 @@ BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const ModelTypeEnum::Enum mode colorSourceBrowserTabIndex); } - const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(thicknessMillimeters); + //const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessMillimeters); SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, nodeColoringRGBA, - thicknessPercentage); // thickness); + thicknessPercentage); AString errorMessage; if ( ! contour.createContours(contourPrimitives, errorMessage)) { diff --git a/src/Brain/VolumeSurfaceOutlineModel.cxx b/src/Brain/VolumeSurfaceOutlineModel.cxx index 288e886a9..25dc6e9e5 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineModel.cxx @@ -63,16 +63,16 @@ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() m_sceneAssistant->add("m_colorOrTabModel", "VolumeSurfaceOutlineColorOrTabModel", m_colorOrTabModel); /* - * Millimeter thickness was added in December 2017. - * So, we set the millimeter thickness to -1.0f so that when an older + * Percentage viewport height thickness was added in Feb 2, 2017. + * So, we set the perentage thickness to -1.0f so that when an older * scene is restored, the value will be -1.0f. The code that draws * the volume surface outline see this negative value and convert - * the old pixel thickness to this new millimeter thickness. - * After adding to the scene assistant, default the millimeter thickness. + * the old pixel thickness to this new percentage thickness. + * After adding to the scene assistant, default the percentage thickness. */ - m_thicknessMillimeters = -1.0f; - m_sceneAssistant->add("m_thicknessMillimeters", &m_thicknessMillimeters); - m_thicknessMillimeters = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS; + m_thicknessPercentageViewportHeight = -1.0f; + m_sceneAssistant->add("m_thicknessPercentageViewportHeight", &m_thicknessPercentageViewportHeight); + m_thicknessPercentageViewportHeight = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; } /** @@ -96,7 +96,7 @@ VolumeSurfaceOutlineModel::copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineMod { m_displayed = modelToCopy->m_displayed; m_thicknessPixelsObsolete = modelToCopy->m_thicknessPixelsObsolete; - m_thicknessMillimeters = modelToCopy->m_thicknessMillimeters; + m_thicknessPercentageViewportHeight = modelToCopy->m_thicknessPercentageViewportHeight; m_surfaceSelectionModel->setSurface(modelToCopy->getSurface()); VolumeSurfaceOutlineColorOrTabModel* colorTabToCopy = modelToCopy->getColorOrTabModel(); @@ -137,18 +137,18 @@ VolumeSurfaceOutlineModel::setDisplayed(const bool displayed) * @return Thickness for drawing surface outline */ float -VolumeSurfaceOutlineModel::getThicknessMillimeters() const +VolumeSurfaceOutlineModel::getThicknessPercentageViewportHeight() const { - return m_thicknessMillimeters; + return m_thicknessPercentageViewportHeight; } /** * Set the thickness for drawing surface outline */ void -VolumeSurfaceOutlineModel::setThicknessMillimeters(const float thickness) +VolumeSurfaceOutlineModel::setThicknessPercentageViewportHeight(const float thickness) { - m_thicknessMillimeters = thickness; + m_thicknessPercentageViewportHeight = thickness; } /** diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index 374b8be9a..a728ab846 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -45,9 +45,9 @@ namespace caret { void setDisplayed(const bool displayed); - float getThicknessMillimeters() const; + float getThicknessPercentageViewportHeight() const; - void setThicknessMillimeters(const float thickness); + void setThicknessPercentageViewportHeight(const float thickness); float getThicknessPixelsObsolete() const; @@ -70,7 +70,7 @@ namespace caret { const SceneClass* sceneClass); static const float DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; - static const float DEFAULT_LINE_THICKNESS_MILLIMETERS; + static const float DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; private: VolumeSurfaceOutlineModel(const VolumeSurfaceOutlineModel&); @@ -85,7 +85,7 @@ namespace caret { float m_thicknessPixelsObsolete; - float m_thicknessMillimeters; + float m_thicknessPercentageViewportHeight; SurfaceSelectionModel* m_surfaceSelectionModel; @@ -96,7 +96,7 @@ namespace caret { #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; - const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS = 1.0; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT = 1.0; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace diff --git a/src/Brain/VolumeSurfaceOutlineSetModel.cxx b/src/Brain/VolumeSurfaceOutlineSetModel.cxx index 00718ec8c..9af38a186 100644 --- a/src/Brain/VolumeSurfaceOutlineSetModel.cxx +++ b/src/Brain/VolumeSurfaceOutlineSetModel.cxx @@ -64,7 +64,7 @@ VolumeSurfaceOutlineSetModel::VolumeSurfaceOutlineSetModel() for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { m_outlineModels[i] = new VolumeSurfaceOutlineModel(); } - m_numberOfDisplayedVolumeSurfaceOutlines = 6; //BrainConstants::MINIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; + m_numberOfDisplayedVolumeSurfaceOutlines = 6; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_numberOfDisplayedVolumeSurfaceOutlines", @@ -296,7 +296,7 @@ VolumeSurfaceOutlineSetModel::addSurfaceOutline(Surface* surface, VolumeSurfaceOutlineModel* vsos = m_outlineModels[outlineIndex]; vsos->getSurfaceSelectionModel()->setSurface(surface); vsos->setThicknessPixelsObsolete(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE); - vsos->setThicknessMillimeters(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS); + vsos->setThicknessPercentageViewportHeight(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT); if (browserTabIndex >= 0) { vsos->getColorOrTabModel()->setBrowserTabIndex(browserTabIndex); } diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.cxx b/src/Graphics/GraphicsUtilitiesOpenGL.cxx index f93f9b3d9..8f1b4936f 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.cxx +++ b/src/Graphics/GraphicsUtilitiesOpenGL.cxx @@ -58,6 +58,36 @@ GraphicsUtilitiesOpenGL::~GraphicsUtilitiesOpenGL() { } + +/** + * Converts pixels to a percentage of the viewport height. + * + * @param pixels + * The value in pixels. + * @return + The percentage of height [0.0, 100.0] for the given number of millimeters. + */ +float +GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(const float pixels) +{ + float percentageOfViewportHeight = 1.0f; + + EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); + EventManager::get()->sendEvent(xform.getPointer()); + if (xform.isValid()) { + const std::array viewport = xform.getViewport(); + + const float rangePixels = viewport[3]; + if ((rangePixels > 0) + && (pixels > 0)) { + percentageOfViewportHeight = (pixels / rangePixels) * 100.0f; + } + } + + return percentageOfViewportHeight ; + +} + /** * Converts millimeters to a percentage of the viewport height. * The current transformations must be for drawing in millimeters. @@ -97,7 +127,6 @@ GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(const fl } return percentageOfViewportHeight ; - } /** diff --git a/src/Graphics/GraphicsUtilitiesOpenGL.h b/src/Graphics/GraphicsUtilitiesOpenGL.h index d1d7269e9..fda72fb2e 100644 --- a/src/Graphics/GraphicsUtilitiesOpenGL.h +++ b/src/Graphics/GraphicsUtilitiesOpenGL.h @@ -37,6 +37,8 @@ namespace caret { static float convertMillimetersToPercentageOfViewportHeight(const float millimeters); + static float convertPixelsToPercentageOfViewportHeight(const float pixels); + static float convertPixelsToMillimeters(const float pixels); static void resetOpenGLError(); diff --git a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx index 6fadc0c8b..cd54c9d8e 100644 --- a/src/GuiQt/VolumeSurfaceOutlineViewController.cxx +++ b/src/GuiQt/VolumeSurfaceOutlineViewController.cxx @@ -81,7 +81,7 @@ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt: this->thicknessSpinBox = new WuQDoubleSpinBox(this); this->thicknessSpinBox->setRange(0.0, 100.0); this->thicknessSpinBox->setSingleStep(0.10); - this->thicknessSpinBox->setSuffix("mm"); + this->thicknessSpinBox->setSuffix("%"); QObject::connect(this->thicknessSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged); this->thicknessSpinBox->setToolTip("Thickness of surface outline as percentage of viewport height"); @@ -181,7 +181,7 @@ void VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged(double value) { if (this->outlineModel != NULL) { - this->outlineModel->setThicknessMillimeters(value); + this->outlineModel->setThicknessPercentageViewportHeight(value); } this->updateGraphics(); } @@ -204,15 +204,14 @@ VolumeSurfaceOutlineViewController::updateViewController(VolumeSurfaceOutlineMod this->enabledCheckBox->setCheckState(state); this->thicknessSpinBox->blockSignals(true); - float thickness = outlineModel->getThicknessMillimeters(); + float thickness = outlineModel->getThicknessPercentageViewportHeight(); if (thickness < 0.0f) { /* old scenes will have negative for mm thickness */ - thickness = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_MILLIMETERS; + thickness = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; } this->thicknessSpinBox->setValue(thickness); this->thicknessSpinBox->blockSignals(false); this->surfaceSelectionViewController->updateControl(outlineModel->getSurfaceSelectionModel()); - //this->surfaceSelectionViewController->setSurface(outlineModel->getSurface()); this->colorOrTabSelectionControl->updateViewController(outlineModel->getColorOrTabModel()); } } -- GitLab From 17d1b8580b67976bf67738ce8f06690b1f320e04 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 2 Feb 2018 11:09:41 -0600 Subject: [PATCH 612/755] Resolve WB-776: Change to Default Tabs: Default tabs are now limited to Montage, Volume, All, Chart. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 97 +++++++++++++------------ 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 280292f3a..b79668acc 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -911,56 +911,61 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() ModelVolume* volumeModel = NULL; ModelWholeBrain* wholeBrainModel = NULL; + const bool includeSingleSurfacesFlag = false; + const bool includeOldChartFlag = false; + for (std::vector::const_iterator iter = allModels.begin(); iter != allModels.end(); iter++) { ModelSurface* surfaceModel = dynamic_cast(*iter); if (surfaceModel != NULL) { - Surface* surface = surfaceModel->getSurface(); - StructureEnum::Enum structure = surface->getStructure(); - SurfaceTypeEnum::Enum surfaceType = surface->getSurfaceType(); - const int32_t surfaceTypeCode = SurfaceTypeEnum::toIntegerCode(surfaceType); - - switch (structure) { - case StructureEnum::CEREBELLUM: - if (surfaceTypeCode < cerebellumSurfaceTypeCode) { - cerebellumSurfaceModel = surfaceModel; - cerebellumSurfaceTypeCode = surfaceTypeCode; - } - if (surfaceType == SurfaceTypeEnum::INFLATED) { - cerebellumSurfaceInflated = surfaceModel; - } - else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { - cerebellumSurfaceVeryInflated = surfaceModel; - } - break; - case StructureEnum::CORTEX_LEFT: - if (surfaceTypeCode < leftSurfaceTypeCode) { - leftSurfaceModel = surfaceModel; - leftSurfaceTypeCode = surfaceTypeCode; - } - if (surfaceType == SurfaceTypeEnum::INFLATED) { - leftSurfaceInflated = surfaceModel; - } - else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { - leftSurfaceVeryInflated = surfaceModel; - } - break; - case StructureEnum::CORTEX_RIGHT: - if (surfaceTypeCode < rightSurfaceTypeCode) { - rightSurfaceModel = surfaceModel; - rightSurfaceTypeCode = surfaceTypeCode; - } - if (surfaceType == SurfaceTypeEnum::INFLATED) { - rightSurfaceInflated = surfaceModel; - } - else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { - rightSurfaceVeryInflated = surfaceModel; - } - break; - default: - break; + if (includeSingleSurfacesFlag) { + Surface* surface = surfaceModel->getSurface(); + StructureEnum::Enum structure = surface->getStructure(); + SurfaceTypeEnum::Enum surfaceType = surface->getSurfaceType(); + const int32_t surfaceTypeCode = SurfaceTypeEnum::toIntegerCode(surfaceType); + + switch (structure) { + case StructureEnum::CEREBELLUM: + if (surfaceTypeCode < cerebellumSurfaceTypeCode) { + cerebellumSurfaceModel = surfaceModel; + cerebellumSurfaceTypeCode = surfaceTypeCode; + } + if (surfaceType == SurfaceTypeEnum::INFLATED) { + cerebellumSurfaceInflated = surfaceModel; + } + else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { + cerebellumSurfaceVeryInflated = surfaceModel; + } + break; + case StructureEnum::CORTEX_LEFT: + if (surfaceTypeCode < leftSurfaceTypeCode) { + leftSurfaceModel = surfaceModel; + leftSurfaceTypeCode = surfaceTypeCode; + } + if (surfaceType == SurfaceTypeEnum::INFLATED) { + leftSurfaceInflated = surfaceModel; + } + else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { + leftSurfaceVeryInflated = surfaceModel; + } + break; + case StructureEnum::CORTEX_RIGHT: + if (surfaceTypeCode < rightSurfaceTypeCode) { + rightSurfaceModel = surfaceModel; + rightSurfaceTypeCode = surfaceTypeCode; + } + if (surfaceType == SurfaceTypeEnum::INFLATED) { + rightSurfaceInflated = surfaceModel; + } + else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { + rightSurfaceVeryInflated = surfaceModel; + } + break; + default: + break; + } } } else if (dynamic_cast(*iter) != NULL) { @@ -973,7 +978,9 @@ BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() wholeBrainModel = dynamic_cast(*iter); } else if (dynamic_cast(*iter)) { - chartModel = dynamic_cast(*iter); + if (includeOldChartFlag) { + chartModel = dynamic_cast(*iter); + } } else if (dynamic_cast(*iter)) { chartTwoModel = dynamic_cast(*iter); -- GitLab From 46264b0173beac417d6ff3d518c905e444851424 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 5 Feb 2018 12:23:35 -0600 Subject: [PATCH 613/755] WB-776 Change to Default Tabs: Change View section of toolbar so that the radio buttons for model selection match the default tabs (Montage, Volume, All, Chart) followed by non-default tabs Surface and Chart Old. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index b79668acc..35568773e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -1839,12 +1839,12 @@ BrainBrowserWindowToolBar::createViewWidget() QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); - layout->addWidget(this->viewModeChartOneRadioButton); - layout->addWidget(this->viewModeChartTwoRadioButton); layout->addWidget(this->viewModeSurfaceMontageRadioButton); layout->addWidget(this->viewModeVolumeRadioButton); layout->addWidget(this->viewModeWholeBrainRadioButton); + layout->addWidget(this->viewModeChartTwoRadioButton); layout->addWidget(this->viewModeSurfaceRadioButton); + layout->addWidget(this->viewModeChartOneRadioButton); layout->addStretch(); QButtonGroup* viewModeRadioButtonGroup = new QButtonGroup(this); -- GitLab From 78ae297b11a3e1903aab1a111718ec98e88978a5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 5 Feb 2018 12:35:33 -0600 Subject: [PATCH 614/755] WB-723 Volume surface outline thickness should scale with tab height: Changed default thickness to 0.4% --- src/Brain/VolumeSurfaceOutlineModel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Brain/VolumeSurfaceOutlineModel.h b/src/Brain/VolumeSurfaceOutlineModel.h index a728ab846..64d7e47a3 100644 --- a/src/Brain/VolumeSurfaceOutlineModel.h +++ b/src/Brain/VolumeSurfaceOutlineModel.h @@ -95,8 +95,8 @@ namespace caret { }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ - const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0; - const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT = 1.0; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0f; + const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT = 0.4f; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace -- GitLab From 69db9e1dfef7772db2d0ef9a1fbf6450cfa52f98 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Fri, 9 Feb 2018 17:13:47 -0600 Subject: [PATCH 615/755] various cleanup and text clarification --- .../AlgorithmVolumeLabelToSurfaceMapping.cxx | 2 +- src/Cifti/CiftiFile.cxx | 2 +- src/Commands/CommandParser.cxx | 12 ++++++------ src/Gifti/GiftiFile.cxx | 4 ++-- src/Nifti/NiftiHeader.cxx | 7 +++---- src/Operations/OperationLabelMask.cxx | 2 +- src/Operations/OperationMetricMask.cxx | 2 +- src/debian/copyright | 11 ++++++----- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx index 4d933bef7..30b7c8aad 100644 --- a/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx @@ -65,7 +65,7 @@ OperationParameters* AlgorithmVolumeLabelToSurfaceMapping::getParameters() subvolumeSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( - AString("Map label volume data to a surface. If -ribbon-constrained is not specified, uses the enclosing voxel method.") + + AString("Map label volume data to a surface. If -ribbon-constrained is not specified, uses the enclosing voxel method. ") + "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for a popularity comparison. " + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + diff --git a/src/Cifti/CiftiFile.cxx b/src/Cifti/CiftiFile.cxx index 6caac94ae..1c0e97be4 100644 --- a/src/Cifti/CiftiFile.cxx +++ b/src/Cifti/CiftiFile.cxx @@ -525,8 +525,8 @@ namespace switch (intent_code) { default: - CaretAssert(0); CaretLogWarning("unhandled cifti type in extension warning check, tell the developers what you just tried to do"); + CaretAssert(0);//yes, let it fall through to "unknown" in release so that it at least looks for .nii case 3000://unknown if (!filename.contains(QRegExp("\\.[^.]*\\.nii$"))) { diff --git a/src/Commands/CommandParser.cxx b/src/Commands/CommandParser.cxx index 785a28669..2f0c4226a 100644 --- a/src/Commands/CommandParser.cxx +++ b/src/Commands/CommandParser.cxx @@ -123,7 +123,7 @@ void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParam for (int i = 0; i < (int)myComponent->m_paramList.size(); ++i) { bool hyphenReplaced = false; - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_paramList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) @@ -404,7 +404,7 @@ void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParam for (int i = 0; i < (int)myComponent->m_outputList.size(); ++i) {//parse the output options of this component bool hyphenReplaced = false; - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_outputList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) @@ -530,7 +530,7 @@ void CommandParser::parseRemainingOptions(ParameterComponent* myComponent, Progr while (parameters.hasNext()) { bool hyphenReplaced = false; - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString("option"); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) @@ -573,7 +573,7 @@ CommandParser::CompletionInfo CommandParser::completionComponent(ParameterCompon // if parameters remain after the option is completed, restart the iteration in order to be able take another option immediately if (parameters.hasNext()) { - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_paramList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') @@ -685,7 +685,7 @@ CommandParser::CompletionInfo CommandParser::completionComponent(ParameterCompon {//parse the output options of this component if (parameters.hasNext()) { - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_outputList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') @@ -805,7 +805,7 @@ CommandParser::CompletionInfo CommandParser::completionRemainingOptions(Paramete CompletionInfo prev; while (parameters.hasNext()) { - //TSC: until someone complains, I say non-unicode dashes don't belong on the command line, EVER + //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString("option"); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') diff --git a/src/Gifti/GiftiFile.cxx b/src/Gifti/GiftiFile.cxx index cb336cea9..84a7e8f82 100644 --- a/src/Gifti/GiftiFile.cxx +++ b/src/Gifti/GiftiFile.cxx @@ -856,9 +856,9 @@ GiftiFile::readFile(const AString& filename) int colNum = e.getColumnNumber(); std::ostringstream str; - str << "Parse error while reading"; + str << "File is not a valid GIFTI file"; if ((lineNum >= 0) && (colNum >= 0)) { - str << ", line/col (" + str << ", error parsing at line/col (" << e.getLineNumber() << "/" << e.getColumnNumber() diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index 80d157213..386050431 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -483,10 +483,9 @@ namespace double mult, offset; Scaling(const double& minval, const double& maxval) { - std::numeric_limits mylimits; - double mymin = mylimits.min(); - if (!mylimits.is_integer) mymin = -mylimits.max();//again, c++11 can use lowest() instead of these lines - mult = (maxval - minval) / ((double)mylimits.max() - mymin);//multiplying is the first step of decoding (after byteswap), so start with the range + typedef std::numeric_limits mylimits; + double mymin = mylimits::lowest(); + mult = (maxval - minval) / ((double)mylimits::max() - mymin);//multiplying is the first step of decoding (after byteswap), so start with the range offset = minval - mymin * mult;//offset is added after multiplying the encoded value by mult } }; diff --git a/src/Operations/OperationLabelMask.cxx b/src/Operations/OperationLabelMask.cxx index 7e4818e22..6b163857d 100644 --- a/src/Operations/OperationLabelMask.cxx +++ b/src/Operations/OperationLabelMask.cxx @@ -46,7 +46,7 @@ OperationParameters* OperationLabelMask::getParameters() OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( - AString("By default, the output label is a copy of the input label, but with the 'unused' label wherever the mask metric is not positive. ") + + AString("By default, the output label is a copy of the input label, but with the 'unused' label wherever the mask metric is zero or negative. ") + "if -column is specified, the output contains only one column, the masked version of the specified input column." ); return ret; diff --git a/src/Operations/OperationMetricMask.cxx b/src/Operations/OperationMetricMask.cxx index 56ecaecd9..ae3042d23 100644 --- a/src/Operations/OperationMetricMask.cxx +++ b/src/Operations/OperationMetricMask.cxx @@ -45,7 +45,7 @@ OperationParameters* OperationMetricMask::getParameters() OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( - AString("By default, the output metric is a copy of the input metric, but with zeros wherever the mask metric is not positive. ") + + AString("By default, the output metric is a copy of the input metric, but with zeros wherever the mask metric is zero or negative. ") + "if -column is specified, the output contains only one column, the masked version of the specified input column." ); return ret; diff --git a/src/debian/copyright b/src/debian/copyright index 34bb7910d..8dd5bbc51 100644 --- a/src/debian/copyright +++ b/src/debian/copyright @@ -3,11 +3,11 @@ Upstream-Name: Connectome Workbench Source: http://www.humanconnectome.org/software/get-connectome-workbench.html Files: * -Copyright: 2014-2016 Washington University School of Medicine +Copyright: 2014-2018 Washington University School of Medicine License: GPL-2+ Files: src/Files/SurfaceResamplingHelper.cxx src/Cifti/examples/* src/CommandLine/wb_shortcuts src/CommandLine/wb_command_completion -Copyright: 2014-2015 Washington University School of Medicine +Copyright: 2014-2017 Washington University School of Medicine License: Expat Files: src/kloewe/* @@ -51,11 +51,11 @@ Copyright: 2014 Washington University School of Medicine 1970-2003, Wm. Randolph Franklin License: GPL-2+ and PNPOLY-BSD-3-Clause -Files: src/Resources/FtglFonts/Vera*.ttf +Files: src/Resources/General/Fonts/FtglFonts/Vera*.ttf src/Resources/General/Fonts/VeraFonts/Vera*.ttf Copyright: 2003 Bitstream, Inc. License: Bitstream-Vera -Files: src/Resources/Fonts/LinuxLibertine/*ttf +Files: src/Resources/General/Fonts/LinuxLibertine/*.ttf Copyright: 2003-2009 Philipp H. Poll License: GPL-2+ with Font exception and OFL-1.1 @@ -251,6 +251,8 @@ License: Expat SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License: Bitstream-Vera + Bitstream Vera is a trademark of Bitstream, Inc. + . Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute @@ -302,7 +304,6 @@ License: Qt-commercial conditions see http://qt.digia.com/licensing. For further information use the contact form at http://qt.digia.com/contact-us. - License: GPL-2+ with Font exception The linux-libertine fonts are dual-licensed under the GNU General Public License (GPL) with font exception, and the SIL Open Font License (OFL). -- GitLab From 2408b2a91933d1a1b9b7e8e12ae826d090f30cba Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 13 Feb 2018 18:57:00 -0600 Subject: [PATCH 616/755] make volume resampling preserve map names --- src/Algorithms/AlgorithmVolumeAffineResample.cxx | 4 ++++ src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Algorithms/AlgorithmVolumeAffineResample.cxx b/src/Algorithms/AlgorithmVolumeAffineResample.cxx index 62ea42180..bd23d0434 100644 --- a/src/Algorithms/AlgorithmVolumeAffineResample.cxx +++ b/src/Algorithms/AlgorithmVolumeAffineResample.cxx @@ -137,6 +137,10 @@ AlgorithmVolumeAffineResample::AlgorithmVolumeAffineResample(ProgressObject* myP *(outVol->getMapLabelTable(i)) = *(inVol->getMapLabelTable(i)); } } + for (int64_t i = 0; i < numMaps; ++i) + { + outVol->setMapName(i, inVol->getMapName(i)); + } for (int64_t c = 0; c < numComponents; ++c) { for (int64_t b = 0; b < numMaps; ++b) diff --git a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx index 6c9e0da06..e79e211c7 100644 --- a/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx +++ b/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx @@ -123,6 +123,10 @@ AlgorithmVolumeWarpfieldResample::AlgorithmVolumeWarpfieldResample(ProgressObjec *(outVol->getMapLabelTable(i)) = *(inVol->getMapLabelTable(i)); } } + for (int64_t i = 0; i < numMaps; ++i) + { + outVol->setMapName(i, inVol->getMapName(i)); + } for (int64_t c = 0; c < numComponents; ++c) { for (int64_t b = 0; b < numMaps; ++b) -- GitLab From da7783fb2ae3c07e0c7cb4e18c685da884415def Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 13 Feb 2018 18:58:12 -0600 Subject: [PATCH 617/755] print out skip gradient status when doing border optimize, to try to pin down an issue --- src/GuiQt/BorderOptimizeExecutor.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GuiQt/BorderOptimizeExecutor.cxx b/src/GuiQt/BorderOptimizeExecutor.cxx index b00bf5c86..e542b8820 100644 --- a/src/GuiQt/BorderOptimizeExecutor.cxx +++ b/src/GuiQt/BorderOptimizeExecutor.cxx @@ -1107,6 +1107,7 @@ BorderOptimizeExecutor::printInputs(const InputData& inputData) std::cout << " Strength: " << dfi.m_weight << std::endl; std::cout << " Smoothing: " << dfi.m_smoothing << std::endl; std::cout << " Invert Gradient: " << AString::fromBool(dfi.m_invertGradientFlag) << std::endl; + std::cout << " Skip Gradient: " << AString::fromBool(dfi.m_skipGradient) << std::endl; } std::cout << "Vertex Areas Metric File: " << ((inputData.m_vertexAreasMetricFile != NULL) ? qPrintable(inputData.m_vertexAreasMetricFile->getFileNameNoPath()) -- GitLab From e3ec246891ff05e5c7483a1f145213c226e047fe Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Feb 2018 08:36:08 -0600 Subject: [PATCH 618/755] Added Red White Blue palette for Alan a. --- src/Files/PaletteFile.cxx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Files/PaletteFile.cxx b/src/Files/PaletteFile.cxx index f996fc40b..35c8a9ac7 100644 --- a/src/Files/PaletteFile.cxx +++ b/src/Files/PaletteFile.cxx @@ -817,6 +817,26 @@ PaletteFile::addDefaultPalettes() addPalette(fslYellow); } + // + // Create a palette with red (positive), white (zero), + // and blue (negative) for Alan A. + // + if (this->getPaletteByName("RedWhiteBlue") == NULL) { + Palette redWhiteBlue; + redWhiteBlue.setName("RedWhiteBlue"); + this->addColor("rwbBlue", 0, 0, 255); + this->addColor("rwbBlueMiddle", 127, 127, 255); + this->addColor("rwbWhite", 255, 255, 255); + this->addColor("rwbRedMiddle", 255, 127, 127); + this->addColor("rwbRed", 255, 0, 0); + redWhiteBlue.addScalarAndColor( 1.0f, "rwbRed"); + redWhiteBlue.addScalarAndColor( 0.5f, "rwbRedMiddle"); + redWhiteBlue.addScalarAndColor( 0.0f, "rwbWhite"); + redWhiteBlue.addScalarAndColor(-0.5f, "rwbBlueMiddle"); + redWhiteBlue.addScalarAndColor(-1.0f, "rwbBlue"); + addPalette(redWhiteBlue); + } + if (this->getPaletteByName("JET256") == NULL) { Palette JET256; JET256.setName("JET256"); -- GitLab From f7ddc5eb7a34181856c9c18311c1f87c15fa979f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 7 Feb 2018 09:31:43 -0600 Subject: [PATCH 619/755] Starting on WB-767 Unifying aspect ratio locking --- src/Brain/BrowserWindowContent.cxx | 451 ++++++++++++++++++ src/Brain/BrowserWindowContent.h | 154 ++++++ src/Brain/CMakeLists.txt | 4 + src/Brain/EventBrowserWindowContent.cxx | 149 ++++++ src/Brain/EventBrowserWindowContent.h | 86 ++++ src/Brain/SessionManager.cxx | 36 ++ src/Brain/SessionManager.h | 6 + src/Common/CaretAssert.h | 21 + src/Common/CaretAssertion.cxx | 59 +++ src/Common/CaretAssertion.h | 6 + src/Common/EventManager.cxx | 3 +- src/Common/EventTypeEnum.cxx | 8 +- src/Common/EventTypeEnum.h | 4 +- src/GuiQt/BrainBrowserWindow.cxx | 47 +- src/GuiQt/BrainBrowserWindow.h | 6 +- .../BrainBrowserWindowOrientedToolBox.cxx | 4 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 10 +- src/GuiQt/BrainOpenGLWidget.cxx | 6 +- src/GuiQt/CMakeLists.txt | 4 +- ...x => EventBrowserWindowDrawingContent.cxx} | 32 +- ...t.h => EventBrowserWindowDrawingContent.h} | 16 +- src/GuiQt/UserInputModeImage.cxx | 6 +- src/GuiQt/UserInputModeVolumeEdit.cxx | 4 +- src/Scenes/ScenePrimitiveArray.cxx | 86 ++++ src/Scenes/ScenePrimitiveArray.h | 10 + 25 files changed, 1160 insertions(+), 58 deletions(-) create mode 100644 src/Brain/BrowserWindowContent.cxx create mode 100644 src/Brain/BrowserWindowContent.h create mode 100644 src/Brain/EventBrowserWindowContent.cxx create mode 100644 src/Brain/EventBrowserWindowContent.h rename src/GuiQt/{EventBrowserWindowContentGet.cxx => EventBrowserWindowDrawingContent.cxx} (70%) rename src/GuiQt/{EventBrowserWindowContentGet.h => EventBrowserWindowDrawingContent.h} (81%) diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx new file mode 100644 index 000000000..6febc53dc --- /dev/null +++ b/src/Brain/BrowserWindowContent.cxx @@ -0,0 +1,451 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BROWSER_WINDOW_CONTENT_DECLARE__ +#include "BrowserWindowContent.h" +#undef __BROWSER_WINDOW_CONTENT_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" +#include "SceneIntegerArray.h" + +using namespace caret; + + + +/** + * \class caret::BrowserWindowContent + * \brief Information about content of a browser window. + * \ingroup Brain + */ + +/** + * Constructor. + */ +BrowserWindowContent::BrowserWindowContent(const int32_t windowIndex) +: CaretObject(), +m_windowIndex(windowIndex) +{ + reset(); + + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_validFlag", &m_validFlag); + m_sceneAssistant->add("m_windowAspectRatioLocked", &m_windowAspectRatioLocked); + m_sceneAssistant->add("m_windowAspectLockedRatio", &m_windowAspectLockedRatio); + m_sceneAssistant->add("m_allTabsInWindowAspectRatioLocked", &m_allTabsInWindowAspectRatioLocked); + m_sceneAssistant->add("m_tileTabsEnabled", &m_tileTabsEnabled); + m_sceneAssistant->add("m_sceneWindowWidth", &m_sceneWindowWidth); + m_sceneAssistant->add("m_sceneWindowHeight", &m_sceneWindowHeight); + m_sceneAssistant->add("m_sceneSelectedTabIndex", &m_sceneSelectedTabIndex); +} + +/** + * Destructor. + */ +BrowserWindowContent::~BrowserWindowContent() +{ +} + +/** + * @return True if this browser window content is valid. + */ +bool +BrowserWindowContent::isValid() const +{ + return m_validFlag; +} + +/** + * Set validity for this browser window content. + * + * @param valid + * New validity status. + */ +void +BrowserWindowContent::setValid(const bool valid) +{ + m_validFlag = valid; +} + + +/** + * Reset the number of elements in this instance. + */ +void +BrowserWindowContent::reset() +{ + m_validFlag = false; + m_windowAspectRatioLocked = false; + m_windowAspectLockedRatio = 1.0f; + m_allTabsInWindowAspectRatioLocked = false; + m_tileTabsEnabled = false; + m_sceneWindowHeight = 0; + m_sceneWindowWidth = 0; + m_sceneTileTabsConfiguration = TileTabsConfiguration(); + m_sceneSelectedTabIndex = 0; + m_sceneTabIndices.clear(); +} + + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +int32_t +BrowserWindowContent::getWindowIndex() const +{ + return m_windowIndex; +} + +/** + * @return Window aspect locked status + */ +bool +BrowserWindowContent::isWindowAspectLocked() const +{ + return m_windowAspectRatioLocked; +} + +/** + * Set the window's aspect ratio locked status + * + * @param lockedStatus + * The new locked status. + */ +void +BrowserWindowContent::setWindowAspectLocked(const bool lockedStatus) +{ + m_windowAspectRatioLocked = lockedStatus; +} + +/** + * @return The window's locked aspect ratio + */ +float +BrowserWindowContent::getWindowAspectLockedRatio() const +{ + return m_windowAspectLockedRatio; +} + +/** + * Set the window's locked aspect ratio + * + * @param aspectRatio + * The aspect ratio. + */ +void +BrowserWindowContent::setWindowAspectLockedRatio(const float aspectRatio) +{ + m_windowAspectLockedRatio = aspectRatio; +} + +/** + * @return Is the aspect ratio locked for ALL TABS in the window + */ +bool +BrowserWindowContent::isAllTabsInWindowAspectRatioLocked() const +{ + return m_allTabsInWindowAspectRatioLocked; +} + +/** + * Set the aspect ratio locked for ALL TABS in the window + * + * @param lockedStatus + * The new locked status. + */ +void +BrowserWindowContent::setAllTabsInWindowAspectRatioLocked(const bool lockedStatus) +{ + m_allTabsInWindowAspectRatioLocked = lockedStatus; +} + +/** + * @return Is tile tabs enabled ? + */ +bool +BrowserWindowContent::isTileTabsEnabled() const +{ + return m_tileTabsEnabled; +} + +/** + * Set tile tabs enabled + * + * @param tileTabsEnabled + * Enabled status for tile tabs. + */ +void +BrowserWindowContent::setTileTabsEnabled(const bool tileTabsEnabled) +{ + m_tileTabsEnabled = tileTabsEnabled; +} + +/** + * @return Width of the window from scene. + */ +int32_t +BrowserWindowContent::getSceneWindowWidth() const +{ + return m_sceneWindowWidth; +} + +/** + * Set the width of the window for scene. + * + * @param width + * New value for width. + */ +void +BrowserWindowContent::setSceneWindowWidth(const int32_t width) +{ + m_sceneWindowWidth = width; +} + +/** + * @return Height of the window from scene. + */ +int32_t +BrowserWindowContent::getSceneWindowHeight() const +{ + return m_sceneWindowHeight; +} + +/** + * Set the height of the window for scene. + * + * @param height + * New value for height. + */ +void +BrowserWindowContent::setSceneWindowHeight(const int32_t height) +{ + m_sceneWindowHeight = height; +} + +/** + * @return The tile tabs configuration from the scene. + */ +TileTabsConfiguration +BrowserWindowContent::getSceneTileTabsConfiguration() const +{ + return m_sceneTileTabsConfiguration; +} + +/** + * @return Index of the selected tab in the scene. + */ +int32_t +BrowserWindowContent::getSceneSelectedTabIndex() const +{ + return m_sceneSelectedTabIndex; +} + +/** + * Set index of the selected tab in the scene. + * + * @param selectedTabIndex + * Index of selected tab. + */ +void +BrowserWindowContent::setSceneSelectedTabIndex(const int32_t selectedTabIndex) +{ + m_sceneSelectedTabIndex = selectedTabIndex; +} + +/** + * @return Indices of the tabs in the scene. + * In single tab view, this returns one index that is the same as getSceneSelectedTabIndex(). + * In tile tabs view, this contains all tabs in the window. + */ +std::vector +BrowserWindowContent::getSceneTabIndices() const +{ + return m_sceneTabIndices; +} + +/** + * Set indices of the tabs in the scene. + * In single tab view, this contains one index that the displayed tab. + * In tile tabs view, this contains all tabs in the window. + * + * @param sceneTabIndices + * Indices of the tabs. + */ +void +BrowserWindowContent::setSceneWindowTabIndices(const std::vector& sceneTabIndices) +{ + m_sceneTabIndices = sceneTabIndices; +} + +/** + * Set the tile tabs configuration for the scene. + * + * @param tileTabsConfiguration + * Tile tabs configuration for scene. + */ +void +BrowserWindowContent::setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration) +{ + m_sceneTileTabsConfiguration = tileTabsConfiguration; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "BrowserWindowContent", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + sceneClass->addString("m_sceneTileTabsConfiguration", m_sceneTileTabsConfiguration.encodeInXML()); + sceneClass->addChild(new SceneIntegerArray("m_sceneTabIndices", + m_sceneTabIndices)); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + reset(); + + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + const ScenePrimitiveArray* sceneTabIndicesArray = sceneClass->getPrimitiveArray("m_sceneTabIndices"); + if (sceneTabIndicesArray != NULL) { + sceneTabIndicesArray->integerVectorValues(m_sceneTabIndices); + } + + const AString stringTileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); + if ( ! stringTileTabsConfig.isEmpty()) { + if ( ! m_sceneTileTabsConfiguration.decodeFromXML(stringTileTabsConfig)) { + sceneAttributes->addToErrorMessage("Failed to decode tile tabs configuration from BrowserWindowContent: \"" + + stringTileTabsConfig + + "\""); + } + } + + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + +/** + * Restore from BrainBrowserWindow scene from before this class was created. + + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param browserClass + * A BrainBrowserWindow scene. + */ +void +BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttributes* sceneAttributes, + const SceneClass* browserClass) +{ + CaretAssert(browserClass); + + reset(); + + if (browserClass->getName() != "m_brainBrowserWindows") { + sceneAttributes->addToErrorMessage("When restoring BrowserWindowContent::restoreFromOldBrainBrowserWindowScene " + "name of scene class is not m_brainBrowserWindows"); + return; + } + + m_windowAspectRatioLocked = browserClass->getBooleanValue("m_windowAspectRatioLockedAction", + false); + + m_windowAspectLockedRatio = browserClass->getFloatValue("m_aspectRatio", 1.0f); + + /* not in old scene */ + m_allTabsInWindowAspectRatioLocked = false; + + m_tileTabsEnabled = browserClass->getBooleanValue("m_viewTileTabsAction", + false); + + + const SceneClass* graphicsGeometry = browserClass->getClass("openGLWidgetGeometry"); + if (graphicsGeometry != NULL) { + m_sceneWindowWidth = graphicsGeometry->getIntegerValue("geometryWidth", -1); + m_sceneWindowHeight = graphicsGeometry->getIntegerValue("geometryHeight", -1); + } + + const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); + if ( ! tileTabsConfigString.isEmpty()) { + m_sceneTileTabsConfiguration.decodeFromXML(tileTabsConfigString); + } + + const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); + if (toolbarClass != NULL) { + m_sceneSelectedTabIndex = toolbarClass->getIntegerValue("selectedTabIndex", -1); + + const ScenePrimitiveArray* tabIndexArray = toolbarClass->getPrimitiveArray("tabIndices"); + if (tabIndexArray != NULL) { + const int32_t numTabs = tabIndexArray->getNumberOfArrayElements(); + for (auto iTab = 0; iTab < numTabs; iTab++) { + m_sceneTabIndices.push_back(tabIndexArray->integerValue(iTab)); + } + } + } +} + + diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h new file mode 100644 index 000000000..3436576d1 --- /dev/null +++ b/src/Brain/BrowserWindowContent.h @@ -0,0 +1,154 @@ +#ifndef __BROWSER_WINDOW_CONTENT_H__ +#define __BROWSER_WINDOW_CONTENT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "SceneableInterface.h" +#include "TileTabsConfiguration.h" + + +namespace caret { + class SceneClassAssistant; + + class BrowserWindowContent : public CaretObject, public SceneableInterface { + + public: + BrowserWindowContent(const int32_t windowIndex); + + virtual ~BrowserWindowContent(); + + int32_t getWindowIndex() const; + + bool isValid() const; + + void setValid(const bool valid); + + void reset(); + + bool isWindowAspectLocked() const; + + void setWindowAspectLocked(const bool lockedStatus); + + float getWindowAspectLockedRatio() const; + + void setWindowAspectLockedRatio(const float aspectRatio); + + bool isAllTabsInWindowAspectRatioLocked() const; + + void setAllTabsInWindowAspectRatioLocked(const bool lockedStatus); + + bool isTileTabsEnabled() const; + + void setTileTabsEnabled(const bool tileTabsEnabled); + + int32_t getSceneWindowWidth() const; + + void setSceneWindowWidth(const int32_t width); + + int32_t getSceneWindowHeight() const; + + void setSceneWindowHeight(const int32_t width); + + TileTabsConfiguration getSceneTileTabsConfiguration() const; + + void setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration); + + int32_t getSceneSelectedTabIndex() const; + + void setSceneSelectedTabIndex(const int32_t selectedTabIndex); + + std::vector getSceneTabIndices() const; + + void setSceneWindowTabIndices(const std::vector& sceneTabIndices); + + // ADD_NEW_METHODS_HERE + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + void restoreFromOldBrainBrowserWindowScene(const SceneAttributes* sceneAttributes, + const SceneClass* browserClass); + + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + BrowserWindowContent(const BrowserWindowContent&); + + BrowserWindowContent& operator=(const BrowserWindowContent&); + + std::unique_ptr m_sceneAssistant; + + bool m_validFlag; + + const int32_t m_windowIndex; + + bool m_windowAspectRatioLocked = false; + + float m_windowAspectLockedRatio = 1.0f; + + bool m_allTabsInWindowAspectRatioLocked = false; + + bool m_tileTabsEnabled = false; + + int32_t m_sceneWindowWidth = 0; + + int32_t m_sceneWindowHeight = 0; + + TileTabsConfiguration m_sceneTileTabsConfiguration; + + int32_t m_sceneSelectedTabIndex = 0; + + std::vector m_sceneTabIndices; + + // /** Each tab has its own aspect ratio */ + // std::array m_tabAspectRatio; + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BROWSER_WINDOW_CONTENT_DECLARE__ + // +#endif // __BROWSER_WINDOW_CONTENT_DECLARE__ + +} // namespace +#endif //__BROWSER_WINDOW_CONTENT_H__ diff --git a/src/Brain/CMakeLists.txt b/src/Brain/CMakeLists.txt index 06d09803f..efe5e351e 100644 --- a/src/Brain/CMakeLists.txt +++ b/src/Brain/CMakeLists.txt @@ -52,6 +52,7 @@ BrainOpenGLWindowContent.h BrainStructure.h BrainStructureNodeAttributes.h BrowserTabContent.h +BrowserWindowContent.h CaretDataFileSelectionModel.h CaretMappableDataFileAndMapSelectionModel.h ChartTwoOverlay.h @@ -81,6 +82,7 @@ EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h EventBrowserTabNew.h +EventBrowserWindowContent.h EventChartOverlayValidate.h EventDataFileAdd.h EventDataFileDelete.h @@ -200,6 +202,7 @@ BrainOpenGLWindowContent.cxx BrainStructure.cxx BrainStructureNodeAttributes.cxx BrowserTabContent.cxx +BrowserWindowContent.cxx CaretDataFileSelectionModel.cxx CaretMappableDataFileAndMapSelectionModel.cxx ChartTwoOverlay.cxx @@ -228,6 +231,7 @@ EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx EventBrowserTabNew.cxx +EventBrowserWindowContent.cxx EventChartOverlayValidate.cxx EventDataFileAdd.cxx EventDataFileDelete.cxx diff --git a/src/Brain/EventBrowserWindowContent.cxx b/src/Brain/EventBrowserWindowContent.cxx new file mode 100644 index 000000000..ab71321de --- /dev/null +++ b/src/Brain/EventBrowserWindowContent.cxx @@ -0,0 +1,149 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ +#include "EventBrowserWindowContent.h" +#undef __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ + +#include "CaretAssert.h" +#include "EventTypeEnum.h" + +using namespace caret; + + + +/** + * \class caret::EventBrowserWindowContent + * \brief Evnets involving browser window content + * \ingroup Brain + */ + +/** + * Constructor. + * + * @param mode + * The mode. + * @param browserWindowIndex + * Index of the browser window. + */ +EventBrowserWindowContent::EventBrowserWindowContent(const Mode mode, + const int32_t browserWindowIndex) +: Event(EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT), +m_mode(mode), +m_browserWindowIndex(browserWindowIndex) +{ + +} + +/** + * Destructor. + */ +EventBrowserWindowContent::~EventBrowserWindowContent() +{ +} + +/** + * @return Event that is sent to create new BrowserWindowContent + * for the given window index. + * + * @param windowIndex + * Index of the new window. + */ +std::unique_ptr +EventBrowserWindowContent::newWindowContent(const int32_t windowIndex) +{ + EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::NEW, + windowIndex); + std::unique_ptr pointer(event); + return pointer; +} + +/** + * @return Event that is sent to create delete BrowserWindowContent + * for the given window index. + * + * @param windowIndex + * Index of the deleted window. + */ +std::unique_ptr +EventBrowserWindowContent::deleteWindowContent(const int32_t windowIndex) +{ + EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::DELETE, + windowIndex); + std::unique_ptr pointer(event); + return pointer; +} + +/** + * @return Event that is sent to create get BrowserWindowContent + * for the given window index. + * + * @param windowIndex + * Index of the window. + */ +std::unique_ptr +EventBrowserWindowContent::getWindowContent(const int32_t windowIndex) +{ + EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::GET, + windowIndex); + std::unique_ptr pointer(event); + return pointer; +} + + +/** + * @return The mode. + */ +EventBrowserWindowContent::Mode +EventBrowserWindowContent::getMode() const +{ + return m_mode; +} + +/** + * @return Pointer to the browser window content. + */ +BrowserWindowContent* +EventBrowserWindowContent::getBrowserWindowContent() +{ + return m_browserWindowContent; +} + +/** + * Set the browser window content. + * + * @param browserWindowContent + * Pointer to the browser window content. + */ +void +EventBrowserWindowContent::setBrowserWindowContent(BrowserWindowContent* browserWindowContent) +{ + m_browserWindowContent = browserWindowContent; +} + +/** + * @return Index of the browser window. + */ +int32_t +EventBrowserWindowContent::getBrowserWindowIndex() const +{ + return m_browserWindowIndex; +} diff --git a/src/Brain/EventBrowserWindowContent.h b/src/Brain/EventBrowserWindowContent.h new file mode 100644 index 000000000..deb25ca63 --- /dev/null +++ b/src/Brain/EventBrowserWindowContent.h @@ -0,0 +1,86 @@ +#ifndef __EVENT_BROWSER_WINDOW_CONTENT_H__ +#define __EVENT_BROWSER_WINDOW_CONTENT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "Event.h" + + + +namespace caret { + + class BrowserWindowContent; + + class EventBrowserWindowContent : public Event { + + public: + enum class Mode { + DELETE, + GET, + NEW + }; + + static std::unique_ptr newWindowContent(const int32_t windowIndex); + + static std::unique_ptr deleteWindowContent(const int32_t windowIndex); + + static std::unique_ptr getWindowContent(const int32_t windowIndex); + + virtual ~EventBrowserWindowContent(); + + Mode getMode() const; + + BrowserWindowContent* getBrowserWindowContent(); + + void setBrowserWindowContent(BrowserWindowContent* browserWindowContent); + + int32_t getBrowserWindowIndex() const; + + // ADD_NEW_METHODS_HERE + + private: + EventBrowserWindowContent(const Mode mode, + const int32_t browserWindowIndex); + + EventBrowserWindowContent(const EventBrowserWindowContent&); + + EventBrowserWindowContent& operator=(const EventBrowserWindowContent&); + + const Mode m_mode; + + const int32_t m_browserWindowIndex = -1; + + BrowserWindowContent* m_browserWindowContent = NULL; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ + // +#endif // __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ + +} // namespace +#endif //__EVENT_BROWSER_WINDOW_CONTENT_H__ diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index d8112b128..30fc6dded 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -29,6 +29,7 @@ #include "BackgroundAndForegroundColorsSceneHelper.h" #include "Brain.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" @@ -41,6 +42,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventBrowserTabNew.h" +#include "EventBrowserWindowContent.h" #include "EventCaretPreferencesGet.h" #include "EventModelAdd.h" #include "EventModelDelete.h" @@ -78,11 +80,14 @@ SessionManager::SessionManager() m_browserTabs[i] = NULL; } + m_browserWindowContent.fill(NULL); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_PREFERENCES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_DELETE); @@ -110,6 +115,10 @@ SessionManager::~SessionManager() } } + std::for_each(m_browserWindowContent.begin(), + m_browserWindowContent.end(), + [](BrowserWindowContent* bwc) { if (bwc != NULL) delete bwc; } ); + int32_t numberOfBrains = getNumberOfBrains(); for (int32_t i = (numberOfBrains - 1); i >= 0; i--) { delete m_brains[i]; @@ -343,6 +352,33 @@ SessionManager::receiveEvent(Event* event) } } } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT) { + EventBrowserWindowContent* windowEvent = + dynamic_cast(event); + CaretAssert(windowEvent); + + windowEvent->setEventProcessed(); + + const int32_t windowIndex = windowEvent->getBrowserWindowIndex(); + CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); + + switch (windowEvent->getMode()) { + case EventBrowserWindowContent::Mode::DELETE: + CaretAssert(m_browserWindowContent[windowIndex]); + delete m_browserWindowContent[windowIndex]; + m_browserWindowContent[windowIndex] = NULL; + break; + case EventBrowserWindowContent::Mode::GET: + CaretAssert(m_browserWindowContent[windowIndex]); + windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); + break; + case EventBrowserWindowContent::Mode::NEW: + CaretAssert(m_browserWindowContent[windowIndex] == NULL); + m_browserWindowContent[windowIndex] = new BrowserWindowContent(windowIndex); + windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); + break; + } + } else if (event->getEventType() == EventTypeEnum::EVENT_CARET_PREFERENCES_GET) { EventCaretPreferencesGet* preferencesEvent = dynamic_cast(event); diff --git a/src/Brain/SessionManager.h b/src/Brain/SessionManager.h index c5a49b522..ca2b48dc4 100644 --- a/src/Brain/SessionManager.h +++ b/src/Brain/SessionManager.h @@ -21,6 +21,8 @@ */ /*LICENSE_END*/ +#include + #include "ApplicationTypeEnum.h" #include "BrainConstants.h" #include "CaretObject.h" @@ -31,6 +33,7 @@ namespace caret { class Brain; class BrowserTabContent; + class BrowserWindowContent; class CaretPreferences; class CiftiConnectivityMatrixDataFileManager; class CiftiFiberTrajectoryManager; @@ -97,6 +100,9 @@ namespace caret { /** The browser tabs */ BrowserTabContent* m_browserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; + /** The browser window content */ + std::array m_browserWindowContent; + /** Holds valid models */ std::vector m_models; diff --git a/src/Common/CaretAssert.h b/src/Common/CaretAssert.h index b75b919b1..6ad9c58cf 100644 --- a/src/Common/CaretAssert.h +++ b/src/Common/CaretAssert.h @@ -33,6 +33,7 @@ #define CaretAssertMessage(e, m) ((void)0) #define CaretAssertArrayIndex(a, n, i) ((void) 0) #define CaretAssertVectorIndex(v, i) ((void) 0) + #define CaretAssertStdArrayIndex(v, i) ((void) 0) #define CaretUsedInDebugCompileOnly(e) ((void) 0) #define CaretParameterUsedInDebugCompileOnly(e) @@ -178,6 +179,26 @@ ? caret::CaretAssertion::assertVectorIndexFailed(#v, (static_cast(v.size())), i, __FILE__, __LINE__) \ : (void)0) +/** + * \def CaretAssertStdArrayIndex + * + * If the std array index is out of bounds, a message is printed + * listing the std array name, the std array's number of elements, the + * invalid std array index, the name of the file, and the line + * number in the file. A call stack may also + * be printed. Lastly, abort() is called. + * @param a + * The vector. + * @param i + * The index into the vector. + */ +#define CaretAssertStdArrayIndex(a, i) \ +((((i) < 0) || ((i) >= (static_cast(a.size())))) \ +? caret::CaretAssertion::assertStdArrayIndexFailed(#a, (static_cast(a.size())), i, __FILE__, __LINE__) \ +: (void)0) + + + #endif // NDEBUG diff --git a/src/Common/CaretAssertion.cxx b/src/Common/CaretAssertion.cxx index defdf5319..9603ad014 100644 --- a/src/Common/CaretAssertion.cxx +++ b/src/Common/CaretAssertion.cxx @@ -320,6 +320,65 @@ CaretAssertion::assertVectorIndexFailed(const char* vectorName, } } +/** + * Called when a std array index assertion has failed. + * The following events will occur: + * Prints the name of the array, the number of + * elements in the array, the invalid array index, + * the name of the file where the assertion failed, + * the line number in the file. If + * a callstack (backtrace) is available, it will + * also be printed. Lastly, abort() is called. + * + * + * @param arrayName + * Name of the array. + * @param arrayNumberOfElements + * Number of elements in the array. + * @param arrayIndex + * Invalid array index. + * @param filename + * Name of file in which assertion failed. + * @param lineNumber + * Line number where assertion failed. + */ +void +CaretAssertion::assertStdArrayIndexFailed(const char* arrayName, + const int64_t arrayNumberOfElements, + const int64_t arrayIndex, + const char* filename, + const int64_t lineNumber) +{ + std::cerr \ + << "Assertion of Std Array Bounds failed for array: " + << arrayName + << std::endl + << "File: " + << filename + << std::endl + << "Line number: " + << lineNumber + << std::endl; + + std::cerr + << "Index: " + << arrayIndex + << std::endl + << "Number of elements in array: " + << arrayNumberOfElements + << std::endl + << std::endl; + + const AString s = SystemUtilities::getBackTrace(); + if (s.isEmpty() == false) { + std::cerr << s << std::endl << std::endl; + } + + if (CaretAssertion::unitTestFlag == false) { + std::abort(); + } +} + /** * Unit testing of assertions. * diff --git a/src/Common/CaretAssertion.h b/src/Common/CaretAssertion.h index 4a1016dbb..6cc278b12 100644 --- a/src/Common/CaretAssertion.h +++ b/src/Common/CaretAssertion.h @@ -72,6 +72,12 @@ public: const char* filename, const int64_t lineNumber); + static void assertStdArrayIndexFailed(const char* arrayName, + const int64_t arrayNumberOfElements, + const int64_t arrayIndex, + const char* filename, + const int64_t lineNumber); + static void unitTest(std::ostream& stream, const bool isVerbose); diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 87498f4e5..af0ded624 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -398,8 +398,9 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED: case EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_NEW: - case EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET: + case EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT: case EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS: + case EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET: case EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN: case EventTypeEnum::EVENT_BROWSER_WINDOW_NEW: case EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 41990c6a5..e10b02be0 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -134,8 +134,12 @@ EventTypeEnum::initialize() "EVENT_BROWSER_TAB_NEW", "Create a browser tab")); - enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CONTENT_GET, - "EVENT_BROWSER_WINDOW_CONTENT_GET", + enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CONTENT, + "EVENT_BROWSER_WINDOW_CONTENT", + "Event for browser window content")); + + enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET, + "EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET", "Get the content in a browser window")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CREATE_TABS, diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 773d6aef2..9d5b84300 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -72,8 +72,10 @@ public: EVENT_BROWSER_TAB_GET_ALL_VIEWED, /** Create a new browser tab */ EVENT_BROWSER_TAB_NEW, + /** Event for browser window content */ + EVENT_BROWSER_WINDOW_CONTENT, /** Get the content of a browser window */ - EVENT_BROWSER_WINDOW_CONTENT_GET, + EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET, /** Create tabs after loading a file */ EVENT_BROWSER_WINDOW_CREATE_TABS, /** Issued after a browser window's graphicshave been redrawn */ diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index be8692125..870fae61f 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -49,6 +49,7 @@ #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretFileRemoteDialog.h" @@ -63,6 +64,7 @@ #include "ElapsedTimer.h" #include "EventGetViewportSize.h" #include "EventBrowserWindowCreateTabs.h" +#include "EventBrowserWindowContent.h" #include "EventDataFileRead.h" #include "EventMacDockMenuUpdate.h" #include "EventManager.h" @@ -125,14 +127,20 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, const CreateDefaultTabsMode createDefaultTabsMode, QWidget* parent, Qt::WindowFlags flags) -: QMainWindow(parent, flags) +: QMainWindow(parent, flags), +m_browserWindowIndex(browserWindowIndex) { m_developMenuAction = NULL; + std::unique_ptr bwc = EventBrowserWindowContent::newWindowContent(m_browserWindowIndex); + EventManager::get()->sendEvent(bwc->getPointer()); + + m_browserWindowContent = bwc->getBrowserWindowContent(); + CaretAssert(m_browserWindowContent); + if (BrainBrowserWindow::s_firstWindowFlag) { BrainBrowserWindow::s_firstWindowFlag = false; } - m_viewTileTabsSelected = false; m_aspectRatio = 1.0; @@ -147,8 +155,6 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, setAttribute(Qt::WA_DeleteOnClose); - m_browserWindowIndex = browserWindowIndex; - setWindowTitle(ApplicationInformation().getName() + " " + AString::number(m_browserWindowIndex + 1)); @@ -290,6 +296,10 @@ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, */ BrainBrowserWindow::~BrainBrowserWindow() { + std::unique_ptr bwc = EventBrowserWindowContent::deleteWindowContent(m_browserWindowIndex); + EventManager::get()->sendEvent(bwc->getPointer()); + m_browserWindowContent = NULL; + EventManager::get()->removeAllEventsFromListener(this); s_brainBrowserWindows.erase(this); @@ -613,7 +623,7 @@ BrainBrowserWindow::getGraphicsWidgetSize(int32_t& viewportXOut, bool BrainBrowserWindow::isTileTabsSelected() const { - return m_viewTileTabsSelected; + return m_browserWindowContent->isTileTabsEnabled(); } /** @@ -3552,7 +3562,7 @@ BrainBrowserWindow::processViewFullScreenSelected() void BrainBrowserWindow::processViewTileTabs() { - const bool toggledStatus = (! m_viewTileTabsSelected); + const bool toggledStatus = (! isTileTabsSelected()); setViewTileTabs(toggledStatus); } @@ -3563,7 +3573,7 @@ BrainBrowserWindow::processViewTileTabs() void BrainBrowserWindow::setViewTileTabs(const bool newStatus) { - m_viewTileTabsSelected = newStatus; + m_browserWindowContent->setTileTabsEnabled(newStatus); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } @@ -4124,11 +4134,14 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, { SceneClass* sceneClass = new SceneClass(instanceName, "BrainBrowserWindow", - 1); + 2); // Version 2: 07 feb 2018 m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); + m_browserWindowContent->saveToScene(sceneAttributes, + "m_browserWindowContent"); + /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); @@ -4138,7 +4151,7 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, /* * Save the selected tile tabs configuration as the scene configuration */ - if (m_viewTileTabsSelected) { + if (isTileTabsSelected()) { /* * Note: The number of rows and columns in the default tile tabs * configuration is updated each time the graphics region of the @@ -4223,8 +4236,6 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, isFullScreen()); sceneClass->addBoolean("isMaximized", isMaximized()); - sceneClass->addBoolean("m_viewTileTabsAction", - m_viewTileTabsSelected); /* * Graphics position and size, used with wb_command -show-scene @@ -4255,6 +4266,8 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, return; } + const int32_t sceneVersion = sceneClass->getVersionNumber(); + /* * Restore toolbar */ @@ -4267,6 +4280,18 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); + if (sceneVersion >= 2) { + m_browserWindowContent->restoreFromScene(sceneAttributes, + sceneClass->getClass("m_browserWindowContent")); + } + else { + /* + * Some members of this class were moved to BrowserWindowContent + */ + m_browserWindowContent->restoreFromOldBrainBrowserWindowScene(sceneAttributes, + sceneClass); + } + const bool aspectRatioLocked = sceneClass->getBooleanValue("m_windowAspectRatioLockedAction", false); m_windowAspectRatioLockedAction->blockSignals(true); diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 0553751e8..7a58b332a 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -42,6 +42,7 @@ namespace caret { class BrainBrowserWindowToolBar; class BrainBrowserWindowOrientedToolBox; class BrainOpenGLWidget; + class BrowserWindowContent; class BrowserTabContent; class PlainTextStringBuilder; class SceneClassAssistant; @@ -310,7 +311,9 @@ namespace caret { void showDataFileReadWarningsDialog(); /** Index of this window */ - int32_t m_browserWindowIndex; + const int32_t m_browserWindowIndex; + + BrowserWindowContent* m_browserWindowContent = NULL; BrainOpenGLWidget* m_openGLWidget; @@ -354,7 +357,6 @@ namespace caret { QAction* m_viewFullScreenAction; QAction* m_viewTileTabsAction; - bool m_viewTileTabsSelected; QMenu* m_tileTabsMenu; QAction* m_createAndEditTileTabsAction; diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index f55290fa7..3a2cbbc06 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -43,7 +43,7 @@ #include "ChartToolBoxViewController.h" #include "CiftiConnectivityMatrixViewController.h" #include "DeveloperFlagsEnum.h" -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FiberOrientationSelectionViewController.h" @@ -652,7 +652,7 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) bool enableVolumeSurfaceOutline = false; bool enableChartOne = false; bool enableChartTwo = false; - EventBrowserWindowContentGet browserContentEvent(m_browserWindowIndex); + EventBrowserWindowDrawingContent browserContentEvent(m_browserWindowIndex); EventManager::get()->sendEvent(browserContentEvent.getPointer()); BrowserTabContent* windowContent = browserContentEvent.getSelectedBrowserTabContent(); if (windowContent != NULL) { diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 35568773e..f7a74179d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -82,7 +82,7 @@ #include "EventBrowserTabGetAll.h" #include "EventBrowserTabGetAllViewed.h" #include "EventBrowserTabNew.h" -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowNew.h" #include "EventBrowserWindowTileTabOperation.h" @@ -463,7 +463,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow m_tileTabsHighlightingTimerEnabledFlag = true; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); @@ -3997,9 +3997,9 @@ BrainBrowserWindowToolBar::surfaceSelectionControlChanged( void BrainBrowserWindowToolBar::receiveEvent(Event* event) { - if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET) { - EventBrowserWindowContentGet* getModelEvent = - dynamic_cast(event); + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { + EventBrowserWindowDrawingContent* getModelEvent = + dynamic_cast(event); CaretAssert(getModelEvent); if (getModelEvent->getBrowserWindowIndex() == this->browserWindowIndex) { diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index e34ce031f..98a1fbbc5 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -51,7 +51,7 @@ #include "EventImageCapture.h" #include "EventModelGetAll.h" #include "EventManager.h" -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" @@ -506,7 +506,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); - EventBrowserWindowContentGet getModelEvent(this->windowIndex); + EventBrowserWindowDrawingContent getModelEvent(this->windowIndex); EventManager::get()->sendEvent(getModelEvent.getPointer()); if (getModelEvent.isError()) { @@ -1548,7 +1548,7 @@ BrainOpenGLWidget::receiveEvent(Event* event) /* * If a window is yoked, update its graphics. */ - EventBrowserWindowContentGet getModelEvent(this->windowIndex); + EventBrowserWindowDrawingContent getModelEvent(this->windowIndex); EventManager::get()->sendEvent(getModelEvent.getPointer()); if (getModelEvent.isError()) { diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 3e7c7772d..89340b71c 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -316,7 +316,7 @@ DisplayGroupEnumComboBox.h EnumComboBoxTemplate.h EventAnnotationCreateNewType.h EventAnnotationGetDrawnInWindow.h -EventBrowserWindowContentGet.h +EventBrowserWindowDrawingContent.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h @@ -539,7 +539,7 @@ DisplayGroupAndTabItemViewController.cxx DisplayGroupEnumComboBox.cxx EventAnnotationCreateNewType.cxx EventAnnotationGetDrawnInWindow.cxx -EventBrowserWindowContentGet.cxx +EventBrowserWindowDrawingContent.cxx EventBrowserWindowCreateTabs.cxx EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx diff --git a/src/GuiQt/EventBrowserWindowContentGet.cxx b/src/GuiQt/EventBrowserWindowDrawingContent.cxx similarity index 70% rename from src/GuiQt/EventBrowserWindowContentGet.cxx rename to src/GuiQt/EventBrowserWindowDrawingContent.cxx index 9f80f0e26..ee7a571f2 100644 --- a/src/GuiQt/EventBrowserWindowContentGet.cxx +++ b/src/GuiQt/EventBrowserWindowDrawingContent.cxx @@ -18,14 +18,14 @@ */ /*LICENSE_END*/ -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" using namespace caret; #include "CaretAssert.h" /** - * \class caret::DisplayGroupEnumComboBox - * \brief Combo box for selection of a display group. + * \class caret::EventBrowserWindowDrawingContent + * \brief Event to get content for drawing browser window. * \ingroup GuiQt */ @@ -34,8 +34,8 @@ using namespace caret; * @param browserWindowIndex * Index of browser window. */ -EventBrowserWindowContentGet::EventBrowserWindowContentGet(const int32_t browserWindowIndex) -: Event(EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT_GET) +EventBrowserWindowDrawingContent::EventBrowserWindowDrawingContent(const int32_t browserWindowIndex) +: Event(EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { m_browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; @@ -46,7 +46,7 @@ EventBrowserWindowContentGet::EventBrowserWindowContentGet(const int32_t browser /* * Destructor. */ -EventBrowserWindowContentGet::~EventBrowserWindowContentGet() +EventBrowserWindowDrawingContent::~EventBrowserWindowDrawingContent() { } @@ -55,7 +55,7 @@ EventBrowserWindowContentGet::~EventBrowserWindowContentGet() * @return Get the browser window index. */ int32_t -EventBrowserWindowContentGet::getBrowserWindowIndex() const +EventBrowserWindowDrawingContent::getBrowserWindowIndex() const { return m_browserWindowIndex; } @@ -64,7 +64,7 @@ EventBrowserWindowContentGet::getBrowserWindowIndex() const * @return The number of items to draw. */ int32_t -EventBrowserWindowContentGet::getNumberOfItemsToDraw() const +EventBrowserWindowDrawingContent::getNumberOfItemsToDraw() const { return this->browserTabContents.size(); } @@ -73,7 +73,7 @@ EventBrowserWindowContentGet::getNumberOfItemsToDraw() const * Add tab content for drawing in a window. */ void -EventBrowserWindowContentGet::addTabContentToDraw(BrowserTabContent* browserTabContent) +EventBrowserWindowDrawingContent::addTabContentToDraw(BrowserTabContent* browserTabContent) { this->browserTabContents.push_back(browserTabContent); } @@ -87,7 +87,7 @@ EventBrowserWindowContentGet::addTabContentToDraw(BrowserTabContent* browserTabC * Pointer to tab contents for the item index. */ BrowserTabContent* -EventBrowserWindowContentGet::getTabContentToDraw(const int32_t itemIndex) +EventBrowserWindowDrawingContent::getTabContentToDraw(const int32_t itemIndex) { CaretAssertVectorIndex(this->browserTabContents, itemIndex); return this->browserTabContents[itemIndex]; @@ -100,7 +100,7 @@ EventBrowserWindowContentGet::getTabContentToDraw(const int32_t itemIndex) * Index of tab for highlighting. */ void -EventBrowserWindowContentGet::setTabIndexForTileTabsHighlighting(const int32_t tabIndex) +EventBrowserWindowDrawingContent::setTabIndexForTileTabsHighlighting(const int32_t tabIndex) { m_tabIndexForTileTabsHighlighting = tabIndex; } @@ -109,7 +109,7 @@ EventBrowserWindowContentGet::setTabIndexForTileTabsHighlighting(const int32_t t * @return Index of tab for highlighting in Tile Tabs mode. */ int32_t -EventBrowserWindowContentGet::getTabIndexForTileTabsHighlighting() const +EventBrowserWindowDrawingContent::getTabIndexForTileTabsHighlighting() const { return m_tabIndexForTileTabsHighlighting; } @@ -119,7 +119,7 @@ EventBrowserWindowContentGet::getTabIndexForTileTabsHighlighting() const * May be NULL. */ TileTabsConfiguration* -EventBrowserWindowContentGet::getTileTabsConfiguration() const +EventBrowserWindowDrawingContent::getTileTabsConfiguration() const { return m_tileTabsConfiguration; } @@ -131,7 +131,7 @@ EventBrowserWindowContentGet::getTileTabsConfiguration() const * New selected tile tabs configuration. */ void -EventBrowserWindowContentGet::setTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration) +EventBrowserWindowDrawingContent::setTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration) { m_tileTabsConfiguration = tileTabsConfiguration; } @@ -140,7 +140,7 @@ EventBrowserWindowContentGet::setTileTabsConfiguration(TileTabsConfiguration* ti * @return The selected browser tab content. May be NULL. */ BrowserTabContent* -EventBrowserWindowContentGet::getSelectedBrowserTabContent() +EventBrowserWindowDrawingContent::getSelectedBrowserTabContent() { return m_selectedBrowserTabContent; } @@ -152,7 +152,7 @@ EventBrowserWindowContentGet::getSelectedBrowserTabContent() * The selected browser tab content. */ void -EventBrowserWindowContentGet::setSelectedBrowserTabContent(BrowserTabContent* browserTabContent) +EventBrowserWindowDrawingContent::setSelectedBrowserTabContent(BrowserTabContent* browserTabContent) { m_selectedBrowserTabContent = browserTabContent; } diff --git a/src/GuiQt/EventBrowserWindowContentGet.h b/src/GuiQt/EventBrowserWindowDrawingContent.h similarity index 81% rename from src/GuiQt/EventBrowserWindowContentGet.h rename to src/GuiQt/EventBrowserWindowDrawingContent.h index ee483c457..c3ce4f42b 100644 --- a/src/GuiQt/EventBrowserWindowContentGet.h +++ b/src/GuiQt/EventBrowserWindowDrawingContent.h @@ -1,5 +1,5 @@ -#ifndef __EVENT_BROWSER_WINDOW_CONTENT_GET_H__ -#define __EVENT_BROWSER_WINDOW_CONTENT_GET_H__ +#ifndef __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ +#define __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ /*LICENSE_START*/ /* @@ -31,12 +31,12 @@ namespace caret { class TileTabsConfiguration; /// Get the content of a browser window - class EventBrowserWindowContentGet : public Event { + class EventBrowserWindowDrawingContent : public Event { public: - EventBrowserWindowContentGet(const int32_t browserWindowIndex); + EventBrowserWindowDrawingContent(const int32_t browserWindowIndex); - virtual ~EventBrowserWindowContentGet(); + virtual ~EventBrowserWindowDrawingContent(); int32_t getBrowserWindowIndex() const; @@ -59,9 +59,9 @@ namespace caret { void setSelectedBrowserTabContent(BrowserTabContent* browserTabContent); private: - EventBrowserWindowContentGet(const EventBrowserWindowContentGet&); + EventBrowserWindowDrawingContent(const EventBrowserWindowDrawingContent&); - EventBrowserWindowContentGet& operator=(const EventBrowserWindowContentGet&); + EventBrowserWindowDrawingContent& operator=(const EventBrowserWindowDrawingContent&); BrowserTabContent* m_selectedBrowserTabContent; @@ -80,4 +80,4 @@ namespace caret { } // namespace -#endif // __EVENT_BROWSER_WINDOW_CONTENT_GET_H__ +#endif // __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ diff --git a/src/GuiQt/UserInputModeImage.cxx b/src/GuiQt/UserInputModeImage.cxx index 1af2a6a91..7b567a8ad 100644 --- a/src/GuiQt/UserInputModeImage.cxx +++ b/src/GuiQt/UserInputModeImage.cxx @@ -33,7 +33,7 @@ #include "ControlPoint3D.h" #include "ControlPointFile.h" #include "DisplayPropertiesImages.h" -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" @@ -297,7 +297,7 @@ UserInputModeImage::deleteAllControlPoints() ImageFile* UserInputModeImage::getImageFile() const { - EventBrowserWindowContentGet windowGet(m_windowIndex); + EventBrowserWindowDrawingContent windowGet(m_windowIndex); EventManager::get()->sendEvent(windowGet.getPointer()); DisplayPropertiesImages* dpi = GuiManager::get()->getBrain()->getDisplayPropertiesImages(); @@ -322,7 +322,7 @@ UserInputModeImage::getTabIndex() const { int32_t tabIndex = -1; - EventBrowserWindowContentGet windowGet(m_windowIndex); + EventBrowserWindowDrawingContent windowGet(m_windowIndex); EventManager::get()->sendEvent(windowGet.getPointer()); //DisplayPropertiesImages* dpi = GuiManager::get()->getBrain()->getDisplayPropertiesImages(); diff --git a/src/GuiQt/UserInputModeVolumeEdit.cxx b/src/GuiQt/UserInputModeVolumeEdit.cxx index 0401ba66d..25dd51f68 100644 --- a/src/GuiQt/UserInputModeVolumeEdit.cxx +++ b/src/GuiQt/UserInputModeVolumeEdit.cxx @@ -28,7 +28,7 @@ #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" -#include "EventBrowserWindowContentGet.h" +#include "EventBrowserWindowDrawingContent.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" @@ -328,7 +328,7 @@ UserInputModeVolumeEdit::getVolumeEditInfo(VolumeEditInfo& volumeEditInfo) volumeEditInfo.m_obliqueRotationMatrix.identity(); // volumeEditInfo.m_modelVolume = NULL; - EventBrowserWindowContentGet windowEvent(m_windowIndex); + EventBrowserWindowDrawingContent windowEvent(m_windowIndex); EventManager::get()->sendEvent(windowEvent.getPointer()); BrowserTabContent* tabContent = windowEvent.getSelectedBrowserTabContent(); diff --git a/src/Scenes/ScenePrimitiveArray.cxx b/src/Scenes/ScenePrimitiveArray.cxx index 907df290d..c8959fb0a 100644 --- a/src/Scenes/ScenePrimitiveArray.cxx +++ b/src/Scenes/ScenePrimitiveArray.cxx @@ -115,6 +115,23 @@ ScenePrimitiveArray::booleanValues(std::vector& valuesOut, } } +/** + * Load the vector with the boolean values from the scene. + * @param valuesOut + * Vector into which values are loaded. The size of the vector + * will be resized to the number of elements from the scene array. + */ +void +ScenePrimitiveArray::booleanVectorValues(std::vector& valuesOut) const +{ + const int32_t numElem = getNumberOfArrayElements(); + valuesOut.resize(numElem); + + for (int32_t i = 0; i < numElem; i++) { + valuesOut[i] = booleanValue(i); + } +} + /** * Load the array with float values. * @param valuesOut @@ -169,6 +186,24 @@ ScenePrimitiveArray::floatValues(std::vector& valuesOut, } } +/** + * Load the vector with the float values from the scene. + * @param valuesOut + * Vector into which values are loaded. The size of the vector + * will be resized to the number of elements from the scene array. + */ +void +ScenePrimitiveArray::floatVectorValues(std::vector& valuesOut) const +{ + const int32_t numElem = getNumberOfArrayElements(); + valuesOut.resize(numElem); + + for (int32_t i = 0; i < numElem; i++) { + valuesOut[i] = floatValue(i); + } +} + + /** * Load the array with integer values. * @param valuesOut @@ -223,6 +258,23 @@ ScenePrimitiveArray::integerValues(std::vector& valuesOut, } } +/** + * Load the vector with the integer values from the scene. + * @param valuesOut + * Vector into which values are loaded. The size of the vector + * will be resized to the number of elements from the scene array. + */ +void +ScenePrimitiveArray::integerVectorValues(std::vector& valuesOut) const +{ + const int32_t numElem = getNumberOfArrayElements(); + valuesOut.resize(numElem); + + for (int32_t i = 0; i < numElem; i++) { + valuesOut[i] = integerValue(i); + } +} + /** * Load the array with string values. * @param valuesOut @@ -277,6 +329,23 @@ ScenePrimitiveArray::stringValues(std::vector& valuesOut, } } +/** + * Load the vector with the string values from the scene. + * @param valuesOut + * Vector into which values are loaded. The size of the vector + * will be resized to the number of elements from the scene array. + */ +void +ScenePrimitiveArray::stringVectorValues(std::vector& valuesOut) const +{ + const int32_t numElem = getNumberOfArrayElements(); + valuesOut.resize(numElem); + + for (int32_t i = 0; i < numElem; i++) { + valuesOut[i] = stringValue(i); + } +} + /** * Load the array with unsigned byte values. * @param valuesOut @@ -331,6 +400,23 @@ ScenePrimitiveArray::unsignedByteValues(std::vector& valuesOut, } } +/** + * Load the vector with the unsigned byte values from the scene. + * @param valuesOut + * Vector into which values are loaded. The size of the vector + * will be resized to the number of elements from the scene array. + */ +void +ScenePrimitiveArray::unsignedByteVectorValues(std::vector& valuesOut) const +{ + const int32_t numElem = getNumberOfArrayElements(); + valuesOut.resize(numElem); + + for (int32_t i = 0; i < numElem; i++) { + valuesOut[i] = unsignedByteValue(i); + } +} + diff --git a/src/Scenes/ScenePrimitiveArray.h b/src/Scenes/ScenePrimitiveArray.h index 68df88838..2424815ef 100644 --- a/src/Scenes/ScenePrimitiveArray.h +++ b/src/Scenes/ScenePrimitiveArray.h @@ -91,6 +91,8 @@ namespace caret { virtual void booleanValues(std::vector& valuesOut, const bool defaultValue) const; + virtual void booleanVectorValues(std::vector& valuesOut) const; + virtual void floatValues(float valuesOut[], const int32_t arrayNumberOfElements, const float defaultValue) const; @@ -98,6 +100,8 @@ namespace caret { virtual void floatValues(std::vector& valuesOut, const float defaultValue) const; + virtual void floatVectorValues(std::vector& valuesOut) const; + virtual void integerValues(int32_t valuesOut[], const int32_t arrayNumberOfElements, const int32_t defaultValue) const; @@ -105,6 +109,8 @@ namespace caret { virtual void integerValues(std::vector& valuesOut, const int32_t defaultValue) const; + virtual void integerVectorValues(std::vector& valuesOut) const; + virtual void stringValues(AString valuesOut[], const int32_t arrayNumberOfElements, const AString& defaultValue) const; @@ -112,6 +118,8 @@ namespace caret { virtual void stringValues(std::vector& valuesOut, const AString& defaultValue) const; + virtual void stringVectorValues(std::vector& valuesOut) const; + virtual void unsignedByteValues(uint8_t valuesOut[], const int32_t arrayNumberOfElements, const uint8_t defaultValue) const; @@ -119,6 +127,8 @@ namespace caret { virtual void unsignedByteValues(std::vector& valuesOut, const uint8_t defaultValue) const; + virtual void unsignedByteVectorValues(std::vector& valuesOut) const; + private: -- GitLab From a64f50098f409c8b7cf689f12a5adc3708aa59e5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 8 Feb 2018 16:21:36 -0600 Subject: [PATCH 620/755] Continuing on on WB-767 Unifying aspect ratio locking. For each window there is one lock status for the window and one lock status for all tabs in the window. --- src/Brain/BrainOpenGLViewportContent.cxx | 78 ++- src/Brain/BrainOpenGLViewportContent.h | 6 +- src/GuiQt/BrainBrowserWindow.cxx | 517 +++++++----------- src/GuiQt/BrainBrowserWindow.h | 42 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 48 +- src/GuiQt/BrainBrowserWindowToolBar.h | 9 +- src/GuiQt/BrainBrowserWindowToolBarTab.cxx | 105 +--- src/GuiQt/BrainBrowserWindowToolBarTab.h | 17 +- src/GuiQt/BrainOpenGLWidget.cxx | 88 +-- src/GuiQt/BrainOpenGLWidget.h | 3 +- .../EventBrowserWindowDrawingContent.cxx | 37 +- src/GuiQt/EventBrowserWindowDrawingContent.h | 14 +- ...EventTabAndWindowLockAspectRatioStatus.cxx | 2 +- src/GuiQt/LockAspectWarningDialog.cxx | 14 +- src/GuiQt/LockAspectWarningDialog.h | 1 - src/Operations/OperationShowScene.cxx | 12 +- 16 files changed, 396 insertions(+), 597 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 3ae324660..69c0795e7 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -29,8 +29,11 @@ #include #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" +#include "EventBrowserWindowContent.h" +#include "EventManager.h" #include "GapsAndMargins.h" #include "MathFunctions.h" #include "ModelSurfaceMontage.h" @@ -481,10 +484,11 @@ BrainOpenGLViewportContent::toString() const * Viewport content for the single tab. */ BrainOpenGLViewportContent* -BrainOpenGLViewportContent::createViewportForSingleTab(BrowserTabContent* browserTabContent, - const GapsAndMargins* gapsAndMargins, - const int32_t windowIndex, - const int32_t windowViewport[4]) +BrainOpenGLViewportContent::createViewportForSingleTab(std::vector& allTabContents, + BrowserTabContent* selectedTabContent, + const GapsAndMargins* gapsAndMargins, + const int32_t windowIndex, + const int32_t windowViewport[4]) { int tabViewport[4] = { windowViewport[0], @@ -500,14 +504,40 @@ BrainOpenGLViewportContent::createViewportForSingleTab(BrowserTabContent* browse tabViewport[3] }; - if (browserTabContent != NULL) { - if (browserTabContent->isAspectRatioLocked()) { - const float aspectRatio = browserTabContent->getAspectRatio(); + std::unique_ptr eventContent = EventBrowserWindowContent::getWindowContent(windowIndex); + EventManager::get()->sendEvent(eventContent->getPointer()); + + const BrowserWindowContent* browserWindowContent = eventContent->getBrowserWindowContent(); + CaretAssert(browserWindowContent); + if (browserWindowContent->isAllTabsInWindowAspectRatioLocked()) { + /** + * Update aspect locking for any tabs that have not bee locked + * Locking is done here so that it will work for new tabs and + * for tabs from old scenes before "lock all". + * Aspect locking is also performed here so that it works + * with both GUI and Command Line Show Scene + */ + for (auto btc : allTabContents) { + if ( ! btc->isAspectRatioLocked()) { + if (tabViewport[2] > 0) { + const float aspectRatio = (static_cast(tabViewport[3]) + / static_cast(tabViewport[2])); + + btc->setAspectRatio(aspectRatio); + btc->setAspectRatioLocked(true); + } + } + } + } + + if (selectedTabContent != NULL) { + if (selectedTabContent->isAspectRatioLocked()) { + const float aspectRatio = selectedTabContent->getAspectRatio(); BrainOpenGLViewportContent::adjustViewportForAspectRatio(tabViewport, aspectRatio); } - const int32_t tabIndex = browserTabContent->getTabNumber(); + const int32_t tabIndex = selectedTabContent->getTabNumber(); createModelViewport(tabViewport, tabIndex, gapsAndMargins, @@ -521,7 +551,7 @@ BrainOpenGLViewportContent::createViewportForSingleTab(BrowserTabContent* browse modelViewport, windowIndex, false, - browserTabContent); + selectedTabContent); return vpContent; } @@ -596,6 +626,13 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector rowHeights(numRows, 0); std::vector columnWidths(numColumns, 0); + + std::unique_ptr eventContent = EventBrowserWindowContent::getWindowContent(windowIndex); + EventManager::get()->sendEvent(eventContent->getPointer()); + const BrowserWindowContent* browserWindowContent = eventContent->getBrowserWindowContent(); + CaretAssert(browserWindowContent); + const bool allTabsAspectLockedFlag = browserWindowContent->isAllTabsInWindowAspectRatioLocked(); + /* * Create the sizes for the tabs before and after application * of aspect ratio. @@ -610,6 +647,28 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorisAspectRatioLocked()) { + if (vpWidth > 0) { + const float aspectRatio = (static_cast(vpHeight) + / static_cast(vpWidth)); + + tabContents[iTab]->setAspectRatio(aspectRatio); + tabContents[iTab]->setAspectRatioLocked(true); + } + } + } + /* * Note: the constructor will adjust the width and * height if lock aspect ratio is enabled. @@ -868,7 +927,6 @@ BrainOpenGLViewportContent::getSurfaceMontageModelViewport(const int32_t montage } } - /* =================================================================================================== */ diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index c1e65e43c..65d6e4880 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -81,7 +81,8 @@ namespace caret { const int32_t windowViewport[4], const int32_t highlightTabIndex); - static BrainOpenGLViewportContent* createViewportForSingleTab(BrowserTabContent* browserTabContent, + static BrainOpenGLViewportContent* createViewportForSingleTab(std::vector& allTabContents, + BrowserTabContent* selectedTabContent, const GapsAndMargins* gapsAndMargins, const int32_t windowIndex, const int32_t windowViewport[4]); @@ -142,6 +143,9 @@ namespace caret { const GapsAndMargins* gapsAndMargins, int modelViewportOut[4]); + void updateTabLockedAspectRatios(const int32_t windowIndex, + const int32_t windowViewport[4]); + const int m_windowIndex; const bool m_highlightTab; diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 870fae61f..6e814f99e 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -142,8 +143,6 @@ m_browserWindowIndex(browserWindowIndex) BrainBrowserWindow::s_firstWindowFlag = false; } - m_aspectRatio = 1.0; - m_sceneTileTabsConfigurationText = "From Scene: "; m_sceneTileTabsConfiguration = new TileTabsConfiguration(); m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText); @@ -196,13 +195,11 @@ m_browserWindowIndex(browserWindowIndex) m_overlayActiveToolBox = m_overlayVerticalToolBox; addDockWidget(Qt::LeftDockWidgetArea, m_overlayVerticalToolBox); m_overlayHorizontalToolBox->setVisible(false); - //m_overlayHorizontalToolBox->toggleViewAction()->trigger(); } else { m_overlayActiveToolBox = m_overlayHorizontalToolBox; addDockWidget(Qt::BottomDockWidgetArea, m_overlayHorizontalToolBox); m_overlayVerticalToolBox->setVisible(false); - //m_overlayVerticalToolBox->toggleViewAction()->trigger(); } QObject::connect(m_overlayHorizontalToolBox, SIGNAL(visibilityChanged(bool)), @@ -230,8 +227,7 @@ m_browserWindowIndex(browserWindowIndex) browserTabContent, m_overlayToolBoxAction, m_featuresToolBoxAction, - m_windowAspectRatioLockedAction, - m_tabAspectRatioLockedAction, + m_toolBarLockWindowAndAllTabAspectRatioButton, this); m_showToolBarAction = m_toolbar->toolBarToolButtonAction; addToolBar(m_toolbar); @@ -252,8 +248,6 @@ m_browserWindowIndex(browserWindowIndex) } m_sceneAssistant = new SceneClassAssistant(); - m_sceneAssistant->add("m_aspectRatio", - &m_aspectRatio); m_defaultWindowComponentStatus.isFeaturesToolBoxDisplayed = m_featuresToolBoxAction->isChecked(); m_defaultWindowComponentStatus.isOverlayToolBoxDisplayed = m_overlayToolBoxAction->isChecked(); @@ -572,7 +566,7 @@ BrainBrowserWindow::getGraphicsWidgetSize(int32_t& viewportXOut, }; if (isTileTabsSelected()) { - if (isAspectRatioLocked()) { + if (isWindowAspectRatioLocked()) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, getAspectRatio()); } @@ -584,7 +578,7 @@ BrainBrowserWindow::getGraphicsWidgetSize(int32_t& viewportXOut, BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, btc->getAspectRatio()); } - else if (isAspectRatioLocked()) { + else if (isWindowAspectRatioLocked()) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, getAspectRatio()); } @@ -751,50 +745,50 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_featuresToolBoxAction->setIconText("LT"); } + + + m_windowMenuLockWindowAspectRatioAction = new QAction(this); + m_windowMenuLockWindowAspectRatioAction->setCheckable(true); + m_windowMenuLockWindowAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked()); + m_windowMenuLockWindowAspectRatioAction->setText("Lock Window Aspect Ratio"); + m_windowMenuLockWindowAspectRatioAction->setShortcut(Qt::SHIFT + Qt::CTRL+Qt::Key_K); + QObject::connect(m_windowMenuLockWindowAspectRatioAction, &QAction::triggered, + this, &BrainBrowserWindow::processWindowMenuLockWindowAspectRatioTriggered); + + m_windowMenuLockAllTabAspectRatioAction = new QAction(this); + m_windowMenuLockAllTabAspectRatioAction->setCheckable(true); + m_windowMenuLockAllTabAspectRatioAction->setChecked(false); + m_windowMenuLockAllTabAspectRatioAction->setText("Lock All Tab Aspect Ratios"); + m_windowMenuLockAllTabAspectRatioAction->setShortcut(Qt::CTRL+Qt::Key_K); + QObject::connect(m_windowMenuLockAllTabAspectRatioAction, &QAction::triggered, + this, &BrainBrowserWindow::processWindowMenuLockAllTabAspectRatioTriggered); + const QString aspectButtonToolTipText("" - "Right-Click (Command-Click on Mac) to display a dialog " - "for manual entry of the aspect ratio. The value displayed " + "Right-Click (Control-Click on Mac) to display a dialog " + "for manual entry of the aspect ratio for either the window " + "or the tab. The value displayed " "is the value from the last time aspect was locked. If a " "value is entered, the lock status is set to ON." ""); - m_windowAspectRatioLockedAction = new QAction(this); - m_windowAspectRatioLockedAction->setCheckable(true); - m_windowAspectRatioLockedAction->setChecked(false); - m_windowAspectRatioLockedAction->setText("Lock Window Aspect"); - m_windowAspectRatioLockedAction->setToolTip(aspectButtonToolTipText); - m_windowAspectRatioLockedAction->setShortcut(Qt::SHIFT + Qt::CTRL+Qt::Key_K); - QObject::connect(m_windowAspectRatioLockedAction, SIGNAL(toggled(bool)), - this, SLOT(processWindowAspectRatioLockedToggled(bool))); - - m_tabAspectRatioLockedAction = new QAction(this); - m_tabAspectRatioLockedAction->setCheckable(true); - m_tabAspectRatioLockedAction->setText("Lock Tab Aspect"); - m_tabAspectRatioLockedAction->setToolTip(aspectButtonToolTipText); - m_tabAspectRatioLockedAction->setShortcut(Qt::CTRL+Qt::Key_K); - QObject::connect(m_tabAspectRatioLockedAction, SIGNAL(toggled(bool)), - this, SLOT(processTabAspectRatioLockedToggled(bool))); - - m_lockAllTabsAspectRatioAction = new QAction(this); - m_lockAllTabsAspectRatioAction->setText("Lock Aspect Ratio for All Tabs"); - m_lockAllTabsAspectRatioAction->setToolTip("Lock aspect ratio of all tabs in this window"); - QObject::connect(m_lockAllTabsAspectRatioAction, SIGNAL(triggered(bool)), - this, SLOT(processLockAllTabsAspectRatioTriggered())); - - m_unlockAllTabsAspectRatioAction = new QAction(this); - m_unlockAllTabsAspectRatioAction->setText("Unlock Aspect Ratio for All Tabs"); - m_unlockAllTabsAspectRatioAction->setToolTip("Unlock aspect ratio of all tabs in this window"); - QObject::connect(m_unlockAllTabsAspectRatioAction, SIGNAL(triggered(bool)), - this, SLOT(processUnlockAllTabsAspectRatioTriggered())); - - const bool showEditAspectDialogFlag = false; - if (showEditAspectDialogFlag) { - m_editTabAndWindowAspectRatiosAction = new QAction(this); - m_editTabAndWindowAspectRatiosAction->setText("Edit Locked Aspect Ratios..."); - m_editTabAndWindowAspectRatiosAction->setToolTip("Edit the aspect ratio for locked window and locked tabs"); - QObject::connect(m_editTabAndWindowAspectRatiosAction, &QAction::triggered, - this, &BrainBrowserWindow::processEditTabAndWindowAspectRatiosTriggered); - } + m_toolBarLockWindowAndAllTabAspectRatioAction = new QAction(); + m_toolBarLockWindowAndAllTabAspectRatioAction->setCheckable(true); + m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(false); + m_toolBarLockWindowAndAllTabAspectRatioAction->setText("Lock Window Aspect"); + m_toolBarLockWindowAndAllTabAspectRatioAction->setToolTip(aspectButtonToolTipText); + QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioAction, &QAction::triggered, + this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered); + + /* + * Button for locking aspect is passed to ToolBar's constructor + * and is displayed on the toolbar + */ + m_toolBarLockWindowAndAllTabAspectRatioButton = new QToolButton(); + m_toolBarLockWindowAndAllTabAspectRatioButton->setDefaultAction(m_toolBarLockWindowAndAllTabAspectRatioAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(m_toolBarLockWindowAndAllTabAspectRatioButton); + QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioButton, &QToolButton::customContextMenuRequested, + this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu); + m_toolBarLockWindowAndAllTabAspectRatioButton->setContextMenuPolicy(Qt::CustomContextMenu); } /** @@ -808,9 +802,8 @@ BrainBrowserWindow::createActionsUsedByToolBar() bool BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog(QWidget* parent) { - LockAspectWarningDialog::Result result = - LockAspectWarningDialog::runDialog(m_browserWindowIndex, - parent); + LockAspectWarningDialog::Result result = LockAspectWarningDialog::runDialog(m_browserWindowIndex, + parent); bool okFlag = true; @@ -818,12 +811,8 @@ BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog(QWidget* parent) case LockAspectWarningDialog::Result::CANCEL: okFlag = false; break; - case LockAspectWarningDialog::Result::LOCK_WINDOW_ASPECT: - processWindowAspectRatioLockedToggled(true); - break; case LockAspectWarningDialog::Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS: - processWindowAspectRatioLockedToggled(true); - processLockAllTabsAspectRatioTriggered(); + processToolBarLockWindowAndAllTabAspectTriggered(true); break; case LockAspectWarningDialog::Result::NO_CHANGES: break; @@ -833,261 +822,193 @@ BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog(QWidget* parent) } /** - * Called when Lock Aspect Ratio for All Tabs is selected. + * Called when the window menu's lock window aspect is triggered by user. + * + * @param checked + * True if checked, false if unchecked */ void -BrainBrowserWindow::processLockAllTabsAspectRatioTriggered() +BrainBrowserWindow::processWindowMenuLockWindowAspectRatioTriggered(bool checked) { - - std::vector vpContent = m_openGLWidget->getViewportContent(); - - if (isTileTabsSelected()) { - /* - * When tile tabs is on, set the aspect ratio for each tab that does not - * already have its aspect ratio locked - */ - for (std::vector::iterator vpIter = vpContent.begin(); - vpIter != vpContent.end(); - vpIter++) { - const BrainOpenGLViewportContent* vp = *vpIter; - CaretAssert(vp); - - BrowserTabContent* tabContent = vp->getBrowserTabContent(); - if (tabContent != NULL) { - if ( ! tabContent->isAspectRatioLocked()) { - int32_t tabViewport[4]; - vp->getTabViewportBeforeApplyingMargins(tabViewport); - - const float width = tabViewport[2]; - if (width > 0.0) { - const float aspectRatio = tabViewport[3] / width; - - tabContent->setAspectRatioLocked(true); - tabContent->setAspectRatio(aspectRatio); - } - } - } - } - } - else { - /* - * Set the aspect ratio for each tab that does not already have its - * aspect ratio locked. Since only one tab is displayed, use the - * size of the graphics region for the aspect ratio. - */ - - if ( ! vpContent.empty()) { - CaretAssertVectorIndex(vpContent, 0); - const BrainOpenGLViewportContent* vp = vpContent[0]; - - int32_t tabViewport[4]; - vp->getTabViewportBeforeApplyingMargins(tabViewport); - - const float width = tabViewport[2]; - if (width > 0.0) { - const float aspectRatio = tabViewport[3] / width; - - std::vector allTabContent; - getAllTabContent(allTabContent); - - for (std::vector::iterator iter = allTabContent.begin(); - iter != allTabContent.end(); - iter++) { - BrowserTabContent* tabContent = *iter; - CaretAssert(tabContent); - if ( ! tabContent->isAspectRatioLocked()) { - tabContent->setAspectRatioLocked(true); - tabContent->setAspectRatio(aspectRatio); - } - } - } - } - } + lockWindowAspectRatio(checked); + updateActionsForLockingAspectRatios(); +} - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); - m_toolbar->updateToolBar(); +/** + * Called when the window menu's lock all tab aspect is triggered by user + * + * @param checked + * True if checked, false if unchecked + */ +void +BrainBrowserWindow::processWindowMenuLockAllTabAspectRatioTriggered(bool checked) +{ + lockAllTabAspectRatios(checked); + updateActionsForLockingAspectRatios(); } /** - * Called when Unlock Aspect Ratio for All Tabs is selected. + * Lock the window's aspect ratio and if it transitions from + * unlocked to locked, set the aspect ratio. */ void -BrainBrowserWindow::processUnlockAllTabsAspectRatioTriggered() +BrainBrowserWindow::lockWindowAspectRatio(const bool checked) { - std::vector allTabContent; - getAllTabContent(allTabContent); + const bool oldCheckedStatus = m_browserWindowContent->isWindowAspectLocked(); + m_browserWindowContent->setWindowAspectLocked(checked); - for (std::vector::iterator iter = allTabContent.begin(); - iter != allTabContent.end(); - iter++) { - BrowserTabContent* tabContent = *iter; - CaretAssert(tabContent); - tabContent->setAspectRatioLocked(false); + if (checked) { + if ( ! oldCheckedStatus) { + m_browserWindowContent->setWindowAspectLockedRatio(getOpenGLWidgetAspectRatio()); + } } - - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); - m_toolbar->updateToolBar(); } /** - * Called when the Edit Tab and Window Lock Aspect Ratios is called. + * Lock the window's aspect ratio and if it transitions from + * unlocked to locked, set the aspect ratio. */ void -BrainBrowserWindow::processEditTabAndWindowAspectRatiosTriggered() +BrainBrowserWindow::lockAllTabAspectRatios(const bool checked) { - CaretAssertMessage(0, "Source for dialog is in \"saved_source\" directory"); + m_browserWindowContent->setAllTabsInWindowAspectRatioLocked(checked); + + if (checked) { + /* + * Locking takes place in BrainOpenGLViewportContent + * when the tab is drawn as the size of the viewport + * is needed. + */ + } + else { + /* + * Turn off lock aspect for all tabs + */ + std::vector allTabContent; + m_toolbar->getAllTabContent(allTabContent); + + for (auto tab : allTabContent) { + tab->setAspectRatioLocked(false); + } + } } /** - * Called when the Tab aspect ratio action it toggled. + * Called when the toolbar's lock window and all tab aspect is triggered * - * @param new tab locked status + * @param checked + * True if checked, false if unchecked */ void -BrainBrowserWindow::processTabAspectRatioLockedToggled(bool checked) +BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered(bool checked) { - BrowserTabContent* selectedTab = m_toolbar->getTabContentFromSelectedTab(); - if (selectedTab != NULL) { - std::vector vpContent = m_openGLWidget->getViewportContent(); - for (std::vector::iterator vpIter = vpContent.begin(); - vpIter != vpContent.end(); - vpIter++) { - const BrainOpenGLViewportContent* vp = *vpIter; - CaretAssert(vp); - - BrowserTabContent* tabContent = vp->getBrowserTabContent(); - if (selectedTab == tabContent) { - int32_t tabViewport[4]; - vp->getTabViewportBeforeApplyingMargins(tabViewport); - - float aspectRatio = tabContent->getAspectRatio(); - - if (checked) { - const float width = tabViewport[2]; - if (width > 0.0) { - aspectRatio = tabViewport[3] / width; - } - } - - setLockTabAspectStatusAndRatio(checked, aspectRatio); - } - } - } - - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + lockWindowAspectRatio(checked); + lockAllTabAspectRatios(checked); + updateActionsForLockingAspectRatios(); } /** - * Set the tab aspect ratio lock status and the ratio. Note the ratio - * is only set if the lock status is true. + * Called when an item is selected from the lock aspect action menu * - * @param lockStatus - * New status for lock window aspect. - * @param aspectRatio - * New value for aspect ratio. + * @param pos + * Location of click. */ void -BrainBrowserWindow::setLockTabAspectStatusAndRatio(const bool lockStatus, - const float aspectRatio) +BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu(const QPoint& pos) { - BrowserTabContent* selectedTab = m_toolbar->getTabContentFromSelectedTab(); - if (selectedTab != NULL) { - std::vector vpContent = m_openGLWidget->getViewportContent(); - for (auto vp : vpContent) { - CaretAssert(vp); - - BrowserTabContent* tabContent = vp->getBrowserTabContent(); - if (selectedTab == tabContent) { - tabContent->setAspectRatioLocked(lockStatus); - if (lockStatus) { - if (aspectRatio > 0.0) { - tabContent->setAspectRatio(aspectRatio); - } - else { - CaretLogSevere("Invalid tab aspect ratio " + AString::number(aspectRatio)); - } - } + BrowserTabContent* tabContent = getBrowserTabContent(); + if (tabContent != NULL) { + QMenu menu; + QAction* tabAspectAction = menu.addAction("Set Selected Tab Aspect Ratio..."); + QAction* windowAspectAction = menu.addAction("Set Window Aspect Ratio..."); + + QAction* selectedAction = menu.exec(m_toolBarLockWindowAndAllTabAspectRatioButton->parentWidget()->mapToGlobal(pos)); + + if (selectedAction == windowAspectAction) { + float aspectRatio = getAspectRatioFromDialog(("Set Window " + + AString::number(m_browserWindowIndex + 1) + + " Aspect Ratio..."), + getAspectRatio(), + this); + if (aspectRatio > 0.0f) { + m_browserWindowContent->setWindowAspectLockedRatio(aspectRatio); } } + else if (selectedAction == tabAspectAction) { + float aspectRatio = getAspectRatioFromDialog(("Set Tab " + + tabContent->getName() + + " Aspect Ratio..."), + tabContent->getAspectRatio(), + this); + if (aspectRatio > 0.0f) { + tabContent->setAspectRatio(aspectRatio); + } + } + + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } - - m_tabAspectRatioLockedAction->blockSignals(true); - m_tabAspectRatioLockedAction->setChecked(lockStatus); - m_tabAspectRatioLockedAction->blockSignals(false); - - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } - /** - * Set the window aspect ratio lock status and the ratio. Note the ratio - * is only set if the lock status is true. + * Get the new aspect ratio using a dialog. * - * @param lockStatus - * New status for lock window aspect. + * @param title + * Title for dialog. * @param aspectRatio - * New value for aspect ratio. + * Default value for aspect ratio + * @param parent + * Parent for the dialog. */ -void -BrainBrowserWindow::setLockWindowAspectStatusAndRatio(const bool lockStatus, - const float aspectRatio) +float +BrainBrowserWindow::getAspectRatioFromDialog(const QString& title, + const float aspectRatio, + QWidget* parent) const { - setAspectRatioLocked(lockStatus); - if (lockStatus) { - if (aspectRatio > 0) { - setAspectRatio(aspectRatio); - } - else { - CaretLogSevere("Invalid window aspect ratio " + AString::number(aspectRatio)); - } + float aspectRatioOut = -1.0; + + WuQDataEntryDialog ded("Aspect Ratio", + parent); + QDoubleSpinBox* ratioSpinBox = ded.addDoubleSpinBox(title, + aspectRatio); + ratioSpinBox->setSingleStep(0.01); + ratioSpinBox->setRange(ratioSpinBox->singleStep(), 100.0); + ratioSpinBox->setDecimals(3); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + aspectRatioOut = ratioSpinBox->value(); } - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + return aspectRatioOut; } + /** - * Called when the Window aspect ratio action it toggled. - * - * @param new tab locked status + * Update the actions for window menu's lock window aspect, window menu's lock + * all tab aspect, and the toolbar's lock window and all tab aspect. */ void -BrainBrowserWindow::processWindowAspectRatioLockedToggled(bool checked) +BrainBrowserWindow::updateActionsForLockingAspectRatios() { - setLockWindowAspectStatusAndRatio(checked, getOpenGLWidgetAspectRatio()); - -// setAspectRatioLocked(checked); -// if (checked) { -// const float aspectRatio = getOpenGLWidgetAspectRatio(); -// if (aspectRatio > 0) { -// setAspectRatio(aspectRatio); -// } -// } -// -// EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + QSignalBlocker windowAspectBlocker(m_windowMenuLockWindowAspectRatioAction); + m_windowMenuLockWindowAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked()); + + QSignalBlocker tabAspectBlocker(m_windowMenuLockAllTabAspectRatioAction); + m_windowMenuLockAllTabAspectRatioAction->setChecked(m_browserWindowContent->isAllTabsInWindowAspectRatioLocked()); + + QSignalBlocker toolbarLockAllBlocker(m_toolBarLockWindowAndAllTabAspectRatioAction); + m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked() + && m_browserWindowContent->isAllTabsInWindowAspectRatioLocked()); + + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * @return Is the aspect ratio locked? */ bool -BrainBrowserWindow::isAspectRatioLocked() const +BrainBrowserWindow::isWindowAspectRatioLocked() const { - return m_windowAspectRatioLockedAction->isChecked(); -} - -/** - * Set the aspect ratio locked status. - * - * @param locked - * New status. - */ -void -BrainBrowserWindow::setAspectRatioLocked(const bool locked) -{ - m_windowAspectRatioLockedAction->blockSignals(true); - m_windowAspectRatioLockedAction->setChecked(locked); - m_windowAspectRatioLockedAction->blockSignals(false); + return m_browserWindowContent->isWindowAspectLocked(); } /** @@ -1096,19 +1017,7 @@ BrainBrowserWindow::setAspectRatioLocked(const bool locked) float BrainBrowserWindow::getAspectRatio() const { - return m_aspectRatio; -} - -/** - * Set the aspect ratio. - * - * @param aspectRatio - * New value for aspect ratio. - */ -void -BrainBrowserWindow::setAspectRatio(const float aspectRatio) -{ - m_aspectRatio = aspectRatio; + return m_browserWindowContent->getWindowAspectLockedRatio(); } /** @@ -1583,7 +1492,6 @@ BrainBrowserWindow::createMenuFile() QObject::connect(m_recentSceneFileMenu, SIGNAL(triggered(QAction*)), this, SLOT(processRecentSceneFileMenuSelection(QAction*))); - //menu->addAction(m_openFileViaSpecFileAction); menu->addAction(m_manageFilesAction); menu->addAction(m_closeSpecFileAction); menu->addSeparator(); @@ -2014,8 +1922,6 @@ BrainBrowserWindow::loadRecentSpecFileMenu(QMenu* recentSpecFileMenu) void BrainBrowserWindow::processRecentSpecFileMenuSelection(QAction* itemAction) { - //AString errorMessages; - const AString specFileName = itemAction->data().toString(); if (specFileName == "CLEAR_CLEAR") { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); @@ -2047,7 +1953,6 @@ BrainBrowserWindow::processRecentSpecFileMenuSelection(QAction* itemAction) } } catch (const DataFileException& e) { - //errorMessages += e.whatString(); QMessageBox::critical(this, "ERROR", e.whatString()); @@ -2140,8 +2045,6 @@ BrainBrowserWindow::loadRecentSceneFileMenu(QMenu* recentSceneFileMenu) void BrainBrowserWindow::processRecentSceneFileMenuSelection(QAction* itemAction) { - //AString errorMessages; - const AString sceneFileName = itemAction->data().toString(); if (sceneFileName == "CLEAR_CLEAR") { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); @@ -2298,7 +2201,6 @@ BrainBrowserWindow::processTileTabsMenuAboutToBeDisplayed() QAction* sceneAction = m_tileTabsMenu->addAction(m_sceneTileTabsConfiguration->getName()); sceneAction->setCheckable(true); sceneAction->setData(QVariant(m_sceneTileTabsConfiguration->getUniqueIdentifier())); - //sceneAction->setEnabled(false); bool haveSelectedTileTabsConfiguration = false; @@ -2590,8 +2492,6 @@ BrainBrowserWindow::processSurfaceMenuInformation() QMenu* BrainBrowserWindow::createMenuVolume() { -// QMenu* menu = new QMenu("Volume", this); -// return menu; return NULL; } @@ -2609,15 +2509,9 @@ BrainBrowserWindow::createMenuWindow() this, SLOT(processMoveSelectedTabToWindowMenuSelection(QAction*))); QMenu* menu = new QMenu("Window", this); - - menu->addAction(m_windowAspectRatioLockedAction); - menu->addAction(m_tabAspectRatioLockedAction); - menu->addAction(m_lockAllTabsAspectRatioAction); - menu->addAction(m_unlockAllTabsAspectRatioAction); - const bool showEditAspectRatiosFlag = false; - if (showEditAspectRatiosFlag) { - menu->addAction(m_editTabAndWindowAspectRatiosAction); - } + + menu->addAction(m_windowMenuLockWindowAspectRatioAction); + menu->addAction(m_windowMenuLockAllTabAspectRatioAction); menu->addSeparator(); menu->addAction(m_nextTabAction); @@ -2830,7 +2724,6 @@ BrainBrowserWindow::processSplitBorderFiles() void BrainBrowserWindow::processCaptureImage() { - //std::cout << "Toolbar height " << m_toolbar->height() << std::endl; GuiManager::get()->processShowImageCaptureDialog(this); } @@ -3100,7 +2993,7 @@ BrainBrowserWindow::loadSceneFromCommandLine(const AString& sceneFileName, bool isValidNumber = false; int sceneNumber = sceneNameOrNumber.toInt(&isValidNumber); if (isValidNumber) { - sceneNumber--; // convert to index (numbers start at one) + sceneNumber--; /* convert to index (numbers start at one) */ if ((sceneNumber >= 0) && (sceneNumber < sf->getNumberOfScenes())) { scene = sf->getSceneAtIndex(sceneNumber); @@ -3294,7 +3187,7 @@ BrainBrowserWindow::loadFiles(QWidget* parentForDialogs, switch (loadSpecFileMode) { case LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE: { - timer.reset(); // resets timer + timer.reset(); /* resets timer */ specFileTimeStart = timer.getElapsedTimeSeconds(); /* @@ -4134,7 +4027,7 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, { SceneClass* sceneClass = new SceneClass(instanceName, "BrainBrowserWindow", - 2); // Version 2: 07 feb 2018 + 2); /* Version 2: 07 feb 2018 */ m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); @@ -4145,8 +4038,6 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); - sceneClass->addBoolean("m_windowAspectRatioLockedAction", - m_windowAspectRatioLockedAction->isChecked()); /* * Save the selected tile tabs configuration as the scene configuration @@ -4163,9 +4054,6 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, writeConfig.setName(QUuid::createUuid().toString()); sceneClass->addString("m_sceneTileTabsConfiguration", writeConfig.encodeInXML()); - -// sceneClass->addString("m_sceneTileTabsConfiguration", -// tileTabs->encodeInXML()); } } @@ -4292,12 +4180,6 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, sceneClass); } - const bool aspectRatioLocked = sceneClass->getBooleanValue("m_windowAspectRatioLockedAction", - false); - m_windowAspectRatioLockedAction->blockSignals(true); - m_windowAspectRatioLockedAction->setChecked(aspectRatioLocked); - m_windowAspectRatioLockedAction->blockSignals(false); - /* * Restore Unique ID of selected tile tabs configuration. * If not valid, use default configuration @@ -4504,21 +4386,28 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, if (openglGeomClass != NULL) { openglGeomClass->setDescendantsRestored(true); } -} + + if (sceneVersion >= 2) { + + } + else { + /* + * Before version 2, each tab was allowed its own aspect locking status + */ + std::vector allTabContent; + m_toolbar->getAllTabContent(allTabContent); + + const int32_t lockedCount = std::count_if(allTabContent.begin(), + allTabContent.end(), + [](BrowserTabContent* btc) { return btc->isAspectRatioLocked(); }); -///** -// * Get the viewport size for the window. -// * -// * @param w -// * Output width. -// * @param h -// * Output height. -// */ -//void -//BrainBrowserWindow::getViewportSize(int &w, int &h) -//{ -// m_openGLWidget->getViewPortSize(w,h); -//} + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + + lockAllTabAspectRatios(lockedCount > 0); + } + + updateActionsForLockingAspectRatios(); +} /** * @return A string describing the object's content. diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 7a58b332a..3b5f1c43e 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -37,6 +37,7 @@ class QAction; class QActionGroup; class QDockWidget; class QMenu; +class QToolButton; namespace caret { class BrainBrowserWindowToolBar; @@ -140,20 +141,10 @@ namespace caret { bool changeInputModeToAnnotationsWarningDialog(QWidget* parent); - bool isAspectRatioLocked() const; - - void setAspectRatioLocked(const bool locked); + bool isWindowAspectRatioLocked() const; float getAspectRatio() const; - void setAspectRatio(const float aspectRatio); - - void setLockTabAspectStatusAndRatio(const bool lockStatus, - const float aspectRatio); - - void setLockWindowAspectStatusAndRatio(const bool lockStatus, - const float aspectRatio); - bool hasValidOpenGL(); bool isOpenGLContextSharingValid() const; @@ -235,12 +226,12 @@ namespace caret { void processProjectFoci(); void processSplitBorderFiles(); - void processTabAspectRatioLockedToggled(bool checked); - void processWindowAspectRatioLockedToggled(bool checked); - void processLockAllTabsAspectRatioTriggered(); - void processUnlockAllTabsAspectRatioTriggered(); - void processEditTabAndWindowAspectRatiosTriggered(); + void processWindowMenuLockWindowAspectRatioTriggered(bool checked); + void processWindowMenuLockAllTabAspectRatioTriggered(bool checked); + void processToolBarLockWindowAndAllTabAspectTriggered(bool checked); + void processToolBarLockWindowAndAllTabAspectMenu(const QPoint& pos); + void processEditMenuItemTriggered(QAction* action); void processEditMenuAboutToShow(); @@ -310,6 +301,14 @@ namespace caret { void showDataFileReadWarningsDialog(); + void lockWindowAspectRatio(const bool checked); + void lockAllTabAspectRatios(const bool checked); + void updateActionsForLockingAspectRatios(); + + float getAspectRatioFromDialog(const QString& title, + const float aspectRatio, + QWidget* parent) const; + /** Index of this window */ const int32_t m_browserWindowIndex; @@ -392,11 +391,10 @@ namespace caret { QAction* m_overlayToolBoxAction; - QAction* m_lockAllTabsAspectRatioAction; - QAction* m_unlockAllTabsAspectRatioAction; - QAction* m_tabAspectRatioLockedAction; - QAction* m_windowAspectRatioLockedAction; - QAction* m_editTabAndWindowAspectRatiosAction; + QAction* m_windowMenuLockWindowAspectRatioAction; + QAction* m_windowMenuLockAllTabAspectRatioAction; + QAction* m_toolBarLockWindowAndAllTabAspectRatioAction; + QToolButton* m_toolBarLockWindowAndAllTabAspectRatioButton; QAction* m_featuresToolBoxAction; @@ -432,8 +430,6 @@ namespace caret { WindowComponentStatus m_defaultWindowComponentStatus; WindowComponentStatus m_normalWindowComponentStatus; - float m_aspectRatio; - static bool s_firstWindowFlag; friend class BrainBrowserWindowToolBar; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f7a74179d..0395a030e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -141,10 +141,8 @@ using namespace caret; * Action to show overlay tool box. * @param layersToolBoxAction * Action to show layers tool box. - * @param windowAspectRatioLockedAction - * Action to lock window's aspect ratio. - * @param tabAspectRatioLockedAction - * Action to lock tab's aspect ratio. + * @param toolBarLockWindowAndAllTabAspectRatioButton + * Button to lock window's aspect ratio and aspect ratio of all tabs. * @param parent * Parent for this toolbar. */ @@ -152,17 +150,13 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow BrowserTabContent* initialBrowserTabContent, QAction* overlayToolBoxAction, QAction* layersToolBoxAction, - QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction, + QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindow* parentBrainBrowserWindow) : QToolBar(parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; - m_windowAspectRatioLockedAction = windowAspectRatioLockedAction; - m_tabAspectRatioLockedAction = tabAspectRatioLockedAction; - this->isContructorFinished = false; this->isDestructionInProgress = false; @@ -362,8 +356,7 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); this->volumeIndicesWidget = this->createVolumeIndicesWidget(); this->modeWidget = this->createModeWidget(); - this->windowWidget = this->createTabOptionsWidget(m_windowAspectRatioLockedAction, - m_tabAspectRatioLockedAction); + this->windowWidget = this->createTabOptionsWidget(toolBarLockWindowAndAllTabAspectRatioButton); this->singleSurfaceSelectionWidget = this->createSingleSurfaceOptionsWidget(); this->surfaceMontageSelectionWidget = this->createSurfaceMontageOptionsWidget(); m_clippingOptionsWidget = createClippingOptionsWidget(); @@ -2879,20 +2872,16 @@ BrainBrowserWindowToolBar::updateDisplayedModeUserInputWidget() /** * Create the tab options widget. * - * @param windowAspectRatioLockedAction - * Action for locking the window's aspect ratio. - * @param tabAspectRatioLockedAction - * Action for locking the tab's aspect ratio. + * @param lockWindowAndAllTabAspectAction + * Action for locking the window's aspect ratio and the aspect ratio of all tabs * - * @return The tab options widget. + * @return Button to lock window and tab's aspect ratios. */ QWidget* -BrainBrowserWindowToolBar::createTabOptionsWidget(QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction) +BrainBrowserWindowToolBar::createTabOptionsWidget(QToolButton* toolBarLockWindowAndAllTabAspectRatioButton) { m_tabOptionsComponent = new BrainBrowserWindowToolBarTab(this->browserWindowIndex, - windowAspectRatioLockedAction, - tabAspectRatioLockedAction, + toolBarLockWindowAndAllTabAspectRatioButton, this); QWidget* w = this->createToolWidget("Tab", @@ -4004,14 +3993,17 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) if (getModelEvent->getBrowserWindowIndex() == this->browserWindowIndex) { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); + if (browserWindow != NULL) { + const int32_t numTabs = this->tabBar->count(); + for (int32_t i = 0; i < numTabs; i++) { + BrowserTabContent* btc = this->getTabContentFromTab(i); + getModelEvent->addBrowserTab(btc); + } + + getModelEvent->setTileTabsSelected(browserWindow->isTileTabsSelected()); + if (browserWindow->isTileTabsSelected()) { - const int32_t numTabs = this->tabBar->count(); - for (int32_t i = 0; i < numTabs; i++) { - BrowserTabContent* btc = this->getTabContentFromTab(i); - getModelEvent->addTabContentToDraw(btc); - } - /* * Tab that is highlighted so user knows which tab * any changes in toolbar/toolboxes apply to. @@ -4020,10 +4012,6 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) getModelEvent->setTileTabsConfiguration(browserWindow->getSelectedTileTabsConfiguration()); } - else { - BrowserTabContent* btc = this->getTabContentFromSelectedTab(); - getModelEvent->addTabContentToDraw(btc); - } getModelEvent->setSelectedBrowserTabContent(this->getTabContentFromSelectedTab()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 7b5882538..3c4e6c0bd 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -85,8 +85,7 @@ namespace caret { BrowserTabContent* initialBrowserTabContent, QAction* overlayToolBoxAction, QAction* layersToolBoxAction, - QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction, + QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindow* parentBrainBrowserWindow); ~BrainBrowserWindowToolBar(); @@ -145,8 +144,7 @@ namespace caret { QWidget* createWholeBrainSurfaceOptionsWidget(); QWidget* createVolumeIndicesWidget(); QWidget* createModeWidget(); - QWidget* createTabOptionsWidget(QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction); + QWidget* createTabOptionsWidget(QToolButton* toolBarLockWindowAndAllTabAspectRatioButton); QWidget* createChartAxesWidget(); QWidget* createChartAttributesWidget(); QWidget* createChartTwoOrientationWidget(); @@ -229,9 +227,6 @@ namespace caret { /** Is set to the user input widget provided by the user input processor */ QWidget* userInputControlsWidgetActiveInputWidget; - QAction* m_windowAspectRatioLockedAction; - QAction* m_tabAspectRatioLockedAction; - void removeAndReturnAllTabs(std::vector& allTabContent); void getAllTabContent(std::vector& allTabContent) const; diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx index def4b5912..f197f6707 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.cxx @@ -55,21 +55,18 @@ using namespace caret; * * @param browserWindowIndex * Index of browser window. - * @param windowAspectRatioLockedAction - * Action for locking window aspect ratio. - * @param tabAspectRatioLockedAction - * Action for locking tab aspect ratio. + * @param toolBarLockWindowAndAllTabAspectRatioButton + * Button for locking window and all tab aspect ratio. * @param parentToolBar * Parent toolbar. */ BrainBrowserWindowToolBarTab::BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, - QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction, + QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar), m_browserWindowIndex(browserWindowIndex), m_parentToolBar(parentToolBar), -m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) +m_lockWindowAndAllTabAspectButton(toolBarLockWindowAndAllTabAspectRatioButton) { m_yokingGroupComboBox = new EnumComboBoxTemplate(this); m_yokingGroupComboBox->setup(); @@ -83,27 +80,12 @@ m_tabAspectRatioLockedAction(tabAspectRatioLockedAction) QObject::connect(m_yokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokeToGroupComboBoxIndexChanged())); - m_windowAspectRatioLockedToolButton = new QToolButton(); - m_windowAspectRatioLockedToolButton->setDefaultAction(windowAspectRatioLockedAction); - WuQtUtilities::setToolButtonStyleForQt5Mac(m_windowAspectRatioLockedToolButton); - QObject::connect(m_windowAspectRatioLockedToolButton, &QToolButton::customContextMenuRequested, - this, &BrainBrowserWindowToolBarTab::windowAspectCustomContextMenuRequested); - m_windowAspectRatioLockedToolButton->setContextMenuPolicy(Qt::CustomContextMenu); - - m_tabAspectRatioLockedToolButton = new QToolButton(); - m_tabAspectRatioLockedToolButton->setDefaultAction(tabAspectRatioLockedAction); - WuQtUtilities::setToolButtonStyleForQt5Mac(m_tabAspectRatioLockedToolButton); - QObject::connect(m_tabAspectRatioLockedToolButton, &QToolButton::customContextMenuRequested, - this, &BrainBrowserWindowToolBarTab::tabAspectCustomContextMenuRequested); - m_tabAspectRatioLockedToolButton->setContextMenuPolicy(Qt::CustomContextMenu); - QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); layout->addWidget(m_yokeToLabel); layout->addWidget(m_yokingGroupComboBox->getWidget()); layout->addSpacing(15); - layout->addWidget(m_windowAspectRatioLockedToolButton); - layout->addWidget(m_tabAspectRatioLockedToolButton); + layout->addWidget(m_lockWindowAndAllTabAspectButton); addToWidgetGroup(m_yokeToLabel); addToWidgetGroup(m_yokingGroupComboBox->getWidget()); @@ -116,80 +98,6 @@ BrainBrowserWindowToolBarTab::~BrainBrowserWindowToolBarTab() { } -/** - * Called when context menu requested for window lock aspect button. - * - * @param pos - * Postion of mouse in parent widget. - */ -void -BrainBrowserWindowToolBarTab::tabAspectCustomContextMenuRequested(const QPoint& /*pos*/) -{ - BrowserTabContent* tabContent = m_parentToolBar->getTabContentFromSelectedTab(); - if (tabContent != NULL) { - BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); - CaretAssert(window); - - float aspectRatio = getAspectRatioFromDialog("Set Tab Aspect Ratio", - tabContent->getAspectRatio(), - m_tabAspectRatioLockedToolButton); - if (aspectRatio > 0.0) { - window->setLockTabAspectStatusAndRatio(true, aspectRatio); - } - } -} - -/** - * Called when context menu requested for window lock aspect button. - * - * @param pos - * Postion of mouse in parent widget. - */ -void -BrainBrowserWindowToolBarTab::windowAspectCustomContextMenuRequested(const QPoint& /*pos*/) -{ - BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); - CaretAssert(window); - - float aspectRatio = getAspectRatioFromDialog("Set Window Aspect Ratio", - window->getAspectRatio(), - m_windowAspectRatioLockedToolButton); - if (aspectRatio > 0.0) { - window->setLockWindowAspectStatusAndRatio(true, aspectRatio); - } -} - -/** - * Get the new aspect ratio using a dialog. - * - * @param title - * Title for dialog. - * @param aspectRatio - * Default value for aspect ratio - * @param parent - * Parent for the dialog. - */ -float -BrainBrowserWindowToolBarTab::getAspectRatioFromDialog(const QString& title, - const float aspectRatio, - QWidget* parent) const -{ - float aspectRatioOut = -1.0; - - WuQDataEntryDialog ded(title, - parent); - QDoubleSpinBox* ratioSpinBox = ded.addDoubleSpinBox("Aspect Ratio", aspectRatio); - ratioSpinBox->setSingleStep(0.01); - ratioSpinBox->setRange(ratioSpinBox->singleStep(), 100.0); - ratioSpinBox->setDecimals(3); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - aspectRatioOut = ratioSpinBox->value(); - } - - return aspectRatioOut; -} - - /** * Update the surface montage options widget. * @@ -229,9 +137,6 @@ BrainBrowserWindowToolBarTab::updateContent(BrowserTabContent* browserTabContent m_yokeToLabel->setText("Yoking:"); m_yokingGroupComboBox->setSelectedItem(browserTabContent->getBrainModelYokingGroup()); } - m_tabAspectRatioLockedAction->blockSignals(true); - m_tabAspectRatioLockedAction->setChecked(browserTabContent->isAspectRatioLocked()); - m_tabAspectRatioLockedAction->blockSignals(false); blockAllSignals(false); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarTab.h b/src/GuiQt/BrainBrowserWindowToolBarTab.h index 6e1dcee65..18d8a3906 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTab.h +++ b/src/GuiQt/BrainBrowserWindowToolBarTab.h @@ -37,8 +37,7 @@ namespace caret { public: BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, - QAction* windowAspectRatioLockedAction, - QAction* tabAspectRatioLockedAction, + QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindowToolBar* parentToolBar); virtual ~BrainBrowserWindowToolBarTab(); @@ -51,19 +50,11 @@ namespace caret { private slots: void yokeToGroupComboBoxIndexChanged(); - void tabAspectCustomContextMenuRequested(const QPoint& pos); - - void windowAspectCustomContextMenuRequested(const QPoint& pos); - private: BrainBrowserWindowToolBarTab(const BrainBrowserWindowToolBarTab&); BrainBrowserWindowToolBarTab& operator=(const BrainBrowserWindowToolBarTab&); - float getAspectRatioFromDialog(const QString& title, - const float aspectRatio, - QWidget* parent) const; - QLabel* m_yokeToLabel; EnumComboBoxTemplate* m_yokingGroupComboBox; @@ -72,11 +63,7 @@ namespace caret { BrainBrowserWindowToolBar* m_parentToolBar; - QAction* m_tabAspectRatioLockedAction; - - QToolButton* m_tabAspectRatioLockedToolButton; - - QToolButton* m_windowAspectRatioLockedToolButton; + QToolButton* m_lockWindowAndAllTabAspectButton; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 98a1fbbc5..1d506768f 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -203,7 +203,7 @@ BrainOpenGLWidget::~BrainOpenGLWidget() delete this->userInputFociModeProcessor; delete this->userInputImageModeProcessor; delete this->userInputVolumeEditModeProcessor; - this->selectedUserInputProcessor = NULL; // DO NOT DELETE since it does not own the object to which it points + this->selectedUserInputProcessor = NULL; /* DO NOT DELETE since it does not own the object to which it points */ delete this->borderBeingDrawn; @@ -309,21 +309,13 @@ BrainOpenGLWidget::getOpenGLInformation() } info += ("QOpenGLWidget Context:" -// "\n Accum: " + AString::fromBool(format.accum()) -// + "\n Accum size: " + AString::number(format.accumBufferSize()) "\n Alpha: " + AString::fromBool(format.hasAlpha()) + "\n Alpha size: " + AString::number(format.alphaBufferSize()) -// + "\n Depth: " + AString::fromBool(format.depth()) + "\n Depth size: " + AString::number(format.depthBufferSize()) -// + "\n Direct Rendering: " + AString::fromBool(format.directRendering()) + "\n Red size: " + AString::number(format.redBufferSize()) + "\n Green size: " + AString::number(format.greenBufferSize()) + "\n Blue size: " + AString::number(format.blueBufferSize()) -// + "\n Double Buffer: " + AString::fromBool(format.doubleBuffer()) -// + "\n RGBA: " + AString::fromBool(format.rgba()) -// + "\n Samples: " + AString::fromBool(format.sampleBuffers()) + "\n Samples size: " + AString::number(format.samples()) -// + "\n Stencil: " + AString::fromBool(format.stencil()) + "\n Stencil size: " + AString::number(format.stencilBufferSize()) + "\n " + swapInfo + "\n Swap Interval: " + AString::number(format.swapInterval()) @@ -381,25 +373,6 @@ BrainOpenGLWidget::getOpenGLInformation() + AString::number(numDisplayLists) + " display lists are allocated in first OpenGL context."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS - -// Disable check of vertex buffers until OpenGL -// version is fixed on windows (finds 1.1) -//#ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS -// int32_t numVertexBuffers = 0; -//#ifdef GL_VERSION_2_0 -// /* -// * Note: glIsBuffer() was added to OpenGL 2.0 -// */ -// for (GLuint iBuff = 1; iBuff < 1000; iBuff++) { -// if (glIsBuffer(iBuff)) { -// numVertexBuffers++; -// } -// } -//#endif // GL_VERSION_2_0 -// info += ("\nAt least " -// + AString::number(numVertexBuffers) -// + " vertex buffers are allocated"); -//#endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS info += "\n"; return info; @@ -520,7 +493,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], windowViewportIn[3] }; - if (bbw->isAspectRatioLocked()) { + if (bbw->isWindowAspectRatioLocked()) { const float aspectRatio = bbw->getAspectRatio(); if (aspectRatio > 0.0) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(windowViewport, @@ -538,15 +511,13 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); - const int32_t numToDraw = getModelEvent.getNumberOfItemsToDraw(); - if (numToDraw == 1) { - BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(getModelEvent.getTabContentToDraw(0), - gapsAndMargins, - this->windowIndex, - windowViewport); - windowContent.addTabViewport(vc); + const int32_t numberOfTabs = getModelEvent.getNumberOfBrowserTabs(); + std::vector allTabs; + for (int32_t i = 0; i < numberOfTabs; i++) { + allTabs.push_back(getModelEvent.getBrowserTab(i)); } - else if (numToDraw > 1) { + + if (getModelEvent.isTileTabsSelected()) { const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; @@ -563,18 +534,14 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], * Get the sizes of the tab tiles from the tile tabs configuration */ if (tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numToDraw, - rowHeights, - columnsWidths)) { - + windowHeight, + numberOfTabs, + rowHeights, + columnsWidths)) { + /* * Create the viewport drawing contents for all tabs */ - std::vector allTabs; - for (int32_t i = 0; i < getModelEvent.getNumberOfItemsToDraw(); i++) { - allTabs.push_back(getModelEvent.getTabContentToDraw(i)); - } std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, tileTabsConfiguration, @@ -590,8 +557,18 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); } } + else { + BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, + getModelEvent.getSelectedBrowserTabContent(), + gapsAndMargins, + this->windowIndex, + windowViewport); + windowContent.addTabViewport(vc); + } - BrainOpenGLViewportContent* windowViewportContent = BrainOpenGLViewportContent::createViewportForSingleTab(NULL, + std::vector emptyTabVector; + BrainOpenGLViewportContent* windowViewportContent = BrainOpenGLViewportContent::createViewportForSingleTab(emptyTabVector, + NULL, gapsAndMargins, windowIndex, windowViewport); @@ -914,7 +891,7 @@ BrainOpenGLWidget::mousePressEvent(QMouseEvent* me) this->selectedUserInputProcessor->mouseLeftPress(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { - // not implemented this->selectedUserInputProcessor->mouseLeftPressWithShift(mouseEvent); + /* not implemented this->selectedUserInputProcessor->mouseLeftPressWithShift(mouseEvent); */ } } } @@ -1246,9 +1223,7 @@ BrainOpenGLWidget::performIdentificationAnnotations(const int x, this->repaint(); this->doneCurrent(); #else - //updateCursor(); this->repaint(); - //updateGL(); #endif return annotationID; @@ -1679,7 +1654,7 @@ BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) captureHeight, widgetWidth, widgetHeight, - true); // true => apply lock aspect ratio + true); /* true => apply lock aspect ratio */ outputImageWidth = captureWidth; outputImageHeight = captureHeight; } @@ -1787,25 +1762,16 @@ BrainOpenGLWidget::initializeDefaultGLFormat() { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QSurfaceFormat glfmt; - //glfmt.setAccum(false); - //glfmt.setAlpha(true); glfmt.setAlphaBufferSize(8); glfmt.setBlueBufferSize(8); - //glfmt.setDepth(true); glfmt.setDepthBufferSize(24); - //glfmt.setDirectRendering(true); - //glfmt.setDoubleBuffer(true); glfmt.setGreenBufferSize(8); - //glfmt.setOverlay(false); glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); glfmt.setRedBufferSize(8); glfmt.setRenderableType(QSurfaceFormat::OpenGL); - //glfmt.setSampleBuffers(true); - glfmt.setSamples(6); //2); - //glfmt.setStencil(false); + glfmt.setSamples(6); glfmt.setStereo(false); glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - //glfmt.setRgba(true); glfmt.setMajorVersion(2); glfmt.setMinorVersion(1); diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 39698cf52..ef7f45817 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -166,7 +166,6 @@ namespace caret { const int32_t windowIndex; - //std::vector tabsViewportContent; BrainOpenGLWindowContent m_windowContent; int32_t windowWidth[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; @@ -218,7 +217,7 @@ namespace caret { }; #ifdef __BRAIN_OPENGL_WIDGET_DEFINE__ - const int32_t BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE = 0; //10; + const int32_t BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE = 0; bool BrainOpenGLWidget::s_defaultGLFormatInitialized = false; std::set BrainOpenGLWidget::s_brainOpenGLWidgets; BrainOpenGL* BrainOpenGLWidget::s_singletonOpenGL = NULL; diff --git a/src/GuiQt/EventBrowserWindowDrawingContent.cxx b/src/GuiQt/EventBrowserWindowDrawingContent.cxx index ee7a571f2..21fdad077 100644 --- a/src/GuiQt/EventBrowserWindowDrawingContent.cxx +++ b/src/GuiQt/EventBrowserWindowDrawingContent.cxx @@ -41,6 +41,7 @@ EventBrowserWindowDrawingContent::EventBrowserWindowDrawingContent(const int32_t m_tabIndexForTileTabsHighlighting = -1; m_tileTabsConfiguration = NULL; m_selectedBrowserTabContent = NULL; + m_tileTabsSelectedFlag = false; } /* @@ -61,33 +62,33 @@ EventBrowserWindowDrawingContent::getBrowserWindowIndex() const } /** - * @return The number of items to draw. + * @return The number of browser tabs in window */ int32_t -EventBrowserWindowDrawingContent::getNumberOfItemsToDraw() const +EventBrowserWindowDrawingContent::getNumberOfBrowserTabs() const { return this->browserTabContents.size(); } /** - * Add tab content for drawing in a window. + * Add browser tab */ void -EventBrowserWindowDrawingContent::addTabContentToDraw(BrowserTabContent* browserTabContent) +EventBrowserWindowDrawingContent::addBrowserTab(BrowserTabContent* browserTabContent) { this->browserTabContents.push_back(browserTabContent); } /** - * Get the tab content for drawing in a window. + * Get the browser tab at the given index * * @param itemIndex - * Index of the item to draw. + * Index of the item to browser tab. * @return * Pointer to tab contents for the item index. */ BrowserTabContent* -EventBrowserWindowDrawingContent::getTabContentToDraw(const int32_t itemIndex) +EventBrowserWindowDrawingContent::getBrowserTab(const int32_t itemIndex) { CaretAssertVectorIndex(this->browserTabContents, itemIndex); return this->browserTabContents[itemIndex]; @@ -138,6 +139,7 @@ EventBrowserWindowDrawingContent::setTileTabsConfiguration(TileTabsConfiguration /** * @return The selected browser tab content. May be NULL. + * In single tab mode, this is the tab to draw. */ BrowserTabContent* EventBrowserWindowDrawingContent::getSelectedBrowserTabContent() @@ -157,5 +159,26 @@ EventBrowserWindowDrawingContent::setSelectedBrowserTabContent(BrowserTabContent m_selectedBrowserTabContent = browserTabContent; } +/** + * @return Is tile tabs selected. + */ +bool +EventBrowserWindowDrawingContent::isTileTabsSelected() const +{ + return m_tileTabsSelectedFlag; +} + +/** + * Set tile tabs selected. + * + * @param tileTabsSelected + * New status of tile tabs. + */ +void +EventBrowserWindowDrawingContent::setTileTabsSelected(const bool tileTabsSelected) +{ + m_tileTabsSelectedFlag = tileTabsSelected; +} + diff --git a/src/GuiQt/EventBrowserWindowDrawingContent.h b/src/GuiQt/EventBrowserWindowDrawingContent.h index c3ce4f42b..03c34ab69 100644 --- a/src/GuiQt/EventBrowserWindowDrawingContent.h +++ b/src/GuiQt/EventBrowserWindowDrawingContent.h @@ -40,11 +40,11 @@ namespace caret { int32_t getBrowserWindowIndex() const; - int32_t getNumberOfItemsToDraw() const; + int32_t getNumberOfBrowserTabs() const; - void addTabContentToDraw(BrowserTabContent* browserTabContent); + void addBrowserTab(BrowserTabContent* browserTabContent); - BrowserTabContent* getTabContentToDraw(const int32_t itemIndex); + BrowserTabContent* getBrowserTab(const int32_t itemIndex); void setTabIndexForTileTabsHighlighting(const int32_t tabIndex); @@ -58,6 +58,10 @@ namespace caret { void setSelectedBrowserTabContent(BrowserTabContent* browserTabContent); + bool isTileTabsSelected() const; + + void setTileTabsSelected(const bool tileTabsSelected); + private: EventBrowserWindowDrawingContent(const EventBrowserWindowDrawingContent&); @@ -68,7 +72,7 @@ namespace caret { /** index of browswer window */ int32_t m_browserWindowIndex; - /** Tab content that are to be drawn in the window */ + /** all browser tabs in the window */ std::vector browserTabContents; /** Index of tab that is highlighted in Tile Tabs mode */ @@ -76,6 +80,8 @@ namespace caret { /** Selected tile tabs configuration when more than one item to draw */ TileTabsConfiguration* m_tileTabsConfiguration; + + bool m_tileTabsSelectedFlag; }; } // namespace diff --git a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx index c9e8566d7..e240b5771 100644 --- a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx +++ b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx @@ -132,7 +132,7 @@ EventTabAndWindowLockAspectRatioStatus::setup(const std::vectorgetBrowserWindowIndex(); - const bool windowAspectLocked = bbw->isAspectRatioLocked(); + const bool windowAspectLocked = bbw->isWindowAspectRatioLocked(); const bool tileTabsEnabled = bbw->isTileTabsSelected(); CaretAssertVectorIndex(windowAnnotationFlag, windowIndex); WindowStatus* windowStatus = getWindowStatus(windowIndex); diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index c33f0dc59..1481b061d 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -170,10 +170,6 @@ m_tabCount(tabCount) QObject::connect(lockWindowAndTabButton, &QPushButton::clicked, [=] { this->buttonClicked(Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS); }); - QPushButton* lockWindowButton = new QPushButton("OK - Lock Window Aspect"); - QObject::connect(lockWindowButton, &QPushButton::clicked, - [=] { this->buttonClicked(Result::LOCK_WINDOW_ASPECT); }); - QPushButton* noChangesButton = new QPushButton("OK - No Lock Aspect Changes"); QObject::connect(noChangesButton, &QPushButton::clicked, [=] { this->buttonClicked(Result::NO_CHANGES); }); @@ -192,14 +188,12 @@ m_tabCount(tabCount) QBoxLayout* dialogLayout = new QHBoxLayout(this); WuQtUtilities::matchWidgetWidths(lockWindowAndTabButton, - lockWindowButton, noChangesButton, cancelButton); QBoxLayout* buttonLayout = new QVBoxLayout(); buttonLayout->addWidget(buttonsLabel); buttonLayout->addWidget(lockWindowAndTabButton); - buttonLayout->addWidget(lockWindowButton); buttonLayout->addWidget(noChangesButton); buttonLayout->addWidget(cancelButton); buttonLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); @@ -212,9 +206,7 @@ m_tabCount(tabCount) /* * Highlighted button */ - QPushButton* defaultPushButton = (tileTabsEnabled - ? lockWindowAndTabButton - : lockWindowButton); + QPushButton* defaultPushButton = lockWindowAndTabButton; defaultPushButton->setAutoDefault(true); defaultPushButton->setDefault(true); } @@ -279,10 +271,6 @@ LockAspectWarningDialog::buttonClicked(const Result buttonClicked) m_result = Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS; accept(); break; - case Result::LOCK_WINDOW_ASPECT: - m_result = Result::LOCK_WINDOW_ASPECT; - accept(); - break; case Result::NO_CHANGES: m_result = Result::NO_CHANGES; accept(); diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h index 0f0f4ed61..e02b6760e 100644 --- a/src/GuiQt/LockAspectWarningDialog.h +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -39,7 +39,6 @@ namespace caret { public: enum class Result { LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS, - LOCK_WINDOW_ASPECT, NO_CHANGES, CANCEL }; diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 289703756..503c3cf1c 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -375,12 +375,6 @@ OperationShowScene::useParameters(OperationParameters* myParams, int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; -// float aspectRatio = -1.0; -// const bool windowAspectRatioLocked = browserClass->getBooleanValue("m_aspectRatioLockedStatus"); -// if (windowAspectRatioLocked) { -// aspectRatio = browserClass->getFloatValue("m_aspectRatio", -1.0); -// } - const int windowWidth = windowViewport[2]; const int windowHeight = windowViewport[3]; @@ -536,7 +530,10 @@ OperationShowScene::useParameters(OperationParameters* myParams, } CaretPointer content(NULL); - content.grabNew(BrainOpenGLViewportContent::createViewportForSingleTab(tabContent, + std::vector allTabs; + allTabs.push_back(tabContent); + content.grabNew(BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, + tabContent, gapsAndMargins, windowIndex, windowViewport)); @@ -799,7 +796,6 @@ OperationShowScene::writeImage(const AString& imageFileName, } try { - //ImageFile imageFile(image); ImageFile imageFile(imageContent, imageWidth, imageHeight, -- GitLab From f2a688efb838c2ce9ea85110274aa1572fc6377f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 9 Feb 2018 15:27:26 -0600 Subject: [PATCH 621/755] Added BestPractices Dialog and made updates to LockAspectWarningDialog. --- src/GuiQt/BestPracticesDialog.cxx | 378 ++++++++++++++++++++++++++ src/GuiQt/BestPracticesDialog.h | 78 ++++++ src/GuiQt/BrainBrowserWindow.cxx | 19 +- src/GuiQt/BrainBrowserWindow.h | 3 + src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/LockAspectWarningDialog.cxx | 184 ++++++------- src/GuiQt/LockAspectWarningDialog.h | 26 +- 7 files changed, 562 insertions(+), 129 deletions(-) create mode 100644 src/GuiQt/BestPracticesDialog.cxx create mode 100644 src/GuiQt/BestPracticesDialog.h diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx new file mode 100644 index 000000000..56d2fe55a --- /dev/null +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -0,0 +1,378 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __BEST_PRACTICES_DIALOG_DECLARE__ +#include "BestPracticesDialog.h" +#undef __BEST_PRACTICES_DIALOG_DECLARE__ + +#include +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::BestPracticesDialog + * \brief Dialog that displays "Best Practices" information. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param infoMode + * Information Mode of dialog + * @param textMode + * Text mode + * @param parent + * Parent widget. + */ +BestPracticesDialog::BestPracticesDialog(const InfoMode infoMode, + QWidget* parent) +: WuQDialogNonModal("Best Practices", + parent), +m_infoMode(infoMode), +m_textMode(TextMode::FULL) +{ + setApplyButtonText(""); + setDeleteWhenClosed(true); + + QLabel* label = new QLabel(getTextForInfoMode(infoMode, + m_textMode)); + label->setWordWrap(true); + + QWidget* widget = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addWidget(label); + widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + setCentralWidget(widget, WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); +} + +/** + * Destructor. + */ +BestPracticesDialog::~BestPracticesDialog() +{ +} + +/** + * Get the text for the given information mode and text mode. + * + * @param infoMode + * Information Mode of dialog + * @param textMode + * Text mode + */ +AString +BestPracticesDialog::getTextForInfoMode(const InfoMode infoMode, + const TextMode textMode) +{ + AString text; + + switch (infoMode) { + case InfoMode::LOCK_ASPECT_BEST_PRACTICES: + text = getLockAspectText(textMode); + break; + } + return text; +} + +AString +BestPracticesDialog::getLockAspectText(const TextMode textMode) +{ + AString introText; + { + switch (textMode) { + case BRIEF: + introText = ("Aspect is unlocked and it is strongly recommended that aspect is locked and is never unlocked " + "when annotations are present. Failing to lock aspect or unlocking the aspect may " + "cause annotations to move from their original locations." + "

    " + "When creating annotations and scenes, follow these best practices:"); + break; + case FULL: + introText = ("Describing annotations and scenes is best done using an analogy with Microsoft PowerPoint. " + "PowerPoint allows one to create a presentation consisting of slides saved into a PowerPoint file. " + "These slides are annotated with text and various shapes. In wb_view, a scene is analogous " + "to a PowerPoint slide and a Scene File contains multiple scenes just like a PowerPoint " + "file contains multiple slides. In wb_view, one annotates a scene just like one " + "annotates a slide in PowerPoint. A wb_view Scene saves ‘the state’ so that when " + "the scene is loaded at a later time, by either the creator of the scene or another " + "user, the user-interface and brain models replicate ‘the state’ at the time the " + "scene was created." + "

    " + "When creating scenes and annotations, following a set of “best practices†ensures " + "that one efficiently creates scenes that are properly displayed at a later time " + "and when shared with other users."); + break; + } + } + + std::vector bulletLines; + + { + AString text("If desired, enter Tile Tabs for a multi-tab Scene (View Menu->Enter Tile Tabs). "); + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("Tile Tabs displays all of the windows tabs in a grid pattern. " + "The number of row and columns in the Tile Tabs view is edited on the " + "Tile Tabs Configuration Dialog (View Menu->Tile Tabs Configuration->Create and Edit. " + "Advanced parameters are available for “stretch factors†that allow one to increase the " + "size of a row or column relative to other rows and columns. One may also save the " + "configuration for future use. If a scene is created, the configuration is added to the scene " + "so that the configuration is available when the scene is displayed."); + break; + } + + + bulletLines.push_back(text); + } + + { + AString text("Adjust size of window. "); + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("It is important to adust the size of the window prior to entering Annotations Mode " + "(further down in this list)."); + break; + } + bulletLines.push_back(text); + } + + { + AString text; + switch (textMode) { + case BRIEF: + text = ("Setup view of the model(s) (pan/rotate/zoom). "); + break; + case FULL: + text = ("Setup view(s) of the model(s). " + "Pan (drag mouse with SHIFT key down), " + "Rotate (drag mouse), " + "Zoom (drag mouse with Control Key. Use the Command Key on Mac."); + break; + } + bulletLines.push_back(text); + } + + { + AString text("Lock Aspect Ratio (click Lock Aspect button in right side of Toolbar). "); + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("As a general rule, one should never disable aspect locking once the " + "aspect has been locked. By following this rule, tab and window annotations " + "will remain in the desired location. When a window is resized, the window may " + "change in size that is a different proportion (ratio of height to width) " + "compared to the model that is viewed. Annotations in tab and window spaces " + "are positioned using percentage coordinates that range from 0% to 100% with " + "0% at the left (x) and bottom (y) and 100% at the right (x) and top (y). " + "When the window size changes, annotations in tab/window space may no longer " + "appear in the correct location (such as over an anatomical feature). Locking " + "the tab or window’s aspect ratio adds padding to the left and right or bottom " + "and top of the graphics region so that the model’s region maintains the same " + "aspect ratio (ratio of height to width). Locking the aspect ratio ensures that " + "annotations remain in the correct location relative to the viewed brain model. "); + break; + } + bulletLines.push_back(text); + } + + { + AString text("Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes) and set " + "the name and path of the new Scene File. "); + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("To set the name of the New Scene File, click the Save As button. " + "In the file selection dialog, choose the directory, and enter a descriptive " + "name for the Scene File. It is best for the Scene File to be in the same " + "directory or the parent directory of the directory containing your data files. " + "If the data files are scattered about many directories, it may cause problems " + "if the Scene File and its data files are zipped for distribution to others " + "or when uploading the BALSA Database"); + break; + } + bulletLines.push_back(text); + } + + { + AString text("Enter Annotations Mode (click Annotate button in Toolbar). "); + switch (textMode) { + case BRIEF: + break; + case FULL: + break; + } + bulletLines.push_back(text); + } + + { + AString text; + switch (textMode) { + case BRIEF: + text = ("Add Annotations."); + break; + case FULL: + text = ("To add annotations, click the Space and/or Type icons in the Insert New section " + "of the Annotation Toolbar and then click in graphics region to create the annotation. " + "A new annotation is automatically selected so that it can be moved/resized with " + "the mouse or its attributes changed using controls in the toolbar."); + break; + } + bulletLines.push_back(text); + } + + { + AString text("Add a Scene (click Add button on Scene Dialog). "); + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("In the Create New Scene Dialog, edit the name and description and then " + "press the OK button. If a Scene File was created as described in a " + "previous step, click the Save button at the top of the Scene Dialog to " + "save the Scene File. Note that by default new annotations are added to " + "the current scene. If one wants to place annotations into a disk file, " + "click the small arrow to the right of the Scene button in the Insert New " + "section of the Toolbar. When the arrow is clicked, a menu is displayed " + "for creating and/or selecting a disk annotation file."); + break; + } + bulletLines.push_back(text); + } + + { + AString text("Repeat last few steps to edit annotations and create additional scenes."); + switch (textMode) { + case BRIEF: + break; + case FULL: + break; + } + bulletLines.push_back(text); + } + + { + AString text; + switch (textMode) { + case BRIEF: + text = ("Save the Scene File (click Save button (or Save As if Save is disabled) at top of Scene Dialog)."); + break; + case FULL: + text = ("If the Save button at the top of the Scene Dialog is enabled, the Scene File is in a " + "modified state. Click the Save button to save the Scene File and avoid losing your work."); + break; + } + bulletLines.push_back(text); + } + + + AString msg; + msg.reserve(32000); + + msg.appendWithNewLine("" + + introText + + "

    "); + + AString text; + switch (textMode) { + case BRIEF: + { + msg.appendWithNewLine("

      "); + for (const auto& line : bulletLines) { + msg.appendWithNewLine("
    1. "); + msg.append(line); + } + msg.appendWithNewLine("
    "); + } + break; + case FULL: + { + int32_t counter = 1; + for (const auto& line : bulletLines) { + msg.appendWithNewLine("

    "); + msg.append(AString::number(counter) + ". "); + msg.append(line); + ++counter; + } + } + break; + } + + { + switch (textMode) { + case BRIEF: + break; + case FULL: + text.append("

    " + "Understanding the Tab and Window Coordinate Spaces. " + "

    " + "In PowerPoint, each slide maintains a fixed aspect ratio (the ratio of " + "height to width remains constant) with a spatial coordinate system " + "(typically inches). As a result, each annotation in PowerPoint is places " + "its annotions at a spatial coordinate (X and Y in inches). " + "In contrast, wb_view defaults to a " + "variable aspect ratio so that the window is resizable to best fit the brain " + "model (surface, volume, chart). This variable aspect ratio is problematic " + "for annotations in Tab or Window Space both of which use a percentage " + "coordinate system (0% at left/bottom and 100% at right/top). " + "

    " + "If one creates a Tab Space annotation with the variable aspect enabled and " + "changes the size of the window, the Tab Space annotation may no longer be in " + "the correct location. To correct this problem, wb_view supports “locking " + "of the aspect ratioâ€. When the aspect ratio is locked, the window (and " + "each tab within the window) are fixed to the aspect ratio at the time " + "aspect locking is enabled just like PowerPoint. If the size of the window changes while " + "the aspect is locked, the contents of window and each tab will expand or " + "contract in size but maintain a fixed aspect by adding space to sides " + "of the model when needed."); + text.append("

    " + "Scenes" + "

    " + "Scenes are closely related to annotations. Scenes allow one to preserve " + "'the state’ of wb_view. Thus one if one saves a scene, exits wb_view, later restarts " + "wb_view, and loads the scene, wb_view appears identical to when the scene was " + "originally saved. Scenes are frequently used for figures in publications. " + "Scenes are also uploaded to the BALSA database for sharing with other users." + "

    " + "While annotations can be saved in disk files, annotations are most commonly saved " + "to a scene. When creating annotations for a scene, it is a best practice to " + "save the annotations to the scene instead of creating a disk annotation file. "); + break; + } + bulletLines.push_back(text); + } + + msg.appendWithNewLine(""); + + return msg; +} + diff --git a/src/GuiQt/BestPracticesDialog.h b/src/GuiQt/BestPracticesDialog.h new file mode 100644 index 000000000..aa4c8d477 --- /dev/null +++ b/src/GuiQt/BestPracticesDialog.h @@ -0,0 +1,78 @@ +#ifndef __BEST_PRACTICES_DIALOG_H__ +#define __BEST_PRACTICES_DIALOG_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2018 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "WuQDialogNonModal.h" + + + +namespace caret { + + class BestPracticesDialog : public WuQDialogNonModal { + + Q_OBJECT + + public: + enum class InfoMode { + LOCK_ASPECT_BEST_PRACTICES + }; + + enum TextMode { + BRIEF, + FULL + }; + + BestPracticesDialog(const InfoMode infoMode, + QWidget* parent); + + virtual ~BestPracticesDialog(); + + static AString getTextForInfoMode(const InfoMode infoMode, + const TextMode textMode); + + // ADD_NEW_METHODS_HERE + + private: + BestPracticesDialog(const BestPracticesDialog&); + + BestPracticesDialog& operator=(const BestPracticesDialog&); + + static AString getLockAspectText(const TextMode textMode); + + const InfoMode m_infoMode; + + const TextMode m_textMode; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __BEST_PRACTICES_DIALOG_DECLARE__ + // +#endif // __BEST_PRACTICES_DIALOG_DECLARE__ + +} // namespace +#endif //__BEST_PRACTICES_DIALOG_H__ diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 6e814f99e..2d7e66de9 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -811,7 +811,7 @@ BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog(QWidget* parent) case LockAspectWarningDialog::Result::CANCEL: okFlag = false; break; - case LockAspectWarningDialog::Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS: + case LockAspectWarningDialog::Result::LOCK_ASPECT: processToolBarLockWindowAndAllTabAspectTriggered(true); break; case LockAspectWarningDialog::Result::NO_CHANGES: @@ -3934,6 +3934,23 @@ BrainBrowserWindow::getAllTabContentIndices(std::vector& allTabContentI } } +/** + * @return Browser window's content. + */ +BrowserWindowContent* +BrainBrowserWindow::getBrowerWindowContent() +{ + return m_browserWindowContent; +} + +/** + * @return Browser window's content (const method). + */ +const BrowserWindowContent* +BrainBrowserWindow::getBrowerWindowContent() const +{ + return m_browserWindowContent; +} /** * Returns a popup menu for the main window. diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 3b5f1c43e..7050e7a99 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -69,6 +69,9 @@ namespace caret { BrowserTabContent* getBrowserTabContent(int tabIndex); + BrowserWindowContent* getBrowerWindowContent(); + + const BrowserWindowContent* getBrowerWindowContent() const; QMenu* createPopupMenu(); diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 89340b71c..3c18efa62 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -62,6 +62,7 @@ ELSE() AnnotationWidthHeightWidget.h BalsaDatabaseUploadSceneFileDialog.h BalsaStudySelectionDialog.h + BestPracticesDialog.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h @@ -256,6 +257,7 @@ BalsaDatabaseUploadSceneFileDialog.h BalsaStudySelectionDialog.h BalsaStudyInformation.h BalsaUserRoles.h +BestPracticesDialog.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h @@ -480,6 +482,7 @@ BalsaDatabaseUploadSceneFileDialog.cxx BalsaStudyInformation.cxx BalsaUserRoles.cxx BalsaStudySelectionDialog.cxx +BestPracticesDialog.cxx BorderEditingSelectionDialog.cxx BorderFileSplitDialog.cxx BorderOptimizeDialog.cxx diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index 1481b061d..efd22c7f9 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -32,11 +32,11 @@ #include #include +#include "BestPracticesDialog.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" -#include "EventManager.h" -#include "EventTabAndWindowLockAspectRatioStatus.h" #include "GuiManager.h" #include "WuQtUtilities.h" @@ -64,42 +64,27 @@ LockAspectWarningDialog::Result LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, QWidget* parent) { - const LockAspectWarningDialog::TabMode tabMode = LockAspectWarningDialog::TabMode::SELECTED_TAB; - - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); + const BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); CaretAssert(bbw); + const BrowserWindowContent* browserWindowContent = bbw->getBrowerWindowContent(); + CaretAssert(browserWindowContent); - BrowserTabContent* selectedTab = bbw->getBrowserTabContent(); - if (selectedTab == NULL) { + const bool aspectLockedFlag = (browserWindowContent->isWindowAspectLocked() + && browserWindowContent->isAllTabsInWindowAspectRatioLocked()); + if (aspectLockedFlag) { return Result::NO_CHANGES; } - if (s_doNotShowAgainStatusFlag) { + const BrowserTabContent* selectedTab = bbw->getBrowserTabContent(); + if (selectedTab == NULL) { return Result::NO_CHANGES; } - EventTabAndWindowLockAspectRatioStatus lockEvent; - EventManager::get()->sendEvent(lockEvent.getPointer()); - CaretAssert(lockEvent.getEventProcessCount() > 0); - - /* - * Determine lock status for window and tabs in the window - */ - const bool tileTabsEnabledFlag = lockEvent.getWindowStatus(browserWindowIndex)->isTileTabsEnabled(); - const bool windowAspectLockedFlag = lockEvent.getWindowStatus(browserWindowIndex)->isAspectRatioLocked(); - const bool selectedTabLockedFlag = lockEvent.getTabStatus(selectedTab->getTabNumber())->isAspectRatioLocked(); - - if (windowAspectLockedFlag - || selectedTabLockedFlag) { + if (s_doNotShowAgainStatusFlag) { return Result::NO_CHANGES; } - - LockAspectWarningDialog dialog(tabMode, - tileTabsEnabledFlag, - windowAspectLockedFlag, - lockEvent.getWindowStatus(browserWindowIndex)->getTabLockedCount(), - lockEvent.getWindowStatus(browserWindowIndex)->getTabCount(), - parent); + + LockAspectWarningDialog dialog(parent); if (dialog.exec() == LockAspectWarningDialog::Accepted) { s_doNotShowAgainStatusFlag = dialog.isDoNotShowAgainChecked(); @@ -125,52 +110,52 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, * @param parent * The parent widget. */ -LockAspectWarningDialog::LockAspectWarningDialog(const TabMode tabMode, - const bool tileTabsEnabled, - const bool browserWindowAspectLocked, - const int32_t tabAspectLockedCount, - const int32_t tabCount, - QWidget* parent) -: QDialog(parent), - m_tabMode(tabMode), - m_browserWindowAspectLocked(browserWindowAspectLocked), -m_tabAspectLockedCount(tabAspectLockedCount), -m_tabCount(tabCount) +LockAspectWarningDialog::LockAspectWarningDialog(QWidget* parent) +: QDialog(parent) { - AString tabText; - switch (m_tabMode) { - case TabMode::ALL_TABS: - tabText = "all Tab Aspect Ratios"; - break; - case TabMode::SELECTED_TAB: - tabText = "the Selected Tab Aspect Ratio"; - break; - } + setWindowTitle("Warning: Aspect Unlocked"); - const AString msg("" - "Neither the Window Aspect Ratio nor " + tabText + " are locked. " - "Prior to entering Annotations Mode and creating annotations, " - "it is recommended that the user adjust the window " - "to the desired size, enter Tile Tabs (if desired), " - "and then lock the aspect ratio for the Window and All Tabs. " - "

    " - "Tab and Window annotations are displayed " - "in percentage coordinates of the tab/window " - "width and height (0% is at bottom/left and 100% " - "is at top/right). Locking the aspect ratio ensures that these " - "annotations remain in the correct location when the window " - "size changes. " - ""); + const QString helpButtonText("More Info"); + + const AString msg = BestPracticesDialog::getTextForInfoMode(BestPracticesDialog::InfoMode::LOCK_ASPECT_BEST_PRACTICES, + BestPracticesDialog::TextMode::BRIEF); +// const AString msg("" +// "Aspect is unlocked and it is strongly recommended that aspect is locked and is never unlocked " +// "when annotations are present. Failing to lock aspect or unlocking the aspect may " +// "cause annotations to move from their original locations." +// "

    " +// "When creating annotations and scenes, follow these best practices:" +// "

      " +// "
    1. If desired, enter Tile Tabs for a multi-tab Scene (View Menu->Enter Tile Tabs)" +// "
    2. Adjust size of window" +// "
    3. Setup view of the model(s) (pan/rotate/zoom)" +// "
    4. Lock Aspect Ratio (click Lock Aspect button in right side of Toolbar)" +// "
    5. Enter Annotations Mode (click Annotate button in Toolbar)" +// "
    6. Add Annotations" +// "
    7. Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes)" +// "
    8. Add a Scene (click Add button on Scene Dialog)" +// "
    9. Save the Scene File (click Save button (or Save As if Save is disabled) at top of Scene Dialog)" +// "
    10. Repeat last few steps as needed" +// "
    " +// ""); QLabel* warningLabel = new QLabel(msg); warningLabel->setWordWrap(true); + QLabel* moreLabel = new QLabel("" + "For a more detailed explanation, click the " + helpButtonText + " button below. " + "Note: This dialog will close if the " + helpButtonText + " is clicked." + ""); + QPushButton* helpButton = new QPushButton(helpButtonText + "..."); + QObject::connect(helpButton, &QPushButton::clicked, + this, &LockAspectWarningDialog::helpButtonClicked); + QLabel* buttonsLabel = new QLabel("Continue to Annotations Mode?"); - QPushButton* lockWindowAndTabButton = new QPushButton("OK - Lock Window and All Tab Aspects"); + QPushButton* lockWindowAndTabButton = new QPushButton("OK - Lock Aspect"); QObject::connect(lockWindowAndTabButton, &QPushButton::clicked, - [=] { this->buttonClicked(Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS); }); + [=] { this->buttonClicked(Result::LOCK_ASPECT); }); - QPushButton* noChangesButton = new QPushButton("OK - No Lock Aspect Changes"); + QPushButton* noChangesButton = new QPushButton("OK - Aspect Remains Unlocked"); QObject::connect(noChangesButton, &QPushButton::clicked, [=] { this->buttonClicked(Result::NO_CHANGES); }); @@ -181,17 +166,7 @@ m_tabCount(tabCount) m_doNotShowAgainCheckBox = new QCheckBox("Do not show again and user will be\n" "responsible for aspect locking/unlocking"); - QVBoxLayout* labelLayout = new QVBoxLayout(); - labelLayout->addWidget(warningLabel); - labelLayout->addStretch(); - - QBoxLayout* dialogLayout = new QHBoxLayout(this); - - WuQtUtilities::matchWidgetWidths(lockWindowAndTabButton, - noChangesButton, - cancelButton); - - QBoxLayout* buttonLayout = new QVBoxLayout(); + QVBoxLayout* buttonLayout = new QVBoxLayout(); buttonLayout->addWidget(buttonsLabel); buttonLayout->addWidget(lockWindowAndTabButton); buttonLayout->addWidget(noChangesButton); @@ -199,8 +174,19 @@ m_tabCount(tabCount) buttonLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); buttonLayout->addWidget(m_doNotShowAgainCheckBox); buttonLayout->addStretch(); + + QVBoxLayout* helpLayout = new QVBoxLayout(); + helpLayout->addWidget(warningLabel); + helpLayout->addWidget(moreLabel); + helpLayout->addWidget(helpButton, 0, Qt::AlignHCenter); + helpLayout->addStretch(); + + WuQtUtilities::matchWidgetWidths(lockWindowAndTabButton, + noChangesButton, + cancelButton); - dialogLayout->addLayout(labelLayout); + QHBoxLayout* dialogLayout = new QHBoxLayout(this); + dialogLayout->addLayout(helpLayout); dialogLayout->addLayout(buttonLayout); /* @@ -228,33 +214,21 @@ LockAspectWarningDialog::getResult() const } /** - * @return Message with current locked status + * Called when help button is clicked. */ -QString -LockAspectWarningDialog::getLockedStatusText() const +void +LockAspectWarningDialog::helpButtonClicked() { - AString windowMessage("Window Aspect: " - + AString((m_browserWindowAspectLocked ? "Locked" : "Unlocked"))); - - AString tabMessage("Tab Aspect: "); - if (m_tabAspectLockedCount == 0) { - tabMessage.append("All Unlocked"); - } - else if (m_tabAspectLockedCount == m_tabCount) { - tabMessage.append("All Locked"); - } - else { - tabMessage.append(AString::number(m_tabAspectLockedCount) - + " of " - + AString::number(m_tabCount) - + " Locked"); - } - - AString lockedMessage(windowMessage - + "\n" - + tabMessage); + /* + * Best practices dialog will destroy itself when closed. + * Use parent widget so that user may close this dialog but allow + * best practices dialog to remain open. + */ + BestPracticesDialog* dialog = new BestPracticesDialog(BestPracticesDialog::InfoMode::LOCK_ASPECT_BEST_PRACTICES, + parentWidget()); + dialog->showDialog(); - return lockedMessage; + buttonClicked(Result::CANCEL); } /** @@ -266,17 +240,15 @@ LockAspectWarningDialog::getLockedStatusText() const void LockAspectWarningDialog::buttonClicked(const Result buttonClicked) { - switch (buttonClicked) { - case Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS: - m_result = Result::LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS; + m_result = buttonClicked; + switch (m_result) { + case Result::LOCK_ASPECT: accept(); break; case Result::NO_CHANGES: - m_result = Result::NO_CHANGES; accept(); break; case Result::CANCEL: - m_result = Result::CANCEL; reject(); break; } diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h index e02b6760e..baccdbe22 100644 --- a/src/GuiQt/LockAspectWarningDialog.h +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -38,25 +38,15 @@ namespace caret { public: enum class Result { - LOCK_WINDOW_ASPECT_AND_ALL_TAB_ASPECTS, + LOCK_ASPECT, NO_CHANGES, CANCEL }; - enum class TabMode { - ALL_TABS, - SELECTED_TAB - }; - static Result runDialog(const int32_t browserWindowIndex, QWidget* parent); - LockAspectWarningDialog(const TabMode tabMode, - const bool tileTabsEnabled, - const bool browserWindowAspectLocked, - const int32_t tabAspectLockedCount, - const int32_t tabCount, - QWidget* parent = 0); + LockAspectWarningDialog(QWidget* parent = 0); virtual ~LockAspectWarningDialog(); @@ -67,6 +57,8 @@ namespace caret { // ADD_NEW_METHODS_HERE private slots: + void helpButtonClicked(); + void buttonClicked(const Result buttonClicked); private: @@ -74,16 +66,6 @@ namespace caret { LockAspectWarningDialog& operator=(const LockAspectWarningDialog&); - QString getLockedStatusText() const; - - const TabMode m_tabMode; - - const bool m_browserWindowAspectLocked; - - const int32_t m_tabAspectLockedCount; - - const int32_t m_tabCount; - Result m_result = Result::CANCEL; QCheckBox* m_doNotShowAgainCheckBox; -- GitLab From 9e845eddef18f869c7505a80ccead6820630bfe9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Feb 2018 14:42:15 -0600 Subject: [PATCH 622/755] On Scene Dialog, when the user runs Test or Replace All Scenes, include the scene number ("1 of N") in the Progress Dialog. if the user cancels a "Replace All" operation, popup a warning dialog so that the user knows that the Scene File is in a partially updated state (may contain both old and news Scenes). --- src/GuiQt/SceneDialog.cxx | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 9dc125e60..f199d45ec 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1252,15 +1252,47 @@ SceneDialog::replaceAllScenesPushButtonClicked() showWaitCursor(); + ProgressReportingDialog progressDialog("Replace All Scenes", + "Starting...", + m_testScenesPushButton); + progressDialog.setEventReceivingEnabled(false); + progressDialog.setMinimumDuration(0); + progressDialog.setMinimum(0); + progressDialog.setMaximum(numScenes); + progressDialog.setValue(1); + progressDialog.setLabelText("Starting replacement..."); + progressDialog.repaint(); + progressDialog.setCursor(Qt::ArrowCursor); + progressDialog.show(); + QApplication::processEvents(); + const int IMAGE_DISPLAY_WIDTH = 400; std::vector sceneNames; std::vector sceneErrors; std::vector oldImages; std::vector newImages; + bool canceledFlag = false; for (int32_t i = 0; i < numScenes; i++) { + if (progressDialog.wasCanceled()) { + canceledFlag = true; + break; + } + Scene* origScene = sceneFile->getSceneAtIndex(i); if (origScene != NULL) { + progressDialog.setValue(i+1); + progressDialog.setLabelText("Replacing " + + AString::number(i + 1) + + " of " + + AString::number(numScenes) + + ": " + + origScene->getName() + + "\n\nPressing the Cancel button will stop replacement after the next scene finishes loading."); + progressDialog.repaint(); + progressDialog.show(); + QApplication::processEvents(); + if (origScene->hasFilesWithRemotePaths()) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); @@ -1341,12 +1373,21 @@ SceneDialog::replaceAllScenesPushButtonClicked() } } + progressDialog.close(); + CaretAssert(sceneNames.size() == sceneErrors.size()); CaretAssert(sceneNames.size() == oldImages.size()); CaretAssert(sceneNames.size() == newImages.size()); showNormalCursor(); + if (canceledFlag) { + WuQMessageBox::warningOk(m_replaceAllScenesPushButton, + "Replacment of scenes was canceled so scene file may contain both original and " + "replaced scenes. It may be best to reload the scene file or exit without saving " + "the scene file."); + } + const int32_t numValidScenes = static_cast(sceneNames.size()); if (numValidScenes <= 0) { WuQMessageBox::errorOk(m_replaceAllScenesPushButton, @@ -1500,6 +1541,7 @@ SceneDialog::testScenesPushButtonClicked() progressDialog.setValue(1); progressDialog.setLabelText("Starting testing..."); progressDialog.repaint(); + progressDialog.setCursor(Qt::ArrowCursor); progressDialog.show(); QApplication::processEvents(); @@ -1517,7 +1559,12 @@ SceneDialog::testScenesPushButtonClicked() Scene* origScene = sceneFile->getSceneAtIndex(i); if (origScene != NULL) { progressDialog.setValue(i+1); - progressDialog.setLabelText("Testing: " + origScene->getName() + progressDialog.setLabelText("Testing " + + AString::number(i + 1) + + " of " + + AString::number(numScenes) + + ": " + + origScene->getName() + "\n\nPressing the Cancel button will stop testing after the next scene finishes loading."); progressDialog.repaint(); progressDialog.show(); -- GitLab From e85ca3a720080f239297903987b705417c97677d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Feb 2018 14:48:17 -0600 Subject: [PATCH 623/755] Continuing on on WB-767: Fixed restoration of old and new scenes with and without tile tabs enabled. --- src/Brain/BrowserWindowContent.cxx | 58 ++++++++++--- src/Brain/BrowserWindowContent.h | 20 +++-- src/Common/TileTabsConfiguration.cxx | 1 + src/GuiQt/BrainBrowserWindow.cxx | 117 +++++++++++++++++---------- src/GuiQt/BrainBrowserWindow.h | 3 +- src/GuiQt/BrainOpenGLWidget.cxx | 7 +- 6 files changed, 144 insertions(+), 62 deletions(-) diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index 6febc53dc..ec2343e13 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -27,6 +27,7 @@ #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneIntegerArray.h" +#include "TileTabsConfiguration.h" using namespace caret; @@ -100,7 +101,8 @@ BrowserWindowContent::reset() m_tileTabsEnabled = false; m_sceneWindowHeight = 0; m_sceneWindowWidth = 0; - m_sceneTileTabsConfiguration = TileTabsConfiguration(); + m_sceneTileTabsConfiguration.reset(new TileTabsConfiguration()); + m_sceneTileTabsConfiguration->setName(s_sceneTileTabsConfigurationText); m_sceneSelectedTabIndex = 0; m_sceneTabIndices.clear(); } @@ -245,10 +247,10 @@ BrowserWindowContent::setSceneWindowHeight(const int32_t height) /** * @return The tile tabs configuration from the scene. */ -TileTabsConfiguration +TileTabsConfiguration* BrowserWindowContent::getSceneTileTabsConfiguration() const { - return m_sceneTileTabsConfiguration; + return m_sceneTileTabsConfiguration.get(); } /** @@ -297,16 +299,28 @@ BrowserWindowContent::setSceneWindowTabIndices(const std::vector& scene m_sceneTabIndices = sceneTabIndices; } +///** +// * Set the tile tabs configuration for the scene. +// * +// * @param tileTabsConfiguration +// * Tile tabs configuration for scene. +// */ +//void +//BrowserWindowContent::setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration) +//{ +// m_sceneTileTabsConfiguration = tileTabsConfiguration; +//} + /** - * Set the tile tabs configuration for the scene. + * Copy the tile tabs configuration for writing to the scene. * * @param tileTabsConfiguration * Tile tabs configuration for scene. */ void -BrowserWindowContent::setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration) +BrowserWindowContent::copyTileTabsConfigurationForSavingScene(const TileTabsConfiguration* tileTabsConfiguration) { - m_sceneTileTabsConfiguration = tileTabsConfiguration; + m_tileTabsConfigurationForSavingScene.reset(new TileTabsConfiguration(*tileTabsConfiguration)); } /** @@ -330,7 +344,25 @@ BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - sceneClass->addString("m_sceneTileTabsConfiguration", m_sceneTileTabsConfiguration.encodeInXML()); + if (m_tileTabsEnabled) { + /* + * The browser window will provide selected tile tabs configuration + * by calling this class' copyTileTabsConfigurationForSavingScene() method. + * It is saved as the scene's tile tabs configuration. + * The content of "m_sceneTileTabsConfiguration" is NOT saved to the scene + * but it will be updated when the scene is read. + */ + CaretAssert(m_tileTabsConfigurationForSavingScene.get()); + const AString xmlString = m_tileTabsConfigurationForSavingScene->encodeInXML(); + sceneClass->addString("m_sceneTileTabsConfiguration", + xmlString); + + /* + * Clear tile tabs config now that it has been written and is no longer needed + */ + m_tileTabsConfigurationForSavingScene.reset(); + } + //sceneClass->addString("m_sceneTileTabsConfiguration", m_sceneTileTabsConfiguration->encodeInXML()); sceneClass->addChild(new SceneIntegerArray("m_sceneTabIndices", m_sceneTabIndices)); @@ -372,7 +404,12 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, const AString stringTileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! stringTileTabsConfig.isEmpty()) { - if ( ! m_sceneTileTabsConfiguration.decodeFromXML(stringTileTabsConfig)) { + if (m_sceneTileTabsConfiguration->decodeFromXML(stringTileTabsConfig)) { + m_sceneTileTabsConfiguration->setName(s_sceneTileTabsConfigurationText + + " " + + sceneAttributes->getSceneName()); + } + else { sceneAttributes->addToErrorMessage("Failed to decode tile tabs configuration from BrowserWindowContent: \"" + stringTileTabsConfig + "\""); @@ -431,7 +468,10 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! tileTabsConfigString.isEmpty()) { - m_sceneTileTabsConfiguration.decodeFromXML(tileTabsConfigString); + m_sceneTileTabsConfiguration->decodeFromXML(tileTabsConfigString); + m_sceneTileTabsConfiguration->setName(s_sceneTileTabsConfigurationText + + " " + + sceneAttributes->getSceneName()); } const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index 3436576d1..c0b1deed1 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -28,12 +28,11 @@ #include "CaretObject.h" #include "SceneableInterface.h" -#include "TileTabsConfiguration.h" - namespace caret { class SceneClassAssistant; - + class TileTabsConfiguration; + class BrowserWindowContent : public CaretObject, public SceneableInterface { public: @@ -73,9 +72,10 @@ namespace caret { void setSceneWindowHeight(const int32_t width); - TileTabsConfiguration getSceneTileTabsConfiguration() const; + TileTabsConfiguration* getSceneTileTabsConfiguration() const; - void setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration); +// void setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration); + void copyTileTabsConfigurationForSavingScene(const TileTabsConfiguration* tileTabsConfiguration); int32_t getSceneSelectedTabIndex() const; @@ -134,12 +134,18 @@ namespace caret { int32_t m_sceneWindowHeight = 0; - TileTabsConfiguration m_sceneTileTabsConfiguration; + std::unique_ptr m_sceneTileTabsConfiguration; + + std::unique_ptr m_tileTabsConfigurationForSavingScene; int32_t m_sceneSelectedTabIndex = 0; std::vector m_sceneTabIndices; + friend class BrainBrowserWindow; + + static const AString s_sceneTileTabsConfigurationText; + // /** Each tab has its own aspect ratio */ // std::array m_tabAspectRatio; // ADD_NEW_MEMBERS_HERE @@ -147,7 +153,7 @@ namespace caret { }; #ifdef __BROWSER_WINDOW_CONTENT_DECLARE__ - // + const AString BrowserWindowContent::s_sceneTileTabsConfigurationText = "From Scene: "; #endif // __BROWSER_WINDOW_CONTENT_DECLARE__ } // namespace diff --git a/src/Common/TileTabsConfiguration.cxx b/src/Common/TileTabsConfiguration.cxx index 73f2095f5..2d6c23d4f 100644 --- a/src/Common/TileTabsConfiguration.cxx +++ b/src/Common/TileTabsConfiguration.cxx @@ -68,6 +68,7 @@ TileTabsConfiguration::~TileTabsConfiguration() TileTabsConfiguration::TileTabsConfiguration(const TileTabsConfiguration& obj) : CaretObject(obj) { + initialize(); this->copyHelperTileTabsConfiguration(obj); } diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 2d7e66de9..f845b12d4 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -143,9 +143,10 @@ m_browserWindowIndex(browserWindowIndex) BrainBrowserWindow::s_firstWindowFlag = false; } - m_sceneTileTabsConfigurationText = "From Scene: "; - m_sceneTileTabsConfiguration = new TileTabsConfiguration(); - m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText); + //m_sceneTileTabsConfigurationText = "From Scene: "; + //m_sceneTileTabsConfiguration = new TileTabsConfiguration(); + //m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText); + //m_browserWindowContent->getSceneTileTabsConfiguration()->setName(m_sceneTileTabsConfigurationText); m_defaultTileTabsConfiguration = new TileTabsConfiguration(); m_defaultTileTabsConfiguration->setDefaultConfiguration(true); @@ -302,7 +303,7 @@ BrainBrowserWindow::~BrainBrowserWindow() } delete m_defaultTileTabsConfiguration; - delete m_sceneTileTabsConfiguration; + //delete m_sceneTileTabsConfiguration; delete m_sceneAssistant; } @@ -2198,9 +2199,9 @@ BrainBrowserWindow::processTileTabsMenuAboutToBeDisplayed() /* * Add the scene configuration */ - QAction* sceneAction = m_tileTabsMenu->addAction(m_sceneTileTabsConfiguration->getName()); + QAction* sceneAction = m_tileTabsMenu->addAction(m_browserWindowContent->getSceneTileTabsConfiguration()->getName()); sceneAction->setCheckable(true); - sceneAction->setData(QVariant(m_sceneTileTabsConfiguration->getUniqueIdentifier())); + sceneAction->setData(QVariant(m_browserWindowContent->getSceneTileTabsConfiguration()->getUniqueIdentifier())); bool haveSelectedTileTabsConfiguration = false; @@ -2222,7 +2223,7 @@ BrainBrowserWindow::processTileTabsMenuAboutToBeDisplayed() } } - if (m_selectedTileTabsConfigurationUniqueIdentifier == m_sceneTileTabsConfiguration->getUniqueIdentifier()) { + if (m_selectedTileTabsConfigurationUniqueIdentifier == m_browserWindowContent->getSceneTileTabsConfiguration()->getUniqueIdentifier()) { haveSelectedTileTabsConfiguration = true; sceneAction->setChecked(true); } @@ -2293,11 +2294,11 @@ BrainBrowserWindow::getSelectedTileTabsConfiguration() */ return m_defaultTileTabsConfiguration; } - else if (m_selectedTileTabsConfigurationUniqueIdentifier == m_sceneTileTabsConfiguration->getUniqueIdentifier()) { + else if (m_selectedTileTabsConfigurationUniqueIdentifier == m_browserWindowContent->getSceneTileTabsConfiguration()->getUniqueIdentifier()) { /* * Scene's configuration is selected */ - return m_sceneTileTabsConfiguration; + return m_browserWindowContent->getSceneTileTabsConfiguration(); } else { /* @@ -4048,31 +4049,52 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - - m_browserWindowContent->saveToScene(sceneAttributes, - "m_browserWindowContent"); + + std::vector allTabIndices; + getAllTabContentIndices(allTabIndices); + m_browserWindowContent->setSceneWindowTabIndices(allTabIndices); + const BrowserTabContent* activeTabContent = getBrowserTabContent(); + if (activeTabContent != NULL) { + m_browserWindowContent->setSceneSelectedTabIndex(activeTabContent->getTabNumber()); + } + m_browserWindowContent->setSceneWindowWidth(width()); + m_browserWindowContent->setSceneWindowHeight(height()); +// if (isTileTabsSelected()) { +// const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); +// if (tileTabs != NULL) { +// m_browserWindowContent->setSceneTileTabsConfiguration(*tileTabs); +// } +// } + if (isTileTabsSelected()) { + const TileTabsConfiguration* tileTabsConfig = getSelectedTileTabsConfiguration(); + if (tileTabsConfig != NULL) { + m_browserWindowContent->copyTileTabsConfigurationForSavingScene(tileTabsConfig); + } + } + sceneClass->addClass(m_browserWindowContent->saveToScene(sceneAttributes, + "m_browserWindowContent")); /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); - /* - * Save the selected tile tabs configuration as the scene configuration - */ - if (isTileTabsSelected()) { - /* - * Note: The number of rows and columns in the default tile tabs - * configuration is updated each time the graphics region of the - * window is drawn in BrainOpenGLWidget::paintGL(). - */ - const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); - if (tileTabs != NULL) { - TileTabsConfiguration writeConfig(*tileTabs); - writeConfig.setName(QUuid::createUuid().toString()); - sceneClass->addString("m_sceneTileTabsConfiguration", - writeConfig.encodeInXML()); - } - } +// /* +// * Save the selected tile tabs configuration as the scene configuration +// */ +// if (isTileTabsSelected()) { +// /* +// * Note: The number of rows and columns in the default tile tabs +// * configuration is updated each time the graphics region of the +// * window is drawn in BrainOpenGLWidget::paintGL(). +// */ +// const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); +// if (tileTabs != NULL) { +// TileTabsConfiguration writeConfig(*tileTabs); +// writeConfig.setName(QUuid::createUuid().toString()); +// sceneClass->addString("m_sceneTileTabsConfiguration", +// writeConfig.encodeInXML()); +// } +// } /* * Save toolbar @@ -4186,8 +4208,9 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, sceneClass); if (sceneVersion >= 2) { + const SceneClass* browserContentClass = sceneClass->getClass("m_browserWindowContent"); m_browserWindowContent->restoreFromScene(sceneAttributes, - sceneClass->getClass("m_browserWindowContent")); + browserContentClass); } else { /* @@ -4246,21 +4269,28 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, else { restoreToFullScreen = sceneClass->getBooleanValue("isFullScreen", false); - restoreToTabTiles = sceneClass->getBooleanValue("m_viewTileTabsAction", - false); + + if (sceneVersion >= 2) { + restoreToTabTiles = m_browserWindowContent->isTileTabsEnabled(); + } + else { + restoreToTabTiles = sceneClass->getBooleanValue("m_viewTileTabsAction", + false); + } + setViewTileTabs(restoreToTabTiles); /* * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration */ if (restoreToTabTiles) { - const AString tileTabsConfigString = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); - if ( ! tileTabsConfigString.isEmpty()) { - m_sceneTileTabsConfiguration->decodeFromXML(tileTabsConfigString); - m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText - + " " - + sceneAttributes->getSceneName()); - m_selectedTileTabsConfigurationUniqueIdentifier = m_sceneTileTabsConfiguration->getUniqueIdentifier(); - } +// const AString tileTabsConfigString = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); +// if ( ! tileTabsConfigString.isEmpty()) { +// m_sceneTileTabsConfiguration->decodeFromXML(tileTabsConfigString); +// m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText +// + " " +// + sceneAttributes->getSceneName()); + m_selectedTileTabsConfigurationUniqueIdentifier = m_browserWindowContent->getSceneTileTabsConfiguration()->getUniqueIdentifier(); +// } } } @@ -4268,7 +4298,12 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, processViewFullScreen(restoreToFullScreen, false); - setViewTileTabs(restoreToTabTiles); +// if (sceneVersion >= 2) { +// setViewTileTabs(m_browserWindowContent->isTileTabsEnabled()); +// } +// else { +// setViewTileTabs(restoreToTabTiles); +// } /* * Position and size diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 7050e7a99..93395f2e5 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -423,8 +423,7 @@ namespace caret { AString m_selectedTileTabsConfigurationUniqueIdentifier; TileTabsConfiguration* m_defaultTileTabsConfiguration; - TileTabsConfiguration* m_sceneTileTabsConfiguration; - AString m_sceneTileTabsConfigurationText; + //AString m_sceneTileTabsConfigurationText; static AString s_previousOpenFileNameFilter; static AString s_previousOpenFileDirectory; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 1d506768f..2e87107a1 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -516,8 +516,9 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], for (int32_t i = 0; i < numberOfTabs; i++) { allTabs.push_back(getModelEvent.getBrowserTab(i)); } - - if (getModelEvent.isTileTabsSelected()) { + + if (getModelEvent.isTileTabsSelected() + && (numberOfTabs > 1)) { const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; @@ -557,7 +558,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); } } - else { + else if (numberOfTabs >= 1) { BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, getModelEvent.getSelectedBrowserTabContent(), gapsAndMargins, -- GitLab From 5bd5b08e52ea3f8a9ea3df17c1a6aa1c08cb6b70 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Feb 2018 11:40:37 -0600 Subject: [PATCH 624/755] Add the Scene to SceneAttributes so it is accessible and GUI elements can be found by other modules. --- src/GuiQt/SceneDialog.cxx | 4 ++-- src/Scenes/Scene.cxx | 3 ++- src/Scenes/SceneAttributes.cxx | 20 ++++++++++++++++++-- src/Scenes/SceneAttributes.h | 9 ++++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index f199d45ec..10d4c7c3f 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -1453,7 +1453,7 @@ SceneDialog::replaceAllScenesPushButtonClicked() QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addLayout(gridLayout); - WuQDialogNonModal* dialog = new WuQDialogNonModal("Scene Results", + WuQDialogNonModal* dialog = new WuQDialogNonModal("Replace All Scenes Comparison", m_replaceAllScenesPushButton); dialog->setDeleteWhenClosed(true); dialog->setApplyButtonText(""); @@ -1687,7 +1687,7 @@ SceneDialog::testScenesPushButtonClicked() dialogLayout->addLayout(gridLayout); dialogLayout->addStretch(); - WuQDialogNonModal* dialog = new WuQDialogNonModal("Scene Comparisons", + WuQDialogNonModal* dialog = new WuQDialogNonModal("Test All Scene Comparisons", m_testScenesPushButton); dialog->setDeleteWhenClosed(true); dialog->setApplyButtonText(""); diff --git a/src/Scenes/Scene.cxx b/src/Scenes/Scene.cxx index 2c679245d..9f29f260d 100644 --- a/src/Scenes/Scene.cxx +++ b/src/Scenes/Scene.cxx @@ -233,7 +233,8 @@ SomeClass::restoreFromScene(const SceneAttributes* sceneAttributes, Scene::Scene(const SceneTypeEnum::Enum sceneType) :CaretObjectTracksModification() { - m_sceneAttributes = new SceneAttributes(sceneType); + m_sceneAttributes = new SceneAttributes(sceneType, + this); m_hasFilesWithRemotePaths = false; m_sceneInfo = new SceneInfo(); } diff --git a/src/Scenes/SceneAttributes.cxx b/src/Scenes/SceneAttributes.cxx index d034001c4..3199c7f65 100644 --- a/src/Scenes/SceneAttributes.cxx +++ b/src/Scenes/SceneAttributes.cxx @@ -37,9 +37,15 @@ using namespace caret; /** * Constructor. + * + * @param sceneType + * Type of scene. + * @param scene + * The scene. */ -SceneAttributes::SceneAttributes(const SceneTypeEnum::Enum sceneType) -: CaretObject(), m_sceneType(sceneType) +SceneAttributes::SceneAttributes(const SceneTypeEnum::Enum sceneType, + const Scene* scene) +: CaretObject(), m_sceneType(sceneType), m_scene(scene) { m_restoreWindowBehaviorInSceneDisplay = RESTORE_WINDOW_POSITION_RELATIVE_TO_FIRST_AND_USE_SIZES; m_specFileNameSavedToScene = true; @@ -78,6 +84,16 @@ SceneAttributes::getSceneType() const return m_sceneType; } +/** + * @return The scene using these attributes. + */ +const Scene* +SceneAttributes::getScene() const +{ + return m_scene; +} + + /** * Set the indices of the tabs that are to be saved to the scene. * @param tabIndices diff --git a/src/Scenes/SceneAttributes.h b/src/Scenes/SceneAttributes.h index 39f6fab21..473954ed5 100644 --- a/src/Scenes/SceneAttributes.h +++ b/src/Scenes/SceneAttributes.h @@ -27,6 +27,8 @@ namespace caret { + class Scene; + class SceneAttributes : public CaretObject { public: @@ -36,7 +38,8 @@ namespace caret { RESTORE_WINDOW_IGNORE_ALL_POSITIONS_AND_SIZES }; - SceneAttributes(const SceneTypeEnum::Enum sceneType); + SceneAttributes(const SceneTypeEnum::Enum sceneType, + const Scene* scene); SceneAttributes(const SceneAttributes& rhs); @@ -44,6 +47,8 @@ namespace caret { SceneTypeEnum::Enum getSceneType() const; + const Scene* getScene() const; + void setIndicesOfTabsAndWindowsForSavingToScene(const std::vector& tabIndices, const std::vector& windowIndices); @@ -100,6 +105,8 @@ namespace caret { const SceneTypeEnum::Enum m_sceneType; + const Scene* m_scene; + std::vector m_indicesOfTabsForSavingToScene; std::vector m_indicesOfWindowsForSavingToScene; -- GitLab From 4884e151aa966859c705321c28c34d657d0912f1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Feb 2018 16:23:11 -0600 Subject: [PATCH 625/755] Close to being done with updates for unified aspect ratio. --- src/Brain/BrowserWindowContent.cxx | 52 ++- src/Brain/BrowserWindowContent.h | 15 +- src/Brain/SessionManager.cxx | 88 ++++- src/Brain/SessionManager.h | 2 +- src/GuiQt/BrainBrowserWindow.cxx | 113 +++--- src/GuiQt/BrainBrowserWindow.h | 2 + src/GuiQt/GuiManager.cxx | 34 +- src/Operations/OperationShowScene.cxx | 483 +++++++++++++------------- 8 files changed, 402 insertions(+), 387 deletions(-) diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index ec2343e13..6fdc799e6 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -46,6 +46,7 @@ BrowserWindowContent::BrowserWindowContent(const int32_t windowIndex) : CaretObject(), m_windowIndex(windowIndex) { + m_validFlag = false; reset(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); @@ -54,8 +55,8 @@ m_windowIndex(windowIndex) m_sceneAssistant->add("m_windowAspectLockedRatio", &m_windowAspectLockedRatio); m_sceneAssistant->add("m_allTabsInWindowAspectRatioLocked", &m_allTabsInWindowAspectRatioLocked); m_sceneAssistant->add("m_tileTabsEnabled", &m_tileTabsEnabled); - m_sceneAssistant->add("m_sceneWindowWidth", &m_sceneWindowWidth); - m_sceneAssistant->add("m_sceneWindowHeight", &m_sceneWindowHeight); + m_sceneAssistant->add("m_sceneGraphicsWidth", &m_sceneGraphicsWidth); + m_sceneAssistant->add("m_sceneGraphicsHeight", &m_sceneGraphicsHeight); m_sceneAssistant->add("m_sceneSelectedTabIndex", &m_sceneSelectedTabIndex); } @@ -94,13 +95,14 @@ BrowserWindowContent::setValid(const bool valid) void BrowserWindowContent::reset() { - m_validFlag = false; + /* Note: do not change m_validFlag */ + m_windowAspectRatioLocked = false; m_windowAspectLockedRatio = 1.0f; m_allTabsInWindowAspectRatioLocked = false; m_tileTabsEnabled = false; - m_sceneWindowHeight = 0; - m_sceneWindowWidth = 0; + m_sceneGraphicsHeight = 0; + m_sceneGraphicsWidth = 0; m_sceneTileTabsConfiguration.reset(new TileTabsConfiguration()); m_sceneTileTabsConfiguration->setName(s_sceneTileTabsConfigurationText); m_sceneSelectedTabIndex = 0; @@ -203,45 +205,45 @@ BrowserWindowContent::setTileTabsEnabled(const bool tileTabsEnabled) } /** - * @return Width of the window from scene. + * @return Width of the graphics region from scene. */ int32_t -BrowserWindowContent::getSceneWindowWidth() const +BrowserWindowContent::getSceneGraphicsWidth() const { - return m_sceneWindowWidth; + return m_sceneGraphicsWidth; } /** - * Set the width of the window for scene. + * Set the width of the graphics region for scene. * * @param width * New value for width. */ void -BrowserWindowContent::setSceneWindowWidth(const int32_t width) +BrowserWindowContent::setSceneGraphicsWidth(const int32_t width) { - m_sceneWindowWidth = width; + m_sceneGraphicsWidth = width; } /** - * @return Height of the window from scene. + * @return Height of the graphics region from scene. */ int32_t -BrowserWindowContent::getSceneWindowHeight() const +BrowserWindowContent::getSceneGraphicsHeight() const { - return m_sceneWindowHeight; + return m_sceneGraphicsHeight; } /** - * Set the height of the window for scene. + * Set the height of the graphics region for scene. * * @param height * New value for height. */ void -BrowserWindowContent::setSceneWindowHeight(const int32_t height) +BrowserWindowContent::setSceneGraphicsHeight(const int32_t height) { - m_sceneWindowHeight = height; + m_sceneGraphicsHeight = height; } /** @@ -299,18 +301,6 @@ BrowserWindowContent::setSceneWindowTabIndices(const std::vector& scene m_sceneTabIndices = sceneTabIndices; } -///** -// * Set the tile tabs configuration for the scene. -// * -// * @param tileTabsConfiguration -// * Tile tabs configuration for scene. -// */ -//void -//BrowserWindowContent::setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration) -//{ -// m_sceneTileTabsConfiguration = tileTabsConfiguration; -//} - /** * Copy the tile tabs configuration for writing to the scene. * @@ -462,8 +452,8 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute const SceneClass* graphicsGeometry = browserClass->getClass("openGLWidgetGeometry"); if (graphicsGeometry != NULL) { - m_sceneWindowWidth = graphicsGeometry->getIntegerValue("geometryWidth", -1); - m_sceneWindowHeight = graphicsGeometry->getIntegerValue("geometryHeight", -1); + m_sceneGraphicsWidth = graphicsGeometry->getIntegerValue("geometryWidth", -1); + m_sceneGraphicsHeight = graphicsGeometry->getIntegerValue("geometryHeight", -1); } const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index c0b1deed1..e02248250 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -64,17 +64,16 @@ namespace caret { void setTileTabsEnabled(const bool tileTabsEnabled); - int32_t getSceneWindowWidth() const; + int32_t getSceneGraphicsWidth() const; - void setSceneWindowWidth(const int32_t width); + void setSceneGraphicsWidth(const int32_t width); - int32_t getSceneWindowHeight() const; + int32_t getSceneGraphicsHeight() const; - void setSceneWindowHeight(const int32_t width); + void setSceneGraphicsHeight(const int32_t width); TileTabsConfiguration* getSceneTileTabsConfiguration() const; -// void setSceneTileTabsConfiguration(const TileTabsConfiguration& tileTabsConfiguration); void copyTileTabsConfigurationForSavingScene(const TileTabsConfiguration* tileTabsConfiguration); int32_t getSceneSelectedTabIndex() const; @@ -130,9 +129,9 @@ namespace caret { bool m_tileTabsEnabled = false; - int32_t m_sceneWindowWidth = 0; + int32_t m_sceneGraphicsWidth = 0; - int32_t m_sceneWindowHeight = 0; + int32_t m_sceneGraphicsHeight = 0; std::unique_ptr m_sceneTileTabsConfiguration; @@ -146,8 +145,6 @@ namespace caret { static const AString s_sceneTileTabsConfigurationText; - // /** Each tab has its own aspect ratio */ - // std::array m_tabAspectRatio; // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 30fc6dded..1f7004e72 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -53,6 +53,7 @@ #include "LogManager.h" #include "MapYokingGroupEnum.h" #include "ModelWholeBrain.h" +#include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" @@ -80,7 +81,10 @@ SessionManager::SessionManager() m_browserTabs[i] = NULL; } - m_browserWindowContent.fill(NULL); + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { + CaretAssertStdArrayIndex(m_browserWindowContent, i); + m_browserWindowContent[i] = new BrowserWindowContent(i); + } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET); @@ -362,19 +366,17 @@ SessionManager::receiveEvent(Event* event) const int32_t windowIndex = windowEvent->getBrowserWindowIndex(); CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); + CaretAssert(m_browserWindowContent[windowIndex]); + switch (windowEvent->getMode()) { case EventBrowserWindowContent::Mode::DELETE: - CaretAssert(m_browserWindowContent[windowIndex]); - delete m_browserWindowContent[windowIndex]; - m_browserWindowContent[windowIndex] = NULL; + m_browserWindowContent[windowIndex]->setValid(false); break; case EventBrowserWindowContent::Mode::GET: - CaretAssert(m_browserWindowContent[windowIndex]); windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); break; case EventBrowserWindowContent::Mode::NEW: - CaretAssert(m_browserWindowContent[windowIndex] == NULL); - m_browserWindowContent[windowIndex] = new BrowserWindowContent(windowIndex); + m_browserWindowContent[windowIndex]->setValid(true); windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); break; } @@ -561,6 +563,19 @@ SessionManager::saveToScene(const SceneAttributes* sceneAttributes, sceneClass->addChild(new SceneClassArray("m_browserTabs", browserTabSceneClasses)); + /* + * Save browser windows + */ + SceneObjectMapIntegerKey* browserClassMap = new SceneObjectMapIntegerKey("browserWindowContentMap", + SceneObjectDataTypeEnum::SCENE_CLASS); + for (auto bw : m_browserWindowContent) { + if (bw->isValid()) { + browserClassMap->addClass(bw->getWindowIndex(), + bw->saveToScene(sceneAttributes, "m_browserWindowContent")); + } + } + sceneClass->addChild(browserClassMap); + sceneClass->addChild(m_imageCaptureDialogSettings->saveToScene(sceneAttributes, "m_imageCaptureDialogSettings")); @@ -804,6 +819,65 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, m_browserTabs[tabIndex] = tab; } + /* + * Restore windows + */ + const SceneObjectMapIntegerKey* browserClassMap = sceneClass->getMapIntegerKey("browserWindowContentMap"); + if (browserClassMap != NULL) { + /* + * m_browserWindowContent was added in Feb 2018 at which time the + * aspect locking buttons for window and tab were consolidated into + * one button. + */ + const std::vector windowIndices = browserClassMap->getKeys(); + for (const auto windowIndex : windowIndices) { + const SceneClass* windowClass = browserClassMap->classValue(windowIndex); + CaretAssert(windowClass); + CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); + m_browserWindowContent[windowIndex]->restoreFromScene(sceneAttributes, + windowClass); + m_browserWindowContent[windowIndex]->setValid(true); + } + } + else { + /* + * For scenes before Feb 2018, need to restore from the GUI's browser window + * to the browser window content. + */ + const Scene* scene = sceneAttributes->getScene(); + CaretAssert(scene); + + const SceneClass* guiManagerClass = scene->getClassWithName("guiManager"); + if (guiManagerClass->getName() != "guiManager") { + sceneAttributes->addToErrorMessage("Top level scene class should be guiManager but it is: " + + guiManagerClass->getName()); + return; + } + + const SceneClassArray* browserWindowArray = guiManagerClass->getClassArray("m_brainBrowserWindows"); + if (browserWindowArray != NULL) { + const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); + for (int32_t i = 0; i < numBrowserClasses; i++) { + const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); + CaretAssert(browserClass); + const int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); + CaretAssert(windowIndex >= 0); + CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); + m_browserWindowContent[windowIndex]->restoreFromOldBrainBrowserWindowScene(sceneAttributes, + browserClass); + m_browserWindowContent[windowIndex]->setValid(true); + } + } + } + + const int32_t numValidBrowserWindows = std::count_if(m_browserWindowContent.begin(), + m_browserWindowContent.end(), + [](BrowserWindowContent* bwc) { return bwc->isValid(); }); + if (numValidBrowserWindows <= 0) { + sceneAttributes->addToErrorMessage("Scene error, no browser window content was restored"); + return; + } + for (auto brainPtr : m_brains) { brainPtr->restoreModelChartOneToModelChartTwo(); } diff --git a/src/Brain/SessionManager.h b/src/Brain/SessionManager.h index ca2b48dc4..959029327 100644 --- a/src/Brain/SessionManager.h +++ b/src/Brain/SessionManager.h @@ -101,7 +101,7 @@ namespace caret { BrowserTabContent* m_browserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** The browser window content */ - std::array m_browserWindowContent; + std::array m_browserWindowContent; /** Holds valid models */ std::vector m_models; diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index f845b12d4..d59bfd160 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -143,11 +143,6 @@ m_browserWindowIndex(browserWindowIndex) BrainBrowserWindow::s_firstWindowFlag = false; } - //m_sceneTileTabsConfigurationText = "From Scene: "; - //m_sceneTileTabsConfiguration = new TileTabsConfiguration(); - //m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText); - //m_browserWindowContent->getSceneTileTabsConfiguration()->setName(m_sceneTileTabsConfigurationText); - m_defaultTileTabsConfiguration = new TileTabsConfiguration(); m_defaultTileTabsConfiguration->setDefaultConfiguration(true); m_defaultTileTabsConfiguration->setName("All Tabs (Default)"); @@ -303,7 +298,6 @@ BrainBrowserWindow::~BrainBrowserWindow() } delete m_defaultTileTabsConfiguration; - //delete m_sceneTileTabsConfiguration; delete m_sceneAssistant; } @@ -775,7 +769,7 @@ BrainBrowserWindow::createActionsUsedByToolBar() m_toolBarLockWindowAndAllTabAspectRatioAction = new QAction(); m_toolBarLockWindowAndAllTabAspectRatioAction->setCheckable(true); m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(false); - m_toolBarLockWindowAndAllTabAspectRatioAction->setText("Lock Window Aspect"); + m_toolBarLockWindowAndAllTabAspectRatioAction->setText("Lock Aspect"); m_toolBarLockWindowAndAllTabAspectRatioAction->setToolTip(aspectButtonToolTipText); QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioAction, &QAction::triggered, this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered); @@ -932,6 +926,7 @@ BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu(const QPoint& po getAspectRatio(), this); if (aspectRatio > 0.0f) { + lockWindowAspectRatio(true); m_browserWindowContent->setWindowAspectLockedRatio(aspectRatio); } } @@ -942,10 +937,13 @@ BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu(const QPoint& po tabContent->getAspectRatio(), this); if (aspectRatio > 0.0f) { + lockAllTabAspectRatios(true); tabContent->setAspectRatio(aspectRatio); + tabContent->setAspectRatioLocked(true); } } + updateActionsForLockingAspectRatios(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } } @@ -4027,6 +4025,36 @@ BrainBrowserWindow::getOpenGLWidgetAspectRatio() const return aspectRatio; } +/** + * BrowserWindowContent is owned and saved to and restored from + * Scenes by SessionManager. Since SessionManager is save to + * Scene before instances of this class, update content + * of BrowserWindowContent. + */ +void +BrainBrowserWindow::saveBrowserWindowContentForScene() +{ + std::vector allTabIndices; + getAllTabContentIndices(allTabIndices); + m_browserWindowContent->setSceneWindowTabIndices(allTabIndices); + + const BrowserTabContent* activeTabContent = getBrowserTabContent(); + if (activeTabContent != NULL) { + m_browserWindowContent->setSceneSelectedTabIndex(activeTabContent->getTabNumber()); + } + + if (isTileTabsSelected()) { + const TileTabsConfiguration* tileTabsConfig = getSelectedTileTabsConfiguration(); + if (tileTabsConfig != NULL) { + m_browserWindowContent->copyTileTabsConfigurationForSavingScene(tileTabsConfig); + } + } + + m_browserWindowContent->setSceneGraphicsWidth(m_openGLWidget->width()); + m_browserWindowContent->setSceneGraphicsHeight(m_openGLWidget->height()); +} + + /** * Create a scene for an instance of a class. * @@ -4050,52 +4078,10 @@ BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); - std::vector allTabIndices; - getAllTabContentIndices(allTabIndices); - m_browserWindowContent->setSceneWindowTabIndices(allTabIndices); - const BrowserTabContent* activeTabContent = getBrowserTabContent(); - if (activeTabContent != NULL) { - m_browserWindowContent->setSceneSelectedTabIndex(activeTabContent->getTabNumber()); - } - m_browserWindowContent->setSceneWindowWidth(width()); - m_browserWindowContent->setSceneWindowHeight(height()); -// if (isTileTabsSelected()) { -// const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); -// if (tileTabs != NULL) { -// m_browserWindowContent->setSceneTileTabsConfiguration(*tileTabs); -// } -// } - if (isTileTabsSelected()) { - const TileTabsConfiguration* tileTabsConfig = getSelectedTileTabsConfiguration(); - if (tileTabsConfig != NULL) { - m_browserWindowContent->copyTileTabsConfigurationForSavingScene(tileTabsConfig); - } - } - sceneClass->addClass(m_browserWindowContent->saveToScene(sceneAttributes, - "m_browserWindowContent")); - /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); -// /* -// * Save the selected tile tabs configuration as the scene configuration -// */ -// if (isTileTabsSelected()) { -// /* -// * Note: The number of rows and columns in the default tile tabs -// * configuration is updated each time the graphics region of the -// * window is drawn in BrainOpenGLWidget::paintGL(). -// */ -// const TileTabsConfiguration* tileTabs = getSelectedTileTabsConfiguration(); -// if (tileTabs != NULL) { -// TileTabsConfiguration writeConfig(*tileTabs); -// writeConfig.setName(QUuid::createUuid().toString()); -// sceneClass->addString("m_sceneTileTabsConfiguration", -// writeConfig.encodeInXML()); -// } -// } - /* * Save toolbar */ @@ -4207,17 +4193,10 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); - if (sceneVersion >= 2) { - const SceneClass* browserContentClass = sceneClass->getClass("m_browserWindowContent"); - m_browserWindowContent->restoreFromScene(sceneAttributes, - browserContentClass); - } - else { - /* - * Some members of this class were moved to BrowserWindowContent - */ - m_browserWindowContent->restoreFromOldBrainBrowserWindowScene(sceneAttributes, - sceneClass); + if ( ! m_browserWindowContent->isValid()) { + sceneAttributes->addToErrorMessage("Scene Error: Browser window content is invalid for window " + + AString::number(m_browserWindowIndex + 1)); + return; } /* @@ -4283,14 +4262,7 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration */ if (restoreToTabTiles) { -// const AString tileTabsConfigString = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); -// if ( ! tileTabsConfigString.isEmpty()) { -// m_sceneTileTabsConfiguration->decodeFromXML(tileTabsConfigString); -// m_sceneTileTabsConfiguration->setName(m_sceneTileTabsConfigurationText -// + " " -// + sceneAttributes->getSceneName()); m_selectedTileTabsConfigurationUniqueIdentifier = m_browserWindowContent->getSceneTileTabsConfiguration()->getUniqueIdentifier(); -// } } } @@ -4298,13 +4270,6 @@ BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, processViewFullScreen(restoreToFullScreen, false); -// if (sceneVersion >= 2) { -// setViewTileTabs(m_browserWindowContent->isTileTabsEnabled()); -// } -// else { -// setViewTileTabs(restoreToTabTiles); -// } - /* * Position and size */ diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 93395f2e5..20f4b72ea 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -312,6 +312,8 @@ namespace caret { const float aspectRatio, QWidget* parent) const; + void saveBrowserWindowContentForScene(); + /** Index of this window */ const int32_t m_browserWindowIndex; diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index c0ef3e5d5..51ce0c55b 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -314,7 +314,7 @@ GuiManager::~GuiManager() if (this->connectomeDatabaseWebView != NULL) { CaretAssertMessage(0, "Need to uncomment out line below if webkit is renabled"); - //delete this->connectomeDatabaseWebView; + /* delete this->connectomeDatabaseWebView; */ } FociPropertiesEditorDialog::deleteStaticMembers(); @@ -2207,7 +2207,6 @@ GuiManager::processShowGapsAndMarginsDialog(BrainBrowserWindow* browserWindow) this->addNonModalDialog(m_gapsAndMarginsDialog); } m_gapsAndMarginsDialog->updateDialog(); - //m_tabMarginsDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); m_gapsAndMarginsDialog->showDialog(); } @@ -2223,8 +2222,6 @@ GuiManager::processShowMovieDialog(BrainBrowserWindow* browserWindow) this->movieDialog = new MovieDialog(browserWindow); this->addNonModalDialog(this->movieDialog); } - //this->movieDialog->updateDialog(); - //this->movieDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); this->movieDialog->setVisible(true); this->movieDialog->show(); this->movieDialog->activateWindow(); @@ -2317,6 +2314,19 @@ GuiManager::saveToScene(const SceneAttributes* sceneAttributes, "GuiManager", 1); + /* + * BrowserWindowContent is saved and restored by SessionManager. + * Some of the data in BrowserWindowContent needs to be updated + * by BrainBrowserWindow which is not saved until AFTER SessionManager + * so direct each window to update its BrowserWindowContent so that + * BrowserWindowContent can be saved by the SessionManager. + */ + for (auto browserWindow : m_brainBrowserWindows) { + if (browserWindow != NULL) { + browserWindow->saveBrowserWindowContentForScene(); + } + } + /* * Save session manager (brain, etc) */ @@ -3022,20 +3032,6 @@ GuiManager::processIdentification(const int32_t tabIndex, } matrixChart->setSelectedRowColumnIndex(tabIndex, rowColumnIndex); - // const MapYokingGroupEnum::Enum mapYoking = matrixChart->getMatrixRowColumnMapYokingGroup(tabIndex); - // - // if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { - // EventMapYokingSelectMap selectMapEvent(mapYoking, - // scalarDataSeriesFile, - // rowIndex, - // true); - // EventManager::get()->sendEvent(selectMapEvent.getPointer()); - // } - // else { - // chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, - // rowIndex); - // } - updateGraphicsFlag = true; } } @@ -3167,7 +3163,7 @@ GuiManager::processIdentification(const int32_t tabIndex, EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().addToolBox().getPointer()); } -} // tabIndex +} diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 503c3cf1c..0a5b146d2 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -38,10 +38,12 @@ #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWindowContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "EventBrowserTabGet.h" +#include "EventBrowserWindowContent.h" #include "EventMapYokingSelectMap.h" #include "EventManager.h" #include "FileInformation.h" @@ -66,7 +68,7 @@ using namespace caret; /** - * \class caret::OperationShowScene + * \class caret::OperationShowScene * \brief Offscreen rendering of scene to an image file * * Render a scene into an image file using the Offscreen Mesa Library @@ -105,7 +107,7 @@ OperationShowScene::getParameters() ret->addStringParameter(3, "image-file-name", "output image file name"); ret->addIntegerParameter(4, "image-width", "width of output image(s)"); - + ret->addIntegerParameter(5, "image-height", "height of output image(s)"); const QString windowSizeSwitch("-use-window-size"); @@ -168,7 +170,7 @@ OperationShowScene::getParameters() #ifndef HAVE_OSMESA void OperationShowScene::useParameters(OperationParameters* /*myParams*/, - ProgressObject* /*myProgObj*/) + ProgressObject* /*myProgObj*/) { throw OperationException("Show scene command not available due to this software version " "not being built with the Mesa OffScreen Library"); @@ -245,13 +247,14 @@ OperationShowScene::useParameters(OperationParameters* myParams, throw OperationException("Scene name is invalid"); } } - + /* * Enable voxel coloring since it is defaulted off for commands */ VolumeFile::setVoxelColoringEnabled(true); - SceneAttributes sceneAttributes(SceneTypeEnum::SCENE_TYPE_FULL); + SceneAttributes sceneAttributes(SceneTypeEnum::SCENE_TYPE_FULL, + scene); if (doNotUseSceneColorsFlag) { sceneAttributes.setUseSceneForegroundAndBackgroundColors(false); @@ -273,9 +276,9 @@ OperationShowScene::useParameters(OperationParameters* myParams, /* * Get the error message but continue processing since the error * may not affect the scene. Print error message later. - */ + */ const AString sceneErrorMessage = sceneAttributes.getErrorMessage(); - + if (sessionManager->getNumberOfBrains() <= 0) { throw OperationException("Scene loading failure, SessionManager contains no Brains"); } @@ -298,255 +301,193 @@ OperationShowScene::useParameters(OperationParameters* myParams, EventManager::get()->sendEvent(yokeEvent.getPointer()); } + std::vector allBrowserWindowContent; + for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { + std::unique_ptr browserContentEvent = EventBrowserWindowContent::getWindowContent(i); + EventManager::get()->sendEvent(browserContentEvent->getPointer()); + const BrowserWindowContent* bwc = browserContentEvent->getBrowserWindowContent(); + CaretAssert(bwc); + if (bwc->isValid()) { + allBrowserWindowContent.push_back(bwc); + } + } + const int32_t numberOfWindows = static_cast(allBrowserWindowContent.size()); + if (numberOfWindows <= 0) { + throw OperationException("No BrowserWindowContent was found for showing as scene"); + } + /* * Restore windows */ - const SceneClassArray* browserWindowArray = guiManagerClass->getClassArray("m_brainBrowserWindows"); - if (browserWindowArray != NULL) { - const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); - for (int32_t i = 0; i < numBrowserClasses; i++) { - const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); - - const bool restoreToTabTiles = browserClass->getBooleanValue("m_viewTileTabsAction", - false); - const int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", 0); - - int32_t imageWidth = userImageWidth; - int32_t imageHeight = userImageHeight; - - if (useWindowSizeForImageSizeFlag) { - /* - * Requires version AFTER 1.2.0-pre1 - */ - const SceneClass* graphicsGeometry = browserClass->getClass("openGLWidgetGeometry"); - if (graphicsGeometry != NULL) { - const int32_t windowGeometryWidth = graphicsGeometry->getIntegerValue("geometryWidth", -1); - const int32_t windowGeometryHeight = graphicsGeometry->getIntegerValue("geometryHeight", -1); - - if ((windowGeometryWidth > 0) - && (windowGeometryHeight > 0)) { - imageWidth = windowGeometryWidth; - imageHeight = windowGeometryHeight; - } - } - else { - if ((imageWidth <= 0) - || (imageHeight <= 0)) { - const QString msg("Option " - + useWindowSizeParam->m_optionSwitch - + " is used but window size not found in scene and width=" - + QString::number(imageWidth) - + " height=" - + QString::number(imageWidth) - + " on command line is invalid."); - - throw OperationException(msg); - } - - if ( ! missingWindowMessageHasBeenDisplayed) { - const QString msg("Option \"" - + useWindowSizeParam->m_optionSwitch - + "\" is used but window size not found in scene.\n" - " Scene was created prior to implementation of this option.\n" - " Image size will be width=" - + QString::number(imageWidth) - + " and height=" - + QString::number(imageHeight) - + " as specified on command line.\n" - " Recreating the scene will allow use of the option.\n"); - CaretLogWarning(msg); - - /* - * Avoid message being displayed more than once when - * there are more than one windows. - */ - missingWindowMessageHasBeenDisplayed = true; - } - } - } - - if ((imageWidth <= 0) - || (imageHeight <= 0)) { - throw OperationException("Invalid image size width=" - + QString::number(imageWidth) - + " height=" - + QString::number(imageHeight)); - } - - int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; - - const int windowWidth = windowViewport[2]; - const int windowHeight = windowViewport[3]; - - // - // Create the Mesa Context - // - const int depthBits = 16; - const int stencilBits = 0; - const int accumBits = 0; - OSMesaContext mesaContext = OSMesaCreateContextExt(OSMESA_RGBA, - depthBits, - stencilBits, - accumBits, - NULL); - if (mesaContext == 0) { - throw ("Creating Mesa Context failed."); - } - - // - // Allocate image buffer - // - const int32_t imageBufferSize =imageWidth * imageHeight * 4 * sizeof(unsigned char); - unsigned char* imageBuffer = new unsigned char[imageBufferSize]; - if (imageBuffer == 0) { - throw OperationException("Allocating image buffer size=" - + QString::number(imageBufferSize) - + " failed."); - } - - // - // Assign buffer to Mesa Context and make current - // - if (OSMesaMakeCurrent(mesaContext, - imageBuffer, - GL_UNSIGNED_BYTE, - imageWidth, - imageHeight) == 0) { - throw OperationException("Assigning buffer to context and make current failed."); - } - + for (int32_t iWindow = 0; iWindow < numberOfWindows; iWindow++) { + CaretAssertVectorIndex(allBrowserWindowContent, iWindow); + const auto bwc = allBrowserWindowContent[iWindow]; + + const bool restoreToTabTiles = bwc->isTileTabsEnabled(); + const int32_t windowIndex = bwc->getWindowIndex(); + + int32_t imageWidth = userImageWidth; + int32_t imageHeight = userImageHeight; + + if (useWindowSizeForImageSizeFlag) { /* - * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration + * Requires version AFTER 1.2.0-pre1 */ - if (restoreToTabTiles) { - CaretPointer brainOpenGL(createBrainOpenGL()); + const float geomWidth = bwc->getSceneGraphicsWidth(); + const float geomHeight = bwc->getSceneGraphicsHeight(); + if ((geomWidth > 0) + && (geomHeight > 0)) { + imageWidth = geomWidth; + imageHeight = geomHeight; + } + else { + if ((imageWidth <= 0) + || (imageHeight <= 0)) { + const QString msg("Option " + + useWindowSizeParam->m_optionSwitch + + " is used but window size not found in scene and width=" + + QString::number(imageWidth) + + " height=" + + QString::number(imageWidth) + + " on command line is invalid."); + + throw OperationException(msg); + } - const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); - if ( ! tileTabsConfigString.isEmpty()) { - TileTabsConfiguration tileTabsConfiguration; - tileTabsConfiguration.decodeFromXML(tileTabsConfigString); + if ( ! missingWindowMessageHasBeenDisplayed) { + const QString msg("Option \"" + + useWindowSizeParam->m_optionSwitch + + "\" is used but window size not found in scene.\n" + " Scene was created prior to implementation of this option.\n" + " Image size will be width=" + + QString::number(imageWidth) + + " and height=" + + QString::number(imageHeight) + + " as specified on command line.\n" + " Recreating the scene will allow use of the option.\n"); + CaretLogWarning(msg); /* - * Restore toolbar + * Avoid message being displayed more than once when + * there are more than one windows. */ - const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); - if (toolbarClass != NULL) { - /* - * Index of selected browser tab (NOT the tabBar) - */ - std::vector allTabContent; - const ScenePrimitiveArray* tabIndexArray = toolbarClass->getPrimitiveArray("tabIndices"); - if (tabIndexArray != NULL) { - const int32_t numTabs = tabIndexArray->getNumberOfArrayElements(); - for (int32_t iTab = 0; iTab < numTabs; iTab++) { - const int32_t tabIndex = tabIndexArray->integerValue(iTab); - - EventBrowserTabGet getTabContent(tabIndex); - EventManager::get()->sendEvent(getTabContent.getPointer()); - BrowserTabContent* tabContent = getTabContent.getBrowserTab(); - if (tabContent == NULL) { - throw OperationException("Failed to obtain tab number " - + AString::number(tabIndex + 1) - + " for window " - + AString::number(windowIndex + 1)); - } - allTabContent.push_back(tabContent); - } - } - - const int32_t numTabContent = static_cast(allTabContent.size()); - if (numTabContent <= 0) { - throw OperationException("Failed to find any tab content"); - } - std::vector rowHeights; - std::vector columnWidths; - if ( ! tileTabsConfiguration.getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numTabContent, - rowHeights, - columnWidths)) { - throw OperationException("Tile Tabs Row/Column sizing failed !!!"); - } - - const int32_t tabIndexToHighlight = -1; - std::vector viewports = - BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabContent, - &tileTabsConfiguration, - gapsAndMargins, - windowIndex, - windowViewport, - tabIndexToHighlight); - - std::vector constViewports(viewports.begin(), - viewports.end()); - brainOpenGL->drawModels(windowIndex, - brain, - mesaContext, - constViewports); - - const int32_t outputImageIndex = ((numBrowserClasses > 1) - ? i - : -1); - - writeImage(imageFileName, - outputImageIndex, - imageBuffer, - imageWidth, - imageHeight); - - for (std::vector::iterator vpIter = viewports.begin(); - vpIter != viewports.end(); - vpIter++) { - delete *vpIter; - } - viewports.clear(); - } - } - else { - throw OperationException("Tile tabs configuration is corrupted."); + missingWindowMessageHasBeenDisplayed = true; } } - else { - CaretPointer brainOpenGL(createBrainOpenGL()); + } + + if ((imageWidth <= 0) + || (imageHeight <= 0)) { + throw OperationException("Invalid image size width=" + + QString::number(imageWidth) + + " height=" + + QString::number(imageHeight)); + } + + int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; + + const int windowWidth = windowViewport[2]; + const int windowHeight = windowViewport[3]; + + // + // Create the Mesa Context + // + const int depthBits = 16; + const int stencilBits = 0; + const int accumBits = 0; + OSMesaContext mesaContext = OSMesaCreateContextExt(OSMESA_RGBA, + depthBits, + stencilBits, + accumBits, + NULL); + if (mesaContext == 0) { + throw ("Creating Mesa Context failed."); + } + + // + // Allocate image buffer + // + const int32_t imageBufferSize =imageWidth * imageHeight * 4 * sizeof(unsigned char); + unsigned char* imageBuffer = new unsigned char[imageBufferSize]; + if (imageBuffer == 0) { + throw OperationException("Allocating image buffer size=" + + QString::number(imageBufferSize) + + " failed."); + } + + // + // Assign buffer to Mesa Context and make current + // + if (OSMesaMakeCurrent(mesaContext, + imageBuffer, + GL_UNSIGNED_BYTE, + imageWidth, + imageHeight) == 0) { + throw OperationException("Assigning buffer to context and make current failed."); + } + + /* + * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration + */ + if (restoreToTabTiles) { + CaretPointer brainOpenGL(createBrainOpenGL()); + + TileTabsConfiguration* tileTabsConfiguration = bwc->getSceneTileTabsConfiguration(); + CaretAssert(tileTabsConfiguration); + if ((tileTabsConfiguration->getMaximumNumberOfRows() > 0) + && (tileTabsConfiguration->getMaximumNumberOfColumns() > 0)) { - /* - * Restore toolbar - */ - const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); - if (toolbarClass != NULL) { - /* - * Index of selected browser tab (NOT the tabBar) - */ - const int32_t selectedTabIndex = toolbarClass->getIntegerValue("selectedTabIndex", -1); + const std::vector tabIndices = bwc->getSceneTabIndices(); + if ( ! tabIndices.empty()) { + std::vector allTabContent; + const int32_t numTabs = static_cast(tabIndices.size()); + for (int32_t iTab = 0; iTab < numTabs; iTab++) { + CaretAssertVectorIndex(tabIndices, iTab); + const int32_t tabIndex = tabIndices[iTab]; + EventBrowserTabGet getTabContent(tabIndex); + EventManager::get()->sendEvent(getTabContent.getPointer()); + BrowserTabContent* tabContent = getTabContent.getBrowserTab(); + if (tabContent == NULL) { + throw OperationException("Failed to obtain tab number " + + AString::number(tabIndex + 1) + + " for window " + + AString::number(windowIndex + 1)); + } + allTabContent.push_back(tabContent); + } - EventBrowserTabGet getTabContent(selectedTabIndex); - EventManager::get()->sendEvent(getTabContent.getPointer()); - BrowserTabContent* tabContent = getTabContent.getBrowserTab(); - if (tabContent == NULL) { - throw OperationException("Failed to obtain tab number " - + AString::number(selectedTabIndex + 1) - + " for window " - + AString::number(i + 1)); + const int32_t numTabContent = static_cast(allTabContent.size()); + if (numTabContent <= 0) { + throw OperationException("Failed to find any tab content"); + } + std::vector rowHeights; + std::vector columnWidths; + if ( ! tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numTabContent, + rowHeights, + columnWidths)) { + throw OperationException("Tile Tabs Row/Column sizing failed !!!"); } - CaretPointer content(NULL); - std::vector allTabs; - allTabs.push_back(tabContent); - content.grabNew(BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, - tabContent, - gapsAndMargins, - windowIndex, - windowViewport)); - std::vector viewportContents; - viewportContents.push_back(content); + const int32_t tabIndexToHighlight = -1; + std::vector viewports = + BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabContent, + tileTabsConfiguration, + gapsAndMargins, + windowIndex, + windowViewport, + tabIndexToHighlight); + std::vector constViewports(viewports.begin(), + viewports.end()); brainOpenGL->drawModels(windowIndex, brain, mesaContext, - viewportContents); + constViewports); - const int32_t outputImageIndex = ((numBrowserClasses > 1) - ? i + const int32_t outputImageIndex = ((numberOfWindows > 1) + ? iWindow : -1); writeImage(imageFileName, @@ -555,17 +496,67 @@ OperationShowScene::useParameters(OperationParameters* myParams, imageWidth, imageHeight); + for (std::vector::iterator vpIter = viewports.begin(); + vpIter != viewports.end(); + vpIter++) { + delete *vpIter; + } + viewports.clear(); } } + else { + throw OperationException("Tile tabs configuration is corrupted."); + } + } + else { + CaretPointer brainOpenGL(createBrainOpenGL()); - /* - * Free image memory and Mesa context - */ - delete[] imageBuffer; - OSMesaDestroyContext(mesaContext); + const int32_t selectedTabIndex = bwc->getSceneSelectedTabIndex(); + + EventBrowserTabGet getTabContent(selectedTabIndex); + EventManager::get()->sendEvent(getTabContent.getPointer()); + BrowserTabContent* tabContent = getTabContent.getBrowserTab(); + if (tabContent == NULL) { + throw OperationException("Failed to obtain tab number " + + AString::number(selectedTabIndex + 1) + + " for window " + + AString::number(iWindow + 1)); + } + + CaretPointer content(NULL); + std::vector allTabs; + allTabs.push_back(tabContent); + content.grabNew(BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, + tabContent, + gapsAndMargins, + windowIndex, + windowViewport)); + std::vector viewportContents; + viewportContents.push_back(content); + + brainOpenGL->drawModels(windowIndex, + brain, + mesaContext, + viewportContents); + + const int32_t outputImageIndex = ((numberOfWindows > 1) + ? iWindow + : -1); + + writeImage(imageFileName, + outputImageIndex, + imageBuffer, + imageWidth, + imageHeight); } + + /* + * Free image memory and Mesa context + */ + delete[] imageBuffer; + OSMesaDestroyContext(mesaContext); } - + /* * Print error messages */ @@ -648,7 +639,7 @@ OperationShowScene::estimateGraphicsSize(const SceneClass* windowSceneClass, /** * Get the size of a toolbox. - * + * * @param toolBoxClass * The toolbox scene class. * @param overlayToolBoxWidthOut @@ -663,9 +654,9 @@ OperationShowScene::estimateGraphicsSize(const SceneClass* windowSceneClass, bool OperationShowScene::getToolBoxSize(const SceneClass* toolBoxClass, const SceneClass* activeToolBoxClass, - float& overlayToolBoxWidthOut, - float& overlayToolBoxHeightOut, - QString& overlayToolBoxOrientationOut) + float& overlayToolBoxWidthOut, + float& overlayToolBoxHeightOut, + QString& overlayToolBoxOrientationOut) { if (toolBoxClass == NULL) { return false; -- GitLab From 063d09d429e0e4021fa6d4e8f8c5e2161e18cba6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 13 Feb 2018 16:37:07 -0600 Subject: [PATCH 626/755] Removed EventTabAndWindowLockAspectRatioStatus as it is no longer used by tab/window locking. --- src/Common/EventManager.cxx | 1 - src/Common/EventTypeEnum.cxx | 4 - src/Common/EventTypeEnum.h | 2 - src/GuiQt/CMakeLists.txt | 2 - ...EventTabAndWindowLockAspectRatioStatus.cxx | 161 ------------------ .../EventTabAndWindowLockAspectRatioStatus.h | 145 ---------------- src/GuiQt/GuiManager.cxx | 36 ---- src/GuiQt/GuiManager.h | 3 - 8 files changed, 354 deletions(-) delete mode 100644 src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx delete mode 100644 src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index af0ded624..5b960ff70 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -452,7 +452,6 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE: case EventTypeEnum::EVENT_SURFACES_GET: case EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET: - case EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS: case EventTypeEnum::EVENT_TOOLBOX_SELECTION_DISPLAY: case EventTypeEnum::EVENT_USER_INTERFACE_UPDATE: case EventTypeEnum::EVENT_PROGRESS_UPDATE: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index e10b02be0..855a96624 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -350,10 +350,6 @@ EventTypeEnum::initialize() "EVENT_SURFACE_STRUCTURES_VALID_GET", "GGet valid surface strucutures and their number of node")); - enumData.push_back(EventTypeEnum(EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS, - "EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS", - "Get lock aspect and related information for all tabs and windows")); - enumData.push_back(EventTypeEnum(EVENT_TOOLBOX_SELECTION_DISPLAY, "EVENT_TOOLBOX_SELECTION_DISPLAY", "Display or hide the selection toolbox")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index 9d5b84300..5dd9d2251 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -182,8 +182,6 @@ public: EVENT_SURFACES_GET, /** Get valid surface strucutures and their number of nodes */ EVENT_SURFACE_STRUCTURES_VALID_GET, - /** Get the lock aspect and related information for tabs and windows */ - EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS, /** Display/Hide the selection toolbox */ EVENT_TOOLBOX_SELECTION_DISPLAY, /** Update the User-Interface */ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 3c18efa62..3b469b5e5 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -334,7 +334,6 @@ EventOperatingSystemRequestOpenDataFile.h EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h EventShowDataFileReadWarningsDialog.h -EventTabAndWindowLockAspectRatioStatus.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h EventUpdateYokedWindows.h @@ -558,7 +557,6 @@ EventOperatingSystemRequestOpenDataFile.cxx EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx EventShowDataFileReadWarningsDialog.cxx -EventTabAndWindowLockAspectRatioStatus.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx EventUpdateYokedWindows.cxx diff --git a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx deleted file mode 100644 index e240b5771..000000000 --- a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.cxx +++ /dev/null @@ -1,161 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2018 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#define __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ -#include "EventTabAndWindowLockAspectRatioStatus.h" -#undef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ - -#include "Annotation.h" -#include "BrainBrowserWindow.h" -#include "BrainConstants.h" -#include "BrowserTabContent.h" -#include "CaretAssert.h" -#include "EventTypeEnum.h" - -using namespace caret; - - - -/** - * \class caret::EventTabAndWindowLockAspectRatioStatus - * \brief Event that gets lock aspect and related information for tabs and windows - * \ingroup GuiQt - */ - -/** - * Constructor. - */ -EventTabAndWindowLockAspectRatioStatus::EventTabAndWindowLockAspectRatioStatus() -: Event(EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS) -{ - m_tabStatus.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); - m_windowStatus.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS); -} - -/** - * Destructor. - */ -EventTabAndWindowLockAspectRatioStatus::~EventTabAndWindowLockAspectRatioStatus() -{ -} - -/** - * @return Tab status for the given tab index, even if the tab is invalid. - * - * @param tabIndex - * Index of the tab. - * Must be in the range [0, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS - 1] - */ -EventTabAndWindowLockAspectRatioStatus::TabStatus* -EventTabAndWindowLockAspectRatioStatus::getTabStatus(const int32_t tabIndex) -{ - CaretAssertVectorIndex(m_tabStatus, tabIndex); - return &m_tabStatus[tabIndex]; -} - -/** - * @return Window status for the given window index, even if the window is invalid. - * - * @param windowIndex - * Index of the window. - * Must be in the range [0, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS - 1] - */ -EventTabAndWindowLockAspectRatioStatus::WindowStatus* -EventTabAndWindowLockAspectRatioStatus::getWindowStatus(const int32_t windowIndex) -{ - CaretAssertVectorIndex(m_windowStatus, windowIndex); - return &m_windowStatus[windowIndex]; -} - - -/** - * Setup this instance with the given windows, the tabs in the windows, and - * the given annotations. - * - * @param windows - * Open browser windows. - * @param annotations - * All annotations. - */ -void -EventTabAndWindowLockAspectRatioStatus::setup(const std::vector& windows, - const std::vector& annotations) -{ - /* - * Find tab and window annotations - */ - std::vector tabAnnotationFlag(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, false); - std::vector windowAnnotationFlag(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, false); - - for (const auto ann : annotations) { - switch (ann->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - CaretAssertVectorIndex(tabAnnotationFlag, ann->getTabIndex()); - tabAnnotationFlag[ann->getTabIndex()] = true; - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - CaretAssertVectorIndex(windowAnnotationFlag, ann->getWindowIndex()); - windowAnnotationFlag[ann->getWindowIndex()] = true; - break; - } - } - - /* - * Set tab/window status. - */ - for (const auto bbw : windows) { - if (bbw != NULL) { - const int32_t windowIndex = bbw->getBrowserWindowIndex(); - const bool windowAspectLocked = bbw->isWindowAspectRatioLocked(); - const bool tileTabsEnabled = bbw->isTileTabsSelected(); - CaretAssertVectorIndex(windowAnnotationFlag, windowIndex); - WindowStatus* windowStatus = getWindowStatus(windowIndex); - windowStatus->setStatus(windowIndex, - windowAspectLocked, - tileTabsEnabled, - windowAnnotationFlag[windowIndex]); - - std::vector allTabs; - bbw->getAllTabContent(allTabs); - - for (const auto tab : allTabs) { - const int32_t tabIndex = tab->getTabNumber(); - const bool tabAspectLocked = tab->isAspectRatioLocked(); - - CaretAssertVectorIndex(tabAnnotationFlag, tabIndex); - TabStatus* tabStatus = getTabStatus(tabIndex); - tabStatus->setStatus(tabIndex, - windowIndex, - tabAspectLocked, - tabAnnotationFlag[tabIndex]); - } - } - } -} - diff --git a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h b/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h deleted file mode 100644 index 92b30f11e..000000000 --- a/src/GuiQt/EventTabAndWindowLockAspectRatioStatus.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ -#define __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2018 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - - -#include - -#include "Event.h" - - - -namespace caret { - - class Annotation; - class BrainBrowserWindow; - - class EventTabAndWindowLockAspectRatioStatus : public Event { - - public: - class TabStatus { - public: - TabStatus() { } - - void setStatus(const int32_t tabIndex, - const int32_t windowIndex, - const bool lockAspectRatioStatus, - const bool containsTabSpaceAnnotationsFlag) { - m_tabIndex = tabIndex; - m_windowIndex = windowIndex; - m_lockAspectRatioStatus = lockAspectRatioStatus; - m_containsTabSpaceAnnotationsFlag = containsTabSpaceAnnotationsFlag; - } - - bool isValid() { return (m_tabIndex >= 0); } - - int32_t getTabIndex() const { return m_tabIndex; } - - int32_t getWindowIndex() const { return m_windowIndex; } - - bool isAspectRatioLocked() const { return m_lockAspectRatioStatus; } - - bool hasTabSpaceAnnotations() const { return m_containsTabSpaceAnnotationsFlag; } - - private: - int32_t m_tabIndex = -1; - int32_t m_windowIndex = -1; - bool m_lockAspectRatioStatus = false; - bool m_containsTabSpaceAnnotationsFlag = false; - }; - - class WindowStatus { - public: - WindowStatus() { } - - void setStatus(const int32_t windowIndex, - const bool lockAspectRatioStatus, - const bool tileTabsEnabled, - const bool containsWindowSpaceAnnotationsFlag) { - m_windowIndex = windowIndex; - m_lockAspectRatioStatus = lockAspectRatioStatus; - m_tileTabsEnabled = tileTabsEnabled; - m_containsWindowSpaceAnnotationsFlag = containsWindowSpaceAnnotationsFlag; - } - - bool isValid() { return (m_windowIndex >= 0); } - - int32_t getWindowIndex() const { return m_windowIndex; } - - bool isAspectRatioLocked() const { return m_lockAspectRatioStatus; } - - bool isTileTabsEnabled() const { return m_tileTabsEnabled; } - - bool hasWindowSpaceAnnotations() const { return m_containsWindowSpaceAnnotationsFlag; } - - void addTabStatus(const TabStatus* tabStatus) { m_tabs.push_back(tabStatus); } - - int32_t getTabCount() const { return m_tabs.size(); } - - int32_t getTabLockedCount() const { - const int32_t tabLockedCount = std::count_if(m_tabs.begin(), - m_tabs.end(), - [](const TabStatus* ts) { return ts->isAspectRatioLocked(); }); - return tabLockedCount; - } - - private: - int32_t m_windowIndex = -1; - bool m_lockAspectRatioStatus = false; - bool m_tileTabsEnabled = false; - bool m_containsWindowSpaceAnnotationsFlag = false; - std::vector m_tabs; - }; - - EventTabAndWindowLockAspectRatioStatus(); - - virtual ~EventTabAndWindowLockAspectRatioStatus(); - - void setup(const std::vector& windows, - const std::vector& annotations); - - TabStatus* getTabStatus(const int32_t tabIndex); - - WindowStatus* getWindowStatus(const int32_t windowIndex); - - // ADD_NEW_METHODS_HERE - - private: - EventTabAndWindowLockAspectRatioStatus(const EventTabAndWindowLockAspectRatioStatus&); - - EventTabAndWindowLockAspectRatioStatus& operator=(const EventTabAndWindowLockAspectRatioStatus&); - - std::vector m_tabStatus; - - std::vector m_windowStatus; - - // ADD_NEW_MEMBERS_HERE - - }; - -#ifdef __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ - // -#endif // __EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_DECLARE__ - -} // namespace -#endif //__EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS_H__ diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 51ce0c55b..70bc95358 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -79,7 +79,6 @@ #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventProgressUpdate.h" #include "EventSurfaceColoringInvalidate.h" -#include "EventTabAndWindowLockAspectRatioStatus.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "FociPropertiesEditorDialog.h" @@ -298,7 +297,6 @@ GuiManager::initializeGuiManager() EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } @@ -1479,42 +1477,8 @@ GuiManager::receiveEvent(Event* event) warningEvent->setEventProcessed(); } - else if (event->getEventType() == EventTypeEnum::EVENT_TAB_AND_WINDOW_LOCK_ASPECT_RATIO_STATUS) { - EventTabAndWindowLockAspectRatioStatus* lockStatusEvent = dynamic_cast(event); - CaretAssert(lockStatusEvent); - - loadLockStatusEvent(lockStatusEvent); - - lockStatusEvent->setEventProcessed(); - } -} - -/** - * Load the lock aspect status event. - * - * @param lockStatusEvent - * The lock status event. - */ -void -GuiManager::loadLockStatusEvent(EventTabAndWindowLockAspectRatioStatus* lockStatusEvent) -{ - CaretAssert(lockStatusEvent); - - const std::vector annotations = getBrain()->getAnnotationManager()->getAllAnnotations(); - - std::vector openWindows; - for (const auto bbw : m_brainBrowserWindows) { - if (bbw != NULL) { - openWindows.push_back(bbw); - } - } - - lockStatusEvent->setup(openWindows, - annotations); } - - /** * Remove the tab content from all browser windows except for the given * browser windows, close the other browser windows, and then return diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index d4f832ce7..2a79a8cc2 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -49,7 +49,6 @@ namespace caret { class ClippingPlanesDialog; class CursorManager; class CustomViewDialog; - class EventTabAndWindowLockAspectRatioStatus; class GapsAndMarginsDialog; class HelpViewerDialog; class IdentifyBrainordinateDialog; @@ -231,8 +230,6 @@ namespace caret { void addParentLessNonModalDialog(QWidget* dialog); - void loadLockStatusEvent(EventTabAndWindowLockAspectRatioStatus* lockStatusEvent); - /** One instance of the GuiManager */ static GuiManager* singletonGuiManager; -- GitLab From ea8773f0c0e0159f630b0110620884a691863e56 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 14 Feb 2018 09:35:13 -0600 Subject: [PATCH 627/755] WB-777 Performance problems limited to scrolling volume slices: Removed duplicate graphics updates from toolbar including volume slices. The problem is not seen on Mac but is still there on Linux. On a Linux computer holding down an arrow key and releasing it results in 5 or 10 seconds of the slices continuing to scroll. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 46 +++++++++---------- src/GuiQt/BrainBrowserWindowToolBar.h | 2 +- ...rowserWindowToolBarChartTwoOrientation.cxx | 40 +--------------- ...BrainBrowserWindowToolBarChartTwoTitle.cxx | 3 +- .../BrainBrowserWindowToolBarClipping.cxx | 3 +- .../BrainBrowserWindowToolBarComponent.cxx | 7 +-- .../BrainBrowserWindowToolBarComponent.h | 2 +- .../BrainBrowserWindowToolBarSlicePlane.cxx | 9 ++-- ...rainBrowserWindowToolBarSliceSelection.cxx | 24 ++++------ ...BrainBrowserWindowToolBarVolumeMontage.cxx | 12 ++--- 10 files changed, 47 insertions(+), 101 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 0395a030e..7af465847 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -3530,7 +3530,7 @@ BrainBrowserWindowToolBar::orientationLeftOrLateralToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3541,7 +3541,7 @@ BrainBrowserWindowToolBar::orientationRightOrMedialToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->rightView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3552,7 +3552,7 @@ BrainBrowserWindowToolBar::orientationAnteriorToolButtonTriggered(bool /*checked { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3563,7 +3563,7 @@ BrainBrowserWindowToolBar::orientationPosteriorToolButtonTriggered(bool /*checke { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->posteriorView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3574,7 +3574,7 @@ BrainBrowserWindowToolBar::orientationDorsalToolButtonTriggered(bool /*checked*/ { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3585,7 +3585,7 @@ BrainBrowserWindowToolBar::orientationVentralToolButtonTriggered(bool /*checked* { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->ventralView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3600,7 +3600,7 @@ BrainBrowserWindowToolBar::orientationResetToolButtonTriggered(bool /*checked*/) Model* mdc = btc->getModelForDisplay(); if (mdc != NULL) { this->updateVolumeIndicesWidget(btc); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } } @@ -3612,7 +3612,7 @@ BrainBrowserWindowToolBar::orientationLateralMedialToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3623,7 +3623,7 @@ BrainBrowserWindowToolBar::orientationDorsalVentralToolButtonTriggered(bool /*ch { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3634,7 +3634,7 @@ BrainBrowserWindowToolBar::orientationAnteriorPosteriorToolButtonTriggered(bool { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3675,7 +3675,7 @@ BrainBrowserWindowToolBar::customViewActionTriggered() if (prefs->getCustomView(customViewName, modelTransform)) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setTransformationsFromModelTransform(modelTransform); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } } } @@ -3703,7 +3703,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx* if (isValid) { wholeBrainModel->setSelectedSurfaceType(tabIndex, surfaceType); this->updateVolumeIndicesWidget(btc); /* slices may get deselected */ - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } } } @@ -3722,7 +3722,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state } btc->setWholeBrainLeftEnabled(this->wholeBrainSurfaceLeftCheckBox->isChecked()); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3769,7 +3769,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*check wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_LEFT, tabIndex, surfaces[i]); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); break; } } @@ -3822,7 +3822,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*chec wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_RIGHT, tabIndex, surfaces[i]); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); break; } } @@ -3875,7 +3875,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool / wholeBrainModel->setSelectedSurface(StructureEnum::CEREBELLUM, tabIndex, surfaces[i]); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); break; } } @@ -3898,7 +3898,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceRightCheckBoxStateChanged(int /*stat } btc->setWholeBrainRightEnabled(this->wholeBrainSurfaceRightCheckBox->isChecked()); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3915,7 +3915,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumCheckBoxStateChanged(int / } btc->setWholeBrainCerebellumEnabled(this->wholeBrainSurfaceCerebellumCheckBox->isChecked()); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3932,7 +3932,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationLeftRightSpinBoxValueChang } btc->setWholeBrainLeftRightSeparation(this->wholeBrainSurfaceSeparationLeftRightSpinBox->value()); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -3949,7 +3949,7 @@ BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationCerebellumSpinBoxSelected( } btc->setWholeBrainCerebellumSeparation(this->wholeBrainSurfaceSeparationCerebellumSpinBox->value()); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -4158,11 +4158,11 @@ BrainBrowserWindowToolBar::getTabBarIndexWithBrowserTabIndex(const int32_t brows } /** - * If this windows is yoked, issue an event to update other - * windows that are using the same yoking. + * If this window is yoked, update all windows since they may + * be yoked to this window. If NOT yoked, just update this window. */ void -BrainBrowserWindowToolBar::updateOtherYokedWindows() +BrainBrowserWindowToolBar::updateGraphicsWindowAndYokedWindows() { BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 3c4e6c0bd..d7bfe5410 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -133,11 +133,11 @@ namespace caret { Model* controller); void updateGraphicsWindow(); + void updateGraphicsWindowAndYokedWindows(); void updateUserInterface(); void updateToolBox(); void updateAllTabNames(); void updateTabName(const int32_t tabIndex); - void updateOtherYokedWindows(); QWidget* createViewWidget(); QWidget* createOrientationWidget(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx index b829cdd0e..ea4313238 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx @@ -113,8 +113,7 @@ BrainBrowserWindowToolBarChartTwoOrientation::orientationResetToolButtonTriggere { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->resetView(); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -124,42 +123,5 @@ void BrainBrowserWindowToolBarChartTwoOrientation::customViewActionTriggered() { m_parentToolBar->customViewActionTriggered(); -// CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); -// prefs->readCustomViews(); -// const std::vector > customViewNameAndComments = prefs->getCustomViewNamesAndComments(); -// -// QMenu menu; -// -// QAction* editAction = menu.addAction("Create and Edit..."); -// editAction->setToolTip("Add and delete Custom Views.\n" -// "Edit model transformations."); -// -// const int32_t numViews = static_cast(customViewNameAndComments.size()); -// if (numViews > 0) { -// menu.addSeparator(); -// } -// for (int32_t i = 0; i < numViews; i++) { -// QAction* action = menu.addAction(customViewNameAndComments[i].first); -// action->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customViewNameAndComments[i].second)); -// } -// -// QAction* selectedAction = menu.exec(QCursor::pos()); -// if (selectedAction != NULL) { -// if (selectedAction == editAction) { -// BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); -// GuiManager::get()->processShowCustomViewDialog(bbw); -// } -// else { -// const AString customViewName = selectedAction->text(); -// -// ModelTransform modelTransform; -// if (prefs->getCustomView(customViewName, modelTransform)) { -// BrowserTabContent* btc = this->getTabContentFromSelectedTab(); -// btc->setTransformationsFromModelTransform(modelTransform); -// this->updateGraphicsWindow(); -// this->updateOtherYokedWindows(); -// } -// } -// } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx index 816ee0f43..2e1e2b9cb 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx @@ -219,6 +219,5 @@ BrainBrowserWindowToolBarChartTwoTitle::performUpdating() EventManager::get()->sendEvent(attributesEvent.getPointer()); } - this->updateOtherYokedWindows(); - this->updateGraphicsWindow(); + this->updateGraphicsWindowAndYokedWindows(); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx index 8cdd370db..a671d9f81 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx @@ -180,8 +180,7 @@ BrainBrowserWindowToolBarClipping::clippingCheckBoxCheckStatusChanged() m_volumeClippingEnabledCheckBox->isChecked(), m_featuresClippingEnabledCheckBox->isChecked()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } } diff --git a/src/GuiQt/BrainBrowserWindowToolBarComponent.cxx b/src/GuiQt/BrainBrowserWindowToolBarComponent.cxx index 508e8d8f1..3ac368a52 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarComponent.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarComponent.cxx @@ -137,12 +137,13 @@ BrainBrowserWindowToolBarComponent::updateGraphicsWindow() } /** - * Update toolbars in other yoked windows. + * If this window is yoked, update all windows since they may + * be yoked to this window. If NOT yoked, just update this window. */ void -BrainBrowserWindowToolBarComponent::updateOtherYokedWindows() +BrainBrowserWindowToolBarComponent::updateGraphicsWindowAndYokedWindows() { - m_parentToolBar->updateOtherYokedWindows(); + m_parentToolBar->updateGraphicsWindowAndYokedWindows(); } /** diff --git a/src/GuiQt/BrainBrowserWindowToolBarComponent.h b/src/GuiQt/BrainBrowserWindowToolBarComponent.h index 03496f2ec..7c7763257 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarComponent.h +++ b/src/GuiQt/BrainBrowserWindowToolBarComponent.h @@ -51,7 +51,7 @@ namespace caret { void updateGraphicsWindow(); - void updateOtherYokedWindows(); + void updateGraphicsWindowAndYokedWindows(); void updateUserInterface(); diff --git a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx index 5e9c89098..295683bfa 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx @@ -253,8 +253,7 @@ BrainBrowserWindowToolBarSlicePlane::viewAllSliceLayoutMenuTriggered(QAction* ac btc->setSlicePlanesAllViewLayout(layout); m_parentToolBar->updateVolumeIndicesWidget(btc); - updateGraphicsWindow(); - updateOtherYokedWindows(); + updateGraphicsWindowAndYokedWindows(); } else { CaretLogSevere("Invalid layout in menu item: " @@ -310,8 +309,7 @@ BrainBrowserWindowToolBarSlicePlane::volumePlaneActionGroupTriggered(QAction* ac btc->setSliceViewPlane(plane); m_parentToolBar->updateVolumeIndicesWidget(btc); - updateGraphicsWindow(); - updateOtherYokedWindows(); + updateGraphicsWindowAndYokedWindows(); } /** @@ -324,7 +322,6 @@ BrainBrowserWindowToolBarSlicePlane::volumePlaneResetToolButtonTriggered(bool /* btc->resetView(); m_parentToolBar->updateVolumeIndicesWidget(btc); - updateGraphicsWindow(); - updateOtherYokedWindows(); + updateGraphicsWindowAndYokedWindows(); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index d32db99fd..43973a4f6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -440,8 +440,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesOriginActionTriggered() btc->setSlicesToOrigin(); updateContent(btc); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -452,8 +451,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesParasagittalCheckBoxStateC { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceParasagittalEnabled(m_volumeIndicesParasagittalCheckBox->isChecked()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -464,8 +462,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesCoronalCheckBoxStateChange { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceCoronalEnabled(m_volumeIndicesCoronalCheckBox->isChecked()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -476,8 +473,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialCheckBoxStateChanged( { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceAxialEnabled(m_volumeIndicesAxialCheckBox->isChecked()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -631,8 +627,7 @@ BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoo this->updateSliceIndicesAndCoordinatesRanges(); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -672,8 +667,7 @@ BrainBrowserWindowToolBarSliceSelection::readVolumeSliceCoordinatesAndUpdateSlic this->updateSliceIndicesAndCoordinatesRanges(); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -685,8 +679,7 @@ BrainBrowserWindowToolBarSliceSelection::volumeSliceProjectionTypeEnumComboBoxIt BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = m_volumeSliceProjectionTypeEnumComboBox->getSelectedItem(); btc->setSliceProjectionType(sliceProjectionType); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); updateObliqueMaskingButton(); EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); } @@ -746,8 +739,7 @@ BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) CaretAssert(validFlag); browserTabContent->setVolumeSliceInterpolationEdgeEffectsMaskingType(maskType); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx index 9b80ad4c6..77664f67a 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx @@ -162,8 +162,7 @@ BrainBrowserWindowToolBarVolumeMontage::montageEnabledActionToggled(bool) btc->setSliceDrawingType(drawingType); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } @@ -177,8 +176,7 @@ BrainBrowserWindowToolBarVolumeMontage::montageRowsSpinBoxValueChanged(int /*i*/ btc->setMontageNumberOfRows(m_montageRowsSpinBox->value()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -190,8 +188,7 @@ BrainBrowserWindowToolBarVolumeMontage::montageColumnsSpinBoxValueChanged(int /* BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setMontageNumberOfColumns(m_montageColumnsSpinBox->value()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } /** @@ -204,7 +201,6 @@ BrainBrowserWindowToolBarVolumeMontage::montageSpacingSpinBoxValueChanged(int /* btc->setMontageSliceSpacing(m_montageSpacingSpinBox->value()); - this->updateGraphicsWindow(); - this->updateOtherYokedWindows(); + this->updateGraphicsWindowAndYokedWindows(); } -- GitLab From 67301b736bd85b9b1c8899b119a5e6eca606eca1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Feb 2018 09:27:52 -0600 Subject: [PATCH 628/755] Resolve WB-777 Performance problems limited to scrolling volume slices: In the toolbar, there are spin boxes for slice indices and coordinates. When the user changes a slice index, the corresponding coordinate must be updated and vice verse. There is a bug with spin boxes in Qt (QTBUG-14529) that results in the spin box issuing two value changed signals when the slot takes 'long' time to execute. There is also a problem with that if one updates the range (min/max) of a spin box, a signal is emitted even though the spin box has its signals blocked. The combination of these problems resulted in a backup of key events when the user holds down an arrow key in a spin box, and, after the user releases the key, many key events are received and the slice continue to scroll for a few seconds. When updating the spin boxes, the ranges (minimum and maximum) values are updated only if they are different than the current range of the spin box. This has eliminated the signal caused by avoiding update of the spin boxes range and prevents the volumes slices from scrolling when the arrow key is released. This problem with the slices continuing to scroll was only seen on Linux and not on Mac even though Mac still had the problem with the signals (windows unknown). --- ...rainBrowserWindowToolBarSliceSelection.cxx | 87 +++++++++++++++---- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx index 43973a4f6..edcbf779f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx @@ -361,12 +361,41 @@ BrainBrowserWindowToolBarSliceSelection::updateSliceIndicesAndCoordinatesRanges( int maxCoronalDim = (dimensions[1] > 0) ? (dimensions[1] - 1) : 0; int maxParasagittalDim = (dimensions[0] > 0) ? (dimensions[0] - 1) : 0; - m_volumeIndicesAxialSpinBox->setRange(minAxialDim, - maxAxialDim); - m_volumeIndicesCoronalSpinBox->setRange(minCoronalDim, - maxCoronalDim); - m_volumeIndicesParasagittalSpinBox->setRange(minParasagittalDim, - maxParasagittalDim); + /* + * BUG NOTE: + * On Linux, if the user hold down an arrow key in a spin box + * and the time to process the signal is "slow", qt will emit + * a second signal (QTBUG-14259). In addition, calling any of + * the setMinimum(), setMaximum(), or setRange() methods seems + * to also cause emission of a signal. The result when the + * user releases the arrow key, there are many backlogged signals + * and it may take a while for them to process and the user + * sees the slices scrolling for a while after the arrow key + * is released. + * + * So, do not update range min/max unless the new range + * is different than the range in the spin box. + */ + if (m_volumeIndicesAxialSpinBox->minimum() != minAxialDim) { + m_volumeIndicesAxialSpinBox->setMinimum(minAxialDim); + } + if (m_volumeIndicesAxialSpinBox->maximum() != maxAxialDim) { + m_volumeIndicesAxialSpinBox->setMaximum(maxAxialDim); + } + + if (m_volumeIndicesCoronalSpinBox->minimum() != minCoronalDim) { + m_volumeIndicesCoronalSpinBox->setMinimum(minCoronalDim); + } + if (m_volumeIndicesCoronalSpinBox->maximum() != maxCoronalDim) { + m_volumeIndicesCoronalSpinBox->setMaximum(maxCoronalDim); + } + + if (m_volumeIndicesParasagittalSpinBox->minimum() != minParasagittalDim) { + m_volumeIndicesParasagittalSpinBox->setMinimum(minParasagittalDim); + } + if (m_volumeIndicesParasagittalSpinBox->maximum() != maxParasagittalDim) { + m_volumeIndicesParasagittalSpinBox->setMaximum(maxParasagittalDim); + } /* @@ -382,19 +411,40 @@ BrainBrowserWindowToolBarSliceSelection::updateSliceIndicesAndCoordinatesRanges( vf->indexToSpace(slicesMax, sliceMaxCoords); - m_volumeIndicesXcoordSpinBox->setMinimum(std::min(sliceZeroCoords[0], - sliceMaxCoords[0])); - m_volumeIndicesYcoordSpinBox->setMinimum(std::min(sliceZeroCoords[1], - sliceMaxCoords[1])); - m_volumeIndicesZcoordSpinBox->setMinimum(std::min(sliceZeroCoords[2], - sliceMaxCoords[2])); + const double minX = std::min(sliceZeroCoords[0], + sliceMaxCoords[0]); + const double maxX = std::max(sliceZeroCoords[0], + sliceMaxCoords[0]); + const double minY = std::min(sliceZeroCoords[1], + sliceMaxCoords[1]); + const double maxY = std::max(sliceZeroCoords[1], + sliceMaxCoords[1]); + const double minZ = std::min(sliceZeroCoords[2], + sliceMaxCoords[2]); + const double maxZ = std::max(sliceZeroCoords[2], + sliceMaxCoords[2]); - m_volumeIndicesXcoordSpinBox->setMaximum(std::max(sliceZeroCoords[0], - sliceMaxCoords[0])); - m_volumeIndicesYcoordSpinBox->setMaximum(std::max(sliceZeroCoords[1], - sliceMaxCoords[1])); - m_volumeIndicesZcoordSpinBox->setMaximum(std::max(sliceZeroCoords[2], - sliceMaxCoords[2])); + /* + * See BUG NOTE above. + */ + if (m_volumeIndicesXcoordSpinBox->minimum() != minX) { + m_volumeIndicesXcoordSpinBox->setMinimum(minX); + } + if (m_volumeIndicesXcoordSpinBox->maximum() != maxX) { + m_volumeIndicesXcoordSpinBox->setMaximum(maxX); + } + if (m_volumeIndicesYcoordSpinBox->minimum() != minY) { + m_volumeIndicesYcoordSpinBox->setMinimum(minY); + } + if (m_volumeIndicesYcoordSpinBox->maximum() != maxY) { + m_volumeIndicesYcoordSpinBox->setMaximum(maxY); + } + if (m_volumeIndicesZcoordSpinBox->minimum() != minZ) { + m_volumeIndicesZcoordSpinBox->setMinimum(minZ); + } + if (m_volumeIndicesZcoordSpinBox->maximum() != maxZ) { + m_volumeIndicesZcoordSpinBox->setMaximum(maxZ); + } int64_t slicesOne[3] = { 1, 1, 1 }; float slicesOneCoords[3]; @@ -424,7 +474,6 @@ BrainBrowserWindowToolBarSliceSelection::updateSliceIndicesAndCoordinatesRanges( m_volumeIndicesXcoordSpinBox->setValue(btc->getSliceCoordinateParasagittal()); m_volumeIndicesYcoordSpinBox->setValue(btc->getSliceCoordinateCoronal()); m_volumeIndicesZcoordSpinBox->setValue(btc->getSliceCoordinateAxial()); - } m_volumeIndicesWidgetGroup->blockAllSignals(blockedStatus); -- GitLab From baaaf28d12018122e14b7e4869f885b9dd73513d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Feb 2018 09:53:17 -0600 Subject: [PATCH 629/755] limit height of scene preview dialog so that it does not take up the full height of the display and so that the close button is visible. --- src/GuiQt/ScenePreviewDialog.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GuiQt/ScenePreviewDialog.cxx b/src/GuiQt/ScenePreviewDialog.cxx index 2090196ad..7d04eb6f8 100644 --- a/src/GuiQt/ScenePreviewDialog.cxx +++ b/src/GuiQt/ScenePreviewDialog.cxx @@ -33,6 +33,7 @@ #include "Scene.h" #include "SceneDialog.h" #include "SceneInfo.h" +#include "WuQtUtilities.h" using namespace caret; @@ -122,6 +123,8 @@ ScenePreviewDialog::ScenePreviewDialog(const Scene* scene, } setCentralWidget(widget, SCROLL_AREA_ALWAYS); + + WuQtUtilities::limitWindowSizePercentageOfMaximum(this, 90.0, 80.0); } /** -- GitLab From c1a9ef01b34d8d4f8b862f836214d568b34791e9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Feb 2018 12:04:12 -0600 Subject: [PATCH 630/755] Updates to the best practices text --- src/GuiQt/BestPracticesDialog.cxx | 101 +++++++++++++------------- src/GuiQt/LockAspectWarningDialog.cxx | 19 ----- 2 files changed, 52 insertions(+), 68 deletions(-) diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx index 56d2fe55a..f9ba87933 100644 --- a/src/GuiQt/BestPracticesDialog.cxx +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -27,6 +27,8 @@ #include #include "CaretAssert.h" +#include "WuQtUtilities.h" + using namespace caret; @@ -64,9 +66,12 @@ m_textMode(TextMode::FULL) QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(label); - widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + +// widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setCentralWidget(widget, WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); + + WuQtUtilities::limitWindowSizePercentageOfMaximum(this, 90.0, 80.0); } /** @@ -105,9 +110,9 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) { switch (textMode) { case BRIEF: - introText = ("Aspect is unlocked and it is strongly recommended that aspect is locked and is never unlocked " + introText = ("Aspect is unlocked and it is strongly recommended that aspect is locked and remains locked " "when annotations are present. Failing to lock aspect or unlocking the aspect may " - "cause annotations to move from their original locations." + "cause annotations to move from their original locations when the graphics region size changes." "

    " "When creating annotations and scenes, follow these best practices:"); break; @@ -116,10 +121,10 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) "PowerPoint allows one to create a presentation consisting of slides saved into a PowerPoint file. " "These slides are annotated with text and various shapes. In wb_view, a scene is analogous " "to a PowerPoint slide and a Scene File contains multiple scenes just like a PowerPoint " - "file contains multiple slides. In wb_view, one annotates a scene just like one " - "annotates a slide in PowerPoint. A wb_view Scene saves ‘the state’ so that when " - "the scene is loaded at a later time, by either the creator of the scene or another " - "user, the user-interface and brain models replicate ‘the state’ at the time the " + "file contains multiple slides. In wb_view, one annotates a scene similar to the way one " + "annotates a slide in PowerPoint. A Scene saves ‘the state’ of wb_view so that when " + "the scene is loaded at a later time, by either the creator of the scene or another " + "user, the user-interface and the orientation of the brain models replicates ‘the state’ at the time the " "scene was created." "

    " "When creating scenes and annotations, following a set of “best practices†ensures " @@ -132,15 +137,15 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) std::vector bulletLines; { - AString text("If desired, enter Tile Tabs for a multi-tab Scene (View Menu->Enter Tile Tabs). "); + AString text("If a multi-tab scene will be created, enter Tile Tabs (View Menu->Enter Tile Tabs). "); switch (textMode) { case BRIEF: break; case FULL: - text.append("Tile Tabs displays all of the windows tabs in a grid pattern. " + text.append("Tile Tabs displays all of the window's tabs in a grid pattern. " "The number of row and columns in the Tile Tabs view is edited on the " - "Tile Tabs Configuration Dialog (View Menu->Tile Tabs Configuration->Create and Edit. " - "Advanced parameters are available for “stretch factors†that allow one to increase the " + "Tile Tabs Configuration Dialog (View Menu->Tile Tabs Configuration->Create and Edit). " + "Advanced parameters include “stretch factors†that allow one to increase the " "size of a row or column relative to other rows and columns. One may also save the " "configuration for future use. If a scene is created, the configuration is added to the scene " "so that the configuration is available when the scene is displayed."); @@ -168,10 +173,10 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) AString text; switch (textMode) { case BRIEF: - text = ("Setup view of the model(s) (pan/rotate/zoom). "); + text = ("Setup view of the models (pan/rotate/zoom). "); break; case FULL: - text = ("Setup view(s) of the model(s). " + text = ("Setup viewa of the models. " "Pan (drag mouse with SHIFT key down), " "Rotate (drag mouse), " "Zoom (drag mouse with Control Key. Use the Command Key on Mac."); @@ -186,18 +191,17 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) case BRIEF: break; case FULL: - text.append("As a general rule, one should never disable aspect locking once the " - "aspect has been locked. By following this rule, tab and window annotations " - "will remain in the desired location. When a window is resized, the window may " - "change in size that is a different proportion (ratio of height to width) " - "compared to the model that is viewed. Annotations in tab and window spaces " + text.append("As a general rule, once the aspect ratio is locked, it should remain locked. " + "The aspect ratio is the ratio of height divided by width. " + "Annotations in tab and window spaces " "are positioned using percentage coordinates that range from 0% to 100% with " "0% at the left (x) and bottom (y) and 100% at the right (x) and top (y). " - "When the window size changes, annotations in tab/window space may no longer " + "If the window is resized with the aspect ratio unlocked and there is a change " + "in the aspect ratio, annotations in tab/window space may no longer " "appear in the correct location (such as over an anatomical feature). Locking " - "the tab or window’s aspect ratio adds padding to the left and right or bottom " + "the aspect ratio adds padding to the left and right or bottom " "and top of the graphics region so that the model’s region maintains the same " - "aspect ratio (ratio of height to width). Locking the aspect ratio ensures that " + "aspect ratio (ratio of height to width). This ensures that " "annotations remain in the correct location relative to the viewed brain model. "); break; } @@ -205,65 +209,64 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) } { - AString text("Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes) and set " - "the name and path of the new Scene File. "); + AString text("Enter Annotations Mode (click Annotate button in Toolbar). "); switch (textMode) { case BRIEF: break; case FULL: - text.append("To set the name of the New Scene File, click the Save As button. " - "In the file selection dialog, choose the directory, and enter a descriptive " - "name for the Scene File. It is best for the Scene File to be in the same " - "directory or the parent directory of the directory containing your data files. " - "If the data files are scattered about many directories, it may cause problems " - "if the Scene File and its data files are zipped for distribution to others " - "or when uploading the BALSA Database"); break; } bulletLines.push_back(text); } { - AString text("Enter Annotations Mode (click Annotate button in Toolbar). "); + AString text; switch (textMode) { case BRIEF: + text = ("Add Annotations."); break; case FULL: + text = ("To add annotations, click any of the Space and/or Type icons in the Insert New section " + "of the Annotation Toolbar and then click in graphics region to create the annotation. " + "A new annotation is automatically selected so that it can be moved/resized with " + "the mouse or its attributes changed using controls in the toolbar."); break; } bulletLines.push_back(text); } { - AString text; + AString text("Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes) and " + "add a Scene (click Add button on Scene Dialog). "); switch (textMode) { case BRIEF: - text = ("Add Annotations."); break; case FULL: - text = ("To add annotations, click the Space and/or Type icons in the Insert New section " - "of the Annotation Toolbar and then click in graphics region to create the annotation. " - "A new annotation is automatically selected so that it can be moved/resized with " - "the mouse or its attributes changed using controls in the toolbar."); + text.append("In the Create New Scene Dialog, edit the name and description for the new scene and then " + "press the OK button. Note that by default, new annotations are added to " + "the current scene and stored in the scene file. If one wants to place annotations into a disk file, " + "click the small arrow to the right of the Scene button in the Insert New " + "section of the Toolbar. When the arrow is clicked, a menu is displayed " + "for creating and/or selecting a disk annotation file."); break; } bulletLines.push_back(text); } { - AString text("Add a Scene (click Add button on Scene Dialog). "); + AString text("Save the Scene File. Click Save As button the first time to set the path and name of the scene file. " + "Once path and name of scene file has been set, use the Save button."); switch (textMode) { case BRIEF: break; case FULL: - text.append("In the Create New Scene Dialog, edit the name and description and then " - "press the OK button. If a Scene File was created as described in a " - "previous step, click the Save button at the top of the Scene Dialog to " - "save the Scene File. Note that by default new annotations are added to " - "the current scene. If one wants to place annotations into a disk file, " - "click the small arrow to the right of the Scene button in the Insert New " - "section of the Toolbar. When the arrow is clicked, a menu is displayed " - "for creating and/or selecting a disk annotation file."); + text.append("To set the name of the New Scene File, click the Save As button. " + "In the file selection dialog, choose the directory, and enter a descriptive " + "name for the Scene File. It is best for the Scene File to be in the same " + "directory or the parent directory of the directory containing your data files. " + "If the data files are scattered about many directories, it may cause problems " + "if the Scene File and its data files are zipped for distribution to others " + "or when uploading the BALSA Database"); break; } bulletLines.push_back(text); @@ -284,7 +287,7 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) AString text; switch (textMode) { case BRIEF: - text = ("Save the Scene File (click Save button (or Save As if Save is disabled) at top of Scene Dialog)."); + text = ("Be sure to save the Scene File (click Save button or Save As if Save is disabled at top of Scene Dialog)."); break; case FULL: text = ("If the Save button at the top of the Scene Dialog is enabled, the Scene File is in a " @@ -350,7 +353,7 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) "the correct location. To correct this problem, wb_view supports “locking " "of the aspect ratioâ€. When the aspect ratio is locked, the window (and " "each tab within the window) are fixed to the aspect ratio at the time " - "aspect locking is enabled just like PowerPoint. If the size of the window changes while " + "aspect locking is enabled. If the size of the window changes while " "the aspect is locked, the contents of window and each tab will expand or " "contract in size but maintain a fixed aspect by adding space to sides " "of the model when needed."); @@ -368,7 +371,7 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) "save the annotations to the scene instead of creating a disk annotation file. "); break; } - bulletLines.push_back(text); + msg.append(text); } msg.appendWithNewLine(""); diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index efd22c7f9..11ea8c6bd 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -119,25 +119,6 @@ LockAspectWarningDialog::LockAspectWarningDialog(QWidget* parent) const AString msg = BestPracticesDialog::getTextForInfoMode(BestPracticesDialog::InfoMode::LOCK_ASPECT_BEST_PRACTICES, BestPracticesDialog::TextMode::BRIEF); -// const AString msg("" -// "Aspect is unlocked and it is strongly recommended that aspect is locked and is never unlocked " -// "when annotations are present. Failing to lock aspect or unlocking the aspect may " -// "cause annotations to move from their original locations." -// "

    " -// "When creating annotations and scenes, follow these best practices:" -// "

      " -// "
    1. If desired, enter Tile Tabs for a multi-tab Scene (View Menu->Enter Tile Tabs)" -// "
    2. Adjust size of window" -// "
    3. Setup view of the model(s) (pan/rotate/zoom)" -// "
    4. Lock Aspect Ratio (click Lock Aspect button in right side of Toolbar)" -// "
    5. Enter Annotations Mode (click Annotate button in Toolbar)" -// "
    6. Add Annotations" -// "
    7. Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes)" -// "
    8. Add a Scene (click Add button on Scene Dialog)" -// "
    9. Save the Scene File (click Save button (or Save As if Save is disabled) at top of Scene Dialog)" -// "
    10. Repeat last few steps as needed" -// "
    " -// ""); QLabel* warningLabel = new QLabel(msg); warningLabel->setWordWrap(true); -- GitLab From bc522f0f8305a61da59b5b7004465b147cf86b23 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 16 Feb 2018 10:04:03 -0600 Subject: [PATCH 631/755] Fixed crash of loading older scene that did not contain a window index in the scene file. --- src/Brain/SessionManager.cxx | 11 ++++- src/GuiQt/GuiManager.cxx | 81 ++++++++++++++++++++++++++++-------- src/GuiQt/GuiManager.h | 7 +--- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 1f7004e72..abfe27e9c 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -856,11 +856,20 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClassArray* browserWindowArray = guiManagerClass->getClassArray("m_brainBrowserWindows"); if (browserWindowArray != NULL) { + { + const int32_t numValidBrowserWindows = std::count_if(m_browserWindowContent.begin(), + m_browserWindowContent.end(), + [](BrowserWindowContent* bwc) { return bwc->isValid(); }); + std::cout << "RESTORING OLD SCENE NUM WINDOWS: " << numValidBrowserWindows << std::endl; + } const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); CaretAssert(browserClass); - const int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); + int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); + if (windowIndex < 0) { + windowIndex = i; + } CaretAssert(windowIndex >= 0); CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); m_browserWindowContent[windowIndex]->restoreFromOldBrainBrowserWindowScene(sceneAttributes, diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 70bc95358..1f43f8231 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -182,6 +182,11 @@ GuiManager::initializeGuiManager() this->cursorManager = new CursorManager(); + /* + * Windows vector never changes size + */ + m_brainBrowserWindows.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, NULL); + /* * Information window. */ @@ -557,6 +562,8 @@ GuiManager::getBrowserWindowByWindowIndex(const int32_t browserWindowIndex) * Create a new BrainBrowser Window. * @param parent * Optional parent that is used only for window placement. + * @param useWindowIndex + * Create the new window in this index if this index is valid * @param browserTabContent * Optional tab for initial windwo tab. * @param createDefaultTabs @@ -568,6 +575,7 @@ GuiManager::getBrowserWindowByWindowIndex(const int32_t browserWindowIndex) */ BrainBrowserWindow* GuiManager::newBrainBrowserWindow(QWidget* parent, + const int32_t useWindowIndex, BrowserTabContent* browserTabContent, const bool createDefaultTabs, AString& errorMessageOut) @@ -589,33 +597,44 @@ GuiManager::newBrainBrowserWindow(QWidget* parent, int32_t windowIndex = -1; + /* + * Is window required to be at a specific index? + */ int32_t numWindows = static_cast(m_brainBrowserWindows.size()); - for (int32_t i = 0; i < numWindows; i++) { - if (m_brainBrowserWindows[i] == NULL) { - windowIndex = i; - break; + if (useWindowIndex >= 0) { + CaretAssertVectorIndex(m_brainBrowserWindows, useWindowIndex); + windowIndex = useWindowIndex; + } + else { + /* + * Use first available window + */ + for (int32_t i = 0; i < numWindows; i++) { + if (m_brainBrowserWindows[i] == NULL) { + windowIndex = i; + break; + } } } if (windowIndex < 0) { - if (numWindows >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) { - errorMessageOut = ("Unable to create a new window as the maximum number of windows (" - + AString::number(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) - + ") are currently open."); - return NULL; - } + /* + * No windows are available + */ + errorMessageOut = ("Unable to create a new window as the maximum number of windows (" + + AString::number(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) + + ") are currently open."); + return NULL; } - BrainBrowserWindow* bbw = NULL; + BrainBrowserWindow* bbw = NULL; BrainBrowserWindow::CreateDefaultTabsMode tabsMode = (createDefaultTabs ? BrainBrowserWindow::CREATE_DEFAULT_TABS_YES : BrainBrowserWindow::CREATE_DEFAULT_TABS_NO); - if (windowIndex < 0) { - windowIndex = m_brainBrowserWindows.size(); - bbw = new BrainBrowserWindow(windowIndex, browserTabContent, tabsMode); - m_brainBrowserWindows.push_back(bbw); + if (m_brainBrowserWindows[windowIndex] != NULL) { + bbw = m_brainBrowserWindows[windowIndex]; } else { bbw = new BrainBrowserWindow(windowIndex, browserTabContent, tabsMode); @@ -1248,7 +1267,8 @@ GuiManager::receiveEvent(Event* event) CaretAssert(eventNewBrowser); AString errorMessage; - BrainBrowserWindow* bbw = this->newBrainBrowserWindow(eventNewBrowser->getParent(), + BrainBrowserWindow* bbw = this->newBrainBrowserWindow(eventNewBrowser->getParent(), + -1, /* allow any window index */ eventNewBrowser->getBrowserTabContent(), true, errorMessage); @@ -2464,17 +2484,34 @@ GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, EventManager::get()->sendEvent(progressEvent.getPointer()); const SceneClassArray* browserWindowArray = sceneClass->getClassArray("m_brainBrowserWindows"); if (browserWindowArray != NULL) { + bool windowWasRestoredFlag = false; const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); + CaretAssert(browserClass); + const int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); + BrainBrowserWindow* bbw = NULL; AString errorMessage; if ( ! availableWindows.empty()) { bbw = availableWindows.front(); - availableWindows.pop_front(); + + if (windowIndex >= 0) { + /* + * Use window only if it has same index as window being restored. + */ + if (bbw->getBrowserWindowIndex() != windowIndex) { + bbw = NULL; + } + } + + if (bbw != NULL) { + availableWindows.pop_front(); + } } - else { + if (bbw == NULL) { bbw = newBrainBrowserWindow(NULL, + windowIndex, NULL, false, errorMessage); @@ -2482,11 +2519,19 @@ GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, if (bbw != NULL) { bbw->restoreFromScene(sceneAttributes, browserClass); + windowWasRestoredFlag = true; } else { sceneAttributes->addToErrorMessage("\n" + errorMessage); } } + + if (windowWasRestoredFlag) { + if ( ! availableWindows.empty()) { + BrainBrowserWindow* bbw = availableWindows.front(); + bbw->close(); + } + } } CaretLogFine("Time to restore browser windows was " diff --git a/src/GuiQt/GuiManager.h b/src/GuiQt/GuiManager.h index 2a79a8cc2..4e54028a9 100644 --- a/src/GuiQt/GuiManager.h +++ b/src/GuiQt/GuiManager.h @@ -214,6 +214,7 @@ namespace caret { void initializeGuiManager(); BrainBrowserWindow* newBrainBrowserWindow(QWidget* parent, + const int32_t useWindowIndex, BrowserTabContent* browserTabContent, const bool createDefaultTabs, AString& errorMessageOut); @@ -233,11 +234,7 @@ namespace caret { /** One instance of the GuiManager */ static GuiManager* singletonGuiManager; - /** - * Contains pointers to Brain Browser windows - * As BrainBrowser windows are closed, some of - * the elements may be NULL. - */ + /** Contains pointers to Brain Browser windows */ std::vector m_brainBrowserWindows; /** Skips confirmation of browser window closing when all tabs are moved to one window */ -- GitLab From 15cfe20d2d0a86d9d93ce4d38fe64e349c3e1440 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 16 Feb 2018 11:13:15 -0600 Subject: [PATCH 632/755] Add option for Connectome DB username and password to show scene command. If the user does not provide the username and password, they are retrieved from the user's preferences. This fixes incorrectly rendered scenes that reference files in Connectome DB. --- src/Brain/SessionManager.cxx | 6 ----- src/Operations/OperationShowScene.cxx | 34 +++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index abfe27e9c..3ce0be075 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -856,12 +856,6 @@ SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClassArray* browserWindowArray = guiManagerClass->getClassArray("m_brainBrowserWindows"); if (browserWindowArray != NULL) { - { - const int32_t numValidBrowserWindows = std::count_if(m_browserWindowContent.begin(), - m_browserWindowContent.end(), - [](BrowserWindowContent* bwc) { return bwc->isValid(); }); - std::cout << "RESTORING OLD SCENE NUM WINDOWS: " << numValidBrowserWindows << std::endl; - } const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 0a5b146d2..ccdf98f3d 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -40,6 +40,7 @@ #include "BrainOpenGLWindowContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" +#include "CaretPreferences.h" #include "CaretLogger.h" #include "DataFileException.h" #include "EventBrowserTabGet.h" @@ -119,6 +120,10 @@ OperationShowScene::getParameters() mapYokeOpt->addStringParameter(1, "Map Yoking Roman Numeral", "Roman numeral identifying the map yoking group (I, II, III, IV, V, VI, VII, VIII, IX, X)"); mapYokeOpt->addIntegerParameter(2, "Map Index", "Map index for yoking group. Indices start at 1 (one)"); + OptionalParameter* connDbOpt = ret->createOptionalParameter(9, "-conn-db-login", "Login for scenes with files in Connectome Database"); + connDbOpt->addStringParameter(1, "Username", "Connectome DB Username"); + connDbOpt->addStringParameter(2, "Password", "Connectome DB Password"); + AString helpText("Render content of browser windows displayed in a scene " "into image file(s). The image file name should be " "similar to \"capture.png\". If there is only one image " @@ -127,9 +132,16 @@ OperationShowScene::getParameters() "into the image name: \"capture_01.png\", \"capture_02.png\" " "etc.\n" "\n" + "If the scene references files in the Connectome Database,\n" + "the \"-conn-db-login\" option is available for providing the \n" + "username and password. If this options is not specified, \n" + "the username and password stored in the user's preferences\n" + "is used.\n" + "\n" "The image format is determined by the image file extension.\n" "The available image formats may vary by operating system.\n" - "Image formats available on this system are:\n"); + "Image formats available on this system are:\n" + ); std::vector imageFileExtensions; AString defaultExtension; ImageFile::getImageFileExtensions(imageFileExtensions, @@ -223,7 +235,25 @@ OperationShowScene::useParameters(OperationParameters* myParams, + QString::number(userImageHeight)); } } - + + /* + * Need to set username/password for files in ConnectomeDB + */ + AString username; + AString password; + OptionalParameter* connDbOpt = myParams->getOptionalParameter(9); + if (connDbOpt->m_present) { + username = connDbOpt->getString(1); + password = connDbOpt->getString(2); + } + else { + CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + prefs->getRemoteFileUserNameAndPassword(username, + password); + } + CaretDataFile::setFileReadingUsernameAndPassword(username, + password); + /* * Read the scene file and load the scene */ -- GitLab From e2bfc7d5ff61c0cee94ef221ae019fef50218917 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Feb 2018 11:33:43 -0600 Subject: [PATCH 633/755] Resolve WB-779 There is no warning for unsaved files for show scene: A warning dialog is displayed showing files with modified data and those with only modified color mapping. --- src/GuiQt/GuiManager.cxx | 74 +++++++++++++++++++++++++++------------ src/GuiQt/SceneDialog.cxx | 10 +++--- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index 1f43f8231..2d2c1c9e1 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -738,7 +738,27 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: - modifiedDataFiles.push_back(file); + case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: + { + /* + * Show both data modified and palette modified + */ + CaretMappableDataFile* mappableDataFile = dynamic_cast(file); + bool paletteOnlyModFlag = false; + if (mappableDataFile != NULL) { + if (mappableDataFile->isModifiedPaletteColorMapping()) { + if ( ! mappableDataFile->isModifiedExcludingPaletteColorMapping()) { + paletteOnlyModFlag = true; + } + } + } + if (paletteOnlyModFlag) { + paletteModifiedDataFiles.push_back(file); + } + else { + modifiedDataFiles.push_back(file); + } + } break; case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: { @@ -775,12 +795,8 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, if (paletteOnlyModFlag) { paletteModifiedDataFiles.push_back(file); } - } break; - case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: - modifiedDataFiles.push_back(file); - break; } } @@ -814,6 +830,7 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, * Display dialog allowing user to save files (goes to Save/Manage * Files dialog), exit without saving, or cancel. */ + AString paletteModifiedMessage("These file(s) contain modified palette color mapping: "); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: textMessageOut = "Do you want to save changes you made to these files?"; @@ -821,41 +838,52 @@ GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: textMessageOut = "Do you want to continue creating the scene?"; + paletteModifiedMessage = ("These file(s) contain modified palette color mapping " + "AND \"Add modified palette color mapping to scene\" " + "is NOT checked on the Create New Scene Dialog:"); break; case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: textMessageOut = "Do you want to continue showing the scene?"; break; } - AString infoTextMsg; - if (modFileCount > 0) { - infoTextMsg.appendWithNewLine("Changes to these files will be lost if you don't save them:\n"); - for (std::vector::iterator iter = modifiedDataFiles.begin(); - iter != modifiedDataFiles.end(); - iter++) { - const CaretDataFile* cdf = *iter; - infoTextMsg.appendWithNewLine(" " - + cdf->getFileNameNoPath()); + AString infoTextMsg(""); + + if (sceneAnnotationsModifiedFlag + || (modFileCount > 0)) { + infoTextMsg.appendWithNewLine("These file(s) contain modified data:\n"); + infoTextMsg.appendWithNewLine("
      "); + + if (sceneAnnotationsModifiedFlag) { + infoTextMsg.appendWithNewLine("
    • Scene Annotations (must be saved to a scene)"); + } + + if (modFileCount > 0) { + for (std::vector::iterator iter = modifiedDataFiles.begin(); + iter != modifiedDataFiles.end(); + iter++) { + const CaretDataFile* cdf = *iter; + infoTextMsg.appendWithNewLine("
    • " + + cdf->getFileNameNoPath()); + } } - infoTextMsg.append("\n"); + + infoTextMsg.appendWithNewLine("
    "); } if (paletteModFileCount > 0) { - infoTextMsg.appendWithNewLine("These file(s) contain modified palette color mapping " - "AND \"Add modified palette color mapping to scene\" " - "is NOT checked on the Create New Scene Dialog.\n"); + infoTextMsg.appendWithNewLine(paletteModifiedMessage); + infoTextMsg.appendWithNewLine("
      "); for (std::vector::iterator iter = paletteModifiedDataFiles.begin(); iter != paletteModifiedDataFiles.end(); iter++) { const CaretDataFile* cdf = *iter; - infoTextMsg.appendWithNewLine(" " + infoTextMsg.appendWithNewLine("
    • " + cdf->getFileNameNoPath()); } - infoTextMsg.append("\n"); + infoTextMsg.appendWithNewLine("
    "); } - if (sceneAnnotationsModifiedFlag) { - infoTextMsg.appendWithNewLine("Scene annotations are modified."); - } + infoTextMsg.appendWithNewLine(""); modifiedFilesMessageOut = infoTextMsg; return true; diff --git a/src/GuiQt/SceneDialog.cxx b/src/GuiQt/SceneDialog.cxx index 10d4c7c3f..7caea8bfa 100644 --- a/src/GuiQt/SceneDialog.cxx +++ b/src/GuiQt/SceneDialog.cxx @@ -2352,12 +2352,10 @@ SceneDialog::deleteSceneButtonClicked() void SceneDialog::showSceneButtonClicked() { -// At this time, do not test for modified files -// since a scene previously loaded may contain -// modified palette status. -// if ( ! checkForModifiedFiles(false)) { -// return; -// } + if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW, + this)) { + return; + } AString sceneFileName; SceneFile* sceneFile = getSelectedSceneFile(); -- GitLab From 36c99cdb101f528cc18423ef3ff82eaacfc8b369 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Feb 2018 15:04:37 -0600 Subject: [PATCH 634/755] Resolve WB-778 Scene does not reload a modified file: Each data file now contains the time that is was last read into memory or written out from memory. When a scene is displayed, it avoid reloading in memory file that are unmodified. This test has been expanded to compare the time associated with the file's last read or write action with the modified time on the disk file. If the disk file time is newer, the file is reloaded. A use case is as follows: The user is running wb_view and has an in memory file. The user then uses wb_command or another instance of wb_view to change the file. Now, when the user loads the scene, the new version of the file is loaded and reflects the content of the file on disk. --- src/Brain/Brain.cxx | 3 ++ src/Common/DataFile.cxx | 86 ++++++++++++++++++++++++++++++++++++++++ src/Common/DataFile.h | 8 ++++ src/Files/VolumeFile.cxx | 1 + 4 files changed, 98 insertions(+) diff --git a/src/Brain/Brain.cxx b/src/Brain/Brain.cxx index 7a35c9784..72ae0aba8 100644 --- a/src/Brain/Brain.cxx +++ b/src/Brain/Brain.cxx @@ -732,6 +732,9 @@ Brain::resetBrainKeepSceneFiles() if (caretDataFile->isModified()) { continue; } + if (caretDataFile->isModifiedSinceTimeOfLastReadOrWrite()) { + continue; + } const DataFileTypeEnum::Enum dataFileType = caretDataFile->getDataFileType(); diff --git a/src/Common/DataFile.cxx b/src/Common/DataFile.cxx index bcec1826e..b3de1bc67 100644 --- a/src/Common/DataFile.cxx +++ b/src/Common/DataFile.cxx @@ -18,6 +18,8 @@ */ /*LICENSE_END*/ +#include + #include "DataFile.h" #include "DataFileContentInformation.h" #include "DataFileException.h" @@ -81,6 +83,7 @@ DataFile::copyHelperDataFile(const DataFile& df) m_filename = df.m_filename; m_fileReadWarnings = df.m_fileReadWarnings; m_modifiedFlag = false; + m_timeOfLastReadOrWrite = QDateTime(); } /** @@ -92,6 +95,7 @@ DataFile::initializeMembersDataFile() m_filename = ""; m_fileReadWarnings.clear(); m_modifiedFlag = false; + m_timeOfLastReadOrWrite = QDateTime(); } /** @@ -181,6 +185,12 @@ void DataFile::clearModified() { m_modifiedFlag = false; + + /* + * This method, clearModified(), is called by all file + * types at the conclusion of readFile() and writeFile(). + */ + setTimeOfLastReadOrWrite(); } /** @@ -318,4 +328,80 @@ DataFile::getFileReadWarnings() const return warningMessage; } +/** + * Set the time this file was last read or written to the current time. + */ +void +DataFile::setTimeOfLastReadOrWrite() +{ + m_timeOfLastReadOrWrite = getLastModifiedTime(); +} + +/** + * @return True if this file been modified since it was last read or written. + * (modified by an external program)? + * + * If any of these conditions are met, false is returned: + * (1) The name is empty; (2) The file is on the network; + * (3) The file does not exist; (4) The modified time + * from the file system is invalid; (5) The last time this + * file was read or written is invalid. + */ +bool +DataFile::isModifiedSinceTimeOfLastReadOrWrite() const +{ + const QDateTime lastModTime = getLastModifiedTime(); + + if (lastModTime.isNull()) { + return false; + } + + if (m_timeOfLastReadOrWrite.isNull()) { + return false; + } + + /* + * If last modified time is newer than + * time of file read or written + */ + if (lastModTime > m_timeOfLastReadOrWrite) { + return true; + } + + return false; +} + +/** + * @return True if this file been modified since it was last read or written. + * (modified by an external program)? + * + * If any of these conditions are met, a null (.isNull()) is returned: + * (1) The name is empty; (2) The file is on the network; + * (3) The file does not exist; (4) The modified time + * from the file system is invalid. + */ +QDateTime +DataFile::getLastModifiedTime() const +{ + QDateTime lastModTime; + + const AString name = getFileName(); + if (name.isEmpty()) { + return lastModTime; + } + + if (isFileOnNetwork(name)) { + return lastModTime; + } + + QFileInfo fileInfo(name); + if ( ! fileInfo.exists()) { + return lastModTime; + } + + lastModTime = fileInfo.lastModified(); + + return lastModTime; +} + diff --git a/src/Common/DataFile.h b/src/Common/DataFile.h index 6eca1d879..ed2ab2a07 100644 --- a/src/Common/DataFile.h +++ b/src/Common/DataFile.h @@ -21,6 +21,7 @@ */ /*LICENSE_END*/ +#include #include @@ -98,11 +99,17 @@ namespace caret { AString getFileReadWarnings() const; + bool isModifiedSinceTimeOfLastReadOrWrite() const; + private: void copyHelperDataFile(const DataFile& df); void initializeMembersDataFile(); + void setTimeOfLastReadOrWrite(); + + QDateTime getLastModifiedTime() const; + /** name of data file */ AString m_filename; @@ -112,6 +119,7 @@ namespace caret { /** modification status */ bool m_modifiedFlag; + QDateTime m_timeOfLastReadOrWrite; }; } // namespace diff --git a/src/Files/VolumeFile.cxx b/src/Files/VolumeFile.cxx index e8dded5d6..2c646ebe1 100644 --- a/src/Files/VolumeFile.cxx +++ b/src/Files/VolumeFile.cxx @@ -360,6 +360,7 @@ VolumeFile::writeFile(const AString& filename) m_volumeFileEditorDelegate->clear(); m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); + clearModified(); } bool VolumeFile::hasGoodSpatialInformation() const -- GitLab From bba57794681a991ae0598c15d6aa0c36f9fbac2b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Feb 2018 08:57:59 -0600 Subject: [PATCH 635/755] Resolve WB-761 RGBA files: added support for reading and displaying GIFTI RGBA files. --- src/Brain/SurfaceNodeColoring.cxx | 19 +++--- src/Files/RgbaFile.cxx | 96 +++++++++++++++++++++++++++++-- src/Files/RgbaFile.h | 10 ++++ src/Gifti/GiftiDataArray.cxx | 2 +- 4 files changed, 113 insertions(+), 14 deletions(-) diff --git a/src/Brain/SurfaceNodeColoring.cxx b/src/Brain/SurfaceNodeColoring.cxx index 0b3915314..d3d02d2a8 100644 --- a/src/Brain/SurfaceNodeColoring.cxx +++ b/src/Brain/SurfaceNodeColoring.cxx @@ -1456,19 +1456,24 @@ SurfaceNodeColoring::assignCiftiParcelSeriesColoring(const BrainStructure* brain * True if coloring is valid, else false. */ bool -SurfaceNodeColoring::assignRgbaColoring(const BrainStructure* /*brainStructure*/, - const RgbaFile* /*rgbaFile*/, +SurfaceNodeColoring::assignRgbaColoring(const BrainStructure* brainStructure, + const RgbaFile* rgbaFile, const int32_t /*mapIndex*/, const int32_t numberOfNodes, float* rgbv) { - CaretAssertMessage(0, "Add implementation."); + if ( ! rgbaFile->isMappableToSurfaceStructure(brainStructure->getStructure())) { + return false; + } + + if (rgbaFile->isEmpty()) { + return false; + } + for (int32_t i = 0; i < numberOfNodes; i++) { const int32_t i4 = i * 4; - rgbv[i4] = 0.0; - rgbv[i4+1] = 0.0; - rgbv[i4+2] = 1.0; - rgbv[i4+3] = 1.0; + + rgbaFile->getVertexRGBA(i, &rgbv[i4]); } return true; diff --git a/src/Files/RgbaFile.cxx b/src/Files/RgbaFile.cxx index 1c5a08f20..278b0783c 100644 --- a/src/Files/RgbaFile.cxx +++ b/src/Files/RgbaFile.cxx @@ -20,6 +20,7 @@ #include "CaretAssert.h" +#include "DataFileException.h" #include "DataFileTypeEnum.h" #include "GiftiFile.h" #include "MathFunctions.h" @@ -95,7 +96,53 @@ RgbaFile::validateDataArraysAfterReading() { this->initializeMembersRgbaFile(); + const int32_t numberOfDataArrays = this->giftiFile->getNumberOfDataArrays(); + if (numberOfDataArrays != 1) { + throw DataFileException(getFileName(), + "GIFTI RGBA files must have one GIFTI Data Array"); + } + + const GiftiDataArray* gda = this->giftiFile->getDataArray(0); + if (gda->getNumberOfRows() <= 0) { + throw DataFileException(getFileName(), + "GIFTI RGBA file is empty (number of rows is zero)"); + } + + m_numberOfComponents = gda->getNumberOfComponents(); + if ((m_numberOfComponents < 3) + || (m_numberOfComponents > 4)) { + throw DataFileException(getFileName(), + "GIFTI RGBA file must have four components but contains " + + AString::number(m_numberOfComponents) + + " components."); + } + if (gda->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { + throw DataFileException("GIFTI RGBA files must be FLOAT data type. " + "Type of data array is: " + + NiftiDataTypeEnum::toName(gda->getDataType())); + } + this->verifyDataArraysHaveSameNumberOfRows(3, 4); + + m_dataArray = this->giftiFile->getDataArray(0); + m_numberOfVertices = gda->getNumberOfRows(); + + bool rescaleZeroToOneFlag = false; + const int32_t numValues = m_numberOfComponents * m_numberOfVertices; + float* floatData = m_dataArray->getDataPointerFloat(); + for (int32_t i = 0; i < numValues; i++) { + if (floatData[i] > 1.1f) { + rescaleZeroToOneFlag = true; + break; + } + } + + if (rescaleZeroToOneFlag) { + for (int32_t i = 0; i < numValues; i++) { + floatData[i] /= 255.0; + } + } + } /** @@ -107,12 +154,7 @@ RgbaFile::validateDataArraysAfterReading() int32_t RgbaFile::getNumberOfNodes() const { - int32_t numNodes = 0; - int32_t numDataArrays = this->giftiFile->getNumberOfDataArrays(); - if (numDataArrays > 0) { - numNodes = this->giftiFile->getDataArray(0)->getNumberOfRows(); - } - return numNodes; + return m_numberOfVertices; } /** @@ -135,6 +177,9 @@ RgbaFile::getNumberOfColumns() const void RgbaFile::initializeMembersRgbaFile() { + m_dataArray = 0; + m_numberOfVertices = 0; + m_numberOfComponents = 0; } /** @@ -149,4 +194,43 @@ RgbaFile::copyHelperRgbaFile(const RgbaFile& /*sf*/) this->validateDataArraysAfterReading(); } +/** + * Get the RGBA data for the given vertex. + * + * @param vertexIndex + * Index of the vertex. + * @param rgbaOut + * Output containing RGBA values for vertex. + */ +void +RgbaFile::getVertexRGBA(const int32_t vertexIndex, + float* rgbaOut) const +{ + CaretAssert((vertexIndex >= 0) + && (vertexIndex < m_numberOfVertices)); + + const float* floatData = m_dataArray->getDataPointerFloat(); + + if (m_numberOfComponents == 4) { + const int32_t v4 = vertexIndex * 4; + CaretAssertArrayIndex(floatData, m_numberOfVertices * m_numberOfComponents, v4 + 3); + rgbaOut[0] = floatData[v4]; + rgbaOut[1] = floatData[v4+1]; + rgbaOut[2] = floatData[v4+2]; + rgbaOut[3] = floatData[v4+3]; + } + else if (m_numberOfComponents == 3) { + const int32_t v3 = vertexIndex * 3; + CaretAssertArrayIndex(floatData, m_numberOfVertices * m_numberOfComponents, v3 + 2); + rgbaOut[0] = floatData[v3]; + rgbaOut[1] = floatData[v3+1]; + rgbaOut[2] = floatData[v3+2]; + rgbaOut[3] = 1.0f; + } + else { + CaretAssert(0); + } +} + + diff --git a/src/Files/RgbaFile.h b/src/Files/RgbaFile.h index 962a6df99..3a57222f6 100644 --- a/src/Files/RgbaFile.h +++ b/src/Files/RgbaFile.h @@ -51,6 +51,9 @@ namespace caret { virtual int32_t getNumberOfColumns() const; + void getVertexRGBA(const int32_t vertexIndex, + float* rgbaOut) const; + protected: /** * Validate the contents of the file after it @@ -64,6 +67,13 @@ namespace caret { void initializeMembersRgbaFile(); private: + + GiftiDataArray* m_dataArray = 0; + + int32_t m_numberOfVertices = 0; + + int32_t m_numberOfComponents = 0; + }; } // namespace diff --git a/src/Gifti/GiftiDataArray.cxx b/src/Gifti/GiftiDataArray.cxx index f38635da0..a8fb0e34a 100644 --- a/src/Gifti/GiftiDataArray.cxx +++ b/src/Gifti/GiftiDataArray.cxx @@ -222,7 +222,7 @@ GiftiDataArray::getDataTypeAppropriateForIntent(const NiftiIntentEnum::Enum inte } else if ((intent == NiftiIntentEnum::NIFTI_INTENT_RGB_VECTOR) || (intent == NiftiIntentEnum::NIFTI_INTENT_RGBA_VECTOR)) { - dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_UINT8; + dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_SHAPE) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; -- GitLab From 154d59c548dc7a4021c204d6675e63b047bcc5e4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Feb 2018 09:33:10 -0600 Subject: [PATCH 636/755] Update Scene File to version 3 since older versions of Workbench will not be able to properly restore the scenes due to the changes in aspect locking and movement of some window parameters from GuiQt to Brain (simplifies wb_command -show-scene). This will cause a read error in older versions of wb_view and the error message informs users to update software. --- src/Files/SceneFile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files/SceneFile.h b/src/Files/SceneFile.h index 1207faaa1..c41a97a53 100644 --- a/src/Files/SceneFile.h +++ b/src/Files/SceneFile.h @@ -173,7 +173,7 @@ namespace caret { const AString SceneFile::XML_TAG_SCENE_FILE = "SceneFile"; const AString SceneFile::XML_ATTRIBUTE_VERSION = "Version"; const AString SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG = "SceneInfoDirectory"; - const float SceneFile::s_sceneFileVersion = 2.0; + const float SceneFile::s_sceneFileVersion = 3.0; #endif // __SCENE_FILE_DECLARE__ } // namespace -- GitLab From 5d01013b67169c6341e0a099fa9ca7e51f314db6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Feb 2018 14:14:57 -0600 Subject: [PATCH 637/755] Continuing implementation of best practices and lock aspect warning dialog. --- src/GuiQt/BestPracticesDialog.cxx | 53 ++++++++++++++++++++++++--- src/GuiQt/BestPracticesDialog.h | 9 ++++- src/GuiQt/LockAspectWarningDialog.cxx | 3 +- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx index f9ba87933..cb5727c4f 100644 --- a/src/GuiQt/BestPracticesDialog.cxx +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -23,8 +23,13 @@ #include "BestPracticesDialog.h" #undef __BEST_PRACTICES_DIALOG_DECLARE__ +#include #include +#include #include +#include +#include +#include #include "CaretAssert.h" #include "WuQtUtilities.h" @@ -59,17 +64,25 @@ m_textMode(TextMode::FULL) setApplyButtonText(""); setDeleteWhenClosed(true); - QLabel* label = new QLabel(getTextForInfoMode(infoMode, - m_textMode)); + m_printPushButton = addUserPushButton("Print...", + QDialogButtonBox::NoRole); + m_labelText = getTextForInfoMode(infoMode, + m_textMode); + + QPushButton* closeButton = getDialogButtonBox()->button(QDialogButtonBox::Close); + CaretAssert(closeButton); + closeButton->setAutoDefault(true); + closeButton->setDefault(true); + + QLabel* label = new QLabel(m_labelText); label->setWordWrap(true); QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(label); -// widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - setCentralWidget(widget, WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); + setCentralWidget(widget, + WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); WuQtUtilities::limitWindowSizePercentageOfMaximum(this, 90.0, 80.0); } @@ -81,6 +94,34 @@ BestPracticesDialog::~BestPracticesDialog() { } +/** + * Gets called when a user pushbutton is pressed. + * + * @param userPushButton + * User push button that was pressed. + * @return + * Action dialog should take in response to push button being pressed. + */ +WuQDialog::DialogUserButtonResult +BestPracticesDialog::userButtonPressed(QPushButton* userPushButton) +{ + if (userPushButton == m_printPushButton) { + QPrinter printer; + QPrintDialog printDialog(&printer, this); + if (printDialog.exec() == QPrintDialog::Accepted) { + QTextDocument textDocument; + textDocument.setHtml(m_labelText); + textDocument.print(&printer); +// m_helpBrowser->document()->print(&printer); + } + } + else { + CaretAssert(0); + } + + return DialogUserButtonResult::RESULT_NONE; +} + /** * Get the text for the given information mode and text mode. * @@ -176,7 +217,7 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) text = ("Setup view of the models (pan/rotate/zoom). "); break; case FULL: - text = ("Setup viewa of the models. " + text = ("Setup view of the models. " "Pan (drag mouse with SHIFT key down), " "Rotate (drag mouse), " "Zoom (drag mouse with Control Key. Use the Command Key on Mac."); diff --git a/src/GuiQt/BestPracticesDialog.h b/src/GuiQt/BestPracticesDialog.h index aa4c8d477..73399c2bf 100644 --- a/src/GuiQt/BestPracticesDialog.h +++ b/src/GuiQt/BestPracticesDialog.h @@ -27,7 +27,7 @@ #include "WuQDialogNonModal.h" - +class QPushButton; namespace caret { @@ -55,6 +55,9 @@ namespace caret { // ADD_NEW_METHODS_HERE + protected: + virtual DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); + private: BestPracticesDialog(const BestPracticesDialog&); @@ -66,6 +69,10 @@ namespace caret { const TextMode m_textMode; + AString m_labelText; + + QPushButton* m_printPushButton; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index 11ea8c6bd..9e115eaf7 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -124,7 +124,8 @@ LockAspectWarningDialog::LockAspectWarningDialog(QWidget* parent) QLabel* moreLabel = new QLabel("" "For a more detailed explanation, click the " + helpButtonText + " button below. " - "Note: This dialog will close if the " + helpButtonText + " is clicked." + "Note: This dialog will close if " + helpButtonText + " is clicked " + "and the aspect will remain unlocked." ""); QPushButton* helpButton = new QPushButton(helpButtonText + "..."); QObject::connect(helpButton, &QPushButton::clicked, -- GitLab From d3345896a8ba9fc7da551cd52448bd5e7b4c52da Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Feb 2018 12:45:56 -0600 Subject: [PATCH 638/755] Revised implementation of Best Practices Dialog for annotations/scenes and Lock Aspect Dialog. --- src/GuiQt/BestPracticesDialog.cxx | 431 ++++++++++++-------------- src/GuiQt/BestPracticesDialog.h | 6 +- src/GuiQt/LockAspectWarningDialog.cxx | 201 ++++++------ src/GuiQt/LockAspectWarningDialog.h | 16 +- 4 files changed, 317 insertions(+), 337 deletions(-) diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx index cb5727c4f..2cd4bda99 100644 --- a/src/GuiQt/BestPracticesDialog.cxx +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -58,28 +59,31 @@ BestPracticesDialog::BestPracticesDialog(const InfoMode infoMode, QWidget* parent) : WuQDialogNonModal("Best Practices", parent), -m_infoMode(infoMode), -m_textMode(TextMode::FULL) +m_infoMode(infoMode) { + setApplyButtonText(""); setDeleteWhenClosed(true); + m_text = getTextForInfoMode(infoMode, + TextMode::BRIEF_AND_FULL); + m_printPushButton = addUserPushButton("Print...", QDialogButtonBox::NoRole); - m_labelText = getTextForInfoMode(infoMode, - m_textMode); - + QPushButton* closeButton = getDialogButtonBox()->button(QDialogButtonBox::Close); CaretAssert(closeButton); closeButton->setAutoDefault(true); closeButton->setDefault(true); - QLabel* label = new QLabel(m_labelText); - label->setWordWrap(true); + QTextBrowser* browser = new QTextBrowser(); + browser->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum)); + browser->setHtml(m_text); + browser->setMinimumSize(600, 400); QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); - layout->addWidget(label); + layout->addWidget(browser); setCentralWidget(widget, WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); @@ -110,9 +114,8 @@ BestPracticesDialog::userButtonPressed(QPushButton* userPushButton) QPrintDialog printDialog(&printer, this); if (printDialog.exec() == QPrintDialog::Accepted) { QTextDocument textDocument; - textDocument.setHtml(m_labelText); + textDocument.setHtml(m_text); textDocument.print(&printer); -// m_helpBrowser->document()->print(&printer); } } else { @@ -147,274 +150,234 @@ BestPracticesDialog::getTextForInfoMode(const InfoMode infoMode, AString BestPracticesDialog::getLockAspectText(const TextMode textMode) { - AString introText; - { - switch (textMode) { - case BRIEF: - introText = ("Aspect is unlocked and it is strongly recommended that aspect is locked and remains locked " - "when annotations are present. Failing to lock aspect or unlocking the aspect may " - "cause annotations to move from their original locations when the graphics region size changes." - "

    " - "When creating annotations and scenes, follow these best practices:"); - break; - case FULL: - introText = ("Describing annotations and scenes is best done using an analogy with Microsoft PowerPoint. " - "PowerPoint allows one to create a presentation consisting of slides saved into a PowerPoint file. " - "These slides are annotated with text and various shapes. In wb_view, a scene is analogous " - "to a PowerPoint slide and a Scene File contains multiple scenes just like a PowerPoint " - "file contains multiple slides. In wb_view, one annotates a scene similar to the way one " - "annotates a slide in PowerPoint. A Scene saves ‘the state’ of wb_view so that when " - "the scene is loaded at a later time, by either the creator of the scene or another " - "user, the user-interface and the orientation of the brain models replicates ‘the state’ at the time the " - "scene was created." - "

    " - "When creating scenes and annotations, following a set of “best practices†ensures " - "that one efficiently creates scenes that are properly displayed at a later time " - "and when shared with other users."); - break; - } - } + const AString briefIntro ("

    Best Practices Summary

    "); + + const AString fullIntro("

    Introduction

    " + "Describing annotations and scenes is best done using an analogy with Microsoft PowerPoint. " + "PowerPoint allows one to create a presentation consisting of slides saved into a PowerPoint file. " + "These slides are annotated with text and various shapes. In wb_view, a scene is analogous " + "to a PowerPoint slide and a Scene File contains multiple scenes just like a PowerPoint " + "file contains multiple slides. In wb_view, one annotates a scene similar to the way one " + "annotates a slide in PowerPoint. A Scene saves ‘the state’ of wb_view so that when " + "the scene is loaded at a later time, by either the creator of the scene or another " + "user, the user-interface and the orientation of the brain models replicates ‘the state’ at the time the " + "scene was created." + "

    " + "When creating scenes and annotations, following a set of “best practices†ensures " + "that one efficiently creates scenes that are properly displayed at a later time " + "and when shared with other users."); - std::vector bulletLines; + + std::vector> summaryDetails; { - AString text("If a multi-tab scene will be created, enter Tile Tabs (View Menu->Enter Tile Tabs). "); - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("Tile Tabs displays all of the window's tabs in a grid pattern. " - "The number of row and columns in the Tile Tabs view is edited on the " - "Tile Tabs Configuration Dialog (View Menu->Tile Tabs Configuration->Create and Edit). " - "Advanced parameters include “stretch factors†that allow one to increase the " - "size of a row or column relative to other rows and columns. One may also save the " - "configuration for future use. If a scene is created, the configuration is added to the scene " - "so that the configuration is available when the scene is displayed."); - break; - } + const AString summary("If a multi-tab scene will be created, enter Tile Tabs (View Menu->Enter Tile Tabs). "); + const AString details(summary + + "Tile Tabs displays all of the window's tabs in a grid pattern. " + "The number of row and columns in the Tile Tabs view is edited on the " + "Tile Tabs Configuration Dialog (View Menu->Tile Tabs Configuration->Create and Edit). " + "Advanced parameters include “stretch factors†that allow one to increase the " + "size of a row or column relative to other rows and columns. One may also save the " + "configuration for future use. If a scene is created, the configuration is added to the scene " + "so that the configuration is available when the scene is displayed."); - - bulletLines.push_back(text); + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Adjust size of window. "); - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("It is important to adust the size of the window prior to entering Annotations Mode " - "(further down in this list)."); - break; - } - bulletLines.push_back(text); + const AString summary("Adjust size of window. "); + const AString details(summary + + "It is important to adust the size of the window prior to entering Annotations Mode " + "(further down in this list)."); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text; - switch (textMode) { - case BRIEF: - text = ("Setup view of the models (pan/rotate/zoom). "); - break; - case FULL: - text = ("Setup view of the models. " - "Pan (drag mouse with SHIFT key down), " - "Rotate (drag mouse), " - "Zoom (drag mouse with Control Key. Use the Command Key on Mac."); - break; - } - bulletLines.push_back(text); + const AString summary("Setup view of the models (pan/rotate/zoom). "); + const AString details("Setup view of the models. " + "Pan (drag mouse with SHIFT key down), " + "Rotate (drag mouse), " + "Zoom (drag mouse with Control Key. Use the Command Key on Mac."); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Lock Aspect Ratio (click Lock Aspect button in right side of Toolbar). "); - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("As a general rule, once the aspect ratio is locked, it should remain locked. " - "The aspect ratio is the ratio of height divided by width. " - "Annotations in tab and window spaces " - "are positioned using percentage coordinates that range from 0% to 100% with " - "0% at the left (x) and bottom (y) and 100% at the right (x) and top (y). " - "If the window is resized with the aspect ratio unlocked and there is a change " - "in the aspect ratio, annotations in tab/window space may no longer " - "appear in the correct location (such as over an anatomical feature). Locking " - "the aspect ratio adds padding to the left and right or bottom " - "and top of the graphics region so that the model’s region maintains the same " - "aspect ratio (ratio of height to width). This ensures that " - "annotations remain in the correct location relative to the viewed brain model. "); - break; - } - bulletLines.push_back(text); + const AString summary("Lock Aspect Ratio (click Lock Aspect button in right side of Toolbar). "); + const AString details(summary + + "As a general rule, once the aspect ratio is locked, it should remain locked. " + "The aspect ratio is the ratio of height divided by width. " + "Annotations in tab and window spaces " + "are positioned using percentage coordinates that range from 0% to 100% with " + "0% at the left (x) and bottom (y) and 100% at the right (x) and top (y). " + "If the window is resized with the aspect ratio unlocked and there is a change " + "in the aspect ratio, annotations in tab/window space may no longer " + "appear in the correct location (such as over an anatomical feature). Locking " + "the aspect ratio adds padding to the left and right or bottom " + "and top of the graphics region so that the model’s region maintains the same " + "aspect ratio (ratio of height to width). This ensures that " + "annotations remain in the correct location relative to the viewed brain model. "); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Enter Annotations Mode (click Annotate button in Toolbar). "); - switch (textMode) { - case BRIEF: - break; - case FULL: - break; - } - bulletLines.push_back(text); + const AString summary("Enter Annotations Mode (click Annotate button in Toolbar). "); + const AString details(summary); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text; - switch (textMode) { - case BRIEF: - text = ("Add Annotations."); - break; - case FULL: - text = ("To add annotations, click any of the Space and/or Type icons in the Insert New section " - "of the Annotation Toolbar and then click in graphics region to create the annotation. " - "A new annotation is automatically selected so that it can be moved/resized with " - "the mouse or its attributes changed using controls in the toolbar."); - break; - } - bulletLines.push_back(text); + const AString summary = ("Add Annotations."); + const AString details("To add annotations, click any of the Space and/or Type icons in the Insert New section " + "of the Annotation Toolbar and then click in graphics region to create the annotation. " + "A new annotation is automatically selected so that it can be moved/resized with " + "the mouse or its attributes changed using controls in the toolbar."); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes) and " - "add a Scene (click Add button on Scene Dialog). "); - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("In the Create New Scene Dialog, edit the name and description for the new scene and then " - "press the OK button. Note that by default, new annotations are added to " - "the current scene and stored in the scene file. If one wants to place annotations into a disk file, " - "click the small arrow to the right of the Scene button in the Insert New " - "section of the Toolbar. When the arrow is clicked, a menu is displayed " - "for creating and/or selecting a disk annotation file."); - break; - } - bulletLines.push_back(text); + const AString summary("Display the Scene Dialog (click Clapboard icon in Toolbar or select Window Menu->Scenes) and " + "add a Scene (click Add button on Scene Dialog). "); + const AString details(summary + + "In the Create New Scene Dialog, edit the name and description for the new scene and then " + "press the OK button. Note that by default, new annotations are added to " + "the current scene and stored in the scene file. If one wants to place annotations into a disk file, " + "click the small arrow to the right of the Scene button in the Insert New " + "section of the Toolbar. When the arrow is clicked, a menu is displayed " + "for creating and/or selecting a disk annotation file."); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Save the Scene File. Click Save As button the first time to set the path and name of the scene file. " - "Once path and name of scene file has been set, use the Save button."); - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("To set the name of the New Scene File, click the Save As button. " - "In the file selection dialog, choose the directory, and enter a descriptive " - "name for the Scene File. It is best for the Scene File to be in the same " - "directory or the parent directory of the directory containing your data files. " - "If the data files are scattered about many directories, it may cause problems " - "if the Scene File and its data files are zipped for distribution to others " - "or when uploading the BALSA Database"); - break; - } - bulletLines.push_back(text); + const AString summary("Save the Scene File. Click Save As button the first time to set the path and name of the scene file. " + "Once path and name of scene file has been set, use the Save button."); + const AString details(summary + + "To set the name of the New Scene File, click the Save As button. " + "In the file selection dialog, choose the directory, and enter a descriptive " + "name for the Scene File. It is best for the Scene File to be in the same " + "directory or the parent directory of the directory containing your data files. " + "If the data files are scattered about many directories, it may cause problems " + "if the Scene File and its data files are zipped for distribution to others " + "or when uploading the BALSA Database"); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text("Repeat last few steps to edit annotations and create additional scenes."); - switch (textMode) { - case BRIEF: - break; - case FULL: - break; - } - bulletLines.push_back(text); + const AString summary("Repeat last few steps to edit annotations and create additional scenes."); + const AString details(summary); + + summaryDetails.push_back(std::make_pair(summary, details)); } { - AString text; - switch (textMode) { - case BRIEF: - text = ("Be sure to save the Scene File (click Save button or Save As if Save is disabled at top of Scene Dialog)."); - break; - case FULL: - text = ("If the Save button at the top of the Scene Dialog is enabled, the Scene File is in a " - "modified state. Click the Save button to save the Scene File and avoid losing your work."); - break; - } - bulletLines.push_back(text); + const AString summary = ("Be sure to save the Scene File (click Save button or Save As if Save is disabled at top of Scene Dialog)."); + const AString details("If the Save button at the top of the Scene Dialog is enabled, the Scene File is in a " + "modified state. Click the Save button to save the Scene File and avoid losing your work."); + + summaryDetails.push_back(std::make_pair(summary, details)); } - AString msg; - msg.reserve(32000); - - msg.appendWithNewLine("" - + introText - + "

    "); - - AString text; + bool showBriefFlag = false; + bool showFullFlag = false; switch (textMode) { + case BRIEF_AND_FULL: + showBriefFlag = true; + showFullFlag = true; + break; case BRIEF: - { - msg.appendWithNewLine("

      "); - for (const auto& line : bulletLines) { - msg.appendWithNewLine("
    1. "); - msg.append(line); - } - msg.appendWithNewLine("
    "); - } + showBriefFlag = true; break; case FULL: - { - int32_t counter = 1; - for (const auto& line : bulletLines) { - msg.appendWithNewLine("

    "); - msg.append(AString::number(counter) + ". "); - msg.append(line); - ++counter; - } - } + showFullFlag = true; break; } - { - switch (textMode) { - case BRIEF: - break; - case FULL: - text.append("

    " - "Understanding the Tab and Window Coordinate Spaces. " - "

    " - "In PowerPoint, each slide maintains a fixed aspect ratio (the ratio of " - "height to width remains constant) with a spatial coordinate system " - "(typically inches). As a result, each annotation in PowerPoint is places " - "its annotions at a spatial coordinate (X and Y in inches). " - "In contrast, wb_view defaults to a " - "variable aspect ratio so that the window is resizable to best fit the brain " - "model (surface, volume, chart). This variable aspect ratio is problematic " - "for annotations in Tab or Window Space both of which use a percentage " - "coordinate system (0% at left/bottom and 100% at right/top). " - "

    " - "If one creates a Tab Space annotation with the variable aspect enabled and " - "changes the size of the window, the Tab Space annotation may no longer be in " - "the correct location. To correct this problem, wb_view supports “locking " - "of the aspect ratioâ€. When the aspect ratio is locked, the window (and " - "each tab within the window) are fixed to the aspect ratio at the time " - "aspect locking is enabled. If the size of the window changes while " - "the aspect is locked, the contents of window and each tab will expand or " - "contract in size but maintain a fixed aspect by adding space to sides " - "of the model when needed."); - text.append("

    " - "Scenes" - "

    " - "Scenes are closely related to annotations. Scenes allow one to preserve " - "'the state’ of wb_view. Thus one if one saves a scene, exits wb_view, later restarts " - "wb_view, and loads the scene, wb_view appears identical to when the scene was " - "originally saved. Scenes are frequently used for figures in publications. " - "Scenes are also uploaded to the BALSA database for sharing with other users." - "

    " - "While annotations can be saved in disk files, annotations are most commonly saved " - "to a scene. When creating annotations for a scene, it is a best practice to " - "save the annotations to the scene instead of creating a disk annotation file. "); - break; + AString briefText; + if (showBriefFlag) { + briefText.appendWithNewLine(briefIntro); + } + + AString fullText; + if (showFullFlag) { + fullText.appendWithNewLine(fullIntro); + fullText.appendWithNewLine("

    Best Practices Details

    "); + } + + int32_t counter = 1; + for (const auto sd : summaryDetails) { + const AString linkName("n" + AString::number(counter)); + + if (showBriefFlag) { + briefText.append("" + + AString::number(counter) + + ". " + + sd.first + + "
    "); } - msg.append(text); + if (showFullFlag) { + fullText.append("" + + AString::number(counter) + ". "); + fullText.append(sd.second); + fullText.append("

    "); + } + ++counter; + } + + if (showFullFlag) { + fullText.append("

    " + "

    Understanding the Tab and Window Coordinate Spaces

    " + "

    " + "In PowerPoint, each slide maintains a fixed aspect ratio (the ratio of " + "height to width remains constant) with a spatial coordinate system " + "(typically inches). As a result, each annotation in PowerPoint is places " + "its annotions at a spatial coordinate (X and Y in inches). " + "In contrast, wb_view defaults to a " + "variable aspect ratio so that the window is resizable to best fit the brain " + "model (surface, volume, chart). This variable aspect ratio is problematic " + "for annotations in Tab or Window Space both of which use a percentage " + "coordinate system (0% at left/bottom and 100% at right/top). " + "

    " + "If one creates a Tab Space annotation with the variable aspect enabled and " + "changes the size of the window, the Tab Space annotation may no longer be in " + "the correct location. To correct this problem, wb_view supports “locking " + "of the aspect ratioâ€. When the aspect ratio is locked, the window (and " + "each tab within the window) are fixed to the aspect ratio at the time " + "aspect locking is enabled. If the size of the window changes while " + "the aspect is locked, the contents of window and each tab will expand or " + "contract in size but maintain a fixed aspect by adding space to sides " + "of the model when needed."); + fullText.append("

    " + "

    Scenes

    " + "

    " + "Scenes are closely related to annotations. Scenes allow one to preserve " + "'the state’ of wb_view. Thus one if one saves a scene, exits wb_view, later restarts " + "wb_view, and loads the scene, wb_view appears identical to when the scene was " + "originally saved. Scenes are frequently used for figures in publications. " + "Scenes are also uploaded to the BALSA database for sharing with other users." + "

    " + "While annotations can be saved in disk files, annotations are most commonly saved " + "to a scene. When creating annotations for a scene, it is a best practice to " + "save the annotations to the scene instead of creating a disk annotation file. "); } + AString msg; + msg.reserve(64 * 1024); + + msg.appendWithNewLine(""); + if (showFullFlag) { + msg.appendWithNewLine("

    Scenes and Annotations

    "); + } + msg.appendWithNewLine(briefText); + msg.appendWithNewLine(fullText); msg.appendWithNewLine(""); return msg; diff --git a/src/GuiQt/BestPracticesDialog.h b/src/GuiQt/BestPracticesDialog.h index 73399c2bf..51ea1c304 100644 --- a/src/GuiQt/BestPracticesDialog.h +++ b/src/GuiQt/BestPracticesDialog.h @@ -27,6 +27,7 @@ #include "WuQDialogNonModal.h" +class QLabel; class QPushButton; namespace caret { @@ -41,6 +42,7 @@ namespace caret { }; enum TextMode { + BRIEF_AND_FULL, BRIEF, FULL }; @@ -67,9 +69,7 @@ namespace caret { const InfoMode m_infoMode; - const TextMode m_textMode; - - AString m_labelText; + AString m_text; QPushButton* m_printPushButton; diff --git a/src/GuiQt/LockAspectWarningDialog.cxx b/src/GuiQt/LockAspectWarningDialog.cxx index 9e115eaf7..2eebda8d5 100644 --- a/src/GuiQt/LockAspectWarningDialog.cxx +++ b/src/GuiQt/LockAspectWarningDialog.cxx @@ -25,11 +25,12 @@ #include +#include +#include #include #include #include -#include -#include +#include #include #include "BestPracticesDialog.h" @@ -88,7 +89,7 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, if (dialog.exec() == LockAspectWarningDialog::Accepted) { s_doNotShowAgainStatusFlag = dialog.isDoNotShowAgainChecked(); - return dialog.getResult(); + return dialog.getOkResult(); } return Result::CANCEL; @@ -111,72 +112,97 @@ LockAspectWarningDialog::runDialog(const int32_t browserWindowIndex, * The parent widget. */ LockAspectWarningDialog::LockAspectWarningDialog(QWidget* parent) -: QDialog(parent) +: WuQDialogModal("Enter Annotations Mode", + parent) { - setWindowTitle("Warning: Aspect Unlocked"); - - const QString helpButtonText("More Info"); - - const AString msg = BestPracticesDialog::getTextForInfoMode(BestPracticesDialog::InfoMode::LOCK_ASPECT_BEST_PRACTICES, - BestPracticesDialog::TextMode::BRIEF); - QLabel* warningLabel = new QLabel(msg); - warningLabel->setWordWrap(true); - - QLabel* moreLabel = new QLabel("" - "For a more detailed explanation, click the " + helpButtonText + " button below. " - "Note: This dialog will close if " + helpButtonText + " is clicked " - "and the aspect will remain unlocked." - ""); - QPushButton* helpButton = new QPushButton(helpButtonText + "..."); - QObject::connect(helpButton, &QPushButton::clicked, - this, &LockAspectWarningDialog::helpButtonClicked); - - QLabel* buttonsLabel = new QLabel("Continue to Annotations Mode?"); - - QPushButton* lockWindowAndTabButton = new QPushButton("OK - Lock Aspect"); - QObject::connect(lockWindowAndTabButton, &QPushButton::clicked, - [=] { this->buttonClicked(Result::LOCK_ASPECT); }); - - QPushButton* noChangesButton = new QPushButton("OK - Aspect Remains Unlocked"); - QObject::connect(noChangesButton, &QPushButton::clicked, - [=] { this->buttonClicked(Result::NO_CHANGES); }); - - QPushButton* cancelButton = new QPushButton("Cancel"); - QObject::connect(cancelButton, &QPushButton::clicked, - [=] { this->buttonClicked(Result::CANCEL); }); - - m_doNotShowAgainCheckBox = new QCheckBox("Do not show again and user will be\n" - "responsible for aspect locking/unlocking"); - - QVBoxLayout* buttonLayout = new QVBoxLayout(); - buttonLayout->addWidget(buttonsLabel); - buttonLayout->addWidget(lockWindowAndTabButton); - buttonLayout->addWidget(noChangesButton); - buttonLayout->addWidget(cancelButton); - buttonLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); - buttonLayout->addWidget(m_doNotShowAgainCheckBox); - buttonLayout->addStretch(); - - QVBoxLayout* helpLayout = new QVBoxLayout(); - helpLayout->addWidget(warningLabel); - helpLayout->addWidget(moreLabel); - helpLayout->addWidget(helpButton, 0, Qt::AlignHCenter); - helpLayout->addStretch(); - - WuQtUtilities::matchWidgetWidths(lockWindowAndTabButton, - noChangesButton, - cancelButton); - - QHBoxLayout* dialogLayout = new QHBoxLayout(this); - dialogLayout->addLayout(helpLayout); - dialogLayout->addLayout(buttonLayout); + const QString mainInstructions("Do you want to lock the aspect ratio while entering annotations mode?"); + + const QString supplementalInstructions("" + "Prior to locking the aspect ratio, the user should adjust the size " + "of the window and optionally enable Tile Tabs for a multi-tab view. " + "If this has not been done, click the Cancel button, make those " + "adjustments, and then click the Toolbar's Annotate Mode button." + "

    " + "View the Best Practices Guide (this dialog " + "will close). This guide explains the importance of aspect " + "locking and documents procedures for successful creation of annotations " + "and scenes." + ""); + + const QString lockAspectInstructions("Locking the aspect ratio, and never unlocking the aspect " + "ratio, ensures annotations stay in the correct location."); + const QString leaveUnlockedInstructions("Advanced users may choose to lock and unlock the aspect ratio"); + + QLabel* mainInstructionsLabel = new QLabel(mainInstructions); + QFont font = mainInstructionsLabel->font(); + font.setPointSize(font.pointSize() * 1.4); + font.setBold(true); + mainInstructionsLabel->setFont(font); + + QLabel* supplementalInstructionLabel = new QLabel(supplementalInstructions); + supplementalInstructionLabel->setWordWrap(true); + QObject::connect(supplementalInstructionLabel, &QLabel::linkActivated, + this, &LockAspectWarningDialog::detailsLabelLinkActivated); + + QLabel* lockAspectLabel = new QLabel(lockAspectInstructions); + lockAspectLabel->setWordWrap(true); + QLabel* lockAspectRadioButtonLabel = new QLabel("Lock Aspect Ratio (Recommended)"); + m_lockAspectRadioButton = new QRadioButton(); + + QLabel* leaveUnlockedAspectRadioButtonLabel = new QLabel("Leave Aspect Ratio Unlocked"); + m_leaveUnlockedAspectRadioButton = new QRadioButton(); + QLabel* leaveUnlockedLabel = new QLabel(leaveUnlockedInstructions); + + QButtonGroup* buttGroup = new QButtonGroup(this); + buttGroup->addButton(m_lockAspectRadioButton); + buttGroup->addButton(m_leaveUnlockedAspectRadioButton); + m_lockAspectRadioButton->setChecked(true); + + m_doNotShowAgainCheckBox = new QCheckBox("Do not show again. User will not be warned about " + "aspect locking and unlocking."); /* - * Highlighted button + * No text is added to readio buttons since + * radio buttons and labels seem to get a different + * height in a grid layout. */ - QPushButton* defaultPushButton = lockWindowAndTabButton; - defaultPushButton->setAutoDefault(true); - defaultPushButton->setDefault(true); + const int COL_RADIO_EMPTY = 0; + const int COL_RADIO_BUTTON = 1; + const int COL_RADIO_LABEL = 2; + const int COL_RADIO_INFO = 3; + const int COL_RADIO_STRETCH = 4; + QGridLayout* buttonGridLayout = new QGridLayout(); + buttonGridLayout->setVerticalSpacing(4); + buttonGridLayout->setColumnMinimumWidth(COL_RADIO_EMPTY, 20); + buttonGridLayout->setColumnMinimumWidth(COL_RADIO_LABEL, 20); + buttonGridLayout->setColumnStretch(COL_RADIO_EMPTY, 0); + buttonGridLayout->setColumnStretch(COL_RADIO_BUTTON, 0); + buttonGridLayout->setColumnStretch(COL_RADIO_STRETCH, 100); + int row = 0; + buttonGridLayout->addWidget(m_lockAspectRadioButton, row, COL_RADIO_BUTTON); + buttonGridLayout->addWidget(lockAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); + row++; + buttonGridLayout->addWidget(lockAspectLabel, row, COL_RADIO_INFO); + row++; + buttonGridLayout->addWidget(m_leaveUnlockedAspectRadioButton, row, COL_RADIO_BUTTON); + buttonGridLayout->addWidget(leaveUnlockedAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); + row++; + buttonGridLayout->addWidget(leaveUnlockedLabel, row, COL_RADIO_INFO); + + QWidget* dialogWidget = new QWidget; + QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); + dialogLayout->addWidget(mainInstructionsLabel); + dialogLayout->addLayout(buttonGridLayout); + dialogLayout->addSpacing(10); + dialogLayout->addWidget(supplementalInstructionLabel); + dialogLayout->addSpacing(10); + dialogLayout->addWidget(m_doNotShowAgainCheckBox); + + setCentralWidget(dialogWidget, + WuQDialogModal::SCROLL_AREA_NEVER); + + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + } /** @@ -187,19 +213,31 @@ LockAspectWarningDialog::~LockAspectWarningDialog() } /** - * @return The selected lock status + * @return The result if the user clicked the OK button. */ LockAspectWarningDialog::Result -LockAspectWarningDialog::getResult() const +LockAspectWarningDialog::getOkResult() const { + if (m_lockAspectRadioButton->isChecked()) { + return Result::LOCK_ASPECT; + } + else if (m_leaveUnlockedAspectRadioButton->isChecked()) { + return Result::NO_CHANGES; + } + else { + CaretAssert(0); + } + return m_result; } /** - * Called when help button is clicked. + * Called when link in details label is clicked + * + * @param text of the link. */ void -LockAspectWarningDialog::helpButtonClicked() +LockAspectWarningDialog::detailsLabelLinkActivated(const QString& /*link*/) { /* * Best practices dialog will destroy itself when closed. @@ -210,30 +248,7 @@ LockAspectWarningDialog::helpButtonClicked() parentWidget()); dialog->showDialog(); - buttonClicked(Result::CANCEL); -} - -/** - * Called when one of the buttons is clicked. - * - * @param buttonClicked - * Button that was clicked. - */ -void -LockAspectWarningDialog::buttonClicked(const Result buttonClicked) -{ - m_result = buttonClicked; - switch (m_result) { - case Result::LOCK_ASPECT: - accept(); - break; - case Result::NO_CHANGES: - accept(); - break; - case Result::CANCEL: - reject(); - break; - } + reject(); } diff --git a/src/GuiQt/LockAspectWarningDialog.h b/src/GuiQt/LockAspectWarningDialog.h index baccdbe22..2859c4460 100644 --- a/src/GuiQt/LockAspectWarningDialog.h +++ b/src/GuiQt/LockAspectWarningDialog.h @@ -25,14 +25,14 @@ #include -#include +#include "WuQDialogModal.h" class QCheckBox; - +class QRadioButton; namespace caret { - class LockAspectWarningDialog : public QDialog { + class LockAspectWarningDialog : public WuQDialogModal { Q_OBJECT @@ -50,16 +50,14 @@ namespace caret { virtual ~LockAspectWarningDialog(); - Result getResult() const; + Result getOkResult() const; bool isDoNotShowAgainChecked() const; // ADD_NEW_METHODS_HERE private slots: - void helpButtonClicked(); - - void buttonClicked(const Result buttonClicked); + void detailsLabelLinkActivated(const QString& link); private: LockAspectWarningDialog(const LockAspectWarningDialog&); @@ -70,6 +68,10 @@ namespace caret { QCheckBox* m_doNotShowAgainCheckBox; + QRadioButton* m_lockAspectRadioButton; + + QRadioButton* m_leaveUnlockedAspectRadioButton; + static bool s_doNotShowAgainStatusFlag; // ADD_NEW_MEMBERS_HERE -- GitLab From 3397e71ddd40d03beadefe7d9b9f5691243a81d5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Feb 2018 14:48:19 -0600 Subject: [PATCH 639/755] For annotation/scene best practices, add item for scene files - do not move or rename data files reference by scenes. --- src/GuiQt/BestPracticesDialog.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx index 2cd4bda99..664ddd881 100644 --- a/src/GuiQt/BestPracticesDialog.cxx +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -170,6 +170,19 @@ BestPracticesDialog::getLockAspectText(const TextMode textMode) std::vector> summaryDetails; + { + const AString summary("Verify data files are in a common directory tree and file names are reasonable. "); + const AString details(summary + + "Scenes contain the directory path and filename for each data file that is loaded " + "at the time the scene is created. Once a scene has been created, moving or " + "renaming a data file referenced by the scene will cause an error when the scene is displayed. " + "In addition, if data files are scattered about many directories, this may cause " + "problems when zipping a scene file and its data files or uploading a scene file " + "to the BALSA database."); + + summaryDetails.push_back(std::make_pair(summary, details)); + } + { const AString summary("If a multi-tab scene will be created, enter Tile Tabs (View Menu->Enter Tile Tabs). "); const AString details(summary -- GitLab From 376691ce35697a0118a660bb5f116791eebba095 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Feb 2018 10:41:23 -0600 Subject: [PATCH 640/755] Compilation fix (don't use DELETE as an enumerated value). --- src/Brain/EventBrowserWindowContent.cxx | 2 +- src/Brain/EventBrowserWindowContent.h | 2 +- src/Brain/SessionManager.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Brain/EventBrowserWindowContent.cxx b/src/Brain/EventBrowserWindowContent.cxx index ab71321de..4ea87f4a8 100644 --- a/src/Brain/EventBrowserWindowContent.cxx +++ b/src/Brain/EventBrowserWindowContent.cxx @@ -86,7 +86,7 @@ EventBrowserWindowContent::newWindowContent(const int32_t windowIndex) std::unique_ptr EventBrowserWindowContent::deleteWindowContent(const int32_t windowIndex) { - EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::DELETE, + EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::DELETER, windowIndex); std::unique_ptr pointer(event); return pointer; diff --git a/src/Brain/EventBrowserWindowContent.h b/src/Brain/EventBrowserWindowContent.h index deb25ca63..b03dd88ce 100644 --- a/src/Brain/EventBrowserWindowContent.h +++ b/src/Brain/EventBrowserWindowContent.h @@ -37,7 +37,7 @@ namespace caret { public: enum class Mode { - DELETE, + DELETER, /* DELETE is reserved word in MS Visual Studio C++ */ GET, NEW }; diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 3ce0be075..11fd8e40c 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -369,7 +369,7 @@ SessionManager::receiveEvent(Event* event) CaretAssert(m_browserWindowContent[windowIndex]); switch (windowEvent->getMode()) { - case EventBrowserWindowContent::Mode::DELETE: + case EventBrowserWindowContent::Mode::DELETER: m_browserWindowContent[windowIndex]->setValid(false); break; case EventBrowserWindowContent::Mode::GET: -- GitLab From b92f5b6935676ffe0144b7a2702db680853cb0f8 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Thu, 22 Feb 2018 22:45:43 -0600 Subject: [PATCH 641/755] add coolwarm and spectral (inverse), update copyrights to prepare for additional matplotlib palettes --- README | 6 ++ src/Files/PaletteFile.cxx | 107 +++++++++++++++++++++++++++++++++ src/debian/copyright | 120 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) diff --git a/README b/README index e79505c77..720348613 100644 --- a/README +++ b/README @@ -87,3 +87,9 @@ rewritten for different argument types, modified Resources/FtglFonts/Vera*.ttf Copyright (c) 2003 Bitstream, Inc. licensed under Bitstream-Vera (basically, modification of fonts requires calling them something else), see debian/copyright file + +Files/PaletteFile.cxx +copied some palette definitions from matplotlib and its original sources +Copyright (c) 2012-2016 Matplotlib Development Team +Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University +licensed apache-2 and MDT (bsd-like) diff --git a/src/Files/PaletteFile.cxx b/src/Files/PaletteFile.cxx index 35c8a9ac7..9046cd8a0 100644 --- a/src/Files/PaletteFile.cxx +++ b/src/Files/PaletteFile.cxx @@ -836,6 +836,113 @@ PaletteFile::addDefaultPalettes() redWhiteBlue.addScalarAndColor(-1.0f, "rwbBlue"); addPalette(redWhiteBlue); } + + //coolwarm, http://www.kennethmoreland.com/color-maps/ + //"Diverging Color Maps for Scientific Visualization." Kenneth Moreland. In Proceedings of the 5th International Symposium on Visual Computing, December 2009. DOI 10.1007/978-3-642-10520-3_9. + //this palette was interpolated in CIELAB space, and then translated to sRGB, so we need to keep a substantial number of points + //use the 33 csv file + if (this->getPaletteByName("cool-warm") == NULL) { + Palette coolwarm; + coolwarm.setName("cool-warm"); + this->addColor("cool-warm-0", 59,76,192); + this->addColor("cool-warm-1", 68,90,204); + this->addColor("cool-warm-2", 77,104,215); + this->addColor("cool-warm-3", 87,117,225); + this->addColor("cool-warm-4", 98,130,234); + this->addColor("cool-warm-5", 108,142,241); + this->addColor("cool-warm-6", 119,154,247); + this->addColor("cool-warm-7", 130,165,251); + this->addColor("cool-warm-8", 141,176,254); + this->addColor("cool-warm-9", 152,185,255); + this->addColor("cool-warm-10", 163,194,255); + this->addColor("cool-warm-11", 174,201,253); + this->addColor("cool-warm-12", 184,208,249); + this->addColor("cool-warm-13", 194,213,244); + this->addColor("cool-warm-14", 204,217,238); + this->addColor("cool-warm-15", 213,219,230); + this->addColor("cool-warm-16", 221,221,221); + this->addColor("cool-warm-17", 229,216,209); + this->addColor("cool-warm-18", 236,211,197); + this->addColor("cool-warm-19", 241,204,185); + this->addColor("cool-warm-20", 245,196,173); + this->addColor("cool-warm-21", 247,187,160); + this->addColor("cool-warm-22", 247,177,148); + this->addColor("cool-warm-23", 247,166,135); + this->addColor("cool-warm-24", 244,154,123); + this->addColor("cool-warm-25", 241,141,111); + this->addColor("cool-warm-26", 236,127,99); + this->addColor("cool-warm-27", 229,112,88); + this->addColor("cool-warm-28", 222,96,77); + this->addColor("cool-warm-29", 213,80,66); + this->addColor("cool-warm-30", 203,62,56); + this->addColor("cool-warm-31", 192,40,47); + this->addColor("cool-warm-32", 180,4,38); + coolwarm.addScalarAndColor(16.0f / 16.0f, "cool-warm-32"); + coolwarm.addScalarAndColor(15.0f / 16.0f, "cool-warm-31"); + coolwarm.addScalarAndColor(14.0f / 16.0f, "cool-warm-30"); + coolwarm.addScalarAndColor(13.0f / 16.0f, "cool-warm-29"); + coolwarm.addScalarAndColor(12.0f / 16.0f, "cool-warm-28"); + coolwarm.addScalarAndColor(11.0f / 16.0f, "cool-warm-27"); + coolwarm.addScalarAndColor(10.0f / 16.0f, "cool-warm-26"); + coolwarm.addScalarAndColor(9.0f / 16.0f, "cool-warm-25"); + coolwarm.addScalarAndColor(8.0f / 16.0f, "cool-warm-24"); + coolwarm.addScalarAndColor(7.0f / 16.0f, "cool-warm-23"); + coolwarm.addScalarAndColor(6.0f / 16.0f, "cool-warm-22"); + coolwarm.addScalarAndColor(5.0f / 16.0f, "cool-warm-21"); + coolwarm.addScalarAndColor(4.0f / 16.0f, "cool-warm-20"); + coolwarm.addScalarAndColor(3.0f / 16.0f, "cool-warm-19"); + coolwarm.addScalarAndColor(2.0f / 16.0f, "cool-warm-18"); + coolwarm.addScalarAndColor(1.0f / 16.0f, "cool-warm-17"); + coolwarm.addScalarAndColor(0.0f / 16.0f, "cool-warm-16"); + coolwarm.addScalarAndColor(-1.0f / 16.0f, "cool-warm-15"); + coolwarm.addScalarAndColor(-2.0f / 16.0f, "cool-warm-14"); + coolwarm.addScalarAndColor(-3.0f / 16.0f, "cool-warm-13"); + coolwarm.addScalarAndColor(-4.0f / 16.0f, "cool-warm-12"); + coolwarm.addScalarAndColor(-5.0f / 16.0f, "cool-warm-11"); + coolwarm.addScalarAndColor(-6.0f / 16.0f, "cool-warm-10"); + coolwarm.addScalarAndColor(-7.0f / 16.0f, "cool-warm-9"); + coolwarm.addScalarAndColor(-8.0f / 16.0f, "cool-warm-8"); + coolwarm.addScalarAndColor(-9.0f / 16.0f, "cool-warm-7"); + coolwarm.addScalarAndColor(-10.0f / 16.0f, "cool-warm-6"); + coolwarm.addScalarAndColor(-11.0f / 16.0f, "cool-warm-5"); + coolwarm.addScalarAndColor(-12.0f / 16.0f, "cool-warm-4"); + coolwarm.addScalarAndColor(-13.0f / 16.0f, "cool-warm-3"); + coolwarm.addScalarAndColor(-14.0f / 16.0f, "cool-warm-2"); + coolwarm.addScalarAndColor(-15.0f / 16.0f, "cool-warm-1"); + coolwarm.addScalarAndColor(-16.0f / 16.0f, "cool-warm-0"); + addPalette(coolwarm); + } + + //matplotlib's spectral is from colorbrewer + //Colors from www.ColorBrewer.org by Cynthia A. Brewer, Geography, Pennsylvania State University. + //Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. + if (this->getPaletteByName("spectral") == NULL) { + Palette spectral; + spectral.setName("spectral"); + this->addColor("spectral-0", 158,1,66); + this->addColor("spectral-1", 213,62,79); + this->addColor("spectral-2", 244,109,67); + this->addColor("spectral-3", 253,174,97); + this->addColor("spectral-4", 254,224,139); + this->addColor("spectral-5", 255,255,191); + this->addColor("spectral-6", 230,245,152); + this->addColor("spectral-7", 171,221,164); + this->addColor("spectral-8", 102,194,165); + this->addColor("spectral-9", 50,136,189); + this->addColor("spectral-10", 94,79,162); + spectral.addScalarAndColor(5.0f / 5.0f, "spectral-0"); + spectral.addScalarAndColor(4.0f / 5.0f, "spectral-1"); + spectral.addScalarAndColor(3.0f / 5.0f, "spectral-2"); + spectral.addScalarAndColor(2.0f / 5.0f, "spectral-3"); + spectral.addScalarAndColor(1.0f / 5.0f, "spectral-4"); + spectral.addScalarAndColor(0.0f / 5.0f, "spectral-5"); + spectral.addScalarAndColor(-1.0f / 5.0f, "spectral-6"); + spectral.addScalarAndColor(-2.0f / 5.0f, "spectral-7"); + spectral.addScalarAndColor(-3.0f / 5.0f, "spectral-8"); + spectral.addScalarAndColor(-4.0f / 5.0f, "spectral-9"); + spectral.addScalarAndColor(-5.0f / 5.0f, "spectral-10"); + addPalette(spectral); + } if (this->getPaletteByName("JET256") == NULL) { Palette JET256; diff --git a/src/debian/copyright b/src/debian/copyright index 8dd5bbc51..1b89d54fc 100644 --- a/src/debian/copyright +++ b/src/debian/copyright @@ -59,6 +59,10 @@ Files: src/Resources/General/Fonts/LinuxLibertine/*.ttf Copyright: 2003-2009 Philipp H. Poll License: GPL-2+ with Font exception and OFL-1.1 +Files: src/Files/PaletteFile.cxx +Copyright: 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University + 2012-2016 Matplotlib Development Team +License: Apache-2 and MDT License: GPL-2+ This program is free software; you can redistribute it @@ -429,3 +433,119 @@ License: OFL-1.1 DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +License: MDT + License agreement for matplotlib versions 1.3.0 and later + ========================================================= + . + 1. This LICENSE AGREEMENT is between the Matplotlib Development Team + ("MDT"), and the Individual or Organization ("Licensee") accessing and + otherwise using matplotlib software in source or binary form and its + associated documentation. + . + 2. Subject to the terms and conditions of this License Agreement, MDT + hereby grants Licensee a nonexclusive, royalty-free, world-wide license + to reproduce, analyze, test, perform and/or display publicly, prepare + derivative works, distribute, and otherwise use matplotlib + alone or in any derivative version, provided, however, that MDT's + License Agreement and MDT's notice of copyright, i.e., "Copyright (c) + 2012- Matplotlib Development Team; All Rights Reserved" are retained in + matplotlib alone or in any derivative version prepared by + Licensee. + . + 3. In the event Licensee prepares a derivative work that is based on or + incorporates matplotlib or any part thereof, and wants to + make the derivative work available to others as provided herein, then + Licensee hereby agrees to include in any such work a brief summary of + the changes made to matplotlib . + . + 4. MDT is making matplotlib available to Licensee on an "AS + IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND + DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB + WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + . + 5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR + LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING + MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF + THE POSSIBILITY THEREOF. + . + 6. This License Agreement will automatically terminate upon a material + breach of its terms and conditions. + . + 7. Nothing in this License Agreement shall be deemed to create any + relationship of agency, partnership, or joint venture between MDT and + Licensee. This License Agreement does not grant permission to use MDT + trademarks or trade name in a trademark sense to endorse or promote + products or services of Licensee, or any third party. + . + 8. By copying, installing or otherwise using matplotlib , + Licensee agrees to be bound by the terms and conditions of this License + Agreement. + . + License agreement for matplotlib versions prior to 1.3.0 + ======================================================== + . + 1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the + Individual or Organization ("Licensee") accessing and otherwise using + matplotlib software in source or binary form and its associated + documentation. + . + 2. Subject to the terms and conditions of this License Agreement, JDH + hereby grants Licensee a nonexclusive, royalty-free, world-wide license + to reproduce, analyze, test, perform and/or display publicly, prepare + derivative works, distribute, and otherwise use matplotlib + alone or in any derivative version, provided, however, that JDH's + License Agreement and JDH's notice of copyright, i.e., "Copyright (c) + 2002-2011 John D. Hunter; All Rights Reserved" are retained in + matplotlib alone or in any derivative version prepared by + Licensee. + . + 3. In the event Licensee prepares a derivative work that is based on or + incorporates matplotlib or any part thereof, and wants to + make the derivative work available to others as provided herein, then + Licensee hereby agrees to include in any such work a brief summary of + the changes made to matplotlib. + . + 4. JDH is making matplotlib available to Licensee on an "AS + IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND + DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB + WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + . + 5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR + LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING + MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF + THE POSSIBILITY THEREOF. + . + 6. This License Agreement will automatically terminate upon a material + breach of its terms and conditions. + . + 7. Nothing in this License Agreement shall be deemed to create any + relationship of agency, partnership, or joint venture between JDH and + Licensee. This License Agreement does not grant permission to use JDH + trademarks or trade name in a trademark sense to endorse or promote + products or services of Licensee, or any third party. + . + 8. By copying, installing or otherwise using matplotlib, + Licensee agrees to be bound by the terms and conditions of this License + Agreement. + +License: Apache-2 + Apache-Style Software License for ColorBrewer software and ColorBrewer Color Schemes + . + Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. + . + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software distributed + under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. See the License for the + specific language governing permissions and limitations under the License. -- GitLab From 90a0957cdfb1dc7d00f77ca1599996b353b4734c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Feb 2018 09:15:06 -0600 Subject: [PATCH 642/755] Fixed problem with double scroll bars on Linux for Best Practices Dialog. --- src/GuiQt/BestPracticesDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BestPracticesDialog.cxx b/src/GuiQt/BestPracticesDialog.cxx index 664ddd881..aca973f2e 100644 --- a/src/GuiQt/BestPracticesDialog.cxx +++ b/src/GuiQt/BestPracticesDialog.cxx @@ -86,7 +86,7 @@ m_infoMode(infoMode) layout->addWidget(browser); setCentralWidget(widget, - WuQDialog::SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); + WuQDialog::SCROLL_AREA_NEVER); WuQtUtilities::limitWindowSizePercentageOfMaximum(this, 90.0, 80.0); } -- GitLab From 53796cb95c0f81180e67fdb054cf36e386df7647 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Feb 2018 09:28:43 -0600 Subject: [PATCH 643/755] Change logging level from "fine" to "finer" for missing scene elements. --- src/Scenes/SceneClass.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scenes/SceneClass.cxx b/src/Scenes/SceneClass.cxx index 12dfb959d..36a60414e 100644 --- a/src/Scenes/SceneClass.cxx +++ b/src/Scenes/SceneClass.cxx @@ -1229,7 +1229,7 @@ SceneClass::logMissing(const AString& missingInfo) const } if (s_debugLoggingEnabledFlag) { - CaretLogFine(missingInfo); + CaretLogFiner(missingInfo); } } -- GitLab From 0c873372c8323cb695d98076fd2724480c7a97b5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Feb 2018 09:37:11 -0600 Subject: [PATCH 644/755] Update for WB-778: When comparing "last read/write time" to "last modified time" use a "not equal" operator instead of "greater than" since a file could be made "older" (file restored to a previous state). Also, log at the Fine level the timestamps used in the comparison. --- src/Common/DataFile.cxx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Common/DataFile.cxx b/src/Common/DataFile.cxx index b3de1bc67..22c115d66 100644 --- a/src/Common/DataFile.cxx +++ b/src/Common/DataFile.cxx @@ -20,6 +20,7 @@ #include +#include "CaretLogger.h" #include "DataFile.h" #include "DataFileContentInformation.h" #include "DataFileException.h" @@ -360,11 +361,19 @@ DataFile::isModifiedSinceTimeOfLastReadOrWrite() const return false; } + CaretLogFine("Testing reload of " + + getFileNameNoPath() + + " last read/write: " + + m_timeOfLastReadOrWrite.toString(Qt::ISODate) + + " last modified: " + + lastModTime.toString(Qt::ISODate) + + ((m_timeOfLastReadOrWrite == lastModTime) ? " EQUAL" : " NOT EQUAL")); + /* * If last modified time is newer than * time of file read or written */ - if (lastModTime > m_timeOfLastReadOrWrite) { + if (lastModTime != m_timeOfLastReadOrWrite) { return true; } -- GitLab From 578452e57743423065c287ef7befb1d2bbf97d23 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Feb 2018 16:51:54 -0600 Subject: [PATCH 645/755] Fixed a crash during scene restoration when the contains one window that is not the first window (window index is not zero) that occurred with one of David's scenes. --- src/GuiQt/BrainOpenGLWidget.cxx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 2e87107a1..456604ba7 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -479,6 +479,21 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); + /* + * When restoring scene, the first browser window may get closed. + * This occurs when the user creates a scene that does not contain + * the first browser window. The close() method in QWindow may not execute + * destruction of the window so this widget may still be valid but + * GuiManager no longer has a pointer to the window since it is being closed. + * In this case, the window will be NULL. + * + * This problem is related to the moving window properties to the SessionManager, + * in Feb 2018. + */ + if (bbw == NULL) { + return; + } + EventBrowserWindowDrawingContent getModelEvent(this->windowIndex); EventManager::get()->sendEvent(getModelEvent.getPointer()); -- GitLab From 4b554c1821350d1f667393fa1a78c19ffb473ec9 Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Tue, 27 Feb 2018 18:55:20 -0600 Subject: [PATCH 646/755] add missing cylinder boundary criteria to myelin mapping method for testing --- src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx index a948f7782..0eeacde28 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx @@ -578,12 +578,13 @@ void AlgorithmVolumeToSurfaceMapping::precomputeWeightsMyelin(vectorgetCoordinate(node), nodeIndices, nodenormal = normals + (node * 3); roiVol->spaceToIndex(nodeCoord, nodeIndices); float nodeThick = thicknessData[node]; + float cylinderCorner = nodeThick * sqrt(5.0f) / 2.0f; int64_t min[3], max[3]; for (int i = 0; i < 3; ++i) { - min[i] = (int)ceil(nodeIndices[i] - range[i] * nodeThick); + min[i] = (int)ceil(nodeIndices[i] - range[i] * cylinderCorner); if (min[i] < 0) min[i] = 0; - max[i] = (int)floor(nodeIndices[i] + range[i] * nodeThick) + 1; + max[i] = (int)floor(nodeIndices[i] + range[i] * cylinderCorner) + 1; if (max[i] > myDims[i]) max[i] = myDims[i]; } double weightTotal = 0.0; @@ -597,7 +598,7 @@ void AlgorithmVolumeToSurfaceMapping::precomputeWeightsMyelin(vectorindexToSpace(ijk, voxelCoord); Vector3D delta = voxelCoord - nodeCoord; - if (abs(nodenormal.dot(delta)) < 0.5f * nodeThick && roiVol->getValue(ijk) > 0.0f) + if (abs(nodenormal.dot(delta)) < 0.5f * nodeThick && nodenormal.cross(delta).length() < nodeThick && roiVol->getValue(ijk) > 0.0f) { float weight = exp(delta.lengthsquared() * invnegsigmasquaredx2); myWeights[node].push_back(VoxelWeight(weight, ijk)); -- GitLab From 0bef2b5edc960fc16dc1606de5bdd957399f9ed0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Feb 2018 12:02:36 -0600 Subject: [PATCH 647/755] WB-714: Removed "Cancel" button from the dialog used for manual entry of tab or window aspect ratio. Also made fixes for the default aspect ratio when the tab or window aspect is not yet locked. --- src/GuiQt/BrainBrowserWindow.cxx | 136 +++++++++++++++++++++++++------ src/GuiQt/BrainBrowserWindow.h | 11 ++- 2 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index d59bfd160..ff9c4e137 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -759,11 +759,14 @@ BrainBrowserWindow::createActionsUsedByToolBar() this, &BrainBrowserWindow::processWindowMenuLockAllTabAspectRatioTriggered); const QString aspectButtonToolTipText("" - "Right-Click (Control-Click on Mac) to display a dialog " - "for manual entry of the aspect ratio for either the window " - "or the tab. The value displayed " - "is the value from the last time aspect was locked. If a " - "value is entered, the lock status is set to ON." + "Lock the aspect ratio of the window and all tabs. " + "Aspect ratios should be locked prior to creating " + "annotations and remain locked while annotations are " + "present." + "

    " + "Advanced users can right-click (control-click on Mac) " + "to manually adjust the aspect " + "ratio for the selected tab or the window." ""); m_toolBarLockWindowAndAllTabAspectRatioAction = new QAction(); @@ -920,58 +923,97 @@ BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu(const QPoint& po QAction* selectedAction = menu.exec(m_toolBarLockWindowAndAllTabAspectRatioButton->parentWidget()->mapToGlobal(pos)); if (selectedAction == windowAspectAction) { - float aspectRatio = getAspectRatioFromDialog(("Set Window " + float aspectRatio = getAspectRatioFromDialog(AspectRatioMode::WINDOW, + ("Window " + AString::number(m_browserWindowIndex + 1) - + " Aspect Ratio..."), + + " Aspect Ratio"), getAspectRatio(), this); if (aspectRatio > 0.0f) { - lockWindowAspectRatio(true); - m_browserWindowContent->setWindowAspectLockedRatio(aspectRatio); + aspectRatioDialogUpdateForWindow(aspectRatio); } } else if (selectedAction == tabAspectAction) { - float aspectRatio = getAspectRatioFromDialog(("Set Tab " - + tabContent->getName() - + " Aspect Ratio..."), - tabContent->getAspectRatio(), - this); + float aspectRatio = tabContent->getAspectRatio(); + + if ( ! tabContent->isAspectRatioLocked()) { + /* + * When aspect is NOT locked, need to get current aspect ratio + */ + aspectRatio = getOpenGLWidgetAspectRatio(); + + if (isTileTabsSelected()) { + /* + * When tile tabs is enabled, find the tab to get its aspect ratio + */ + std::vector allViewportContent = m_openGLWidget->getViewportContent(); + for (auto vc : allViewportContent) { + if (vc->getTabIndex() == tabContent->getTabNumber()) { + int viewport[4]; + vc->getModelViewport(viewport); + if (viewport[3] > 0) { + aspectRatio = (static_cast(viewport[3]) + / static_cast(viewport[2])); + break; + } + } + } + } + } + + aspectRatio = getAspectRatioFromDialog(AspectRatioMode::TAB, + ("Tab " + + tabContent->getName() + + " Aspect Ratio"), + aspectRatio, + this); if (aspectRatio > 0.0f) { - lockAllTabAspectRatios(true); - tabContent->setAspectRatio(aspectRatio); - tabContent->setAspectRatioLocked(true); + aspectRatioDialogUpdateForTab(aspectRatio); } } - - updateActionsForLockingAspectRatios(); - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } } /** * Get the new aspect ratio using a dialog. * + * @param aspectRatioMode + * Mode (tab or window) * @param title * Title for dialog. - * @param aspectRatio + * @param originalAspectRatio * Default value for aspect ratio * @param parent * Parent for the dialog. */ float -BrainBrowserWindow::getAspectRatioFromDialog(const QString& title, - const float aspectRatio, - QWidget* parent) const +BrainBrowserWindow::getAspectRatioFromDialog(const AspectRatioMode aspectRatioMode, + const QString& title, + const float aspectRatio, + QWidget* parent) const { float aspectRatioOut = -1.0; - WuQDataEntryDialog ded("Aspect Ratio", + WuQDataEntryDialog ded("Set Aspect Ratio", parent); + ded.setCancelButtonText(""); QDoubleSpinBox* ratioSpinBox = ded.addDoubleSpinBox(title, aspectRatio); ratioSpinBox->setSingleStep(0.01); ratioSpinBox->setRange(ratioSpinBox->singleStep(), 100.0); ratioSpinBox->setDecimals(3); + ratioSpinBox->setKeyboardTracking(true); + + switch (aspectRatioMode) { + case AspectRatioMode::TAB: + QObject::connect(ratioSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindow::aspectRatioDialogUpdateForTab); + break; + case AspectRatioMode::WINDOW: + QObject::connect(ratioSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &BrainBrowserWindow::aspectRatioDialogUpdateForWindow); + break; + } if (ded.exec() == WuQDataEntryDialog::Accepted) { aspectRatioOut = ratioSpinBox->value(); } @@ -979,7 +1021,44 @@ BrainBrowserWindow::getAspectRatioFromDialog(const QString& title, return aspectRatioOut; } +/** + * Called when the user manually adjust aspect ratio for all tabs. + * + * @param aspectRatio + * New aspect ratio. + */ +void +BrainBrowserWindow::aspectRatioDialogUpdateForTab(const double aspectRatio) +{ + BrowserTabContent* tabContent = getBrowserTabContent(); + + if (aspectRatio > 0.0f) { + lockAllTabAspectRatios(true); + tabContent->setAspectRatio(aspectRatio); + tabContent->setAspectRatioLocked(true); + } + + updateActionsForLockingAspectRatios(); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); +} +/** + * Called when the user manually adjust aspect ratio for window. + * + * @param aspectRatio + * New aspect ratio. + */ +void +BrainBrowserWindow::aspectRatioDialogUpdateForWindow(const double aspectRatio) +{ + if (aspectRatio > 0.0f) { + lockWindowAspectRatio(true); + m_browserWindowContent->setWindowAspectLockedRatio(aspectRatio); + } + + updateActionsForLockingAspectRatios(); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); +} /** * Update the actions for window menu's lock window aspect, window menu's lock @@ -1016,6 +1095,13 @@ BrainBrowserWindow::isWindowAspectRatioLocked() const float BrainBrowserWindow::getAspectRatio() const { + if ( ! m_browserWindowContent->isWindowAspectLocked()) { + /* + * When aspect NOT locked, use the OpenGL widget's aspect ratio + */ + m_browserWindowContent->setWindowAspectLockedRatio(getOpenGLWidgetAspectRatio()); + } + return m_browserWindowContent->getWindowAspectLockedRatio(); } diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 20f4b72ea..de77b8a0f 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -238,6 +238,9 @@ namespace caret { void processEditMenuItemTriggered(QAction* action); void processEditMenuAboutToShow(); + void aspectRatioDialogUpdateForTab(const double aspectRatio); + void aspectRatioDialogUpdateForWindow(const double aspectRatio); + private: // Contains status of components such as enter/exit full screen struct WindowComponentStatus { @@ -254,6 +257,11 @@ namespace caret { CREATE_DEFAULT_TABS_NO }; + enum class AspectRatioMode { + TAB, + WINDOW + }; + BrainBrowserWindow(const int browserWindowIndex, BrowserTabContent* browserTabContent, const CreateDefaultTabsMode createDefaultTabsMode, @@ -308,7 +316,8 @@ namespace caret { void lockAllTabAspectRatios(const bool checked); void updateActionsForLockingAspectRatios(); - float getAspectRatioFromDialog(const QString& title, + float getAspectRatioFromDialog(const AspectRatioMode aspectRatioMode, + const QString& title, const float aspectRatio, QWidget* parent) const; -- GitLab From c2b196b07ad1710136a6700a2abeb25a5ab39b7f Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 5 Mar 2018 22:48:47 -0600 Subject: [PATCH 648/755] add filename to nifti errors and warnings --- src/Nifti/NiftiHeader.cxx | 32 ++++++++++++++++---------------- src/Nifti/NiftiHeader.h | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Nifti/NiftiHeader.cxx b/src/Nifti/NiftiHeader.cxx index 386050431..55e879be3 100644 --- a/src/Nifti/NiftiHeader.cxx +++ b/src/Nifti/NiftiHeader.cxx @@ -633,14 +633,14 @@ void NiftiHeader::read(CaretBinaryFile& inFile) swapped = true; swapHeaderBytes(buffer2); } - myquirks = setupFrom(buffer2); + myquirks = setupFrom(buffer2, inFile.getFilename()); } else if (version == 1) { if (NIFTI2_NEEDS_SWAP(buffer1))//yes, this works on nifti-1 also { swapped = true; swapHeaderBytes(buffer1); } - myquirks = setupFrom(buffer1); + myquirks = setupFrom(buffer1, inFile.getFilename()); } else { throw DataFileException(inFile.getFilename() + " is not a valid NIfTI file"); } @@ -695,27 +695,27 @@ void NiftiHeader::read(CaretBinaryFile& inFile) m_version = version; } -NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_1_header& header) +NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_1_header& header, const AString& filename) { Quirks ret; - if (header.sizeof_hdr != sizeof(nifti_1_header)) throw DataFileException("incorrect sizeof_hdr"); + if (header.sizeof_hdr != sizeof(nifti_1_header)) throw DataFileException(filename, "incorrect sizeof_hdr"); const char magic[] = "n+1\0";//only support single-file nifti - if (strncmp(header.magic, magic, 4) != 0) throw DataFileException("incorrect magic"); - if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException("incorrect dim[0]"); + if (strncmp(header.magic, magic, 4) != 0) throw DataFileException(filename, "incorrect magic"); + if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException(filename, "incorrect dim[0]"); for (int i = 0; i < header.dim[0]; ++i) { - if (header.dim[i + 1] < 1) throw DataFileException("dim[" + QString::number(i + 1) + "] < 1"); + if (header.dim[i + 1] < 1) throw DataFileException(filename, "dim[" + QString::number(i + 1) + "] < 1"); } if (header.vox_offset < 352) { if (header.vox_offset < 348) { - throw DataFileException("invalid vox_offset: " + AString::number(header.vox_offset)); + throw DataFileException(filename, "invalid vox_offset: " + AString::number(header.vox_offset)); } ret.no_extender = true; } int numBits = typeToNumBits(header.datatype); - if (header.bitpix != numBits) CaretLogWarning("datatype disagrees with bitpix"); + if (header.bitpix != numBits) CaretLogWarning("datatype disagrees with bitpix in file '" + filename + "'"); m_header.sizeof_hdr = header.sizeof_hdr;//copy in everything, so we don't have to fake anything to print the header as read for (int i = 0; i < 4; ++i)//mostly using nifti-2 field order to make it easier to find if things are missed { @@ -761,22 +761,22 @@ NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_1_header& header) return ret; } -NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_2_header& header) +NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_2_header& header, const AString& filename) { Quirks ret; - if (header.sizeof_hdr != sizeof(nifti_2_header)) throw DataFileException("incorrect sizeof_hdr"); + if (header.sizeof_hdr != sizeof(nifti_2_header)) throw DataFileException(filename, "incorrect sizeof_hdr"); const char magic[] = "n+2\0\r\n\032\n";//only support single-file nifti for (int i = 0; i < 8; ++i) { - if (header.magic[i] != magic[i]) throw DataFileException("incorrect magic"); + if (header.magic[i] != magic[i]) throw DataFileException(filename, "incorrect magic"); } - if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException("incorrect dim[0]"); + if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException(filename, "incorrect dim[0]"); for (int i = 0; i < header.dim[0]; ++i) { - if (header.dim[i + 1] < 1) throw DataFileException("dim[" + QString::number(i + 1) + "] < 1"); + if (header.dim[i + 1] < 1) throw DataFileException(filename, "dim[" + QString::number(i + 1) + "] < 1"); } - if (header.vox_offset < 544) throw DataFileException("incorrect vox_offset");//haven't noticed any nifti-2 with bad vox_offset yet, and all cifti files have a big extension, so they have to have used it correctly - if (header.bitpix != typeToNumBits(header.datatype)) CaretLogWarning("datatype disagrees with bitpix"); + if (header.vox_offset < 544) throw DataFileException(filename, "incorrect vox_offset");//haven't noticed any nifti-2 with bad vox_offset yet, and all cifti files have a big extension, so they have to have used it correctly + if (header.bitpix != typeToNumBits(header.datatype)) CaretLogWarning("datatype disagrees with bitpix in file '" + filename + "'"); memcpy(&m_header, &header, sizeof(nifti_2_header)); return ret; } diff --git a/src/Nifti/NiftiHeader.h b/src/Nifti/NiftiHeader.h index c00f26720..cf733e8ec 100644 --- a/src/Nifti/NiftiHeader.h +++ b/src/Nifti/NiftiHeader.h @@ -90,8 +90,8 @@ namespace caret static void swapHeaderBytes(nifti_2_header &header); void prepareHeader(nifti_1_header& header) const;//transform internal state into ready to write header struct void prepareHeader(nifti_2_header& header) const; - Quirks setupFrom(const nifti_1_header& header);//error check provided header, and populate members from it - Quirks setupFrom(const nifti_2_header& header); + Quirks setupFrom(const nifti_1_header& header, const AString& filename);//error check provided header, and populate members from it + Quirks setupFrom(const nifti_2_header& header, const AString& filename); static int typeToNumBits(const int64_t& type); int64_t computeVoxOffset(const int& version) const; }; -- GitLab From fa1b05e275b70439b2f223c375e13af7677dabac Mon Sep 17 00:00:00 2001 From: Tim Coalson Date: Mon, 5 Mar 2018 23:08:36 -0600 Subject: [PATCH 649/755] new myelin-like option for ribbon mapping --- .../AlgorithmVolumeToSurfaceMapping.cxx | 63 ++++++++++++++++--- .../AlgorithmVolumeToSurfaceMapping.h | 6 +- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx index 0eeacde28..c49a881d9 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx @@ -30,6 +30,9 @@ #include "Vector3D.h" #include "VolumeFile.h" +#include "AlgorithmSurfaceToSurface3dDistance.h" +#include "AlgorithmCreateSignedDistanceVolume.h" + #include #include @@ -69,6 +72,8 @@ OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() OptionalParameter* ribbonSubdiv = ribbonOpt->createOptionalParameter(4, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdiv->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); ribbonOpt->createOptionalParameter(7, "-thin-columns", "use non-overlapping polyhedra"); + OptionalParameter* gaussianOpt = ribbonOpt->createOptionalParameter(8, "-gaussian", "reduce weight to voxels that aren't near "); + gaussianOpt->addDoubleParameter(1, "scale", "value to multiply the local thickness by, to get the gaussian sigma"); OptionalParameter* ribbonWeights = ribbonOpt->createOptionalParameter(5, "-output-weights", "write the voxel weights for a vertex to a volume file"); ribbonWeights->addIntegerParameter(1, "vertex", "the vertex number to get the voxel weights for, 0-based"); ribbonWeights->addVolumeOutputParameter(2, "weights-out", "volume to write the weights to"); @@ -89,14 +94,15 @@ OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for sampling. " + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + - "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " + "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " + "The volume ROI is useful to exclude partial volume effects of voxels the surfaces pass through, and will cause the mapping to ignore " + "voxels that don't have a positive value in the mask. The subdivision number specifies how it approximates the amount of the volume the polyhedron " + "intersects, by splitting each voxel into NxNxN pieces, and checking whether the center of each piece is inside the polyhedron. If you have very large " + - "voxels, consider increasing this if you get zeros in your output.\n\n" + - "The myelin style method uses part of the caret5 myelin mapping command to do the mapping: for each surface vertex, take all voxels closer than the thickness at the vertex " + - "that are within the ribbon ROI, and less than half the thickness value away from the vertex along the direction of the surface normal, and apply a gaussian kernel " + - "with the specified sigma to them to get the weights to use." + "voxels, consider increasing this if you get zeros in your output. " + + "The -gaussian option makes it act more like the myelin method, where the distance of a voxel from is used to downweight the voxel.\n\n" + + "The myelin style method uses part of the caret5 myelin mapping command to do the mapping: for each surface vertex, take all voxels that are in a cylinder " + + "with width and height equal to cortical thickness, centered on the vertex and aligned with the surface normal, and that are also within the ribbon ROI, " + + "and apply a gaussian kernel with the specified sigma to them to get the weights to use." ); return ret; } @@ -200,6 +206,13 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam } } bool thinColumns = ribbonOpt->getOptionalParameter(7)->m_present; + float gaussScale = -1.0f; + OptionalParameter* gaussianOpt = ribbonOpt->getOptionalParameter(8); + if (gaussianOpt->m_present) + { + gaussScale = (float)gaussianOpt->getDouble(1); + if (!(gaussScale > 0.0f)) throw AlgorithmException("gaussian scale must be positive"); + } int weightsOutVertex = -1; VolumeFile* weightsOut = NULL; OptionalParameter* ribbonWeights = ribbonOpt->getOptionalParameter(5); @@ -208,7 +221,8 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam weightsOutVertex = (int)ribbonWeights->getInteger(1); weightsOut = ribbonWeights->getOutputVolume(2); } - AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, mySubVol, weightsOutVertex, weightsOut); + AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, + mySubVol, gaussScale, weightsOutVertex, weightsOut); OptionalParameter* ribbonWeightsText = ribbonOpt->getOptionalParameter(6); if (ribbonWeightsText->m_present) {//do this after the algorithm, to let it do the error condition checking @@ -217,7 +231,7 @@ void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParam vector > myWeights; const float* roiFrame = NULL; if (myRoiVol != NULL) roiFrame = myRoiVol->getFrame(); - RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); + AlgorithmVolumeToSurfaceMapping::precomputeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns, mySurface, gaussScale); for (int i = 0; i < (int)myWeights.size(); ++i) { outFile << i << ", " << myWeights[i].size(); @@ -344,7 +358,7 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* //ribbon mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol, - const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, + const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, const float& gaussScale, const int& weightsOutVertex, VolumeFile* weightsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); @@ -382,7 +396,7 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* vector > myWeights; const float* roiFrame = NULL; if (roiVol != NULL) roiFrame = roiVol->getFrame(); - RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); + precomputeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns, mySurface, gaussScale); if (weightsOut != NULL) { weightsOut->setValueAllVoxels(0.0f); @@ -466,6 +480,37 @@ AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* } } +void AlgorithmVolumeToSurfaceMapping::precomputeWeightsRibbon(vector >& myWeights, const VolumeSpace& volSpace, + const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame, + const int& subdivisions, const bool& thinColumns, const SurfaceFile* gaussSurf, const float& gaussScale) +{ + RibbonMappingHelper::computeWeightsRibbon(myWeights, volSpace, innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); + if (gaussScale > 0.0f) + { + VolumeFile signedDistVol; + MetricFile thickness; + AlgorithmSurfaceToSurface3dDistance(NULL, innerSurf, outerSurf, &thickness); + int numNodes = innerSurf->getNumberOfNodes(); + float maxThick = thickness.getValue(0, 0); + for (int i = 1; i < numNodes; ++i) + { + float thisThick = thickness.getValue(i, 0); + if (thisThick > maxThick) maxThick = thisThick; + } + signedDistVol.reinitialize(volSpace); + AlgorithmCreateSignedDistanceVolume(NULL, gaussSurf, &signedDistVol, NULL, maxThick * gaussScale * 3.0f, maxThick * gaussScale * 3.0f);//if we somehow have a voxel really far away compared to thickness, treat it as at least 3 sigma + for (int i = 0; i < numNodes; ++i) + {//modify the weights from the ribbon helper + vector& nodeWeights = myWeights[i]; + for (int j = 0; j < (int)nodeWeights.size(); ++j) + { + float toSquare = signedDistVol.getValue(nodeWeights[j].ijk) / (thickness.getValue(i, 0) * gaussScale);//negatives are fine, we are going to square it + nodeWeights[j].weight *= exp(-toSquare * toSquare / 2); + } + } + } +} + //myelin style mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol): AbstractAlgorithm(myProgObj) diff --git a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h index 85eb25109..ace638b42 100644 --- a/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h +++ b/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h @@ -34,7 +34,9 @@ namespace caret { class AlgorithmVolumeToSurfaceMapping : public AbstractAlgorithm { AlgorithmVolumeToSurfaceMapping(); - void precomputeWeightsMyelin(std::vector >& myWeights, const SurfaceFile* mySurface, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma); + static void precomputeWeightsMyelin(std::vector >& myWeights, const SurfaceFile* mySurface, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma); + static void precomputeWeightsRibbon(std::vector >& myWeights, const VolumeSpace& volSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, + const float* roiFrame, const int& subdivisions, const bool& thinColumns, const SurfaceFile* gaussSurf, const float& gaussScale); enum Method { TRILINEAR, @@ -52,7 +54,7 @@ namespace caret { AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, - const int64_t& mySubVol = -1, + const int64_t& mySubVol = -1, const float& gaussScale = -1.0f, const int& weightsOutVertex = -1, VolumeFile* weightsOut = NULL); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol = -1); -- GitLab From 6dbcf306e0fd137a7119cbc887119852f6a000d0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 2 Mar 2018 09:27:13 -0600 Subject: [PATCH 650/755] Improve error message if user tries to draw a border in tile tabs on a model (such as volume) that does not support border drawing. --- src/GuiQt/UserInputModeBordersWidget.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/UserInputModeBordersWidget.cxx b/src/GuiQt/UserInputModeBordersWidget.cxx index c9f718fa5..61ef74a4d 100644 --- a/src/GuiQt/UserInputModeBordersWidget.cxx +++ b/src/GuiQt/UserInputModeBordersWidget.cxx @@ -609,11 +609,16 @@ UserInputModeBordersWidget::drawFinishButtonClicked() } if (surface == NULL) { - CaretLogSevere("PROGRAM ERROR: Cannot find surface for border drawing."); + AString tabsMessage; + if (browserWindow->isTileTabsSelected()) { + tabsMessage = "Verify that points are added in the SELECTED tab."; + } + WuQMessageBox::errorOk(this, "Borders may only be drawn on surface models. " + + tabsMessage); return; } if (brain == NULL) { - CaretLogSevere("PROGRAM ERROR: Cannot find surface for border drawing."); + CaretLogSevere("PROGRAM ERROR: Cannot find brain for border drawing."); return; } -- GitLab From 123410683c3ad7bfbb57f392a8efed6363d067b4 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 2 Mar 2018 09:27:40 -0600 Subject: [PATCH 651/755] Hide "Image" mode button since image alignment has never been fully implemented. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 7af465847..231647b1f 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -2582,13 +2582,18 @@ BrainBrowserWindowToolBar::createModeWidget() /* * Image */ - this->modeInputModeImageAction = WuQtUtilities::createAction("Image", - "Edit Image Control Points", - this); - this->modeInputModeImageAction->setCheckable(true); - QToolButton* inputModeImageToolButton = new QToolButton(); - inputModeImageToolButton->setDefaultAction(this->modeInputModeImageAction); - WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeImageToolButton); + const bool showImageButtonFlag = false; + this->modeInputModeImageAction = NULL; + QToolButton* inputModeImageToolButton = NULL; + if (showImageButtonFlag) { + modeInputModeImageAction = WuQtUtilities::createAction("Image", + "Edit Image Control Points", + this); + this->modeInputModeImageAction->setCheckable(true); + inputModeImageToolButton = new QToolButton(); + inputModeImageToolButton->setDefaultAction(this->modeInputModeImageAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeImageToolButton); + } /* * Volume Edit @@ -2632,8 +2637,10 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeVolumeEditButton); inputModeFociToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeFociToolButton->sizePolicy().verticalPolicy()); - inputModeImageToolButton->setSizePolicy(QSizePolicy::Preferred, - inputModeImageToolButton->sizePolicy().verticalPolicy()); + if (inputModeImageToolButton != NULL) { + inputModeImageToolButton->setSizePolicy(QSizePolicy::Preferred, + inputModeImageToolButton->sizePolicy().verticalPolicy()); + } /* * Layout for input modes @@ -2646,8 +2653,13 @@ BrainBrowserWindowToolBar::createModeWidget() modeRow++; inputModeLayout->addWidget(inputModeBordersToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; - inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); - inputModeLayout->addWidget(inputModeImageToolButton, modeRow, 1); + if (inputModeImageToolButton != NULL) { + inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); + inputModeLayout->addWidget(inputModeImageToolButton, modeRow, 1); + } + else { + inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); + } modeRow++; inputModeLayout->addWidget(inputModeViewToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; @@ -2658,7 +2670,9 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeActionGroup->addAction(this->modeInputModeAnnotationsAction); this->modeInputModeActionGroup->addAction(this->modeInputModeBordersAction); this->modeInputModeActionGroup->addAction(this->modeInputModeFociAction); - this->modeInputModeActionGroup->addAction(this->modeInputModeImageAction); + if (this->modeInputModeImageAction != NULL) { + this->modeInputModeActionGroup->addAction(this->modeInputModeImageAction); + } this->modeInputModeActionGroup->addAction(this->modeInputModeViewAction); this->modeInputModeActionGroup->addAction(this->modeInputVolumeEditAction); QObject::connect(this->modeInputModeActionGroup, SIGNAL(triggered(QAction*)), @@ -2736,7 +2750,8 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) else if (action == this->modeInputModeFociAction) { inputMode = UserInputModeAbstract::FOCI; } - else if (action == this->modeInputModeImageAction) { + else if ((action == this->modeInputModeImageAction) + && (this->modeInputModeImageAction != NULL)) { inputMode = UserInputModeAbstract::IMAGE; } else if (action == this->modeInputVolumeEditAction) { @@ -2789,7 +2804,9 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte this->modeInputModeFociAction->setChecked(true); break; case UserInputModeAbstract::IMAGE: - this->modeInputModeImageAction->setChecked(true); + if (this->modeInputModeImageAction != NULL) { + this->modeInputModeImageAction->setChecked(true); + } break; case UserInputModeAbstract::VOLUME_EDIT: this->modeInputVolumeEditAction->setChecked(true); -- GitLab From b8f0e3dc03d4e9b0c5c7b3d727fd26c8aa2bfa5d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 5 Mar 2018 10:37:22 -0600 Subject: [PATCH 652/755] Updated Help Pages for Version 1.3 --- .../Annotations/Annotations.fld/image001.png | Bin 29103 -> 0 bytes .../Annotations/Annotations.fld/image002.png | Bin 153110 -> 0 bytes .../Annotations/Annotations.fld/image003.png | Bin 6266 -> 0 bytes .../Annotations/Annotations.fld/image014.png | Bin 12171 -> 0 bytes .../Annotations/Annotations.fld/image016.png | Bin 12125 -> 0 bytes .../Annotations/Annotations.fld/image017.png | Bin 24628 -> 0 bytes .../Annotations/Annotations.fld/image019.png | Bin 32969 -> 0 bytes .../Annotations/Annotations.fld/image020.png | Bin 43812 -> 0 bytes .../Annotations/Annotations.fld/image021.png | Bin 32932 -> 0 bytes .../Annotations/Annotations.fld/image022.png | Bin 72586 -> 0 bytes .../HelpFiles/Annotations/Annotations.html | 1242 +++++++++++------ .../Annotations_1.3.fld/image001.png | Bin 0 -> 28753 bytes .../Annotations_1.3.fld/image002.png | Bin 0 -> 135691 bytes .../Annotations_1.3.fld/image003.png | Bin 0 -> 176249 bytes .../Annotations_1.3.fld/image004.png | Bin 0 -> 33435 bytes .../Annotations_1.3.fld/image005.png | Bin 0 -> 34791 bytes .../Annotations_1.3.fld/image006.png | Bin 0 -> 34204 bytes .../Annotations_1.3.fld/image007.png | Bin 0 -> 181701 bytes .../Annotations_1.3.fld/image008.png | Bin 0 -> 153887 bytes .../Annotations_1.3.fld/image009.png | Bin 0 -> 7942 bytes .../image010.png} | Bin .../image011.png} | Bin .../image012.png} | Bin .../image013.png} | Bin .../image014.png} | Bin .../image015.png} | Bin .../image016.png} | Bin .../image017.png} | Bin .../Annotations_1.3.fld/image018.png | Bin 0 -> 2889 bytes .../image019.png} | Bin .../image020.png} | Bin .../image021.png} | Bin .../Annotations_1.3.fld/image022.png | Bin 0 -> 12660 bytes .../Annotations_1.3.fld/image023.png | Bin 0 -> 24230 bytes .../image024.png} | Bin .../Annotations_1.3.fld/image025.png | Bin 0 -> 27924 bytes .../Annotations_1.3.fld/image026.png | Bin 0 -> 38314 bytes .../Annotations_1.3.fld/image027.png | Bin 0 -> 32646 bytes .../Annotations_1.3.fld/image028.png | Bin 0 -> 72127 bytes src/Resources/Help/HelpFiles/Edit_Menu.png | Bin 0 -> 37542 bytes .../Annotations/Annotations.fld/filelist.xml | 6 + .../Annotations/Annotations.fld/image001.png | Bin 0 -> 40514 bytes .../Annotations.fld/themedata.thmx | Bin 0 -> 3114 bytes .../Annotations/Annotations.html | Bin 0 -> 133894 bytes .../Annotations/annotations.png | Bin 0 -> 40514 bytes .../Features_Toolbox/Borders/Borders.html | 313 +++-- .../Borders/Borders_Attributes.png | Bin 49469 -> 52887 bytes .../Features_Toolbox/Features_Toolbox.html | 148 +- .../Features_Toolbox/Foci/Foci_Attributes.png | Bin 42066 -> 44627 bytes .../Features_Toolbox/Images/Images.html | 84 +- .../Images/Images_Attributes.png | Bin 0 -> 41205 bytes .../Images/Images_Selection.png | Bin 24192 -> 31089 bytes .../HelpFiles/Menus/Data_Menu/Data_Menu.html | 48 +- .../Menus/Develop_Menu/Develop_Menu.html | 39 +- .../Edit_Menu/Edit_Menu.fld/filelist.xml | 5 + .../Edit_Menu/Edit_Menu.fld/themedata.thmx | Bin 0 -> 3114 bytes .../HelpFiles/Menus/Edit_Menu/Edit_Menu.html | 141 +- .../HelpFiles/Menus/Edit_Menu/Edit_Menu.png | Bin 37502 -> 37542 bytes src/Resources/Help/HelpFiles/Menus/Menus.html | 33 + .../Help/HelpFiles/Menus/Window_Menu.png | Bin 0 -> 68153 bytes .../Menus/Window_Menu/Window_Menu.html | 226 ++- .../Menus/Window_Menu/Window_Menu.png | Bin 78555 -> 68153 bytes .../Chart_Layers/Chart Layers.html | 58 + .../Chart_Layers/LineChartingLayers.png | Bin 0 -> 64879 bytes .../Overlay_Toolbox/Charting/Charting.html | 198 +-- .../Connectivity/Connectivity.html | 143 +- .../Overlay_Toolbox/Layers/Layers.html | 159 +-- .../Overlay_Toolbox_horiz.png | Bin 0 -> 59077 bytes .../Overlay_Toolbox/Overlay_Toolbox.html | 146 +- .../Overlay_Toolbox/Overlay_Toolbox_horiz.png | Bin 61836 -> 63422 bytes .../Overlay_Toolbox/Overlay_Toolbox_vert.png | Bin 67601 -> 66644 bytes .../Vol-Surf_Outline/Vol-Surf_Outline.html | 119 +- .../Scenes_Window/Scenes_Window.html | 251 ++-- .../HelpFiles/Scenes_Window/Scenes_Window.png | Bin 156094 -> 328462 bytes .../Help/HelpFiles/Toolbar/AllToolbar.png | Bin 0 -> 87816 bytes .../Toolbar/All_View/All_Toolbar.png | Bin 65607 -> 0 bytes .../HelpFiles/Toolbar/All_View/All_View.html | 184 --- .../HelpFiles/Toolbar/All_View/All_view.png | Bin 58954 -> 0 bytes .../Help/HelpFiles/Toolbar/All_View/Thumbs.db | Bin 10752 -> 0 bytes .../ChartView_dtseries_DataSeries.png | Bin 123206 -> 0 bytes .../Chart_View/ChartView_pscalar_Matrix.png | Bin 106335 -> 0 bytes .../Toolbar/Chart_View/Chart_View.html | 93 -- .../ChartDataSeries.png | Bin 200935 -> 0 bytes .../ChartView_DataSeries_Toolbar.png | Bin 38780 -> 0 bytes .../ChartView_dtseries_DataSeries.png | Bin 200935 -> 0 bytes .../ChartView_pscalar_Matrix.png | Bin 181616 -> 0 bytes .../Data-Time_Series_Chart_View.html | 61 - .../ChartView_Matrix_Toolbar.png | Bin 52289 -> 0 bytes .../Matrix_Chart_View/Matrix_Chart_View.html | 97 -- .../pconn_matrix_montage.png | Bin 283734 -> 0 bytes .../pscalar_matrix_surface.png | Bin 244703 -> 0 bytes .../Toolbar/Chart_View/Montage_toolbar.png | Bin 69087 -> 0 bytes .../HelpFiles/Toolbar/Chart_View/Thumbs.db | Bin 5632 -> 0 bytes .../Custom_Orientation.html | 144 +- .../Toolbar/HistogramLineChartToolbar.png | Bin 0 -> 100268 bytes .../Toolbar/LineSeriesChartOldToolbar.png | Bin 0 -> 63168 bytes .../Toolbar/MatrixChartOldToolbar.png | Bin 0 -> 61898 bytes .../HelpFiles/Toolbar/MatrixChartToolbar.png | Bin 0 -> 66469 bytes .../Help/HelpFiles/Toolbar/MontageToolbar.png | Bin 0 -> 86711 bytes .../Toolbar/Montage_View/Montage_View.html | 99 -- .../Toolbar/Montage_View/Montage_toolbar.png | Bin 70874 -> 0 bytes .../HelpFiles/Toolbar/Montage_View/Thumbs.db | Bin 5632 -> 0 bytes .../Help/HelpFiles/Toolbar/SurfaceToolbar.png | Bin 0 -> 64728 bytes .../Toolbar/Surface_View/SurfaceView.png | Bin 60981 -> 0 bytes .../Toolbar/Surface_View/Surface_View.html | 67 - .../HelpFiles/Toolbar/Surface_View/Thumbs.db | Bin 6144 -> 0 bytes .../Toolbar/Tab_Functions/Tab_Functions.html | 110 +- .../Help/HelpFiles/Toolbar/Toolbar.html | 886 +++++++++++- .../Help/HelpFiles/Toolbar/VolumeToolbar.png | Bin 0 -> 86555 bytes .../{All_View => }/Volume_ID_button.png | Bin .../HelpFiles/Toolbar/Volume_View/Thumbs.db | Bin 6144 -> 0 bytes .../Toolbar/Volume_View/VolumeView.png | Bin 60817 -> 0 bytes .../Toolbar/Volume_View/Volume_ID_button.png | Bin 6398 -> 0 bytes .../Toolbar/Volume_View/Volume_View.html | 132 -- .../Help/HelpFiles/WBwindow_Horiz_Labels.png | Bin 0 -> 790840 bytes .../Help/HelpFiles/WindowForScene.png | Bin 0 -> 316513 bytes .../Viewing_Area/WBwindow_Horiz_Labels.png | Bin 718040 -> 790840 bytes .../WindowForScene.tiff | Bin 0 -> 391624 bytes src/Resources/Help/help_resources.qrc | 123 +- src/Resources/Help/update_resources.sh | 3 +- 120 files changed, 3009 insertions(+), 2349 deletions(-) delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image001.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image002.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image003.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image014.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image016.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image017.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image019.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image020.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image021.png delete mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image022.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image001.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image002.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image003.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image004.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image005.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image006.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image007.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image008.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image009.png rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image004.png => Annotations_1.3.fld/image010.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image005.png => Annotations_1.3.fld/image011.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image006.png => Annotations_1.3.fld/image012.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image007.png => Annotations_1.3.fld/image013.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image008.png => Annotations_1.3.fld/image014.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image009.png => Annotations_1.3.fld/image015.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image010.png => Annotations_1.3.fld/image016.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image011.png => Annotations_1.3.fld/image017.png} (100%) create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image018.png rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image012.png => Annotations_1.3.fld/image019.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image013.png => Annotations_1.3.fld/image020.png} (100%) rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image015.png => Annotations_1.3.fld/image021.png} (100%) create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image022.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image023.png rename src/Resources/Help/HelpFiles/Annotations/{Annotations.fld/image018.png => Annotations_1.3.fld/image024.png} (100%) create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image025.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image026.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image027.png create mode 100644 src/Resources/Help/HelpFiles/Annotations/Annotations_1.3.fld/image028.png create mode 100644 src/Resources/Help/HelpFiles/Edit_Menu.png create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Annotations/Annotations.fld/filelist.xml create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Annotations/Annotations.fld/image001.png create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Annotations/Annotations.fld/themedata.thmx create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Annotations/Annotations.html create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Annotations/annotations.png create mode 100644 src/Resources/Help/HelpFiles/Features_Toolbox/Images/Images_Attributes.png create mode 100644 src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.fld/filelist.xml create mode 100644 src/Resources/Help/HelpFiles/Menus/Edit_Menu/Edit_Menu.fld/themedata.thmx create mode 100644 src/Resources/Help/HelpFiles/Menus/Menus.html create mode 100644 src/Resources/Help/HelpFiles/Menus/Window_Menu.png create mode 100644 src/Resources/Help/HelpFiles/Overlay_Toolbox/Chart_Layers/Chart Layers.html create mode 100644 src/Resources/Help/HelpFiles/Overlay_Toolbox/Chart_Layers/LineChartingLayers.png create mode 100644 src/Resources/Help/HelpFiles/Overlay_Toolbox/Layers/Overlay_and_Map_Settings/Overlay_Toolbox_horiz.png create mode 100644 src/Resources/Help/HelpFiles/Toolbar/AllToolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/All_View/All_Toolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/All_View/All_View.html delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/All_View/All_view.png delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/All_View/Thumbs.db delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_dtseries_DataSeries.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/ChartView_pscalar_Matrix.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Chart_View.html delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartDataSeries.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_DataSeries_Toolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_dtseries_DataSeries.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/ChartView_pscalar_Matrix.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Data-Time_Series_Chart_View/Data-Time_Series_Chart_View.html delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/ChartView_Matrix_Toolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/Matrix_Chart_View.html delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pconn_matrix_montage.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Matrix_Chart_View/pscalar_matrix_surface.png delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Montage_toolbar.png delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/Chart_View/Thumbs.db create mode 100644 src/Resources/Help/HelpFiles/Toolbar/HistogramLineChartToolbar.png create mode 100644 src/Resources/Help/HelpFiles/Toolbar/LineSeriesChartOldToolbar.png create mode 100644 src/Resources/Help/HelpFiles/Toolbar/MatrixChartOldToolbar.png create mode 100644 src/Resources/Help/HelpFiles/Toolbar/MatrixChartToolbar.png create mode 100644 src/Resources/Help/HelpFiles/Toolbar/MontageToolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_View.html delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Montage_View/Montage_toolbar.png delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/Montage_View/Thumbs.db create mode 100644 src/Resources/Help/HelpFiles/Toolbar/SurfaceToolbar.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Surface_View/SurfaceView.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Surface_View/Surface_View.html delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/Surface_View/Thumbs.db create mode 100644 src/Resources/Help/HelpFiles/Toolbar/VolumeToolbar.png rename src/Resources/Help/HelpFiles/Toolbar/{All_View => }/Volume_ID_button.png (100%) delete mode 100755 src/Resources/Help/HelpFiles/Toolbar/Volume_View/Thumbs.db delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Volume_View/VolumeView.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_ID_button.png delete mode 100644 src/Resources/Help/HelpFiles/Toolbar/Volume_View/Volume_View.html create mode 100644 src/Resources/Help/HelpFiles/WBwindow_Horiz_Labels.png create mode 100644 src/Resources/Help/HelpFiles/WindowForScene.png mode change 100755 => 100644 src/Resources/Help/HelpFiles/Workbench_Window/Viewing_Area/WBwindow_Horiz_Labels.png create mode 100644 src/Resources/Help/HelpFiles/Workbench_Window/Window_Elements_Hide-Show_Buttons/WindowForScene.tiff diff --git a/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image001.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image001.png deleted file mode 100644 index 332b19cf2b450ce5c6e0f50d3a4d36d260ea8f71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29103 zcmX6^by$<%+ouswrhuT*NQekXIBE<~lx8X_AT9l+d*lca5y_Db7>bHWca4o4OzAGE zO}YjH#;6y6??2~yp6fd2I`?xw=dRD^KCw>?wXQJVVy2>^x}u}4`J9T1`s&3q?h?br zxUTQ^go=uG$NABtr#g=w2|V@oaBz0Dr=n7fkAL~cWBLV$TC9ipS5CFOiUii{ab+)! z%o@0Fm0%fk;NMms-fHNbxce37=YGp*99TQ-_7ZtO<8hfx8(zuCmjr!y>vG3I@Po*oo~30*O%~Ytj-rhW}El6t}SV8cdpDH5#sS zULxNVg28pU;O?&t8spXv6^yqY055=7+ltlKYdDVvm2%l=4;xs2xZ zd}c&TtDpLGnOBO(vmQKg?q9gJ^_B^2jdp zW4QjTut##caNN)}Z_nXcp1A%ue5$XqI62!{ z0tsboX=km@q$N_yq)y8vb}JrAp@OT{*Vyzyg_y$W!u=8Et)jx3_sJC1ns=C&+P3Zv zNrNEplcX4~-vXBH_8}nyp69fI{vYc^-t;PuvpbuJtuTIz5mB7x*GZd8RZF}6m*p?Y zJHRYs+FytKg8Yj7jBH4@B;T}KNbxi!>(mQ{+&2H1Gm2lf-P?!?G8>gOXtFfA|LtS7 zS&+^zU1{wy?aprGh~yO=+abP@jag6~6a|%J$ZlyK9X+T}EQ@?iYe;_`su3fpSmk#1 z$Yn_Howm*N2y2z8yG%!R=JjELxZuufUfMj4^=Zg@M!(zj%eDGBXPL}SAFr4B2xKY) zi+X|t2LjbYgQgt0Hh*kpd&N&SN^cvbj{lVp`}xDXoYWd-DrcbdG_X=nbxmquO`v>R z0P}_aN9&iEGwWL1@yKcHRY$cU+@A789^og`_rD%u|?&-syt~hf(kR zcYH{MS=>Y++#etSJLoksoi!fsu!sEX;DgsAVHiAdCtRjfUQo80g?Cg`>Qp+K8ZV&K z8-D_Owx(YW5SRVm4RI!Y9(ryl9{q5WO7d}Dx@@8h^Nqnfw;qpZ-e!$`^iljQUj_?{ z?+|B5(=3Y6{F!GWdEG4Q!&9e-sfbr^W$U6@NtEN0zN6Wut*yOmpRMNY;J)CkP~*zE zn!_oVvYLa7!SVdvav&f^ub$NMjZsQ$ub5Gay*p}u{x4Y%0Q#uvnWfH$je{xeU%Z(B%tezJ*IUg%XU`IYMix4y!-xxo zkkB>Bv5>;8AzJ>m2(8dNt0~^es-A~`0{AU=BDpq1&u02hXC4FhhiYRY7^NTr0TV*! z2Oj4K3tTWF7l8kCkUw-Oea>&(BF0hecrs@0NCmc>^&8DW9w4>Y(=^bI@1LJy&I6#k zaAZjNLO&ZH@x2xgdWQwGv-8mrgxBu??ybDy)fNr2Kx(*>6d4%MrinyoqCk zcbunf(kE>TI*_2D1)0Rao-2XdfT*`$QQM*0O=|6iyI^801awlNcF@Jjf9S;@kg{Bf z?>qSaowto)`^Er6mXvPONP@-|BX}o5?%HvEm+IEe0{_`U%-l)u9Ed$I6b(}~2>iT0+s(=E9sVP*Dwsp#y&f3ve1_r@+A&oipk ztHmCX6VJ(VFQH>%SDCg{w*&jLa-8~nD>K^qI%qSP2>LV7_2~MKL?&3eK*Sxk5z`ht z|2et6X?DM~>Z+eOJ~C)tHo|-$x*^$gJ7ihqkUKRobi>x8BWU>4Jum2)L14LhdawY7 zq=z9{KekA~wD8sI3)Fdff$?%+{7#zHQJUlK8MgoYq<@=Cktn3TmiRq&|n-Za)$}IlUH*#RdzZRR_K+U=>13CkD^#aw`;?H zV8iHd+4gAs|5t4GpY-(e%n}mXC{dd5W& zS#PO1YNevlhD>iMjD7⁣`FH+4lKa`@h-S9*#lzq#O0gt7j31APzBFYZM~o{P6s2 z?v(fga#$6@_Na``n={c%ZTGgCH;l3<-Xj9?{de%)iBo7|yvGcGt8#S6azNN}Xtf?E zk{pYy=PH9W(RoUL7P~DKfyxw#C5x6Cb<;M?BqhxtJ@fZ$!ArKRvp48NJ^mW0?He76 zfiSxgn96miz_xdi^tGIqG(^p15$QnOLQPrd=HK|qW6j=8w+rJk+kkPOy(|kFUHB&- z47y)r6-thuBgdcCse=C+f&cEL7J&ZdZr4xDpP~~aay7OkgDiYsjDIdeW{E>FqCO;0fN3jJpQ)q& z25QT%Ol2%or^(=dzqpmCMr2p3IKMM69@0C`6H?Zx;G*KD&8m9E=99rsZ93+1q6j_r z*(wA^>D#UzsHfn3Q(7Hq)9-h~dB*7SHY=Ht70}c*w(Pg_gnY6ob%9W$$W8pQP;RiQ z;}P9=X;w?Lab-+P^pVd$9Y0r8GH>vvySDX(ZI_1aZ$_lkExm| z3*OyNe3Zo_j*Ug>)hqr};4+F6m|;csp7OM6U2Sow{ygL1iLa&`VgQOd<<|+itao|f zbvdQvc($)I(Mtwme=v?Z3O&_=1W;T}d=Esmng|++LdlvES@TBf{uxQa{aXdv!XClX z(+7k_wzUcI_SH4ni0Vi#Mk~=Igb54ctO~qdb-)b;9`}aFuVB9!#R%KLb$CJ}*8<+` z;Qni$=5f;H_FHqNZObz#HmudVnZd~RUhgvZEkK|KccXy?jGMnqIj_sXBcwn;K6DUw z-$9hkPoCZ?s4DcA_qkRZ*#fg3uzC2*e5k>6T^yc*vG`Odmak;7IKBSQ%d(%X)J0zmSAR_@d-{EFG@jZpWq4QQB zxSsFx@WgI3Q4BG!UO9ke(G3^5=4(4W0@V{P2P>x}^HhF(mLguEoCYoX3s*aWA1c+) z1pYRg^(L#GFQ0Ef;%BTH-p2inIDRtTS-II}g8#b1J4fV=Q9J88ColX)Z~SI0gLX=Q zJAjBzo%Z<03al2-tFv4MIvt*?`*C-z<{Qj>ubNyE9WE8V%{TEqUEQ3M{Poq!xWdt@ zp`rhvsdE*+s=<-X1`xa&UV{UsOKp;p+h-qUDI0}D!lHl__U8=$Ln!%vrpc-d4>S9<2O49 zsq=7iq4xH7gvC**h_{pRrPa9AyAAV?6!>!Z=1(`gI~C&VmFK*rF!y^QDGx)Y@(f(7Y6V9lIs{`|3^P z64|UTJUm#J7nY^I6$5X!U4R27vbO@rgeseO?R8h zHz6P!+|%X&b77agp>%y=&Wz+Rk4`hRlov<{^LFp>U!K9l&$1(7T)L5X>v%WoH*Lhd z_imTDUEE98fJs+$7|O3X(1<5jo5~h+yvauEo~{r?)wr!~MF5ERp@xEF{1r#r*w3|L z-t*x-l+~Bx{AFD2sP;k73L=_kbA5rbsK=?+o?c>YPi*~K9mmJMDaas()Ad%1PPL43> zwj$B7PdXh-%;&=G;z(R7D_yn;Y`TX!!tAG8!`kEw&m}(c*oD#XBAL~~A{5n6Nc#Uf$x51Xv{e+H&F zR0m+2QK5C_^5{O}`uG1f zQk4|0g{IIUt{;lc49F*Dkt;p=#HQgHtp0^D`7zvDoEE?$JDLe;otBiW#^<~V1?VYH z5!l-!L922JH3fd~isoW_i-GZBagcXvw%$p&>P|_asxFmi9AyEU>ctG z$G0{MKUmOHVK;@^iqjTqrot+)-Q!L;O6?I3SVQ{sO0$>Yt0y%8p@uP1ZYaSXF85lB z{jna@^Izy{htX{Afw%Wq(a#zgD2=Vv)1Yz}U;K49Y81l*h>FB#E?8#`olQ|5BRfNhFG}<{WF_D(Co! z=`s*I@oUN*y>qY0W*SN2F5rKqD;%P(paRl>YlfY4!9rkP(m(2joP#bhu+pR7>&u3G z=o8TaIw&%Q{tdV76+2(~L!F;o^YjnQKUXS)_p^jYmMe14CKEBjsXWj$J%8>h0|Hmi z$wcCzSkGWR&{c7|N^%khDD!peRIHrX6khbkvI|1AvLnfL@Q5(`sVs~Q$@EL>sGK)se=e)nA|(dSI8$I7p&AwFet#c0RjehESyL2K z@|0RiCY+*s*=g@ZBvLXjm@%GdJ7@eX? z_xr#L0NP-GKTrJnO}d5Y=TWQ)&9#xV$ZMACQ*Lk9+)`K4A9^c}!J6rWCRdQ^?<(77 z)G5=cOSWN_w1=T=Ws4d2;MWZqK>H52(JSTgsE3WK^Ja&dpqdmq75kfJLeYb&{(kLp z+&f7k5t(s~HN*ZXD=AeqE+rq0cdDd=cOS*#PH!G+g^^=mP*{H2l?+c?0H~P#{r0OK zf?y_H*8E+nL>mog{_}aW$Vlk78ju~m&m+za;B^&U0pblG{n|5K5KgF|_jbgcu(L{&a^C2CTfA#36hY@}KUlc!(qLMusGGKo7+BQSWw!?N~1gRJqU2 zyj7J~kzXUsIIkCmwl2%5J+sMG!0K2pUj=koJz!HdG# z&2=?GR6(@oCZYSF-0RH$A@1IEqu3&U!s!-p;~h{%ZB*OZsQ zua3V2^@4|XM34Z;{_ukA6PhgKE;dCb6kQr|79N7fdHp1w@|TrM7_y%x4TGMEs;CY- z`1fiq1~{CLpHr-wVBd3AF&)OLJLUQU;LnyPi(K2%H<-!|`RGl!Z5SrLK8`7>qy7@@ z!Qn)9Ww;@q0757=-#=c$7UypHKK3|C<@eYPc|1FO(@N7vNsfJ`I@Z-&w8!7ic0#A_ zN-X+d&;~EDZ=X?7WheF;G--cN6N#M&poV~<5cwUZt*1iIoJNLkv# zLbfoH7L2s}C%IuK|ExTi{pC}o!1~!u=aw0HIcQOtMsaBKbI--XzU4KE>WGBF^(YCV z2urR=j?E(+#)JOB%>8HebAkbZ}2LFk7v9q{23{NOj_$u{0Y>*)W^0Lh7H4uF`F|AQ2R*)9lY;SbxxvMJcZ`FyY z$xyq#a{*0oo>i$GR~<@sOB(S!v!89G>lX%>wBLKlqk-Mb3yQ5Am)*m#_MYH z#S%-6IzcTJXU%v`E5u0rOGKxbg6TR+SAZRIJmhs*Ok(+kb2lxLOlm$fuTF zyhNv$^q~M~$hHM1hiBd2{9Q|E->OiIzpJoFS?0Iu3o}Z)!?xM8P(NGbvFxoN5|1q>k~`vkB;8fD9xz5$^m1X z9rta4-_=wXNHN3Q;B-2YeOJd?$?DgxM9yYm>oBnP4*7fK_(oN9{3NerQybyNwj)i? zoLMu#2|_g69lYdKmlXs129a%!*#AJF0P% z&D_Vu87}b{tK7QB+V-$8djQiy;iuUx<_dfP`~ zan|CBx;*RL$@Kb&sw;y}WcrR7K3GQ#-WAE8^0Zx;ayfTJF6tNpqv=(eqL!{Uqm7`u z4>)UeR!H=UUHe%f%jT6Vxj>8lT-R7e;6dhP-=`@~dxoIn%Fv;NQ9aQd(c&E8#i1uw zK*M72U%cFGzDGtE-%YiilwVB*(Y{( zTtPl&>m|>8{8R4FUEm(#!HXN{tQ$h@P}^d!gU?Mbp1?+nEceSB8z@P^?4u8w&iTY* z>s?m~fXuRCr2@8KKM8$mR)QP6kKr@2yV7oLR$8`q6G$ZCIXSf5Uqbw<40s;PI z#w@zrkNA1ZpI_w)$34XGjlfj(0h!7@&O=9Ez5qPjOb}|ISQ*${265{n0e42&PTTC~ zDatLiGYFHPfAOf+PpD35Ge_&pgx1!=eS#2Dn#+n$^JRa=UBV{Gqv|@Fk|y@dl5bDX zVbL0!QgI|`Gzj|JE*4u(T%dZqL1bA|>7nH-3mr8M9X+$Z6Ywjvv1TA8^6f%j14Q<* z1r_rxgzAp-aTf9@D+Y304VmVje2g*On3zi(ZIL5S+%~Dwn-{l!;}=5Zp8rGPNi*BI z>#)pf0oEQ~5&yZLskezeOuAj>PsSFRLy_J$QbLBCc1Y>(7Vk8_bm64aEFJdHx<&fK zkuwc&=pq)2B7||^8xtkvrl311%_g3oQssq3D|662P1~a+=5Q07zgOBld}o?omN9xa z4G<&j-OoHrWa@Yb>%BmW!Y*%3n5r}J#hLG3^^DY=S)YD$qK<2!b+3TUso2tx`D z+GtETC`E^JGA|Ef=L#R*PgB2Fo&f`WsaB%D)`EXrg*nMM-wkWwUqY{0=;j;B5T_V9V0ebX?&5^bOrG@y>SYLz$y_v16E{A-kv=$eN) z8ZcG`IghpzlLT!t%Z}hz`h{h?en6VBIzn6HCIvA9Gm}gmqTcNzgA?B?pGkhAdm|Xp za!^PxY7t9?usyyy5gx|4FMSe?DNj_{rgtbHJg(~ySP%zmh&=4HPY4uWlC1~|!IJGV zo?4?KM`l)%v~`8t)__mytpWM{jR$l(ANYU>+WEOaW(_?w_}qQyF!7Zsx$ln^k4;S=k+JEd=+Ku1rY7yZH zG>jUHh49_W#B{AK{Q)5WlcNZ;O{1WK%X?SN2*>wjU%|ZL5A2H&8Bq3MA63IuRMbkq zR@KA)u1A(ge*)z&rkk;q2#@}vI|F8j7D4suY+!1r=zkP@_fz9LWSOOEEN zKzbWe5PYP&5CY)eg+1=IlqOUBq&g3}23=c`%)ku2`7s36A z^JdPE6kh*ZCkWV{2OoMl7`>cp^+@bk0=+1~3S0L$EjhK+K^<}-0L_L>)>B`l1{bnO zOP8ar=Pww4eBe<*NHKJ6Al;+ZEyi_;wZfMj*)SKpjVGq!lN(`n)pNV*w~CXf0{_`>*pc)h^zqP973`p&?~H^z z8$KTX6s*jr-kChs`;?pAZoBxRC@e*D#k0 zzy9{{9&#-GN|QJ?FiJFcOKPx=q&3+vYcE=+uY~{?k)E0LmN~qg9@*s3R@j@Sq%N6K2;TO4#>~sT6ZK@JcNT=AWW7csC^AO z_U1Kq`cg=T2Y5AJ&%eIHy+xd55^nkY8}5F036xxCM?2hh}}lW0n|J& zKoJ~@yE-6}$o5`%5&Q^3L)Y|$UkxelR!=Z22EYzY$%f6ssdH8BCSg`KIdfAmPB$ju z?k*cj5kJD?ASSWb<(H`5iPE!!&!aIMuU}}w{KAE%NdxH zzhbaEONnQLYC&W;Y!~t-R9(OcHOj>Nras8m=R>KbGx`FuD2oTi3FL_tbr^neSwYPAz|S0^t>EW2d9bO=sS_I+!f(H*7g9bt$D^x>CjcZLkK!> zbx73dvo0U!&Oi2wPt)B!4W!ExdiOZhQ!eg=bId-OYj_4)Gl=u;)!kMI9ai8yJDWQ{ z4&DtEU~#Le2YJhWLinb2a?oYHQu>*k_oW^zYN*Y zW{~2-$p)ZJr5#t~Suw$n(F*vezpPPBQYRuGTY~$1a(((O&a*&tOyxJ+o*aUNuZjT< z!Hurs5!D*P*YJZP%&m*N+OT=}D6y%_XK-7Z(i2K0dT{v=a7%7ta9JVx_%<#{zch7Gvil#St^jQ!5QnL zWZ|{BPAp=N8va0cA=Qo8Hlf}tkKO?rg%=ybkerS+P6-9zn-=SR@kV)X3(zzrN^RF= znTMQ+54JcG%Diwmv6VHrwCOMySf_L%p#w^hw&LcN2R4KPnEnJA&SGco)ym|smedK4 zO{JLXocI3v*njfT%`L&ES{L88YR|}rOUI-bshyGDtIVfGsa%qBr@7XB!N%&b8kd?+ zD)`~78JM-qIO6b`t7=7fiG^aEZGv0AiJc!4Hu?E|W!;o@(wFTs8YLQy@TNks@C2NA zUK{DsoffJ6ji~YG0$7EvUbLyB)`=02;#$=2H5!1gRSPMt_w{V_l#~|Vsi?@4nZhlx z;HtM%=kdq3XM+l@UP!5ecw-D@^ceR@$T`HP`(P*aStx}kzC>a^)?;yH!Owi}-6Yk{ z?l?2?i=Gg;J9}g6YJL57M193-Z?kP|)UespxG!4Nwyg2&}t>}2)HeCi5^&@<)zUiLRGcIHXuhgXGZ58n=$yQhc?z92vSb8GqqoA<%c zrlv0AYu`=Nm7D_?{wfw;JAQMJa3U|8Fp3kk--!f;JpceXxhOq#59G(PPgvM6PNMI& z=;{w6&uL883G?WfkHvk1p_RSXPM=-<6J15J0}F@iv9F71?8Yuwx-U&qX-^lIzi*`} zI+N-8zHhWj!{?uSptSe1|VIa11%>=JgMlqOSvAg&d5!>t{AwcRIy0 z!5_o+a%($nXP9wVxz94}>*IY}w#whLO_yN^4I#f2>jIvV}S3yMa4DEySbIU^{(c`)I#at1!tqiHOO~i*X-d9`k1%?Cj6zD#Nob< z3gxV*2t6)^W%EW)6p=Td{sr~eqR8?SsFb`anO4?=fjQT;IZK8((~Wip9Ci6>>Tyo4 z^}5xLLz)O>nLT#oj?{ag=w!w05s-35$MitFho$F%;qh9Rnw~Gpb%ZekC0uS=U_8xZ zv*~Jhm}<(KTkAlpG&!B!Z2)}z7&XfEgrzd4SD*oE#$MU6{f~xM6>nmKB`?fQT3nU* zL*>_RBMRv2ZB^pkDlu$bpFrh;?!EK!q^@`~Z0S5D(R?slapC_n_nj6d71k-^z}L0% z%SM}6_%jU^h9kqdRE6nCa;9n#Dg(wp0@kAcHac2aXJc9ajXKnV9$ z0E%<(2Y>%ew$WS#v6AEcdiSg{7fj zbNVK>(n$O8VG1(SR(XkMbh)tvKUFT07`x6==A%E>(d#_)v!6)rQ9AB43res-4aR4M z4KUyU1;!Xa$3?T&&Es#M5j|YjE`(gT7oiBbRx~Vm$#Wco_Yq4}>RUAB_+~9%8vO}6 zMhw?M>=!j3o=INa`et6jo1g#ElNYa10KsjM)@iXN2!>{_HTIz_v>jdtXdz*>Y3Gaw zaNDvIG3+sL>oTw4jSmh6Q@*RO|Bk+^ir+B3rB`?3PGGG@f!fG4Y8{m#=l2uNGIloQ zS(##RxS!HZxNW7PZKVvi;1)#!avlbm-8vO&jn)x}9I$QKC$*Z=8~7<0{3-XL?1(FL znFx1AnvghWCvIMz638toIj&t-0ZN_4PAbvbZVo4ip*>MuzE9!`uE@{9-*=(J^2(H1 zHlW0CTh!q99-Q7g;RTKr3)by6DBb$oO99L}ebs*_W^f4mQjzBPi1Du#wX4}dF6|PU zx9fsH@xQHB$PVJkp9^D*DdLkW7yYk0MZ_%@%60VmsbMd89(dAlpXuxQ*{B$&J{U2&@FkoX}CNQBsI z0&nr~yM}-VGeFgaT%olAf_O-%gs9Ofhfu7Y)wbt~+}4vMw}m(AP0Baz#7TG9wD#|R zlJQK+Ub??J8RNLw6~iZLEVI3FwQj9ua&Xn|n;1(d4do|);&DjW>-@`0Plx@%j8+iKJIH{%At zpaE6Uxmy?~%o~3}w)fobe6-B+anJHRt^3~DFNWFl)CiujB~X>zKz_V=N3xr?l^$Zd z+}7WjdkVJd2cysBZ*C>8{pNT(=qhZ}b)YZ7DZZ@4 zDx{sz5^v_`q{Y6xL~x-6J2el%p3OfLzM3KZ2Xy@oCx<7ft2KMG@wMl{+@Qnm{UG{AV%X5nc6vQo2bDiIptX2okF9v538qbqEhhM~E;uR*T7x5~RfqSH zutswo#2ZDqA6Jf=*^`X4btId83ou0AV%fo04O6R^%4Dl0RwIwZ194-Pdj7?vDI@-= z)XwGAr6_1VZ+mAo*so=lkvZVr18kOGuZk5LBMX=2{zA@zGYQN%x*Grje@uRtwF8KyQXIIsm4g0x{ z+7-j4k9TpSxkW+W&G(@NrQ`+Z8uEl-M(gtLn1(|u9|xyHQyKtMXHLeIs;FI2+h5-x zGT(bYNN083pIup#C=RN@BXopSDs9~I9pTDK(4UZo$qvqSmu#)SXYob+1&xF&zd;UBl>$CX3EfK)~1K=ERg3FQplwI|85_15xG6|8-T>=9g7E1pkUNOb}8G z54yiD0Ru@G^1UprXbi2Ex0PJ11sUDJIJ8LD?zr;ccqLtE6jwTCa8)tGbquak8Ne{6rVo zuWZ%e{dZ?+lj~5bO*-?>0o~%@W{6ezaEotg?;`1QS>20eT>ktoVhy~81$EH%@H3>? zr8Y5M4_gQ({kqJsZ#qPehj;+zv;mljOp&WPZ>8xtl?9A=rNeQ6N_N(dIM|x?L07;B z2UndA@wbv zZZ)n_{rgkz;i@p+K>$4#&gy~#R}N4Ip^Ua6DG%ws^ z?I|NUVKpwDCy31UBW66vB?7!2l2N=N@F>TFs5|g4@y7)FHo-zxYDJU6>Z*q|<63oi z*4cX)Ru2`GLoaEIFmea{+>lT_ONy(b=e0Qe+(}z@-x=2)1=hpw^swTw<&u@8N6wO{5VGLc+BCu>i@&^+h2ph*tfv>wa6?(C@BzIJKh@XhA$UXL`y|x~Gq@Sj1@ zlw`3lrJAx`J3jarRuG^j5T;@!)#S$1@%MdK1y7q&Ha%s8AfRBF1D;X$ZWx9$oWxg{ zq^<4{q5~H25EffDwZMF?eNdKkSOfvyOQ8qF|lIUSWOhR zMMBt$|J1i-3TL(+pH=y#6`L#<@sT;muhF5xkRl8xL9#;D+ecz&ny>PglRX$`(&^f6 zUQkrWH^e*{#HbDFc$SBvZL`%E_i+x-cHlB`UR_fw>imj-S8RQ&ZAlgbyN+v?>lLCN zzvMHPO2C0X75GG(j#%UqeHLh*Vu1X2_aFGXClDa6svPpD`=PqB2fxThb3E+QO#@Xb z)5iP@&iY@7n!n#+OGq`C3Y;$bpm-dx_tM81G)pcj^U0L01VB!Xo}EOl968jQY1JEP zQ!0BYN%rT8(PUGWIY1Myry1M(o>jW%59fUidjb=d+*y@E>orzLgWn99gbQj1BzeSM zl}UFEMF71*Z9?-Zrr>HpCq!(%mCf9Lw`U2R9(}l{3Zl8q_^C|7J0dkY<<3Vp+7?|V zP1R7W^RkO#DEpqA6YJzV>^t?)U#~pc=XKD^vxEl#-=yrKlHhafxC#Dx(9alrmhDy= z>2vJuriHc1rZoXEu*tc&>S_<)$&uZ!OuwMzMr}T)vGPm+Tq4$2T9Yl%L?o%eqabk> zRCATuQT%i)1|O*QvfDuQ%iL-@D{Ht-I`tG(v5`L z0KOx+zhW66`WI^N3KBLfUd|6@WF|pX5fwVHW0>X!x|ARJjFh`rD6LmH&FM3LaX>Zpa(B6K+LneAaKNBDtVZt zEc$YY`Wzj2pe_NI=t~7MvXcGyo8c5^^|#kQ47r|XXy_wc6zI=P^#8eyLj?vmY`kih zgb1K73(IupD&?{(>6WX6)^E2eg?-j<%Tj=taX{M&4|Ek6O6XO`tme#T*5XxxQn!jT z=Uy*nDSwJVM{2`bmHqGw+~5W7rz!J~sPt}$yuTkPfGBR&7Z%~e^Cl9D+H;`()Z=IJ z8L^|+HCR7&)d;G5IvL#4a)a&`ItHMod~8Pn{S`zpGplOPQ1)?!alwZD!Ed>J6kMzp zuZ4|=Z~a59=za;OwXwpZ5t$ol62@B%$mBhx*eLV<;N34zQBk%Rbt2BCbwEPW0aUYJS3kHIG5G3eKVPAalh^X7H#kx~){38Zf!v*>-pC^T zz7ZfqeZ%9j=~T*Z{ri;4L>?D5Ko*t*wRVE!-(j#LWGI!{4Y#MCaCqPsuqB}vF54SN z2klXX8SrfPLF2h#--rrv7lE%B?|=+)3(@dZ#O%O;HGM~6Z`SiN%Vc^H_uO0vvEKnp zW}(uA^j!7qI~)<+OyRUjdPAN^Z{#i!&Sd-x5^3zD-YQ?(j(355iB5JD=qR#s7R+~v zT4B!@<7%dSJSDbIyF|zc-BOIwm$fOl6`4gemyCGN@mWp!ss8(3$D*UlO^_@$& zEL?}Oo!0JrmUd;Lg@Dyau8$GGL3K)8-$A4Sx@s90CUUm)iPvcRH4=nHxa2{&dF441 zfcuNFrL5IyN--z@sp1wrs>gbR9#>&~(00ydk1{BRhk!}CHmwrE3I9=-N_7!2&`47)#HQW#OYwzQs;<3a&Q)^%<#IA&i<0HCuuzvzH&2?y z&KKU0+jrTECoC9sooCe$FX)#_IeqZ?;suf=E0j1_lBmhr@G>^jMc$I z2M2=Xz|kv$QONk-S!{uxwg2iP_rn+6+27b>-wr7oH0;T@)dB%oRGT;K`YX_B>E@O3 zdJYvbp`Xqd1tlyN#MN$@JNNFLir+l3(f7&SC*{9{l+_M}OeFSC4eFHcmp@5+^Vxr0 zKY=*b+WSH*U>ox1ZoNHI$Dt+NQnq5jOZ`mt)RY+IWx~$RsaJwb>ualNV(SKTrPtzQ z2G8l}evt%CC#c6l;8G-IN5t6ToF{7BghXfwX-7sr8QPpp?ufLC1;j%{qND<>#o|qc z1r^GPx=*$qwHhjmupz@;pLOTp-hx}st`GF=-OxmawPYlUey8RC6twpO`52aTG9_W? zF=4XD{PQBvV$jfa1aMrz>$JBE)XjD~h4DQ7p0d)Hh1i4)9@&m4;cYcqFoEs8dNAc+ zt4sfql3a|BK+JrNpyIU>D%?UmLh&ZNb}U{E8=$*IcvD9`E>4)@EKCm8znO z;pGxk1<=i2n-K5eXhv9A^}C#h^J^u%#XA~}ACuKj%2t*@ez{tw>DlV$=sS_0;GcXG zMx`3G1+r^)y@!~w$VeQlIKjU-DQo5ek_DE6DRBOhGjYs3us@Q@AjjN30SO|LZLi#j z9ZMel_W7K7*%6SfOD>l=`jkVESk(=ve@mk$I@|RuT0zRboaAFQ*c%gSCU)_Mo zelI1%GfrsQd8U7eFoOuUSZ*0vU&{7t-^tKpLMmH2`s*fX>b8-n@FQs<2JXt%>M;LS zSECjGUtVp*BC-eUc>0hktzJ1<+m5U&6d5+97e*P;@VR33ZT46ptQN~Yrm#E|Vofh! zW}3)3mZ6^sAdT{4x#r_aFY1y`2A=ue?@sLNiHufZE@~!qDeu2p?1t~#Cwh@V@qyFR zv%r_xW~Va{ffOwWqvF@c%jK(3-&3N~vI#W0!E>|#m4-PO3D$QHF&ay?3coI3*E8=l zlUl-u3^XMHe;n05TNTath@F=XoFD!!9hedg;nBc@-}i3HheHIBXtK*VX39`)x@}UY zPIw_&B;!F?%)=zg*GE2buP_jG%A`o9*~N9q&UB`ud&Ol(F$f>fO0Uf#`IdtH%a}y! zNi3p?D8O^>il@cCTm!6^u^MY3pYosD)%cfWJa}RJfop;?|G;oiny>rzGHPMXBDa0P ze))5^@JVF#e6GUbCs)NTeH6oE)bOCw)P6KRLIav(%j!-v{>WcKG};VQFNkv4 z=`IRh<(*`Qu7}rvS@q5uigWd%lM<&LcH`o*ZkL@wuCwt8J+6bGuWbd*IdsJnUpx`` z1}F(aIjM6CtAL#2#be**=+3YZ(<}D(E)CjR|6fgK9oOXdzkfhNL_t9jC6y8Z>5U#L zArezjLRwm4NRIB34g~}TN=)8#BQYAB(mh6Z4Mq&cVBi9JFj!jeZ8*d zbz3k>CFgN!JwkmCif}TL@Uz{u=59G01e`hgjgBU6i13(h$wrQad6)ZDb=zJ1OjF60 zZ2zW$T|O9sn|y>xWkaYAZgl)RAiL|#-fCPFzWT8%+fcj|$I5F`*=^n&$QEv3SFZvW zC;iIPbCJyNNiR+5C`bi5Yb(P-sbP}X;N$ikf5(RJ)L$svA7^Ot$&E$IB@!%?2ETv; zu;W{t;c&?QIW(wS=(hsDwKQBDb!IaO7bQ1GYT@&BFwRu5d%^;c?J3$3{XplN^X%la zsDR@6ID5_V7f5~Tmo|&SRZ3$6fBvKs#&3bZaU#!@T-TXE5|}s+CMKP8iyq&n;Ak1G z&5uev(7ul_l6~bD!Ag%XbC^x5`jbcpt9}oawRduN>|e#`DHz2^Y~Zc?&q^2`1I3XZ z%vH&P`)Lw3<-Xet|5^bM%H8T-hwgkcP~8Sy(7+Xt|FvWA&l^L8Yz+c#$k*yVaBa}{ zq%;t=QZDGoso^CFhixO3B32j#7vu+7qE{bi=4CbDT+F|pVUra9v9WyHE!YMaT8}O9 zsHJtf`#qj@RUIR@!VyzHDY!5&UeVCr*IRM16(!30i06LWVRtOZEOwAi*G9A{!ho9L z+o++(Mb4u`N0LbNY$xclKfpiN2GE{YwUE2nQR`5RP-o<>b&Xlezv5PnzOmfEU? zy*!ad0Nc*a6qjb1qx0&7*28stlu+nvQF<6aMcGe(TVhBdqC#hdvaW&PrN zrdvN$HL+!F(A0^mfX;~T3@ohm{|{`Y-=zy&q&s0rUTDI3l>2Y#EQA#{PTP0)%pYKIHJWRLg$i^!}55NXD8!0b!AA)&|_uBPK zkTmtcL#0DZ>~5h>r2%I6S>~%zK+8tW3YJXWZvk>EhU69991Ul++0O91s2NY^oI%Fb zA8J6Hylk@q8J~v)*;R1Xod^6E4BR_AuEx$|*>RE+7?t==7W?3X=1;JLZe$k2gp5Sy_G`=Hr#UNXZU1%wFl(s#$}Pt$*H-8Gm_1|y4;bi8{m?#SOp zl&7`V;nsvDf9LapMnp4v#vCLN$7KY^E;x@l=MHFc%47fpVnZuhDx!R~_l(8{$sAO8 zk4tACwm8O>gXHROZ}I0n8i$FSBJtUo-o#k-R6-3}{!HYW;&i?tLY3ldLueo&*<87Q zE+z}FE2|}~ypD_2-H;&Sm$$}hf*qxPpxFS$S(%W49b+ay<*7Q1?1-PM3G}F>&v;(H z7w#A|eN)M=wgfz1moSu_9gV=pwn2l=29%i74eXVp`Q+=XGe!R#Z=|7GEZv0t%Z?e< zFwEBjRi2oSd`T>2kQ+d@U?UE8{tDorH9F_&uK5zjWfA>yc7UWXFDZG5^;kS%NHoOt zKji%N)kbWwM9I;|+~q_VZ`VlT(#`=#4O5xqn#^hF%V7q6L+ty-(0iP0E7q?lR)pHe zD8r~!E$C7;f^6oX&g}`CfM}iVfp;;h|BEXy8uFbaJ!2yd&*P)lCmw_+%WCU*^sr9D^8GYd{CsjTIj0?Bd9V@1V%}TqT3(A{0C+(Mo zbpjDO3GiPdT0u?5E8>W2epI!01mas}SPX!yVBbj}I0LJd`|N+Gr865TD&OoG5%;Wg z08!c`dt?(AY(;ls>lb-zme?4}$wB^BUfI?g(v^NnZ|lln@^nWF!rB}R&|SPn_7Q*D zdM;HDFmdf$U|V^-TCByjdn=q-i@j)!d}9I0+?NO33+7QLrUHT?6d*bGd0fZlu|bsM zez#-LIvxcExQcbN+;_*_uu3=LdR}vnNr5kA-Qv1D=zc!7EPQF4KPDr;uWw#W=mCx; z!9H-mJ0Jt0Va=I6c(EtqvpO_j{IDoXX}#*}ZYUg5Yas4*sNJ?W0c0?)MNQ0(?bD|> z%0pxusH=5JRlZk=X_1WF_y8C*|YK4L(4G?vl6^m5PAD+5=x)ZW> zx9!?1|6Y1C%E!a-)`^2J9>dhb-(FzH;cW!%ht8_fSyf<@eHU5Ei+>JECbE-0x8`!_ zmZVCSJ;W(!TI-~n@S_J6CHi|e_d$}(3|xXc>D@w90x?vQyg zBf?R7pyyHZ9oIej0^|@fFZ1HFAQ+dO*0mn07JC|E0VrLwUA3NC<)`aMgbKZH5^;+u z;QKH#lDfolWXO!VS56d)kuFCZZ%!FJ7_!xKqK=5)+}`A82Fg1Bm_nS?Mg7a>kZt*A zrB6JvPPH?!2;5}Zd46Re2r}E9+iN-ChECav=g7q@5XDs>qxy z^TX(oVDM|r?xNm`QWY)|!A^9zikf;z2k<5TE`3H@Rj#4?)uL951+{I^N^*%WsKC6%!ZPJx5T zZPhE6lI;CRvr6&bbOyFO~kK0XLCW3w{kXP&jr^sxJ4-;Ji zxmIp_%I6qxLWpskW=R6MUxHLEK^T;ejB%Qse~dzEnnAaq6kW zed@}aXDX+fQyH#qE5IU^&V0@roZKcO^+IX>&d-15lPfvVU+KZY=IQ@%vw<(!6L)8h z%ROq(8BXo`S4};~Vp-=DuN=vw`@eP*)!aO_e!(pCD^2y7-yrA4l0%{|e`_ChwV10n z_elmNB6Wh3W|M$gftMYToFzX$dwQ1 zvlyL#&*N7@zOc3elvnV7JH4-z4(vrPSMiPFT`yLXX@2Jv%7kcfrG$Is76tt1JRVeC zj)t%VoO%bHE|GI*+)uMoRUA;;%n=C6a6~1f>wQZhir%%UaF-PHVuzv^N$2h()-(bzI z#y33@9qc9(kF;I^G(NF_wT#%4a1Kyapz~k_Y^AFt`?xZnKvrx6Y7!)W%d{z8UhIoePvIhGW3wt#+aPa`2-Z?h&cN8O1F+XcGlI{!5Po-Tew|DWWGa|I}} z!FIMv#k3QfQi8ft`__-sdTrvUm!&(!pm)THD8)`3+>zUL6@1}}d@9nYxV2s(yH)#A z)r)Y069 zo5*pCEOpmi#txAzl8x}U z>(jgM?j@PW>pUCRMg)Gsz3xlx@kdFS#Mbn3OxYV!BhTdFn zcO5JBbMlqI{Tjw$`w-q zJMl8yxOLQe_??awzK1;i)r)sab7J%7M9mt6BjD|wvh;sOt`mZ|I1so`>E^gtvBib}iXa9mg2s*bE(kmo#Dd}pL6 z+lqJ)VUV*K&!F+w%o&$SF@A@=_MFjGOa}M(l_{w$XXUK7F)jyY0___xPr)#Y_3)XmM) zP{`0uXvNoZiL6;zPxELGQZ!obA53ocs2wIGl9#afvIpsoOefY@wxJ{v^> zj(i;M_iy|I-j_K4k#ne}94Dr9JSvuarh1Ywb!)*-#7UY_?5f}jX_-zTa3-lVrewtt zQF&vV#r%U8^IQKvTKCsyTZIrjT^a9sbsGg5cW!&3v(4&Y>C*hnRw>DCov2LMv8|&rvOFdcC&M*p2AI(% zKE~_i62|9Xp8i(w1UkJo(4hdt6H1m)0Cwq&%r7chkJ==jpt4o^b1qZIvX{2?_6pub zY29ZTt9Zf6pSTxdztbh=GyCJ5yT}be-)-H>TG~(jM#Y?Ir^GM`I$HgO9oY^(pwIOwFF@2*oshD&CvkO`qiaKF~*>$0rHqMIwWij>Btg zX6}nB5?OEPsy9t9>7i(k3Kh9|07ffgw_w#SMS&k@g$R$`58p)zr{)d-Y}p&Am)|^n zI3i~GRRtgT$6*jF;?a-r=+!&Sh~Z`Di_27f$;12^{$aOC&6PYcNy)Ec;wdTXiNtc10?7z)TMI!t!GzT z&G@wX?pX7p3<04)S<}Hvh06;0a=|0R1rE?Tcm#aV&14`T=BLF2*lY=ZJp~cvyE%Q| zNbD5{XBTcij)9C}yaRnvZ3<6T*_8r%wXWLs|C=Z=Gt?$E3WILtd5_yI5<+yQmy0)c zd#98m;$`;KhoS!4|J*4R0W-VVY+^Il4)QA8^ylkx6dMn(BE1!S6kjH}3V{v z=bu6kCrM`*y^VBp;&zu9{uT@a8|#B+Z;w~gT<|vNwa=mJ2U(YdrqFAg=T zYfCEJxL^4Fc{!CPg&UBE)hYEAr%G;P zU`)Sp`1m|KnBJFoI$cq_BE0ziD%*f8t}bU6Z!q6m`{WD}k1bPlQ*c)FI=`$*oST>SANQ&`=PiA`XL?sBpRbaR_V} zAkB+vwnBDRHZ~5WUg3qYyDzlT95R8>x{eg z01hQPQLWzsz5Zx_B^hDURPL`(zmnKrm40I6DvdXMsIroqB?P?#f51K7aG%_($w*S@ zn!kmWaZ0!wcWrU=n#Rwl39Xx{-Y5BjTAYS#RtEM3I?va>1{GFOR$Y8mNz+(mNQJC_Qjy`Q|RuHhFi>w|Vz)vM7En7vgw+ zA8~_O``*M(^S#*&t3YLSE!!PEzYhWNWoBrOoSz|bp@0_r+jb5EB3rA3umFpW+si=d z<87{-=I~z=u3F5|F$i*q9XhdsKS|)@gZCHqGj|yO1I@B!INc1I{?Jp=7QqB$bg?v0 z>?_UCu~zmkU6+fdOwz6$$Pbh(pNt1dls*3g2aj`$)H1I2 z6Nt%=MKyT@)*}-yuN*c9 zo$e#-QgsA@XZEhc&+HqnPS6P5zmC=YhS+2kHriGRip|)KSqWihFxY(Q;(IWEefaqx zT|@W5Z_Jxz7Q~7IBlyhVavQs(OaCv=6YG7sw}iDZUss?^TZsEzvy_~jhUtdlQ^b}E zh}MTo3r9*(@PH|APS^?fa%;(y%#%d{oiCmD2L2VkS2c88CPaW*Pi51i;fcu7hQ@tgFgWLRZ z%&MpQ0_9@60cq$@XCGV)hRmY6{z?zB6XrC5qq54CJnkbux<>3Q1_E(Z{7olBA<<|QUhd{{G6s=`xa+y+WSzLt zv;rq576eoW40Nc$7zM)8F(#s@E>|uOK+68(Ct7=LpVs~?HPmad3nt6889_+Sil^%H zEku(%@F%c1-Y23rYKm0n9N*sU*y@>mysE8qQ1w^6F2wIzenKRi`k~z8ln=-xla;AA zDKTcv;o_fsyPSSAo+=IVTkX@%(aK)-HSQD;zBNH4zJ51=poyeb>MxA&J6|OQTBu2U5ckl2|tIVi@MMfW9a!$yr_k;Zc#w#4b<_Zu)o?Xu z6(-L6V_VuzrWg~6kq}u960S{|qh65P`?eD#lZ%AqR#tR7H@L}tCPwO6;xvAChQa9J zw>yXk!Sbyuo|@fTUGRFoW!2>>v7m|;e@TauL_BBdPEGw(oynR#Sg9913$V*#n;g`o zR~;2kPob0RT^6!T;}FoD?B4#8q8j5Uz$7ge=OcSC=#5DIgQjc{49O_|dk+{WYlNl1 zahM0tQqB|%`TCR3131B;9%zNZGFZS5u8p(zTYDdbyR*2G$?#ddX+8A6o=G(I z#^pm4PGH^B0;u2WbRv{{D0Dt`$!VjIiT6lB{oS)jCwh-?sf&qb-@5FY7Srx=76yV!=#*(`h2fspnicfTh{kq!@h4n#X!MN`^QnOt^i$ z__W%7h$jC8`-_aExxN(F#gd~>L3Mwpzswhb8g_;HaqAoCtdwYlLo@l%R@%9Ep{MJ5 z|Bd1r?ZgV_%i>OdNq$&DjUNrRf8@ltID%9b%Ic@t#@TZHd^QQ{E1TJ2>k#b7(p0 zeWIArasCL?i41D8LO%OC8^l6;C5630Pwf@A3CIbyltTYLX4Tj8kpEWtla$|>NUn&M zT`%^|?=Dx*0N)+u(`7{;M?KC??{Wt??G|V}2fcegjuk>!b9cpS(zblP_{{aw@58|! zhO0Bx{NQt!RlVGPqE-W+PhW_}V9=taNznee%Bg|~BRrPm$z|F{xZ)lWk@ zfVvOo?-iFp2t#b`mzysgN8|^fKgAHeCSTle5U)bv`PJHD_#kxDD9$UBvKdTy{$Z(V z`L^;FUYNP3rQd?@<>HMzd|WYOfE-$(PK#OHEtKlN=8is&naO;1cjgtEE^=16c*(APfBa% z^zP2Zv`uo7w#}9NE&Q%wBQX-k3LtVs9NGn?GnBid*w4AzOgKRE01|^%SHo7-$elJ) z^j)R}9ed9A>64q&Q5r4rVDFs~LhTcL+=Emd=T%qsdoE!HQK*|wC{3BjJKT2#_G(k^ zd(3^JgpSp@NcM|g_22GFhiI?N-Tl<>>BF1+Q%jurvyNZB7Dva!SGL%s3eHl7h9{*o zB9+TBUbG+Rt$S#;R_8n+nyZ><_$mA{HOLKmcoI?5m3t;-@b_c}9}$5u>$CKe!eN~k zyzpNz@#75ve;YXF$@g*+BL{q{d@XC}__TCKYO?pJ*eMm8xj&G1gbts45HP9U8vmae z_q@XuBahSy2R8ZLoBtM#aQ`-OeXYI=-ODQCY9vkqusCi;mbu^#UCfYeZi z=;dqh4A$asj~`#r(byTkU%K;D!zu*{W7ZH%NTHpz`K(i(_eI;n?Ijn|7W~QkdY_%k zlTWkat)>+v8_m3U*v}Skn?zSrYvv8IxfhKf%f&Ixcp@N7$K;t@eKNY+{Z$OBoPoW{Ug$h9iTiQ|TZJ};an~c~%!Muk+V(30 zu3%hUB@akFfDO^-HruEr(Zze+-xq9`hvb-RRZ%n@`Fu1+{J3s6EvJZV|>hu%yg~6 zb0yAI(Oc&f2V?hn_-`*zcuJKE%EMD)x<5QXQ;o0ACND_?V*6-o(&$O; zrt?q`X$cO@McAB6*H-P%gr4&@tUj@j4Gb`m>ew~o8tUSl)eW}uU82v$fIZA%_%#1l#Ml3k>O0A_UTEslfjOp6?_ejo-QfK7>wr$F00SX2Z@bm zj>gASje%Cz*s8aR$0Olp7pL@_DM*2x5j1>mr9S=~k6CMGI+D2*ZG=^F9&k4h)uX!) ze>&GFePB4$cyayf#MC)Ilct*SG74IMgq^6sLTa0VXNcG%wDCa}_deSH7>0R!kTvAL zz7&9N7HX^GFFbXj$G0*g1x{Ph$W>G0H|Jk;;CvreDi_uYRBtq=?RMKK=jl)z=o82$ zUf?Bxy5Z^ETTjg8g=mc27GM6rq`*|UAsxTH=%EA%Y@TlnQ6ZU3>2gW=q{%KaeH3Z>V;4A^(S0*^Ul=oi;SH-mSGsy07u%KdwheY7 zCVD3mvh|Q*OfMhiD2_UESr^%DH<~SDZHx7yAd`cu8uK&}Q3h0*v5Tqw#oh7KF1;tT zPV6n#hYzyOzM-$Zi7jIs%F`EPWB5>=!gT7OlYTNThhq(=@ryy)dZT!YcRi6ksv{^l ziNpCi+>Mr876955!0){r?@8zGq=%ADKmi(d+}YzXDYevZm?hfQCDwj!v>7FmE0{)* zQ;_SFYL?-<72!S;kw0lN?D~O&-d`rr}m5BK3R+MnxtIDli=O_ zuGtIm`o0=nE_?5r(UqKBtb$2;47{0*3Enm3m)n4^(K_xuXaBDE64GQm>i$#6NBx+B-R?aDMoz+iGJTrZ!h0Em3Qm8ykGq=_{!p_`X8py6$)nO5^n?`26 zrv1M?Cv5ew4+1Tf|3X&fG0?l6ktbj1nw(wL+Ul7r6>_l0g@|<-oYqxjp+=@=wVsCW z?+o|+jSQ0`p1+!Z;+Gm+7Az2XV12iRfkkp!uaX$OKhUzZrKl0HZ~c%By-K6Qe%*zo z-8o#BuMW3##}&!zE=sV)!o{-V$j*P)RsxQIzKWGF8mRKAOSW{E9yF16CHK2}PJ#K?{?eVPaX&g^H6p^xglEJg*4a5sKx1 zUCU&S06T-N6$_JQM>dMvWdTLP+IGrWf$h2e)qGcDo^8D;T(vf-9uREHBXiiYyB9qe z&CCOrxN4)z=QqpMCdnz!=8nQQ{mSOYI6`J`Oy8@da-z+&prI+t`)_S^H^mMp$`rO17oXddu!I+kn3N;@FNIo#<>`ebkZmMf=dnC3iD$LYHbQ z%ERfEN7L^?(9%}!x`sIdTpz#SKwAWw~q0}8xul`oa1J-wc3S!Ze-zdt(0mg9HUA>A*_dkDJ8hubN z*2irnC$r;97QuZSS#kbHm+0m!j$$vq>s_bi)OZk5+erL-3m>H!L`Y!Gi-Z0i7(v1hi2Ut!(@Z-Jp_3@gd}}@`#Qa`*z8_R%XXNkrGx4y_nUgZwBLEP!S!If`Gye1Bjg#@U zYnV{f`RTqG=-!)!*8yGy{@Dw=>5ykZ@i8xf3tAl{cP%QWHzY1V@GSGlLO;A)7cwie z#ooQAuB`@F>51Ip_I`6M52h>_tu2mxInw4kGBXk7(IS!fhu@TBb^IQESexURu|+6z zvHElOBk&F<^aWVB+iR&SiixQrmAFy3>$gMn{!UHuZw&FEzr;TUo~beCQEQuCt||-p zEM}q)izF9?)O^yc)roH-KWEO=m9%)xM2|jms6CGOb+}=;QRQL!7E+Yh?#dwkk)?Gq zU2){w4=6%VcjDp!u4;>!UU5O|OS;IuYM6K|rfd!%GNaLu&d8CF#{-J!5WY0Ju3GfN zK`c*-RI!{%9ItO7h+V$-UDt8V4Ct44FHeQUQwnOufmD5?3Yn)Vs^89nXs=MnQC$+T z%CB?tPL6e19=-e=GXI%iF%T`1VyquSqDn0ehdv-!eFO{C#m;X#egzdC8F7QGtf+a) z{(g=3?5k?(dPA?cZ;VQRf-4Anee-L~Bdn?H#1h47w5R1C!QJC8{bXm6BnJP~Byfk; zzCoo<>_3Bo;52ae26r*|r~}CL5mESsL8?OXnB4d{!-pzgJJ^h))WE$58WC|=D)MU+ zf<2-w=TFTzxQptazRx`S3*j`fU&q|A75T;aRnr1u`89?BVWhtKNKMzUR!e*AL*A=2 z`lREz8*k55Xx|C0X+70(KGb;!Q;}Oqv?(0f<~aX$Rx|I!4np_lv&jB|43yDhNjpn4 ziV7mB?X*cYKS(rJUb6)+?u9CW>_iH`t8mUy-3h@_s-(q27nw6Sp7IrDzXgromKEdIsS6{AjvZQ^s`jUF9(5duRUViyun(O1Ow|iv&JLhxUTHlcG+B+`M%VLkv zD8Q6Tchg)m$})!fM5v!xLX0ci4YeL!4=5j382Kd3n(>H^PlWkyrGF4S9W0y+2L|^Q z>%e77v$p(}xaH){jLScT8!3;acd`e4j2(nhCvR`{wzRN){P*v{#doZUBD}A~NlYpo zb|12Mp$+tTi+3rd6Ox@{-VEP9dQm3|Ib8cLrN2?tV&uX&I)YyZIIyPus`+VXkl?PtuJ#}PdA~nb!#D%msJYAzTDvaush!MKNzCZG6|Np3@oLMDZYM#f zG>zHKuTwvKQh=K5*W>=o1=X&MX1WS{xUsGK`R8^fD#EO*f49cThk_n-Ew)?Gzu~=*8{(FQL;x=gvn@8->Ftj_&~uGfu~Rlw0I~MNTo?JiVG0bd@_!y)TQ!csL`GD zR!Ffjn~WBXD~kjBp{Z4tWix1!AbdBGzz-u7t5+XVMjqnnxeknYMvZtjZz&pTaCDvv z6Zx8+kY~N%PBT{w)ls5s&Jz2l3oVC`Xb(nxK^Yd+YIPBk#7%l>fmU0eevFp!-6H}4 zw?kvS_kP$LaCU>o`=lM_*L1sSLEiF9rE1I3#3zXHx4k&)2#RD!{TGgz!Jk&+4X8O- z6rD_i*#!6d61l|!vk0>u@zf_;U#5Pa^(1uC9j*^#fy~+h11OUNTg7f7?^E(nB5%{S z-=s96&hkYk(}+He{LehD5;$N*7aEb+(I2e;86IEUo zzw))vSqm=uQ#AHm$mO?uIgPl2VhMRhDwg2Qv5TdQJj)7z!01^CNQ1td!G@Q>CEc~# z35y-C8Dt4^*ZX=EvY%10tLPrEnPK@TqO|NO>EVtP%+b_5XG#>*!;3tgCAGP&(2fsH zQ-#hHzorDeAxE_LMQ#Nqo87q?Y{-CJT(EGEg?YZc{$h3C^*wprlEdVqSkTO}ZPcV$ zF=25O;@%2nMLUT0V~drp#T5? diff --git a/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image002.png b/src/Resources/Help/HelpFiles/Annotations/Annotations.fld/image002.png deleted file mode 100644 index e220ec0757fabff51c28e19340e88949884b5206..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153110 zcmV)RK(oJzP)4Tx062|}Ro!pfR1`mnZ(O7nKcKOW4i$^9Ra0BJ8yc;~21%2p=|UR0&DbiW z$#rfTQ`a`O(`{9s_5yDV_yd5l2Of}kLK+Oj_Ok5(v`JGz71bo9J#^YYXp{DWs&KBa zQ@dTpxRI}aIp=pi@6k0t$5)!;m`NF6-tt{FpOKHBn3g+MAqmexC-gw4rh87hTrL7G z#)U`L!(So6-Zux@>;H3gR;i~0B%VTSS3P|m@o9jRsXML@Al^p#@G0Lx-0?i(9WEw_ zSYddU<1E8793KxjQ|c&UmW!mTC>k>?{om1c9S zUx<6_jj_!T&^M{wWM#>IBbOSf*xP<^F{$j$aOQ5Y{cT zROCL1M7^NKKL z&(yA}mSw#iM0^;IB{ZO5!wl{^Sg-*ysE~&Yz8!E;Qv(A`lu*=Clo*MpVGd>OdF6n^ zam1Jntk;<}MrqIC5$=Q>n{*R}?8oOIDUw5En2dl--Xw34!z7E+5pr-OgyQ-soSab)C%saskMla`aQLVzg0+MZf20tJU&K{hZoBrUc+U4e9&3o zw|KmGEe4#xz17wBu{f`SS_4i66?j31EjY7n{zGfhONK~c+td!TS#B}JoR}5UAd7p& z5phTyXSkK0xCeD3xaYP^o&J~#Xp9xFb0C;HHml5fA<%h1eR|qw7wxF+oNL9T1Aits?sKNIwvGaN)^WO$I^cUV)HzL_| z1K?{9p!>B*)`xfEv!4N6IG{J&h49W#Bz^(#YWw%`e_a{8n{G9m5AeR~_yl0%<7V@p zF(4oS?(Xg_q=&UOH=_@(2qb;d?(lI|clxp^z`Cd)dU<-Hr@I^O9-ip$ z>%oAFD?HrYI1nALO33vxpS|D5@zc*|9v<#S2%f%zFw+1 zSatoNVn&{iVBj-_0m&aPFE5TJCTAhm-`|hAx;k`pbU-t-hK2?skj#K!UL7T%bYIVv zPx*%{LxPU8Jv25p8o_AG_)KAH1lZ3U23%cTP+FLef|3f97Z)I}u+%7AhDJ%h5_0|h zeH0X$B^lE?>9^m|wlq8C6Rql*&Rr=ODvOKI)Y4&u!HIHQSWdqYG%8QRL+_b;$Img) zhx}vt=;l~CoW36oE$t{PDMnLkm&vC}RHu%$6(y)|Y&G>Y)>fjjww`$iBkQ-Y*fC^a z7_5)W0nF1}S7Y9{a42tgR|hhW97b7X-H0F)o=4KZ6b9@#IB6Os!td*40^g}B%-6cv||j@=PADiQ4sRcL5#M|gA$`Z`K=4PC8uET;k9enANFbwg!c0|t8g;6^itmtO#)Li|xuS`N5*Va%8m zcylJ^>qQ|&WzWsc9W9Mi0J}MJYOFzJNeeuE{1N2qj*6Nl_~BI|OC8^HMR|E8 znrdqh6&r`n)&?}PO<|GI=x(k@OGh_+140lU?1kdeN_hDOAb{^wR^+3)+zX>qQ{m^s z*&hY12D^?UX#@lRsu(ycTZ7dCosl3RHj+j#aNc1+Gb}P~&2yw=>DWubR$0}AiIXQ| zpraLa^{t3YOh$;mH(Dqh0z$(P7a5AW>ME3T=Hf#EP*GlnhNgB*m^2B2G>ZoXhaw^* z5VbW87(Zz;-1}NlO@S5}8IJ&eFT^H{f-6mirRAmQb8$ycdlOpPJ2;bam^RBx%Me9D z+0syro&guMP_Y|3aT3evGBdA;*jR)HdL!>xHe9^|D9Ahz5tD$_lsJ@?7Ne@F7T(@o zsI9I=cb^N!j73T!#6^WsdF(?>LK20WKh6G~?3w}i_yr;%E}90`ku-vV ze_afmG$WI6(t4H_(PTE10Fx#c92{)U^<4Kf^OCtx=eno-K0ZE!wtU(w%{|T3lt&t2 zP*Bid{(oI`jLaYx|B~4f&)A$ByuTaxTfnP`lPTiR)>DB zRe6v$`{Cv7gWy14vo;kG5svnjX5=2rfvblvd^}ufT5P3Yps>khIlXT1_w_R7Iyb)W z%JnB#mKPilj5?YJy}bS4tU`3DA|tGgJX6qrqwCGg@*%DuZ0`MEiqJ@yk;KeL85 z(Cvz`X%o@hPy?3$Z`9LN*xTxb;LuRc$eImY{y_n7>+Rv1v@2(noWXhf(^Oe#%#Z#Y zcU}~Lz1?oSHU>*GCLQB;M3jB%v^fI6$A$qz?Oe+`X?i8WV;walp!6G>v^J)nOpg+5 zIyxukG9(=3G%}J#F!0G?V1UjZE$FA<3Jmn;Qk9&K+Gv9FgS)7nvo+1!$m!`|!Py&c z>4^Sbw6%9R%;a3(YHe$WFX`KLpr1|~eem}3aFpZiOQ#CQJ1R#)te@k?ox-J!rg#@O z5BQpKqoFmxwc=iQQpm`OgPGyxGQf3X3OpZ`LxqrayRZ(vNac}^9$XviqrmFrF~C27 z=iP*>1HOJV@iU*so5q;xYo%kByQeoiJv0Wbha?5-abYI7k$lmlo*g%PeR1fuV_}uLC&OU(fIKjmck8P z^PU_*^jxxFfKq_A2wj@82Fp4AuC5)ko)bsMBU`FtJUQpl^TBdVHvJJa4y%Wr+hpG} z^-CgsV115q?E5-8V0XSVaz28Ae+>-KBc8^5Ce6NvOKu#+R;wHC`Dfvt_>o+XN74ue zMldjff%5?aR)IMiSgaCrHhGoj|Bw0AZX?KsGy6$^mDjeQu&RYxsWiOLUQ(w9`FUb| zV)$nd_z{RlFff9Fv%-MJ`DZD~ci?Pc*8W_XkUxw0C9q`zH~SmUqJut6e!G9!2r}o2 zRG5A(Twgd=-2>Nvcw=8b3pmcZERw$!?R25uy%$0LpUpKoZ6w#$h4VdWplK~sM{U0l z4V~{vYrk@8a;E?D9p(>$Pxu$}P+y2{J`4TuL2WwSbG0=hB7#mdp=ZtLPgm9_d0+c( zoqYj~F;BSA{@vqIFHV=$(1mE<@|UyCFMo*o`udZ~75vU{ zJ3kaWviO}%`5K36@43Jq9`2Z=7(wP-v5=t#c6Ik)N~|YBLmZn&O&$Vl*wgW&)(za; zkB$RZDKi^?VbA`7Zxl))ainSKeKQ@q#~`6)Hie?w|M}` z$;rdk;~*jtk15a`2RlV&n`%z1Ti9pjJ=TAM?1ohS5nPIpbLk;BcI;T=O8!AbT7nvS zJn^1zb+Y-vw&z5i4|gV4_oAXALx^#4al_(TIJWhh6INyMYirf!UzxPkcJuUO!m;2L zZlj{2%>KsV@L=&c2%G54iP4C@6fNUiG-g|tjzi10&xWq;+52aEloM8IX(`5y8#jDE zSh^Mr{0&mSQ`Dpw`JP=5|FmclLVOnw8&Ei(`W)?q6_ft4tj0%a9Pd2zZGp=edukgLrHxf zrcW7b@>Z0TAh)m#GiJ|1ZE-rvn_Mw#+5~!25s@4eif*6*;z|Z!uDd(9pQaN*fkDQV zSoeA;6kX-jMVBxMCk-TRB<-WunFU%=6qMA!em)n1g{YxPF4clv?a(Yih;U9qW*0Yd zyKrNyE8VnR89u0+`8;@(Y1QF1=E9C(=Wx$XPaly?mue-26QYkZVIZ7Vnh}4x5FRb8 z&gZsn5r<&XGj+VhxqWVrf=@7Ov$@XCl;r;1*+Q>85^zsX7h(2BXGgp7W)ogn89nnj zTcUy@!tG%@wcE;#ICQ5nGT4S8mDqX(uin$qnE-8e<l9D(wyXej5c082R$#_-S?sR*%9)7m2q3{ZS zL;GEM)d$LZI_=Mm&zf7?xosqneM&ka{dIJ7!Q00%>y*oVPe%hcQ&%FI`@{Ua*r%cc zCq#;FsRpusVVaNlvq{&YNe>Qko!cZq-bE`yud62l>E5rsVM?ME!K=0icKt**!zIz4 zo(F7rR%<=2+0OeScGCw*OfFo}B?E&os(gi|Hm(>sBIfrj5{95yvInZ8yY zo6lrE{zv%_9z19SzVgqUInyY{!;J~$)laFty^S-kMk=R;m@r|2>Br+m4%Q>yRa;w& zl`B``f(tG{Qc@B&Zrq4bqed|pz!(GX&~}Jtmz9-s`&I)|Q&SBO9}X7PrM!Co@ZrN| zRyuzCcxVPDp>NBzN8^wCqaXd~e!ZxhLZ%9kMyF|{q^ThkA(8is4sXTx?)VxiTKsX* z%ou#{N590JOD<Y<-w&JzdR&Zl$C6+zA z47&~=MMrHpdb~pr6CRB6oPAia=>X=>n1JX0_9zfB8d1T5!yRwFxD5T_qY)kGX$HSz z085jSh9zO_aDNuFwgc1FEiF>;$Yk*H%P%7(C1tSFY#w{mG+uk~lu*qr=t6x-KHA-a5gqDdV*G7d@i#p5+CE&fWIA42_A2)5JAi<=6h!!Y zqEDWAPPo&#+Eh_dVN6tlch#y@X8)jOTp~W_{DRLq4Qb8wWLyszA(g&)HI7#HAtlNK zzklcvL?*;z>)Le~GieGu$jy!&*nx-s{7>W@*^6DdrD)ARhMwRUM2FBU%>I%P7B0o? zU0nz8{;D_8?L*TN_gooei|~pu2rkj?tFOLl@ER5tb_zUdoAyGA-t}{Ciz{8{i;ljJ zjeGM^d~iM1ZQYGdvipoZ+Yym8o)!k!=F)9-NG8( z5fvR~a4o@f?AS3ggDfm8#Jlgl3k_^%xb3<6Mr{jWM3SNXAYrv;<;$q+?8k=Jp23Ru zwjsdJ2Rru`kb$Nc1!K)if5nRR+p+b%x6vJxg2|(!(9x+lk+QN-lWwoaTW@T@sBvj< zkpjr}sBQ^vmA`rQay;?cDjZASj{O;RRFqn%t%M_x!rqC?o-QRcaY!zf@BVg&^SShHr05vHoQ zj4+8tRj&k@>eGEC2|Zo!+O?bTYRv(ipIo=Y3Oh7L2%+Eqy{x$ z^PVh>zkVT!+6(a^vDmX?0}7fv5fvGPl}|s2hhN$Rzn&)C^dCP(!8?CMZdVw?^R(mA zr76hD%EY?YpT`SNy@rOi8r*aL|6d%WqkoAKQ9uc1FB3`Yw} zF@+HowC|^`q7p~IFVExL~h)J4^=Bg4bm^l$giyM)g%$S2E#h8>5iMrxUY}l1cfe~XuDAm=Jp_%;^ z!l)G8)U1uWxh?ScQFV$?#5AR4{rJZ}#;<<$D?=B;r*l$X%V_k>xh)br9W_OGZ%;11 z_VxLA;vav)_5*FW`<@7FZY@VuLpw(KcjJ|p-^BG_{VwLE1z_{0Eo7E&!;=b4*5Zp1 zZw5-I>Rek z5sabuoE8eshFNEa zTOhp1_-pcWuwun~Xkmz|dE=w8H>(b@74IQ};i%I3k_>#J8!>n(Wsg7pxEahh-gu*d z-@PCd0T&|9zXrX z{phI3MrK(PUViFP9L#UPq6-({XvQ{lw9=%<*ptDre#qFp9ez>MkPyZ_cP^gjZ0LV?E=)AnV95bkxO`A5&(4X?# zr1mafv4V<@hnaP1oK;m-;FVWi#uvYMJL@{(kf%0jrg_gj_Y7Lw^uA=1#`fixUycVJ zc)%8IjwcB+0jUNFsU`w#3>sTlBWmqDY&N{sD)^3bV z3_`PaEbh1_1y8=P9uZtWtYD10KAKmv^RnR9+Kq)v7GT%@Ow6Qqxo_(_q-W)0`h+-C za%M3=L1y8fJ$p8O@{^w+Jv|+dJo1PU%EIl?q_)_1Y#$8GBhySbW^sw)5QAP^Z!6?7fn-L#mJ%7)XnG*L17_`a-k?LU8fYQ8>(9x zV03ge?!EV3+uZIhe5s%L~yK5P{iK6KR&tfhWz45#eL;xhrSmt@Ve|7D&@>dkb-$k1mFhy861y zC=7fsBQ2h@ZmuO9hgWo=K_w+eI2LoztbDj+1)1Qr?a`W7QSL$X`;10xXc(@z=|&vf zwhr4O==4MjK|jMwwKY^Q2rqEM+!<)BtAq=M)Zrt=xcjcJ;i-Q-j&&RtmtFUH9QNr% z^RXj1;=-sly_M*8U4(a@`6Fh2={}71tU)rhRv(W6y#B;vD0Yox%*Gnz`?+Dsb&Jtj zR*a-^V~kR%*|O67`SbD3Z+_F@Sqxt7v^aNepT)mD+GjEc?%ll`W2Vf)w&go8d+DXv zzil@rO&^CQ4rf=l0c7nxh;cJ6K^P~&nQc92EZB>d;52;kvR*v){F{iIIt7cT1|l>* z4l9;D$648Ak%gwG}6NB8{!e|h8~9NxAbWqAj%b#tYYRFVf#i-mzkrvX ze->rUp7_$&zluZKH=~}6a{kgQ(cRf$+9H@W)07~SwSw9T%&uo5KqGYm{^&~hr1bKNmD5Q0vxw(lGr^u7w*ZZ0|-g3(=X7(jMq#2*&QeIx( zN$nL}#vm$0*nupBiD-1RgrY_|2*wd@K$Y+nCfd5&T9FhVO4Aet1@Fg=Nkm6;Ek=(^ zHl~t=*Itf){^m#c?LXhZFa;}*MH>W>XpP$#LwgfI)MJ=!+dL9cJ?sPN7l4m zio&{e>x_9s@LJfMkAmO%dg!^{YiVi#{9{qPcQqdQ=i6`#h(dCtFOKAvAvt9q{?LGh(E-40v#lmgC!3>9%t81m|>S{CVm4=p?nTbP(4jCK|m;ZEa z=%?ANuCkW#41+O|v#XRiu1Qh>sw>Dsw|gvtIg9o1<*cftkc{qmJn^>|a4@q3u~R0a zyRj0TZRN-+ZA4!O&21e`2#e>Mlv^)q8>mUrO3-_}Pu2f2cdT8z7ScF(lWB|Shr{7e zdKhev@JTIGu@5u$?lT&*muDa%JzMBB)J~iQV8G3X;i)RgXkWxX9{($HOX|?x*M?PZ zz6sx$c=(2B*5QY`qAK(;{8VVPA7Z1Ypzz3cjG8$Qu00*d&(6WYz1#8ftFNKf)d!&w z-bjd_Zq_WrNf)IJwbW4@3+;kUZFrOAi}5MRv@QWX2={Ru*z4i?qQAEj)pUFcXUs@9 zGKR+5YJ{guMtRm@_{LGYr=Sjt51|F(bu4@ONxb^@Dk=|ssN#5AyL}&G6GJh6$_z9W zmBOX36T$A`49e_+sguL8eqSEu&zXs$%q#?rnvAtJ z?SAMF2uA|V%e}5#b7vrDFPa>Cjtgat4=H%ER*2>_^N^-LTpy~fYNwK(e^!1LUI}RN zQq8C&ko1#~kus(Ug>$mPK>0OW@u5XZ@9A3a>A8Nwfh}L=LzyYXFBdOfY=n&jhs=J$ zoy}*D`rJ`$Y&;c*M2??CBr+apa`G6nrfqEd%&78JkNB{x1DiK*Hf6~}R%1$nMzcUY zcZNr1=VS_N@x1!_I~EJ9ysJou_9f5@&7gb$I#pcW@nNlzB%F z!=Hg{duop2XtjrFOMO)t20Z)`#yEWq4OM9C=p(Fj81N3DSxM_dCrYzts!y8V!w)}f z2F&L_|9SlW_rEvVk*4)l(Xsh;Ey7l^Yf|=^8woaN#~S3eMc~FO=c0*`-{s`7dd16_ zwCDzmj}JDE0gW_^<`k79E-4iejE&gAX!CA;{G1T!v81?!nw~#@eh3KiXGD276c*JX zX>^=%7Et{Xx(_|{kXf9bGiQ!5KWIiK+Rz|#PRg$VCtJH{d~iT;jjKBUAU3Dh;mXUV zl6G>DGM#^5cO@fFL8 zis8d!VPP=?`*O{I(exuDsXW#2^DK09s%8Hxv{YnRFxygs*fm>`raZK58Utefr_el2<(uAo5q_x)krE7K7gr;V z>tC_Q$5=H$v8Wj zQC8oLl;jv%F@SJ?nxX32;6vdZ5*&zznkqVx@QVQ*wRnH?9u!jppLFRLuyArB8L>OV ze|4a{wF#a7u{QMoKCEHd5VM>?59>y+qJNqAAR>viA# z?sv`j6nsiLDvxk=KbH-(M5FP`nV=(w6=cdRV$utm21=SMqZ+Myo#a09TnrDOrxo*6 z7G$EbMH(3gQx6>+B!!PxD33!0E|tfYqZ5vMBoguR05c23%p=LI@^uuFT&TV8*}M+h z4`*ZY+(o!>))e!hz&^gC=XTHvSvr^PR7aH|*p z!<+3J;HN%H;2#!Ea}PbCju&I#;(K~i-dx6$k`IMB*^hO!!c(tMCvyBH9P$VxKn6a+ zqWU#skiA*jlJ04`thNZ(&hQCNJ(tssG*g|QE)mVNV^c8*W`8kqyS{-{!nLuG$T)a$ z&aJ*ua^T1Tvja^Iug>Ah6@El0A{@J2uRf82p_W_vQ2F*}T;FK|5yn-&n73%b z;!BExeo0A5C((u4tNaptVg{n|6LiDc=yg|H-+=I_7o0bt^B%{laBh$`I*)wI@=m3bledU8f3;`bA1(BdfX6AVe04y z$3iTa7WbTYaLsRgRuJ+93KDe{hVM6K!(DpH!QBDDZaBgy|C+iy8D{cB8OV zoApezY05r+t#)Z$R^vfQG$;l=v@Lq3J`_Dp=2s0Y1K0iYISGH_Np}2;UgeOXc52*c zZ0V?cvW(fE6=b3X^{vL5=vFkLqmu9>A)t3vzK+6?gr9_z9hV00#J$F|>esadlitrg zMhnIXHfhR;iV8P^RaP&Rsq%zxjW>A|3jcybw5I;kGx=BucAX0b3!~1(^MnHlFwwJx zLA*xgtF3xZc?6Sl60CZr_arz~?y!PPg$hssrI$3&?O-@gyMs(#d&M~ZSlP+iu5-m7 z=3I^#3V^Cc$m?%t5?pGqO+&Ap?+Y0sl%ax5+|Nb8vz@jiAz6&cUfXg$%A;k-7N_>w zYDUg=sais2}Y+&UwzKb4#0I*ivSd?3l9sWcyh6#fSBi@Unu;(O>F0N78%x>Avz=FG1_y zpj>*UWb4qm?n$`m9pP9rI6W6#4NZbcKk-r>1(O7(@GrQ;r|p=t{iS?Xkm;WD7}I-Z zdy}DGM{R;ff>PzEY-?_`usg$K+aZ2q1(|``KCqefPy@kMZl4=cccORgvvTN+_RWvx z*v<7Rt}&iAS$J%Qq1X1lJ=#wApnNv}`E;}dH(ZCFZ*W>-7QvtIxE4M|7aGWd_g^Uq z_iEqy)GqSOk388v)U51$A0KMG`o(UE5Ys+WQhOvIBv>q+o+-bcY5Yl$={;E@&XiQX z6_64*cD8l8ca&fGBxF>N&Xr{TJY7;gy=NyzXW|LAe8I0WrMR3azv^^WsEw$mC(EFC zlC)F<)i6yrttN0fU_Z(GYOInSsAp5R@`@0o6*wctmUT8|D39{1oKHHbUT3&J>H5#5 zK8w>4c+UlEA5Y%T65ae?FksuMvH3~Uop`0{JePXyJ7>#FEZ;iYI+R}m#5up}wDrkk z%?n!997`YKsLHP-_Ntk=^0NSw$2>UxN4U1-JKsOkxy|nk&*}0zmwzt#X<~OozjrQJ z(ohmzHfm>y=bY!$I=73HvXM&Io^7(kZtb;tPi;J#GSsQ+4ApHHP|vpBk0RgMcIZb@ z*GE-`@cmII;bCaGXM>wF!SR26|4e0{?%B{boG#x-asR{A^>N_&qiD%skn#s@(HW=OJiXx-9-&O91|N z>f+Xx<}Svr4CPnQt198@6Nr!iUjx5j(psj<*12GFv}*`3r@0jWJePE?`BnBQrbRJ( z{WM+IT8B-}9c7VipXn&~O5xeWU1X=8OGBN@Io-KBT^%CWBy0tPZLoD5aloOCdUSIq z@*D(n!hWna$d;}&v<$(oMR|q4()&uvF9D{yHI=q@Wb^Pm`6E2rsk;S9PAJ+lq%c~; zZFIKzbTp12BzzV#Y#RDp4lHsmG2w}ZedD9QseTx4(CfYim8FA^zUGg%#G%TQ+BDo) z8m`uJ$vfQpXLC>Z6fTF3-SZXCf=f7+2~~njxcs=ysltuSYx>E2Cl6i0q4g$RJL694 zJc?W~(9?!J2l6m^<_y$v&uN=y5E7$9%o?rpWI?nno-6-=40;zvjUIW z$!Kq^H~h%}m&`&Qy;cL`)8IuP^`^EiM8`y-g`wlP0*4?9 zH?4EZb)MCqH|eC6Jt0Pj74vo$Vj4tZmg+3!vC`dknnKr<(zUj_r5lqbjz>51dGgD* z@}&@i)H^n>TJJ_is~CBwW1hodNAF7rX#rbaFCrv$Jd2~7Zw>eEgwu7o3+2^~biH6V#v|zGjXyLK8v=~K|H3$re#+Vc?l1mF=9y?7>N=iCKU z=VyZe2?Z&zHreuY6rMHiEu1#br+pM&wI53gt`uF(lAIMADX4P8(+ucL$(fFoPuFVq z(4_iwUu!uUbJ_$f0j7H8S?R0@2$!AQ{~F})gB|a!KvqdL3U{u-wfFotzb?{j*2{!b zi)RTOl@${c%kX&HvGGtjW`#FlLqQkDj-O!0Yf@5@0ZH(QH;EVekk=0ITwbrc-g^-_ z9Vu9_a5kq;j+lhPk9b69XBXxzy$*YS`y1T%`>nWa(IPze=;LUo$L;Jnljy}=gMU17 z5dQRr4QxGt$KKt}&tSP>3L~pzr0?UN!fH&v^bUBnmtp3GS0LP%eEd`t4Mo`}a(&WV zRR~o_NnlvBn-Hem;FggHdGe$a!u8C99lH0O6?ouxPvNZ<%ka=+%dq3Ew@}ugJpp2D zTy!S0)O1bxL1FXe^G~Csjx!xypF^_n=@pfw>9m(8H(I{y z2XXIzKEO@EtMQ|s{tvonJysA`&7|~Pvnd^W$(R(Rcir17kj}745`em|$n(0d;K>SU zv|+_^94mBuhGEB>&*H&{AH%AbAH|;^TW<1ea45gtb?I)xi%&kqJ%c=#E4eAtQLeTw zSQwP|Tz(FPz6qcDn-5w46UsXikm4VNr4+|nL1ipv;0W)OOR@IB*CP9)=$@>O@`@aIJU3g z)!+RXLG!Q2oN-ayve9p5b2h(@c6KLPx#YSpq3!5u{PnGU_{tZ*h`w$HSLfa{TekA6 zeAO$byTGU<#)M5nt$P%H`@p@dkrRdEon`SOlViU}Ag;J<0isf-!{4n9Q?I%WH(fLl znMaOc;~UFS*3CM+#N%r*ZoyLAdBbA7wel5=Uvv|0T(khy^=-K7%4-qobN&c1HS-kH zqV;-_=}qU-5`D3(C-Id;ils zib$Q)y4CMu(QRL6D6N^;#f`HWyVv8LRU6k- zv3`FRX3SX%-_BwjVkC^ixz&s}n1=oDy~E(k;g~aXJhB+gexRiZ*W7YDMunc(#qSLF zna+iGF$A^M4qo-Q_L1nm?H3)-*EAG1F_ku%q6qLnZwH=v`Y~kYRO9j+Z$kO5l{i>j zkFg7G#;Ac@tl6AJ?_h2kf8vigQqYJiZ@LMUn^$3HaUCwb`U>P7*pAXB7kuHmEAYyT zZ(zW^3zuJY19Eu3u)YPKzx6AO;h1<1Hgv2<32eFB**UM&r% zN(&=x19 zznHN&vi?0J&0B)L#!>_^u=e!v$tSgcxOz|5TsH=|-b20^GJYH?7>u{(>Wc>V5IVnO z%hd9Q8v`jUx^NCWYJ!o#s4ulOZHCUB^ADcW!qr|^fM5RfFP!b&iv$JTY|#DqLeQ#D> zMq22l<{cPBEt&tk8M4O1HyU5N^%lJT(woTYp@!n`jiU^ZnHuGeYi_#@IUC$CZgjL^ zLW7-g4kzlM!5@WKUu!eo-?$#p)Fh@ZVBk&eE}uJn3I!Y0QK!7NQ-@Zi4Vf+;QJ8hX z#c-*sMh6!@8Ng|1w$H?MH{(QxhC8C=hkASBv1gya03(<;W*)_^Iv>ot^m?p+^g;N~ zV6fwZTM!>R9{=;d-^HP||G?UfyD??al?dxEpe7oOgYWOejCtcsEJXS?5tklZ0Op2k zZHT4d+P$wFfByaN@Vg)W2(>ih-g5W%k+5zpa@M|uj5aR>*B*t>HJ`)g|G5>R*ZdIQ z{18ISB3%qtN#;3i29+kN{uGUVR+DDD-cqy%y3s^$Y>H-n^S8z?|cz|f8=>E z#4vvK;7{?l-#^I(`A&w$@<7gh3a*Y2{QiM&Ve{H|(aSF`v=!yDKaL*qj70;Z>UV(pGYXC=riK4qrWGJ>K)XjUd1Tl}BzxVC)3m7(Ek^7o*olXOy>h3#A2 zO*EPGUHcdxwF@beqVeRTFJbDOiEt@6gobW!_))Pat}8=XHsfGMB_ntDCUkIi)}58d zz_|Yb|C6}oSz>}?rK_nD+uqN@1All18@D`%>9= z(7t^(^ytQ!WzK<}$nR;#!7Z;MD}5BccE=6iS9(rKvd%<~8jl;}9iODS=k8eaFzQcK zs6T}tJsD?mEso)t6fm8XN$Y?cZepN?Wy@E=lV1f%9i4=Ui6LnGpB*BRy_06-?*j;%oxXzNCAGx+Ledq z9-3`wer({nC-oF2AIzPaf?xge*GTr~>@_TfVaa;%mxmvLXG{u`NDpBQvfI{Bf~dr? zh&on*FoyH0$xcVYk{i(5l8aKBCE`OJQ3%czuj)Jf#8CAUbG5&r{d%rte;WB+Ii~6h zvhkNk|A8QeKg&H*f|yZU->k00n9+>Zz-TievGMR~D8^%t{0*hG?MMlXrC7^HRWlh$ zX9NE5x5sH7Vbl=@tPZ3JxuLNIM;N{Sv4(8S``i_%EG<26n z_~KXp!$gA7ELZE>GF>Xa%CL@Q!m}K;Qm4*AD$iv?R-06wtYb>bZ^uC&H{GUPa2;N~ z;9Bz~3n`i&oCUH}lXvJJIl|EqlJB#n(Q$^43kH3ckkb_Slil<3cw*Qr@{X%7y%fEk zAsC;UKr<|@Abe`uX>)#>N7GU+N*b_*906y|iq@p1n>t@JL9N%R zUcslNwHFh~g0KrF+YS+)4TYmN>6tWnC25>y9YOE%SHRiH`-h77;lxl}e&r>Mapx#o zrd7eH?Fb^I^JzelGM*s-k0*eOwIZY}_M&;g6Wt#XFEO5>Hi% zEZnC%$^q%vv16wHw2q)Y)PUC7t)6LJTDaDx|PJ@(Oh zR9jI*x(r4{kT+U7+R@s?_Zg|*lTK1@Tr-nm;U5vpIHeAOqwz1HBK{+OAe^X9oeO_9 zi58{oi+2u9f?IT}_f(#)m0#s*4NQD(I9e7jlJA1@+a#K@Jk8#-M`!#97WJj>Y3vMF zzI|`Fqe8Gzf)VaB&kl!s_ru;3tvR>VmZN*l_bHnk7_ov(8Lh-uAwsMgEJBtb6T{H8 z;)2P%V?E^@g2bVfXgbPFM(Z%n9Mlfv6{z>@&zPo&lyeD-Bfy;nnFz!RGTXq@9rdoX zouPuvt^s&*5WMq`|3y{cIDTFvf$M=&8B~|;;CmuA!TnhhWT(T!XZ5~lQn5enpjY2Z z5mCR0Az0z2>+>;*{=`JYaO9Ztaiu#5|QWb_Dy` zjydzv$Na|`uU3!=UMt8P{7W-Q8xHNnj7qd3ap1ysl8_8962DS>SUt0}q%uTz`YBl& z94g2xzciVS|8aiLD%+~7ht3&1oWzXHE397+Y~9Xf>0Ip{E}bdAr8_Iggdf3ft!z5V z+tEcIgr$U+6Uw{f8wHd-90k1Z`qkU6FuPPJ>WiD;$iYhhg- zDS=f;tzD6mmBcvoxd9a}Ayrn82lv1*1|AJUaX~IWiNfcR+=C{!SC&PWMbimd;Fd&J zr>b06SBEe&yUkgaI$nFA_~Ibps6OYUhA5wAWh&!rli;v|cer=7UZKwRm4GxJi{~d( z916Seq2QfjGPaY4=J~8&OOQ!mSz?wFrKI-io|wq_oCKo=on3PhoqZh1g{JiI5Pm3? zTKk7ddQW&3UNv4c%dj}sSUcbGtTqeR_UGU|<}P{0X)xmSz+@RR;W$x-<9(GqT#^zX zMcetgW=oo3NkHcF1Hz?r$9M7Y;WzT8)2*FfWhai6Ut0vk8|C;mK*e7sK5I#02N;2? zYHfT%?d?>VLtz^ZF6Vn1M-pQCs(?+IdpF?k&%Qz7ABr!3>mE!PB*06q+0A(b(L^Jxx7$=9!iF z+V{ST`m#KDa}hCyi;NXCfynF>9vY0A%3}0+1R;jseHyAAsBZlPrwBv?OV`o}Bz)vD z>(~HHLCB7mE4d>ww0OViuwUDL3bH5{yz33knJhtb+Y~N}?sfBu#f{(tXjH zj&>{z>tpTX=L7vlE?soU|Yuh!;B7tNNt)%W7kJlJFrusaZt;UHzYZ^eOm_O-3aB z2PRCMjFP-!1VzV#@(hLiSZq*qBJ#GaKu%vAZn}65r516`nVU8rcW{l&m!IUQtZ6`U zauPR2*Yd0Ct&Xo!400*ecxtk6>WKuO#*0lo?KSwzW6$HRAN~UFMd^5d!(OzF@iuGO ziQxg*wCfGLngf@vwHs5Nh`!Sin&#WmMlg|U$z zZVlYRGZ*+7fi?IUAxiWQO}QY&PG8|9;c`sxb3Uo!{h`C)6-0KMX+k1h_|Nn7_tlK&@d_m zG17G0{SfFgz|Ec9To@n2Df8)PctTDOHPHn(-i4IPYOd`7eL#Z0`SV>421+r~>?uiv zd_Eu|1Dby~Br7_ZHvS%UTW;Ra|`jx%Kf}>1W9gz43+H zZ^R~U?P;ZB$@GgZ#Jev&MS=V)__vo}M@Au*Obo`m>vm%77nj=N|IbIkDtyYstqGR; zReWE|3f8P>D>+G!>86B()|1pRdQqLBXd0TG>1EqVGA&Bua2eptC^Qp z79w}&F3kP>S8-un2OfQX4fm7H#MdrQ!;`PC!Q2_s_#wz9^Y!J%>_Y7D?!wZW?nZC= zn|R^94fNDXgKu9G%4(W0EisIO%z}FA(KL*1q6gl49ZlgAarnTqh=}Ibo#{C_FQyCI zirsP7=uyV&=S;-y&N2?IUW1Jpxp1SS!kxE&0lxeMy>qg-$j^6Z)D&~hk4Mf&Fff9F zPY?s*LsAMNBTuY3N}x!w72|W(+GUFKqW7l07uUntjlLh}%nwwSmNz&FBA+|?+0Z75 zv5FTCmvmpxRkzM<9W0)abKDTY=tIHu;a~CgW<<=CG!!* zJzhEKbZnx7N)y9E`9_Sx;`x*D;|I3ja|@=Swx}AT;u6qZSw&Md9jIJJ4F}3u-SZ8P zK}+>6?9N)i?FRmMZtYf#OPP-g_@(b7=>^6yi&)`DU|Vo-&pvv=HXAL68Oo#;3G)FqxwdIOL$eXGhW?yPN$d_r9s#!x-zRX z^s}9(d-^Gln7M4ZzT9&(YC=4+s~Rvdbqu%<9z{D=;s`(Bx8UN7X&a`u9|PQrwwXrpNi1z5n_`UQhv^Je{X zuDJm<`&@CLkzSOgIoMj!hYPO$f(hMX^I6z!89J&BBH*g(BJ}$Q^NZH{z@?DJUOJxa zd(s9{**=H;+CCjQj$mK}1D`Yo#K$xq6#~kRPaQ44a_}dPZmzj^)5G(HWy|>i(I70k z>(!Es>eW#WNtzHSiJ!zKCS(4>1xO6_!WGvp!M3C27@e954@Ny|Z(%@keqFnl?`CF| zBGkJLPdxDyXIo}HdyZh?l}k8TSdY!z zUwYZiUxGhT&}!mJFG5)wi0N$pKI2&TTTH zla3REn2^MiB$R1UUW(RDT{AGP#i*lXa@3bVbuOE$)}}--M5(Z92&1#D5$)ZsT=xp( ztd8McSd%L0?Unne8@-`g%)YOpqr0$j-8S@aJ?+ciznA-AxR1ll2Z4TcIw2f332-&Q z##)rtr5U2a(7f~a2T&6<26g!*xaO;OA!GeN@ZPa*JpA*YnNP}F1gKq_X)38*IyYf} z=ybAS9iv|mVQ;VAggfs3CemUVUWP(ibxIr10;!OwGR`)gOWw0Bb0pt~!+>Z&zcVF0 zSDy_X@Mn5wH4MA>xt=X2cb?0G>o;U*@sDXRf1VnQydQDdVuD$j$vsPtWDPABxpgLu(lH;5B zqJ)-sle_}OSHu@9D=Q5=CwQckf5+N=ZEYR=gSc&kd)n$6nmHNZS}#2Z1-}RPthLgN z7|1=Hl2Q87cpvu*Hn!5;KOzjBt&Hv1-h=QkeM$QC{AehC1gCrp1oMYW{n)m5H|Ecp zCo%uACvEW(%xZ`HF*G)pg?v8y1V$U{3<; z*k|M{#PsgaBv|#+uJ<|D+=jdoM(dw*5ynIZBIc^EU^a!Q3->nJd^!$I=9zA~dLT5! z5AW~IU@+WCNZ>-JoJNLw$7H7fADW!C10h_5ZM6sqeBnT53kgo`+IM4=YVDd=oHT9P z)=qjs*vn_apG|J`rc~@bsR0@|j?c`~cFeMDWP6!Tq*-dFD34H;uK^(CLLN}g<=JxW zQEim+qW)yzrY^@cUcsHYe#m;{N$P;#0hi<2VTQ5goYPVD5Dy{?ZT7TZ9uN$I$G~z@ zfm~px!qV5%ZIp|X9`VBBRPA?XRBjIfZk489;#Nt0qTg^yu;^zM6`d<77`7t-GVw@Y zrPz2W>=}`3V^QipbzNR}pXd*Io(W#HMSUT-OyYZk8a|(C@1t-ne5w>n^QUWrqmUDS z)z^x%C_2#jAPuNLNh_*V177acq6dvP1%5tpeWI+hJ(CGe^eDWjSsucXDWA1-=3!~l zmZ!E53&YZ&`d#KeW6mQkjH3wwRlx2p@*#~W2QAvtP8@BYow(yT6VCOs$zFR>xI}Pm zfA^X-h`jh(OiyUQo0~Ub=FCOh3t5M&u35y`m&-AR5rKMWZmZyQVO_!wWK3ETj%ri6-3LbQau z_4tyOD6dcJ?%&$bh|;V{H=E41lN}Y_#{TuP-hFzF;@s(IKeH7kawU#s30Zf^_ z5Yy9=Y|$vrK7b9o4^h_oWAWk(QCCA3UYb3V(k7VA%*xo)#m(LfALZ@oj;b=c;>RU` z5oFNOSc#)W4VXD~{9t*fob+@e=U6eLYmeolKC@9eIcXGUvWyr}$LJs2$=}{kiTvtz zOd2=Zyxv+@j`F5{j2)eDN^xg<j4^PZvgzl6CN4PH0v-(YaWof{c z<4_PB^pTX5Wb)|Q(LNJeq;<)Cr8l;6g7rF4i-IP)vkBvX2&G%Crfl zto)1&#=e{ghQ%`}n@(BDV@T^F?+=k$>npHr&jC!DIS=99y;#3_C&o{k1Gipo*NIL+ zkk`ot=N;OPnt@2nn>yx{+Nz7QQP23OX~|skX>Y^ZD_5eO<2h1rxQFzN->2Ul~pM=65J;Qw0MkzK}(@LoswbO zrt+Q7o$DL!+~(C$!d8|x@p094z9;AHAkMIA3=7w4lWpHgV$C*InyKwP2@37m(mth$ z6DOJ%b**W06wPg3jOVw1{Yvx(B*L$J6LuFel6OA?4u_3GS5XEs>lqm$fVX4=x) zXo?!&~s{C*Hv0ue^j1_H1oI23~tT z^CUsmSX+VI+#L9G>qA3L9VT)H+R1*Yt0}?Zo$q7gzC3=Or4`9Ev*czK;<6W%=04cKD(eg>C)__NJ!Iph}rGM%33a@(n-TQ^S14)fZvb?Acr&YDWjdEbZLB z3khV}+tYXQGaYdZGFuH7&Tz{Z+HKZF7h#~O0=p08Q21ZOuSgW*KvofE&zp;q>_ZG! z=7ZTYCvjHVhll_CFucN|ux9ISgi%9ybP*q&?1&`7Al%PB z^Ek#`{_pVGTaA9ta7>>(*387!(CnQXaIiClf-Dx*1%-HL{Xu;7Yu94e%BOMBtf{8I z)Hh0ETr%0oI;4KI{b?Sa;g3ES^B4=}oYc1|f0$E48Qc-+KIl~u~W_!%>qd=?)c0M4+F1)KPmlz{(BIl~tIG2GNT zqs66j@fxEBXKas6CkZk=ln~RPwh~Y7_Yz_X9Bh+jY>KqdMyBq;_;_P9xpaSk9Ex5NQ@e8*`?2^vqefIOip)Fak7Zo-~!lQ9JabS%`O-<%DMEoL}u1 zBNQ=M1}F{3nTU06lRg)*d&4U9x0PTkomwWlc;ezO-i5jIrensm={U*=+-o*hayG>P z%aMu39BAKl8}Q&hy9)GpQBw``L3(;VeCVyUX8AJIw^3=>y%ptE^@yJ`8VQqUW73%Y zG(WIzdJf5CPv&p{}VZM4l1qfVxZOy zxR2qn{_CE*2Ep#-AWvdQtT&&11oiy^DDU;f?U$V}akz69Ei;`GyAhQorReOfMgU`c zTD?>KA(N#vX9+9~X3@Cl+a~8e)4le(3jFPle?&)BHX7Zc;SvyyZ{2zo%}rOKp{@oG z{`Pk$D=J1uzb`@~PDImirK!5Tu@$9d)d-`5Q(0aCKLz57?v6q{{NzrgCI(^ib}A^O zb2oadU2w@FnwT66+rYv$RL}y_(oxMX5F{EZtj*hxKm7e2a91XL7*4E}F-8|BMPh&E zK6?1}@>3=BAnxJJk72FqIb+T{bP$I#@-R2T6K`x>PisR6ii#`I>QRT^-2VVBV@%HF z%U5%qCr2SdSe7PEcBdL%?oLOd-V39){->pS1W?zdk< zUO^|W|K>N~(wK{vxW7r?0{qLb{|8GhyA`8Tk{u{zn*w4I_=SaI`1>1MFeYIpl13#X zEZAYX6`njqEKKUZE{2pUD=X#xQ}&t|`0+lIK+sQprZFr9WN2SGD&%V{N57%ZeSH0m zl}1XhkADE2-5oO<(TfMocESASp56)6hcJ0m;-gcNo(*NLx+gl4kg$9}FN#MQ^CGwN zJpK5eFc6%Ach|1Lt@r$dTZ>o^O^kY1J%4obyI8Ta68HTi85LD^j8huP@MOKHtf)h1 zWE4ZdQQ0I-MMXuJWrb4!JBJ(Abbb!6ocCEz5@bTE2u4SBf;ORP@Jo;lP1;MQh!V1u zkDGA;o_+3KxFpU&npY#HF1iL)TVKKcs#-*Hak908Ur%kQWQ6ZFnp$RIPKpnz2O`i> zlEM9GnOutqLO9pc%v#QH)H9@V2@etLP=d1A%zd`ugeY-r1{|t|D4)s8qbtpeo}8KW zb#$SN493@kj8RlROj7;&sXUnxg|jmy4Zv|T=HZ4LuR;^;=w2K&M-LuB+x&4@#TnTE zZQil*N!(<(2$z3;6apOM+!V>MhDaJW7K>+HiEzJO{N?dC$rSm4OES9azI-og_dJiv zdIlIxj6-BXG6ETFR_$)3cG$`Fr;d&mnrPa{7dUg|dQpH+7;e4c795D)fTZLo9Llan zZ6o*Y4TR!LH{Fgu{AC$pV?t?qnA^|fG6fe(Imq)(kPlVvkUSNf58Gw8P|b=s(jQimR)*m)=e<@?`)XZ&p3edjFvzaRdbreTIdql>RifgzFHV>ll19P$~*j-V(% zmyb>evR=9>H@7GVt2cW4-D&EYhFG?zU~3h>WY9+8b>frl(wwENiN-C{(fM%6BOnx4 z-||KD9NU6dH|C*-q1rMT-!Q1|DAw&S;1-eqj7yt{OBXFhVnXzZA{go?AUX=uXl}pa zn$P2%mzJTa%N_L<#qi|p;HK;6;s5>q38W?^Q8@|X2K;ywil(?;s+j>R_#rq!ADtlVEA$igQESVmM(M*HpRKE#@3?yTV#?$+w9)22^YW|Fl(!r2uHS(EfH*87L-z@aHRd>PPggRN zY6^V{ptg2yI`72TDYI#gh@#1_7j^uAXm~h<%aIW3aEQ#JOqd~g5dm}C>nUPF-@aoFd2uPT~ zFg3x*E^fzInmOY6EhGk4Cv%(4HIaI}^!mGqO-R9YH{XWH-Wn8Ac%(6(pF5f8xS8;1 zuI8jX7<2g@vSaz2X|rA9=>eLT&$YYQcz))GVUIk#u=U*)C~kAZ;sulNKEKrz#4f6< z@4%94Z@`Qw52TlMA&d*1t*r{k+Kn!*F}2p#qpGo)+c;7g`NfZ>oL00^@o20o!j|{9 z<49&cm97Mu$1b3`D$0Bj!Kbqgk+Ctxc|e-Hln!b2>UW)67imiiqA!~o=~*^q?o0%` z51`961WPVT;~Lr1IGA0CC0AZet=^MsE*F?jV6;=v*VZ?fv7OM~)C6|+4UM7@=7$;SFg0n$WUPGUMN|=&3oe+Atn3oR#U^3gm^c&3J(kfU z#!Vc9*IrykP8!V5mdwMASI)-nt-Fvob{fXSv%Nmym`dd(zq|(X7A~R5xd;vX)JZZG zqn652ngo53#?LP0a?evoLn+?dv;(P=W^?vbXq;MVE9#LnX(EFaUxfo(HXt%?6gt|d zuu#eCU#?8&|JLBqk?f;rtnh^6f@& z+!zzdU45o;Wz9^QMO#Hg{U=3R<6gW==Ngyd6B?@@$IsR$8WCTx@aSA)-ohXrpmV{% zl`r)2W1e9_-rRS!7R_{-Ly^n(-XJEiJf8`UjOgAkAWxg z1Ofxbi3XnDefQ3tdgh!nXHMCJyuxzYq=n$7n{R|Ky<;nBA!$rxexL;;5rP(##zqT9 z*8&!4b&A-josyL&(9M-0Y*s-I{%9P9Q0>z&%@d9sK7cl=*D~l2GN~mL=sjZNd@j2> z&-$)Z(#T)A(pVV#XH7aUCFhrRrG2_keRY*oF3LM)H7F!12{U|ZfvFG9y@^Q z=1vQ4r!h=PWYD>tw<*JXi#a52vgS+*W?H-2nF%2ahv=+YcuI4pb*yzK=K5+XGN|vW zON_K&N9|HOg$rb&qq>DN#VkpxC4%kGa902CXTPSHH3@AMrI?kOiNm}1qlxEn3+K#) zOZ+U%@NdMantmL~I!NUmS2CVXNShWw=BO26A(3dTt)s}^1(VZP;qE(T(XiVFw`Qyy zeG3<59>hF8Et>B_yOIO*kccc+hjf{pF^p1nv^~8Be+%iJ01L4^D=NS@%bE$`Ra}EUt_i zzjVb4^V9CzHrvv0ynqg^U4FIa+?>gakdm1*^KJiv?ui-ET6FYWd3A0~xg|rm*x*lf zD6hVi#(K|s$Uj>5qv6DqAp$36TR2nKB6KQtz}X95p?}%Z@+$ZQ-cHTZ0L;l`C>~0U zg8Y0fN5MQ{M_h(8mMoczR@#vH=uD5HWNPc`5kX1DP**GcD|XU>1Os7?gNT{-{;ySwXJjl~ zM3EDL;|hyFbGloRoS0x)nw#oPd-Z$dH7sCB zIWw9pf&09Cww^dr8nG`=3_wXqiFL+!HMv96uZiyqkAUVz+^9HtgRu05 zu0`CmlNRF9Zd;ND!MlCF3zt6e^lFU2#pX=-$v)YyKl}Uk*V0bT-oFtq?aDz6wRZ3S z&^TbsKe|r@j5!7N! zdmoM-$)cBxUZl)h%x$s;@XC&o0US#;m1jKxaT)mhzbs>D^L@y#?87YDgG^41Mz3{n zZbMiCD#MXGYK?5pJgHzn)OJxou^+(EW$Bp+yX55(b6hCz=yxZ6U%e3!Lm^Sr==son z&6n;=>r9NCy(Z(;Ytcl>7aM`G=1gl@%%Y=YaKq?%R$i6Y+}3CXk)1z#3U*MFIOh}< zE2d|nKJNqr!bZS9K8(17A!`_6S(2L3N##0XawMs7lx*#=Nsr9NKp|KRE;?7%89Yfs zXJ75Pen>;wQ4N=NPYj*f@orCIJnbc3BM6xWRRgE(v51&{ON-Z^^)4A&maw|m))|A_B8#7PhEhdDYkPI5ivbi zGI=l58ro}9L+ukZq;;d_n>{F<|CXcj3}7m^#!%e<*~P|oXc6hRyi>?qhH4N%i`!y$ zD@p8OiEF9U(Myd(CA}v@Z~L=D;|W8YoaRB#Y~DR=eYbi4u(iV`O5q~l&O_~1dGTFHgYwCx*QYfkYP^~1m#yLWc%)h7i)PIFglHsrFmnRUFufFM?852|1Sl@a_^WrFJ%+%h|N$=?6C|S=~UJy-& zf*2j+)v`9+fA8J+?stBH8}IuVRwlaQrK87rzQ^}%|IaICtg^M<#RS>+O>m^oKz}dV zy8Fr8GBi~mmE?K`5lHP$r98n9y}K_?~bTLu*Ozc_s(3O*QjycP#J2ch_0nSpNy#j-D4mn_Q>>^RD= z$mF%W?}n|9q^zE z_ArrxI;gVw|B58jPJL^T4Uk(~ca0twieWbFfm{=)kF71X#^~DISL1ZojoNhPT1!FC z?UUZo0upi8IGLn&i11qkfHyVB5-C_a)-!cCR25;%Te~r7`U1?IG0A$hn_71svCbnb9_H zy@M19(;ExzPg?1hEr5%qvWzxNfsqLDC-71Ur=qHcT8GIpGqX|`In=gpXGBHHWtc6M z6co@?h&v6#W8lj;ZAxbB%$QsE_(#RmR#nnwFplO6&ggDyKvjJwk|re+n7Zi8t^)B1 z@ic^QMi>=lgnCq#lE$|rCmSBLor|VhFeUR$*Nt`6@MJUsANIYowH`Tn#n#zI61D## zLv4QOM$eJnGijLPmn&`A=~FmoZB}4QwcoxD<<(qj?nKCBFKIYE&Iq<|+K8qe58Qm~ zD)`duLF3#zz_?vJzfe;B*@t!@i=IiAuDlHiVGL!|#p{^$#R}XZx&@QY4$;s4Y)M9O?WAE@F zjy>JE6_u1DJT}1!V^mT|9^LIlyr38zI;`vIWzb5%zSju z(H!d?<%x_=BJ9v8IX)0KmX_d!b#LO6U;F}!kM6>z_HfLcG8JB294d$Z&r7Brd&X7Q zQVJ6eu$Zqi?NR$JW}&AUfB4-R{M"-RekBN}|CWA)PM@S#Y1`?^;Vk+B?eQ|bMP zQsHZGh?R34I}<0#V^2H9-tIKhaV6tnPdLtN;HVpFuaarEu5EaVV@lh!(}kso zOG&ZdPmK1E2on|aL|E$?I%de#pW2pmP|!uOdr<@8qy1@n+J<spIgTTg94)iEt@oe7!6tvpJaq#oLS zkS3#Xzzz4@{a(zX(P}%5_Tp315E~tVC?3|6A-*C>4HxiAWGB&&uGKbu#4V5KqX`tC znX&}%x)vZ>oIk%uUyCRS2n3|6Q~lPsD2Sf!sXh8FKsMq9y(2A0F#;;Tt)>uP{nC%= zIw}IMt$BiWKpAK~wF%$+`OCQTj+GV=(S8Bn`_{M72tVZPegj!m!)Pkngy&w_iepq= zU%FtnwS!Z6PygZ(>?^83TV*yj?9Ic?%jV;k-~1A?Izq8vdOZI6==ZSha0OyrTJZf} zK0$-#Y%Ey31l~hU`00-x$J`rNo?WahRrx5Ts(nbXJ8G#W?&a2t@Bi=@s1gCBF|OB8 zCxM8FtMWLWcEvx#=Wbb>;LjN z1|y~+CfEo2Hou7HHXngYZw>ym=5^e7%T4ek!s#S3u4`l+%#j z+hZ7yKKv^r&b$G`o%QtaP8&Dc8n(AIV$YUWalFErhU(FH?(rYt#m#$gkTy(UB#4Kf zd>)7B<-BL88EsxPnUSd^l@qkn()etC;W2E^?ZE7`7wSC{OaCK5mS8I7C~msaU*tKFtiGcpNbgvuCCwIgSnq z=tO+1BwQf4u@M7WE^v3FotXNaoSbZ(x9a>(=dQ{tT;LxZioCsBF-ULoSqF9#*9>C) z8|zV6+CXGKfHnrotZOIEtk4hGHk$itlQty6-R4?2%=%3{IN05YXPETzC4cEOB0Hk4oU)AEAZmqUO`0*6brdsAyeBNm3MTO z3-6ikj<#Xi8}Xlf?lqPk!a&$meD8~&<(94v|Mk$fkk{FUq^V12>m$V))@GVYZY_?B zFwM6W6}eq>1@$KOGgi>*8v{|9zlRH;2Gf?MVgI2leBqn_54kV>8plfNu`-1VpWYwr zQ!hP16c^@U^M=Q`i}1&^nRC!Z@7e*LF{q>R%#PO&lTh@KK*r)k)@iI?`!sgu(8U#P z)MDuDw78-G6{l+PL5d1A>-RqR@5nySb0<(JBXdq2#X?2WBEa#2*cpV1XUFifLdm7#eP($gX~NJjG|7|^$Y zZCh=`tsQkV67InFAO0bH`Th^T^$-f{$h-}8p^u18{w=$?yV|+`FpZ7BLnpMp2y_26 ze*eT{==Vv)%(!qGwx5H`A&S&|xiij~J_9EYXQPd_ZyVRW0yi>5Akkg>=V$4iJpr`^ z$KVvP5I_A)Dt@|lAKtrcCe24chqv+E{lwFaR5?Z8A|`{VZEeHaCmzO;DvJ2Y1avl> zMr86-xY9M$=C#jb7mdv$5+>tlRz8v$D{3#bdIzYnw_@p19ND%9m2I>=yw#>dm_GkK zh@Do27hc&1_hobO{U3Y{Yku<^dR(W6m+gN?POlF>`soMAnA$kgD%$jU`bFV~Kl~0k z)+yfr~AH$V7&HL z0hY}Q#D=U&ESVF9T{I(zCi8cA>t<|m_rdB+I(c|=4+0m_?4mu7{$#hp$-NC7j5;uX z`R#Pg)`^`os*j8F#HKCVQJSBP7{-*VqzP3*LK0qj?l)-e2uHkU7q;)+f|a-32lr0e zhjQ)98MxDsByqNW*mvI|WTu1q7N?=bE@cmK7NUBZpnUpo(|sjz86qaiD?pVzw5x+e zfrgV*eB~f(J9#ciCMsDf1%lS#oqIC=E7L~vh9*PzL{QX5T}$!Aom*lhadT(p&AdXu z;y|z!=Df%N+Sv?t7vcoPZ7Giyj*@AE`8L_j@6q4pxlH7G=zU^npc}_%uw&p^EAw#8WU_!``H$L$EPNwX+k8$ugB zA~Z4VxHAdSx>w(@L~{qXZNTXP+Ottqb#(6@q$I^-9yPV(L0IM57z~{)*jlFF-SmxD z#@$`|yjzix9EgpFxaFU>goLb@o+zrh=>5=9dlD`SX5ywB0&slq4g|zbLv_gsWM?_! zsiz*tAHMf3OFNVy3*pMRL@{9zICi)dE@{R1?OzM<>977fe)nJ8F?uB6GoK=%K9l^& zsm`WD+et|&I9=IFw@x)Qf@O2h^pnyCiWy8}1!Em(ZP7WCFGU|5t{!(pQ{kwY<628` ztBY4WnSvfvR#nsI;4<8~Xe!q2Dz|FW+z9yz(MbJX*G6=%XXazt#))TdwA-f3}nQBKWhKaT)>^b-#dPuTiy7!ax73lC||bWfl2=8RPeH!0c1&APmz ze@xw`Q2REBNfutxxA2nMqUQrV7f;TZgSJN=$9#Ihan5=TfBxN*^sW+$xUe9uS8p6Y zyb1Xol?Y3kZQ+N(9)G&Zqw6&fUmBlJLupM1Vv^Gl73gi@+wu0#;ecGx{ zb656fbhdP%w>A&%f$@m)ZpEQ}M=A0S!fHAy&!cE~@vIc2#ra@U?l2Z)%qCO23rW!- zguwwi`JRTpHZpfDwK#tAIDL5rqrRqy+@muVa1HJ`*@S@FQcRzgg0j4m)Tceb)Du9OJhv*uO#|uL}l(bMG&sr0<`L*xU zc{?&qgb=s=jzcfVc1%gv%45W6@|Wmh#;yyx3~ABQ$)O8 zNWKRy76?%Jz_|~9c=#uHD=wO{`ADq1c?mrrBq6)#*VwUTFX-$Zt$ogDYigkPiupLY zYa4cLZ=hF<1@sL`9cFS6zTP(H&6-cc-3ulqV$rujHbRj0$;BrOci)_X?|<_ll;#~n zUr-9GJ-%vuZ-9omLRfBC=oOLqfKoa)2>eg7-ixqS<2c!u@CJ0i~_ z)_%hFY(@pXY1J+0DapaWRa)DaY(FT6Ykd7c$!ork)TQ3>!5rpb#tyx89%o-Jfm zkbparb9d?`G3!BiWE$eb8`0|-j0bODgy+^hi#63 z_$rF%_tKx&h>{Byt~pok0A1;iv%kHQPN&-}H(G{>xUvnU z`8)8v|Ep&p+69=NITx#Mx(V@4ZP-zqi)}-6{L8?)3Q5v8=t5WnzWaYagIjbek_d}# zBz{Wvb0%CNBBFURb7ntZ1}|xy8>x%^^DB8RhF)+w5(xJ`^wn5YNITvz zI-O>8fpa^^(JdI?ZyWw1>(U+n7N1JV1fyJg1)z+M#N9~XGNw#MS3^0Pdfgf1IEZFU zrS!}bkN%#HGa_G`*nf0SEr_Ag#@SgB$7&G<0;@W#1+U#%T3VX5LsJ3zEdyz}O7bDX z`{Vb%36Gh#AT_WL4Rq-0%V0T^d4^D3T7}%=Q)r|t{A6_pKJ~GCuw&?@3(GAsai4mnSDeg>d)NcWd0LPs!d!Bmi_lTXh z5&`|y=%gdp(2y9obyZPj+koOS8X2Mlr-wo@hiBWB2q(b}!Ok5AsZiiS=e7R0_kH&e zu(*I&m(JlNTGSY5cP6_z0jUVOlsM#v(j<+M#zQ+;<(IfBDTx4aMg*#S!<7Bk)HP9g z!X3R74TT2tP@jM<&7X5=m^+Iac+eQKmxr4Xks+w9siRx30PNqn6K&ibIMIeZbN(V8 z(9_M5H9vhE1KXK^jm+6flS5J`66ppiOn3)`S)7b~2@}h)KeX^CH|EKmtYU77jH})J zZxMG5fbNONH#Ig`-oUMeNd)Q1^OeSWI^+#vnG~JLJB9)T>bz>0Z5w9zmwJX`iH-_K z56?$Lm=sb)XIMf;HRQUFQDh;-Ftuv|!>W652-HtM|3G9P*@K359r%)1&{v^tKDYU&R>j|2=zn0Lxpst zNFW#zQZhSx!Iyn%qI{p8eHqq<9vT=LUT4DWkTv!uUspSoCfEj7A}lXP+8yG89&o1n zD~kG#o-F2I4%730nibu_rr}BP6ZdXvm++y+T}jdnF=PW2H8yZ(85zzXirnof{D)>l z=TlbS$P zl~q@KY6g;{14&R=8;#e!s2F3I)&ZWG=p>Uzp{S{)!)or{-Po$8)=sXe06saxm~u>n zXXM34bEP?x05KG30HgVwRlaQ(d|}~)kIr<+fH=6%~dzWNBD4rQdu6zErMwSvUtxucsop$dwDTw;3=cezfTkoho!Lbw9 zO*dWfdB`U!89v?9h)Hs0^;>|*GW5P?OYdsTg`agz1uZ^hq9Nbe+0;Te=SKn%0h1QD z4#Dk{-2LcT5D{|8v4hyUcQ5Md+mShE778kQaQCXI*zv|Ticf}dCw&3#K2n4^se$y2 zUxea^T zx#a;&jS05Y@3km|+%$1oI3i?5$wck2PZ~^%m~sIriI62GCXU$E+UK9RzV;&^1Sq7a z#iPZck2%NCA{G;(dvYx{k*<#s5c8oph>qq=yB#59&7qX8lt*h;bE$Q!H90cz42#-; z3eDikyw(~fL*ng4<97?;j?91l`?k_lzVLyVRN)4-L3mKt_V4IgZF(n@+9X0|m~ORO z{Wibf$+nHId-V8?es2F;V=F?YHLGi`*^w@)RG7Bqrt<<8B~iZ7Nkp!ZfaXRmlFcMy zAt{Tf4Riqcg;nILiGck^1 ztx-q!<;t!sXAcfkxKJS>6i>dm6Dw|7Wkr;4$Sfg`;BY=MEFPq|J|OnOBXztWX+ZRj!X}Qh_$N_XQOW+Wc%%?UX~`K7QVlK0GjK{ zv3>hK%8G)ha=RGi$Eh~j(1Hve7~1^Q)wfX`)Q;@@VtS<8OX-idqH zW&{NIf@}Nv&^(EliI8c53pTXt*7rnu=SN_yIn%spZEEgD@5t0@BXSzi1Fr3%&N@7? zW<717JkjkE4xipO6xG*I#hkWx6l**A&}&h90Om1r!mW4ROq)TQfxLY=TK`(xhLGCt z$n5i(YqixdQRd#;`2dbUalaOvI^J=fU#jXhn-V=$J2YnYYvBC1-uXLf_jr=&$9X$4 zy)2GYXF-PIX^~e`drjX09wiYsol|LRCoc;DVKKPx{txkqP3?3B?GiF2&*w9a8i@tv zn2D0pI$`pZ3~L|-5Xni2*85VrxR2r2rP(NDkMVYd1zHnh^2_Qxi05|dpgi9DG3c5GXJ_0OG#bs}7PGGfQXyt-$~^F-MlPKzL}%xu+H$;ZcU8=V|&9HeA^rwZk4pT*Qeo z|GNP$E;bH&F3%|f3MpSnrF_IZ^SRDNE$8Ec6<%viC|&aW==?G`8Yv##Sij{ozWkqy zv1!fU&_&yd#E1~K!xek>=2JRDG2z0m(PKZI1Dgqbo8Q89=XUv&*zi2kI@jbHH_B~d zqS?KR!nla&+eyOR*K^YRiq44Xyp&{V8rTDcsJ0fg3R0mWXhQySrmAlxaY5n=40YGS z>fy(vA!@kUgg536mGsU4pfm$bvR|O~p7QP6WAfU6>$%CJwkVn3_W3UNS_@2lH)Yy? zo9l~}t$fnCr3Prc^E+03f*nZ?w6n7>OY2By6K>RU$lAXPE+MfGp?fG>x#`@N0EaIuUWiUVg_B-I4-i4TmP^`M|KGap@p?=UC%W2y2%Vr8M3;&HJO@(fC_su`kv-BtzvW$(~LOhN;)M zKohRE7%9GQuV|z)6!}EVNdGvc8kS-Qhgs`dVWHW+uQzf;) zPGB05lrwjarwg)C$EeBEB3j zmqJhQACQUla`01WR)k5mwbh)+bIR@u+ znT|jFQqi%>WImw{3zXdzq z+>IFw$lBM@j6EA)rbc%Qq63|<=|mYmcISJo^SOGueap+wMF<_D-}RnF789fKyHZI+ zs;8|MukI?qop&yyt3i1oq1PR14mxS4$c=AB;ccR6eWa+v#$X@N$*a;*hHqk^^92lwTA|)0!lmeh;*;Tl4s6`E1J#w)C@dj2N&}OVyEbC?u{?Ou`^UBr5-=J^ z-?Mxn4l#;CW5;gXu#`46R1UHR?do>rij=P1mzY2$jg7`cI}l5&j%z9;j%Fc+wCiJ3 zYek42sL#g3e=LO?5olIU4$7+P5KFHuZOv3tq5*w$oAKe+t7#L;c5(rO{WP%1v(Gz zK~`=Q4IkvfYV7k%)hB$VI&|$g*^V7Fh7x=0j9mPHXqMV&CARB~DVy!L-CsxLntJWB zoxL>AZ0(}Ng(0REFJD1(jar;wMDxbRE=)=Fr@4hcW~8OiOU_BS`9~pte>N80yBzti zZ9)Btd5oGZN4;;9wv?m1nws26f#}RB zr6G0(y?CVI*4uAH!$x|Eac;&he)S8?UqJ64lrC&>+lssI{|Kgpdr|VT7sUe!m{0So z7oL3)vsbMo{1&2#c8T*A&<2%m`iz$E%33v8ldN@N%(`rOujJaxVkdCZsyVG9{ZD^LqYA0<8SXXN0HPOAU5 z(%7+%wm%;9h(UKnX{qsaK-lW9o2Ri ze!KP!G}G9-pDx1u{k`d#gV*#5qcSxP?}o83@UL%4DGVdW##=K-|oGFvqhNo3iRLC1WY(%u2+In|MDV4WYCVwDsRM8)gjjEqK!|P;hAO+j3pG zzouOCt&(+Z|JzY*W<7|ZE2}DjJaq+yB+>wyo>A)hannsxkWa4{wT;cFre~VT@xIu| zK)=xmGZ5;lb3|K^&hge~+F;sc-$v6GeGl`jc8F#P$B!MtT_1QqUU}vzwEIlK7e8<( zHP4^N%e#-`f4{xbVxBxa-QYiBpo`Ra19QhQ9YZ?Cy` zq3`o{WCAoH*NOD@M?e#!g=LVKS;U$oUmDK#)|cV85C59p;U^(;dISxgov?%+q3h|& zC&X)jqNOtW#>;s74Y>v-sITTcP)J-mdWqAx0=b*=h93>q*F5=KdfW)2DF*KagwQyg znuPSM?oGEile$h|z#|aLXVCVKzTd!ei+(cIk@7Q1H$732fka?qaoN|PgO^Z+#zJGD zkC3houZ{RyeTa@pKyX|%T4<0wJuQ{S@sW&jo6W07rJci6>vkLNrA-aWok2 zEI)<%epk9N^P$rkGCA~$KoELYB#ng#nAU(k+Knk`4Y+g1K7ZaEOroOKjW^7uXx#-1 zZnzoyPaMLt^#3_&_A12C`MAyrlO~hlDW&HK8f`~Ti6`2i)8G!9w| z&h$I^;g5XW(v%F8Z7w~)bkK0!-_M)O%?!c|rC=1jRUSTu%o{>6IVIi_%}EW$D&h)s z%)&=3%!`p0TnFm$yT|{4Xe#V&c=>tETy-ag>PqmJ7hl8Tg$wa@`adns&B2W18|kPa zfFi&Ic=YCAu!atpBYfzQ<1h+_z472jQc;?{2Os+Q=MYPUnb)?GF`+%MA3Yb9QdIm# zO#uGo(;vWrZQJP6aW3wd(t|b6(|&kP2Hov-aJOmONn35Zj6PZm&QEq0k`=)OFU$TUKWls)7} zXKFe#kVr>I!%XB1xy&sQq_vnS-Vs7_*kzTOpV6GC>dxC z2*0S`+Mx{auuod85_fermf_E9sQ}X2ht(hYD5g&eCr*;LA)zW8gJ9orF$l)M*C>{V zSZd6a)DDRe&w7bCGj>{Y8bp)NzRU|_YE*LWJnrDu_Rjy!ACIVupGzXd!V@jpx>Vwv(@Q%E$$Ssy|kzmpC zJfnj3n>VCcY29Nx^jp__$g(xgyyPD#>2PnwXQCzCMGkagZ&584PEECJga;@Z);vpe z+s`tD0|on9+iH)-N^@#IhibxwQc_ZqRXvJ}i_eahI;H{z6z5b%FI3F6d!|WIkWaZq zQX8*DGJ`8ZCPbu3A8%57g^X2(0X$8RklR065(6XvG<{WnMa&Eb{*Tt*vHGL_YtA+I zX3q7kbtUAd=l@Jeh*N9Ez=irQm=J83@v$Ed5twed8gp`|Ls>b8QE2s~6!R!KkCVvEa~X%bi+VV?CWR_|pHMP0d^N>dab6rZ2-n+9aNR@?ve5 z3_(yI#!JWy5w|PmvM-H&?|2K)_=t#V9MulNrD92*KlbPE_|DH`tJM(@F&b+uv>WyE^{1OUJLL=e zm&b8!kfn&zaBnkxx^BY9KXM1wKKpkpSv&_WexYzWeHbkan=@xdI-}@xFsNxGs+(Gg zXc;ajE(M0i|?fTF=ehfzkS$OD}%aP^@>U7pdkG7^B# zKpT&0!?0{doTaX>9+`4&y&K{rlSWA!ktl&eS%Vv96{|+#=bgMu$M9Gdgz%y zknZ%TSi@$UGR^nsdd=^#dU&ztW4-rw@7vd_YvJ_keS@NQ+P8Z=V=!Vzrb&`~Qrl1M z%C5Hd&v+U*k!NBACPrXl1jai8!eNHk=pA{8iDc}o?|e7P(tPyAZuBrJb9zz;gOzq6 zr=WykKqkY>kE-QVYH*?Fl>{1Px7C!PqRk0Y5+cqjBB(t3vi1Ajm@bt_yc_yBf{>|$ z+SX}Trh`*Qa{hNirzYAsF#;1K@Xt8{qY0Tc3a*}*tiX>{*`K}mMk*KBT%q{|J0T`9 znT-26AE3g4DkD5J5^2;z=%Zvx>Igef19N2aQDJ|;~gi5DlhkE=WQ6Qxg#z{Ch#xe?I$k5Mr<2>i;Gey*em zym)Rbu9vIx2$^g!q_JoS+ISmkjOBE$Chz95!8q$BdAx;OLOvPp+3Y^({)o07#v8L0 z_JKs$Q5x;dnUvZxmQ>qiWcqFhjp3+Y|ETvg$CgVc8cr(QiRH}Ik#`TyqXlowH{N7< z;I~}Li(5YfKYE#EjqMTKR*&+?EBL#`KzqDn@@~&3LMHq*I%$2oF=(#vns9)ttKyiA zv=7rewx|o|#EhfMvHv}C$7la!>}!=T*iy0?dE2hX(nXNd1eqgTO`<$@YsdG*Hns{& zW7FuAC|2#&ech8G`n5nx-tZI~uESjM1T&Em?%Jyu-*XsKZP; ziHv2eA0Z=!=U@*lFBSp<)umnEsx=f6E)c3*n)r_%L2tw-IiUNx1KQ??VU!vC8hK zr?npYPnKc!f=qZ4>GTtZh6$@GYk(@+4UKJRZK#H`epU_YMG(KjoJukexxgb3kyh^cAUSmQHRd&hHMgtnux2J2sc6-1*} zK;!q`b1$NTe9%}`gwl2=%;ni+H+{-p?KNQ;ihc2mU;K_~xCo3yi#jJ8zXu9(s>5A) z=BYKvShNJMJ@ZF6d&eRnArgfr4L|LKF+mR*fdT2K}g7Q>ys%$x>VuyxNNgoa0=xv~g*5A4N& zt1n)9@=-K-gab`wIGR_Af#y;?zIFqW;^Pqz6o`|%cOb9486g24IJ$Q~@=D4P6Bln0 zw}5~EOKf2PW4vvi$ags-pn!`mSo6bgV_%gkR?dmRe}C~Ch@G_z9hKQQLeKHhp#eB~ z_$W@~oMJeNO8ow*moa136l~wN6&=H#2=jBrj%^!JOGl>ubToTt-%iwY4AG}t2oc3F zo_*|5BrUrOUTr04a%S8&Ix{|S{1gKC-iFPGkVfO9UG&oL6B>iT_8M$_eFr*Q>+t($ zUm#2*TJUn3k~bj4Sb%ebUamg?=pm z`^!JTihDnV6R$pnr`G3V)$*x$W8)?|v<-(hx(GL$ux;yZBr>Y~(F42CT%&<0o|mh5C{_oUUtyw{s_+-?|g+P3;Jej3$FQa$YV}?xj9^ z_~D1YdmbSZ=P7@A(q0^Yr|Fx~FNgq>i_?s)Q{UZ-nXv&D^4M~y(BghimQ>Q~c_r5T z`7d-oLqgW!hUuws+?9=g>#4~I4hhAv9b3@tpN99}wH!%tk=U_g8@BD)hZq7ybLmO^ zed8{M43%rIMD3TBs+Un1Wj#%Rkyb7wC-D{$A`Pv3kk z6{zbWywnxrcwPZ^9LPZsI&qBQAY47Y5$wePo;i8gx8n#J>dMj3$1o`SHsj#o9Gqf+ z#^d|9A|!PV;zAhNoW2it6Jc~a1tK}v6@Pi*6|~ltBEPyF?%cg^-?5p@9P{iygp-7$ zz;H59g{K(!k>V@v)Cx}#8I`snz_}K$ZQG5kf@*lt8$?yV5B&p1UlLqj&InDsV;g~s z5;E?{+9)k5FD-(Tr!OjM>)^}C@x>>O(1S-5_LG<$Jdq10GS$uHr*Z0JE-IQ^v3u8B zNT0g|0Sq_dh}RY#7%w4n<_@d2@B|85J@MfW-iE2^83^+lLT-K@8t7O1*rDxk^9e=v zv7L-JcMwCqLC8IF3{CV^I?z*(J;(FW-B^q4tRhs@)SMNLHoVqzJ|H$IZ_jard5 zb3R4cj1IsM5YZt4I9*Cn4R_vM4Q{(<2(2e>3yW6kA7>pt_Y5V$`X z@Rr70lu#nI{pG)6>)u?xK4jVLI(zsdW8N(I5F7XQyC8MyY=rx|p_PFvby_Sgf)aiWG6Q>Wl_E{l$f}>+FeR7KB z0!+KND^=&{a@0R-NA`s;eBnF#p(GnJHBSDxF2${i4kdl*?xm-%6APE$2+x6TM5oPQ z6x4bQc?ILd1GMmupxCIRn+Lv5{csP6KzI}*4)+Ye z+b;r(7tcj5gT7UEc;fbzOX#gW071U=nHLm^K!%l{*pZEMlCDTLG7j9ecQdSs!rZ&j z!}zSURKzpdc6s(r6g4?xHG}-Qxp|Qr^nsfNmaQ6*G2N{n@Mwd>Sl*Cv^dvGeZ z6nB02K@zue1P}=$*H)!0JON2jwN-go~85bV~8y0%^{T(l7Wobx#|V;Fa- z3Ym*mU_bJ9%}RVA*-wtciwgrgQEH&EXWh?B)(B(v?dfm zt_UDpv=HGc9fb(FIT9_31s&{X95lahM8)_bb>=(-`vvoS(;FLJ--c;RZo`dplJNIe zUdK>CEbdypoJ?{FlBQ-Lb83>MY~iR8s!tv=gfA~DTBKr-mwyOCJbUoUhRtZBbm7*U zZy>wl%qR&7C_Qxy$Foi$b>0ndX)44{N)WFO5sDs&>DnGOHLeccgt2|m|J=V>LAfj2~zCf zfjGsL;!dQwql3#!O#)PfO>b&ywhrIrrP@iFJuFiP^=hvUcU7m=A#p?;Y1Jv9(>LFhk?W<8iAtMDmoowq-RO{5;Y<|nWW@Yf z^Chh)A{5U3nH6PKBk_3tv0W4~??7O1B0l)w`{Cn8Sm12y5MPRqmOnQte<=LC1qWJ@ ze17iQ1{W6iTBX_`#lVl+W#1kG3=irlswM%p6q_!m!xQgZ@(5_hB3xxu??=qZnbL$C zBvrArmWOB^#&s=t(Hd8NPNjYlM+k@5jym*P3Ke4|5e9{p@%Im~B851rcl5iij5DTi zMN&W$K9sVAoAV%E{relpT)qnNA>P=${$<3^SwVMM{tR=%hUvfX6wms48cXopb8FEw z5XvB!_hAx`JOuw2N;(&l;-31`MLag1c3!AF$IqO&p14*yc1|1<&4sQN8b%DArFqQp zx*AD%J2f>`-2)6E)3qK*v}i&i=-%~|Y=CDbPt7;iSGScT>%F>lO_cujN5F;1qNlqH zZeHG$JW^F&*y_A=?cnFUswZw-u@SiZwfXku-w=hjyVI~Q$1(-7VD)@>wFqE;FIj8u z1l`5ljgL57{`g$6DY_~JsbAU=Pnj~s7RJSXB1FU_R@4rrvr`oOsRPUh!%yD zyw_;sn5f48%mX&j_lXgh7=eiqm>7ZUZv?af({Yp12tp>guTl0;G-O9X@h+u1HcNSh zW#>7D&O0ar7Tk^nyQW-=keN)nDP;zQa?x(=?I<=#;i9sn1b*Ss@b_>+@u>ntB__d} z7W6v2)S;?8ELex+4hYO84;I@#Kn0S+`}d-yql?-;K?n~Dg%?Aa3yru^(=jwuQLoR* zp4D$DaCp!SNLyzgLPCSl*VTr$?m>j{S|h5qN=ZP6#mcXNHp(z&5HF>zLSiaQZBkk1 zxp3h#J$FQO$5W3Ezcqh40Kc5}=^XhQ1yzdEef9iwoxXBX~NY%=3$MD-pX zo+MySw6ocS?80iyUAzKQC&h@1LUUCG25HP68YClJ+xoB+msCIJw6~X1g?&o7UL z*MwD>KlPtsr1b81k`!kMM3)Rl+Bx+SW<^)dCe0I>xkGz))6}4cI643e7R-Uamn*8u zE6~9)2n>mWFSW+SbUK1vbI(%0|NQ4a{~c4fIxS0iRVqNa+~nr&g!Rup4ZnnGi14Qt zS$?jiO4?Xij@F(*garDcr1%uNhuz`t?dhK{v z9Yy)+ax`{%Vpsh!!|fLjFRix;D?Rhi~;!A0_qQe5@O1 z{%B!q&eV22cXjtb;gPNQ^jCj^6?fc)g1wtiR^CTOD+2wUO{l1AwzO~M$>VfoE&OO! z($-Xuvf2jpcekOwr5B;W0jMo0qKh-SbMtmbZA~TZ4|~vAorAS6@4y@`NGB2#jk`W( zPL6F|k7r)pk9irB@ch$H)9u!5dUI$)&FKn8D-NcMtQwjD^wIRg8;x`zP+m(7U3#i{ z_=)E*W6n%e6rIA5yB7{@d=5GF18}3UcqF}*CA8)7pyvk<3%1l} zArRAl`?0wmt_AnK?JdYHu0SMBV%#Xb5rURRsm;xpwBd9u-Dt0=+CJC9@jyqQ8q4y%0Rkw?Be zLbRw{B4XkoRiQx;4&NTvO{pl8b8s3&d3gg$Prr!#Q_WoX!$?kwr^R;}hNy+}ub=u4 zB!^$!6YEVICAz%oZ9@;aJrDnA8ct3_WMm|&tE(-9KDr5G{k9elD~XAX!sgeX z!jzTwp|`ml+jbNqJw1g0*hQNtf9%`30lTvs@zt+=f#713|Bh9rqx%AysHiAZl$CL; z^XUVv4*`s=lpGh$>^AYL^5`R^VA`d!#JmIt2h+AC+IrqxUk4}lUr4pCrX1dZk?`}f z?KJeheNs7AS@t)t!F5AJg9Wcvf7k}oF2S!Bu-YWfHY9|eIVvly=Ptv2*thQ_Rxe+O z9dGSJDqWIw(GO>7&OsbHa1#A=VdWDTgYLSM7;yGSQu~xG_3$OpPfCtNc}*=DCi;40|D`P{BBn*$+*F4n#|v=(r~eH%&Q69$ ze+&IRuAv*B7ObShfa=;x?8_-681`b`?D@z(xPu1Xfrw3>godUXoH~2}2lpOA&yXuT zU8#^2PU6(;iM;G=bdot7-n$F!Eo8pvUJ2a&efIO8g&Vz;$i14zpstSdIcnan!4zGz z3UT?}&9!tTcZ^aLFBB9NAURu!r^T^yyPE&?^%S+K+nppqscYBs7f3`=ZTy zM>ELGsD+04r%x52qNN|1NuK!KW532j|MM-{QXYa&bTS%q51}(66V7yhRna<#$ziVe z$>T5LKOg!$ice-CDrp)LBkAygN#(WD?O=J{DMrAq#~rKYBAiYHa*rQEdD|csWv0_c zEtg)G+z7Yb7K7$N#?Or|+Tue!vHM6i-FMBz(Kr5#wx~t;*IO5IH#a_o6Rknf61Aa% zP7OvRK9iI|gfc8D42Rx)2}eqsP+v-BGMG}OjwV!A(J-8}LHp9NSbK|*83ZIC7ZKC9 zb_6y~d_=Y5{=xQH#BhiUTAV^7cQmf_pLg5+A42!>4Oq8*7vfT8ptq+6%^lrHA|W&F z7`yNdyCb-Ssy?Zt9t z(KE!(H|Y+GTk!Zqy1(L1NyJu2a&%dCO&R-=9Ompfi|EE>C#EGu;iVU!C%*B-;Zs!z z=*mW3^#Ep0WuQOqCard=yGSEE&>xL$-H4*ArC#>0 zt*rwgLB9Cg+Gnuj&VNB1jd?ZSBJ75NIelU)-YRv+S3db3Jo58L@QJT}on9~c36Npv z=gv*U-Nku`JJ>!%^WHm!B+Xn%bf~!zK{jnM&&-^O#cZNO(-Q?nNJ>dU9^C?k%$deT z*@lvmMg&h=h#L}tmo}at0$q+28qsdvSB#LTbS#}o|Bkiv5HehdBjgzCJbjShM`zSz zd=|{V1zsI_Xc=(j9Hvq|nqsmZ+dQfbw)(Xj9701wJw=0&*3OT-FBYzPA0~NLV?AA6 zb#wI;$QYyLp@MzJ`MRSo~X zV$}Bgqk}uP++A;y5cv_I=EJMK0C5=$B_pubi5xYjFTDXZjYqIIHv=yHop|)|Cy2wm zuw&m*L=iSS3J=36X)e8I4B&wWA0S4g81i}>2)p*2oiE-?OPh*&?p}%-8tDJ|smIaV z*^kcd?MO`whim6y>?VPCb#ubW#58z$4&$Xi{}IikF>RaP!k54L5d1i{raalcHIhL+ zT~>_&IuAHjbQ+{nc#+J*kz)sO%Zeq)%FSjxFWR~JL=YDoz%;s-I+>k=9h4-+`?D~K zu!Wm00hW~4w86ZmZ{b~UN+OcUtoizSV)L7&xbM@S$6n$_wKFaz3DbSz;KhwdADPCn z(uf_I3f5L$Npf{dyfxOF7rRg33m}z!@tG&Fljl_){ycvO@PxO-2En0Nb=%D-Au{of zOF>dZ04eVIiWnEGV#IT{-I--ioso_i)2GvyUKJg3hQXVLdJ6I3MUU3QW9;}`DTWzr ztH?9hzj;QsLf9PCHAtV|oimGVo!Sc)m z%NL|CMJc&-hWp|BR-?PGlukBfoO#K`pM61MKo8#t%$y}}-k$j5lTVe>3Q)rA&^2(We>CWMFXNkl4mHU!PI$Hm#z^4zfW-cR6x z+vel>Km8uHUBe{sVF*tQ!_nQx@CWXa{Sv0rQwQBqad#g^L^#AK!>(jH0s}qa*&mDr zt8aqGkppyd=7TAz$#4pAr;o-!GA3TgIdK>*JahH4Njy!}G;jrOyX#i`an186IPeAr z1LJY)@;Eg0d%?xs8?$d%f#b(>FytA6S<_O9rb*^JhY%j&gR1OORJpjJhv?gv=Xir` zS1!GlL?%qdB=-h9{EMFG%Wg`%2vEL)t4rb^ldMkL~<8<$Z8)dF9-nH%b(_?sSD9(eG*_|Z4Nj@Wt2QPbRw zC36yq{6a8LcLW7AA|{r^f(JhXKcYCxD&t)+I+B{S^W6S4#fT-fJ?I@GUJi~!v|A6H z3HLQsm1w5_&skAH2%wL~LHe6*C@(-*ayoIUi^ag(tMo}RC~fL2yywo_k+*#VB4Vav zVd5~>y?GFmrZ2DD*z7k=nDR7M>KDZKW0O#D3 zcAkS2;mg^#mv0!|&ZXjSPdtL|K~GH2NTFUs07~{BM{8Ff9T8t-M`k~tTKL+P2`LC6 zj81wkpd*H`I%B&ecISnmm&()EJBZsq@)@k+4#$$Ql0fpd?cMmhEUm3h5=%FpL3x}t z?lUFWYPIDb-2z9ySuisPL`35L4@UAFqm!;10&w>ow^^BOr7{eHFv+N-gLOBrK&-m? zHcJeo-Hhcag89_X*>f|kzR44b>=uL|-%iqyCZ?qkXfm<7p$=s&eVCc-M{aT^zVW&F zC@iceH{Xp`Dj(3J*4Z(=oI1&*@j%#>;)D})&y8!?UZ+}6>H+ur{X!a12BiZ^KwvH)6r^o8aH=f%yI)3{+CY&a=sW2YBFm93#P{Ts>{y@CKe_#E<#Q??5^u2fesq z3w)xIk)Gs-DfH7=c=Vv_bmW++8V&Ct~dF6nVuHnM*_$yorZxvyz!Pi?Dx=zS!=L{L5tm zg?23tiD-lv9HjxpUg9ptN!l`8Ox)~{Xff^=xkYz3asU+X2`74SvGs~8=FUv2#uo7# zRiF-VDS$yG9cc!HM!=WnF9xAn+Jf9QXe)f7WYZ=aL{(+AHOM-6KUapfzfx^>T!#7> z6BA<*ZV_*_(NQ~9zwHo|htd>VB_}7JJtG^<@n5K|dZvNap{jsN?GmDqCYyz^^jr;Q z(mY&FQu`*Sregn_Z{n@&Dt!85??vP3EIjpxwHPLFOrAC!^-X=aYtOC`2(ydQ!*AeAzkUV3|M|D@Kn5dAap$tP1sBJH><@ z11^Y(3~|WFnRl&uXMQQeTqtQiwOiCVRTU5J)gC3iZ|3?!@9UYRG0Sf){IT8}>%QKR zqKi2rGxd*Er=DAVV+OU)w9$Nz_1@dPuXQZuK=r82Ht{yyeQ^h&^}^xewL+&Tk8OQe z<`aCbB*h3xA*9g20<7gE#V!}Ftzr6Er;l#v5?ttno1aE1oGMjcmVtTCpX`ar$YP)YkbGj?Iw7I|%eD<)s1S+yMHa1%4 zT9Qy{Ty0vh97_(D?g=|-Y;5qx-^B5jSqP6hgj3ZH5mz162ydA&Jll*hE;MG6nj|G9 zp^Rtun%@hhv0&N$9eX&PHf8&fVfB`M*in6igP(BesFuEDI(mi|{mSrYcz7-7+SmkjPoCZ4a#IGJl zUGD%odwcNNFZ~yi!+b1`w1zQw4p#Qzo?Dj?DfL>!&^AGKk(^nE^H2|-{LSO2;?}dX zrwgC@!dHAe{m$CGQ`ne}?| zm_X@L+CJWTZRJWtd=3UR7fNcA)|mNi&tKbLbAej@4A@W&uT&Chs}IX@n6 zewAu<2%vl6o&8q;B!2i z*oNBEr?Bh!y$p2di_DZTbW)pU!(X4q@zNSByX`%wJh21auJQQr2X3}F71^PcT~y^bua?|djIX` zMuk`Evyhznt!s^iK0+M&Ev|ob(qKx%&z|6Gm#H1rg&dCB%CYS>Rkl7#5^srfl!lHw z&p=%MKYQ;1nCEev2|wt)_ey|7Veg%yNKsv~Y|D~tS+?UU+p*8df9KzE5}yGD2kNWdjScMAVC5Ih~9g@=XpO2@Zv)u*i^C7$M?m)TV`i>XLe_2 zXEX@;zZ6is?|T@0j^-irHZ(Li_s5)q_>V-SGUTbUwJHk!^vhicBfN0N~@snD$j_acRKy8F=9dKY*Jg?WKY#)Z4fb3UG}%~dAC7v-rwEz z>-%IuJ#N_M>S&nF$%2S*9Kk@C^ zsk?E|qJ^d_IMm1z=xGB$${ub4tvn*mGwGV;iD!O|^rZ{2Y_JkLPqkBZb1}BP`ZD^$ zGV#y@_u-k>k0B#zF4gQqsZekO+DZ>lLyKaojA-tZMphSEp(f7AaJ+}+%*w+H&pnB- zyfs)H)<6xeLp(zWLVaKc9{z(5;}^f7n*|d1`#!abPmk7&sC*k66rY(vB@G{B&&Bss0p84JnsmmOxQw8Z55gkg7kz4?Ar1g9hCBX zkvpF`%hn;EcbvRK7YB~+(I{x(iU?a!dyL>JZjfg&7ObuIRJ;a`23bi-2{JM=h6kSI zdAB}AC^T8rXIg|Qs4XJ4B7E*P>RmtK#T~CaYP)^c-+I@C_a>gIPsG5|>Z$VFxK@6_ zV3XIKR`I&NVc(Q?yr6U%gSN0#8iPsmQtyH}hSw!Tsx@ZnxSN5I~~>4)NtqTstX}6vMxWrry$5IKyjNRM&m+L3Rfyu zcv5=dQa>#wb&pN&3c3uhwknOAfvbF_5iE`+d$v)cKPj!rTSLzf99F(l*cAT}Tnc(> zoTx6fLqEl7OsZ~oI%D=0=RHQ<<+*n<0<^T6usl0_3K;w|tn&DQTYb>Y;ip&*eOQ=)0@Byd3l=>fA+?Tc-Ns2XLg~ zA{OSv;pFMlShHxBqk=t^a>c}2>ds;F?>D0}BnBV8_kN`FDu~)4rsl&*9>94df=4dm zoU`lQm+=mvBtuY8d&Oj8BEzx$^_Ow*SP?xqug8Yv)NJ&nA{o^}+FT1c<&nfDDk2oG zzO)%9PL*QW`r9xsIT$-mR^sNHR#Dg#G9 zk02`7LMShsAKbGSIg3}J`FtT72g0ymW&(EZKY_JtNDtatE$LM~)po(A`KfWUZ{I!| zm^kI^(8VMq722?2gEQ`gJ6q6ARH<;U;7h%R#tVn>r+@c<@cqB}5dzyTQpv1`*MIyF z5f+RpdefdYYZhv&%BU?HhWyM#YA_cdE^`J#ecDl8M}L8NIgWP;D^um#yPo#0cm@6K znNMVm&eA6#s-^L}MS8y90#^cdjr#q!mw5NKDEJjD(F zJBE=736kk+q6&fDp>Mz!fB2ohK`?Kb2M(m-d-M8uVK$Izz;n^raDha+5v!@`;@8uP zrj7xmXCxsviFa(s@!c1mwX2GV&&F52_!XK8I>-BE4`c4EWU7YmMH?@HF3e3Mm!=2R zx=Ng_Y{E^{9_--23-Q-#+5?psYiMjHzWSxF;aK5W-1>EW#ij7-M%xEwP6 zW|W;cjKjP?RMpUo6>DcxwKkb`@ov#=ccZfGEOOT0fX(!}-OhGzKR6rFwUsF1s_#^ zeldoTx<&MPKu?$^f?e^J*Bd_XJT{5M;Peyoxbx0C9YqYeEiwY2bjmB@AZ8|_p|~|` z);MW(3EP6;0E9q$zt5)@>dKYUI6Z@1yLJsTD&=tp{cUk7KZ@5MRN`G!VCI(Obu3fx~C1X?O!#8DC05xn}Ju;=qFk&CTkPLOk~57W~nF z{W9LtFpOw(Z!1J)4Wr7B>fX z(y?U+=ZE1)PtO9u2lJOK!zrr#*B}k|FP=wsHgeQpW6D#05K2!SL0do^&TRiZiu=USk**_vKXDM!5w-Ap!djd_xHJG#U z^SqDPo;+$|;=puoy zt0+OynHt=5+fr21%EZjHCj8@Xj^mqu`6o01T!JwG06+jqL_t(ha|&^hp7Sej_{79I zI56s3y11C&N}ZRWHL*vo7N`$~TH>lxZJy72czRy1puW_uPkpDKG^#Z2B+iy*p%{#= z4fqUnqvTvUqG_))nkz(&34x_EKT1BhIvv{8ssDz6b&pp?+28iGIE_bz?c29I^{LJ7 z@h%tyqcjZ_lwW^mlc*a5R-Doa=55=yIpa%d$78%o>xMx@`NHW#cy{X^dQ|@q&d^H3 z)7y^V)>}4V(~pdEPl~bs za;D-_Uwi<;zP((T1Gn&8T0thgI+_-vwz-?_pW%p;+-(_K(nyTv;B1=V+Wf|wsEtg- z>Xm_b{P9gGpLSXzY`60(X`Ki>DF885a+ z_dw&)XK;aka!LzUCiJw}*4gks{nI}=JG6%$ zddL}*N@K9P%Tv4)s3qFbP>%g2wcI_f!{GzFFk@a8@}p8QlV-2V>-Hg##~xKQ(UzKd zI~L@W;7Ll`ZdsC#bLC~+qy!>6HGOCyW`&ObG&t<5@ZtoXz30!Hk2LC1_>nvL@(yoh zWi`jZ&1kDDM?+f(ua&H!WZ)dqX3n9_UK*Y!pRnxKE|oQAMZQSp?C!`CkrFf z&0;*0NKC;}`3w<_krWt~n+`W>=%ZBj-N9ji%&&=WK@Cvn8o?M-1~I*UZ78yHGSGeQsB`zJmu7@w(ldAw!53K+saiD6B z(M-|sm;dNn$l=9c-kd_inIqVHp&K8&V?B3Ko!rGq3u^SZoTzT~x9U;ddN)|KLvsgx z6T{LD(Z-0<+IfXLt>R=6#TG(JCqm<%XiBegtSpJmijVI{TT?ZD^V9!8-pp96TeSp7 zw?9q0bLm((!_!Ze-d&&PontpR24DWvgE&*&i6ykRr#4ZaYSQ2hlRL2%17Q)=8YcW& zD5zZ)qG-I8l6hzD>)T|(4YM!pi=M5k$NCRHgwEnO@yaVZxY|y^qD2dE^5}2T&>4+* zzaSFKDunRZVA=9T*zyc5q)^#1KP{FbPR?_7u0L_7IbTtB8u58c@yX9F!uS5{dlaY6 zLmvCnmm(*3y?U2Q{<-1;GSj(O_VmX@?a-B?9-6h9D5!jA zH_rQ@NB`n`So4W*Aupf|fBm1^@P%)D8~r^V(e*_6ry8$%)Mx68Wy_X1nz=G}CaH-e z0IOH8c2wFm_B2*y4oycxlLeKjUk^7T_doPSO20BNJN+nnxtNRzW&cy-JF&qZkukJ% z6B&&}E|lVVS@}afMR@s@=ixhR5k9wODT-+cXYp*(EoXr_GVrW?!Jv2VU~xXAJ?Yeu z(84rh=1dVFWMpPL-OuWy}=Gge5LwqBCAfVXeJ$JrS^tR2v#({IZYq#$pPR>k2;fYclI$w*F za39?LK#sfmDZLAy>I3b>wsAMJbLURnc;k&8F)nd-{=|N?2BqRJzeCaUz8$D9FUF21 zcB7GY1Q+Kg@%*75&;I6Dyd+zVHN4Dz@%UTl4#>i19=vVTLdy+|>Qp~V?(f~78e`V? z`lg@M`85vRL1Iu_*jO1NDmpiF2aQqvERFjcr#E+8UD$WDi1y@ohFX6SZD|q6iVorB ze2F}ndK_k9a9LT>_)5%}gGDPnbvJQ5lcunAPw=i=aE~{Zt-Q;5s%({~r_l-JSD)%{ z(FxV1%iUR&2)y{xbF^C;hC6r_<`pV+Jx;}@8}FpSW|~9l@9M$K)J&ws_u&y<&|S|< z%;Dk3xEt%oy7@WI6%pQ$C4n74GKt!S&Clb1AKHzaWh=2{K@Q$HQNUeA?r^)U9fBn- zBNNX&|5F^^<%dPmzbW(wvltQ4Hmrd$;R@!MiMq{x*IFk zE<+l}-`yAdkU|@Q)sGf>n|XEu{3_(oR-~Ck>fnL@ee| zWY|Havg`$v0;s=++MCS9>w<-pt`Xl?&N(z7WANTfu`qm`>HDpNnr zFEQAvsw!UQPIMNHZkY70Ipxq#0m;0|V|Z43oM;wmX-qLsXQUGaQbv_A(ph3Y;^?C) zV;W6LU6vJ-yHt>c1+B0(=~Z4%PL4CMb+(}MCu3$pyw0M;U`(u|hKi`1J$sgx6P7sn z^|v=N1he93FbK~@JclE}N5%!~(=DGyayPAgP{u!A8Omhs7ZUB=U6|qwANE~OCq1|5 zZYJi==P)rvkkNT9_}$6IWn!Ze@DI0Ur2Ct-Nl(G#z{P_VZa^B%h&bA0EN7sn6Sceo(NR`{V<&k|mllsx zCobZ_Z+sV(ulxdMdqXiR&lg>_WD@>{pvnM(H86%JQIKYgTHqysYLLcUO{~#TBI~iI;PkBw!a1Q zsvB?fq#dF?YNvk6Yw5%}duS!(kH7nuPFi3l{>S%L4396RQxH5?5)6mK^$nF}<+`8l zIxODuTiupM?XY*}0<<(hy~e4S*XStH6dmEDWHR2PQtv5OIP@?h)vL0ld?Fqoej~ zncOl8cr`3NJ>41nT1hCV;i^L`;n}>vt43=O6&4mc?;<3cBuZzUWBHr{_)j3W$6Ld; z;>n07Eo#(rQ|Bh6`=mQ@-etJ|795)3)^>Lx!iDhS9h6@TSDp8E1?xEP`b0o98HH;< z5~j-XGuU>l47V&zN5%egyvh)VmmmKXPSy8f+1f$Gq@|*VGU^$*^AOElfN6rN+%B3I z`v^@Or3JU*$IooXx(A9^p-yj;flX>aI zW}cBIQqg$=~3ibx!h4H{aqsn|X;{!JXdz*3&ZvBsvQ~&FMnC@cT#6#j7uW{FMhprJe8I zd6iGW;w5&gnMF56Y*H~7qv@s5)&Rzt z58-Wg_gufvYCaZ`W`B^C@J_orT{%`aAs3Z-0IG z^LQ@?>=REs;cPWO@rh43$`fJ=_Dv?Dv`Q57k`|6M#4Qj6W z|C=cI^BBFg=u=q-=dDp%(pn!K_x=}R?IEiHw7{jMgc zJ~3MFpmGJf4H$_ka~H0~L%w0CqI;N6e_=gB{J0WoY@)@AR``d6*m93+8fDu>bL7lFAm zQyq=g?#61IoS}{isPiYD{}2wKVE)y}QSYJE`^Mc;m{QPVesB z->CEiw1J8T7F4FEJ~d!uyiWv!^7Z%i&^YV@eDk}1hVOreyAC>pjimHt0u(q^sXXCa zR(i^dkE16n207`8Gz@zHTY1f82G3-DT1rsaOA%~RD&5W$Aam|=#PwC6khTl&_~>Vl zpGqHkJSejDWM_e%x#(xsA&`L1#WyT-_P!P;f`GB_@kUS%nd=9c>1b_;5ceRE#; zkJ4DMHoNag**86{On2OsysI2*lk%%x8=Ho6i?{L(SN6C2Y0@xv+_ic)+9bGamu_@i zb5B8ZQ3`Yx)HZ8};oSXAqj{(+EZRx0el;4c4-O-<0#v9vQ44pZzmBTH_pLj*+e%uE%*%nFioJ_uS(&Ol50Jua3~5P+6dg>`hD zkwO-IwB6`=y_|myPQjzG_RKTS;J*9rbBfS6!5k5jjCE_%9I;0?uVUmcqO(f2 zM2E{dYW0cCp`lnV8hCyf7Uyx=$E>4*)uX2-vHP5KR6_ot@h)kB(i+jS{Fc`6ZDUyF zIXJZhuBYO)3s4#M(`Utd=Nb8XWV~CPJFlyF$KZAc?|gmt&;9~w^VcJmE0SKCdvgba z-^#GM2f5e@q34N(iF6Zl_&5rh8nEGG522_0IG&|nuf=m?aO6-at@YoDt#lN6m|Cxk z=S0x~X)Wev#E#m*8=UsEx~y(DJXiXzD+$&ola(PFqoAGrrP2#Nqj6$L2LEK`Tie9& zL@y=_N~>|Aa5=cJv{skZp|V6jb@n7eu6ZM=mBzIsUW!*6ET8*nFeq*+?X)^C=c%$S zO!Tfk@kqUtk}j8cJ{m-=(=LjSgL#Ik>nI-0L@q44J9)+`^Jt#?pl)1>_PXmBwIkC9 zb*#9lI(BqNQMf?wxsPml1M4^4ihV!YOyjCl107X@HN*2%dE%PVN>dQRwXJmrAyq&r zUMkS)D9Ki@HL?YZb+WsD_q)F9C&iNE$B#SW#QX2Re-!7p^kTqjj|Pv0f;V5n4}bb7 zt(wH*>8Nac>X!NV{VNA~@1_>_e&J8BnC>^OCKyhvEvjDwTKzO;(hl{dyFMET7AMB% z9aOfo7`aCE{&da$799F%p`t@!-NX9!x4-R_f0`F=tu4-Vik=ZBD=kY4&Xi#p!(Yd{ zTw;lbo@$$diK~aAormyfM9|_jZbd9CpYSh&s$ICdFVqkExznjEmFW(a$3$H2Z{F`p zt1>K)zFVBFZhLxs@b$m@KCSq-^Da&t&9OBT22V-CuRE`muQ=z&G2`pgheL-8D3Xo9 z@)b+5^QEVd!3D~q{5UjshhfF4If&!pXYR_SNNqfe%DO(Rr3YV~r4EnyGxaCIGt+w?s0Lcvh{r;I211}T4T^A9@K(c^Iwcr^T@m3 zCn|3$uw0Kc29NMK(9?zEykNa-?MfWkcMzG>Ch6%V|&s$uk#L^rIjEqAn{Ubg8>}$CHiw`1lOl~W7Z6=rt)NR@5#`s@U3zsdKDDY{ICs40wIB;Cv_9ohaCMJ>87i%5vvZ8pX?mkQ7Y> zi;jTe(g4>N7mDqxnH^wl!z6d z;Z=+%-XrbD`BTRcLw|rRWff$2Hz1TpHDYGo?Hj|2#KbfyRhd@o?hO63>T$>YU&I}k z(Lxa`m3iR60etqepLKRzmR-9wSx&H(uXbY^AX;tc^66c7-8EdlI>=V2D%0T7vyUsw ziGs|ah|ejV%CI(>JlCC1ZT27;Sg~S-v%(QBO#I+ZJLa7STiXsZIk+2W62#9 zr~cJbK~G~8_RZqO95e>CW3(|Lyvxdqo;D^dpPR5*oSyor4wa#&+IqP`^$8!EAD0`f zeU?vf8Z0W)pG1VqR5B^g;zF8%H0MFwdHO(;N9ouQ#*MT^W$0(P&^%taaG~?J)pf0& z8uK>yr&6ZcsQwY|FBPn>E+@V6*n)Dh@`ZaF7gH%;={4@$LAZAx8Mwbq^sas}Ix$h2 zcQW47FC0&#tphX&QGBY1$5y@wqxFictV|r+z5~9rVXK8y3u&A`&7{e;rmPgHOULU~ zhmi?^7DV8MJgt)5t4zf?=P7)uAa@?iYfq)scXgg7->tXa>iiTxT68qv?0mFBwF#~~ zT6wHrzutK&j|PLb&f3{&=ca1_R)4o|H@?*NCEV3{msLONIlFhZ!|2qxB9Qi-l`oS}?g)99Or=P*5@(kXomTl?A6F1s7_fzFhMkoxH$TA`b;7(_C>#2A>mEYYa!KgD;NfoRN z!6ZA2Zn3lSxa)DZ<5KVLx-XU1`@0C5J7}(nDO`)7Ijgd?5S7-kBrYmn@Y+xHxbZ~{ z^V`&GS6;P23%1GdXX9UsX3Yuh@HM9N8!y=0QF@gxNt7`i@ATHMYLi)A*MiSIE^KTF z4wWakmENQ!dRMTghlq~UWa*VxaJYj+(W7zb{yP4LFG3ja;Yz#OXsNYJP>

    zDbiN@LaGH#*n)zBF-W%W?xzhT0W2*^)V({p(IZ+Xpj2BK6OiU|cA{<%#NCC7GPSZl< zp;Vmc_1GtK4QkyT^5JgPtx9cWsDIQ}^_AMqKd4|KEldwl5)%-fM8Jk|!n9%qw(VD6 z8}YHSh6->%v^Xsu#+$sVTg1is#9*`bX>94c;L|t~;Tnd8i6$b}%BKs_MzmCq@`<47 zUBRAnD6^L)tp(*(5WX!at(9SM_Ox>BZ`I?5(c-82ypp_@M^E8OeW%~G3hEclPl*(5 z?s(4?d1)Zk=is0s5!L$xxYEAdp#IWWkX=F5>Bg<%b$MMh!s3nI?BBnCc!6PcD!u4{ z7R1(fDql=b`3z@DuXv4RjVCwrQoPb?;jizyH*0W+z8I6YIyH8bR&zpOiVF6fSMtx#KVO?ry`S(!Sl_t&fOk8iP;9qWDxtq081cp&_A&iHr5nE=mfb$i$?C zW;h!U-Z6|!OiUf7r;uSCtxnKyD#7w7twcpCO9ab3P*nC*L?ue6pC+FMtCgjJqyasZ zG6aXxYA~t{m8C(WGE}w&4VtSB`SX_|f4C4D*&Keq`WL~fcIYSZtBAJQ}Zd8tNpp~yeS7$4V zsG`r)QRLFfb#New(Gam$KPa6Ce{$E*LG|w*#L?n_f^e(;wzArqTWGa{%%-QEx|{)s z2=`p9SD&ao;{_24o!4#NyxAch~sW zYPUCG(Y$ak$b=K+d$$F(N&RxYf;V1Nk1toyTV8k!Z|yxoEz@Lt^xjWk{gOP6R}V8% zpUQB6mJoWE2ubI6-a%zcDx)2a&aE}x71Sm%P~GPg1F@iSEV1ynlD*CB?Cjxq%cFkR_w(n^J4{r4t}|bipOuw0W-+Dts&NuY z3;sX&)BlF(xi{l$pZO4)X$)QGjN>sf)n)Klz3=s>d!Dgz!+mM(a@wo-p$NOIJu06i z9(p>I+l?qOG20GnFu1>Y<(=?P?>z49y%D3Uo#?7VgL1OQO$gx72V0q{EN_@6%4=y= zx5Ny(V0*m|xV>S}K5uk)A5hxHT3p;*OT(Sdb0IlH+gU+yC+evciL~?Dhxnm51(h+=Lho zEUjQ@<(;mwMw<4aSXgkn(*y+30PnUPNL@~g<7cSJ+m?;#pFZbdOK*w0?L z28n?@N2mLfypf zg_Flkf86C8j+9r7Q#(Mrej|oy-!+-G?2KANtP0apkgXWgCOJ$AOf@n~PAgW`= zoA6f)faP}sVR2XTyjJC0Zr$n>?KWg$>+OO;lWU?~vHHv=yEM&W5;GCrw;elD8JOmhtx8(rbMc$V1zHDi`<-jxJ{++*@9K zS3QPjJypKdVNd(6^onx_m8G4SEneK;>|ObVV@)=toh+z4g-b~U#OS2%G001 zqX?LAs-J?z*}D@t6t8bem&M(Ytir2*%gV}z$C0~V^lpEvZ?)4B6VvWb;y^Jm`>r}P z-&B^)(M2nbu?jvh+B0X)jN1LGOyw5?eeIPO&=(MmmeLbAc=8;U%#0tNSMD)vZFxUE zN2EAc*DB3ZcNoLS)G0!`I?lanac7!-_YhVMW+|q;+XkNmHFXU&$XIg=<|omw)MHzb zotKUE%X0D7^PAD1G!M5gj>P6;r_f7ptoiZb2qFU`t8gaU$fWk1K?cfLv5!Q}p2=<# z+Md1xT{vCYj}0qyQFerhjFdx%h%_#|XV;tXr8SG$H?Ck=qt7|qW6JP3lHdJxW&3@}~0i-NyFFm+{}!ua;;06rTQ{=$kv(ZpW?KL6#fqPlP= zUV83%Ec@oeW0OwDTowkLUNFL;oazK)V($3MD)l{**xIM3y-yW%%X7K;rds}$rV~6; zxQL|>uhLha#6^nr7T>TDDS>Th?C7U=UMkznolSQx1GxP|AI62^qiE_4Mt)8@SCu@B zca%W5lI5->XTgp5vo9rJ&@Yf~H+bMmr4gI_?up&k=Y!ks*+c~to`DT9LxbO$@Z@fZ zvlrsUpZy$z;mMfaFRuf-^zI=LhD*!i{nVJ$qDllsLGL0`69t1&>D~Qvsd}tD%VSTA zzmlhwVRhTzS5nrMBYvo9^l=e7&M$CgIKc|GgBfFKn4~V8iS91 z`e6jqAKy{#PV(l_3i|*xaXE%97|ztM>UWI?cbxuKuzuIOzH28X?NRN*^-ULsO$%9y zAy$T-`mS;$PSkmuHxu(NUt>$VF`aG6teW6bIU1Xa(+*8#S{?c>?Pb}n{N!i8L`Rr3 zE==EEsrw7iP5daW(r5>1dGxe*)ql0&T9%br8LkwPBu>=0l!msBXLKFG zeKg~g!F++C(e#F$;lS@79L{S-t9jPmJZ>HC`ljC}$G{jyCM`n^40Xb^XmN7ny_>)4 zVykvooQIArLctnD@2{W#gU`{P84q2D&KSmPgC?CPc-(MU8k^Ae-JbexOiu3>Z|U_- z{*y#d6!f{ZLEpqY#lWTi1*NevlvfP2uCA6E z$D@@Ult%g7o=94beEfFD&=0wG!wz+ zL%(Qju47_oy!w>S6e1?VhtgnDOTUOG!7=Au>ZcxhC>(n$oP1=DzGREO?zX@xvq zP#!yEHwz&uOPaT8hrYYZ_5ORjGOu-<>Qp-w-pTr{Zav@0(Azt5ht2x#Qt$|7F(37< z#Dn7neb;!gcIsW18>{nV|HX}um+4)B;G3-H(>9V_wfepWNlN2D31;7 z$yrlihGE@G{-KrN>zJptm?A7(kq`9 zVOF-@MReY&pq025hVMjBpQ`>#_18NA+f?dQ|B4QoF@>q*v9qqJ&QXmSDR@jZz0yfr z^-}2tyV3}rsnQw2GWi^y3I;}}xz^>4E`4f$Y5q->iBGM>(W%BTG7%ujc)gj}r8;eN zvG0w))JC;cD=4*ZDs7Y;T!d09xT&OnyD?$#Y2dsY;hQQxM0hm;r^0|VW;IE~xRl43 zn6+PhWlYiHrV7W^rW0Y(_|ooF@9#wY!iPk1??nAqi$CSpJoTnW*P`5aYZ)4^V%(QQ zmnLhAXoAMywJLA2x+eN27|f~dwVDH(>lVf^G7)y&KosyNjW9%yaL2J}reof_7_k0T z3#R+{+VrF0bQ+)62A|WVe9$nU9eQwZkRxeO+sEw4Bv04YR@_coQ3dVJYwa64cqwGQQyl_h<2=(bI#(~<&IzG)x^4_30G6h&@TL{iWoQZ zRN#|z!^CB7@yK`udhlqBZ@d%}$6c!IiE~bWna04o9RnWE0!FvTFftJ?F)>p=RYGHE z-c7TKBC{i6fR_rIz?SDyX)ouyh=LfY1*=1_+q-@9ekzR^w?}m9{q^eq7F=%mzTh$B zUkWy>{hh>{a3cn$He3!I8b?!YpS5!;Pl*ytoZ#+X_xn`JnP^N;CGTWugeSq`?qm16 z@ToDOxJ%6$r4gLM<>dz9$mWE~vA%G>Uv8Px>8CO9Zo+`ZvW0O)i{^93J?J$t9H)Dd zNe(SL^>-}qYUoT&_b80WXwoQ&ELm&fsvN09i$O{y)?Kav;(lK0yF0DkbqP^<^z&v& zrn#ncP8%H9h8!IdHU(Wd(B<08*>N}-FY%A?pj-Y@4fiHUZbGACWKl!-65@n2bBCe@ zh43qp?|66_FYXdx4S$w(aFwkfyjfX#3KxPyu*-shh@vhgE9kq#j2@F!0(nHeSKrlE z!K=Q$)jK|n;E$m34jrbnf}27n4*!l`iQ*~yM51PN#AbEQd1 zNpYB%t}iG~HZ1-46Rg_(^5F!vPa=L@;&s}?4^tIJ%0h+ODOikQTK_7}(}&lf(bGjt zW8fXafaZ&Zk!{RSjI>)s+%(}di8SCvw(4u^Xq_PzJSMFvU5Ks~E-ptiCM4J{oc zJb{RgOF(Q?_z+au@H|Uh*5a6o?(ks7+yIj}^PT^8N!6+@SVQpK& z*x%EQZu)`?3k^o6@EjEE_`yR)%5DaaNb*QYZ z=V~Sp8JQUfrUOBJS2|rJ_rC1wg_3dqlvQ?FdRGwR)Wu!3TMH|FyB=eGTtKEHr!nw0 zU|`h2mnM%CJ2c^pF$jhLo{w#N{!yH%ti!MW*AMZ+t^yo?^HuCPT8cnUIt6F)`Ujx& z=vF-T^efo2{ROoHL=IS%}<)hEgDW__*Fo+YoU&SMjJc2#PiX4jruWfz-EwoQ)q3Plo zTCU!U-nK?O_LEGpREV%;XJ=OO6q5KfsoQg-)5=_u$1xe}cdNmw!WJQ!8Hi?Qe+h zlW3_c#qrbUhSE&_5PX77#8SI1xu4K3L9pqY!S60b+M10ur6??^Ky6tO-rRK%9Zl6Z ze&QsZce=4j(?LyDc;r|Af!FsQA8yOBU9aOm{`0q}X>7sq-EY!Q)lqb{H{s-|v+imp zd>2gWPcd1+EqJy2kfjFowZ4lvG*w+h;mHyNhXkRlr~r-4oy^DG&Tz?tIC*FXe(}rS z;CyY16DxzRn;-iXo_}ozVQ;{z&pn6I>L&Ja5i0BH>*f+ca4Bg1Xg8{zkC=vnV6_E} z6EXCUoJ{WC@+@9{eHXU9_6&ac*ozn>{O0gf@D6mh;^+VRkNCIWJdK{Ax#TWmym!GO zTxi#sMW(Gq-N}|UIC^j|E;h6~-adKCg6*&F z!2HFFu;Znt5tfvLv=~3UuzfcT(~|I27UB7A<+Rd16F>R;@8jj8C$RO^m+|y7+YuZ| z@yZ0jfsqqeghNj7WS8&t*I##-u@N`HwvfhigX#+K!yi404Y%Kl<9pvg6$zXV%k@JK zo`32IRMUG$VnQOeKJ{<-#^3)RdY2yJ^}QYV;SaurpT2egr%$|zeZ{Bo^zWa*wl`1E z6pqLA(s~JK9RO;*)qJ_A>wI5Y5=QlyB7=66Opm>ZfshfLBjSriIyPa zLIPd*^}qif`E&=q<+r~^6KPQ8@m+YMxCt}Dd+@J6{s(L=D8iPPUc__H?L>I=#JF<9 zXn0d!YZoRa``T--IgD26^xYktwh+&e(Q)W)tVC^73-Q*AlJXjaN5r7CqzLUj9s;WM z&0DX&h{%jQ6z_c#7n*v}U0;qj4xB+=W(=Nw@-gf>Qh>rkd-3{fJK-A~<*sVNcfp{a z`c*qH!7bZ+T6kGsdomBAo(%Um-RxA=HIWV)o1wy!7H5 zPL@O4wxA;<866i-;)%_V<1C5)_Lp9vG203<%Bj0Z6?|f}vfHN}kVLWuo4#4Fw#d0p(kuCJ{T&xQVmn=tWEM3-fCE3lZXb*k;n+WQmD1~l6W@OLC zxuUc9<8OY0Mr=80Ln28q0#I<`I4TF@IkD#=J2@0hEj>87|8*3VjkZxH*xW%3L*kq- zfBDOfBStX~TP17nHQ*nPjW;d_f|9Uuem+*N*?`0drXg(^py{08^j!3|RN?U_U%-v` zehK%knuT7r-3b99`0AIxj+_`DWah2F!r8fq4P+a8eel`~&!M(ua{pD@`N*R7AO7JV z;;y^ya=}F=%AM@lBiryYcb|X!@TU-i4t9bCi2Zt{fkDFaa zeoi#Hbq4YqlFxXGrwD#kM)$5QMO;6UuPit!(f)jJG zhL*p5f}$`xCz~SENVK%~&>R0ve^5x4NGely>BYo}3;qMphh{?6< zp?hp(=g#7SiWns$Yj18ud~_z(t)@$v7BV`9GVaXgFI$J)+zdn~=OQgN1%bZ3=w+MV z+WIDU=OgBoJT*-GuW*`{mWEZUR$?Qqtqya*@SfqnL~pT)xuKkV2a6l~LB8Uybq42)r9I^5Ul zR)p8i5M)g~hHgPplY231_IxD9ry?mn9Z{h=LosytI4j84UU&+*8$X8sa?fHs{`3|U z96y3e?#TQoJ`3>a!!LjKLxiQx0lhe&@c1E|YX#OXoPmbw3Y6D(AS*o#t<9}imcJPH zJ@|3N$3-I~svq07?!!x4_giJ-KE-^s+7#T{op~ST4{`#BghwMMJB2%mKJ4DL9kp%U zTrKm`H{B~_Wz4|sYZp>+ zzIMF$%4=xv_d$KxIShnFpybSMyt;J1PPBWNEclQq#BiL1M8+YRI0z07p}(;pGPEKxcF%zDp%wj*$RO;azp3gDGPRCo z;*et2M(+G}?MHBU95&o~C&yF_#cse!?woe++c#OYW4@_>^;4gZfthWHNl3;_GLb}% zA@p~1M|PHr7Gji)DTIF5n&>rq@4f>FjE%wBa~BX76@sE;dvL0-6tm_o#T~b=M^sV_ znrkoM=+T2HDz6>`!(;{YC6AD8(l}^BE*Yharj@nOSsQ-cVVAAi6Y(iU>t~N-ENm6VXspi})FHv1E1z z&*)=t>jt_zALp)}v^ljZ)=p6h9&++mQc~i$MAu<_0G(FS5I7dESdFC%=OA-N7G0tw zBQ+(7jMJYCwi^k_=~y^_21TZOamPnLiQukwB;?LVTz?J9Tch#d{dZuXvzhLkldy61 zLgE6r{ni^15jvi8zY*+7?4=#J&TpjTvyY6VsHn)t67l82Cz8IW^5*2@RKYRiFJFt4h(P#+$0Iw=2WKvJ;`Uo^ zLa<*i8M8l@FI~*BG>9e3S0Flka+`#LK^6jxIhbOK&PS#6BiICEFd2P9qQ}B{R9qt4 z5JdRsypiHMSz@1&GndR4bU9y#+i$xWjSbD1zjP5AN>3v)eLhyq%R*B_9mjDVax)VU zMA(B8e1qxD zI~x&^(TItr#wWk|b3w3_ySmbo`w*V70C%rnHoU-`2oA-|B$w(Fo-{8cYL|#p3suc= z&6hFEf3gCnzfEJ{U5bI9{p@GoAG16&KRn(8UF+K(df?-i#+7B$Q?N0$3n#%Nwf8k^);PG-STyGEjZed$ z2WAhf2D|WhC4H~P_P=B zlA!jf@AOm|8iVQ&F-5%##_NfLD}i}B&ol_o+B{W1{lcB# zQ$JdL`X&aU6}-lR{+>!u87l931eGl~1dniNjCHE`6ikyXxUL1vg3lO*-c_IaQ9*DU zbGp==QF>cY=>2ko>bCwA5^IVMc$y)4>}TSAx&Cs|~`JH_imF z76yj%OTpsZ-bnPoTJ#qCu(X z>uEtEEM6CO{v4o%5S=AmD>0STG5wszz`G3t8uyL>T>tR$yY#E=9Mxde)eQJ(Zcy~= z{HwJ6yw5pp@x*ZSUVA!>Y+B6m-sm>Zd5|xv&K04t=paIQNxaV|6mbg|A(WbMfz*f` z;F*?O!Zgt6?e4nWGz&I>{DC>h&7oCwUj8=QnD31izc-+CXy$tZ)b}lvnj7LzRSh-h z?WX&jK40|t(_lkT0PhGU(n61iarN`!eG83TcU&w+cO7kXM*5+CFaR?%S0OEa2AQ52 zfq37d>V4U;YjQ^RzQoKs+$b$BoCSt9S+uvO{Z&J2J*tX!;o|-`kQ&mDaGLk(z379w zH+R5qMkYdesW^H0N)(jr!@&bj;#_Y(+U_1iS$hM{zLv+yO7mQ_x)KsfTbi_e6mVt6&sEqKi-WDJBNtDLr72TKzBIv)%qZ?YY=Dl z>_>P0Cy_sQH3p^ODLbd^<333`ro+1)1JjJ`UC>3EkXliSvB-pyL>^t;od8xqslPN* z+d}IUw0+1Gp(;&^PTWP?E}R~_RYu9=WDTV=Ru^W#$nyfG&UR+Nv*``73iggKmhy2heXYfzXtAl zJE=-vLbG0{=sKpF=DP}GW3iSO-j!}W&5ng}R~*lC=U@^a6Z9kvW;o4w8wo!GZ zp_TXJ%3G^YRo{ZTvlI<>_#-MZomO(lh{EXHm8Ro-c}1hSd><;#9Y=k_Ansm8+pc;3 zG)G4lJI83si#C{j&d_QReL5YjdKpd4)u@l+)sF6HBnHPJZ)TQLm#(Hvhj%XqrWx5g z)Hh;S#=K;TNGk5Szg1T!&%T2wI9-DCAtkhR+l}158+rLD9N|H8ae-VbZ+0i*crW?P zMNUHUy=2lz9}?FzN>4gZ?#0|Zn&C?I!!e3j63_af_INL97M;a{^4ri@7>@HLr%+S- z0#@9xjLtsuoK@%a`PtZk;77(ZKqe$cwTssM>v$Kigmx0EdC^!qFL&5X^J5B6(;Ss{ zYjfyOHHw#_7t+?^0`_et?H<~0&7E)h{qiv2FtFA(ntD5i6Q|E0C@c{HgCX!Iqwx(4 z=H-5Qp-)7QUmJXT$?WT_T> z002M$Nklm{)zMqOqVm&XMK@; z+z-`Rr%}CTCT2t|McjpKIvzcNZQGBbq^umb-n5S9Gi8!&S{SA-6C(;F(JJG@;@=i8 z#u3`>oNCa{OTS}7dETNcmr(A^?xaUperfPoi0w077q3D z^T1hJQ5#&z9ax4RR@0z0+JjNFzY~LvG<)Y4K;sbo^dGpNX73_-nLL!H$G8hDuS9BU zg5!rUD2R44*^~h?HZ2D2cloWG&T%yum}X>GgT2eh>k%1(jt%SS!MX%x7aGvgTu&jQ zJX1{%<4 z;{1!?4y{)P)8o0iEFvQ-IW(_!iukVtX=etL{=A4H5l6_@;j&=(Twco+{1q{R}B+YmWu<=IzL zcO}~W8xT0B6BiBzA)q@A9c}bX&_~mIm7Iq=0D4P;Z;}r}(tS}K;ETgOK9~{gLr)3x z3K94g{JU54J;E`t@aUt@J7WL9z(~$V*`h5(M7TdP(o*O*u8#)6GkEqKO0N%*2zD&a zc-(muLc9tjO=Q#H-)@fMUuVHrAHktp_ib%f+D7#K8g=p$iTwsNHl{_Iw&JwUQJ)qOxY;e8Ud-^2{rk z8i|edrKp%!5sb>x+SDMs}U>s{yRZSVqy^jva?M83HM~^CJUm zbK;|;)9D*3g+_$sVk3;-`Wyx(UtV(E(M#{z-HB~Dy=FW5&Qq?xqk-O-1CZQ0h$yZo zgE^NX$;f7Nj&N~_ZcgIhobR%NXf>`X!?!S=sEa>Y+-mpbtAi`b2rDWs;=q9d?!?+ChKO*^#rpf&5JZt-Y+M%Q?Y!H<6{R12 zWkrO=a&^fSCB-9c9gU87&o_cf2I*VS)zOBi>L5DI?8o}BLBv&XH^zzPOV?YRH%Oy6 zGJq@AJv_{APEWywv}p7uG$X3Z520LHqKzWQZdyC%qzjFVMSE)<7Vf_bM{{35(cEpQ zD>#qJ=#vOo5rnY*C?vIKp`dpw9)ICkeCECfoU^m{^NLctFzvp+Pj@R)=6Jh;>iQ4v z{G|E#%>xIV-Qe`jOw7d}wXHRH;_$Nws+hsu5*fszKx*T*qqwjd{!tv~lnn+3grGMh z7`|P79OqHa^^_+6izrPyi1?mtI(|(x;a`etL)I1mkM5k4%ip zjR>Xng07@gT-cCCH`8?25mSp9gDqI<+k>t)Ulb4e;#6A*isRp+G6;8jot)Smewb0b z429>nVqjJuLK1jj%>(ep=!@vB>A@g(ZMF4n*s*;-a^_?rIXTHu1QDZtKZ#1DPOmet zzgoTeZDnHaAt!Cf@P!NU&4ULWwSM=v58AtSVvWs>_{H&`Q&}kqX(<^vG2>Ol97sb{ za3W&orlD!}MP57UM&Cd;;tI1dSlP!#KoC!w>0_>%=g9E^Xlg6xT-k``z$&y=)^Toj z-~#7MUtb3NI~L&gp~VQvDnW2TKk_*4<0y*1F>?U(Vh2#nITN1gi*hawcQ^W>=i(r$ zV@{)fMH%wzHgX{vfdJo7M|wh)5Y9uH_v76{&W!*{MD(8o#gec@MI}%y+J#+PcA~qc z8LRHtfViXtYDdaps#HX#!?nV|G$XqTOp2(>QQ?`hr6?&XL0d@$x_Rc*85zopml5=q z9gje+FoU{zI85)@{e8TI$;mpvtyEw@IPbhrhMweyq9xmKD(6k4l+Q-asWs?|Yr(Pn z=Yi8)-H{oFcJv0@W1f^J?Afr=Gjh{>u&a!d=>%xFcH-vE+m z^`nLA_o2OHWE6W0*0iFh(;q%TJg-YVh48J37!0JQ)jT4gk77_xtd4|wwEHxmpBh_1 zH<0wSN$U#PB{`l)YZ|Ix79DkUfLq*ZeK$ukS`!O*|P_FB%idadBoL24Z{Q7ZO0x zIX%Hw%tT~sG6qf!puX@t!rJ4=z$!8L<{*-D=b*%AC(nn2P<=iN>HhN(*cgI{gjm!q z4o7RuDXjPF#NC|(m`N!|H0M-q6n)2~_T%?m0Vw2svf3PulU-EYIN5`+>R77vck%q% zkH-O2D&an`yStgnC%iJ#O>rj0q5i=k&e>g0ubj$uav>WJWX(ZQ;aOC2k-PfNjhMA? zj^mfm+&X;_`}I`0cbr+cmnH7~Y{K6^L3+X^V&$v?KbEw1- zO%10e_;u7Fs<9LGfvsd>J!lE@NBclCvi(;Rk^$5uokM-(d30nqQqJCiuBaC0{#fV{ zUg!)9Mn@DUd5A0!Fgdjm{l(0vhp{);2Xn}{HV(8uxFddd>XkG z>QAS+KYp+Kv~ieg!63R)){@Mj}OF&8frHN(Ge!aHj(EN(bidm`k1o_{Y*5H zevv~6ec|s*V!(Sfn>W9L&wcLWTx~|ZrtD&rx(1`+>Wa|)vVWlxh(yvi z(K~k!7f2tZAgKn0@_3_g7j^~hqS7J7a`7}HmDGrZ#dlMqp66i$t?+4LsuC(sa2KYF zlr?9^!W;^$_lCcRD!;^K2&#{MsCH8C=Wb{Ab(z0IYkDONChgY%LjMF zBDysdXSoP`rGE#K3(3fca=%PowC0glFV{7Z0X|6Joa*q8;gyz|sOOni50#|?cvnrk zE?rgW8|dUhwuTqw0}&RH%p(M<>$laRTdO3_Jy{nCq1ZDrItBiu7rnJL*z(k?*t7Q# zmabWb8QB?#iH&j6s!W-Wn+{iofoVo|1$dLw#4|<3*z(*P@Cyh-fNUI+d3DRHHV1h2 z%+*Lr$|GH(CLGm-TX_z1vgrb?3`8TARyCUE6{9-(1n-O;!oV4t&?%gau;f^-=y-WK zvIOm++;Z{od4Lx^@Z`0L}}AB5mfjf=+mW*pvMf%EBYJlje^)X`)v!YUCoK$ZGXF2v^a zpg)PqQ0)Oc4-Q3NLpNfmuG`|%hyKVu1hj`@pk{!~B%YdttuzL}^Rw06XzZxK;C_lB z;6!TdFTWSZ1m)EOEj7=FEB zNUNBS?vPfT_t}qGeQRlafH3uUqP*ic!u?_q91_XvGW4XLG?U6)o%E!>pA4>w#|E(& zq{d?)Exm;F_;dcpp*t!BEp;t;<3+0XM@JwzB_6Z$vbb{#qe4p>k0T_p`QT^^U#l@b z&B!hTlM*G0i4~qK#B)!-!o%Ze1akG|M@NahJh<|qB1c-<0$!BNr09UQ-FPum${Z!9 zw((v{0CMw}VqiY)A1$ zwa5(z&XKoq{vwWxwjKGv!H@f)D#jndG*h*J>ip}eiyuT-nz?Ih<2*Rjqz0-4oZAr>t|!`Vv2r$k{!bTjtpAU!<} zz5bk>@jDP4(ZikGLYytUfW?dFJKC4;HCexy*on9}{O!t>?>aGFBNs$}&GWkdzGn}j zY0>5VuF0q~*T%YLJiT=b213KRQwl?TWgeeFh^S12e^?M&6Km0wauJE=XHjp7yPZKY zqhfk7r*>g)t8 zm^wtJBp|JAKGM48V4!LiYI*(Sz~a-W;cj?-K?S0?GdmLOk76zgxHY9Kbm z6e6*Vl9r%YRCFJwf=3^Mf~g_G-CQ@7Kl*q_O=sYViMeQNt>x~l9$^7d2;#YPFz1pl z=VchLZb$n>p{IivtGgR$p{02q z3I_zD;K0*pqqrd@V-b?Fa+xj!O*42|Gl6%;NL24X%R63Yx=>f1jJ&WLkZ_nX|IQ?& zT%3>8ZToo`-HzlAUH~l`MC=KQ1tWa$)W`oHd+z~l`FUOU?c2+{?e*TLy{VWPbPyy+ zfD}cMlBhzFmL*%3EIEmtL|IOpI8Ii)R^r%Bv1LU`7&(fpN-0($B@!e7u%HYE1I%Fh zy!Ynyc3-*ozT11r@7yu7WGzt@0A~jHgTnz{x#fSq?>p!0v-du3U7B+1#!w5!VN4fY z9cuWinu!3n)E&B1aO*22r`B=1KYHtF<#rOv<@XSS0w3~TJf|A!+yRP&K$7-JFJ6!6 z!2X9+TPkZmyRFF7nhrcv(bdj|`s>G(=w4B#v>-q4xp;~LWZSC@k#+jO1dD+ibB|oc zC^K=gX}LB-WCwTQm4wZhMNs=bJR8lU@qWFW^u)}X?O&h&B`po#RC;(*Y3FSnE^KOd zxvK7!8TGDADzx9D{8$1=&w5Y5b3XX<`Ko%8M%01m1TiC0>{n>HhsVpSyuGJ#Csh!v z-`)*=X34E;%%f;$StC9OP|k$5LhH&5?7_amjsRrBQT3|Fe?)tuZe8zNkZZM}%RbnX zAStz-nlg@C8jsHFG}_N<_JGP&kLH{&P*LIIIJTwop&Y%rE-Ejo#kL+4?<>;OB0T;q zf1;2>e09J>5E?9{vD89zjXQr3WF?0rpyZ(EN77raHnnv1rh59i)icmXW%eG__~%*w zpZnbB{_%Si*|)hcg{jdIc@5vxh(b*IinigpN#URv7>?%s?zb(fLv`r+zSz znMTa0 zTh@9pj@?|JLePvIv>x1OK8;+}#LXvwZ)de$kQLCnC)gQrG$* z!E6J1FIH83E#;?Eh@M^Qq;tHCKiqV@r57;+zR3Kf3UJAZq7&Eye>wk#LS0aQ30Pmo zx@s=UP7NZU-skmsa@umv%1tor>>5`113hG&3#vU&W0}~tLC~rru&%oha(cFver!vL z%@s}a{Iu)z3?nXfv+Ftsg9|dIhC3(KlbBGVxx#3SQFtdSa$dZk51x4xyR5r=!BM_3C+6nno!tv#+zxAx9 z9-7gU_@MfMoZoZb|I^pldx7ka-5+BkZet31{wpskd2?L>GDka1DiAIlhfe?<4uQoZ zge1t=*PGCSt5p`E6OJInip{0hmEK!Wj0!9~dQ_n(jqCI#_<4=dEO;hDqR2B>tZQ{x zooL2-2Ym|UW9_QR&TSHHuaOg1_)I|cG6=MJ_jLrSy%hQ8@}s;-;Bc@UX)9O@^#3idUC6PsE<3mGH1Y80F*_tXgtcZ>uE z1`lg@V^NKTs`95wa?j$B1JR?gS)@2bmBUo?+MJ4uiXfQZcD zYO-;2K_C6}C$PsFdM}v$v9tP*{^xr=vOjV++$^4RFTJW4pF6Jt6^|3kn*u6+6j+L# ze4j=RJ=WH`80^?+kVO&z+WHs%+v)UZXY&RIz3cKtdgKm61c7>6L&H@r=h~zXpAUx* zp3i=-yK7Xrtvwps5mk1`JPC5)P>-5pbuCZ5s*&=Z9@&J5as3V*xJ-X)_b}`zT(>ho z8>vepy1;A5nKc!U`DzM1T9S$pxHI77G5u`fZ8EuiHi$DyK#i*L>YB#>1^PA`>4DU^ znitTwSu-0bvSWH%KR8s??I@XN2M0$I93Lozhtz>UODAbY7iyF8bRU(2#`XTdrnZOQ zl&_W4t^EZpzYeRBs<68&atG4ymsC#}wy381z z3jw`xJ*Ks?TL%x(TMEJSg{|AWH>ohvk)G*s9B=4rZN}w3<5TDs!7@F`dXFeP+oix9 zc2(;m3Nq>?)yLF{Xh!}#j42Yf?XEf1ujX~OV_VZ67{`|wyvhEG4@~Re&Ijb5r>_b* zs>?H>Ue6)m`=WByef5^6G3Ab_F^msnpjRo{1h(e9>{&MnZ`1FA55m+75Sh3WZCUrQ zTm(BeW(Cebi2fM9rs&TqICdLyP@+05BBTzODe^wm-0Yl=!4kF!754&!|4yu-Kl&W+ z^~k<;H;674#9sZ{E4ui?YfyBd^aZiPDQ8r4Ry2ATMjt_}4t3qMAs#GfJf0vzNDl9M zsSPV`Y+Pw$*?u%5PRJh(8oKH92H(Sv4SKHqj+Z9B4@;s5nP}-~20aW+$0P)bVuqh1 zV(>b`rCy+hekJ@%$`YY!uocaU%01ZB4~<>ZLT^|bYvdoLDm3`0e$}1OD{Phu&fPr$ zScbC)G}t<#8>7$5lk}?ME6Tr5u=;}?HrxRHJShGAypN`sYx{tT*Vp9kMYt_yq4jSl zbF!+{tV=hOv@L*7yMaND^16bf4Eo%9UHgTS=5ojej<8YbX?Gwm=sP>8A)VDVdWq?J zR^R>92kxru(E`E^DjXY%c`sexpjY-Ib8~!drS^c%d+D|RX|L6gi@K+*-RawE1*$L< zaq-wYroF{wWv*@MbrP*X*D&t(6(y3(8tgf)76GJ`SW}{kj*Go2raA2G&XMv5g#Gz3)z4jF2&Z4WpT>)EWI=&4 zde4E3_Ey#uW>4=D7++hB>2d7k8iQ2`LL_miqkyeN+%nE{&jk?2-=ta2F=i38FYO}S_~ zPh$?JA6gsvT#6*7A#bvz7r*$tKKT6~z2gXUzhTXP+G6>0e(zlmEm}q8g696}^Dpb_ zbFZntiDLl6EgSB%N?_Pw2pk=FA<_YoFXUG}Q6}C%o5!`oh#gjK#p5@qxP1H}77-+D zj*<1m%vjX=ZHC`9>MU}cG}ez^0mATW>%p5UCes>x{%AXh8M85&Tva68PgdsP&_&}F z17o+I*D8r1y08mqO-_2MdVqsqsS7A&qerO+a5SJPJ)Uu@lgi1N!WJh7#KG%uw)lA0 zVJdE7G(2%qRRVJkqg4mlpA(B8=u_-3e$SBmrGCBoFLB8Kn_C(`)=&QcA@)j6>+zg+ zvK`9yZYg#op|05Ta^XiOceniOT?%gu$+hB9)*V;)Y*Y*GIWld6X^?}c-Ng8FuEe+L z$B4o0iss+abE@-M-%FPXqu;=d|9ck~?;FyG?Y9cOu8n=5c!&?B&t}!>9YrtZYF9QL zm2L)Py4u!liPVz1V^i$Geso|fa_sM`;N@UAdRbvF{qCxoHPDAiG@mz^GX`_F^2VYD`p2~RsgzbdFM&)HRVR4GKU4sD zzzdbvQLkPBYNwCvTf-nAq+#E~YD7EqzAyf!o_O*1+trb|k+f(pfSsU;aq9p4yAxU+ z9a8yrS`~WG^a@}K^EV7lhZjH7njiAmo9cb|hj0N2tHFpS8WeoLM31dX6$g;gQ!W_UnnFA7H;$&MK!A|EHbMK{jVsnVjvi8_qyy(8)R6m zW~t^}%McbL4)3G+yG?d zK-jA&(AA>@8;`2eiHLQ7O#9Hq%bPhlA0Wt<&S^OKBRukVo<7{J#?Xyj`FDdZ|Gm|J z5B$d$rl<8`tgD=SW_Qx@d*DTXo0n*)gU!5q_JxI0zFw@>EZWjrn>86|<_KiY2 z0W$+$FFmV)fy3;(ZWZYmKfwWH4a*lmiNj&@FU`AWz?JvG24tmorfTTbRen*Zp@4a z9oOIAUkSz_aO@Kx*x zbR&k0YHE>TeQ}sl^)V`~mR5Qg@v>2DSA8Rs$5oon;h?dh2WfV9(xVC+1$Y<&#UtZ7 zl6-<}wWhgHoD5wWa*QkgMnDIX?^8TDr!C#2bc5)@oTT2=v;v-(ddCjnJP>9>r#J^) z>gqeB^v*n#--;ZFwd=fx94-bugJbF$Is&wk)vedRqGWyrQ8pV9hGrx(zB(Ko`zE$SP@1;0l-r+_P==KD57 z+TSnmxUhslO)R1D>}?z$Yf)U@H6Ps z&H@KXZ;~ECIZG1gr*%-+R$~`8eIzY@>lI>uRYm|_?!v>7De?7IMF5UCoRkrQQ>k$V z)$(~g`>VgJ=|>;XQ?MC>c!a*kX1ue?-nD_uvcm!k=;asAQ+3hoH3lM##Y80qwcdlP zJa8F@d;_f84nr4kV3kAJi~F_pz%oE|)f|1Uoeg!O|ER!pV&|!eZHAMv4!L5s%?}R3 zLNsVH$SkE+w5f^Nht%A|#hyvC6~?+?_sh5msKdwmReU&uCT3p!t%Q#5(w71*ca#{@ z{=+!n0}Z-vxfRNxiNPN+whf)$PZw*Gs<2Q|^MpC$Q=zp66z=I$iOp-!rw!~(Bv#4Z z8aR%OviQ6C9vNtwu@=0~0?q_!n#@zZlWppMv5hl45;iIhk{sRqt z{xyeg5>va0FR5%yz8vxx5=_KyLW6>r)d;X4uNi5FU9LC}j;mbP@CeVzzuR*YglyDI zg|tV1ZiFPxKmIjQb&NJ*fz3jHGXkoFsSbb zHVX;^&xt9s1=D@d8mh4<-Qexv^?5y!#%&(hVwh&FjdWB5clV6&oLDzeLhD8KnZ8 zXwT*6PmWnnmf<3o#+4t~fdf$(Cj1A#W4$tCj+yOKjsx;uzGk7} zn?t{OFq+2fUb)QqCW#L0-1S>p3$Zpn9#rUZ7+WZ_a|1%dpRi6}C|^!6!wZcTl}m~J z)wJF+8cj+GPoXptsb>U>w98fC*Jh-1~&)TzlQic@>&A8p)&Ft@x zu%$^D15n!ungokoh)5yUy^BOHjD=Kh=al+44@2tOk>3?i$Bi?(Jl&^P`yqzZ((3PG zA3jW*>qU?k0_Gm;e6T{#%Mvr|Q!Ov?q(nKACHe#HkHvA5bKorfxv3%$JnN3YV-lD; z&u<38vDgsrWxf5g4fd1Y56a=I0GlEa@H2eZ9@>Yr0H=>``hb2CYC3xg0kfuD6*<|n zy`H@~A#{N$%_0WHo{wf=YG%b& z30V-UlZ|@)_|{c`J+>Fy-$#B%FOZGOm>3H_@%U_;UFoKpG~$Y%K3|IlwVSNBL@+3` z`ArL#%`xwyTRNKm2+#|J7{m#FD8&0@zt%T2Z^9QmN|*e#rUJNQ*bX&!9S;Gt0mPTjCKNi;d57%?p~AZWDeB^~+*nY#J}{zd z2fn0BRuPQ@@gH&OiH)WT(Iu?~E@_XvGl^wf>jh@~8Krn*i@g(56(@V-X(}M-p7*^- z4p`LSB71fD1n5bx^7O$R1ZfY+h&kj}=#3@!R&e)-DS_mrnObdEZvCJzAx0}T31Ze~ z_K+A`u&naOk=Vl_q>fRKLpv$_P{00)KK`RW_+B8p$M^VO_~jdmaCc`{ufKLf!Ok9F z0w4?g38N9TRRfcX;+5zi(Cw{UQEvGfeW$Eqc&j-O8hfD8fAr?-dUE9!S}vb{j`8Oc z^qzj)g40t^3E!qWFvHmg@qS&tZL(CO2Yb2hJj9_;_^r89A~54=|;y!YcuNdT5p#L(&3U z$d4O0fyv8;waO`#!jYfX(ZtOlUrZ^nw@lBgUtxLy4m2`eOiM$47*ae=njV)IW>qtr zB=e^d4Us+5Gi;U_S5d;p4l+xCo>^EJ5#y|1Cd0MBwYzh>UC{+Ocx;fMlMykVY=GCx zefthq5M@5^`{6Q}^j^6PPTWq$b!l^6rAhizFkZ`$lbQ?2IW(r)X=wGq6?LwRsJ;hr zf~3o!HVa@A-46jf2HMGx3z2^lp)hoa_8PY2tFW`9LU#)IdmKSAPW4nTUV3c?Ya8*( zd$ptOE!wbz&R|KjT=W9yjbS{%qt*~Ddr0)0VUU$BdQ?8(ym`DGr_ZXk5=T>6Qs?}b zy1hf%>s?f|HYERO7yY?eMX;+&c6?30@l#X!-H-hT>b^Egzd5e$ojDyn{IrrYtGamP z^9-&nC_}%G99KynX2u698d^D~%0eD^l-EdQ##li13J3?U+liw|jr~=pZ{6T?c3LGy z^;f`yvBrDn=ur(_TZ5`EA3!Y4zA)+1_STOBOo8Vw|DFHuByoFP_?S! zwdY?&??GS!uP$-;M}g5i2qYVn^EOM&8mnE9GyL9|_DlPi@4{m8k|}~|&jT4g&VpKJ z%=*vXeq99)a()oi@PW3XU-R=gffB6Nfe#MDnJ4(v$QCo0huQ`YGq=dF`!2{8o- zkKIyY08`!y-`@Z_uxc$&CAH~O`s87%LS`|ok+;G!99cdtXBOjB3t)Z%3q1tOGREH*!mZ*iQw~F0NqW8@@TL z>VcBh4_#$l52$w;F|@g3FmTquUz4E3Z; zFnPL!=oqb7FsqT7CwLAfyOX#MtR0pc{pIniA5jcqRy_4(O*+1$ZT`uQVrKi5YNsnTV0rH^20}h9*dg z>G8i?nT+qMK<1*-TDWuzLGhjfy#p##5^abhL7T4=QBlL2i}_pmtGrhwn% zq#Wu###3Nj^O%%4xuT89tB5mMp!l~Xv8tIRJL~e+wbAF-%_pxjvb{rr?I;0hmkiYU zRrKT7&@LX|3;rL4-fQmrR`J;o&wSo|+0fVkTW$kwnj^T$1Z<-i`_MNNW+PQpS%QT~ zY_ZqmXTX`?k3lj)&l={Y|FTBAhia_|yqL!LI6zMi!vO_p)@OlPU7;w?J=BJTz6E1i zfHkI>HRm1N!_xYkzEb~X9X|R!n(jr2%JaTcm-R8MH@47;xcxr3z5%J=QCvRmh0AnK z#l_2-p2%yIwb#$+WlyX_%XoUmr{^Io^lM-rTD_A&wBZWGsV(N{(a&PPCD2k@g%+C{ zP%eOfVPB`5TL}JHb5Z(B6%PJvYP&69HgcBNLw|_Z%aL{lj>S} zL1VB9llw`1t%C}!3vDKA-Nw2!*+YeelqOF+tnJ{e^7I5Fu1<|DJt)uBfOZhJd)Y%R zUTX(rjxe*%QlKYvFK7b*=c7xlf|yi6Lu^kL`beCuWkIFt1aWawS%yI|yKDjgEY>tZ z+6SL(v_%kKOX|5_`8|F3$G@NFpwIR$oM-l~31n7{)!1N{FCkv;V(}ATnq+DLOnU41 zqZxy$!6spH9~qLx9bCAXyj*Uev4U=k6Pr8;D097?%3eFKry+Ix#;1NvZ+ye2Pkiz7 zG=7(b)rOTeZH-o)#pGlo`C&x5N9ejS%rBDbSA64^0?hl0pSh*|5#010X?j&uT)>6M zXp|)uln`NF!G0%kWLX0{;~I&dl6w(XePD?Q;!rpJhaAo7QptqR?lvp(Tga0UGOXW_ zg;i<94s%hkO3;WNHQUT{Ks`)*&Lhr_dff`rY^iB&+EpS>-Owi-X z#7OuIy@q*9Fi18R*@IN`ywBa81^Iiz>h(>kH*o-g{j5@uJvs?wLxab(1C*DihwZk0 z7m#=bNU}i!+Tw8xPB%YO(`Fh;#P&)N#^XrO6vU)erK$StENII~7<}1eZQDPYL|nPl z9($=<0T{-mrfVql+vv|&|m7PYZ?l|-0olIJy|n5$4G0Q(ifaNOiA1~sPBjCNx0xFD6- z>**v(42HTmP6)I^VWlH+wX(plH}h?$4**i-iPL1AB-}ymE^X_pzy1Y%_%k1GI|#iK zd+csnkM|B<@mIWSR%OjI)p-wXiPNej7Hy9aJb>)VJ`Q^pG%$3#8EX|ztwbfZ4@Di= zpo2rZO@3g375Lt*kr_R>H><%zEnWMr@6|u~iGQSj@ZCS9-#BoJnM&aHR35)Sb3$83 z-lyOb5zYOLZ)ouc&Z+!3w08?2!@wFnB~>DM`c%9zm`%o(9N`572n;C#T6Kg*wV9X( zX*l;_D@Da+m(kp zQ%3=Me#uL4M+9mD%t#JDNgB)rHdL*UQN$etn6Kc(oof~GuG9Pp5fY|{x`o8O1_%)KmShxJImNB_-uir(HIYU{Pn+rE3puC{FATM_;p zd)Bw-iOit7&6az69{w$TR69g{%*Ko0z1aX|uhQH~&5>}OJFLMu99Eb&Rzy=~x<(sy zVz9J1=(I@u%oV3pW-umm#oSe@BOpm{1oQxQUsvy_Vpu!%_8n});8uxI#@F*EN z!{gUSD_T2ro_+F7h$DGzLF>oGK!BYj=VOoq{_30J+w1=`(OYQ2;J;`he62vZ=ZzM3AE@v1Rej; ztg_!7m+#S-TBAG{uOY-twrH6t84eJWZeY~GJ`BsZ^wO7@T94%5-FCfeDl!u@tVC8gVqnM^u&DMCf>h(H8VdHS)kVh00&f9h7)<9t2>r^@ z#}Oc(mTSGHr5h>j<)~UZ1G@h3Q~D;N<{w(VsZY$#>LHr4zxe2cE;GWRQDTnR&Uq>? zpC&w~)s-K`v~&Y1E%S^JU8YKCxd?LO;CERzUpdNncMla8mNmXc5K$zSRFoNQpE@9i z_W5j8q&2w-Sk{ZO0Nkd?Q(4;I*0VDIHW(W!4Z%J`*SVdIZUsDM0$iCi#FwB@^W_2tTnh%kuJ+=i+pD{hTf*b&K`Vt-p zE!MQR*Hval+ZQk9^&jT8)Vb@^cKqww=WD%39%RVpogmx(<+tJgtRgFru-r>@^*`-4 zEMfX=?8OlG_ilbqrm@_azsx#K;3$ug0D0FX*7qL&UR&ogVLXe`&Z7{H43f4#ww6pZ zZ0toNDix8l7^>hPV3ZD}Rcj&&#jp}oX%dsuA17ohh=Pl@%^ARv`N zQq20vh)+3u8bgSSn~3~f#|{F`Z>xo4jt_stLLr5jL0pcN1x6)RX{XtMT*TF^^2Pi) zt#~fU^*AJvGXafKk$oT9&n@(0YuHWI=#d9->G$KxA4&xk_Hst>It+brE_$?j{7qat z&}=p%iZn1j_Lg8F_7KGO@L;6kD&p2}T287ok0r@Kj@?}oN(OF1JfqfP=&Kt@b8n6T zzUw3duOL;Jh#0Ru$vbr_XwF#!viEpwUI0AV@|qGb`?^sD@I00CFCa) zV)MDtYWTzWzO?azKi z&y08LSBJxzWz2f7dl-1ZtFet!%0v=OuDz}gbk-TZ=U~y};$3el;YEOrP}yGw4h#^e zFfOKMOguno!9cxUabvg3o-)YX~Q z#a)`vQ@DaVu-=-bm&K3A7)?_N=cz(5IwhbIWtd+^&ww7BiMg!`G^o`^x!b{GK9km5 z_oMx3@tT{kuMFq+`D}~}zIIeyc_vaj*=$!aD!#DKY_)CzcEPK}i(kO0WP%2LC&8HK zdYdi}eabf&U1RX#{cvqTy|&5GVGixP`7)?Zsf+4{utfa8FOb<=`ydV^kWNTM#unPU{;L%RF2!IAl7~8h9bG%(~6&a9O4VScY;s`z(qbJr4bef-qv@$uTu@I2s=zwlN_%eZOkHNQ0U@y?5m>*Q=h3>YMoH_2~+0S0I zok5t>E!#ibgJ6(73WKsrkZO7`Dy~nW_nbq6x1>CkVU9jT+uxBLUco-EX$~l`hD)%e zFTHd@ANk?$xto{CTmIVak6r#}+!iM=!`8w|y8%_fKe0qPp9Ll(t!Xb7Cj^Fl1krm4 z4l7B-kx2g?n1j}-!i@Y74gslQJX)de<=@&=evfhK%=>}{sL_#Aa?VisbbHk8oRE9N ztNa!M<0DV#vsgYITe+rBUVL8v$I^LyW9+bg>!2T|QC`vPkS10h#4V(zsqn0(B6Tg1 z;SpQa1Cy|Oe;5YVv=l+q>_z!cfU_(zLnhiHFgMxsPBxD>k8KwH025o9i-^IAJ_2t6 zeOcX^M=Uv^>O&cw4wp5wgTulCRVVB%N5rANk!jVps%O3BzeTb70^%GD`KGForYrDfxQFTT~RKdtMo!mlWiLWXD1a=s( z8QIoE{VWXHNrKL8dSUdsK~W4=$0ij5M25i?B$kjOTJ*i~W+F-D4ACMmH zX$V;)agalr4)&9w6D8Ack{oW~H=2D-+nG7~bR=xHhYzi594J5CPh~YQu0R3L##eFW z!9aN@KBw+pk~6~z_AgW30TuB^=RRqjl&Dy(TMvbn;AwQi|{%d_w~*$o!z{oA3;d{^WRw1%T#uA{+|Nk zd`$aAF#99B8g*|*eEX!CANO&u8jI>Pxt=ZtN6NJgOx23w(afCKcXTd-ZiVl@QS9F zAJ-PM2A}h1G!C?Qm?-up#yOi1Qcm7_K%sdM3VyeQcC0{^SO&GR#CLmx3Mvn*xJ(c~ zcu3c254574>K{3v?WbTij*JJN?EnBk07*naR43$py#qbH z>uV#&^y)*y`u;c8^~v+k>xnC`>Xj!yqvyWogx1FfG{J@oGwC@Sb7}?%qy9P@0RK0C zo##qN$T~NuZfHV-gByHjSbr^51SYLQ*9V`cS7l!}QE0NTqB>BXgIKX2-OzC|-a^Sq zkB*s0unueJSZY8vp0HnCjnTG8W0~eNxDWlpxavQQdGbs6JED0*lz@nOg^?Er)H5=n zG{JBC#oLOvZZUpiL_?Wlz_Y-Lumeqy=|rGvOsv7?OgkGi{am?B)=Ku<8?C9M8?DUB zRjuB>tdRq}QJ|Bz>$+Esg8!uZVTaY-epNvOIxra6T0;;`h2zA%X=9E-l>07SeiOHf zSe9NA@(|DrM-|8s4O9^*zs{j=Bn%@um^Y~Pd#j$3;wNrVX)ui)bxU&^Xgge0d6n5> zOVH+-9ubI#v8A%a4vi!|To+8h5(mED&vZRtHgna_L0;-%I`rurj}12jZj*`_Z%44Q zve7P8kOqUoYZw4TFbTIk+>@N7?-bFX`>2K%jw(nZw(q^Ahp6tJpog8ph2zawr-l0)_UrN>;F=GS+D zVUk^pcwzVEp#Sz3hrml{AJAZS(>Jq5zca+kB}+9;jnR$48rie~^kr#nq_1e#k7i}6 z6CowGTHCM-dA!mt@CH=qdW=&6x_>y^qsjOqRF!?W?L#b~_mam^y!-uQ8hiD$D)Wqi zVUsj~AxFlJsSCDPJpe4ZlUHUJYpua44ejGR(n9}+kQyL~eMX-E-BuK>T?c)TPT)!V zT8+cx6|&?b5eE#?P<>h_c&F&u7 zn>AQ){^p9NKoEZPyO^Ih>DFbunEvohhQ1Ol{CwZe)vn!P2E0NhN|T7;Y1(uG@zZlQ z2)jnVsEY2gKndmaGjz6r&*v-ziy5TMM>b&ErkU1&KkD`v3ET+wPEnO>uypB(Sz@_| z?Nc3?(!~5NSimi+8Bg4y4=~OpdfK5^2i&TrKpcSaW5DS~V6tk=0g~Zhq(oo^xBC7r zyda(GiI2C9zLy5hD~OckDa>m623mSCfd65~1DaWSiavD+!bQ5BxEARPTOc-Fnt4N7 zvKvCdTmX`H#{B3wvB(15Fu%p&+%c_w?vhp>-_VI;Wt>XJv~lC83QiJMbfv&1YT(je z=luwBhmEl@R&^jx&~CT^P_U?Kk#zTs5it3A?ym!FS|x+_j=gsK;td^pjTx;1ZA=yz-O29#{0tpaJkJ2t(>SgOWUs*_I6v9jR^g^L%Qw}GGB=5Z-_2N> zR1C`~`f#gXM zpze?2dQ#KXQ(w~R`kM-FqJ5cwtwkl9^Ch(T<~3%r;jakP>c@}Lf}%m3hIv>Zuh1)7 z8rjplpT~ewoXL4~daDe?IH%~;17y=Ch|!C7AOWZ z^j^*|89KUPSAoX(3*GQoIdn4v$W2*^ec`I?RH>7y~vD*O?tj0cVWB~ zJwSh3eb<2faE{pm?x%8TS24C{2tZ9LI~R#rPi2zijqyMmn`(}OtM!wx#nDf#;gXTs zr_ThO4lTd_N%~5=By>RGH4-~B3b4T1X85AFidJ^@J)>oH4m&h3#^@x3Z55JG#|BV7 z&_2q?wi$7g@h>Tuy0&klo&D{AlBf7ojSH+jjaZ|v#PEM~{82@O<^ zLm(k|k)V?OwoQ~Bb}u+n>Q;L3@9mU~^=uA1bsTm)-Hce`T;eB~VMe0K*V&$HGS@LpZmx6bwy^CSSp#)x#wO~CE!y8EtUfp4j(>d<#13Xu!iB- zh&l{UM+oghplE{L6d78TMlnlAP3)Q6WIP?P@`7ZSZmgT?WO@6EEhV~FG!i@`SBA|B zfyAnhDwJB&FBzttORtjUF}jkBjG_tW0gQWd381zd)ykOmx+e7t|L}*^vGeQtd;iy- zCjOH(g-?cb@$p_=c1AP<8?ly#=|slaaTh@@-~}?t0%KIrqcpy&rtQj2?Od5t zb)uqy1&2O1kD~jjBVbJOGBw$GWhd)@R9EVmLz$2i!ZCn z{`jN*%x9(l=|7jg2&wCz{+H7EM>#X@fn8wLn60b3@iJJ@AimtyU(?|ueEyK1)*url zaHH@6Ax1WONmeih0Q#%7i5;LL9rS2NHq>#mhXZ`3eYl%c#2~``^g4+jHcrS!PBuT@ z{@(THpKY@m>v7~E?EnP%i1lgSp|K@|(ofFl@>l;*EqqG513-hI7Z%K1K!Mw(QTA&_ zu?~YdAL`bPQZjZL&@hT94eao&U1kI?^I~kXl_6I( zk?Ca6c|sqd{g8#hjN?8P;7SFbM}pqQ+>$EqdzkkFM0uC4owsT|-ve9tFaK8U1HACs zC9NiLx@J&j1h_CtKxnWy@{k?EXj#020d1YQ!NNz&v4AW0rXRO#qwv75Z<+(kl}LsqNZuMH$9bq|EoIrkZ@;gSck`}rkxJzUp?V+^r04y9FjEX@5f8XPzO z4h6V(bV|+lHB=m=#{eHI@HBM#FD>i4Ud-r2By?AC7k{Pej5?b~flecB3oH|wTDE4z zk2#rCXiBI3+sd%1s{;i&u27|Jp{?13b%;Hc$ALigIj^?dw-lsW{Ry1JPj)7?V`P$e zOV4l*)8h{P+G7jaiVv$f3UiTcwmVH0$ZO7F8|2||GS_l%0%!#*pN?HzO(I#vn;9K} z+;RIPN)dp|F|@HDbNI51!MUNYh?>3{zF(y#q> z+7m#wck6Yx_WKOkNaxaebK#ftz6o@P6CT~bXkaz%R%d2XH9S78cWShHlZe!*)SG7e z#9DIABSXRZy1K_vUpp!QN-z<@cG*_p?<^ z4ocTLVAsw-Z{HiF*BjLE>M=yr^tsV~neSuASWKO{F>UwXW@#`*0%&mR{KM*9oFZDW zkzkO7%7~~d1jIm4^=?zVk$-v%Gi}yg9_|o zwZnpL0^gNN8*RsX^K~oI^mX7S5QJpm^Z*F}y%^--rE)71@VrrIPY0G@}*fAt?r z*J-2PZP%Gy4tCzt-ECBtxc;n`Vw?Kt4E-oris!anx*fxzBbGy&L4S=X7=nI(94X9a z5lg%B?e%X9y#%?zX79xtb8_sm&mvT5pGj-)vy1WCY-^nENZ5>Fl zZ?83U@fS$w{w9KX7`8*HlS)THSVmTutvO91hN1TmK_Uf-V`W?60elc2fYAuNe(>u1 z<^2ZJBFcB>_caJAMQrBkPzp^CW)^I=&%pEz@4LyX6#<;XBV-{ zGStEc>4GMUNRhxtv;m){4@C2sUts*nzIJfwF5^P&1}3viF&Y`vpl60` z305JGXV)$noCPd{PzwA`ka9l?w6c$&nIDorf{O-0GLN5Oq_jy3?HMoY?BQ6DgMy~WMXgzmPTdUVqc{DHA2O*?yf=mU&UeVUe(jGw#9t@@?P?Aql zfrZL?X&&a*G?RNv2awq@a|*{3R}hLY{fB&C3OY7{oZiS3R$)(&g;$xH{S9E1$%*6K zH?!D!>n=&R96W-y9fs!}S9T3+jilb~m|tm`&M>SD(|3ON%-+?bp)>VZw6X)=1vG+}k-% z8ec)k4G4PS0IC@xh@Dx~T=<-#i)D2{bzdF>;v1V+u^SQb*esP$QSs4RiuwlCzjd%Z zCdF8>)e)@EZYAWY`eD!>7QXX*gfJg{`>MDhcF@<3@;vDiYiceb>|Z4jvtE?38A(XD zt6PYgH+8e&(Gtwsk$u+kHG&UNUq|?mk^`ICZ?3fmeFm30<;lSAW#8^3FgdO>Pp~zB zTwp?;ulcmU9ajjK`x2%AxgsoIsv;+_qhlYU3b3HJoA*jWTmbs?7}C=-*)|tgTf3s2 zjq9pI(f86%bTJ_USGYF4zO6T#0RaMX%`GDf0x|K^cjp(W?5JSzMfK6%2(c$UJa@I5 zUL0E2DmOfUKct^P>9n6^z1qNBAAQH1qoM~Ndysw1VA1=yBD=49WR{6+gSFRVsP}hh zL^Ic@$inlwK$KY&*1IW!L9Z`dQecD10~jLTzy^u~yuW{%iVX`VhWeH8Tr9ER436x; zn#ov;He@p5#sxn?#^VK_W^ozw$t-r-PS`BMD%FTBW`M;zP#(}3pg($-WhlpK4M4H2 zxDYd!pb9VdK`Gu;Pl3#JI;4#UFKce-rjk#e)N}pA`sC|Z^^9crO%N#RHk+)^^Uid#TKi9v=2LW9q}!p6Ia zf)a7E`yn#BC>!QRRGmvB?d-S2d$W5N2v|>zKn^V9ft+!H-rMhT08DtuIMIW7M_XFI z&b*~1svGvA4`$>pS#!rB{!ZP7%<^@0-tK=XLlAdSyT_Z{-!B0=4UX1m4HbN#9MY<&R&t4!bbJ9Ez~8a%5fCl}P)59E#>@%#Gf`Z}z? zmv&uH$ai$>fs}d@vv_(EcyO_aTrcYHoPqk@zM+A=!y4W^sY>iT4BRa= zT{d2bDHa_3oy`%IGZ(b&=~g`*B*cTJ3I_s}9i5wZjUDHUJWUUFWwg@gicVn0=7v;-q600DDsnAP+?Hr&i8 z3^D>4l0MC@`h9l`yl98$*2OO}aXh8u z$-4SZr%A4GuBS>nz}h&NLYKuy>4Hf(gO}lBy;LDRS*<3DI?MX|%mb|7cvBxt)O9=# zAraX7EIrqOXobqDO7C(TXgj3fY)otOSD@o3v6Aa27-9r~2|)ce32Gc|7Hr+J6BnCI z1>^zh`XG=d%*Eyn`e4z6>g}4KKi&I{_>K`q2< z2rnQFsDZ}7I5dL+H-W)TuNZGD_9#qV_JjwWnj4hCqKSE-I_SYd%Tf*>(hBDWR>hE> z2r8^&^N_TlZ|?m`M9&V~Ir5C8fxZdDmp&KwkwZm+z8>vOET|Eu4Y2~#*ID8W!El(Z zV4jJ#Bb+3|#!$52=_JBg>%+w3R&3QVS+K7e(%|NPyIC{T@ATEnnwi0+gsIj;JyY;RtMEr2)&dW>#41E zvLl#SZZbZjkjJ`4+5`(5a9JGZYxJ>}#s#6fm5 z3%!o%tB1!br16ZSvJ3WgX=~s*RU>f9dQq8K4*N2Bsoc0^oeyNN8 z+?Ljk=F|n_>g@Tv9()-FRl2ILy+5eI1j4cg3P=n)+1)zHxs zY77MR{=u|9g>}&AvV?Pxdf1Z`SBT5e*s!r9^p`*>wYT0>KlkWEQ@Evc6SVlbr&nqa zL|U5Z#~zEI!2U)52H^s^!JC^69X^CtWe47tZxIY)d$-1T-6h9}e*W*c^-upRUfbzE z-*(;_qADXf_|+fB*^HO;{+FbG_&-V?dlm?p>dc_XI%nBCaShST|NeyqV9vV(=QQDR zDVx&v#V=C{)pY2|l78e+Q@tI0rg$3;e3daI+^0!k<43&>eF!J~!6}Cp62Se}NoI~X z)d{O{5Yqwo3ey=DTRK8eJ4m8a$=*qjK(9%TjwtbE78>}jiR@i4ZQ%oRkQ;*&!Z|_E z8K+8tL{&$9Z9@NE=Y*P*uqf*!P>`csV}1q8INt1)@I#%}_A^NhM^0(l@wghN&|)1+ zqI(=unFOo_tv*e!Jnp`sh_hRvN4m9pYOx(W`%0t8DWJoR3Z zLs}W@%x5Fn^N|GGU|U0hV92zS=?*f#P)A?;YcAN!2LHDcPV3L1HEqI%Y(e5O&&C3r zfCMPfV1FQkvT1dx6n zyNBt@4YESmgov((o5-TcoT?qb7C?^XbP-0l8NzjbFR%z=!u&Zee(C$G=LL#GxCh`*xLk~ zH#EI~h1MHYDm?mvdu4ieix{^eJmpYvA_zTl?1MU(e^RvzRjpsTLiWgvB}AG%J>zX* zsvXYeKAui*pr;u^+6L=sjb7Py8g^9*4G(T21e<;|H1zW^Qf6Zlki5gdj8u6ydwLmK z3e%H$RG%Cy=@bynv4y4%Y(lUYBmmBkkRIUxqXm$lK|hZ;b?p|e4IBuQlSjDkoD^@t zWz|an*yo3S4%XOeNI&~?xH@py{za}5=<2yAq+k9C>EeUHldnqu(ftdbaX9GE)ofF{SD3*C zBzZ?jfhjPbsgnblhleG|o`P=PS^`?j^TE;%fc8NDn`ChiA@WXAdwIwcqYTjPCg4nT zD1S7qv6WNmTRfod4w70d=8oU~C{u|g?tr~MRSuOI)se?(kR+ax1fMDa$D|TI`tL20XB$gX0d+AXrjvka6XK^1J<=YO zn*)}gWak-o7Z3qJg54|rtiw1{Jutz6>G}+$-D67Z}PBa5= zV?tX{^AI@eoPGA(sOzwkW!Nqb`A4S?wO`}gxlX@Rk9}VUG9yuBnZ$bSjalaXOtxV? z6C;{?dyrBfOJ(E-YBWzY^DlHWBEbtSIFB<&ni)bBv=~NJx8lIm|Dh1H;1B_iMH^)P zkimq-)muuT8>!KZwSJP#6f&217XfjQ4A5Xn>#O-WZ|f?yg_A&j~uYgg$|1YQV9<&WKSf5eKLu6#CpQ#A*R%2R^|pUp zz?#wB6YckBUU_CZY&y4Oa-|K40N$vCQF3mV{^6=e<%MqD+()tiwb&UX;4lOfk7K#1 zTJ|22o}0ieA@hEM*b%kXhZNshN20*{p2c~b!^|k|dq8{(Y}_|9z&adem@cR|2SkhT zdTQ$ETNcO+X0gQMnSV8{|NcMq>$&gxt8KOANh-7-lYa9vykFjn1+%~Xi;}S+t%6%0 z{i{9xpY+>f*{pu%>Q#FyocQhk|C4^~9sQc=y%sKCAX&L3AJ$I~QZ!j*Zmc=%1lu$A zT0q8(6Kg|b!G)H7?MhHzfN|S#0JtsHz>~D875bLT-^93L5#)~Q-V>*~Cqi|c1!`p0 z-)m?Fl4p#cLC;nM zjY!5^`a?b_1w|ok`7ExwrTV8r)ktOt9=`gVUsQe`cSaz`1om50H6pMVwonIrM z)CT3M(i^A!kjE_Bg`P9Iw#B%mI%k80RD=H@WB`pe_+wL`O&INo_VFEz3($N9@_3@6 zM=eq{`jG=XaA9o^CkT$ABSz?IpCwdd=4DzUFt(>m z5Zs!aU)*tf2?RW>>S%4$r~sV=H2XO6Xf^jqf({;<#&Ryod1ha|zpnc_kl7&3h51D? zAFl=nXWHbBcE)0iLi$;@!y@59Hp87tsRk}z!BDt_DX7usE6{#hVC@YStA~^_f+ImV z&_`eb&t|b$AlptX;UC9Fp#SDEOBpmWE*iqIo&7eUBTJ>z=ptyLW$|)wyV;D!cx=+V zEwdr3Op|Rb07a~%ggqk=1(Tac14^92S@EeCp@{ElGZt3Db5hqHu4?TW+`-Ql!L8hu-hjeCzYM#r!KT`1 zX>X~)doYxo)(etB5KUnP+Ji=5W_Ia%L=D;vE-0Qt2alWrcnLk_Xt+rt;= z2~nYt?6>=IZ^2XPnYA@NzJ;?4>-lcE428&SuW26=#8A+w<5bo*?TFT|98^^BCBT@a z^eg<$pBiboB z&m%2)0}*v*g}!b|n=98b8fNk`Pwc|>Dd}28Ht;e~GExVKE5VUI?TuBme|w&}X1LlX zNJ4k^=u?qsc2Pay{!_$D)uuaFu#xiQ^E?p&mtfJ^izpl9#r9HeXPI*$&0I9T&z^E| ze#FAqYw`D9Y8Ch}rg6mA=6sT-w`@VnX13XR72`3=4EeNSxz+-)Y3wF@uz*@M;WM|` zdT<6C?lFSKWz`taqP0odxIOpENGc)Z4+o|v+dp@=tfRN;b=@4+h*ze0t%pu%xc>yEzhSKr$hy)e6`{Ace`2|9lnBmZw3gZVuI+z+q)ZqM99BRkF{k zi{le|<1meEFrrn*>txf*K$&&zc{b%+&gjG;n*PV7Lj=8E-gB5(I?2$$8InoPAzfQ& zC_Fx{@dL-`4_I{jD_%UVi)!qlfBuk)2NIh7zExf5r)+u)uN;T&4FcIO{jEE_w;?Ku ze?&n08^6M#%#ty!T82L0U-mM_)N38OkrCa*=uSL@WyseYcO$4lRFQg z=NeP;RGewhmy~RnX*edv-92&#a4WHi51b1Q&Wd6ZQW?^fV4ZUUj9)o5QDMnr>|Xcl%YU`BHha^gJXz&(X1*Cx1F^;RXpe(D47Cn(;(6`AEu_ub_t z_{?3uh3^<}A=QN0MP+cVHzr~o*sM+(V-<&0RW=sEs_hnsw2gELW$;FWI-ju$g=VaW zL%WI|}Mt}yA{R7RW38*$NY8E)l>xEF+pJviTDUMW?{j9JS zyu?{1s2>u;JU=J#l!8!u8{*V@`EqR%_5IcyTDBCEOeQ)^jsq7!)2|qU!H4$Za7_mu z=~J{{iCNW=4dxpTS?|{^>D6#SF_xHS$~0j07L%AJAZCZ z1|GM6Utejvp9&*PT5e^uiB~7-c|15l5xO?hsw_bC_YiqLDG?;-*(3!5*)>=0Pv^!4J$$1qf(QC|j)Urklc!ma~%YSJp86Ml-LT%m7 zguQ7!j(P>Tl#84=iFIvvmxt?&SBb$FWAscxA4x)^tWHQZ{Xu)=_a3)RC@y@juF-nw za&V>(NnHKUtqVi)S0DTT$fNzsf)v(w-)trd|6X!wr+Ta&9=2NG@e{QoPxUpH>hZIJ z(7jqm7%QBHAdy(OgLmU|LZ-E&`^{Pl=I!x%zwPlfTG?EU9kmgdg`Jc~#_Wl)l~&e& zfo1j-+EZA)RNoZLbv9)ZXJb){_|xVr+tY0mdp%Y>U2mx?kh*FtwnII?avQUZS&}?b zfcnsR)Zb+of^7UnIE;hTZ_d!nGZjOYf?#p>CJLk9gi}|A_UZC598NZU6gSiZO_9#b zFdsrbYbIjgV`xG0{t_b&<>gsuO|JD`eb^>%Lb&&G2o&6tNY8#Ne-aq}5O5-JVFtz~ zKUl`6gJ445*hh3Y79FBo=3yI9jS6c`>iPmA(;eQm7D)MR7QgPI>njmAr=rr~z7Cw7R0Skzafbs`$5)dqaCz5YI z8ipq06F99oR$5y0s*J`K=l849kSX341VL=>YNNdL*%CE11e_Kgow0TwZ6fe`L^BUV z0vW|1sWwc7lYV-Lr30_UX{j=e+It*$Q8G&+cEp)91Km*O!Li3s`cTL}fI*YWyNAtw zlsYL7-d#QnBsJ&kGZNyYT+fD}871jI zuJwh1!du@(jw}mG^c4_Oa(IatL;yan97mu~)+6U%Sr7DiCZaK}$2`oo`v0!CSRv~C zjiZ)7nJ}qi+*woOuGdoiBZ~fqzCeV+-uTvUo4x4=X7^t~E{M046qYm|#e#e>$2MTa zbMcT96lC2Lt*T~@9I@8^RLcS`&csQHuBDu!3HbOzU{^NRd!dZaZaHK*y%abP*IP{SUfqkcs`gJkB>TFidTe$W?NjyAIlt#pzc9V zjXd3~goZ(+tEwwl&lGqQ*`JBSIpkivm1Bp8C{vPqIuhgxq><@?prbXYq3@UaaKQVk zP5oXIAV@TI;1Hsjgy_1dN&2n_=t1Uzoj8fHq0fkGvoH!XZ-`u%AjWj$Z03Oh=fVi% zLI^>WgGPUoDrt6xCY41Q0Slk<9JK7x24vQtu7g#}v&#jlo91eYRy!Iex*;k9pmZ3v z?lJe)8A=IW0c6vZk4Uko*eQghVLWBHq(dhK`C0#zbrd{l{nLkOztV5X7F0pDmq4NK zhvnGABE?b@-FY!Q5&#YpRhCy>XtgV^vb>@i8wG0YY~N)&P%5|^1(B(e^>%q*yIuGA zJZ6u;J5gtK%wiXV z8Eu66TnlWN-VU1DY!jVagWx2h%S4CtNlMUFV1}fJkKRhvT*S+fwgQp0_OTR8P*|Fq zja}y!piX5WHo*R23bs-4UcPCogDqe3q~}_Dqh4G4uWPOO_GX%sqHT%fK{im-FDoIV zXct-HLp5un`hW8sX7_D_wRr$y$Q?*weGX@)k4=6hup`&xWJe>iMDN~@w%|F!RD9-n zO2+N*7!i2psO9!hmk4Cu_P;2GC$fox+O_7U*!{g8>#8B@sinpYTDzFU^W?&Egap`+>#%kg1Xh+Ae`ohyt&^X5%db7Na?4s5}>ASxYf7&Ke!oQ!qej2qZ|< z7kz!#Ia=bzk*Pt84TIG5WLR0xY9Pn;R@%JUQa~7@Fp^pL3ppu1*Esikg8H~|42tT> z+?vunV=T-z)+<&ei#;Z{WVu6MhKG-mqr*XjV!yybB*Q_TOkxds>eLk1V5oy@K(4H~ z&I-JB5MR2uxQAeTs%V>*QS37@2aS$EUL&<2XFW=^%oY)+j7aiT8!o#Dk%u!Bk#SzW zh|g+%T4QC8lv#EQ-RMhzLh04!0Z*^Jv)27RQV~H{HAD&|-y&t??2cW9XU?ND@w0Md zug-{!tK;guMAQIt)})`uP>tgaO=O~c&q7G{wctgOJHj|AoR{k|4&_`hS`da}LH#ns zIKj>L?1WuN@)g4o3Znm(o^SmnJK2Fr1;i^!&<0`u?Zd7xfwGEhwy4@h2BG{a5zFru zZ=fc#iZVxlO#ImymJZE7Kz>R_SCd!~qmShAd{NR`mv1NHYoXv1fRZFjetSI_d6Y#% z>vN(dEg&yCf_@;t^ulUbnGKdp9&2iL*q&YDjO(Zac=gR^o z(kw$-YC}rDO|BZSqbPYa$@`+9JHB^e14zq8yOA6~YRGTX6Kn>^6;VHGtEeR!hEk0q zX}&?AMI7StHWn+Ac z>u=tH(|~~@!fs(MWCw8~aa8tW#M<%3(;!i#52IDcX4hZb4C^;!Gg%Sm7^ahCoX;Rn zMEE*h)MwdKr9?82I+&9pl+1frQ;;3vF}xmNIT;%-o4z)A74K_3c(N#M!AYGWj}*sn zdFZJ(joggV23qr8ikj1z%YxC>0X_AQ*TyJm>7PCbd8^n8Sv$%POTZuj6z3z)JjdG7 z+I7ZqWCCU}++D$lVFUu^dwCp)53jGjgd&Ee0t1HWrxxcu0#I|4teXk?^erCP6od`D zRuP0;MVIwV*6JW)3w>RCh}J+OKzfqn7$PE@8Bn2V&O^n}2|9ITU|fUjE9s;&B9J!J zC^Q>(wbsd)2rY;*N9kG*m}+xD7?E_R2-4{zC5g&Ufc=NBXR@F9;SA(4pYPC_AgzdmeIEp>QraF*4U9t<Tb3IAjJ+aezlW`#VHamLK)!*SUlY5L>`NU_Z4BI zPGz8|eI&{*w%JUUQZH>QXbIy1_AHrbbj6_q^PTo{+66a~1P^fy%BVJ&JVG$Y%jXAy znP8R;cZO`s`pvEg^d;VU2W9xj{nqe<2J6`Z{F?)H8`6in2kd~iH8t68ywk`rMf{ig zey8$$X*+)QkIcUGUbBmLnf=LUP!M^Y*+Z8tL~hEb=`qV`t#cVA4>Lp)=j_48H9tc! zGSvEP3|YyOK*<>iGz&>Vu{P+4#9CvHQyg4L#MRIJp9Thuh45sE(z8ZO&D&2)p>7KF zhYD=G0HlG)-AC)4 zewXvYFsYP8dZ8&8JFPv{Tqz=)Ngy4Ep-ClmFg&!6NYHP&r7N5xH^UmyF6;~9%*M&r z>OU{AB5cHj+8T|Jb7Kz8A)$p_h%=U2yDI5Xzd#>(tfDzT6>0glhr|NFzxH>cJh~ux zagJ%Jq=ID;F#73bsPu+6D}!dDqoh4Rb)0cRd1MZ;@kwA-6iMRbqrI>j1wqCs8A_uZ zLkJVuK36A}&i0bd9x%Z**JmD}$yowtB0)!v<(n?B_q<`7?cKNMjONEusole`u-P!e z$hAbK`iv5J#8^d2xxT=Tr4N_7za`V2h9KPom*^k2QeJJ)qOO(b_cK6AN19rRv0)+- z_4r^H2Ee6Z{yHcRABOxFULG);7Y|D$2zh(Tg{j$}7gY|iht!EV1CJ^M1wBDxd3G#D zUoMp5$#cb(Y{r{P<-KAMJ2Jr1vm;>9OiCY%E`}jfv(6B1YE|_`7{@|qG}*O*jqqgk z6~m-A4pE;Lhs~8aj=U#M$+k6PP*8GaTDD=M1IUSNrXl&dEQ4(x}26Hi4y9$fcP*FW3Yl%mze-QltZsx zT45EyfN=)>cGB~2Gv+yhjgX)7IF#&uh zhG7QfDD&imXQE>6F0^b32?4>lO3c8AqK}`5E7i>>))gp?U{Afi(V8W5B!V;)ebhKl zSB%X50_Ni&#ez_gB}z*940E6@2y2h`T6%Ua>_;L+3dw`y3kmH=TTrtKG$>RkNs1!{ zSTU8n_8cWc5+M(cVN@|>GLpojASVHvfsGl3+!UZBMss|Ek^&Df$VdO|qwF~_o0;!2 z=4awiE=*8j&XF9e{#msZ?<%&5T8wKZ`~Z-T;+@6Taczf{>@2al%sCg84XhhDoniWgJC(uKkM ze9|yOG#6%(Q-NobpG8JyjC`1SDHZzaEMpFhGu|UX%?3qWmcUaAr+CSYK_bEE#W7AJ z_)S!jIoPled7LbahoY%O3UXK&6?K!AVzm~SXzfXiWO#Qma9bD5uR-!(lmy^~#aW~( zko2<1RCpaC(h~lyf=Ou;rjlz|XxPW^cpVux)wZd;Kwe)O3oVI|Xp+}pFR^@j(WGQm z+P^nmZ1?fm-?;Z7`@=_mV*80Wds)y8g6a;nr5HI`6OqIR$*GUoH-<*Ao7UvE)^a< z#)D3w%1C6$w4T#2c#2lkT_H9(U>-_m<{?60eo(b1f+DXJX+C6Qu!q$}-bvPpJi#Lb zNh*JwKxICS*C56t`T+KvMmY#3;w+YV9(k+)N#C?7^h%+_%fKKn&g#c#VbWwn9+AwAeMYQAE{g|5s%Ya5e^Vh`jNqAaJXj}eoh zM5_e#e&nx6S)|dKJq^;w94ONWe==_2_TiIA| zO^?w!0rue#G}m#U25t0SX!(Az5%F#&hM?vXRfUkQ@{+sqQRJLX1f@tU4tAc-1oGfX zr5ruN1R}@92XU2T|P^fhG(-Uj}TM>H(W)&R`DR{gX$Q4U`yGy%zs@NFw_w zj7|jtWL+aW#KPb?DJbkuO|=1ejuCl9SlG~uleAHxrY)TX8lB}lFf#HE6Xf+|u%w4L zjUn}osPW|7_t=7Gn8YW;}eWtU)0()_vicO2W&In~I+V-b0W~8xf0s}Tj z{TFhC_824B7q?#IUlPEJ9$2{&1Bho*JH_>%^UyIOo{K>o+id`4ac=MRJk%Q%1}me`rSMnN|_hh&6B9?>w!t){rMSw$^0Glq>7m++#I& z)j%49@J6n5sgZ?Ots&EmQ^d4>!-aNW&p|vHP3|O#Q92HJ8Y2Z1M)J5vv_F`%+o z6l2E334@6zGnL;Wc}(9R50lt4gcvXRpJ_sWpS6<%lR`C<3q!nmZP@?-KmbWZK~yA3 zsoWI0x?)VGVf&3yE8=B=YocjF`?#^0<3vY+F$X>PNFXOETnxt`M5Ockv|(DGYa&Af zCZ{zW#1jSXl(=vLFLJ&IJw-auLVHAcM1om5STxLd6%$dUA*40|l?X#6x&|@phn&>Is)0b6EcKyrznc z4^S&~lzi&TecasKW;Y$`uqhu!!dtr#g6^dmYRKw;Sa0>;ueViST4g<#^;q+5%{B%L zP>0L?oy1t5jnAWE;H)igwKmUvHqqKg^h5(%qOY;8DQh1df(^`k^%pT`1OcW|mNIMQ z`Q=tsQDZ$Lz4mzf9*T*NJE!(UAD)nC`g`#xX^piAxj)?wYi^?=OmXU zT|yBoloQLGDX`+9Mw=wr8mH-G9EVRr2ZH(1X@ioNR|TLjiE{|^5JY2WNaPDF1o^2{ z_JveBEXRTE5~$~UGL#OW8#N9t@&@G5=qk?ZjU;gdff&_&IfKYDP0^%F`2as+oC32L zR<8dv5g$0Gg9rl%Aq!neU?62|0-!X#^Q?Cu(Ku~oV$^H~{Mqb53x;=c422HPZy+m* z(D#JZk^?UaqxtAil}wyzYV5QJ@wa}ubinC!1{1M8a*&WsfH(Q@MC>>@82V}UvyZ(0 zy%5hb?J=|>CDnIE58iGjhwI;&X&Jp4&S3RlglrdiO&PhCTUuQ1Of1GHKl~()JJ(nF zvn4*bvlMdv&;PuP%VB9hp%&0X4?b%5-2DrpFm_=)77qqZaDlLAHOdqlN(?=heNw&& zh#-y0sAhHnJRV^KlSB}s5Fj!!O&PfXy1DjSyfM$gZJ~Z>ybv5bOe8xM`@ZTn8bte7^Qz%UjG>B zV~k`*x{ZO)&Ed(aW@Z6SL@fkk7J#|Lj-aw=c6pRipn)ab;O`}f`0030zjR*R*Ed6 zK$3Grpn{sh;iVt2>arRK9l4V~&41+e`H&;K=0n$5(_5PC@a>1`zxMooS{fT#2hrlEH*ZFA zi^SE-bZqVJwvX-JO|25~yWDXdd{I%iK9`q1T^09NSp5&`iHHNvP`AFW)fu+Apoj}Z z7C1{U$KfDxy*1~~)aJAybwHMyrp^-7%R+RG@UqS{zqQGvvazb^t&Tw&-#*!V&{}(0 zOZXCjOd48N`Yl>I0-TOQ#a>zpbyq+hK<)}9oZxKOa> zLviS|YUt+7?4 z5_FZ-|4eWzYoDwjUxDp0X6r7w$Ugt&FWQrPp0bXk9bBg~7mc}_#y>Jxj>Mt+jd6Df zfo?8`ey`uD)@(5nTWSR1)?05~ST(O^L*}9uJgon^<3Fvhdw_1mzpDJT^rVC4hX9e4f!0|Sax~dLutU_i3?&d8ZE3Ll{z{;~ zF!EDV*8Rl8RyZ-|3Zi8I%K;g(+3}0~xvn=^DwBOewI)~q-G9m#sY#>N3=4Sz$YhFI zo0Mo2*aTc0h%<-?aW-D(47A!w@&ZW~v5Fw&eM$j9Mo-2}tjjnH+Cu_61Lc1|MtF*I zoF-2wBN<@frh&;v=V&GfF-6JiGTOjL$usn`p$qeOc|R6nanTCx6E4R#3mhuLCpKqD zYA5U=l@;X9n6$G268OL=iLs=W(GtF_v>1gB36}C7&mS70K_JdV4$Tdq@u+R1#5Ma+_K0qjivW zOMc7GuELnmcg#6%tQFo%x!@QqVZD`hH9?E|Dn_9QAJeduLokrjQIAocdK|cXaNr0j zhbhaRr$1m)C=|Zbe30_6Tir|uvJ<@^M3i9eKZ5Gq z5LvjrnxGhykxU9dNq{S&QUksa%`G!ndN@pICs{s;^(Xm3k%CaGb$gy)` zy_3T{Z-LP}!#r00IhC9-E-bJjsv0z-9PVqTuOCPY@SvJt#?d46!v0gfD?B`5>D~P_ zhn6UUX!bmhcbU^ZL7NmY7&Y-@ndvqUJgqu48M7G-P;h9}<)p>1oB}@VrX0b82yp79 zKI^}DpRMSo=Bfu|gAq?ukp^f0A)-3~^=MhB@=RfrhX&foc|jIoZKo2wIoT=pCJ*yP zd%!GFU=puV?B^J)=^L-V+&=dEAF%uGyU*pu&N!@i?53)yT?7xI0ezSB9XDh$V&V3% zRozo%v4WTd2ZGl6`c_+XvQA}AoXTTm$X@(vKb2QL#~z!&IF*!_*tKuI$$obC1FoG4 z)6&6uNfyZzN)!pA2p5Dg3DfYTM6vad$d$5!#C~Uqf|NK`%kta<6)dD}cDRZqL4k05 zH}IQ?6?kDuv>G$Xy-mPg75p38!aV-zKOMY0ZxtlRh9`z0`f^B9F;aG1yh5MolA zaS%FSTg}2!l*i~iE1d@uMPjM4OcEbfM415-N`_3@k#k5^iSQtgb5^V{pj1UhL1b%Y zfC9TPtfRmWInx2^z-ZzZrr{t_*eo7ogkCC9Cg`TkYi;?81{xnOS>^-N><>_`3jZ<2T;MLUWtt1ZiR|Nib%#^l9h ztb%p=86u-cN=xnE)~Lg6f;a4Ma|D@ ztawMU$*AdfO>b_p!3zc#)D|QkqzQKpA4%qz*m%c}1^ab;gLLI7{4t0#dFiSPEYX;- z0|&aTwWS?4@*F4w^BjZar>0Sb!Ws1JlWM$j#uManrM?rR=s$gk9QZg<4x|d2h*<$S zw@{$KhG|7KO#Ntt!s1NoLRkjRZ~z}59R)iOv_$!C9~h^|ArrvpL-PQAl7s&01Sq zT-%nVfE0CqI26N$|)VKa6gs!L1Z_p>al7+sH(?lmBs zVCb}n<1B(CkR94!#;f3o0$cv=<#zGkUrhZUkm-$W)^vGYs-?DeM7W2wW-bCvluNDo%*hfZCeIEbAzGrVvQ727vCVGmZPi z;6xq|CwF4Bi`>~1`%x|=4`koQXeUKo+YoDe95ym-ZAnB>LX?0-4EfBT(7F%Wt?zmx z0_Z_|?6JegoX(}WV{)c6w`82=(4y_zh$_$tj*^U<97`XXU2>|%>S1A@1+vHKucW29 zPD}c#b4(IcI?hdKxcz{3)x4hU`O6J!Lhh+0XHL^*(3f z&?d52D<}4tBC+(LbgTVItySDtVKsNw*x-eO&Y%si0%}uKuP9Ak+bj5p6YYev!*>0} z*V)FYOYCqbefTKUAFm9+P$X9j$}l|A$tDWB5PenUlBW3Vil78yMpGzjplF~QUDPnW z#wtA3bYNa#M$Jbf?sog(6y_MMp?BjrqI z=V=>3i9~Im6xC7X=3vno9M>3d;~Wrj9nssWH7o36HNbc zYIM>l-VUKQo(9IAgHD?g+cPADlO(Z)Q)){}#RK%Hu(<~s>=di`O=x-EyaT;D~ zHJxzd=t8a7auE$It1X)ZbOz)Ny@Cwb%VETHPsA*JicP+e0_6{U-~;yX!w=hoz$78qKK*A1-mQV-=dbgV-yUxw#r)zyyO*h8VJh#@jW&j$x8=jP#l z>iLSir0=+~ms&i2ccu*3bA86eas%Zj_P%eg9r(=yR{BV(BfxC=^DR!1q3!xM>$tkZ zDW04yYV>oR>zVkSPy>xj7_}RgHM(_`NR-& zQLHrQb(bYr5RvFE?8l6Fp%qoH1FdOxj9WpOinZo(4*fWmsmeq1IusM25`;5JjxLkA z5FJNiiuD~F1{RF4?wCI_6e$ZmQIU&u5LHW-;9Lu|dQr zZp7Su>m}Ag}n;&^t zfe*qvvv!oFGlLgbGE2=0hAl+x2mD}iXh=H&6^NqCBi!Q3WZKJ^sh8O(#crC^Stx6` z>VM_d&}17CQ;UsXo~7vif)5o*M5Jaw{aTD@GDIzzBz4qhOot$k`Ynx?L-)h#)eR_& zNLzAY6AS-a^X%g!UeO=MSDf!-wfvvTgu#iYFNqQuJfzhdp;z^1aStyaLpc5<>e269p&;xim z1)5=mhS`@%6jMkI6~E9U$(^`GSU_H)EJ@@f$bE^?=)qeQ^34 zTnuuV%P~F89wbuJ<5|2SX^1U&E*)BY!{nvzxZ@5Q0G3)uM~B^V%Pr(V*18D#WalcZ zzVa89w(g(T+0Xy|=dMuG(SlF*gqQexEf!ZJL}Vq_p<|?B+;k|~lF`%so?{;9>+?lz zdd^upIB{2#h8Haew&2MEYxwU5N0aWlyvy3JYj@<4c#y(&^0cpX*iqM2YgTPvriIIM z#3HEgclKI$dxy0iX+z|j+z!Y{K5XL3+&UY>fTRQad(G=#XO~@n zH3A4R>ztzBns3;S_8cLKnYX@Zn{7dGAssagG=6A7gUZlogH5$&Q`VA$2zrs_7Z$jD zzt9sOPSw>{Uu|7oT@KM$YDm#t$YcM=V97vfy*c<$zvn|r@k3FVqBKE{%8#iy+AW9^ zU*HUW|C(Vfp3XIs5m+5kULNzn^c+oK^&s&bO5_k7z7w2+bG7A)HW3$bv7by-&=eMB zkfYZgbw$=CkCfQfPi}R|`@?TOZ2f3F&LU%>4QMHy0(bG2@Sg=%Et~1F`xJ&&pF>V~ z`GqTO3o87F_8zo@55jQmrqUDUuou}mmAc3wmD+wb>Kd!p-)KYQ6eEvOy5gbklJvri zB&IlTmnj4FpxV>rz(l-{P(wOOw5LpWIckfF!-jc;;7jcRDkEqTtEy z&ez)d>ha z!`b*p`-)o(TnC&ZvxHXRKm>!l8& zp_;UY?>E@me}{$pMUSb^)R8wHS!jre$1QTmEB#o6()BsgFbWr5e4(vayTW!qyvz3e z@^Q=WgKSj|YJvcP)IugF+Z_9`x@-fb7`@gT-)ota#`ry%);l+91Ed5B=cQPJ_%C@b z<+;63@CVR6RZdI<4`tYdeTcxNbOHS}5DVs79y0{ekJNweU?LS1pUUSUN+t5>hK&V3RWW)kwBCh`Jn3EDjdYM!L;m+Mk) zZqZA7sUO8bsW0_KPV@PCZ(YB|p`TyqeB$A_9e&4QYr6$w_CT3yE3x&@wmQ0b^P8Hj zb8Dw7+H}mmQ>xFTys zb!Q{rvDDXH_g0RQBBV>V(Fc#b@>BP0r)vcSt^5kgz{rtPPa1`poYLRo=)kl+ZUUo4l!r9$g7~^3j`6D)?IeGIRiw4u(A0=aaF0 zF^7;J?K7jJqi2ucaqPr2Z{!4tTCe$2^|LA)TSf=)D%hGhNTS}0Y$Tn~33OfsGcL}v z7xURp_c7-U+38-nlRU2gh)i$>)0^olV>a*dU`i_I5P|v7or^n4?;KvwB&FmS*eD>2{m2 zSHgWSV50)m_K8XPYBy$!_jxhm5|#SUJE%!RtFmx+p)LQ;a_3nKx)sw=(XU!`=dqW}d(H#+aqT$7$=02fexF^519GfeyqH(qI*Z`cO=X(0!8 z22T0-OK35C;R|0tEuobf8T52sV6#8|#54GfHkK)r7ryfOubeiGSRSAv-SqNwyE%HZ zedL!PaqOyl!uQzs0^hUkh1)4YM?99OSXBKJp&WgbX=-<}aAOE<6Y+ozJOrPCF zuE+YfNqT5-9W`lCtW}dHeaG4#)mrc7UdMKHHEC>WulSlY=6Rg;bj|hGIqA4ZfBH*X zg`!8HFN>TH1P#`$3OT*xuKhS$5*&^q0xYmB707=A0qztM*se_zB!G}d9{Y5GHqAvjS*xgR6suPRsj~$sYJTX@`cj>k8rHVn)M{B2p&!qG z@!2&Wq<}Bw8IgxX{x}=Q*?E_<@k!2+_ejIrdgEK)Y+w1xSFF3M8?|btFh)Y%WL4Oh zPE$WY4KpyHGUyW)U<{)oFDNmU=t~MBDHuC1MsFT3F@gs+45_2`@(XPX${TT#y-TsV z%F|Q-qW69DeKxe58XO?b(>kI*Xo5Lu@~_k!t#4kdhBm!{?^J4mD!4)udpxP z^+g+}n0@c2f6j592tt;M}|}m6GhWd>0)KrW>5wQ)#Tg8 zYcF4tNbJNb5rBHE=8d1d`m>zFX)XrA{HMM~Pdtqm{$8i{jP?7xPr8A>e#~s^LtE`P z|Km694L_iJ?sppPiy!`?ef~qAx4sgDPmdiRe&oXzN+lvae>jIk-nI zK3r;LkCfTQ|GUxUL)0U!`?78aHEG(sQej6Kv#YjUWep9>?9Myyw7vWG(lr8NmS@Jw z;;qN8)_9y~Oi@-QO>^VuPmKpCx1mHPmFSISPR<)aU(l2p;6y3vR8&^lTi*FL zl>Nz`M^D{JRLM*p`${cpH-``mNc8tZ&wqCD|2)PmPSmzkhvtJiukU;JK6jr*try(5 z7?sJ;rN%fftxuiCX>KE@dj97lvQxccFXHi<=;@F;uDRwKyX2BfZ1>Jx_V~j)Y#KG~ zRBrkVBNc^^xpXES$i+PJSNcy2Bb|au5k=%w$%w^R6}P|T7RyE^NnLQy#*s!B>A7$7 zUN`b?5`*txJkGe4@j?epe(6qVw&8^yc#^-vq_^#i%NfsQth5LG732L3y^jvPXFCJc zFp`tB;b7dtC}Ny&Jb2lIrtv5L_fPCopZ}D-{i|=ckN@+>ZO5h^_L)z7#&%r1gKoWe z+T5S>$FE<3MT4e$qSi4gv<|n0T|Js|X{*1y+O?CBQIi6{JaLzMdxc#}2_clintd-N zAdf!!sNHqz|S{1gu&uT&)5QXhNF8g9PX8cwno^lsc}yZ_)1 zkhyxE(v?$u>t{Y(_f`^AuGB?H#tG#v`kmBdBwpULrN=$yna^K}pU)ezrMRlRrXVRT zigZ*Uwq1Rdty{m|x=}lyVG=*`(8JbswBIsPiOTTg@@7L6QZC3-srXB*sSze(FhA37 zxbAW*D=Rx|M$BCfjH~^CaRoz$OojS)F=WUfSJ*y=oWa$MbcPJwI77dyW@Ixu8C?v` zFnMNc7=4T;2BO~dwxM#Ep~s9d#9LX%(BJo2~BUhgR5#C3WBKi4t- zlyMVdGehSv$T-AMvhhNOgiZ#qZw*DZ_0wDJ5C8lRZR(>__KDAb!oG9YcU+BC(+y3w ze{R29h+2%l_C7rQHGg237FlQ#Xx{zt-R6rRoQnBH4F!PmHUTKBse*WagKe2)CUdu(GKrBS5>PUe{Na~!NPEew`}W(82OhDJzEKmT2g4qs0h)`5m`0!jFI&ILuDbDBikx%L7`^^Qe@qrAxTe`p z85N8@3>hgIo4;nr5Xq^$hw=N2-(|=!UB`Hev5Zm1kik)OB}4dG#-B4TWjw*Snz51b zKE_)a`x$!~n;7!qCm4Fa!wig%J;~5x-o?ePjO6u?BPWUYRvj`zdQ?KO>Ee>{6KPp9N7yiqIw)!ipt!rzS`&*!vS0N-DRd? zXBjd@WQ&K$Ad^*-Hs&2WACWCylvmSNEex@vbV&VP$`xWC9o&Dwc09Jj27CH#5|LBs zK5n_{O51kr)f72Xe{!sn-#zhc{iAs)L#7By`7T8^`kf-LPKJ!x7~_)+85~7CA7aR$ z$Z*NXDFVx5{E8t1_Bf-E@!O2ujIS_c{A4IUz>snK55}7qjf{6Pe2k+E*%E>yXN+XX zPIhR2(Ru5T;X1;&mZ9h0N5J-;KefMn$6xZp!hsaC{l9DepIzs<&f4GJZom8X-?g^e z+AQybdG_7|?{$qj#om+0sSPO+%eCUT2gf1XPHSD~{QxpT6iX(|0mt>NX)tefQSx=h88qr&+BTEE3uq{6wL+eF0{25USPewy*4s3;)o)}#fT7} z06z%k5ag)itmq`lXs~YVy$nTGyBObK$WZ7s^i@NLzJ?is{uU1zKS7N$c<*4yFdbx^ zcr4C)oK1J=Ir^Opks>j@t_#g!(7J=hfKm@W6$!9ge&cp`yN8jI8X2ZoT5FQETwGe>M91~>85iM3NZUT~ z38Nmw*d)%0StQ8aiyYCSGve5)i|d&)R6UsrqE)(~+QhSQoHt}=<0_xzJ<@3GIYUFu z>DdX(&wAdLWFImyWBNC8`)XH1V1_5e2~@Oske+)N71iI<+_WzWp7Wmw|JUTQJQ zspMxFl+Q5~b?JKNh@|qpmmvex!B7PE6UHTsA2aS?DEivQ(Bt%69a;z)GHi;( z{*j?*O2$ah)l-ZU--92Yb?CkI8amc7^36(mOYA3a`iZUQzmpwT1+TKt4Svqvll2~l z^QR}%okBtX#r>|JI;SbewRTt2O364Kz2>N^m62B}m4oxJLX2B7Qq2EUgbV`o3xhiBoK0ziYJI9) zL}aZ5B{Q1JPE{XSDc1z_*_Y+ifAcqgL!S4L*;l`M>d#$*XUOT0ER~|JRbO4@NFS;# zjFeDY$352=xNyLVb{ARpk!%}SM_yoYO)kOtEWYGBa{qBz$f)RE61|ywO&$yhi7#Zoc z{)(}K@mq|I3^{8bW9V4M_y|L<_i2W5V>OIFWytWon~}@V@kfkO_ua4mgX3xi$9~26 ztow^~c1P@v=QU!BFYwNsciKaqhfsKsh34S0iqxQmDbdrB6(e@=od+FUCa6qWbCTd` zzP;IcH}x)vrwVrD@#l}HuYj({B00ptv=BfJzT=?lAy@VDDr@{^qm#fo{FcKu(l~P5 zpq&U+J^gA+_nmUr?%>ND?N(avz1uSO@3dMEvQ>%6Eopx`*QM zmV?%p+G`mVsn$12C+OK++f=*BvNN=X7aF*n_F3P0s~HSMSSOH@H;tv3F^53IU#uayR8Ew2FOeB^J&R=|f?@wk08 z)@9{Go9)s9j2>;;=TQVnA@3%U(KwX-(>=88vQo0_y5Z|AUdZc=^GdRlay7FVL&v_~ z%vT*#j7f%!*eFAfl_63DCxcSV(4pV!xq=_BI`;E0Uv(_LuJ#c{V|tt-GDTE#j7-Kh zh7983>&T!jo*UmDKlpuen%cXu8N0aPV*6b2=Qtgm&WwfJIk@>b7{(wTI#SYn*81Q*R`9F4 zY)hWsN-|T-R}KJC(r&%M7CYRu!w&WrTlEkcf=%7DV?y!10Vu5;f#Bj4yMKF*4UVN) z%>}u(BBRQ(=ChnA!rZBrbkHBs5j?*3HKW?4T7DrP%frC}KZMvEyhabtg%y7~DhQ zrxc55TWE_CmUa4kBR#zVnVdE%zI_$De-|F3%Zz3$?k(ASr(98*jBY-2R4B zeqCB5+BFwmV-3q2p7VO0xImTTk(h4!K)Tic5JJPxtF7j)8Yj&ot-_&ILoQdKja$z< ze>{B!wDGCPTDcV0_>+iM9fc)>rM5gPzKKTWMl>>U8YZeIoIzU(_*Qeie`weq7=OT; z)0!+a8?a017QMM-!j`=*U?rtM`Bj`Z=tHsyd8tgVT}E@u@|JPi|6Q{NKi!|Ryw;nW zVy|cIcv;WGm_e0MJHdTA;WK{dLm#rk zbVFV+yeItO74WSLwP4$uZn}w5n=2OT*G~1kzxq{ItMhMP{xS~7qo|)pPkJp}q(IQB z9MInP?X^R1Kja!#ih92FkGI;;njsUE)_!ffd(2`~cdDoKs(w7vP^`B3w0YMfZRa2F zq|VCcl=qi?f0?UIle5ryMW>^3Yx6u6atPBwTnwj2sP8rJ^>xv)eDHx?*40gU%(i@+ z-FnzkK<~;T<8}p1VQ(Kfz6!3sY!7SiK(WWZK9*+d!U=oxwzw^a;55D)6n$BWHI_r# zYMHm;ZbWm#bJmsCV}V?s)irIl&``DY4#sRCF<`aHG28ZHd>Uk^>{FkDR!}x?M<-M5JN-V(Ag5djj3rVW-P0|d1(vvp(x_`d-%20>PR!H6 z7B~{Ttsqiqfic>%dp6l@X3QpOHrdJy_heP4-;j*2*6X@?3}rB=TYRRi@j`?X`|PD%vu>aV&AkKiP`2+9rimwyRe{|L2e z`z;qQc=P7XlwTzo_3Oxs^j(`JXFYpD#g?YX2@FRXzSh zC4`f`?rZAz7@I{1QHl{FfvCq-c5}9ib~k)(gH3#A!s$JVJfKbVc%;j77Z2Sh87aYq zniHx6^N^43?d@Yd^jKS45A(Yk<@gL5)6UpaPqtdk%1em0XuE2iLG?28?98Ms_=qG?0q!J|_HD9dIih59}f2zV} zoGebT!xh`mfEJo6T^j&ecO5$J2+>t#~K7L!#%|%muy0m+O3= z_nN+3C-q8xU)6|BQe%>p6}ExF5xeWh4_F!yVM-8zPyX}8gXSBd&E^r0)oxDOJ7B#v zBeU%Su3*w$UpQyge2rqnI;T=B5T3XEi_LzqALmRN9csA1t?udn;_k*B9WjrrVob zE=U`;d;AF-@iSlYwfM6Pz1WU(>2t2;Oc7b${yZz$UScc1w$j$zvBui3Z@0GBw>eTl z!b>r70^w(z##n6H`Y~F9@B`_2HaIv9(=e0Y)0I7nLzrI68c0VRyVnB2Ol!RGDu`BP z_GHZuZ9Jpjwoa$ml_EM}ki>Wu|06!aedYVQw1jPfWxPFBV_#1hh8Q$#Zz@f-4ZMFz z2i+F>8QlAdv{~ELnY4zzm)YzQ6jReCEK!dj0#a6?p=^999(26ek#C=QfGF4--)QLD zp=uL*=3mc^pZN&t1YP)Kp<^h%+(t|n<-8#~gHywc@_kqTp#AEhr--t$tgo*Rc4C@& zf%c}M)yq2!&ShCfywLK?{g!noMqBx$9VsH=j4jCoVyQ}ptiVKR#*!UjVO^L*QWdQJ zZeDxc*qpI0kj){N7NVU3p69;&BNnEPCAX^_*b!-%TtrM$W9E&gW6**awlRzotz-}< z_W9_C<_oisJFT_3!)hDKt*)*d7_!)H)~_@prduaNCIcp+=HmyylQA-M>1@*`sQ+;P zpUa3TS`)ole;)wHz4u;JO!gdqY;|?DD}~rkl=gg4+41+)H@vl?1szkRQ+D7t4_NaX zo2~qTaz_pksX;8SBX5Fw4rC?*iE>7+Ce1zT{6D$^%Dtq_Vo5lpqCR-Rpu3LBL#iWq z?VYubN!s+bW;0V} z7DcfoUW96Y9}(C@wgvrZc1g~hl?-zOSz~Sxk);41w~zuTteUqscg|Q>htFc!Yptnl zr~UoJw7oYk1!olFN7SaX4U&X#h#}bL zK4oY)MS=k%C1#^+Xd^SwS83fe|F4jydOaGBO=ds)8Dhilhgo@y$taKaw|^UPyDag(nQ~1{$I;Y zZ7>8yO5RD7Wxf|o`A$bvTVc9oc-49Ui)`XIq)HkG-U+{hrH}MSmtHcy}ZL#l+4=}WNz-CNV7vkVddcNHAGv72UD#wC22u&WO0IxD|pN# zY}c=icx^w%t~oGoljRg%&hj-z4j^L}3i;*MmvhJ_y|j%P@zJ|%mc=$_8Q}oEmC`9i zL0%^|&Vo{#clsrzq{EP;Z_wjM?MKbsR?%2#Yt}3SWedCLO$+mt5T%Jwqo^s9V(}dE zB4DQrY_I$8hagjh%+=8aL-o#g!azI07+rq(!re!P$UR1RGDUF0p(M;I))>c%6)U)R z6Q|$Ekn6ZuOEuas>eMa#V}4hYrpTh={tAnfMNG9+eHZsxl17ckb3hAcc>Z6mfXhcx z+vlZc*nzqO_NDrNqIx6EHV%-Ra-K`WmFOM2tY(Ye|)o0M}1u zpiE!3-+GG=VOa7kZ=}-ZpaVyg2C-~r69x9{qx*D3}XUT;$=Hf zeV=W&zYApBxG&pUD4L!mLdn8ep--+QBjm`?8!HhlP~mF`?^V=%U|=q`QI zL%C@gFtHRhU(eNpxhyC#vLfQ(-^zO{Z90c*SQtHS%w*^^96Eust*=XcoHt~rafL-J z=(ovwh>0AC);L6r)<7}S{>dma5&3C0onoP0&PxB+T&z5~}nQi*ZO|JM_#!NM7+8hKqE<%;hJnh%o&#Ag6?21q9 z-fMgJv|4~>mouSJ`)1ld+ntr)vQHfSTf4Mpvwi!5dvW3xHr9!WKJ#|@EhCU?qeb1; zUbxGm2-;@M=3DMSl|?f~ZLp%%<=G}!cM*SzWfU{dF<^Fp(IKc%oh*_zUYBAyD?y?k zHv3t_Emw1h8{t6P;A*4Yf0WwsJ5t$5_6g>(bFLc_Q-B-}@L(2F| z9I>4@WT!SwTrTO}dmpfU``UhRQLZJ*!OiQ2?168j+E$#jk{cm;6d^$c;#KZT+7ys`6<@=!6XP%r^MEKj zqduF+FSY5)USJRs*8{YF8HJfefRPI8v387Kj$nvLBnJyhth9B7rRQdwHzNS-0lhie z$6}1RqUk^|i{v=a2p;0Jko}a1&C@?E0A4_$znrBu>>fTB%&{YrcHjUsVj{%4x)NKz zezh}bC!_A4;$=MJ4_Aa711j9Vcdu=}>@xEx=Ov>gsPMC&C1EwS038xt!O=gS2XiMP zND^{~i5&9PuP!`Zk(-{U#}k=JYfmE24?XmdGw3fmXLgcL>Y@wSj=KEH|A?+H<#^@N z>V913lrLn=B$K7Tx!Z*2ztkJTNly1=`?X^sf*MG?x8q2g9o)Xp`i9YH%qaveL{)-D zmN_0aO@1ytRAE0@`BU=2U6wH&uvv`E403Ogp`iJFA@X7))bPXJmSk5>* zInxDpzO{9yTBKkAwlS|Xi3$ej$5dp*ys(0&i4dnKyiYP$wfT$uCFjt0{q^R({dSAI z*iONQ3TDR`R}nTn=c6x&a)v$lU9zgTMzYj5BahR;EY_J+nmM1L5TnwBheOL zE0Wf>{4uLMu-+xl#VFCjN+m}Y3Sv+bVOUk^w5Awf;c#C5EFv2)l|&SVR~RAGJof() z+qJ8OF4v=W{S8;}(IBRr;^I1mOZ<`^s>pEw1NQi?UAF#$3(WHm|3KRqqOg1KMe6EL z&7>j@1nFSIcfb4T_mYYN?K&LY`GX%ctEn+-Z%6&Vk41Co7_-*bx4OPw<-aO-k(wyyVmnGnVI~KH!tATN$XX0UIfzoK85tR~_NF!) zY3j7mHk=dIPY_1%JO&{F6Jt8$x2eo|yKdkr+N-46BZUuI&KSAI6xL=M^KK|J16#B)GKCPq`NjN9&x64qcjl^Gbm z!3mG8#vo-Av2_Mg>=B^E!O1kMD4nw+)Ko_zEfr%)4_wJ^-$KmD8Ex4r$pu)lh1tEJs?iIwfIw=0V;wt{@t{3))r z1P<6~^*cNEabNHY+lq3(WsjAaf0T%rI!e_`%7}@QpWBq{ir7_SCOBP>JsU;S=MC8l z-npkApiR7w{$ZJ!CGZ7&=!X(*O_A0ei`r~)32i=@cudy742A?KZ=SqVFr(OfAy`v& zEU3u|i$y2Q+ZnX%@)8>?tFn8K4A}M4F)NSB0I_I@o-%P7lfW8?AJ`y zm<9AOg)4`h>;qcdJ>_LV(8G*eS~EDlqALP8%N)zYROVQF!%jO~@+-(C%Ph?kaHJFE z3^YVbUdVqD_2DUcJYJjQ>pW4TiD8+ZLj)FZ1`V!?b$0gK-FN=NZg~CGL~}G11Zq4N z59Q0+F+zSk(>1Sq-GU)fWF{g|<&{Q#0yRPXW_05JhU1Yp z9*clwcHl%d^-aDku1mtQ2O})QVFUt#mYR*oFAHikv)iUp7F1W_R6zIT z9Jco06ZY=;s9iG-A*7G~VZAIOf?!uiR!8A;19g}H8_S47;xqU`1cMJ}ci&o_@RfKf}am@mWp+2x#j%qGT%?D|`7 zG+#x??%459=FbmUyMNL~S9M$B&PH1{ooZ_?tYUq#pS;+E>z8th#_z?xv>vBOtm1(R zQ%3`lmqc7rRHkmwGFXxp^N-VZln&a8#vFpc5I4blqRmr z4rMqamdBZeGhGUGyMoz}dVhe}Haps&gPqwk=7`+lDdv;zxn91)&_TB@`vHLpjKBzM&(|d2*3%Oh_+pAeqT zFu(wqK^c6%_kx!iuO*t4xa5-3C9%K&7r@26|NsA-^Pcy-C(*uO;qfY~>~FDXq!Dx` zV;k9&MJS00G5^ZS8m+mZ(LVV8>+IntkJ$u9ZiAXpe}KBt@-}N}*kS!gE&%h#?dq%d zI!xj>Z-jmCpCqHzaGH6I7H6-rS zfqd#ypZaax|8V=xXFx_QnOw669(V!oD2$;3DhSZ(1COv!q;3V+pe#~nOMZZ1g*Yzo0TtDnrD^MkBrCc%9OQUk!3%RmBkn% zpnIqKy!LxAI?DO`4va+&lP5whECe1Mf{GmX0-h12WEU(Gqjs~iJWiPsnmhMk;QpgL$Fls<4g42MgMM+}-GbM=f% zk$02)nEt+0n-%~?UD>LvBMCHq_qfycq~*mHCzmGgScXh$7ZP$6B==T8IdA6g)%lYV zJMzf0HvC+_m3MSmd1HqKqt!TKIBw--L^n7R0irTLf&xS}n;0@*20{n9=bu0JY372* zp15g%=!@D+a#EEzeGwwLFq&?;j!vuV-e=)Lm6ajUk*y>bR=GrUk+X)y9&23MW=ol{ zonOfViexZ69;>M37q%hN-Ry&I@3SD+;5|)5YY;!alC7}V+||}`@{swbg0}XpqHUa| z*<@SXHm*u?{8&F=w&2Slt9rVP5}a=47VVhUlgt(7TL{MyqSa?UeTVr&Mf>9CjsQ0{ z+H&)vHP7s_>yH1p1s5ZhB(FVu{;V~()L9kt>~ff6f)ML2)H$UPlebMeQ21&eOlW!D z{I7^@>B=RCs3a(S9qz!T-oE(7FaFLC4cR|%mbFN)t)=bJM~?&hwOSp9DGaT?EKmVU zJ5FSTM?#cS4iz`Lqn6^$acf%LPBNMoU@v)q2ZWJVue4ba3_akFT61)#txnF7h)$U& z1$wpYw+Sfp`3|o&RFjB~dh9-O058Dm*bIB^gN+5-L%yJ@k%aRmaS+e1LDh#yg{PXc z#$-1MV!utcjasa6$r>kiP-nB7F1=CPSOCIEEilGZAExMv2&_CxC+Zr1CTbIe?17u%*HJYa8)+ z!RIfB$)-yxVwDFhDKdL4O~$Ps`TabWagsq(Yk5gsjom$Fiw74iIvX{q$E(j*#bkv; z<9}6wpRsbeZ=%vCa1x(;>O~uUq2DSQj|CR(01j6W$k2hlmA3DhnK# ziN-C3ES2)fJNj?5+-Q$Iygp>-$d~nWmjd{2hs9Q4YU&>qU@7ivfRQ1sROhdaT@z}c3qO_|Ba3hjYHKuHXUzr z+PG8?S34aa1c&Q2{ik|J75(QbXdcXSmwNl5A$yH8EayBxm2xVTu_H&oy9>3}(9~gN zSAn;8`>ZO{3>gq3MZT#TnVUwWpt7WmBdax5o00ne?0;Q*Y{pP|PQQBpYuF-kPl!Fww4h%B>d zHBf!Ac^FCwa|>P1D!=kCrln0808d-d`20>4jC&!a7I(W za&INj}Ol{4C}GLLUMF|z|KLSSfQmw zb!($l)>b)#`EoF5GG@wW$(XeqJZL^eS^xPzo2kC+>8DFZOqzBb9av^gq{tmIblNah zPCbu|*>C?gLVHKeKKjuTHDAOKn2d@fRJ%4eJB!hWTCG8Ii8t4v>0XP4npRHTGUYJD zx*zSfZC~4F;l;4CfULEyIg5(3z`O+u${YRZB6SR$8?dL5aZ8<_gPlvc3K1B5I6QnG z@O3R?5hI2ZSHM}4F_00<<<=~K@ykTKcGtw6)|PCtzqsikh*#uzaXP$ms9+8IffGXz zFUk=FNMiU37{X{dXv0#Y)r_@SeXIuutqalu-@&(L8kTJdHIDN$37Z7IRF3RO!e=vS zoYu*Zy>K!E@hM`3`&(_Lf7I3zv$m0m+v?qmwzgN~4!9`I4c46AV=I3?W)LD=&sz$1;{!G2I4!ji|qJL<}UOoGN z_kq*+5-k1vg(23w6AYdjj1PTP*&9jE>-eMKOwan(ONfZYFBbTW8~wOO%qNZE(hC zFV6amvMvgni@1$0AZU*+01G4f<6Y|KMmj`Pr%2-w8AFm@!Np|C8;aHj|dXm*S_Yk7gby4 z7(AfMFov(5+}kY1Oy~HmFlO#473`>+77OJjrrtAUsg{&AoM|w1vu-@z=qx%~cmz#4 z`(GvoO@yHnM_#t$UwqUWpt@HQrNEH~VIY^Qaf7qu2j*5eh@3w$2L#I%$=Bv_y7IIt zs`Yi)FFo^dJF#ul&hCP2fK#UZl-n)GV3h$uDvDcOopT^^O$I-V-7rROGl4-E;nOb! zEILwe;bM(#R-;!+#3w^CHCwb}kQV0F%B}KjhZP5?C7bhGc(mL6F{IvPXfd+UJvc$T z{IHOlEY*$d)y}+Sz7@0T2ZL56R0DgcQ!b`3=Ggp5*nQ}Z!*|vW7oU+(F zdZ{?IH3%9+#fC1cv=9ccSl8sFEjCymn%ipWWFditx7Uzq?8%rZ>Jo!COHC^msq`Fh zs`MATAL@1pOI?q3IWldT+HW`B)cfD;O@@rq{KIYQ8ITd1SeUfu&-UBw>3OTEYPagD zCcG-gb{gYToQP%2sBlEmBnrxx+_P#DwLBjkBicHHc_GZ&Rb>rKTAiB%9ZO+Xq3v&ZFkB z0tI+4Dk0OXu>%;7APCvU1``|#W2L9r>T^BTlHO^X@b^^^EoM|Yy@=rE zAVe85895oRi#I8KP&?)jMWo&M=}(ua`v2^o>0~+*Shc{85-mP?@+9XuaPcQx^1mG^ zEaaB7sHlEt{LXP}IN4ym-{`die|*3(V8b66c3u+%Il83L4`1V>;Oj@DUo%`Qvt zjoVE8oK?*2waS5dD@?mDPIgYb|GnME{IO9sr)9ekij)axO(nV5Q zLDv!+eo40<8nTN{uW02@#2>Qh-Q+Oxj%41(=IHjvicoa~-*x{Wg+%-Y(=Gx0d{FAVw|p1$NI{ zgvhV0>?VuVj@v@r5MB=o9;9Xptgjx5F$3K8k-#pmMZ1r_Wt(0Kb+LfKwUD)*+hfsK zovp7DiBZ^DKpLx1SZ85HE(gz0#xjS2%4AkxPbHnd_0#3?>bGd(>*f_TAEQ(ZEYmBB z1;zu^gEtu@iuH)P<-TMwJjc?@#obr=jOxKdta|Z;qSe_mu|)@ zHt_LMO`0M#rzY(!G-!fj*U-a!;xF#C0LB2K8)J~XFk_@F&GCdVY{0qdRxZONiMJBG zNSO#ZUH z>mUuA%-cLfEel~FId7T75>wX?>QZKX8`oQ)s@!62W7crK6G}eyn>cbc5g3uYzrb4H zbBdNLY-0tIjgMSib*ojLXtLsS5Vojw%d*cp$0ME9C=pg=O_LKjU%Bl{>d`WG|2Lk5 z)f}}@V~bUxpi_o$!6xDZD~(gu-})_^Eu4d_wbKG8$}F)wgQMBRZ=){tGMGzZC@L2w z2dZWeh#d!8gb%HG&TEV(jYa+aR&CCx{~>F!bh`aS7DGz|_DJv%3-m>;wXn}(JBDrU z=5zEJsx==~`xyuxS`-DZ$;${efW_~jrVJLLS29y9{PI)+-2qM;qX%r7ocC$dPUgQD#~pgHGie*iYx{pJo^Yt zvUQ0<@|-_QeGhrT&DC|}u4b%lN0)`5>MM8gc5eE8+5`bcfdi|Wn#}&}&y0+Fsc2f! z7|*}DsjL8U0IO&zhxW-&8qywS|L)(F@@ax4$&WetH4K+NzlqNj@nab>$)#j6zIu$W z@jwfS>eBL&yrT{>_P#NveT=Bnec$MFI$G=P$CoXp%$Rl70BM*y4j^+$$5x~#S)j4pIx<(<28Jr7 z?<3k%Bw2$joxeMXw(2QM^y~Kz+6p=I`tB|(T(@Bp2T#~)^Q6hk zU;q2fGwcQa2ePD}VVEN9>T2Lpg_Lj8CPNiKy+|b>jVH;8kCI<+%vgL!yky8=FG`(8 z4peP_ty5o?Ln-A_M*ly|kzF(xbh4AFuh?8W&B~j+=!Zh1&z`a*F zM6*0}6w9x!w85Wz#?D;-pwp^hqc&yXG*MCtrWKRcOJ#c!xtbMp5Zk8r+DgZiO&mCZ zhgNGfnNA=SqPoH|`iQ_ENa^H&_?Ce?itCU$(s+1tjaD{~5vhuh2=B6L-#%#IyKTqZ z2kpSX-9$?fTWBA&mbqQlJ$4O-E#w%+TnYn-u48~>6xFwkXh{)SR*7ba4`r}01MCwd zku26F>z(6`sy;^$q@WpA4a)_z5CWxC^1CZ5EXM+p4e~tsfj};Ap*5BtCNv2|OOlKZ zY-CA(Cn*Lcr$M+@Osw13;E;9h-3GIh1?X*@fV$MKFPBDr(lGE>ddh$n$UWrZFwHqv+96 z4w<-f!sf18BhQ_%fwL2ad2%BD zg`z-f@>u*ED$=uy{8o|3qsTcet3hh5b&q3^1O+NrCYUf!t<}e#ztz@*S^L6)Z_>$u znlkc88n#n4Hz>XrzHt_ zYdNXOrA0^}QABPqvXr$f%nkrcP68>e5J{n73MopL-2?Qgl9l=@BJw7Xjuk(o4TKLc zaQd8Z7;*`);=+{_vUeP_iqquMrq&oII8r?fosh>W(~Y)4x?&=9!e%n(a3D9VF4$xH z2HsDfK@5E-=*W9tX2iB%+sT0pY2Wxe&DZj?gX!k(u^kW`_rDjn4_pOq*{hMpAqYBgK#hF4VSxaA_d6XtgUu z8n~B=k~~C&8(yL%lIvntDJLQ5R0~3Yh|UKwME7OT_5CEbWelVNw*f5U#h7L3c>%OO`=OsAt#qx80EG9O(F^k-3PmX~KX7Md;wUS2yx# z4umLzhw@=Wq_1w|{HU}p<<~y{`I1uk?YA2VkCNhkOAF^M=tO3s<%==t8qZfh<86E( zgQi7A#1Hk6n!KHbnMJ7mnUWM%#Z-k;)GD^4R4E+z=uLnfl@sefH)!8_^m&_`S|Q>g zr@KPbLVgImfw3Yf0S|Ex<130$DHE9p!GW4qB9LaTR~kqkG6&IIxVF*ikb(Ndkz4IA zc7D+Y%Ff|4sWz+D>RWrQuBFE!Tqh4b!cxsUFfGB zLPx9vO#0|b&enG%tTxwfm9Z9!c<9^Ji)To&U+rQ$w@&LFy2d&OuY&Tfrj{g@TUKqQ zbK0U8>aA{++N?~yWy&aEUPD>Ff46N+rTESjmVC$>e0NJC*kfe@)UfOU^IXg zOGEhB0B$UXI0n4Pz)GA}6<(|LgssX#l;>>P0!=2`{UF9#(MMavQxPQzU6 zK&9i=O_Y3TG73gi5%g9grk#`zlXjybF)8H#)K8V(D#(#e(#~rf|>UH7&I@@`#B2eU;gS-Rz`t; zGblxHDQ@dTSC|#6Wt`}~niwer{GFoZkZflFh`yY%7BPcYR;Gd0sF$Q3tPBL;&L{U+ zbF9X`*zp&Zp{TLCzSrsSkeoknzL`l&pE`lVG0ykItcK>Cm1vU&aMIQ*LY9s&?#V|9 zUGM>!m+I1R!ayR_21$&@;yP#r_W__yAsXf7t{M(;oN{AQ=b+9_j-S|wevFk^zwsEX z(F8pJK~|VKypQ@s{TAL+Q_)UM8wPnNV~0RL1*u~_gkxD&ZnM4%b|L#M)ITV%Aq{Xv z|24P!^O*mJvGWk^tj7AO{262%agmo>2~#0lT0i!*Fsj&(O`=;L)53vS#Odu0M><-PC5Xj zU$(*!gf2g86$bGwF=hmS=@v?C&eU1`S;UV?mP_bbV?@!HB&>pKz}8>c?l?&WE`}VT zOS#FAZNW`0qn{6!JW@kV0h<&=-?6bq|kTppB zme)JFgyG3rORuex)0$?o%{T>{HMJNyJh}2bxhX%?*|HuBVkF|hS({%NwyJg5N#w2M zv1KTv6umeCBoeIab_`<>Lnm3Qz&0W+U!~P9wb|0-7{*{2lK`8m09-+j7kQ~Z6gqrR z@$*Q+cz`)%6gM+Od|3=EFo&1duo$qch$f*eN10sZ7`p^as>~`>d*H+v0>RbwNC62( z~CCEtUcNJFIk%ykJ5C6o+OJ3Sr%g~QQup9ck!$MStX?GK|@vr`> zlqcJoM{8><$y}+p`WJq|?6%v?E?g)kGI*_E{ZkN4Zc!3CVO*Vp({(Dkt=k1z}&auAuxKzWGl z<^14&!S)0FK*vx7q5`yg#~=hi7jW8qpb?umcv)_Knw&<~U@sy`bztcRbVx(?OyxHa zCGgXfpx-trByQP6$_hjQZX)9t5(nciLe8xm(SmZ2ijB%@%3o?R#AM`zGKhH$L)DRfmmpbup}R7FTRY*Zl@P!HNNPM&O*IyanO z%|9uT$k-{03v-KBBQAihs>BhdcAO%rBnL^C3%a9OiY^nYixfk%7SwyY$%!AfSa^c& z(y$mkP3Ecb+QJ51C$1f_rS1tjz|-@U-_*?SE0hQAM)+E*_ZRHR)rYOEaoK+KmY;e{ zguET-uwujMLneLCd>Qbe+;k<{-OU|OZ{ZyOp&{est01_V#dc#17T2|e{T%^Yd1(>` z;eI>E1pF0>pugS^?j3;E%izyr95k5Y4CWm0R95v@7>gQDyYsx@IWOwZYR{2J#J9N# zkyqb19-9)@>%awgDNI(U-TKu5>k3`vOsrrQn68H2WBX3nSldh1HFUML`>q5xfP_*; z=ivODrLhuuCb`mDrImqUMD*kED3tShW$@q_!3fLSG@_{hIY53P6bC5M1imRS=rSDh zD)nS3h#wn>mx?7>?hTXsqTn=zk!4&KfR@6vdnrfjP6k*2#%3Jd#|gUcGI?W_h!$5d zc`_5Gj*jx zSGNt#*7FmjxcTT~&)U$1L8~KzSHW+Nalb|h3NywrWaW79o4`=&skcdPO!|rHUcSlr z&gwaIJ~!#WTtP{RKa-;z#%p)PK4Bvf>c#>oOY`1*nvUzKq#1`z zo78p^QLWV>3|!ZU$_F{lH0(r02+a8qnxdiRD$8y|v$5Q4wwgw#-Om&0fOcdyta`4A z2D#OiA|)V5ofr zjO%AMt$QAav5_I!owt|2M9PEcHM|EIx{*_M{>*c>d;eh!qZpf)cGFzfDU@8A^Y}Y` z9k0KY+YhuM6XZks+otAcsQWl)``;h5hg-_byTom0U15uLOG(yPX(c$M`>PJo{cil@EA!Z z7s5qb+CFHBgCjQIeI75Z(rS|J&V(6idd8APlFq&3Hdk@hdLr+!rm@|irVAz6^O zlQ9$H&>2up9!s7ssv_m!{p82WbL6ndiRHlEp_>pnaX2K+JsT`O{8ta-v4OfUW$9we z30ng$E2pt$6^VG&nIHMaW7g8sX*G~xE{9ey8UunCUwH00yAH*UIu$yP zjF|n$|7iB!_m&_-Jr))J-~QVYwCK)IMPg9xor3B={nHX19}SKAur(rqMmi1x1bxAZj4O;yfJiAPas@I|IQGS?3}OK zmKqZdq^fxn-DrTZOMP2;(qi?q7JwkLR=GwVK{wY3~@1rf_Wyg&~L<9mQN{-E|@o7q>(!cD%v=7P0m zcC#P@Kg7{}gCV%VE#p~%W>0dO=q<4}kLMXd?&dTVs(5Uel(hodWR)uxKQwK1JCb$? zA>e13Jji0$Xw{&l>QE#g5#E>#*e4M$O%a_v*fDE~m+!Eamv#UnqPCreyn%3=+$Wt0eei>??h?enUyqS|=BcM( z-(6a@{8zv9&3eFvb0aQ^5ug4ir=4DD($d@UH#_X+-@Mu8ubOu#{Zd2E)0b-!BlhB7 zKVh{=AJS7*sLr#@-~dq~jHyBQlVeM(5Rs;sn~cFcM#cl#$Oqd`${sn?K2)mVC(@}9 zJP5fW1KHy}D<8Iz&;@%ba*RBf-x`1zy=x_B3huDuFtr6>^Hn!cb6IW6j7N=2f+ZSk z($TqylR>T4MC&;q%}HSWtn~mrmWo0C@rb&DcWB^e0qG@XA$7k za(>1-Y|D@FI|fo^cH-byEmc!zWr;O=Z)n*L`uH5^^nVqI*<3&Rs}nnHWjtuh6N9vT z&sftPS6anNgKa#Cb|R5nReg)2XX~ zYVz0v2$6pcL%;ZN(catQwXp`^e42pnBNefDVZzpN1i~y}Z+DrChTeCL)ZVOddC}+m zKpHZ~h#}$hc7@+fJ#C@YF#u0VS)v+cDvTBa>wXLFA-dDpCM*A-TKpxaTv$V7=! zT1TuImfvnvwGYniispN!i>bM*Kk)Y?Ut=bNPNJ(RbocibMW`huNr-3AM* z(C5P|*HZ zOcAB!AP@-|kO9*#u3*F@h^~SVmb^GeYBnj7Q4u31V9gsq3t74Xr;4`eVg4U_}fMhD|x?9ORL-lxMi65#~o(*k|?4)KZ4% zgbpgvp5AVoa~(KuYU2W&?x%-ed<^7c&AM`P7Uz3I3q+V5d3)csyzRo+l~G>@2Meu5 zzg;ne4lCW^KXCnqHFU--+UB(?<}E}*yx^j(9M0RHcSHGq;ZDcdy|6Q6vq#U{_Lpxq z-)NB1k5P~vwV0{0d=erSb(fpSbj>yNTda4~=3|StZ+yl+MafTqIkwU3u`#6K{${~% zXP?X3UgqwpyDKcwv}*H+hj-v;ckkhR-~?O_n~J6-m!|u-YWsmRWR5^Ctf`cJ-fq2q z0;Z7H?)4^s$xyjYG5EtCO9MwN(kG}2)?!0H7h{sSMbPvfghZb?1bopf+HjY34P5KA zX7S)rDzTdkESaCim(`o}AR6tlrNp=;KTdIV&lyV6#gl|q-b%7H zUQJwx8CsBY7!xlEbgG=KxvSl}cJ#r(irW0_tj$bL+v4anV#H*xAh&ohULkU80Xj?z zXpNu*66O07B+Qo!YgP?)xq<@jBA#&&*5n2TYYrCrGIBZr3|2Gibdbf#k*;F0M-pk& zJrF2{9TtHYb0vC`6Zs_;nk?}y9x{V_5p|Rk&m6V)eDr;9)i{4$-=lM$SJBZQo z|Lo6}jFxgBfBeU0%AL6d(px`K@>Wv(P@+;fwXGXYf)la*&;M!7Q2VdJNWT2iOE^Aa zh`#fTnSPpM&>TDvWa64R$DpY=w(}dE*6_s!`;Y6tV=vV`Yu~{6nhy@aWP>_igaF|S zJN>F6GD75&)^Ui|8KdgWr818!kr0dts{qz)TN39L2;aM6BswI}TtttLE(7z9+0_`hYdWdnh)igTzDw$W6jAU|z^0MG>|z=wa2c zfs7<8=WNJx)EZBD>^CkDMUoGb0>8JaNO3lW$fxPVJi{^H5~84dzvXF|yIyzB&M)GW z)^h&xE9A042gpmmU7N;+>c<8@GKka|>x=SfZ^8BhXUMPzc4py8yWyH~yAoNY>hPH5 z*St0kOKYxd(>_p1LV9=6UOMi#<9LOKGccQ`Kt@=+f3lD6A9!6SsW-WH^`q7>+2_>T zL>j9R_XSR<>&GjjH4F7&elYg6TGRn5Q+7je&8{cU*1_km%@8r=n6KEN=xol?IPoi~ z276)>Cevmwtt8qV-*qyvVUrjH<-+h+Z4qPXV~_+^5bI?UggEvxV3~4gw`J5fNvu|e z%v~Hsao0^nxjD!wE97$2cdT#ccH4X9ehgN~W}Z1~NfPM`GcgqV6BfxaG0~dj(;==P zV9JrifFlbqx9ZAJ2*FUP7g-JBj~ld>SuV$m=2)zX1qzh}FHxXalbiC$cwTwAN{nwC z#?J@oL`&0xz)xVM3l}cf^{HFQy-CEC9WRqj0>cyI;}qgn+YZ5rQ1tCT{U>LEbt1Gs z|MODQO-WmAZOTb8^mp83tVGLKevNa~`s=@LtJ}BR*)wOHYxW)A^Gi`_bZkNwulAJ~$A!5*snvJKW8C6|N$;sjy_ zd;QSkff|D_D`$9bh=?z`^Ppw?sMTPAnyM--Jv(B-zn-%Snt9fMh_oXfxxKMyH}A>W zmx7}@TE3rKTw9u3sY%@yw{8IBi4p@xI&cGM}7x2Dr*SlZ5(fEHqL;dvE{8h zflp{&c@k#OO+bnC<6~7e`&l4|fAtJGg^v9|BS=l5gP4=t)A+0di3lzfEj$cV zQW>qlYYRIQQj<}J%QaqFcr`IyBjy@1O;mTX%8<#R=_V~e{| zNibLjOF1u$kny~8ua46qhHTsBzU@2Ti@_*O$N&0Y%^-Z(SH5C9KJpO<>Q%wCuG_m| zE8+y5ee9(9ffQe?djzBNptY>`*=?~8+b0))mb$1<+u7PP_Hg^dHr}v81P?n_!oB3q zg5Ur^s1B6OzmtbMw8)o2@zDWWQJU8$?m0lNndlkf@dr=`I7F{=kj5 zTgz_9C&~+x%htHpe5tFecdnrxyGBg&#hoKM?=plU`)F>+s7cURMosfXc~i|DJ)Z=k zkFk$jE)V3bF&q>hkZ7>B&l<}2Sj*C^d8bg^d34eaFM93n4|9}<680RVjY%Zt;@*@E zc0X(N>!cX)ioF#qy>*}(kYQAtw;V+AzJI~~F}8O%Lk^z3aC?i-fL606qSx8!UWRJ^C={q_jS z+S-Pq{p$4$aw4WP(?09j=dl)`M%5@^hnMvKES$A3%(Pe??buUoD|nePptE`C!bDJz zHI^e2e9sj4+k$O_l~v3TZl44KdDiUIa|Ih(rzOOWoi;&IdTyS6V6=n@V+@YhzOrAg^dO!wX$ESk{TWb`y)<$+crbn8q^CaW4wW|*+`4fVGF zM{lymo$dD2|Mv~r$c!Td%q-%w=~CtxpaR||d@Selnut^@JtVDxLpIbd2BBin?JJhn zm_AZ8$6F>du3VYeet9A?2?-;kiYY6J>ZI^|&!0MH+xG5qKJ#+>N9XG$nrZrA95#RI zQzeZ>b&~%1pC>%WF!vFjpFlz4yBRVTKLbv5v>AW@_e&6^a%aH1%H141c+j~XQ&UsG zTJQX6m_sajgJS1O@;3osbCq4pgof=4oxe{`tKP0zzQYbL+-=v--(*wKY5Qu=z4ooT z7tl*Y4vjV{n=HUVv^u922NBaoW{tV3(OUyx_+#;p*$dHUZM1yQ8gi9ROQDt!S>Rh?2EvrPp#!_Y|qP9Gunm` zMy_uAkkk65F4>8-LK5%7ar;NKocZM}2QkX6mpUoocmfR$7z7!j_NQLoR4W-Vzk9AZ%@D>ix z5d>)Q>OZ>LM&CE;7&b9nFZ}og2a>)NhosMZ=g*+md1f?VMTU6hAzG*yE?YcJ-{X-Nx%K&GKpFy(Z|UH3=L*&q6)a`!?)R~Y2;_{ zMq9!1>(FhiM|oY7Pew-zn+p|c0&4qClkgw<>F#@6BdE{S#Fl~7O^}K_&lplZ=~UWk zwzb;({@G91sV_ZdlP{bjVU98aEvWIIoq?+eO_7@FfjTfs6%}pNoY6!y2`ouV4rhU9 z(I~?^Ung%@RDBx}Tu}F=UqPO%l-F2?;WacoM3Q~g!WC+O$ons&%^5EolOVtvu1}ea zm^RgqDY}9b;xy(gJ^T0ng`wyeIz?j*3g_AI=&h^Ed8q5UXU`ss;Y?^@bg#4X;ydgg zjjPGA2}{T6t>xuBLBP;hQK7t-eC`T#_WQzrV^20bU_FUmyKU*m>^D#R1~C44d$IYX zJ+!Sp0xm^l#OM|RVF?5 zGnD$=HbG8l9>mU<_cczq;WZ=l{vkY9Gl>`EfB0buKg!MPzN*#}t2 z_U$1}GO%f<|1VmxcuAocmjqhzb&)Z9Ja>$Gsa`zJCaA*HtT2c&MOrRECfTfKB4hMU z0*gnh8IW}a>-W)I@7BBQ%+wfEUcWU$3~1#h`na9$002M$Nkl3d|zT*IcxC}?GV7OWqY`)hyt9ux_x?cQ(RXNx4KRj*c>8_v+hm=$dvQPr-_ zosROiCqBnBI11!EB=)NB2ybARc%P3PUImK+Ni*_mz@Q9#<;v!PTGY!ag8_|HV#wai zANnSJmd=yBaHqx$l1AAsqR0RK-_3sdr%MKnYxi9@X)@k?vy&IYoiDvlGFPJOi`tJ7 zljCwd5#I|GQ)^+o6xaN_9^aezg1qyovm+M9(B#Qntx^*fgQ*JF5baMt>{noMB9=UP zlXI2F?Ya6B)>znUhm-HIPmO=nJ~94bd#di6_Jy*q*idL1BM6iakx9(pJL4a)*}#~c zuRdzG-F&xgf6qZ6$GnZrPM|Wgh60G+nL{-YG-S+#WN2K!(akklx_2MDpW)6MIhQhU ziuAS`HW^YiSB*?h+YAj{8@BaYcxc#02B)ok!f%NkEB5N}z{PsBOS2Zlm;p~8|fRaS%L3r`+aDUJDdav0pV28}xeN>}qdiWe0hu}Rf^0b4ZSrFXz~Yo-S2Vk4$&;x20L z#L~pk<_=Exb?3?N;UCv%YSPOC)!+J#6m4oY`0X8gw^`?|KHIjF4z(PwT9fEIrCS$; z2oi?Wq5e)4E!(IMgHVEna++;o@tiKdc%@;WMIV1B)p~+ln?uj%SW6IN0o8>v+k5R* zbjwymb~&1|l83&A$DPK|w140Ox&S5e22t8;ZbSr5f>1mC(I1&T`ly*S9F=SP!WW>x zzDFPKI24K?#Fo@Gc&BY%$}kq^7wy=+PonY3_$j1q2JlaX@G@kI&BUTjp+TC#z~zyV zT1EL~ipb=2&x9Rq!HBQLtS`3DeqrgC>*&C(5yNqb}X+HFplWhE3N?-zNj7 z2v9~&sy}lWw#I!|SbF@F&5_&sY&CLRKfsx5K(7sJIU(`VVJ_)UGBqvg)(CYZfg&al+bX zw_AO&o9s{CT624#*+*=q{hSR}KVzO%yfu{T*TxY|MZPAJPB@;UqA+=J8vNQWHc;;5 z(!|nZO&-_yxD&~}*Za3V*59vZ)91N288l5u-4vlM12=Yeb=&S;yPdy>=_|ILStpXj zBZb`3?5i@HCqGy*NnIT+ZTLbj+LHy2*NfNYXMrn|YCo(`F9y0N>Fx! zyJS%sM3(1Zz!s@xL;yRnK5D;R^JR!s0lO=CyZwCZ=j~4?|I}7}aa#^7pj}7{l%H#~ zHN*j?rY0T3uZT#_pNy9a$7>wFkgbTAh%o#>4fQCYmMze8-Ui5{|G%{$ zIPG5hg)0kos2$M(ep1M7AMbQ^lt&`2UdEsH-@b%VYueAc{XLWl+h!RXhjT|sIdMGv(wyv3y&!P0ptN%LX1{;tfIdWc_##RfexY@ zNHtZbY_tp9pEuq?E!uA6nga9tke=yw+QkS0kteBvzjfi#q|hcqBGvSn8MQb^Xp~8` zb)xETcLM6(-QK7%bHC3uW;zx(Leu1SzkAni66-xZln%s@(;-rYzu4%f0|4x;Fvq3I}0_^4vo2G|Z1lo0T zb0Z7Nw||TKn=YsOd9H~Z4>=&Od(#3-BTqXEe*F_aVfNT#X0R5We4;cOF<`n5iqLh= zC1d4Ym)HFrZ_|!CP7#M*IyOwmz<8k8*v~b@Jj3KA+Qi{eEu)H-$po?PVGQufqtN9g zV68Hg$;A-|iuCbWqvb>POw9u}Sn)DCiOqKH+O5`q*ML30^99S0OHu@;n+%w)!JA>k zE}lP{3-0;XYcgVr$dpf3=kJwQSdp$FbNAPKw7+hezZu@s!-7$h9kKlWfDQYrZ0G#V z);D?s^_Z|U5g^Z^DDs*3u+>gx?2j`j``}RDxxHw2gIKqcuP1u zHAF<-7D|Aq>%5&`D}j+IYf8>!{^RhWhe^L(Zlgz?B48+Why|ftofy8 zo4H}eX~wFrP_!oXdv#MNl=HppCpM#=zm(g%J|ffL+JMeGN}r<1y{J%E*4U2fg7q}b z+C4Ce$|%-dz1C|lbkK<-QEQz~UvII7zmxXK`mEiCr;?w<6C+LzbbUZ^IIJ8`zYNAJ_7g;1aG-rRj&&%OJ(y4P{(rU|Tt zN}snKh;eSuemgP#6p<9oJV{>XDrkg=mz`djHy;f_J=6x#wZ%q?Kt&XnR|RTq(t|KD z3`IJ*;itp?MB70TnZ8FoqM{Y`FxsbC&v(3@!+hKJ(K*mDD{4~P7cHo-d;7#EN(2#d zVNOk&-UtofF>qTxWG{7V%E`^bY}6QeCu{|xg3Wnq6zRyEr(it3FauN=w{oB+wGgVL z%q4{3V)UX&!=lW>s_qO8DQY7(7i@~jrLq{UdaBb>ce3TsynUhV^EQ3UvL$c|b970r zqyeT3mz+P{E61xb`bIZ*uDI`W=Zfz2d3xQQ3%Uk!TonCjE{M4(@#o=T3^!W~wS(?; za^J5xs{I$2$(6V4wzBzW?cmy`oe#BJ@6=(d%r?=6g&aETNd@`CR@6cI&)_Fx^KWT^ zMAhoSDKwitZ#Kj8GbtSLl!>vUuzoNMdw?V6K4f+2gVt4~IAlkT!=1{~<1E#VE_b=@XKofxuXEjBZJ)*8Y+Hot4g z#+v!g;EKJU$-4JE6Zd)YL1Wc+s;LLVKwgQ7C$nokxCXQSck5ph9%T$}ZlvOg%Qo@K1J<^IL{?KX1=ZD7S3@+5 zvA%erd97oAt6$T(kcU1`LSGTJuE}@YD5&NlJFubix)$7OkTaN>*c&T=L0CY|B2_Q>s2QNB$w!67v*}(h-Jx%NzI;-%WolqV2qSg zGetiI^U|B_SbEqoY$Xa2r;PWtm)F{XTMyfg+YZ@sG;T>msUt)eGGID4x|b3AUe3+d zvE`0+onJk6H#vhYtzP3^hDlDO92X%ex{niKYYgakwi;Bu*DY;PPPGf={l=xX(Npc4FXBMsG&f(#?J(2m z6(*xEkH8EOS(M0a3};~`?XkPU1>29(P8}seAd}_=Zk!q*GG3X1EwUH!1kEeO$#2f) zkUogKlqXBIzyo;Y^eOV{dZf!bAMZ4E8Sj3i+mang$Dm!xg6Ma3MCM_UO~hu=Qv0Ue zu-$6|)j4~fgnFy*P8;pM#vZI(wZly_mg9nWP_XWruCPKAt<9;|ID-c?X*ZDr(f~Q0q(&tCA`pPuP%!9#(yCC+@2220xWr)P zx!A5=WT2v8-Am45sL7&5Q4>-VOcUTN@RKIU9e3RED%7OsH9>T9_up!`+zF|BeU5w6 z{(5ffzOQE(yPu~C?7m;#sJ^>ARBpHZ_y;Z6P+^bX`=EtaGS-l-17<|+oSM003oT-r zYRnhsoTf?*4coodD4I(K2-p(On{+x|w`-^qlEfC+`exD=`<7vR(q^UzyyyT^ujfeL zo_%ya<(a?u;*0P#-t%`CRMG3XUMA|jRPlfLm%mN;(BYC};{ug#+E0WJ45Ey^{pDXe zhA#ZEkI^;e20Ft$>wJ&C?{ePsb2h8!g5G|Gt)Lm0^Fa#YKRGOF!a7%^yh27!x{90x#8lRy|I~fCwyVX$t(CSkvJ9LS;k2PCiqVh*=#I_ zGEKwG(S%(`5%}lp9Fk2p6+K1Z{=9u{(U1C$hb{x8M^MU7poYJV9Gic|XD44= zw81a`neF@7&m*J^^s909W^9~F$xo^1*@?GrOT$WSq}%*g$AeR$ZK+fbk&(R%-hMVq;41a*26%~e6GNfa!4Z_2jKp%ECJ$CF&O zz~TwZ^%v~&O2%Yi>yPpw1e?i7Hwp#)6yY`A4}x4 za*#Rb5Bmd>6@7e|;${sW))95rt(-d&3*&+F}B9knSgg8}X1Cvtj?i#P4S#FFGz*}k5<-s0 z6t(@!e+dn?*X*zV+U$3K*X-jTcM7ewSZe_l#HjDOT(oqL%vMWx17p6vP%3I_y^EH7z@(hTthtAHDrF0KpmkvJAC`i)_QQe&CbnI z_X*RFD9Fu+$$+?HbnE#3PUpvc{o>c$_h0$VL>^4{?=tGm!omk7GW?=(Atky%+KXZQ>?r_B@&@0hU9ptCylG&Rr+ z2VWlJPZs%5cg}95Tt||0Gd$BeiD2)}*1LfU$>44Lv^Vj!w}xKkW0#BMo-k!QM8Lb7m>4T@>m{qZJ(IJE3Dul2I8SFSo@|AQn6_hAWUX~BZ_Vu<`)la? zgG3t{&yqDR_t{+Kpsim>S_O-B@!BF?X%YM6>IJD4X?p%S>%0q%J@9iyU792+hSer0 zNpPZSibToRq>uq~BO%v#xyHqX{G2zx@{c?D+B0rEqz7t?r}Bz`mG3B9m4v#5WF zxrWp?Enbk#!pH}b*XrFBqi^-H_EEtdZSNTU4l@CQhf)WMixns~Bzpr&BF5XAS>OSY*Uwm$LJ@uNqug1L`3PonFLDN3E z3F7ZWKU4Gf1nMqwL`6VR1gGm3V2<}xR$2Qqe`RGgYqqr8N2@3p&?w!nK0jo34}0b2%`5h_vkCYaq}Zz>(u>&ugQq1 zhHU#+x0mKB_G$2AgRFIoZ#HKRzhbktKK=(k`1{=9osm&~qd$_twhn~1lS)FZji7?I z%tdWV)LO&oCA;dX`0>9Jdq z(9TE3El!NTif5I*)ngZ^`M4K@IUQ)Rj(EKl=GJK-*h|zgZ6l8_+I{1Aq*r)s4+OVX zL_{l^QpoG9+V<@`>}8CatFtF#rRePN;lrpMZF7F9CXaiQ@zBI^Jwi>iizlJp(>v>IHeZP)HHyvARTbtc>$9rv&2s5_2VoCa)Rjm@$W+?`(Y_beB zV(G;M-Z}aUytaXgiTG@kSL0=7o#elACpEN+$t}n2x&!<85#Qe=`)b`{lZ+UC_WVbx_kS))_$PnrLcyn(OQvcIpTdNLGz*E;}^*#yo<+s8N8o zLA&?cIHLfZ!J+Ak&8V#m+I}rL)^d#38oymeL{Orl9~rUlbS^YDFW%g7?cTflTs*$r z*Y$qA=I*EGb(8VZywgpOb#uqQ-lOMLGNFh~NQ#WEoKNht-M(+XRa2^>v_pX?Wsb}E z%~A4JkC9K$#;mM6VK)rtt^GORLX6T?_%SGJxP7%B) z`j>ipR~j-e3rqt1Iy_CgyzX+kr=s=B$(*c6(lR`21IIS)1o-raZt>gx-KcipEzxQV zsV1}M2au(DaMb?ootxJ2&#AQMwMzE4xdKY_7{e(p38DUOD(&~vZ0{@kkf*sCB10FF zIa3L%rgh7Fc)(sB9kPkJ4ZG%MpZyqX)}HmWRr`+H{)$7kg8KOhn2Aan%ahy5q9)H% zM$Mf#nlzd`nqcmP(qwig+-nUCO+;x6yaAE%d9zs05=9q4O~T}k%Omu_guK+)_vc_ z_j-NnK03~=e{bF2-PaxWx_3ACIeo7Ts`k}2q=WP> za#LB>mQ$4K{MF0Uhn=agVqMr;56|0AH8U4pL`xAATJ@<7L|O{YbC6@&pwf3N?X=~g zto^~?67_#-$*u@(v;0l-cC_&8!trmE3=t*R(ddbc0^4dO#A7KQ_ z=Z*n6@{=|{ zJ_dHY)Z4q#km-U&nJi^=Pt8t1)BxgIZ38#XrEG7S=%|}8y$!vxQ}i0zi+7bQ*fsPe zI&y>)ey(Ugx{DnAJwOc%vZ|LTG#rHv%lhia3qsn=Lco;OZA3~xT476p9!BAPwj+Gn z`g;#p@O-UR$J!i9@oIj|Vn-8pj_55^?zNuG8S7fwuzgFlcAosgVuoUD;0Sr0f=@JY zT>M=ILmr+MN_qZz&7ExSgmVAhI!N@|*5}>F?qt*?blBQ5gLn}{kQ*S_ItmlANlQ{_vueN zYWlj?^6CXkY14JNoHwb|&(1FJGijj$jV_s8pa&fw7Q_szs537RNImS#Mv5~ zz`&fgvqV!TS?s?)RAEC$VLrB1S@{Q6?BfSnJ02%Gdx9K0>kJ$xivcT6px`mth2d|w zVC#34S_TJA3JJKq#A6Nyw|mjdGd#>M+}wvR(;N}a}t-G)>-(N%~1GT(knHE%0o4Rd^)Ih+=gGs?( z+tysz*2m6^m++r=r6JS#qArjH1utijTCgad3xjwUVzvZTHhG9do8W^VN5=E&U1>P|ZMZ;ry*wm!f0HTSVQakbbAuG*TsmbWR`M)#Va+SlFR{d{+E z(C6v)>i4n3I=#&1jt!azG3B<(R$ERj!d4`T%*@+57oZ6Ilt+cT0&;fn6~%|zAnFG? zf#g8aVy$7!=}uwCpMRO)q|-61?y>+$owq&7yWQ5Tg$gfYa_pOhjtVoX0pU ze{bWw=gF@fg#oAHcU^n;{QkXtFQX^)dzY5T?{eKpg<^S;W>P5zl>2p?OLG63Ga@HR8+n*k7wS}p;rM9&rI39pUl(&bI(DV^=IE;|M3EO`Hp$Id+d2r$R2_TCvKl`sP%#srKvc1 z+aw|oO5=RnY0$ZSE4OzgYthR9oI_Hny`ONO!7$ii){p#4Bhgq5OsfBLeU;^QwA$X0 z6?<@mqC*^EY@6NP3@-$yQnL*Lqm81E_$-BnhyE$J^kI6LH3ES!c#hx(-J68PxUgYY z*N@tDL}yYfXail_w|&*R_bu2ONzwIKixp?d31GB_dSE{7!b`=lHB-P?17&{*dUC3o z4$!CtXtIfBETf`{B9BkSv3e}{LJ*7g(FAiRqz1~?NvX$rO_NufyPp;V88I10_x<`@ zJ?}08&Kq9&N1x+PX!mv9yPNYF97}38W@FEwCx^G4jUv&rhOx%G77crXLg)fHf+)3P z(q`PCV|1t-Wd`6Q<;K*%ELYgDiZrQ7x%l~Dfc?(I>$+<*Ub<) z1aBK{U>qa%xzCyX+OMgC_V4^0k$jHPEm}-BEt>D7EgFrGA7tWC59SG1z)YmHBC%va z*oNgeIC<*FHfUe6NGz^Am~vtp7_C&EK3_m+Qu|O*eFgJIBO<`KNkA4FoumJjXT!evAgwNk9E`Lj&b+Bx;E}y(ChB_*8O+-Tl>0(Q2WSeDGeZlra2@O zMSqLzqdD3FL92~sptlF7ZRn?icJIVCOWjv)sbf7?Cs zH3-dnfc|!R?0hA?#_;QcFdBVO>~GDHgTmX6pqRgXDQhQLD;C!~5Es~_@o(1d_AlEt z^g=v0#orjg<_gv(?$a}T-UJBJRmkTZGP?}}Qx2QzL|eJl@cZjF_M6`e4(YfO&d>hd z|6yn^?_Rd0{gBiSEIJX{TN!;_eBkd|)?$$XUDel%UR#JZBbzpl!FZnbv?IPX`?$2*9(rXiS1NPwJid{kCvIUmn z9Q99R38(={LLk8tdJ3ix7E=GK=Pur4 zAY}}-U}}=eh-qTF3xK}w|8MV1pX55P^ZxWU-80>@?;8fd3Lz ztc8}TvRp1({*X_pROL(lf>ha+%7?hhRk4$bU6!M=C@B=FP#`ISf=GY>0T3W|%!1kX zt=H)_zjMJ$3?WexMM{`~`Xw7Zz1_b3-uJv`d(Lz0`1ZQ{J??Q=9?SiXOgyRiYa_Jo zAfQ-BSQMq@47jJ@?ez` zbbzLHm(w|X0(!GNA-p@n+;c{%&4^Rp~;X%O-y#ogEqic*btR?qrF4$KtAl#OOp*szf`8g`D@5* zm9}BL9X|Jh4!}O%WF0YJ5{h+T-{6IQcYypV2*Zc{S?yfRsTR;GWI*y0VvJW&vXa14 z1uQkVbxiv&g|(*vxdBzZqlqGOLVR!F*`1vM#mL^(j2*O-+i}p0-{rdeDWt+*>7UU= znMbE@9MUEz;X*JGt(XRPIzIV5Q)!CJ5R5kNr4n;ber=h7?pgnud#jfyg_QReHA

      @@ -262,6 +281,14 @@ src="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Volume_ID_bu
    • The pull-down at the bottom toggles between Orthogonal and Oblique volume viewing.
    • +
    • The button at the left enables the + slices to move to the brainordinate of an identification + operation (mouse click on a volume slice or a surface.
    • +
    • The "M" button at the right selects + masking during oblique viewing.  In oblique viewing, + cubic interpolation is used which may cause edge effects and + masking will remove these edge effects.
      +
    @@ -276,6 +303,7 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + Area
    mouse controls for performing actions including Border @@ -298,7 +326,7 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functio annotations).
    -
    +

    All Toolbar

    @@ -339,6 +367,7 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Custom_Orie + Orientation
    allows one to set and save (or not) a specific transform (pan, rotate, oblique rotate, zoom) for a surface or volume. @@ -431,6 +460,7 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + Area
    mouse controls for performing actions including Border @@ -537,18 +567,19 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functio right of the decimal point.
  • Subdivisions - Subdivisions is the - number of numeric values between the minimum and maximum values.  - Auto sets the number number of subdivisions appropriate for - the data.  User allows the user to set the number of - subdivisions using the numerical value below Auto/User.
    + number of numeric values between the minimum and maximum + values.  Auto sets the number number of subdivisions + appropriate for the data.  User allows the user to set + the number of subdivisions using the numerical value below + Auto/User.
  • Chart Title contains controls for the display of a title above the chart.
    @@ -112,6 +130,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Mouse_Controls/Mous + + + Controls, in Montage view, rotation is mirrored between hemisphere lateral/medial sides and panning moves hemisphere sides together or away from each other.
    @@ -127,6 +148,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Custom_Orie + + + Orientation
    allows one to set and save (or not) a specific transform (pan, rotate, oblique rotate, zoom) for a surface or volume. @@ -166,6 +190,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + + + Area
    mouse controls for performing actions including Border @@ -182,12 +209,14 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Clipping/Cl Tab contains cross-tab functions for yoking the display of two or more - Viewing Tabs and for locking aspect ratios (used with - annotations).
    + Viewing Tabs and for locking aspect ratio (used with + annotations).  Shading slightly alters the coloring assigned + to brainordinates to provide a better quality image.  Shading + only affects surfaces.



    + width="926" height="178">

    Volume Toolbar

    @@ -201,6 +230,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functio + + + Plane
    contains buttons to set which volume slice planes are displayed: P (parasagittal), C (coronal), A (axial), All (all 3 planes).  @@ -224,6 +256,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Custom_Orie + + + Orientation
    allows one to set and save (or not) a specific transform (pan, rotate, oblique rotate, zoom) for a surface or volume. @@ -304,6 +339,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + + + Area
    mouse controls for performing actions including Border @@ -322,11 +360,14 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Clipping/Cl href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functions/Tab_Functions.html">Tab contains cross-tab functions for yoking the display of two or more Viewing Tabs and for locking aspect ratios (used with - annotations). + face="Calibri"> and for locking aspect ratio (used with + annotations). Shading + slightly alters the coloring assigned to brainordinates to + provide a better quality image.  Shading only affects + surfaces.
    -
    +

    All Toolbar

    @@ -368,6 +409,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Custom_Orie + + + Orientation
    allows one to set and save (or not) a specific transform (pan, rotate, oblique rotate, zoom) for a surface or volume. @@ -461,6 +505,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + + + Area
    mouse controls for performing actions including Border @@ -479,11 +526,14 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Clipping/Cl href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functions/Tab_Functions.html">Tab contains cross-tab functions for yoking the display of two or more Viewing Tabs and for locking aspect ratios (used with - annotations). + face="Calibri"> and for locking aspect ratio (used with + annotations).  + Shading slightly alters the coloring assigned to + brainordinates to provide a better quality image.  + Shading only affects surfaces. -
    +


    @@ -610,6 +660,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + + + Area
    mouse controls for performing actions including Border @@ -622,11 +675,11 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Mode/Foci_C href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functions/Tab_Functions.html">Tab contains cross-tab functions for yoking the display of two or more Viewing Tabs - and for locking aspect ratios (used with annotation

    -
    +

    Matrix Chart Toolbar

    @@ -678,8 +731,8 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functio for editing the title's text.


    -
    +


    @@ -705,6 +758,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Custom_Orie + + + Orientation
    allows one to set and save (or not) a specific transform (pan, rotate, oblique rotate, zoom) for a surface or volume. @@ -723,6 +779,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Workbench_Window/Vi + + + Area
    mouse controls for performing actions including Border @@ -741,9 +800,12 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Clipping/Cl href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Tab_Functions/Tab_Functions.html">Tab contains cross-tab functions for yoking the display of two or more Viewing Tabs and - for locking aspect ratios (used with annotations).
    -
    + for locking aspect ratio (used with annotations)
    . 
    + Shading slightly alters + the coloring assigned to brainordinates to provide a better + quality image.  Shading only affects surfaces.

    Line Series Old Chart Toolbar

    @@ -765,6 +827,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Chart_View/ + + + Series
    (top image) chartable files are graphed for a brainordinate identified in a non-Chart view Viewing Tab, showing a data value (y-axis) for each Map Index/unit of time @@ -807,6 +872,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Chart_View/ + + + parcel connectivity (.pconn.nii) -- matrix @@ -816,6 +884,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Chart_View/ + + + with parcels as the y-axis rows, parcels as the x-axis columns, and the colored cells indicate the correlation (connectivity) values between the parcel pair.
    @@ -829,6 +900,9 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Chart_View/ + + + with parcels as the y-axis rows, map indices as the x-axis columns, and the colored cells indicate the scalar data value for a parcel/map pair in a particular parcel ZlZkEHwr$(C?Vi}SZF6GV_QbZ0oA=)DobTN8Pd{DHuI^pCs#Y!i z)_!RPy`2Ol3|Ej7hlR$11_Aub zDbW(f7XU7{OaufZ03<0QsN(VKLKi{@MI8N`JTEWLh<+72!ib&XDTWnG8`4U_xG#qB z2`QR41w+;*msHW1CVUu)v3{_o-VmJ|8chWSl^1pYd292s9>;y84;PXtcDtct;kd_{ z`F?!T$KmRt?eFgHZkcv19f>3;2{6*H@IN8~L;wQBI7o^AYWJo_q{yR~kJh9%fF{pGV zQzR@oGY-^7J6DWX8bk#I1sZxPm9jq|5O4xd%+O4Cc=*6l`pR_x1Hm=BJrLIW3_&M%Lak$talGvtx;uvZrfdDMufNnMTqpd+9faxnJKh56oyM93^r-UDl`eoxANq7BL| zQC<^z&WwbiMW@3U5G9bm`<$F2PZ)~&`v0uQ|L8ApCe}+-(kPioR^E})@bJGo_`ClB%5=o% z_rp=I)f)zRM^%}!;qBVu7uRqP!eqLxZQgG;LF%c+kM%NqY@R-(<09)eyx{^+)NR++bkplXWFn{1-Y(aG(|WBT5&Pyjr>ScltXuQ>0JcuI>hUZ^K>x6N9^5T~KgTJ!7fKS`k?-S0mp+;#Gue^ z@{kq0T%WsegWl+1)4xFnuRY(N@SW~J`9SZh50 zT!M!hOWb$#K+_SK1((-kG8e4TX*+o*i;9=G$YHnJ>}|GQSsW586pQZdN0AP{N0Bin zVy|sx!N;USCGL$Tp~MIaV)KwD^l`Jp_3~|o0b7^tU9?lB$N*mnh}oGu)b>c`SUr@=%fd!uXlYzNs?MSm#+ zJ42OR)|qQN6=}if_;I=-q5}B=+(3-ABoSnAU7G+l{2}7T6z- z-hUxqB&1x|6Ph3xAcqH*Tv{QKKQ*Ph2L82Xwgq;^1eggT=!H2DTJb%Oi-#iLK=S{$Td;@lmMKs1GtRWTA=8_5nq}XCE$_Y%2(tgzoUwemNXV zgurAnnYBKTB1;kwpEe&)qTIo?N2k*X!{Kz==@0%LaC+cHtJwfbtKBkKBAfYODs6yf z7I%pLr-cmbE#CHCUR{6e ztfon{^fOWp$$LzNO-rArHS;p%QaPOOq~jYP>F%?bsds_$r@|T=5;)odQd@6JP`b`-f%#y z$!-B|I=#VYCg)$!ui55G{0jA2x-%IkzjnA4s+A$YV9;T2dhISyc6IUe%@r@!{!ztLy(d&P6`^Jy6S zTX-k~df=I}uCA`?F=V2}K6n1erGDce%8|!d>Slpv^hbK$3%~I z-sH)>MP0jZ&m8cIsSFc6$RB`_nvi-0b&z9!?9sh0LdOEKVL@cfm>UUMqXIH(oU5c4 zh=B}hR#6cVgC7Z7ZMIH*`Bna@bk=w@Z-*QBN~)#iAUL~c=oQj9!@h81D(zypxs&2zRw=T@yB z{;02Fx?_J32>9oy}WkZ^Mwp@G0JTD&2LSl(Z|)g50^F+<~{DMh3SFlF4^V zW;#)e8RnS3J@bL$zW?Nn=f(hND*v)?mNvJbzR?mLC?g(TE6jZtQJ!x29$CZv)&9{L z?OE5k-)c;5l;gS+1p?3tgTBogW*Fo%HUwWR6M7J?>i(39gv+Hhf2Hx|99a=?ovw$x zCeb`Z#|&O>AWB>WsR$MZ9XyI*fb51^12!Bnc(4#yD+I}#tDQK>)mcl&x(W&OPt9+reJ zXi0VD?E1DFEy00-fiG^^-0mSx^#(!dSAefq@iZFh-Sk~HaWuy4BP0ne{tSnyyFn3| z-u@ZtuqqbC-PQL62AA}19D;Y7U})8+zPlyyhrpV>8o(woJ%0ZOu6UjCquyqTq!vxY zYNY??F=U6m$u!CYwIe;2%}upG7WHD3)1H!4jK;rq*8zOMhyUk$GnF8p`{Rav&(KgL zy6BS)o}u&}zPXYP`tv7Ugr>8JaBH`3(0*p~q~XX~D1)hheblET6xSJ*(`Vmr6^kvE zPFmd-D8O@c(pb5S@4Tax<>&Tsv#Fmi?1q_@qZ9rbis;4G-p~|C8rLYql7vwjr!(uz zLs|syO3vwdSz7Hve5=Ph5r*>V$ofDj1RD}DwS$K*GC$lI;T~9zN8}3o_b|a7K8qg| zTTNDly!&h{U|);jm9>)W&T`oXfi0(_cINmp5|F9E?TR3|(~6TmS2gmYaac!sG^x_S z`~9QSgOVIi=ZiI(t&)Kvi%V&KHLCix%g0gK#UJ|#-S?5-+{gPlv^Qbmv1%C)=8UlP z_6%l)2hREQaydLB>jR2a*diu}I%IUBiMfyVH7qV-&bLna>xnTO$j&Jr88Rw66sWWC~(#A)LHJ>?~r}^ znRB&7*ZIpj2A4e7U6n%t7=jU{@E5n250+^hjx>yoQ;O{_ii_3SnJf;R!IYQ!fKSpiK(Flv zaPV@nRJ?$7e@Gxp|3}%78|;q3Iwn0?b%!aZ^+p zgjs-QhIXTGAyU)uvol(;mpzfR2X-u+*`Yztup+E_{K(E51h^Xfq_W{v0= zn_f5)ZZPDTc!O!o(WU}OK8yM0CP0%U4pI;n|O=~ zw$Va_RSBB2fYzEs}gc>TlGVF!v?<>7l%?WG< zLQiaGbh^x%CsL=9d^Nvot9ng9_$#@R%i&?yCaK7cm(X3aLKfx{pwEo_zJk+d-v`Ju z#PgMofHF8lmIq&34C2<+GnoDasa4%|rCfGtP(wTaC%U53AGD0T%j^zOVcrofnG^Wy zo3xdowdDnuecBIpO1%qdz2N1I+Llyk6vl^!=kvq=@cuUL4fL$l<#A!Be>)SXhjek< z5}^#>=f3opM<%-d@ii0Z_1wyPw>EY)92=wj`Qm7OU}}tW6&aRfFzfO_W&PliI3!MQkE@Q z+cAfvf2s`g;g40E)?kUi>^AvwJCsDP&&QxVjD2zAgzBwS;3ELo1ow0%T((O$0^PSR zom8NLp*bG%yi+QdFfvFxg~^vS)Q~PFGd0(4&V1wS=HaBNEj@7YxF;f8US+dcRj6`3 z@L~cP&d?_V=sB0u6*{oIpzG(XHMZrMG?JAaX=2i9H4VBbr7YIyLS(YrliHe_sZ^+h zpLGEhipQ47`lcXl;j#4a%C7gv!Z<~EM$^l0A%r!j(>U1A6$CS2n_cSt9Gtt?*ReZ0 z28#AIo9V6mLcRs=aVcySIL}5pVLlLP0?GJDOA@7eHLr^^aZsEzAMg~Vy9(+EZ zAZL?xpUmZp;gOp331!OK($dm9i@9ue8>Z6yW1dHuQc+4W>%5J$6+fJ3tfHXt-T+WElt1W2lnaQAg z|FN=#OmK^mzG}zIL$xZK-9Nd&SVje0oHO|x4Gj>jR)pT@g@*39AVfrW{OnbHEnuo; zJi8-mg&{KC9gGX*3E5_{!P6DLCzN%qqymYQIE$r676`af_xTy=Rqc>Sc3(l&{Ns` zgR%jcF+Z~S6`bfU@3{CypqJ@I-6J*bz$qV+xH~-Z{!~~mY8yJp5N_&dhsyH3(8foHxrSPAIbF(^ur21yy?qP^mVxD z_o3+#u{NtbPfI-U=AiJH-dl`OomnrVd;?TmTO)OHjp+bfuHjK; zijDDco%4{u<|D|GX2*GvtcPLAj_g@9r3V?Zw6=9l+8tT7xY6^c>0n06%5edl^LVIa zRF3}s{P+U=cKjI#3;T+TnlD~0;tcX^7Qlkk`3g7_4x%K?Xs%Q|1N9S4TQp>ACZ1B( zwq%+D$>}7Vz!52l$I3QZ6NA`2H>+!1-tK)a^~;I>f;_43$%{4&!2{^6C8lN_Iag_% z9?BH^tCj=Pbes8)jiHc{^gRJ-ZTpc6MrM)h*qe>!v8y7X>@-Hj;MRhi*FOecfqX6> z8l!2+-Bc<)eY*QqadfJblDjJmsdVeyJD<^bRyd)z(By~ccrBemu%wBZ`hdKk*xO}3xa?5Ub>sYyLA!lrP zBD{=&5D)65llpp-$qGO@v`AI@%XMhUK$^Ja*&VQ(Rp$k9>E-ncVp%q?x3b=4MHTTf z!;bK}w+(yjo9T(>mi*aZv*1zd6)S3J2ISv~FM%6qcHfr zp1kdT5F{*d@J|v9xm>79L=ivpr;n(RtjLWK3Mpdm15VljP6t4rnhwI3G-R^us@DZu zXai=wEEhY2UecrzQ;Nfl+e&%Bt_g}BU!N#1mK7WmR_V$6A>D>bDd|OsZ6C3sz~pU` zgSI2pK|No~Ti;M&{1%D(dB*n52pX+9wT$)U_RcP^?MeJXdm#zC#0c<<56WNkg1S<& zsjlWMH;6-(*YB))gp>v4&BOApcaNt{4at_J{ASRFt~!`@m9uHRK`FF$8k zS}qP;kvtCe$jn*nA@%4hD}=yifsXTNwWGm;f14GQ1QPc;?t>(v5?((Y-X6${A_kcY za~Dn~2+j%xbFncGxnLgaV_K0XlTQ=Y?wKV9S)hhoM;2k z*bj1y8IxwFG;EhIln&0J$6(?Nd5bZnnz);W&JLof&Ji&=kDzDzHAqreWB*2880jG& zl5eBNS{*zZyZ^;TZq}$2?BT9%M&l{2r?)aXVFyTKTbM6xcRh!W&PHNmbl=)ZsIK(k zb`|ULf*p1F%becQQiN;FKU|vo2K`qqyIrAs%3?oTz6>XKuBHnNIZ-u>qm!97bEbhU zb!D`{72O_bCe7)c69jc|SeZ-;T zh$O&r@Ng%Z|GTgS?KW)kql!eYqoO-)*YuK?zLx4IhEKx}XAV_7%bJb#(UHRvUd>gI zlrO4-A$ z$sSze28$!dmM1T~-O*u~f~m-lLmp`nk5=TaW4%!}@$i8Sb*mXE;kP)Nt)PPD5;NM5 z3O5Pu05bNifP@V*?vAjSjZ3(#kw{#Dtil!3Vv`3XO?=@9k_`PgZmbar&-vE74}fjA zLAU)5_v>Y5gh`3I#Q<&+ZDeVE8$kKEWF&d>DS!X)ZnMJs@9H_r`*{A{@j%V8oDI3- z@7#t>Bsddb+a?(}(%JQGU4c3?8~pW4wMenlVLYPFfM{cIQduVa(F93HGiBg$VMgiF zkF75VQ)wdK9Qncrvz~7#o1~MO8-RXO3*8f()W8wT>ZPen#lu%tk*<~#c^?dv`KU{& zwK{<5`9$inBd!I9D2I)=&{g&izx2Y7djYRU--iu$BL+%Shr#d1LwkWQbVTs%a@fSj z4;G!|1JB=u%PoPk*x4Y5TuyD%qVI^`XoFJT1K5G64WNfw z@phn-tzE$rw4M{Zi~21-)`wp#DO}>WY?@hMKeo2gX-xpLF?88=zw?hD`aIw$@#X}| zZI0o1yQnJO=uQJEQwZ)$77kXiQKw}U58U2xCsYQk^8@8Vk$&;8huaqh2#9#_O76N2{G!TV{ z%uF#pw11pjsotx_vFB1i)Qt1eXAF&Fg^KDilZKyCRcQ(BNGQJwILU3R_)1 z@ijV5O(A#di6&vFZEHf0kReXGG$ciHOQo3Ict&pf+(*X^YGz9+k?$lyG9e+?L=N>kGmEbWx*W2dVdzp!b8hwV@Uyi|}&v$eTY^!ll+7^9;FMHhb!?`}rcG z(P{-b@>&twFL#cfp8z3!gGuO&Upi4PFaU zu0NjI?`RTYvJ=BvKV>G-u^`2DR?UMgcr&C+=MQ|4hoEnC==A}(y575|$$bLT9*9^o zY1Swf5`xp0sx#rY3oavW4%2E!a5xkqC^jWk6gxXb^6KWGZPiY^`Vz zNij8XLZ6P8Lvc#d#a5fAKBy%H za6W0xqq#qpA@G&b*@s{a{NtX{V#uTQXA(Pmc9+}d$(O;0W%~!{3%#?>04DY7kb3W)0AT&8bC66GpO2=K@t~+|!iGs8$wMb+U#Vj@| za`wqsj9x^C_$<;)&0DPR7-OX`=iHDvYp_-S3rHUT7SXLpaTZlM;Z&TdieW?oR6Ap* zM7$(NnhB#=T5wh`S+_to>ab1mHX5U7J!1#3nZl^{dW9i9^#1O7E&IK!aVyyW6S!(# zrB!fAN}BKXeILZ+?d0GxRVFi;7j*iDvMgd1OykwDhMqXoleV_HpQY>cl;GOeT1AbV z<`aAPoY0`AN}f0okt?^48IQIEMCM{R;cudlioQDt-Tx`qiZ#{Gi?;^?_BkIAA32f3 zSW=oXI5Xx(6LQ6M=9w4)>E`uS>|8SGau>oYQ1O>$I|YruSnhVPokJ!D_EB7&fG{q< zUqGQSI&jaA$oeC`%<*u!p`PYkcM5~=HHo`Rp6f$IS4_Mg80bkWzMe+`(19!B%ZteD z<^0(8Br&M)Ppp7Paoc4P+zpTDwAj=EpgKZ=K-7{=jJiT{A(Jd?Ld^Lu`2YT({NnBO zlVmrAHLu>Q&sFAFy_VNErkt(c7~Z5rZ=I2v1aHxMI2nlowE}ldgppp;UVGCwpZdW>0(P<3>$w)MEEBHds}6qGo@dv7ZJlYx90fj z$xA$w>WNIqru_A|q7Mc#n$|*oIGZOJ7*vdjPd);}Vb3slG#Fm&M0vVsA&FxtapN#&uDWw%%Kii-9r+>bK)V0Zin9%fD zOB$(36oZ!eDBP(ggxH=VrcuaQ>f$kLm;7%W$qMp$MR`-Al%Na9X|JNzlKs{E(x^ER zF6&NUZ?x)3`jly)B-7+Mr(}6rG)qz+^6kGjrjxT|RP>fFK-gB(Kpy_3#2EH74mXYj z*iEFNm!|d@h--2`3U=%3wcOivNGQ8dUjCHTRlTWFv5 zl_a5mbdR0jsrzq?QdE0K&kQ+}?UB``1R~JtLLOW*q!HU2*4SGp)oasBOHO3>Kzhy&%N;tt%~= zJxBPT3eSBeA4Y%6eY~@e82sgSmm8s95Gf}Wz-9Q%?fJgy?l!t5OBsH1RKrbd(uaB+ z^G2K+G@$%Gp~rkpyzZrVk2-QK7b%=uYh^ZSa?m!BQ6v zw1)nM0W5Oms6RQHs3GlGop#s#^>>9Uq-OFfo3R6NnU?fL4L^(MNW!qfiuq8Rwo|Lg z!*qTh6n~35P_ZDHW;dU6qK7?ZZ49o<`N@qv)VyW5$AnktqFBws-(wFZovd~u-Gt*r zBo|s);}!Tpm_Q2gX)Xdepdfds2dWPKXOTH%La}LkVgKT|IUjpU| zz%qip&fw|2687@&EjR;oy;^8$NmeJ9iz_8MINr;^4Y~nTM^Y z{b*B4x~$#^2L9SwPf2<%Q%?lFiw@w+&-&!ym!A0e3++$VVAA_#Q+4@@={75vJ=};{ z8*YGmm1$wj*#d2rJn5z5hHeB58m)H@P&iT-GA&pwhmGdBbW^ZDpEbm8@@rt-)mpL4 z0nz1ZQF3ykRaaB`gVt6y;IzrLV7cU2rIm+K+Xl&6K=HZHM(AAQoYUTzbZyKlW~+<| zDk2;m)lCqlC~&hWk?B2(<(?d?-3uY2zD4Sh4syQf^~imP&L zts2$mgw;cw;VBDJ807jaO}GQy>lxpFdBSpQc03eVv5u=VCy_!LOeSkD^ojVb5N^W| z@ipoT)0(fg#nd<%@1vo|!SarVhJF&Zz6-vZf?njH)^G zdBWhZ*M*@B{oLBRH$sU?FlpG6WoJG3ja@LqwH>+(ecRFt*Fs!tGJz4Z&;K zWYS$6f9Yx3G>al8(p9Dgo)ma{eKq{axC%v%8B_jNS;a||MPHjtO7H%0n62DXij_eo z)0edZ0*R_jt0`x8(;N-WQdpxdMn>vykf_WG?heL?(}<<#qv>HvN3c(STqWJ2F>{x@ zF9IF;V7~7UXTvW*d8fAbF^}XLWzEY15%=-neO3XTPR|b&14&EHJnOSQfUfU@C@nCJ z(U?x1n~I5nfg!zt4Zz$F$)h5|o|?gCw-eF2*(JfKd+`P#bZVn+#Aypprqu<-x-&Eu7g3kUV13L{(|<@LRDlzj zYzI^DXk6wKLW;(k^z*;mXKEyu^iLaP9RIqnt<(X4XeEbBLGx^?bTK0Fe7(sp*=M=! zw(VIQP%I$x9VxNgmXi^_DD6R%eEfVmTy*`1}Tw4CR7GF|#! zjVm?jsQDJL(Kr~o4O*Jk*bw%fWiaJ@&{<>Ijp_EUQ8ihvr&SpKvvKD#GYgAK5Nq)v z%iuDDJfh}fZ2ARyMk-{RBS^ksK8ehza0y^CSn~W7CGu8PH2mHot(4McU!KQx{8fiXq!4OX41pyUt)nCzB~FDo~5bn3nD-rXIqjlx9*QaoJ@_ zBnr0!PPp_zXjxpG(df;p^_5=WH|qc;^uEdBCRP36p4fyEhVvjUk-kmrbSiE5h8AGH zi5-IF{f&OI+5;z@sfQ_ZWZ_sYjnkCuPR%;J-_1^`l(*-+`$*T=uu6B35;;4QGa6$$M7d=cjcpjJ%(>3J zK(c~z=H*{>toZGSbPd9F!&Fhq7a5?fJ9u)$4U)llj60j@zAr;;`G~o`H#Z$!Z(z)s zPI@%KZCnO{xw%Sa=fQJ|&>Hvk`6thZlZvT_){4O-Gdyk}nRDimMOJ%$Kwbai?}0$v z$z8Yn_-;pf>21X35&FJ~I&`!9-(648&g^)?fj;Gm zvWG!W{1E+~_iQ-45AbwcsC@yh-m`fD@vh}&ig7tspcnTl{`R#mm$SN?*nd(ir4k@l zLH%{~x)>`z9cLB07?yC0f7q3AGKS(d5gJSMctiC#z&IC-b*e{V2@6D3Rh>m+=X2QI`(y~=8 ziRjCB0j57(_6vf-GOUBPw2gNpJ^bmnA7Ne-^4d(N{x)m5b>RbR!#@(%dBC;!o0PZW zTjq12S_9fOHSl#o_Bc;s4Qnx}4eh*3Mqmb}+?Y#-u*4fBBn3#v9o-L;D~%ZU8C5JX z<`DH~er42+cq5P$lHzhGp^hm^q!$IaQ`p=I`C24n^MUT{mF~_5eYN{1tcR@KRl-~! ztp;}%E=qSflnCOz{(jU_0jR$)w+S{`mk>X-HtCSW-riW(qPiSfcQN^BiWFFDFiq^b zW11-n)G^9rS=AbJ$=K+6I-1IqRAx#)^9~1szp}Y|qML-;k`~zBm%6R7-&AWbodExN z$`O1ns7kU8S)_n>JhCZsCFz9!AjW*>Itf3(u>mHqTKWo`-R3HwLC1t5{12S}`}4K* zkGO<@5-Jpm!8+z>1Q3n&{@*1q0{sDN6FDH#J4JRr1qEtPSxP{1=G- zKh{!!N_1yHMaxdp=6}=D{~s(Z0rsE$pe(4lV1h`m)0$W7{*&zduMkKgkd6taca+WYDwaYU=qm@8=rXdFk`;vJFS8fs~1y zO+bg(_mAT$_71VNbG+7Q?(y}(sn_jOZm$Lh2RE9=NSu|O9Z#pr)z$Gv*t}aq*Wr@_ zS%%24lrodcUkjH)mh%A*Z;#k+bpoem zEV_86g+8xX95~!JUKU>EV74i>;PS~tPLp+?m*%;z@?^Ps#&suBU zI{A^N^Dkpx^#SuG&?L5ttF_u^{F6=t4k?Vcp(29Z|FGmNfBuLbHK*+KB2UG|A&7{H zMfBx6?DqfESVV@6+wuJB@_MAg4TXi@`pc8m(n5i>3);p*uVkxliiXT%-NXKY5VLR5^#rw!cJBa19@aB+nogI* zA351l2es*U5fc^Ny*r#R0xH*RB>Rsvb8~Zl67(ZU;ZbP3_hs%ltR|33_m5Gg@W@6w zKEQr(oLFBBil@Em;-j!p7@l0=GdgU^v7E3&_?{j9ee2-qMvq8^Kr9kVjE`rMiZ{xpRN(LgMLeZ<+(ac%}xCON6PSYzY$hswqR z4ew7W_pPT{bm-1=j=dR9IL+-BMV}z^oX0UeLf6--LT!=+9xo{Erv*38STTaJ=0~o!lNE=`@D|P13&*4W0#xZ2@SA>zSGKm$ z#1xiXii%n}KxwFq5?7kx^70bwzE>;m2M2+wE^ENHuKHk!e|i3U$q{zBx?T?Q=3%Dp z$uG9kY431Dz{%Uy4n@xlN3pxh^e5h6SN{CK`%yjLXY@RP+^pI@{DEbPc3Cr+r>5P?)9cXIo1WU$yp zSsqNEgCh$MJFpz3q%|dSO?Oa`AD2(32FrNf9n_aq@Z_8PhUms7c5NU2NL;_vJ+{~2 z7p_{%#dKe$IUbE4D57Mhw`5>3m9unZuA=VQXy_iEmxpFoZq0C#k6J;H2yi%8?UWu~diSZ5iLVF12eci*^jW|NHzsYdq}+qsa}X+4?>I%Pf)S z5_&hWr3m#xQmYSZiJ`S*9(~vX?5_%K5q+ubUC~|7R2;f2e>r>{SU72&8W%UaTP{U_=fZmL)i}6IMHh58 zfEyr`IWLxkh9mkP#TaLVILn-UB-QGCEVujbCydC^ceUL^&xTm8)7GFEvcLeGx!~d9 zfw1p^fWvM+omC&WI)|l@Ju$cqpPy;|n}Tcfr0x@A0ES$VjQBk<*8M5Ino6XW|l9-uG4%>cYcyG^>mg@$o5V?X|T!y~-PpiJk7{vx;HgeCw&=a&>? zwmQ=uZjJe5nm?g%h(H&3*1*tTJ!whdt$m`rG^YD@P2s7Ad`jlpSmVlsB&%_pziy7Y z^IE?9L~(99t)FB`QA3WD&zx$H`cT`uzI8pXc8ilvzY@773H(eE-%c=vY~_acM%2NL z9ifqhS(BRr2Dm51Dl-=pbSwa1>iOi3il6F3%g|VnxoJGOy1a8;v87aJ!ZfE`SzFx1 z4p!KoJd&sceX&n9(UjF>H+Xyq%KZ~YbenZnQrh!*VurG@Qjn`xA@*vv{_0N>A6&EO zv{bs{JBMu);`eMNFoW>h|9F2V`Xh6tEU`3s>yjz0o;%wc^`ay%V-xvadE&{mQ}D41xRgK-*Okv1+f^LlitH*tAki zYX2V{^HZw#@W$xW8-$+24x?1N-9!SG6Xt{yV;$vDv+XHiZZPDO<%NU1_kcf9et#N; zH%P(fTiq(Y->)w{8v|HQMWxY-TTXW!nt8WB;nA#EMr~ZK>Z|hs8yighd^diMrZ|J7 zH_+%RfFvM$+PMKQTLHkjRv!2~gPJ|ok}p@@W;AAmE3ulKw++aP{F;+&2v z`Lq#(U#wI|wxQE&EP=S9$q9qgv#oo#lhLm8Jqnk1(;Uv{PC)%t&19A&q>|G0^rP7 z#N78{oLQk?;>J3$sk|khGa-Kd3t)7=vbW%V7hjw(jyQhR`Eh+5XMfMMUEjWTXLYSN?vw9>PERYx@rRa@2$w~Ud{=d6Qpc^6LR}+ z?vz>e3qVv?V@Dy<6r!~oPOK^~iV9HaJnm5YR*cdFCP;)&0%Q>p=qQmeBM+ml)v^QD zf|C=>vQeE2Z~ma8jHN)Cyij^O?p!WceR4Y->>PWY*`DCT$r>W+-SC0iey#m%uRRPC ztY%Pew*N~$zr@=~u;%-9gn(AL7LZe;itRNx4B+-Hy2z@BaGVdF%dZiVce4!S;sdt( z^b87ObLc{fmSJDh+h)xh!5aiU|Hht~!6Ev}MkE`>PE<3YKfc86(ncJHoO1K2QpbqE z<{4%22{&+@ziMbJ8~a9fZD_FUVc@jr7)0dj=!@6$4%BwNNl@%~l0vPZNW*#JNNRsL z3ecbD4>G&b^Or&0RMsfJU}!Gic%;biOa{eirABv9rDVmLgHuD5X$6ndhQgLd6`?pR ze^)vmxCwLVY^gF?edC{`(S&{@wQbpKv9!C(_4JCthnE9l8~DDK$AzV#OH+tiNvCl{ zcNpX0hbUo!Fnr||^Qw#6Pl4LYUL-w(Iba&cF_+7g>c?I!fDpyiyQaXW5&9EbSntA1 z6S{v>o}N(Hea!AFT{7+&w8IR@!8!T3Br7w?9E0C(B%sljShLfP_{?v)mc6>v{^NTK zHGzjWbl|(r$o%@NPB12>`1Ucx{?E{_6VCW13-EO@>;nXHC{bz;2N+ARQlDr{FF>_H zRvw#sYn>U67advk*Yar= z^dEq|SeSZ?LMCH8wCIEVtZEvHGY{yxIyF`QZI26P6Sf?5Xe!H_m#UCoGOXUOXR^tK z9}n=y!~_9FvfDONu-tkGUa=%g0&u{Muu7)?oAsj_n|u4BBm-3}{U%8-Kwn=b7~YRT zqK5WHS0ooVV~K?LE6_H7IBPb@GifKCz3mRLY>r(F#Z0bPGZ!z;fZdhzwRmFEE7L4z zxQK_6Riho5#^jY8Pl4cUI7TVyUc+tT&GV$xL2>(HNKGN16q^}Fjc2vj1T=j*aiY3# z`*9%JJr>ARra4^SSnM`i^W7T{2hNY} zjY!RNdoWe zuhouA2NJb0#vSHc;TcoSYn$oe*B{dKX$qKA3X&X){tt^B~crF`JEF zTwcPmS*j^_mQ2#y8Q%w-7Wn)s>>jC!9Hy0RvJ~4lB3NS0WA}oH>Tl>}u0N}oUP+l@ ztFDa?;N@$EZ0?X90E`Q(56Ydn+v5n8TmGB1x?&{GPaL6iS*eB0{~~k{Bb3>4_@VBZ ztMElHEmX|wQ`p5XCAli`m9I>Sk=x;gtrCZmmcNcpK4_p$qi@ns2^H9@L^YaWtBW-vh8}p0;U{cedo-1reJ%UzZtpSC{=Sl!E?&Hd3m1b0BdKKN;ZYXHPn^Vm z|NW;p#kqgyFIWi7tR|F<;i$OrorXO`KDkfkcaQP-@dG@#dl_54pH4$AnfqpTz}pA= z@wrzA%zfG)Yq#yhhDD>XVj{K8VO#LxZAO$TQy9OE`4cy|O}@B}?TZg0c*QCNKjwDx z7`wk;0TjrKjFgU7hv9fSdN~gMdl0K8DgL!2 zeS?3}XusgNHu|H(XrHY#dD_)M8O zygH4T#2;b7XRc`FKMWaYC-DcH2ckjgI@o;EIAeVAmwqVSv>P_RAYlkuoOEki4qca> ziAl~zPwKK-Ti^JLq`{6EBhmExz3?vKB7%S0JD0$hduQPM`2XRug#rq7nbmo!-TB!v zdWJt|EJwH2wNRx+dn(6Tgz6$b+qWJIGy39U=tV63Xg2z<)iQs^-S1*%g*Ld?X#=j@ zIE$qPr=fQLO~_fZJC^pUiC#;0;_D9X2;DRqz0bAAMLN1HXhRc>Y_kQLyfv|4X#js} z_F9UyU$=nsgMH}GVkt%*y@Jq-fq2-v0XD^O0cNXZ4g+(3W)n5=G)zbP{s8~$zf-0Bkva8KF0hxUzGE?D`5ye*s5tB>uQlxpV!cR&Ll8T1@FYUtbVPA7!{o9ApQOC9*8}YG zq8ODGmDeI{cn$U>io%J%4glKBNYyQ{_F`L@H`A_|=jql_3h{cs}WYvg}_eM$%}sNvv1 za3nq|a~2bcnVi?qol-w6ayS@r7m?AGP|f!n?5Wy^w!|lMDZAnrP8-9Rr59%~p!zV3 z-x-c-^iw(`+NriJn~nFrdD3t3Db=a#7yjt1H#O^w1_ipI>DW!U8r2zRlP38-Kt?cwkf52DHov zjQye(%DFbhqHPyZ>$6fyDpuVUQ|2B$dI*j3FTeaE+J3QO#l-K|T;kDJcfx-oFmhW6 zCV3YG`qaj=Ow}=K<9W0kP}v~reQcV#5a_fDM;3gB4EPG}FEW3keYXvm*42ZU(BvU& z>TA4&(TE5EYE_{6tH`lvS-4{<{RUNz$@O@5KSq)Qa`M%EIGjF$%CQhT&X0hfdo*5U zYl;^Fae)y$lEpc!~s}Wn^UU)ff+P6ZXJed%ZuNa(Z z9CU6r6^Dw4;6i`kFW9?kHc)d09ZTViqJ>Bp8=Mb$oE`D_>|vZoA>2H)5x-K7qCfoe z99s1(pIoRUIG@uizQR}%`p!G}E85rx!u6w`=sdd?b`fKi)MTGAwpK97@_Q48+3h>f zNYVp4S9DJX4 zb>KT>Dlb8Uq4I~O6KK~FR#*(}`JqO%vXp;~$q9f9q^ z+fgrduOiUZM&2X>X%7Ltrqf*2dG}gn2V28%eAXs!=bupGI7ZLu)F;F<04LP%+n=TRbML06EU4bAEil&?U#~fUuzMl+XT>P^Ee3jwXb8j5>X_PR?JVQqxuZB8 zau2VfmGyeh@tD>y{JZ8G45oqX;r)AvqzH->uIH!~6#k0Hi+8Kjk`t=81gc zLwI;NoSoGJ9B7By3t~-YeCa%UYI|@w#nEg3#Z_X~&!4}9OP5YyQGXiw<}T2!&wWZE z%A=SH((DC_k=sFBxD!PKXC;iLL3Hzpi@1J<2IwKHuz|$HGY$kJ?A$&IHw0e9ydryD z9Nd2}51p?LM^mqIC|1lJBYru6rxs0q$*gu{Ibx7nqhgkuIDY&v4xIl7XRaN<;WIar z#T1e%lA`F<^Ov#8Q>G3HgNRt>q@k_$+q<^MhKuGFSm#82I*Mn`{5j~v5g+qE9ld!? zOeN5zZ55q^GpbarOPu~ugtD^mWhmg$2V{Q{t)+aP=;Q&cTzAN3o5NUR%KYdyn^x9E z%bGfd%ee}A4Fdkza5QfDUfjgCGr;(sjfml7%76xb)9Ah%cWnQ26FC_BXH9*LrDxL3 zqTidz*j9O*4_rm@n<8Y#A6WnAWw_U*-eH5`S(Fqc9rYK+NO6y5hBSA~#x3?4kd1%# zD0r=}oAx1e#}BApyFY>=vY|=e?@^Pc|Lmg=#?PEo&2q$m(ixEHol$MU_ZV3zdCXNQ z=LA#K#WiR;d^?&<-9|z|JHWL$woRpNg=WxLeBfS!(@U8V-r%2aJ7Y#L=@W<4z$+S) z_{>uMbs~gB;I<>DQk@YNwlwwzMOlAJAz*2kI0B2u#+&5drd)PyrgRqPy0CRI!ac|0 z_?m>KVM{y0DVCoTI`0aDf4P|1nNz9m2;0@2W_#36haJE#yIXf+qd{ zzQXxk?XajvAbR>W)oQuCI-`GQH`>L`4@(=LM?fX>QaEi{0AGqfQCF5Bi?*R7GZ^oX zUcP*(-}%+B7<>jGGku1{JC1)|xg3l(ty>#<+5EjplP0u&^ea@TR9T-km+1tV*Nz@J zg4UZJMFu*z^V;?6vDS4yBonbJRbt}kBU}0Kl;Wq)Jc3Tl7ZFyKB8?EZ)NxTPpUPQl#CoVkT3bkpiR=!ho%9@$@l=kT^5 zQ>M(8q!E;*IDl8r~sqU7=qPKQ22vzKrkpZ;*#`9@3Id!?Jxo_^MWZocetR_Pe)6G5S$4`X9$|ZjhVEP(!pz!JoUM# zAJnrJwL6U^wx}n4nOm2L<0Lvb!w*eo#Lfe56KMX@-2y?oLA*q~s+Zv;BD&cq>Fi%) z;>3QKxa$Zec$dKaQ>#Fm=wkGSW`Zd-8(Dfv1SA3}9sz&-Fw1torl@}X`ohat7~T+w zO=YhWLttzzmtmUB%y3xlh&gVYG#xy!Bs4T8KRUW%j`|%L(P3>UI#390+>EHxdkR8( zj6;;>4eT6=QDEkj?fofir=6;_$T_21H-z#;OZd|~tiw2j(j|x>Xf|#wZR!vO%^N$? z#PUe>2K|4AYv7p02`@tTW7V!#m=F?*C4vFgVC#tAu;QxDZk+O~(|Zm=Nh=WblFH(& zElZp_YI95Q|HP(Kwrp91-MS?X*v_0e3o_|8eu|2U!lA=Q;*{go&6|jL5RL%@2EfnH zFOI*h9rzfRHmyI#@3aMbNjk=bHwj|e^5>uUbK8G5GTqJw=S-Oq5)vZZ`FNGkTQ|XH zb}e7JLAWL4pD`TuZu*~rc5R%J?uXfm>NXO3jpFr4P=T(fGq3=*ec1#V?vaTcp9|My zCQ4@Hwg42X(}si@oyaW64Qonfrt`e3Qv9)4yd79L!Ckan&CQ)?(_sWUPg#S0%}T)` zgFS!#qm;9!x2LtBmoc?VFWQ-BA%?dut`tMW)4n+4v)LQ)ncjzZp6~0yS2F{rhuW4A zXKeKNP=4xX{ynq#wt8LX`Sa&dl8(4h)^!@jR~0!{T59(MJrmv;DZ<#6oz*@}hcRJGqiT~770HiY^A>iU`w$-a(gHgFsUcy~u&2yqAn=18`PhI5}W`FKRd4@K?~oI1Gd- zwnn(ym%zlp@9~Lu1!6s!nquwIcA{kWKyym zYfpWKZu!d~+rkdW|8N0rEND%e8XbQ|?fg2SaJv~eTPCJ0aO$SW90rDdiolxFawe^+ zIbw#B1=SoURyrRR#5kHCh~JuSOxLE94c(T65|T{XKAE3vk|!smqKs~xsBh^+E;0G2 zyls>x&1I-QoQp|{RezJAghwn4%?C|Z-w$)u!Ik6N@W=045p?n-o@H-=l{c+k1k<*;)kX2t4M zL;}pX#w10|Co!CYND4P;Qa?=Et(C%spIn7`#Pf{$%|Ht0NM*5b0%MyJn@@$A&Y?rU z!mn%B;^j*XZk)ObHcNG(BNl(IT)u=XE?LEKDM~6ia^^&lLIuQeA&Og4-^Y(1FV4j5 z*M9(=7g|kZ$BgCu@Ovmwpdgvrgu=ay2OJ37+hlg*UdjzKXU>dOZd;Yn_~g!>w3fiC z9cR%kpb_n2Iurd{eu<_Vv}}%Bn^E{@Dwz@~g~(kIQUD;T7cT~1 zyiPc|=s9K7Z{ap{E|Uo_bQ;f0IrAfT7F+%hUtr&Y0MzzhNb4P^;dJ<5c;wV}q0Sz? z5q2muhK=w=?J7X)k#m1AXVCvJaOW$VX*#XJGU{n4NhO|$1KMMz_r!FOd8Hv6nIUr? zVmZ&? z4!VY!=0JbNapMZTr*rxKSW#a4+S7!4jw+vF?}HAcJ&cAUt<8VbwoD*Tt^Slxe_dMc zv@u#2XrgJOGDkXpkt|*4fx_0uMkQYgS;cP#9(0dDSVL(gPiruG*Kr+ld!VB~UGKUeGJlDHM8M_<*km+ea|>o7AJCu`6cmKq zxpRw+g_NUIn8|6V}!b+c#Bfp#4~ z6=||r?XJJ+n2-D6$n2B>Cr+Ngn>YUniSt7;6`ep#U~&^{JcoWY1hZ$)rn0<&XLT<$ zYT}K1ckiGQo!Pl(_b%Ke;YQV}RWXg$-tk69HYdjzO?!W=v}ujX6rIMM-E&v$h_#{Z zpwaM@Jsq`YEh8BdCkr~0WV*B7!3iDdJ@!Cqhl(ACBedgJh>FtC*{P1IbV|j_PoIpL z2af@}aoUW3Qh4zuHX}xi5F6SYIdTMN&YZ#U;lq=a;pBR;ZZ21`qHry&XZvkjU0Ops z%9C~q&W?Xo$HMSgWo7ZEHk`z-L#mj2o8TlCx-ZiTekUV2Hjp2mM}lSJX-OUh(i3p~=LODE4sVebF^G1i-A=o|<|NG~6HA==;xi+Y^_)djgXrG9J6JP2C?Eit zsjYwf@%wt@qVi?Wm78|BEr5@R;bf*XWsseUNwlU!Y|5Qf%#tDs{B;)6)~nmM#@q^REU62qySXTHndS3rpJIyDtCxp1*^G10Fqk6l)_e zW;E5zrh);7!LywKA>rZxC~&3OjhrLB#0+ z$Xe=C?3{lZ4Z79FciM$yn6~W-J}YHAF3l=aX6I`7Vefogt?iHE3;ns|Xgz)tzTx9j zh+aQ9k2C*};jNG(WI($q$1pOu3YwNC&Xmbx5DtCM$EPG8SykWUE2hjzA|QVekO)Ww zBmxov3lPvVo#qynD}Kt|f^=n&BtXDg{CPb~pFVw(pk%gBvQ(*3;7g&FEn6y&R^N@` zXw1#(jNYRJ)cCMgme+8b+I?DGZ4Srb)$!H-rrgzG;(c}~i~o^^p2<{tyxGUCTiR_n zOodVBQ>yCa^O=d|XJ_V*=IZfDxKN+FNl8}PQb@<#Wpm1*tzTa2a+Txd%)GTBUI zWmHL;dQ_KJ{cLT0P332;ySj|(v`o3H!@Td$<}fhydldBnb_LVYj!=IGguh4+Q}z(F z4H$A|c!f&&U!uO-3uJX-7fIG2VE8Tg{q^hDw9F$4&!0aRYitd}Sd(8`i~GOJ9|;Se zcroNguWQa(9N(a1j@KxcM}uP7qthB>vc72qftXo`nF=RFyL2WjJ#DL>4%Z*0$DJqI zkYisg`urwShV_?{qO zvr+c`vk&q2`HVPtDHOb&0->yi zL?C$)*ha_5C=`FMBvlERz`MD1n0ypUo;-OF92_imqIPw46_XS;;pR1*ydxza?9E!v zf&~lek4{No5oB;efK8JbPi5UTgJQ~*nZqTADRWYOn53`oYh0ldEjOI~3)N}!-e^3- zU!zOGdq!p4o#CzD@zqv!Jay`nt&)20(qRoJGn_nEFhzfFbURUhNP*JXe<-w~ahT4R zS1|jlsklywkdjVMPj3J|3+5zh4Y!iW%gB3ppmBt2?$o^(g;F0=ch+$7CXeOImp2te zx+egEH*bln{ExUyW-f_HkxZITeh{zZM|XPHyYnl(JJOu_nZ^MpZ@(d?^O-KNyh#M! z9|UZ|bTWU#`TI#{1l`LZ1`)%3L-?Hsmbdgn-1mR>t^_cq>+AnYWJm0=lvqOuK?q8y zsGWvJN`%I~)mlp}pREM7Qx#RA6}u8qwbYWvUi`I1B$^OgYKhnq+4;_SGjH-{GBcSZ zlSp`n$$RhKbI-l^%$xV_xo5j$g_lW%(6eD&M!|oRULK434@Y93?=Z_f-L#U~{p4~0 zMlQUMIsQ{nTW1`QcpR8B7I)jt!SIhNzB}KNJQJA%N)9+WI_3*ru-|sos#OI|Ci@7p zNfryhEUa==Vb+FneP;Rh^2KEG@gSIg4<0;F6FPMbm+=ZZzw>6kB~h$2r3s<8A0-Zf z>!*L?fgj>X0Of1r0q3ffK{p53q*kAXlLbysio?~YN)dd$Jq3kH=;SsTATWR#JZkY{LTK*5b|ebITo2d>^7o*{3l0nG~x3JaZinc}LzFeaM= zr9=P(wD2XtljTfdO)LnSR7N1aD+MW(%0+)!l__+UHrr2olV9q8u}W2nsA~637FcVR=IGD`R)WpeQJ;NL?nqgyK^eeoS6U{ zO7zaVL)zgDo`xRA?y@5=tc7|?1MT<)t5o_O<@X)*{5(D>AH_RBTbWoVAGLFUeKmhs zu+#^c@inu0eYA~H_qO}joCA+XIwltGBO@aPzu3%7nK>mDn=*^-#iM2)`RUr2^EG^4 zrx0@V98yTrneZ$OKX@<4_?>@|_-PpE;;XK5!>GRdSepD%EWfqS`_1duuq&Geucp=r zx)@7H3X^qiqe%ya-Uum^d|1ZO-M*E$VZ=XqtETe;ze_@BJc`d0&Rw2%iL-3YE@Zr zO@E(W*^M!Mdm-S8H~vZ44D6hXzI|uminl*rZXO^+%vK@4gD0uvHZKU8EO>tsykV`U z@;qI{RBX~J*0YMcORzAaCQsr_GT!F`CHarcfr8BegPwmUPMi>C`SHgeXP7PfaI#4) z3zLc;nF57h8n5ZYz@{-DC~as&!IRt6tB|DO<7tKFo)gF>#uw-A4@Q@Y%HhTTi@*S& z$C9ovB%@a;Q`#lUMab%lD;IxV<_^6!i(#j{8UF!H{<~Zy+_5&&vd5rzbx}&e_I)rSw4nHrRR{{>sB!RQ~9PFC^F-pC>gi$1L zR-faK6qz2s|BuE}n`9^OL`h(L>oDo84-V6V5{fe&>rZ%k~PRweK+ji>3`nqjH)% zobd=8I|#`mHo$*VX^)#2u@gS4fekA?Q8*$HJ~RGAw{FELxjiMQBk-QR0q!40!ebCU zR0&#mFTm2deId%e`d(Z@gFO6GqJ$!8dmeUaP*m@?bh*=2t)tt|+1(>Cwy&Q}{PZDlXf z5_7)u1HGOE=sUeMrti9jj-!q5&-Om~$Ys~MMG!IzzozJ^iVbSMw>#5UQLCIO#`@nx zA+yq|O>1r6CztU?Ld2P4IQ_&L3OCSXSd^=ernSrA{vV6bw%;0zTD1-HY8OGsS`YMb zy^jOe*Q0;te>>qy0%s2rG>>ygQVbO!0yW!UOkNZo{ARJHXx*1P24`b9Q}Vrbb;xS>lmophe+tv*nbS#Y)cJ; zFAJQGb8!2_Oo)2TX00Bf+{a}xw(nF7>9H4$NhzK5jO5bKJ>k)f)^Mp;K$rO3vme^l z&he7d*i+9HdVCLxLZ?)$bh7&ZgPNP*zn54MLcAQstKoED{4_lqDCwB;naqKL z#{qwXo&ef3oZ?hDO080fDHQPwq(=EPEcCEe38HQ3xie{39Bw{L*LZRpZkqwD>cDd# zFlc=+o{-R43W+#(U>Qk(3*cNT9y^CL!NkM%n7ug=ElR$`_6hyq-sBd&Kvu$0V>2{1 z^bC?E3FFfe;&5g!^|+FM)bV7l8$cg#Y&(B)9Ju68q9$ptb8jKqN}SCl4AN_qw@7P8T|rZ%de3NYE2dcJJJzK#XmUo$I= z&F%T7kfoz&<5$(i2e?fVj|^{x11w}N^D;%)e<`F5Oh$R~s~OPJ8V4@LkS`@|s+4~= zEE;sc>=n3Rubct}IScQx1lLz~LGW7IRHpO6pEz;kD10`417`0XgkR3w$BY(Dv3bL8 z)cd$8iYLXxq;gdyfm9T?YlN;nX$yRPO}MrGNHD(+6Kc&eXd;D`4Ef>-FmNpn&h8@M zgl!o@+Es7b0Pl**wA!lXJ_HMb{V{)a{W0`gsIc2QbLSCWrZj?!*IXQLG6F?E%>BH^ z%8_R2@bqF3)=`VK8%L`IP6dH77_!zMW9tmWo}<%Pft4)^NEbQlRsI0OJ~F|v8?UkTTq?Yp6&9{n67rQhiUxlo_Ulxs z7%I||k1_`eJ_igEI`vJH)1rt`Y8j7TAnhI0HJ_~6>{`DNRvc!t8AYf%E)!F#sM9w= z)9%v%e_#CX;c$FXTwz)}a6=n1Qwb)46PU1VI|hD44>N+Pe8#({J3i6ie}R>G1Nv#~yj7bEd{UtEr#RMhNAzLq(V zYaHm@xpS`3)<#%rqA9IUrCr*WFJG$Vbz@Jxm?x-9O+rlM|z!g!I8hIPNcMDdb_#b$qaNj#f07Vy(<#22J`j#Y3V(pntqWt|CbGvR;7w$Hhsv5xfgSRncaQ@r zq0^We6VCah35v3enoVu}7OUTm9&Nt(^p9jv#$bIU*x8zH#G*-~-0yc?`T+z$q~7?Cb=SJ)!U&{iBVK+RF0d z^xwufxlhf06BB5Jq4G1O40ctB{ajOA%!|ll}lw^P6arx+3ST?MQuvkF=LarnQc+)v9^c8Jt&HoppL%~L_#laxT*hs+LgDJ@GRhu%H|@ao zZN9WC=mQ5*KAIFQN$7`h=HKV(%_zvw(ev~`D^V=HOnJu7$mg%pjpOfKq@6l@F4YI= z_$n;%#WjjvT(@s4KcNWRumN9nFL*&|e0_Z};j4-0+O-=t&>T*lJc(YtdSS}fQ_;VF ze+qv&pRAg?d?Ir|lLM^bWP!6%rApw4s_cWuzk3Eg@->%pJ>xOH3^E5~4#*skazI=* zaFD?gWy)d2{uj7(GY$tYKf#56i@=<$B{V^7qgk%|+6v7)NUgZ057r&MiYLz>;m>_b z;67*&{*L2Tysb=f(aU%|i4MocuiAr_6L^1dSGfyOgzCdXaq{YIvUj32ND&ep&;NmA zSEC94GFJBKgK#FG2ITUW`%^HmRb{}rjMqKpOqZrY?4+i}ii==xe(5p`u%-wPZ z(a#cTvsYn?Ws}Q+5Y>j7)r%_!5h?IZqhZ1=91j-D(vZZb;yNNFSrEpN%r@=s2atab z1Hy-H1@`btBXikgE~9g?E+yrSqMYg!xOAj*0bj?``2FCXJj-{P11e3YzDeqfUR$kX z3La3BXXTnxaQMIf)C&Dqg~N+>Et6@-X3yDJJd7^|t77RgE-6I7ZFNC|PrsmN^)&d> z8(`Wl7YJSsRa#;;?OM+6G704Zr@()yItiJi=Rh_Z?XY=FSwDHhb^VLSXAeP02ZiSue7`37M`2LE8Lz_v=Hr1*#z4-fw z;RtE85Tl(HLRO{?@&KW%MKWHbDPlqtqCi>KN z^YQajp#PvQWIv^V32P6)vx1a&Y-4-Ldu+Bfetr9YsW!)#|s%OnPYcz!dJ`+&6oIqJ6`*bSUA^&~% zIAD;_sc+hx_T=n6HYcGUmGXCERje2uzx)96wm%i@)2(evlfaqo`M|$LHaOt6y1>f* zW00~FYr?(JrhzEcmBN33^+)hxQhSVWS3LCD+;-K01)!YJ8eoO4GZ*705>VS8o=tW3 z7&x#4!mlaNOiXxJQT-LcSEii%MGNSAacM!%w?#{rE=8@{4#N0YD`j81j@nr5NJF(_ z#}10>+f5KG)GFl*nFGWD79=@6haph1WJxkzjLEk`C(ofvmo9&XOeIfn4jee3wI9)c zmU*9)ltj;4h3}6UZ4|MIye|LQ{4_Uh6EpUFwe?Z(%2<^&3s>)rpf^-1;_jZo;O1Qs z@NpD;YFcM&Iz?zhHoxha8dgli(VM11x;5UkHYrjB73uw>4Orl04N$|%T4rHZ4?mCv zl5Vg<>tQQ!+h>0f;wew3iM168dKME8HU`Jj2Dga6VuiBn;u^S$;tEas;>hjZh>xf5)x=uShfq}*4Lv90w&zz=mq`Ba z<}ecnrlgpk4knemA!Ly|Tt_&QDtH&B_ilkwCJDF{^c{aXjaUK4X$R4-Hs7BLRp^ua zH26Fo3+L&CAYi6 zg8WzJKmp}|O2X1-)8D2|8)16da9D6`UMU`@?pmwm>a?ODBK*+=7C8Ck(elH1LFiO% z25BOqJSKk~j>05G&*_^+#cE;9x+n~zg%{f@n9!Sn-ye#xS;A{a6ugwz#p?FL;mGcY zk4t~i%w&4pX|-O6it5D|3fiW1u`Vi#Yqin>Ea5tIIikK;sP^L0#uI@^F8s-9UuVyr z#oc@N(V$@?wb8LTB!JI8lEM&)66D4$X&?cNmUEZAJs-T1vGe zUpoTBz5j=WfkQR6268?MZG6-$dwBIA)~#9r|0Cgw4qd#k@~bcLX;U(<$`s;paPD~A zX*V0gS{Q<#DM1y2<~TVg+NDF=u_y36o>-JZyU&NgqgiDYzA;X?PieoeUcC}bXr;7| z9zB1GB}Gk z+D$K84|v2LL|yi6BzSOc6Fj?46xt8-JBIll4e;;Q=~#Nd3O?LF4TpOjLI?#_$`0t` zfo5Hsnk2XpT)uCPM+v5);wMA5ybfm#Ckve1Mw3p42D%D3z?tBfsC?(E@Cpfm&-i~* zpk0Uqq3M4%aiBC6zHpY=AMQip0+ez58vSQR$_VwEW6-?T)kUkxTXD9`JTxCjc{rz} zV~tyT48FtLs%he@3%pj~@Gq>WRfb58=>*=fv$PCC;|G|v|24kpUI?kLf%QjTV@UhL z=uAO3|1apZM&KY0B$V+z@Q$%ap3Z-J$^n(onUndu)sDlR$kbVuNmxp-YfB!vd)T*V{qrH7COr1Ol zLxzu}I1Gv>rEU50IDF&?1`HUGi`vd-IN`Tk7|YJnBnWq?D4Z8bO+Yf4T77@;K_Mi? z@^)d~L-Zdj(c%jlo69Jy-MR?nP5#60OGjX==T_YK=?o^d&RmdudhH1IlpASup;Mh3 zsW|yqB|A{?Q6W#Phw6l1~>>@UoT z#yfQAAXGD+?9(Z7D(gq)9s7U9vSwM+oLTgrWx<|GJa7B3gXwpDNgtppSnyjcQ{~yW&`HqO}`oR zT#6$-ya}u+Se%90O41s`PrSi!aR3&Lv6mNr?-8V_0ttzeeuGP4Z!ni$o3pzXf>WhJ zs8Rx$bKtd5uE0{73etattmzc_CLiB54vg zeE3`_qdLZ6Ty7&n-f`fszy89r=P$@)NU2g(cHO46D}sJKfMzaD)do|=t{OIP-mF$; z%!|}}AsBz^8=O1&E!NFHs5HpY?7@he1)8LFUf;%#EO6S7$C-Z}lhCP!6P%iM!lWH% zFy5Zby?ysXp%YFgkd~xfIJPlWdlRQOFxJ`Avlzt!r~g0LJbyCgZ$5@OM0?7KNMrS& zm5y{*oPC5BELecSg9l^f%9X;A1<(lc4HiL)FP6zi!#KeHu%%0v&LD7Vwq}8p@fg1# z!}~U0-QSf1>e7EE4sYZ%>O7v%=HR!`I6S*|3GfKO&}LO(W7_~z4^6@DeU}8&S^nk& zuFgj*hf25;au_~4C!#@VYm{!_fnUeB#BVfWmDU|?TK9P6n)iwWCKeR@sSIs$X$qY06&HVWPBx9!y0rJI{O~zxFX{U9 zKW{LTG@c)l>X(nF{+8m2__S`8^K|Outz1#CIbgI^F$9%KSb0-IUL?O4X`rgES|NZ80*{`{}36m@s}EPM$igsxMov zoS^L-GiHB`V9KYeFw)8OgZ^+OA;rF)B?gAp!Knv6=xCes+wte0e-@$(Ya1q~_F%1$ zK1hoE3;u*Kb&-!M#JvK)0tI}SifhMb4)X7_-OpLIskklOp$_zuSLScpdh~r}pebWH>wxKTAosy|J^O zqp+)!YElNHZ(oO}NhQOH6l)SvW;N;{4HUpI*=Nw=k&dQZ58$^ix zXCFU)oUi?7Gn>f!Hec=hNTzV?&Cs)ZcPPZa?r@@Td9DY-(7qMbkx!xsCYJO(d&wFn zhL(RQue217e;SH%mg&Nyg)*iBN6AFX`mnXO7J`d5^IL^>cIA-rKkBkpd4Y=j=l$aV z=Z2KQcpOj<1Vp@L_Og#B{XhNJ8+>w^77;=jl}qY`5sMrubKqU%fI+ML;NW0k z?xJs}K1Q&Qr@jC|`r68MxyOOamoKBCv$}savzdzv9z1x6YSpWed7c@{kf!7@`G+yE z>7Kc{1wunZQLmn{&8_a?*Quvae&IEoKWz>Rl2`l=|BH@as0TI54mVo2ZVeVZwE@?$ z##bNQyLy7E+vB4;8HLj-?S|opc8b=wkIqMj!TxAJel33O_#q;LR$;7HYdqe19%Fx7 zNVUoF_+^YcmKUFjU;pTaBKJ?DgV!V+DOM9v!<@(hAen^L^YG9&C>?c*WZl5#Ngu;^ zMX-R?W}H8MT0B5U3*#5FDW@oKiqti)#q!)f=FAUQeRK(7TQM!j7Kc6=vx z9=m|(SC(*T+Y`OJHHL-QG$9)Me+qxVfxm9TqLc%=_3MYWwaJDm2f#v@=0=G=|5?V@ z30WE+&Gpb`Y(7lB!YBoo4!zN@qobP7md<{1P+`>h=3pFewJ8gRp)c`_g5Gc-Axcn< z0|BA%m{jNqLK;hjYXrNmFxWTqfcNCh=y!j7G;HJk z#@aat(dZb3&MQ?FICTy+woihCc`Aa)5AV*1?i4|RAdhX0pT>WH;D4p-E9!T#q@%w*~mKk!+L4sbt&iJBsA(Ps>_wJ!AnaNzadKGMHD}|yI zh4|L3ThbzP|3r{BjTpj;=WMRUjT1fjVp6_@fEZa&3GR%aWA~uVl)h zC6;A8#^Ka@(uaC|kMGBHMBQ3-(S71FeCrM@UwIU9{96(RprrAPE^dE6z=J2RP_AKD zTns*lqwX~X`j)jk1Ri_TveeU``dGxdS(PqFr-AT|>4A%6&iYS?Kc1`@h$@o~DK#G= zX3mb9^Un@7DGh0RX?af0?**@fOV<(bf9{6wx9q{5o!?_5wvr!i3w#@VPcLt!QNeg}k1G_uJ%a6<*1$YWSuZrkCVhSuM0%y$r zv2d%?8vF0)5dxJhr3XzOX!DB3;Z1+5IjC33R>*Z*sYY|0 z?%srIo+7_GzJEx$J2by&!Zdg+E+G0Z56jsVw==g9Qr&eKH zZlg&@zE*!f=;D8e^t;u>;lM~YZ{C!m$mcoWz-uz6<%|vr;gil^v#S|hlY*1a6-T~S z)(I(A6!mFwAD~`UMese%?@7Kk>|U4olz;hTkfzfR4X60~Wb-bLrugjHGYSK)h)!ok z5oT>{Yy_X9G9=*0khdH#H8n*VKm8<7j?8B{s%Y>ZAwqvCYc{``GYh*YXQv4K!<7b% z5zBLWys&K|nbuyyiUBp1r08Y0!wH8%M?+l~o4u`fZQ4#QGX#p3WX;rnf)BDL{`0H5 zFnPmMOk3cN7|I{(LK@EWa5`3K)S^AGL9>+=dj7m0aVuA2a8IS0)ZQK6FPVYrWz)^% zG+P;Ro$`O;A)z@UWYrin=3!T_j*W|!!+FX{L@)1%%7zemCva|KgO9=w_tf?=P=utS z^a|Tg!K`CTEMIT{Lt76;M%}f>qZ%(Ljr*sY~l&AP>Zy+#i7k>Bi5Hx;G zX@|Pg_owlca@G}%JcbceJ?-Fa%1$dtSNtFz ztr}`c4aCSY$Q&r(9FV+$S`h{a5dnPV9fD7632Yk{%hl&*gu znf#LksD$3r9nk*ZHH46@qPUDg>Ffm(61AGQmATu*YeS|{(eWcf+lU_zTtyQvsabIv z&TN~EBZ1@b&2lr8CM&n|kDo|LrXlJ&FL;`3Xc^-XbvprF{%;+I&QHVhNB?5)f=(FO zjduAX=A(ML)GDE6*lBS)_M?ncLsown*_q|K8KhdLZ}}oI@^AXa$PahH7b<~MF{Fz4 zRPe*K2FH3zj0%EJJMy1BxB=a3YkU5bLEA-((4?3-E{qt90M<}Tfxm8xk}BR>Ni1id zMu$>m8+2=_6!op0F>D;AwAgzAaU^s~4X&jmvvSV&ad!P@voyYhJ2*&6%{hN-K2e$u zTfmKS98zdh{1-P96^t<%116r6`5HhT)}-3Y-nNz@)N>h!aynWY@b)%0*YRZ;*giLB z!D&(?Zl@W#Vu91MInby|5q!Np1%*lI1MeUQ40vs2K5N#Pu^A={ zlC4^`0td8U4Vm~OWIuswWO5c88;fh#t_iq&E#|t?)x*_Yb20CiB#eJpH5aWVPyNV) zi!uE|J#3iS308?=nCr6>o||T(wn|#jMe+SDZ_=a*q8~g$De~K7NaQ@H8X)HCH zkxaIxY{q9)Fn7RK5@uQ8lqhlFGWo1BDr`$Q(#!7k>&Do6pgEGXjMI?uNVT1YYB>eE zW!qrOco+1Y-VNj9zQ=!;T^f^L)k~b-`Ypz81>9G5L0Qt7xeRg#Ci`Hn-4+aLT@evS zf52dpd{V-g6I3LPHjbrJ$mv;5 z{AcfEVSK5NqY-~hgY932c7T*nv`jTR3&ub9;?P(~058_$-Z3Zh&3shW@CuB{98Jc^ zH4d8cR?q&>RM{ESCmLm=*-RYp9Fu)Yc*cK+1c3%>6uvIlv*8R zZ?^AmtDl?vo2AJ!|5=+aT{mZmfQ&42pnz~dC3NQG0dtT10@-}l+1Xjh7pFOQ{z35q zf`v~u_KxyD=K0vF)UB8k_g@eeWIP`~E*;oH5p3Ywfw`e16YkBYQ@XC8Vn3Mcw6{7|3=w zl}E>8C>Mf*dCdp7B_v*iyE>rYaDN&+{>Cbf(~9OnXn1?U#19ueA!;93lt!+$n###< z{j1Bh+#_+SI4?T(*gRy~_cj)ex*ciL)w=W>2+Jcku{oxb`$IJRs}ajsp*|lES#>6maYN>G@y`$aVuiKMhwPZk~{eo z*YzG+z=%ayEPF5JHiAPc=T?#8a>q@lSleS_OTK1K66d5a^MQ)KM5$;z=<<<6PYq!krmZK!PbP)cO#zIWkGWAshg`_*L)Fap4qb$FXyp$2{L@ZRa4W*=%b2?!DkAodFs-HJY$t! zqA#L*&YhyE4!^aK2IFHieH^5}>ECb^*?TyFv~d4$Y#>=5oZqFB_@dJ=)|_O`rvWh-^!G*lP$7<{Zh$j_~PYT>3pt zb*SkvKlfiL#O_(oXgejLjlumhU$7pUo46Nsfaeu| z+U5el87hjVWJFjl-fgaxR@o2*+jca_|B4ANO@RAtMW1W9M1yo1y`UahxnnCxtRALR ztzdflX9S(}5%Lgy4{ARhe2Vva^4@s^aaVzX#?0ac^61B(uvP8KD6ZT2t#R)?UwS4 zdiM7kaCphU`d^v)9EDBudy}jCmAh;4-!BzK(o-M4(=kbdQ3&y2^7u1S(CtN5AZ(4w z_+kxNDvzg#Ptvve-q7g4PxcA-0e_vtiz+k0|MlI9B)>5};c$lH{8&@};ZZBu;xyXFuuL@S_(39gCtme;9q` zAxin+GrC)91DB&ZE}yuGL8g@uxjsEL&I~O3aQ2kv+~F{TIopSdn@5dz(36`4L5*<~ zj{{*4nbmMT{4ZqOZRf6_mnpG`=If@lkh1<(sve`O@IlYZ7&r$DBcGj7qWt{}`WqK= zesAkKB`>c|*fehJo=`22S3RJB!`lNz*Yz+IFt*2165#>95GQC(&@(Ziz?{1A(;Sgo zT1t6z=J?&33zS1k)Z5$J3bK*C^pj8Lmtjt1JmR05ce3ynq}2FgH!Ec*b{+kb^-|L; z$JT!w<5N-aK(Er4SG3Y_3Zk7q!+B_n$Mx} zDuST|L`@b-(YE3SMQ`{(iZ@V|l6<9|O1i;tdC3wr9r;4b_{^By(cdN8K4QN))t4qv zLdM95M)~KatScQb8y7Uw33d7&GHz~A0{6lMZHq!x$p7mAwy|+2K#rx=X9Wt;$z}(m43@#>{I~3%9PusxE@~tA@v+NGhG{v zyI`}zZeqbA=`fzo;nc&MdARU7<7cC`g{3B;f>Jd~v8Uy+jn13ra8||TQ{I}F)h}Pn zqYp7=y=(x8m)%hk*Pc%(PKsRjQz?=K79y&&c9Cv4u~)8`qfL@M+}K`IM=|hBOGauf zl4dWTr2Jc>SYon%t!ui8@Zf>HOvSvo5c2{p>|^f@i|%?XKdg|lx{=&1zNwmROTTir zG9@F4W%4dk#~;a(tzfjq1NH-4xjPGOO-J~`h%-Qt!{-Uh$<{dZkCo4Nx3Nri4{lyH z;LT^bs8XkRM{SPP4`}vlE^ds`n~q23%t* zrj3_r&(bfTLs~j2mZ_;g{z5IvN1dnQ@2$^JhK-C--|EZDbn}@Fz7!d6TreqjnjMI0 zzxD&t>yZs2Vl4)Jmb;y5{IMwg_Y@l}OE0$EhASoRds41!&PBT95lR^)bxP8dcXR;} z={&pS_xU4nQ*6GNGWDqCRRXKLC61AqNj7jy9`Iyb`M+=0%@8u6D!M%{w#*F|#t(<9 zZxHagcuI<%f(z(Knhj6{UL(A@mM0h=4u z`F7mJ;3|otQ@D98E>WukK`OW{r)LcE0Mhpc-i}c-UmBMD*3a^xy@89v5JZTKCOWNb zybGiw>AlVblQp}yG~Td08MQISl%Wovp%lC0n7z2;(r`TyqyA>(H6!n9WY5b>Ri0sv z;eG0V9HMN(kEP5@az}#cpcVh91zN;OtDR&pW=u8cRJt)A;oF(63kY&3slgrn4B`d71R-H<%5I7>N2kWBSV^_Ure~FxhFO zP7~&xZp#`vu$b))VnmuorgQ<%6;myRke8I7712f;_@Q{Xr!&AOkltaUu{ zhYnG!oBXV+*sEpn-(q|3tmmOaZeONNq}1^eano_3D;T!jT__8O&Q>Fmf|bgRok+ zM~jn^QTs+{BA@rA3ldbg>p|{7#RUdxX|(j_v@hGs1@~zzdz#{j(==l5hdrPOxa$uR z#3Q(%z(6(fscP&TK_PjT&vzhfie`G&m2^N57HUu7%l*zDFyk}gaUDg@L(VTcKW#*L z1ZeDJ07`FM>`ERAI(tVGQ6+;c9MawijqES61Ll z#pRG{OFT|Xseq(k#qzYng<_zQ7m0jwSw=}SSp;oKq}M#hI!vFfq@!00Dn^AK%#YxX zw+Ag2Hz*zbCuH&|hhbOZ8cR9`h)AW5x8Y4u{_ndO$G+s+vnV*vG*~n?EDp%1f+kJG z!?pW^L(BYgVTCX1*Bn8=3`fhqlT5e#Pyq135Ar1RP_HElksXKaSyjZMBo^?2GGM0q z@&!(rYDFyuSjrNOz^-a@)X79miwB~_i~ucv4cWH?_opdVgPNDAgI&FJH-m9ay%VZU zo|v5)Q!rQ(b~h|C6Upuc?xUxPT*j8Sg)G`H+g?eyx@8D~r84nkWztU_P2h-GG>zbY z%}O^oyQ);Vs-n+AH5=h2JK)T$jbP+@$3YgF@9$` z$VTkl%7SkntL(PKD+<&|X>it2Vd2~+k@>8EN}2#J{jG~$+^(k}#y_@%9$ zAS8aLsV^|vQFR$%7%vlEpZ_f!z!^vHu3^zLnF^hs`E0CnEe?fZA6Izw_SWwd%&rqY zGs)?5T(rptrAy^V&w~X{j6#(Kd%3+%Dz0u5WRdKWU`mGyL+eTEng`|r`g}iOn{x%B zbtNUpVIh;;*DuBZF%v9on7qOPPa2{Y^+IbM?5#v%oFE+@Y>bM~V>PbqsTl;c z+?fDBhO&v2a0cJr)C+dAZ5b5H%q@?_JB2XMjc5VD8fcTzU5)jvnG9%|cxc(^=HMgx9gv+hE+}8)DEJLtY1{Yo#k%|)&UOy+TvL6at zTWXPK;p)9aFM0F~WPb#C1~tQcNU{}H*1qq^2xYytQov_F*Ug^(92;{(_$U5<2m@(^ z*#Ih4MiCwe(Ckv4QZ~P@Kq_@85k$m0{j@G4jc0OYrEIJIcQ{#Lk#>ar?}a8KKkNo0 zG1=^%_Yd2wUmRR`4ei;B%@>hFckP5fXLKxv;&6>vj(WL~oyz{)O!{}U1J0aCu824% zF8c-)^5@&pU&S;EJ0NW-_ndt1#JzyY6@^2T%Z(09G2Mt+0wy7JXDffl$C+B^m)jVn zC5FxZ18b)Go3q;GWna?wj8&}3Gp5{UuntS);Y;_@qXLRoQU9VIql0AuKd6`l;m&V! zBD5F5-y3Xa>Px1<4mtgzYtXr9E@SNjVQm%A9e2W<4UJYE@EU?p?;WzkWHo`*K6|to zeY3EzO3}K3D7y>uf5)iDihwzCdc>cbUi>Gs_tUlc^6Dx=K*)d^EdhJ@Tl6wgDo552 z-D$trANR<=gUwLP0w6VO4JII(uas`0n98p#it^Mx9TXo6y+pna86+m+zfApXBVN)h zSD^^9wiijuY`$RY00|uBbOG&&m_jskHVEgb-<@;oFpDR2`t}NcSpO}#n+pjhRVuIX zu9%@-_~k%U+@O=|8y+^%V=tK*IDFP3HwG4Thm=U!-;-cTWfsxR`CW-!Cx<&HFJh1W zg}n?2s)$P9VvrK{D}DJ2(g;y$-P^nXw`Wywt8It$c9q;Mr1BRtKrl(Z$0o0`>U=$blE};c>(#9aUm&Vh2r+_XGxwCZ|v1~Zp zyI?KQR|wM!EJJ5`rU#X0n+K>KYBFm6CiqPW`-9BQWec=~bt5Is1bV@)RTNZIi2bY_ z9GHPomnMMcytZD9fr)QcZGRmsXCR0L70KVY^G>O@t7(Pw> zoL5{ZpHa;DMH?(cR)ze(lT&L`8RZbO-%s>4$ZR$t=Kc#zvbK#`v7^@N~&>VODz&RwkmPetHVj2qJZ1Mk*LE@x})Hk zuQ4VbQp9N(g=s`-L05)rM%$%?(!bqGJ`p=h$G8jk#2VBU*Vz5)8cJemaz0tqtmA9T z#V8;IoIE_in!d^8x<9^M#7pZ)J!-<|a%S5JyndPqJ!kN-RIg`4$e^KR@qpIdq5yk#QD_GL8U?ozl?u&Q8T}D+4eH{QtPvdJ8hfhwj2rMZ2;`@Xk z?FExWm;Js^IV2!a5aH6&Ka4FmUefFOM9QDGr3@l;uJAZ($jP;H@t0fPU=&i|a;|~l zT-45)<_g$?8qS{FQbi-G^gk#_grG2O5hhF`Q z+?sN4Cfn&`QyCeaZu?7I9~uiS3)z9IO&)?#2m#Z{Tx*%$=|y&IPLFDdk@&Y`%E+k`e>jBVWI@Q6s)#A4r3h~CSh1EbyYoOvcB{QK z26o@%2|xRlHx8NAqVv2Ci+*Hyp|?D_EyBC+_az9%7UjakPXWb#9YzL9tv);gTe*6h zkzIbNWc-R-7qlp_hseXImgkmMwTn}Hb%F`k8f)uCckPoQRmBnT(()9f(VRppvlJW) z1pAd)qOo^W(A`It0Iaczl^oEzs@vb}fJvW$9gahZ4 z)T(U~{~e&a&^8}Noje=pO{uK&ANfp=Cg^|p05@16#^pq3#eJ3{UQj)(^a%YX%aF2X zTmZkXClDTjKSeY2sU3e#l&?3xlZRHlX|P;cweR73*f+>5{03BssxhFqYoCUG-ADO| z1g2hn9BLqA0_o%2jCD3@K!Z`PknRvQ+_|i|JP)drYc;z{QhjPF5r|8Pg zW0>Tb&>6xT%fyTtham2}>ZWUJV#}hZ>6FtgIvuLeH|i^6&qEPBFCHFcjZxj-Y+?!~ zc5X*A3I_P~;>1HAe;ADN(m6N9ilLGAY4c*ad~%-fx$`h zrAR{=zqpOTCIxXg*c~tuZ_!CmvyFIkos!QI62jutuwh`;;|G5EW4w%_^v4}wvd)h{ z;}I}7NgNf_lr>WST7S@jf=Ot;*83Y%r=Bvk>J5&pb$ZkW)&-lb)Nw1G-&?0XJRRxp z0Nkh}z^shKL}{a(!D_I_ zQg@M+yXc>mD{d@yLS#D?XXjHgHv%yfBB;GLQRa;xdp#94@z_(HGlJEQ3Gi+rJ>ut` z778M>M=~*yZLp6;f8 z(fX-Ez{bZ;F;*^ztq5w8P)QXX6IJXva{BRFvOImZMzheKQR@AcYG@q3gFSS@NnPl_wI7gsT^H1twf_ zai)UGjzYonRgtv8`7nP-*4o7hPvVlw{n}ynr>dAe-)S5C z;^fbbuZ*fgLT?1O-bLB{g90dK34ogX-hG~rJeij;=j3*T1JO~5TR5!W%7y9wzQ^*n zll--$c}f$)@`U`FD*xNXn!Oa}R)ZhkIF1mJ--Zp%MUyyxq<=^PrYzq6=Ge?c(x+&# zHP5|E@6TH_%c3p*Z__F4q;2qLQ{^<`AS)U*=AaC2XEKn>Na;z=6%HWO-M1DAQx!`* z6v>-Od{|tcWIEtAC;T8?d2FR37C-2^WEVu#|G- zaWYeh%r6^>&K5pHaOTMSm1EDE*!VZBx4=h>5E`6>cIj{?BIju$f}tXj87Gs`4n z9ZaIDJ1-yK9HYumE+1m9$vX!Mx69S8gvjX#xOAfk`@WYAn-|A6D^jKZGfcAt(f0Bv zOWL$0ejk7|q*;R*cYOdp$FfD{^B zsq7AzGt-~P5@7VDeb%Ib3D(TBa>c#CwcneVc&fCbk}x@!I?p3HOY69&nrF-jL|nr* z-MnPecSyYig%ujR$&FPly*d@D%=tg$-@gh@wN^kI4dJl8H25W7)xnzNwp zFkTOQDZYe>x%Eyz|N3C0LMO|Xe_6_BVTkrY>$eCI#w&KIeJV>C&LZ}coxpTb2Ae_T zH~niy4mv`v6N=la-+B1VIwvgC@~uF)j%(n2K?T)Wp#wcB?>=d zWE%aEO7oc~V)I{zPgP;M99sf{W=;!rm%n+#pXfxK5)HC3a=!8>Bwz|2t!vtd@=qpK zJzI?67bWl9Gw&A|%&E!B%l1%|NM!sa>(_!iFv;MS;0XG|~UeN{_IyDscwkK&4t zxYNePQ{RJEnj*JveVA??J!7BWa-Pjk98p;>FaIJBN(-zRS#4X8&x`_i>7KEv+L_%y z7+gu{2$-$ReXjq=1XxsRRI^T7{H5sr;?-NOusv_r!~Nsi^R2bW&4`Y&dux!wKl!%g z<-yFSU-Vg=u>Fm?_*DkJU_tuHOp5rbgQuy@Eh;n#xgv?m7xM1r2Df4-4P~pRdg@O( zIbXJ5eBTyL%Umq|47Px$vW-11`RL;qaadUPa-D=(Q?Qc7zjZdr9HZI`0|{l7M{kET z1e-jB6R?4eIZ{T&96nj_D#QmuLqk$}c@j`{MjtM|7Pa9iM}PG2nF4i8Hkdy8Qz!UT zd`J*mr-cw1xb$pjanI7zjythc6IIG}K9_OAoj<&Ym+ zHHB+V!*)vJK8e47OVexBfr*781*E28H#=<5!sT`55A+6`{pNukknYV&h}^(pCx;gD zf7LSYv-{1)eMmm4k8rW(i@Z-MVAGTanc1&jDU|Jy%OUnMM#pa;ME_q1UdxpmcV7-1 zQb%X6rx-^M_+<;8Ig2o-v$4k#;Cd+2Q!@B?il)7RQ97aI6aG@=9-@6K^O-wfM#x_D z<3K#kNT)|b&v7>-n`+odQA#3RaTS+n;r{Vzp5Stmyy9E_#<;yz>&?fuMrunJopHbz zzn!dwyDq=zVy)?m!DD0f6cOd4+qe#b7dynuq(os2klFfkW~D)o6f~>^^$I*=AS2@v zdD5_8;f+5SCwr}_nHgJlnls`sp13%bcZwXJ|3UDI(7wD5pI13(5p-J6KDER_i*Ue-7f zvn>E3it06a?nS%^)0r>aze${g>lGXWoibPrcAbdH4_BQ%MC5;7>m>?`jO-qgVpq|Lw z-o}v72Z(TmIhZlJ6A2L5_Id(E-;*)?(BuHA#lWB-@{OpCy7x3Mri78js(7t-KRyfP zJVaP2*!Dw7lb01f+7lVG=7rev{&X*HW{KI`T=C9&~3egO z#Bn{=f!OfYS`ROB7*lmL)hjB_`ke;4xA}8HA00u5XqLYl7ooF9FsY7@$!YDw?xVl- znLA6hc7T0!jCB>Pk^~jei2M|x0hHy^Q)tcn*!MnlLKI!oMRUu?J%e$rlyF+nW^mbs zA1L4z$aJ9T1$}$SMUVp7;ryo=waJAN{#EYR&0@(82ELPu*Zs;kty5+um!pN12h%Mo zt!)^VJ1atc@`#U;8bDmoV=5^l<^Z%%>0|Q6AIdPxH09NQL^%#&>MQRT;M|v^0y? zxI_0{m{#XinMpMfiunyrcPmP(`X885wyJ6GI|w!O`LE7{blT)bvS3-W{i8dg0-u$# zn#+G5Xplm+n;h8eMc7K>9njb4HHKh>QnIUDrOJ?+m>6=>yW#oqz+`! z=V?Y^BJj)!zUh)!4EEY$_iOJ(ZW2j^_e-JjUtAB^G%{#yr?hjbGz$&6d<`up1F zB&m3pl%qq1@YLpnVjA-FIFSFx-IK9YF0B2Mad#uIh-GR%3-oJpFEZAHHio~-dRvR# z^&N0sMqCA?+keFNuzZI5yJ5Yj1NoT!z)kA6cd)td8hlg{Q0$!^Q(M7OFTwHIZs!)= z!FNGVn;^D3COarZ6&W+*A2$B))_913gaLIoar*e??9P+bw>eim_O0I-gb{>>@8AKN zS~z3&$;o2{K?30o*~0Cgt*|wMUW%fnnCt#}Kva#pZhw~-UXJP?JuGGW@yKaIw01f_ zUW}#ejWy%D5}U{6rnXIo!NrSrWzf~Y`4z#ji-%H4dmhOjnQ3}3)NoW^L|%0!)E|wXYo3h^U++aqtpiza`o_i&kAh_-E-olp$!h*n@vB4p z1@~nas0JB((n++GQt5gb+R6ow*i1SDYPAdGd8(F)qpvB(ua3MwGrsCVahg9?SEHEV z->D3$zt#BB>`uwkQwF%qE>cEnP`pKo z#<12&fVf@b94?WMiY1;QPmdLyw<&rEL1Dck$OF56)0)YLH?_Aqj(A7nA`u#ps_n_a zW_bGa{{C{|%T4Po{SWo;q$5y*&t7p4O@YA}p;ZOB9Cb_BFAv|4s;I2g8)olD*?wbo zSEVl*$CuA}YfNZiLUu)Q>9cbC<0q%u?sYSiFnM9@;R^d1W;S0R&0HA6;dBUO~N3r-eU-& zTa@k$0>;a2Ra6IlEQHb2Ug8^lcH$C?y)teeadGhNTf#oBQz>h$+=NyWA}uVN{DsjE zq3T~Ad}JE$Y{CW`h{&9s?=M>Fel@V{N0JBr&Z^RNk3qpf?k2)yaRQDwTR+%fI)@$U zKRxx|79EC8Tl(tTyCvg`YT{2e2_V){GlPqzjEh$OeBC!g{oL1Vq7%n}_0@syYDz(3 zIe%i=_Ynk-X{5@9Z5}PnD68i_C!HtWWum#n7avC{-|09Yn2_Ws~`gj-=Q*sQt!2V3bQ=o$wWS$-Xk! zwgo0-Yhl0h=$$63?Iw$NU)=9K%{$=i$v_l={jGDG;ccD1ggB%TxE-{DE>d7wSV3Am`Duc z{Bl9{@wckz)5JP_5+SH<+#A1Ulyly{aYM1%Gxw?XrTlkEBthP`PT{7dr(54mjQ^m0 zadpvEpf-%P2UI3a_Z*klD`uT6hSdm=WrMwkEFc)8qLE~{9`fe4pRC&NNksem(TIp- zQQnK3RBV)?zkG&j6uD0=Uo9IkhmMA93FOVUEX8b1q>Slgj!dqVLk!~)4VaG`758pP zOZ&O#hZ7j`E&8IxDQn{cebI-n5T~VJ<0fy~D*xB+6hQa-gwOEZw?ZYZ_)N@qT)^fm zASJM8#EmvjA&k@a+Fx{4;Vi8^qCoDv=UGg%VIl|wuwW#XGigBSVJ6L!<=0gk7ATem zEaxf(aQneP@+}O1kJiLkfH!{pX-0UP?E+IwtF=3@+~riWj5}Od?D<1_Bt(-8XaAn(rK?7 zj!7>wS`b0@+vD zgdVWyi^nVOzO33RX{z;PEDYlLEI!mwV3o~5G}&-?vGkQ2LjQ8|T~VHiJ?Ht&@n4e= zFHatjE5gW(?I2upM%A`e1SrFAhJNxkW6dhMQLCB5AMbBqVS|s!Y;2g*jSw)J`?RI- z+HQw5bWRdIGdr11`At!dBJnHu=S%*3G{*BMELEBPC;9`@ea1QPk|HXKo!i?cJ|i^I z(1%1wj@8IR7$dsKwO_^TeB`aJXg26J`7Rug)N!x=+&~e+*@%`O~1BIH_Ws5(# z^lST*%)56{BwXJwR-J#G-a`YDdP-0~wsjFtyLx^aen_50NpZLMky^~Wai5uft6R@- zyZI#PP8?z=BbI_$w%&-IKh-y{9_DoD4AQJV1RaJO^;B2XLFQuWtPGl?KTS_7H68d? zPq-N%(_k~2Fuh7{>GAy_T0}WK{0Pi!|HGv3N2Mp)jVdTS6FE^IXg&g*lt^>^27cs) z{GmJe1%3EtVRCT2RcDJMVM)}QdOIepcZAjs`CT8a+w^_>iTmmZhXCzI)JKG_aXasV zA>)PwHaRrN;Sz^Vvj&QoM_oZ&JUB8O!%$tCsyu#}nJkXXlc+O#KatAxCcVLF7?U1R z?c*H7{&q@Tc4_%=_UaHY>lz|Tm7jVfaH@X)Y)?B}V3q%+v%ty)o>x$B_}@nQiP$+} zZ(&Wt?|L^&Z3i=ElETckh{AqntLEba%cS|=xi`s&i?F#t<_4*bwl@6EGYD>sEs*eb z&*u5h=-afKBi_lF{bd$a2vawL=|FW-WQH+BUY|1F8W{Z^vyeonWLP938%9_Gj8U1T6d(uzM5lNvxdcpd8bK zjQzU%sDM#Q#@s29%kMD3uaVbjvlb&qGvTkJ=o86*1aljpO*4}*Yi3n)cdQWWq_lq@fn*Y5TgcuZ`e zQ8iGGqEms1z+Boc{hPeSXqkRTh;xoU#aV zXg(gE-Waka3z)Bk+O2j$4h(d3O8=ozrXvEi2cxZ#I43nkC|#@bLV+q9^V`I%@uj1n z5y-%cOrh-PeOotAUq;{S@4x=Z8vo<_!*iL!llPgom~TA8)Mn*pu~N~$`TgUg*Lu6V zT)4@|4E-IrtuW35E8R9 zL*90`qmDV>Rum8ks|ETNt{S($(jm#oX?!gJ6bboeGU8!-&UE0gyw9hbe=5s&6n9LQ5EmtkIP~mP^)NHQ!Q#?L( z^ByFmetPw{PD&;Nf@cFf?PKEtXLT2nCQn+Hl>z7Lhv57ScG^-fpEfv;K8rvgp&VP0 zG^v~m93e`xN_m!^%4($0_mJ)NZ0=Unt!TH%KUu)_5id&aGvY8!26MW^OohY2Q<~ma z&C$r@&%}OY&~&GCr<>1F$-A+}mC88L$`j47PShRjZFfx)kjRN=$v0_*NvV~z=99L- zoi*?Itj4^@X3z#U#LT45T}>q7)^{{1UDFqwcj=^WDx+mZlQf1hiF5v-cDDxTGAPoT? z@LgD#7|P8y{Mm^F&wwvx!+fPWW@&4DWOoEhQG=T}0dY6eu?v)oXNss(Dwo3)&*!ay zV5+LZ%#l7+N1f?hG~yraY0$!S>MgK<1aGnk^8Qghi>6vm5zPgHzX5xeWG@6SJ_YD+|%$!r*mdlk)p3S{Nz`Beev zl!P>@*C2+(Lz1kCEI6rKF_$~0TxF>OZ*ZYvS{&Byg!P$;lmylG4Zv+A~ zqxac=e=Vd~Ay_4rafdPK1HnBI0fFQ_2$sJYbV@=El(Ag6p9z*-z{=uuD;@N9vY zKT7Imh)_@vwJZ=YxZtVu+A1n!-p;^vw^cz`Q&W>0JyUU?NRSrIFVBk{b};jh#M5v! zcDUDj2D3%{K1C?7e50H_T!?(Z+{%Q{q%%X4g68Y$Fvehy@`MguV4=bwMAeo7??Cd zWjR$HMS_ndB3-EBr>|@`;e$pI8D;RjGhlGby%oqg_n12C${+?u&^lb1T2I|xjAc6iqYasRq0kptO5a2=7 z+4S6W@%(V+nrkl)7kdX2nP!Aaegd4N*b=U;t~!%5DlX-IXoP+nz?$8vn$S{xDtu{b zzl!Y-N#Z)<$I8TIh8);$vc+trn=FKL*cLvY{iP9h+5AqYj?|WZ1meW+)jN~LJpPJJ zXM5OTq{&uCr2Sruxk*O!P^fLMN|WvE={V<)y1d9b>?qi{-nTL#Ex22QCyu)${=#@K z?4%;1%PIZVt}+@wFNEl5w%S zz7hzSEapp+jwZObWs2IJgf#ez6B`(a`>br*58nM6WNd1u&#H22S5^uD z%Cn<)9W(OJFP$fj%Mp+~Le^J~aowXFg@%9#=o8Hg7W@%QEQIntM|B032wO-16$lw| zNqpgIV2mnw7yoq{4z&KzVtMp!gj>J9VS^IH=SITE(qoPh*|OI;a+kk~E^)da^N5Y5 zt5wUcwI7{v0uk3sdrFV!k)M3Q3WW%=58-<8+9vFozZWb#d!z@xX`Yikj~dI{2_=@; z-vks5m_hO{z4m-p?)W z__(o8Ug!sd^L@WE_)GCr1EnaH=vlhQ?+r7beN(1hkp8P17r*~34al*ds ztOPVz&(J+{BdQn(PzEkgZVG|Yr5v_4nz9lf8V8Rr9#ti!t0x0e!3ljbQ=@rXP1>d^6Z=h4$&ua(GQC4JY!e2Rw3S zzsvh&KWeCX1uPeZU?)*gaxx~PUMrYKd9BRpiF%cmvd-6pL#LsEfo+g$L96Q_3TR+? zoP3u&v7c01G-3}hMLP)^yc3PO#*sifrrp%g=`xKVLn1v-lcR}_ zes6^5#LTx|+($k82u5TX-90lQA}WpB)Pj`^&zz|3efT5R9<;6smD|fF7<`LHRpR3o zWA7wZnuogxjH;^ID#S5PEk8Gg8ot=?$P!lv^QIo34m>m@8WdvMf^SIwc+oMS=XcZs z&v)WNw8fozVl=J>FO`N-w6sJ9?USpqm`%e*md74-oMUGx)lsP`k`(%iPqG=BeumgE z?V|?ndOzY2yRqYbdUm8F5ch_(QeRkuH*}I%j9qZT4>-x!ZI1t<^M+ zx_m#&=cr4%_4U$LgI--YO z%MGm50>Y|f;6AL;EqrPrQhAZ?d%uy?CbAw&lW#5oI^QEK&#oq_P>sfw$1Jm@rfMuM z)0;$g_b=<2UIi~AWM_}Kps@j+*kjh(SOMjSA;-FFy(ncx^)EhGcTwA%7K27b(OB-pjPH zMIDyLx?Ru*#4^K&&d$;lf5(B@1o^BCvxrI4B~rgXDgzWM)}-Q}7pYY0BncS!)Yp)Q z+it&p!j?iz!%Od-<=?wwcq z-MTsi!FV7~=k1l^Py}fwoqAO!qSmICJ)8XlGl2-KRX(raV2v$yAPaQ|v`907|;B)#7`6%a~q z6>kwANeV#|!ESZ1z%`D<+S`qDuM}=Z0;QEtk5D`-yo>iEdQuwb9pd-gFj9~SSVF?5 z;dZ<}KC9emFW*r+ijU{Ji(84xFNLXN)w413`Q`mbZ^+sKwWjh@y#gXs@rmi;zUqrQZ*P#-*}VC+^3)p}{gO6<)bs_dPtfCfl%Qa}_i> zV$QZfR*I)if&K`>t(jGIe3nyFDqa{H#kJ5wPhHbR^kb#BMCVx7p=(e#xdmaVHY5i{ z@R2uW&C*~EY$`f!u>m>JczV{a)nN;htBCx+`yUS+_;uiRut-gpaV9&A731-DHD4i< zvrMx#r^xpw#OO=bu(^DH<4;UAe8(8y`)+O1={jSv1;bdDWkqG`6$;vJn)?ew<~G=y z%pXxEF>P2l#HJqwB4t+kgiW@ZVH|C8HT(qSA&d`I->4q;{tz0FiGKkdqdXEgr$2@s zni`Zbp!@;g}okc2)`d~#P_%H|O?COiEqO(GIeA-qg z&;6F-XdLrhbCM@BEsS9YvV@keWc>12pzt~c{fRQ#;zDJikGrj!TTZN8Y{Rq}ulzuI z-kVppp>enVBWgB&=8jkxm-G&M2}QR`{rgfW&=^cu8QwnE0L$fcC5e#HwT6yvQ9ZCf zcIbTKL_+D_fnfMBwXnxD`^lb8)|Pr~-Rq!RR-Ha%wl&Dx{_o6m7p_hR%9l)P2JWE{ zng{0~`uOJLq?@|2p57+NYB@^R(e}UJZ4z`D4@;Fg9aM~pH$K!lN2$GVHN{k639DLj zfPWRea2FbL`0R*We%)zRVPPQ#b2#>$M$N=9X!(1C(?YG=Viv{Yrw%}l!U#rgz5e<9H4LHTC;W9XXWml1`an?(@4Z~rGGy=5>ehs{Ko zHZ-XvJ&|@0`rkil5k5xcT2913$7@dTL<2IriC~=--LMM;CTkd~K;_moTj}AtTYuQl z>(cHg1r+*v`}@BwZyxAHr=BagtP>CJ zK6NZXjAK@5f+~N;6{?fx3u_Z>YsbUmmr#h7CVDC|RSy_s) zKn!p4uXopSRi^~|sikU6`*@4b1Ys95gk_fH?O#S$?t0!am4S-bu!x zHlqiHm*)o6<5zAaAOl!R5KJ$4oIi&rnwxpM>qFyZ&+Bcx& z+lXM@GY(>n@PN3?_bLQi#^b1=H;ItaSdf0gy{r1K`ED6a5f+^(Cu0>95 zU7g9+k$a1AZwwXh`@yz~PoZ&@&P&eWI8GR-FI-9MXtl)8D4dBF{gF9&FTiq`4!Km} z4++{n|Hsc_hpu_`2bXUa@VrZY-=Bi4-q$=-?F)0GE{0AnRnwX^EV&7r=pHaI=l-j3V zl(*RzinQ12D_<>Z|7QNHz!5F?FI9G{jyRXTb^!t6U;L0a*z?Dx_~L@>pjP$V8%=Eg*yReH?%-|c>q$PcTf!aWBA9&KlkJbZ`TY7k=Es~^+`8h z+D}?wZRY9xr1OE`hxGuHBBm@XLZ9u(KIj31@qrElDBfD+WsJ-}8bJukU$@?hS1+70 z8F&qfAc>x>f7}aDswSQ0QJv_ue3+S2oWtk4>$>>_Vc`R&tn@ta-5{ZmF^Sw7+Gyme z+FY0Q86r7MKQ!(E@?OHiT34M5XAGPEIZE-TJj$_c`kOp(UCs1(NH3!N%eOIXJ+^xZ zCj0)bbLYT|&FO9+Fg5erZ*?lUx{L^m^OeoD&Br|ZwSlwWC`I?{f^4?u;oRBZCtIXg z7@(kYYy_xC_jE+R2m9XSEXyCaB=q?$M_v#eL7gYu#9&e5fwy_yk0+=n;rROcYAs#I zV0yj(E`7NM_9yZa**w`VQrb?$CXTOaf`uLAxo#^t2ge=`@u-s$Lx)1YJDjC*c)=~} z+wkZI@`OE&ANWPtlPtrHt4(oM@qrWa&*xW=Z*Iop6^VEv^>9RYYohQIA_Xqp@*c1m zK;Qrq-xevy#F~suRUbCx__!Q285z=09!SC+Jbm!&jhhjPx|ImU*8r z84nA1E!KVYXwgzW#ik<<{LRzmf7WIcNzj99q&KNKn(`ezI?>CZ#g@QhQFCjHWbRqc zl7W0%HwphcN|&}x)qA(BN(Yh1IfwY7eq-?XeBXO=AwqL#0r~{VSh!!8;s+8~RP~ZH zcCqqyK=#-HHv73xD;-d5o;+mRoPX( zi4zkeGogcffF@CDa+-j-RTWQ=Ub3{c?s6|w>L((xYlkhDt3*#caaoXNE-f!fMNf#8 z6vt3=FLmjcZsSm=mzYVzGU)Tdl!{B*Q$NFOLf>x@zb^Uk;D&KDW+@&9Jv^L9q}lBG z1JSxiB(IO$@E zw-3Jr&2)ltTgLhWig!0I4Jnm4wYyV704vSJety+;a6H*c9eC06vC_#3Zt7oio<{F+ z7#coX93J20L3*EL>`krU2W`VFWh}Py6;$*N7+cnsjl^)%UOi?J;%Glddxa_*)e?z& zen8?|10A9e2{d9@XlM+d*x@$VWlpn(2Bwbioj4A4Qf6}5j#&h{4oHJ*Etswc1hrfA zPy<1Wsn|hUUuic_U>E{eJ0IL4!HC$8txu-T@Hr_#5urv$jG^~Y-b{%rnSzRn{5h3gWubh=iG<;H7JnmV@5i;w zl*1;ub6lvh!yy)+Q#l)EUQj~QtKYqN&arXofuTCErT+I2Q-Qz0&?{^WhVn=ZT5WOb ze9^8cib_tD%Ml+W!G8o!B@zbBMwqKyWL@H8mh@nzpOx=i30mQOji*!y=0(v^FU5M) z%vWm>m9`_Q498p->#TfhBrlmt^rXjFKNc%eN^a&gTCSL7Tfxn(^gTE7AHB&q;fCBT ziapiO+wehkSTT;F9q?Hqc-=>eOde7#HdUeCu~49;Gy?bwIjF!?ZR81Qx*xB%)%MQC z?+d3KJ{0tlF!GOzSpJ545-7IEH~nL9vJOuVD3CJe@KMregGXGt2p`&_ImyA<2Svr@ zFimJTGT*o6f(tB=oMwO?xron1g)@W_S zx%B#+!L-^&`{@G>Z+ku;Ka6ol^c>Iw8#lk1*oeL;%zLw`q8*@FI|ZjyQK`mcl;&@I z9l@HT!Ob>px<_d_Kz=Lofb$MU?1_(mMs|EadAi3g_u;qHX!ZN*0F%~^f7_lESzyC0 z4P<0CXMfwKZ(LlDWjgWWp2tuC&Ee9n*9>+cIGXa5dp!gBPiMRP^R|a=1lJVk;qKD0 zkuw!C_xEWd70-_pJ9E!vb4kRFuhIr4iLkbk5SY9hGOE_w*K|`a49VpWR}T&>D(smU zTV`MJ#Ii^{s?eq_kL>ODxEs8t887JwSX{DsvA4{6# zOIF#GQU;;PPxE_g;yvq`DC(Fu6w&td$NDC;w!SRiNlmFag+5p^dt zBJI@89;AidejDporWa1+s$%ZB#^Az%cQN#~uw!06f0rGb$2S;9R>T~peQ{6X{t2`S zf)wJ(J%~T@X>yxmnOk~vfCXdlmtzehiwXLNos2If1A#^##|Q}AZs=)Rga912MTE6;XpLCd`|xuuc_o%gEnWWLP%GeRllX;#uD-wimqP8v&?UNrnZyhsdgV$IX6wF3umdwG zVFYfm4p)rrtDj`p;OV#QLiAJkF^=u6hk46_OHM3D+&x)qmM>Q^1a-;wV6=oSUDfp` zdEle)oM7rhBY9vvt#Un6DM)FPedBURy6KUbhQp@flSed4N2e`#V}roVfy3`RjrHF+ zZ@B_O$4?X8p|Q5+rsZ2JCZ->rW_WOho=g2+`Z%9Wk}h90`m|p#i69r-e*3&Wd3@@< zMgeKuQ*)<_vCsrRBTqtr>AgS3%i;IUk3jL`ABFCzvf1&=CR#ZYMjZ}tD^B7QQCE)K z$QCiSb(dX?H|}Y?e`f`TxU~vz#Rc3T7AL>n%*mVDuQDhv!HERpX?t~b5SQK%j;a$NEX8cpb~#@!TI z&%SHTP4^K~ULY~sqx{XTQ!xB~=9f>z+ouOWM1a|7dH4eJM zH1=yt82lK60%d&|YG&cY1=FtnOKWQ|I(pGuN9}le7@C;kl68Yc_I*_k1u0~a}KTYt%HZX1> zCnkZjjyMi#2(O^77N3mQa$-B#W6SOjccsoZrgnze;-y*~l&?f&Pu>`@sl2|1oVRj1 zYLVh57n?|1ug@sS8cAC1+AK_dA^1%o%Pub3DlC0hmfVC6G!$vFOcyItt9Y(pWWpbW z(9~qmVPVADbjPP(e5&cs8L9}qR_5%!^cpWyECeY%VEFm@Wm4FvXP%;E25v|{{Utoa zv*Oi1bhpNN4QIU%d{3sda4o&K7={`rFd6zj-zfJ zdU%tOBE$^9ZkcNkf83KY z7)t>KVtaR*PweJyJ#+4&3;K(hXGvM+x#zdpC}5ST>$FPcY&inGtJHH24o=vyZmcM& zT3yygv;6uDxp9mTKFZcJUnp3xXL8JyOf3o*sc=&F0)8n-gOLGALA9PBz^3$BLNILj zCe8PD$6}j(7$Iz~Oq?D;U?L^-i_fNB zhXg||(_hn?e3U{EyVq%Q`P#3H9WQ>MKP4^Lp@jwYl+x8=Wy)gq0wWJ^<;dgvqY+{x z=gL+SIwTF4X?19@47kKq#HXVh#tzk@{gMDAb&U%9Gp*I9a~1}4PcN2k`vGt<`T+Moco5uh6l~a zsjrfSRA!p7n{G*i6k3>+5~s4%<8c*rGk#~wVA_*;d~r#rR)rgF#YQ}T*vGjAl*J67 z2&70gYddFkv6y`yuFHB@l6Pu<#114javE@KQ9Gxg#8ZnZ*VEkT3qhLK_Ma_zLwmzE zG+zZnetFTqWwzJ8V72XU$^LmaqIP601*^;4Um%)mK>6}h5R<-IIH*Zn(mYC-4h`G1 zG!3bDO69LnzhO^MHVF1yY;pn$^M177&TCgyS4ZQjOdpd8&J+aN?K6Zn0Z%uo|L}Q? zl;DiBWc#}TG7|J4G^=$F#+6vt@3c8_qs%AMRBqGFzs*UD;h~0o@15d!c9>%WhcNw%5qAUbAcvUENj7OKq1Ne z!5*DPY61=QuvMB;gS+BA63xcnP^7EC_Czn_)LyV~ANt}jP2z;7?&Gb|d+*c7OoLow zuZF%}Rk)2!CH<1HUaAw#jt`louoe!-7D*gFKWfjczU}aZA7F;8wWwuVy`Cfh82)KK z2E^5{Yv!=ZRYynr_!M`-8EeYN;B1nO>XL(?+jonHz`IJbazi!njDX@@v`^ zt13ePgzXnPx>TJ3@n-nI={5Xubj2rSgopVOXo}4Avsae-GOcX_g{4 z+_WenOs~|=_CVC-fzei#uAQH1sO*~*Y`&@@~^bsIfm>Q zBl9f?e3*yGMfKPe37n`2hp-dD!Odl)lh zi`8uWGO%jFym*T}g2^?6v?HM-e4aWN*P;90mzI~6nCM*C%C<;1tSAPiR(DKE%cqE6 zC0dkjBs7QO8enylre#nbN726>%D7}XK z7nGK*K^+REXj#6>xd2&o_d01kOEGL`37*KM#!8oqQ29WD_k94X|H5!^4pPJ#58qy44vrgNQ>B;K1dVS_uLjPJ&BVXw z$X(dvDS4$U-Fj|xe+*62>5NNL2{9c9A6A<@a*qg4uj75&h-a^MiG8fMriT7KEJYF- z2AbLKJWVqcCZLD^3qy{@%d#wGnp?xUY^acw;R~5rz=H^!PKZxrLZv9%d=3w74*fru z3Gu&pzqYt>{QNw&rw>=YacveV*CaJv6IqBiP>2B-uH8CCje<)bm0 zA`#oN5|Q701ZfJ=+Xy3HYth3?xi8{ULg$mjx^vCB9sAzdhhc22b+SMGaa&c7zKZzJ z68w4&y!*Gbcot-dJ+T<)vo^Sh-R_bfz(xv`?95jv@ho|&DFK{Z^2>^{4hHwyl5qK6 zb;0GcRm@{Oks-{C2~vesp;CoK3P5j5xxyyK=)ZDJ7xE-kdb8KdE{nTW)%?d?9+E7i zH&9|6M4L!V=PY#BiKkH=R$ho(bR^D(t+VQC7TXIEl)|kFCZOiyd0^*=o>h5q^r73? zohQ=$8VFnjlu%jSQ7Yp1gSzD>tFlA&r%&~nm(E$l7_q}Vl2eJbR;gp*nb!6E1aAP9 zEg(yk@=s};8%WStTTN*gG{zcUJKW!_G$66}vEp|apZf%Zzzwr9W{Q!bxNW!?uIy#> zFELG#JfQpUyO~#Q;DsoC{IAb!@?G@z8|lTyvNntCFays`<$5>8m6;OJ$MYnV1SsDE zBBe32tkQWbvz}no2ibVOT!CDS#@T?%ScuTMN`3wXiTRHh^z7{9@*~w$E7GdkRq^i2 zcXp@gky@+XV2PIxZ2fgZR~dM?Z+9OCrfioGy+UEicOvkCN^*aL(O0XW$a5h_Cv~MD}T#Tf2o? zW7y@z7edWLm6G@|%MM?8f(R7R;pf6UH$KYl4v9;Zk~A6lb)p-oDBFNdB^6w2a|SyT zchS#zTk}h?jp<4_8ic>Nd`!@_^CjpOUko)u9^3lpUcrB zN}Cv_W3_6F#BH<_Z*I}cgCgI$WEjTSXVZg&<)&jgH=Th|RL7{*7n==r!M!lsTR6z||7tA$aS>~j-OdDtS=!L5R8LCL@h zLnyl$Ys14Q`-3O1yiiiO;71HX(61 zn@?f6T}gl5kCb6g*3h&*(X!vkhzUG}+NuGLo4gqD;1AsAU{BbNlS(i#1Mfzt03A^{!IC>!sYTp-!1IT;D^&#Vk)X0@Cz@ zew}qb1X@jv&3&SfmEHVf2Au%BV`#Bc*u=(Ia2dS9AU$|F!6YuE5E}%rHpAP56^aM- zusks}FV%{NgdriOAHu~B8UQ8h1jlw>Q4cO{4qqnm=%ML)9>#*JR+{MUWG#O>kO)L& zpcjS4jURiqP31ka+$6p7j^C8|m#&ZZ{J7(Avp>)uwWs%AeD-9TF+ws0oX`_fl^1D6 zSH#roJA=^2ee=xq&J>ZR2EO#T3t%nQd52chf1ZMSrR0h)Pux+GrUxz)W;n5oUI>$e zDxoCw0R$_`>7tFur)_j$Z5$jVmFwyqM?%Nn-Q8({ATI3|Jrux{^Sfa$sTe*Qtm!=)Ry!@%n*vV|r|@nRx+L>1voIU{DT9+DUKZC>pB!svYy zcMGOoraUY)(gDb5LD z1@0-I=ba2JX6ypr4n}F~^u8*g@Kgs3SCgzs3kAq790~1&f|2qc*=^c{vrJ_fW8x)8 zp%?jBJgs^s5!TtCCbCOhPW!C93oXrJ>mQ@r{SkPJZJrG`mtohB5LhFHaf(CAnSi&} z$50)sQ^WExZ%mBI-jAH625j0&7bPW*DfzKZHcZQR2jQ60${dKTB@wSDXi4iG5hARn zUDl({D)h82Z^7}#+4v!>p8L5UQ?axcw==V-QskR)6JNN=oNrk=DY2zjb@Q8zIy%Co zDG(e~xkGy@rHlR?dwTKbHW*h~83G*yk_}QlMz+Wl&4`eVr-77A!qO`gbLlAf&gk^b zwZf0RoJq5F(T(6d@3r=;mU9Rs5HN!*0X53KkjG9`aq6O{{zaM67cP${VDL%?=CdnkK5(Qe9!KvCu-lrk)R@#om@0y0C6~tskDOv zwJ5XzwmCBW!-8o7@oNO?SSj2qfwo$>cx=OZ|B7siLEprJO5RN>x;Nr+!L1P5@P3CL zND?|N9RJAdIH8{Od!J1X0QiH4`TE*_a6Q=Cbv4V~eq&s$x? zUTBakV9BLnNMa9!^7DPRXSZU{32(#n<7!LUunBIM%3Hv<{%RlU=#?vk__qHL?)-ja&`fs{AuZBN))m2PA>0c zEf(V1vgEN!yKK)fYB11?G%uRvmaH}~{KQxp=`}~nR`zj*4 zg=bMCD|n5;ExrPinw~5Drh6eRF9QySIZ91b^)Wf-O%~^rB!sR#zv#1aK5T-m=Zu)D>vegW`J_z%86X<= z0bu)P5|cZBB&9R%>?pvjTiZMw1dro4p8j>)=BcrFs&Xklv18V5sYX_wj-%u16Xnm+#bPVd#j0oMe55q4h*SPU4jK4?WsTfrzw;yHcUyhD03rHc%LR0la!{YP!Y;LZFIIVe(K3oUjolMG+B~aH*1iN8UD}n z{2yQpmxP$h2P3b8$1H5$VvpT{z-9z9Pa>BLS7lN_$V_T)S3`_6AWlIqps%8Y5zuT&31 zuAXu3oXB$=gk3wBt89JWC?R~$+n*V>H$I+RzF23xd!GH_8WPReH~kGr(@tFOcyfdM zy2@bI+P(4cPl6BOVruC-$QpVChcr;qnT?>-Ds-sFu*{a?t|i`|q|`RyM9|YKT3!fr=E4KQxP;hxa?)`LsmsHIK7osstObJ*JRQ#@j{VqzymD?-|c?S zo2AmUQNgOxDoN+iJ(HnjvBd2R*UAqfai(f>fz5sjFAojTvl0^E{zB)gM|+?-vSZ21 zO#gg8lJ?Q4e5RI#rXA%cP!v|TR`6Chup^@{LjE(_x9H3smGbN{JL4%qvI!0H*t8JY z!;bIByeXpl3;e*;p8hu(=|=(;k?v5_{~VHE;*e~W)h|yEBV8g_ixnc{F2C!wOX#3a z-2~JoPXH%EBgWT|Wr-HA|sB&pAhlIFEPZKB@CiMlfJ=b$fkEU;z~?lE8m=CKTPlg!N5l z8G)$BV-oYNk_8QYbf{#&7)8t(yG62;-sZo)AFjvt<|G`sZntJ_VIol zEtUC)j<)t0Hs$UTl8yve@Sl8`n!7V?d$wZIj}HzBI+I);Hb~2!Wp5G-o!<0*xzgET z;+}M|ma*MUcT|`zo?($&&h@KR&mwM$2HAH2!gmRF-Tr5TtTskd*Ylr|^6v^xw0|P< za?LEa5Jvx`1~sip|58O;e2~Tsa$)O!cD36G%c`Z5&Qma;<@Gj_j>{@K>Wwm;>uJ`q z_|stoMf-L!C`H>xG5N)!#kOwua3tz*^oY|Cy!_sCXNzvus^m%P^1f?~P5qv=9Ja6* z`1*6Nbw58^s9-M8x1vS}Q@U!x?*}KA<_DDEzaU^VaaN*dIfJB>QZ0g>Cu`-;V^H2G zmLj`zLg>4LNUTB6-#*@;7cB=ZP=fJGd+C#K`U-`q4z61L7P zfi_2-B0K!D64i|-r)cVHn%+F!IwlElA}70SnbILzzlEBMcW29~b!i~9`#!^#p7sE5 z1w7+e)DXU$_!{!UyM+1n7pZnt`#RuF_orPI>u24w2P6ftyP+7L#`Mq08xvG86O6%7 z5Bo?urHHh-+{c}d=gY~lywKnyr zD=gx8_m2|tkpsd?RYW{)A#P8^^>OHOPA=rvQ22}C^T(skTxxw6r~7$P()$z*#8T4m z{E2e&&*2h{33o=(KDK3fDlDZXHh&yG^MVlgpM@R9X)Am<#uE7=Bl(aOU452>M^T{u z%B_VkxC^;$n(2hc?-{LfF|h!KU3~cItP_t*gN;rd!MtLN&N+3Rr}3eeHBwmNwz9eK z{o)1LtR6{lwJiDl(kO8Fa4m(qcOu;rd`Dij+>=yqXK*%Q5hw5T^)NX_Q2wmWLyLQ4 zrB>wl$xbRsQ_aq=-sY&3M_Y#K$;0Zl9d{~cU1Qrn+4bV_(69M$fD>Rl`-0!jf~>uN|LcJh zX+6tfzx}%-ZQ9(#;-T+mvU?cW|DvoPz}n*EBK2s+tHzcoXd@pT^tZW}-C-evwBm$2C$h4rwW*9Uf@N&s4aE{0v>;3L8^B z(CCh2!74H6T_Lob4u>2yqoZ*&v&Zbp?ndA&Nsjc>^QAU>ny4iuMt;*z)=HcMRtUZF77UkMBB+JAnT12CiHyNu+K z(w=&wr!BzQ~0>!PmIWQ$bsJ^5{qwrrZxXAF|zFt4h=p!9ypUk@FKsF&idD zkUV5X<3!Ti21(vSld_S52Xib01YfI&&=CCq&@~U|58v4)dUpyNkm;$nh8nT)Lx#_? zLts{YrGE!+8`n)ZT6*Hn@*itIY|AG`Pz(V0&Be7Syc2csm%;Dhl4!~5UF zfiG61fN!uoX6+quOXKAqde2D{Yl{s zCj1yHWay2ONg(5-*cL&IooTOEzNpHLV=v+$*xiw@xqD(A@7zLjB#Lb1Z2gK$tYtzt zNJlUS2M+4&s0{id`;M*RdG5BIgA z=xFAXlM~R4=77F1tnJ?ue6ho!N(J4P$K`9s$PPKQK8v2%!AJvHcindOfO}HvGOCtF zIVQpSsP7L6Utblp_iKR@<1-I3DPyk&Gc!^U5+fR78f&|1BZ3-c-Xr znEg2RTpvIlNNJzC1bpm39@-9xy^+ktv`t_1w>wOVIQHS!7x_L>P)ivD!p#3ZAYdTj z{eOH*%4F?HBVBMr$modw_3H=7BF>^SQG4v@S2DR5mxZG1th0q-h&(>N@Awl+F+{Y^=V6{zjg<%u9`=Cxx?l$GU-vjTI zW30Od!fA!{)rlX0hpl`yy@VUJRNEvOpz_A7fUKRBU;nEqp}g@n5Km6 z!i;SiISuwY>Bux)@uXfC4VS-bwlNDiZ%hKntwXGoY5OA9g;D&76N9P#+s5`6vajR; zztWarwI7j>T1pQiQ`2j9mec}RDZ?nWIW;$pwFvQt{rm7&=nNyLcMs%A2VweS$-EQ% zPyzC>e0TK{SE^1)3nfRcPI=7cR>A~g^*@d$kt33fKID>J2_eZm>(uJ4jvHyI@idfh zTDG^{-QAAnQ&mfOR-~K;5aX;XjrP=*h2pU#&H|xch}4xDyYYO%rf}pfoP%l_EC)Sb zt_MQkLms(UT~9Q4d}J8>LVLji7q^P7DgZ9vV(WthW9)SC!4_>ps@Perb(ab+k$doa ztdQg|)xdr9_2XqRw~z30O-%~sJrwTjpu?6(wn6@B^ISq=X1@(Tc8Ec6222o^P(#%! zGm5Guf%rtkfc-=Z0WY{e(_su6;$=>SIIEVM$BUgvw2F|c1+ zzgw~Z7MU3^*05H^DlLdSrryq;<7rCD8|7@6RVpKY=Qk<<6XIk@O#Bh=uhc{SuXK-R zZdhp4pGS?9s|XtDgFErSb@@)dird8igm^t&RbVWrX9v{TV{fj<$&t9J#4JPVzb#mm`+qw=2}Y6Q(R7**G0mco=l7OLD63H^%`U&znMIYObPx zbxHqvGi)LczF`hi+NqH)(MRjrxS#UWn^RDh>SQ#AuP!Y%|N1R$!-t1C=O{`{DQ#+t z;Z*t^RA>Fsz%JuSUihdG<)uFGs``6Jnh+!c z0VmDUk!F7!t~vq!XrRpP5tNTJS|xv2(Tci|`^~vHFP9SqgHFc~_SM6+fKfP-z4fs9 zMlHlrr<(kQ%1#ge;}GlbfaIsKRp(LHLB#vjeWJc}3kRkGBpMvXyM)E|!u*t2a-MtZ z1$)(b8?Ig?W{7o4_v#rmz!z2o1CYp^IpD|(eA2Mlrn^mnIpEz!75VyJHWwxy~wiM`wnpJhfJ?RY9S-PV=w9;s0OQ$u`O!r2U_+ks?FV8J9HPBsL+D?TAGYIop^^~EBZFm4jTUA1oHH@W} z4VFIYn+0Nn;s|rrkV!ASD}Aj*9nR@-gPGPgZ`t)l*M<8tN^>6T*_l3k2Mi$sWKZO*qy+q!VmC@XDAB)~-v3FJpeXWHhXb==HPtI8 z3|(twgNgernM+!^#W04^=Ck|R3pyOa^lPqLu@p#p4OD$-40te@c_SXZ`xJB@CEQsO z6DW&BcTD7)P5YjeyQ0DFLrLMiEm*o8U1K3Nvipm+u=tSmh0TVIlt<0boR)#vK&mN7 z_BUhKd9PVa_fXo%+;Lzxp|xbslb#C;GFiNuT!CXrBHrdYiGOp?ZKBmzl+kA{ScU!KxOk6TQ0hW7=x(Ej8O z#@j9Y+S0U4nzfz{olkR@kOC;(KNG?AdW3;BI_|@AG-!n~gW*`MSkiHvt=wspAf`-rfnLctyFBISXYcUB(BvGm)Dh=#lrbl^i6~cO9t6-&x z(K}lH4$DD=qWGgufV>7097-^&Xpa(4M59aO-}MkAcwop6vBO#R>X+GK^;X!&{ln_J!3tXa4?%^U=kM z0*9@6d7tIgWH3T`@2Yz%wF$%FGcuJIWR2cPYrx`hLe00Vla2}&^7KVUFUZ~|Dz9)+ zxWBJ?SI7WQ8&?^TaX6tL`_7o}=utq{P!Cw8?7`X#LAc&L(MT|ZSY9`_^rhbq7!&z# zC^wHE0vbpC%vPi%LZif$lz6scKTDAtcHNDgFxeIm^mCW>)^VyD6bvj-EuSq4jJ~uQ zRe$PNsges_{xAIb?*=mBf#XUSGIRw7Dr0fyj3UE)rohdeKmqii$s;h`3su*`EJFF( zaDI0`Z4cazk$)=X^!(=Gge9}|gaY2G;;!Tykppr0PWm|@%B-u;5c9l9>G}|6=>{bZ zO0kKmVzlB37z#58J$4# z6tXmnx)M6BM+1Jd{JOtqW*-Ry^GDN!U4w$Ak&!N^30GPF1la)tPvx=fMU?*})_?yv zIxKj~X3@nZBf1yDFrbn~_PRL=Iw<)I`Z0dWd*U2MtkQ8az_4kB(4KgZPBN;X;pJSR zjUX8^(`WE4t@((8PVp~%qM9`0qKY~6%YXB>F=TI=9L}fzW&;1~G6M4l$tR~lhIG3y z^-zfdOz8i;AmCr+{XcgWCRl{$DeX$nLX}Yz$fy%2Zw(Uh2SWQH z0^?FR&cAk>imD#=G?5hri4_DOd+W;Z1bm}xy+UhL(!z2?v}?&hNpSElwaFz6QruRu zf}4ya(ATdrj@MvlPX-wLU+ZJU2WtcW)Mif|`2Sh?Ke)LPDd>y1gY3L7fXsheD*Y#} z|MSlV;lOe4wRHL3Kvp1Q(hz?0_AoFn2*D<5a^NdvA?Rb(oo(j!nC0kv|LjWj|7Ta& zqzcorZB|NDX>FEB<^SJb0F@yCC^WeL-fL=X6KwpPdw_BTF2A662XTJ!u!QgK;`g~6*N5BXIk*_lngw&+UHU)A_| zwYMKbHC#hBZ=6<@xIlRzeSf0!N_QL65*Djn+6nO9X#Fm-KPjk z4C@xX|YH>vYvKw$0r`uHwD6UY=IN3^sg>TOd2f>c93s3uAw6 zwcjxHneYHd^x}dDKD&@rk+`=-Ozd2W2v|yCJ(`A0TWvwnOEC+FXifAAqm2StF?9A- zEqy^M_gz5k`6C<@Uj`8W0Zj>wcE0}5+S;(GHr6@iGGt+3ZF}=-5uE>yHKFixMxr=zuUu9XwC-b z8o|}tJBz&1+;4U`(lke`evJ2s(~ML<-r*UDAbWGB4>FLOT!QZtTOCRTULfCpF$Dzh z3xjM+{tSVIZ74=T?{?~RK$gTu*R`J! z2Q20^FGeeyBX!ybeDA1d4`7){$3g6rDxqe3R{d4??$N7J$t|y1gzO#-^jfv%U;~(U z5-^Bj_V#{k4E2YKUIIX9FY0;lbK4=GkA zve*WIncLaqS@M#gK3ga(ne=-WnQP%43ol?*tMp|znWwD@VH(^=BrP^1OJ(&(R1>H( zn_p7s;4KhF9HI&1JQYgq9n|rmw_Q6xp~ zrS5S408l+lqRGC(opKdRMR4vm{Ju#;i~~;hA8vk{yj%lX3pj?1{FDx z*xS94I;7$NFp|oE&e0lf1EZfYG!;KlC48&x|huIq`ystkf+XK&mo|J*zWYRN_(e$T7*e9|I! z=&u9Qi70sTC%XLb^Gab6Q*N(%NjJc85CW}F7x6%sCD-hNOyoTmuh9^!^)OcQd|o+E z;WKmM_k^c3a~m<^y$}IPT!zFQNi;U@TkK0%QB)rVv?XO-a zmolrFanPKN4nh69{hqfzJQ9-P!~P0xUvGpJdeJa4%@V8g^!dy9+_cB;Nx+9x&9;dY zQ(Qx9G99&tW9j!TRw?=gpE5idp?-!sSzH6c%*GP@DlCedT`$u!ZtpmE&mJZ>jLfit zrK~#0ZCjKs0+85augVaW?Q+xC-W_zMJW&%t&G96N4m5ZkT0hwE2B#kU;7tAj5z_^76L z@O7u81yazrbaOI@$$a|*<2vynZY0c=Xy!)}fnIP<%L^4`qK!VESy<+1wBwa)Po{M01dDU$L4nl5H|klBb7lhXERx5R?c z{JuEDz32|nTTCfX>}+$V?WfRJm#k`99C5>TxE%4P1G4=M8l^UmXqoepclXEKGsbD?9MAGw)-F_sx3LQDcG?^Jq&lnSbd{{ZQULg9e1=QUEDfITc4BxCth2<;OO)DNr z`QFD@Jd5QIhFuHqs6bkydoa|m5>KkjE_cVn3H#C;J%RwL+uO8TeC(&BiQ+Wa@s+9x z#DsmxUPTY0X{Xf8^c%fDmsV6iwZ&c$2UnbU`CntJH*I{5j+H5yufSh^zMB($QJL3i zdEqGyA14z7divJDKi!N6?`-D!oY9;)5yFiUCq75$S0+?2Q#S8ExnHxVk`AS5yYGFs zI6E(+j1G0$+6e2+inzF2t@PP9X?40i^wcvC-O||+&G4I{DB)?0L1kM|n>PdF_hjH# zNf*zXN?fbTtopeQfMUe#Q-@WiakD8b(!1Zi`XB|sqy1~Q@YBE~rO4)ZveM}oP0 z*FF6vT~XIDtvaEofCjDflg}2I+3ehz)S@CXc{p89x zuG0uaF0#-wI~sq{uz0k`yO+mC)c2H`+pfM3J48%aAOOp!IAGOh{jlw9W+!JEB+1a1qM9_szo|*lIJlebO;U+W zCT){$?nSSWb74MlIRb)qVZ+=Z*u7*Ng093%<#CTfD1UD*tmbY&K)?ogHV?+QdBG$x zr98?dF)X5=GL@U5+r;MZ|K@jgd)HQW5L zfs~=$t3E@g1&5^TFf}!fTy_01cj0|3=4*J(7r^ehSoQNwSiRki@E{&G{jgxU8>*7Y zPB)&h_=ZCKQ;@*iha2vM-P3Epafd2+etmluBy=Fmu>FN|WH7<&- z^Jz3#{z$r~7LRtJN7ENLBi&MTp2qQcik0rifPZbv@nr57*h-EJCDmLFa_`c$*K6cL z#ExE!U3Bj)pI8~IrVYmT*H!mk>b(HsQ1nANVRkA%xEYN=BYz%Ej zR(GP?JFP3e*l-OKmv4qY$?kA%13bF=s&UDsJn1nmgal*m$dTAz-V<||x5cAFOW^Uv z27lO3S&m)1{LvLbSmIBzNRN|v{PcwfHY9Y$wp~He{SmTtF1mkrL5|;-fl3yn)Z>F_g}_+p7h^8 zG|hzGGpo+w6MFvzY+DTb5WZ$tNU#BMd@bwsrC8emi)5K?DBX-y<@qJe83GD|VBo}5)IlZ@ z3{^8RM%+LkiJe+C71?!+oG?_R*1#zN*&=SGD>jS7NS78D|3nVza#+Yw5`R}iNvu+A zjIl~QJ(yA*6XK#^B$5L%b<|n+yZ5~rW`>!^0E2>g_ndk2?z{JX_q)G)zwh4f{&{b* z{{#e0nk2K$A78`+lAOy^g8B*hha7uLx;A}tO{$R!q}h3EjW~i=*TdH z&G`Wqk)e69=N9}!BJuK~SPGwl=cDEzEYKU0cy?aEfqGgIDElQeL`xZ|!CSisPqB53 zWITzo%J3-U z9x3iaZs@Wr$Wh~!uW|FPFVyktXrNY!mmU{%-d{i5LkpX05h0G{z35*(Qwb@JXu<41 zw_`+yfS2bjp{MK6)V>T?b~PfatPD3-t-`sMwFqdafjVm+f^E`` zT#w0c9TzVf5lVx+73{Y<6GnR0So>edD9pv<(+?qYu4DcMoMQ2OM4%;tA}|sO;<>F$ zTy@vb%r6c8tR30!qG@RTl&>-;7wp5b>Em$gt`Ng_!hhok_U}7fRd{>D@MSGD>zMK5 zz)=VOL-iC(faln8mU|44FRO&Ze@jb;ir{BK(<7)j)q+`1G|;d+7L`v^i+YcZlFg3Y zt1-pO7!Uj&D{mz(er+IglDSw+3N$Y-nZU+a<~e=SZGjeBsANtGPs24m4R~Vlk5(%J z{!^c#RDWl9Jw7s$@#Li&_{DI&1($oqBQkmk|Gl1TLRb4myjPlpqSt?o+4VaRZid#5 zyrf*vB*JAf3~9|6n%d1aDci2F-2;8~kxe9KF{uLKYxR)TDI2#6^`u6gl{_L?g=7j7 z$JcZxI7uEUilpoYM&Tgs{@A}`Ba)UCa)RpkEPt#|QzDqk_il+ES(VRN>_FDk8bAFU zhJ-M?2|g1(*_V%cuXtq4W;!<(ao_LNCGd~n6D5^|i*b^4xcQ`Wa`a3gU(?qdXVrW^ zp}_p=k7uG|nTU|{!Q$e5=y|6M>sBr2p-?SELEals23rZ05HdQhZqgkyxNcBGoI~Jc z4}T7er2iu#4s1y7x?UF(jkrJGfB@p@8pN)~hQF@n|G}>-JMr@kNjA^>dSdacm0pB@ zFll9yw_9Y5Fqo)KI}L~3FpA{FX`jXFL>+CjTi|h3EbwQRhwO%ifDgvu3btsXXd<`Q z#fp;#d~&r9_D@p8k7!c3H@n?K=T?Kgn7%BB8K);{_RSq8GjmH zre0e2;Ni`NzV$f&MGvNnOOeLbWB6t9->_!WT6lW(Pz zv>ftNw~7fp~q@x6`6EeXcXBgZj2h~k^{SUW$FtS1HMldr{)QD9C> zN7}e!evg6hB_wltHPd$*!Q}um8h^KmXFtT{)AUGQ3AU;m0Btd*dE6tzPjD^ZKR|5GkP|TpKWv}ocynmLQgOb{h zaEIYWKjzrK^}V!Q=rDziN@s4zr)%f%^lWQs(}}Yf6X`&2h0m>4gl3D7!svxO8U{fIY=7*{X!vr0MW1p$44>mbNiA+>t$>FwkWDSPLwEci$u;n$jc&Pd`F{dE8^^J|-|{|m zd>kYDSokv(P)X-i|B6}5!mT2i@Mk)TP+yyhfBCn2;*p!aaxU~K^*DFA2h&typViaN z+o6{)om1w*DiLm$Z4zEqMyWoF*GXd&uHIcNwoMZ*HPwr4S`haT_$CK1`$ z$6(|GP(M7E6pzNLD(GWgz+`$h_1QS+YpT$wO2^z$v$dAqwtuIJLpmAIMJYc+)rlsw zcF^}5TbpsPs1RiCV9|4-POHgVIS;86TB!T2fKz)D_P?2nhN~0s81=!*d4x3$c{i2T zp|!IU?ae2!Au$cvpRpAkC(h-)PHbRAE2cLM=xo=cYEvSgrR;8FhL^M(6kpOL-5we; z|A%BgHlU6M-G4c+%*Dm1sYqvhOTY)IP;#4N%zTbsR4TK>R`@Y7$w z>E>2(tFr{2LDPjcqT7lS%`MQMt3yUcxrOd%z|+F4i#MTh1r)Oe3F)OcMP=?FxoBxR zhCD4>*?R&3!d#R?YSMDy12r?k%G0p_L^C?+d#UH@c7GrxI~&bxj>g^%U?$x=WG>fR zB`H)-`gYP=&3NY*Y4#MkUz$g0*)?80i8X0D{N~^pw09XXX3Qg;roY!+e7vWejvp*U zkX5d#1*@PXf1dUY96Z&G4yFtAr?4e8h3gpIOHY9FPR4kVE+5C5T1W?xF8P&?!qr&z z0&UG@Wq*?h@6FB(7~#B>wuBPSrFBgl=QCArBCk$}N$b`)MBnZE@f-U|e&}-uiZKvM zF&^W%j_;*7+U|y`J3{BbLPf5DcI!d3babMXbj!NzDhmt`jl2iV$M#gxvV}V2?LUSV zdYN8ldkgAH*CUt42b%nsZQ8K~0K1#Q#4UonwSPBb|G%fvnbE{ zIV{LSQyn%jd5B+#P*?g|o{M~u5s(oW3Idju&Y=)_5NUl>^FfP}^m2`OL|Jb`vtcF> z+J7B;apM;{q-o8atp;yb{mimrr+g-sHrv)9?1gY{xOz{YL&Kxp2!1sRRvW}@sE$le zAYR*10c`yhin3E^J~h%Ta$-`avn+gP;#q;$$_@Z;=1_cQK7Y{S zYpNFd-EG1)>Cu2E=i2p)cgTx`Z$1iB@{pk`?@bt!iai^CBCLK2JHUIxEO*j!;kS4_ ziaUXfY#nX(7hGz=UMzMrS*7r_+p6E&285KJR<%retAzB{1|6~!1-VdZw9wFisjrjf z5fXLkt%$&$jn|N}ISn<10%g|r@_*;vz)EV0JKs{;X6LO$*3k+Cla49O&_PT>x*{IM zRcV+P#H>8x{jCag=hJFq3Y+d?E(ZB~H()kbCjEqyj3VS~oR-wj)nOYDEFQP0WQZ!CVV0zZEVS8l2ony$n%zfOLzXw+o>aD}Oj9Mg@AI zt>7fu#z=+4F<{KKS6?wQJWfW5x`3(j9TMj0OYm2>g6T*OZol_>PT@<#@7B*SO+L2HF~A zybDh{FX=<&WkW$%oit7+Fn*x$fe(H2&3%s1rO_sR|C7_Dw-+(5kAIKEGL%i`gX3#3 z*xF?4RuB888?$~q2mQUrUUr<|skn~A)gL2d!BWhgC}7)hrWA|P{(?QnOZfmxpfNZ+ zd-IpRdr-I=y1V(dZA&|oX458AQZDE_n}*wThL>c`tztnOuzcC~uuYVf={Y#IEwH3v-^$@Z4>XNReK{9*Do;8C3!UH z4W{v`f|VKwpMM!Q;@FlL-JmCk|I7wbe^ zHDLxyd${8>W0SoJ)>WtQ@q@&8QId=_PE3*aZa0!7G@w96*J^;vj87|X|D*=b*FdrD zpO?YLP`JU^G=Jyq4A1eneXpuhhIfxD02 z;M=aGT(HTVVNxzEUss(ZkKAx|R{p;2g~scW&YScA`$;)(!bQsU7jBq<`f_MD9n}F~#o|?v62#pFSK2$Zc7=9!EMpibtPBdU_HbRj?P%^esz&;eAs$ zf8z1zb7(kRjt_rNFYY^k9)^H8{71#_FfS~Czl6wnO810}^ty0QDP<}$0x|+46#>ik z+K7mVk;G00000NkvXXu0mjfbg~@l delta 70127 zcmZs@V|1m#v*;b$n%K5&+qP|chZEbjZQJG~nb@{9$<6=X_nvd^TJM)kz?XWEhH|So-)h1^YdW^X>c(OsmugHh(C~#q73HcG z>qW`fY?aHOBy^Rn*ywhOSu6NNMAoE2NW#K{D&IFeH(O~R`rFdmGNj%D`qw=cz9-o? z+dkJEb6zL&1tN71M^lh~o{%@?N%~XHkFy4SN!fr~?B8={EpGDQ{&J|wI_n2KnQ)bN z?{3Wccwm{PUR}z)t@6y+R8it7+2wR)GbPWa2k~j>V&&G6tXg_Uss#bUz@Z>8;Ak+E zXo{5iin~{30lUARG*y#$NfQq7umChl7M{maqFGlC)pI|mZJ{ky~`e>M&CDm-}|F6IJykrmNXa0D*B2W$kavX{I9x&$=&ta z9U%t9&ClB8NRH?x?Ztto1?XwI5`z|$c}sA6f5xbuo|3I6vNcITkY zpAgO5#mRz;@D}suRg|P=rvX-O_qgpO2Y&+t|8_ckQHV-YDDGU0kX%d=f4sObfMu;q zx)>iLPf3Y=-n@&&<8j9OFIoS`qyHnkAqxzY5eYs0tT`0A=zq`1|1-+)XNbrcZPC0~ zK>$AZ;Ly+=;BW$Ucy#pqh%zlB2Lv1z18mH+qrKhqxt98$%Fl%U*X`TFFyZMjZH~H= z@wTGC7_6MNWky54iR-11W$i@Q-~@;K^L_hfbNQmGH0r29Bp~K>t%Uzuc1pDQl7M>K zQ*teTw})f7;ju9iBBFtNX=%U&tx(`*hYN{9F7IIBKoA5=O=NxonSD-c(&E2LwJMBQ zTrQ9!zdwoOQ#q11CK=3T$sg%Q*SVcT_de-jVfn5)|K}xEg@T!(@aDR?d_KQX$fOB% zT5YYYbt{s+sQOo;eO|7iSE-~#a=m=29;ea3U%wh)aanjKKdd7G${8FA-UK2dBB7y5 z9dQ{i`dAkku840NTCKKPCL_s@w32~KWeOIWbr;JOB+89tD5I>fIJOJB zi1;kb)G5+~Ww<*iFl&GR7HBpYxBGpxIu<21A399jeyI!@l7|J}l->85&*(7p#Gw>b zZjM!Z5R~|Mp3LR|s#m>A#>}Y{o6O~!%&O@euQ$2y(7<8P<~!u$q9o$*&+`3H4}4MW zdZE{QBiLCYTZzp{=%PuxYa8bFx?Rr5>`v297?~h`-C?Dw#N{i7IXNw3jdEC{g>L& zV2Xc(Sh*KT%aKU`t(F7Ekeq=o(eeqAzCr*0OzyviE(U{`hsLnmtrtsl!N~tls}wBg z*HHj=FW_-IM%djD-k3g`Ntno(udnN48FC@;FBg=|3hJPYpx4v#FXuBlGJR9M~OjvmNt` zK|j3YknA`sEJ8WSzRMcQp3VA~E zV}5Av=hxj}#E@OHa@w+z(wT3-zZ<|VCU@z>Krkee_oF49Hijr?Ug#tSopwNIf^aB| z)x!}*g;mmplNW}j36-OO!L~1@b~EMH&N8%Ph26uCpKAC2*V(;cxz)+08QzLEt<6p= zR-8PAi?$m^$(ODwLon+Oied71A1JwS?S3pF&GBB9^12sDI;{>?Ar1!MC`#%BwQ};X~gs(V}8M_3L&zhvydo;FD?F=cWhktwK&R?u4kt z@3k&fq3-3bPkN4n&Hf0$-%B-VapkTRzt-VWhQyr9>qV^YUai;FYRIc~F^5yjeEYIn zmggT-SI0oDUTyi5?=^dJl;YLl0&(_HLww9h&8>Zi&Y+LW<#N1ieNtnux-|QEwlqMa zNvGF|77F`o^k^zAw0__~yTKTo+x;^9YNO5O!#v8J47XeQe4z*+F%Y!51IQ!g{`EU< zF6{MjNnzZ3S&?!2`ubYgsVerzw8lzg(iq(@HK(&U5P#9@24rPr^-lzeS16YZYxaGA z`4HXS`J1hPz*bw#W|PqTm0}Wa{oS!z8R6}A5$R(^=P&Z~{dPj&`~25pAHOj)Ixx=$ zqrUh3oW{v+g1`&_=_FI095H#jOzC;sejkG@fq}T`4?3#i(M`u4;i|lq!L=_ z;BXSy^6t%hi=1ax^mQF**|}ai?`#IS>C+EI&~*TL50lq3NHSZC1RJ=8)i~&! zyZ0ks0BmJIXBq}4g5$aHdsiu>47pPD8zN4Y)b3UyfT9wR2l&$3WQYK%hQ{Xi<)qi| zrgZ;o4Xr2IQ;%&e6Ep`9*a_^np%yt4?96_=lS_@!~Sz%@iEFE9O74e^#r7G?)c$E!FCEi3be}SpIDU zZ?)h0J*(F_K&1eT%UPdi3G{e%5eET}9p0eLB9CFpZoe7+{&Z2~dbViXy|=gL=;ns5 z4p%zRU@{hRyVm95AOzdnhEAv$HEM9xkb$Jc=X?5c7CAwhbukUL_$)C}~9kp8>LX??gkuY4Z~4=;+N z15gE}K=|p{q^^t5ZM9J>l~nJr!+%#l^}u}Z8}6W2P7L@1gB|l8Gc@h=Z&`1R2?ljV zSNKl+rU)?uBIktFySy;To%8sjW zzWghf&glUO)SDFO=O>+OA%s9VBE*p3nz8T`w~z zq0K$mfJIv^2@>x^I{KUM9Jo-*=CO?9*r4+1K@Bdve#q4<#rA5%v)l8{%j{emD`59s<&Dq_x9+$*5^QjA zfZFzJ!~a=@G_;iN?$5^lPcPq4Gdiq8Oei7#TMbE@e_UV0r0lwA37cdH0Nj?b+J!#Mo90n})wN)$Ay79zzwE#P6y@I)l9qXI3gBHyK9Rf9KRC(( z#gsEY2Tp1u(pNctcVO9-VVDh==!;-I^M3T8skdyd>(6TIWmv(59{OvyQ-Eg`bf2g` z^ztCq{>7U?A2;~be+YcFeDtuQz(o$qYHAep58q-gm#&$GMx%Cky~Rc>PwQeh6IABR zzBc2t#p#VqB0(%G6KmPU7Rc2bMV-q+1%@ViU zN338sjilwl&cAQz=Oeiz!Eg-6nAk7Bj=k z6{u3-R&kYTH2GRh8iobE z6?abfIZ-Re-v9YZSx3O)GHS9o7>x-{4G6CD)Bq^u_G7*d90wG0fRmkWZ#h$wP21Z^ zw1sM4O7-`2H5AG?nJR;G$*a}v)wfY5c6;)i~;=&O`>8CiD zyl`0WRj#kKQaXGCMQwB$H*-tvBJg$R)~+7RcL%?A7|11%eOfQ=9 z_5oZFy2=SGRSk-*>RQ;*s4+WXgEy41pvPsqXGFsXSs z{3hWLvdp~}_kn2r=hn*7{(0176w9_{0(Y2}WG{MEDpImiV#ZkI4h06FxAS&K80zlO zxZ+){_9Ced8lzW&5S<`L#Zp=|+i=|Jod6%*AQOo^4}w% zR&sH~%$K64Klw8W%C~*1E8>wFK=DN#Aa>ka*pk^f2$Dtymmn{6L6N%sIjN=F!uaEH z3~+=SseCIHO<+Ci_&WMtbn(U4)zY(F&RdD1ZfLHSh*_o8c|x%xFjrx)<;H1 z+0gDdVx^n74t7}d>A11g7nEoMf!v@L z4V0d(a1CySl|YXtZRuXtRdPu0rl%nE5Ik;Iq-&$&|LC^DG_IHw|gYI#M`8q#?I3X z7p3dT?-yrhR5{wNhl0K;7#(nkND9$wzrTd~gFtis5TpgUIT0QL^&qD)&HEr}d#WyA zX>JR@A-mslHz55{VJr^s_zid?wE>Gp?BA~#LrPhLPXQ-TfEz9bZ7M;m>vJ;jFkh^h1)qmgEr{I|9Ah$y{8Z6(Wb=Kd+c~kK8D&CHgw{u%XtiS#hZtT3ulK;G$hTe7UQQf|U3!LuRcs zS{T4PRbvtO(&xgg`3uh2ZlfmbVyEDW7s(;ldl8WwZY#&=La#aZ zqa6-=R&n1gE4bN@qtd(E!%cLa-4WtFJNA(K3HV}0?MIK5YIa`(GN`5kW=?sD9{dg> zGK0tcKkp>6GJNSSLa$_U^!RW$A_{ngU_ysaO~y|I@VoexU;)^YP-CMJkNU5OXfA?@ zmS4=qlKzxbC!A(m+#d&=U<1D(N8v{orlOG1rkhvo zwGO1Fo3>s#fCjOe(+OP;hP+7bN=v;bt^%)2ng1UZp%&Zg#x%Vu9Pa#-i~sl6Kk%j* zX<>O(d)eu-HI-3sbX7T9GCzOhyMbPa{QWQACYfV zD~Hew0NmaG)Zqq0cZX$2U8ZHeK12Ht0H2)l!=a+Oas5sx-tD}wX|#vZF9W(bqxV_` zHHd!ikHBLPGPT?Hz8LJXLhLFTt#c}Sa|B~RHOGY+roHuZF^Og}g_g5vK^b*gVlOgx zw7K4QthubZR7A&-&@au#Dj=(^Af$j8 ziP=Qx8(M$t9cZJdlRY@9EmZrQUjz&qJ7=7Z&&;*CTVm;fyHN|pf;FKn8>RE;jD8!) ziOV0v1XlK1^Zny_j(g{7x;@?@nlyx$*DCKa>w_JBlJlO?9jaf{N01D+Wv=-uAD!cJ zfZn+!$$G6#L;6_V{LZvELum@bFGL?PESazRJVF6DT*Bc@xKv@UiVhAc%hMMgB3>|1 zSheA?>2%cSEnkeD%8HJO?9il{)`{poxL^}ASFCCbS@#7P)vUJff(hK{)I(u(H?app z4(xzgw!i+yao&6aVm?aNe6d;16^14$04z&^A%Z8E4HA!xbH}A*yFZ=uE&Ji*TbU4vAR9Sf22AGG)5qtu_aNHf2ivDE6{7Syz^2eK9v}V-r%tNfr zq#na$Hl`N;hmlSssc=iOFZy=uZ4y`%;pGCq%yiqpHbGjBu~s?PU|~H#-cQdW565&9VpDOt>D-GjiZ=&Ch&~a`+dUtOU00O( z@1W-r3fiGjUSb!48kxo%RIS^NaBx0Ej<*6j5?vlQ^r<~&z{A>xtJT965vRvXF~%gF zirv?0dn1F*^3vWy>Zv+|fRZmXs@x8OZqE6>$LbM&WuHXNCH}F}aRBXUeM{_CpUrZ4 zLDJaKw9x3NEvfD>_C5@VFJEYh&~^u!&P{!kJ=Xjk)52YMbvcmN3X1t-SPapAh zXr9<@CtL9!Q0?}`H1=o8_oNA9%8o(T;(Ivsi}DiDxXxLqo!0PlIz!)oDB-=Ha1;#N z%03~y>RFf_-CTwSfZl%}FE$yf=IUCFhZ939{V2}XfHvXdBGaB)Yl~uQ;5ENJdhu4; zvXLaY`$>|~9Y%W|PuEXHzGS@}!&}i-C!jy0-a{kTY)t>K(c9(y>?%ExD>k%WHKK)F zu+l;-7So%Z@G|`^>%RXy(nw_uGPHHpX*YY;yr)&;prDB=0hr^`XwR%nWjkF>=|l|; z3D@e9LC-i9<3h(Kk|$$(|TVVwp}};&-njp55F!p=eQfih{Z)+Idp7^;#*SvbMZu3S8NlF$YhT|Vlg65{h1pQBqlv8fl+U?|&JY8q-5Sc2a8&#ral?%oj@%)93I~es)Xogk~PyCybD(LZu9X zTwVnxiaiYQpCQL8^*qB@5_2$Fm#(uf(AlY{cE_!61868RB0zA9XW;ljSxOhwk;;IE@X(a6?FTRC#(mz8sdd%fQtc-b%-V(dgc2ySId1xjztwuBbzL-qtb6j>fCA0NnIcKzy1{Y~s6v?3FN8`>N3R~=){q$$kOlbcG z4K%i;$Za`@?G+8K^tW=*Br}GL* z<08UHeg~u~@l#YIlu$Zu{MC|ku~|PUi98bM9ivTdB#TX1zvt!WfD~S19I38fNddf@ zO%t&v=Q$qWV)f}Q6qnMY3Y$af@^{9*LL;6Y0!YR82&w9ElBo@W^k`!nsuz0M(_elW ze#4~sXNwXP7hp=%%4)c)1j^6sUZw}AY)D>U+)|z5REDlm8sDFZsCTZ>WbdGZtR`Hw z)N({{%*Ct6fn-hASIUOMh6PF5Xb>cd2;p`p%2^-9s2@HrTE8lPawn`8-s2bR#jL&1 z0CGMG?RrevbZm#cq;0@G67}S-N_rLlRs{R*9c)1M^7pQ}<>-QHCl|Ut^k<^5Yc$pm zWFqA*YwjQRVD)~z+Z50-#gYA!CjIRYq_Y}v4uLHI*qj#M4?^Uaryh?a z7%gB^2`^;yLXIsX=4_w$vNqsC}R9TQ))WZc$YgjX83t{|6(Q=jBbmq6uR??2_f zwQ;wT1Iy_r(p44ZSu}uqW^>#{y)y|ku&EMUFIthfkukqK;RVVLd718_Y4)Zy$P6Ss zJsy(m6x=9ONuoezqMI`Of-(LLV7Zez0xyEI%Z12_SZBe{KJx6sf25jl@cb`W^EFtZ z@OLrw*Q=m&UQty$U^c!p{6q~p58Foj%ly!9`8$_-wR19|S{zYi4u|0vbt(~AF82nH zwNY@L)|w%_Ix+Z5;{`1&2CZTJV8j9ItB*ace(*+urAfJ*yvcx&{gxpFAR(=2Mhqjy z=Fn_U(ryCFnVw-p8FR?0R<3r;q(ZlYxl}fzu*oA#w|v(Dzs_-3IEAaeSPox8c~Pc7 z*VHV3Vh0v|Vb-Se@(IhksJC2b{M8B0vnKpJeD zchukVH$}wuh75j7+jVk@0T6|=xJ4`us%ZDZ(Tx8-+MHEh;`VvOZFI|L8)5&9P9fio3_D(<#NageXw?eCqCz_tUFiivQ_yL5zMaE-7_8 zfJ7MFKT^`dnaz3z_&)v7Xhzc(cq$hEgMi0Px*~QgSi%7eJ`pqeFhlwJpXFjlj+A_5y8t;kMx8QTWQB(WOmoiE8jQJbEAWU9`Juzxp3%O{x zmU%!Xefy9dkRb}0%OmN2(jju98%64;!2I!HY5mCk;6(iQL{dhAM%0+0#9A5Uab>T&uRzPy#Ik`GKfk?RTe13J0c7>=kPK|N|Ego+iN0oN8 z{mb`wC^gg)N2Q*^>U2iWx;iE$50x+E`00a5;#6kITzB|*_FQFwTa;e&v zK!r)R#1cX|fNi$hhP6vxD$~zCH?6Zqu^~vaBqBwI3)dOSD41>R6Zc+uf!0$K)RxFX zT=zYd)qWA|iPEqGoTad5WPAYBbO4{NO-j>e6367oKcj>TlET zNZ`RGd#XC6l*}>0yD5@Z%(4t*(*-YVLl`0f3Xbr-b6-itmHIGHlj6`v*&}%yv&QPA z`jV#RmLy}#qosYcIp}c7pYmy90O66AT#Oy+PM}f9Ic?; zz%9keZ3ee~Fst^FW>E?dq(6tqxIKzsm!ooWJN0`vz zfVE1QyKmf=N=5gL?%w7@vmw*{Y-YIHfZ9Ss5DX8cW)A3Io+oK{NZ2B_Oa*qF0GPiw zCJ(DQOfE+!^&EH04Vvu&98zhi=B6zm*2v|plxVYNp<#m&d&L90 z`diHD-#Ei99zNJy!bM05)A5>oqm!qxiJxDnFvwNHQdskfNW)@V>bg}dxEsjHBH8H; zbaqs<2t0*bH^dxXW%(AwF|rbw9^k9H;$^`-IALb&5Q95ARW_NB$ro>PJ#Y9hpR3$* zuA=nBix_y*Pzz-PdV{ahq`akW9LCG8+hQW zI~@M{rp?y`#f_hR&A2m*0)>2*?oWlg#z`~M4}7SxQy829!C-)$atgb&Zq7_M;HrPl z1IN=Dpm8oRCJH`4n-0w31JHFbeCKCX<)_WPIQ)BmB9;$1`-O%^+Pm8A0HfoA`KmKD z@O>#iV&*AEjlrHyU=nI<9e4v)*8Yt=yV?!7)%3=CfA!}eHcww*J~XFA|KGzw3t zQ_K5l`Axk29*{?46L?cXC*&(`8!^vX%L~zDQtPCs1hi>-haG_o04Ts<2vq@9^DtxL zFPn4rU^+epMwvPhc?1entj&L6o9Fn>yxD$Kf34}>kV3Sx3IdVQ;va|*D4+kX6KIeb z{;JlAoHB4N)(nnF2YkKoMMD?Ik(GE9Vxq&83xY;-8Xr`$!)HF8bFg=x;^P1NqeH87Vi3zm&(eDvJ9hiJldxPaS32G7XnLj8YQl=|zKZ4r z2u0q)fa8iL0l+W(1fvMRO!gfK3IWxaZC;yGTrLAG%Np^u%f%`LXi(4?QrgcDP0A&#Uw8R=)|S zXT=#AU>Jl{3))tFrLXm|kXvIvKjOvN<-G_$1wGm(0T#{iN*J6-_JlwePT~@(nM9i( zip_nbbHe#+Jk`kxOv?qR;)5*rqCro&W~89#1e|2EF>n==pC5s)_7=7Wu+qk?)OnVU zvjn_&u8ZEBsL8hBz%?CjUtWH7$v6E8>I0_TY}|nFDzE23X8GtIz=Pbrk4!ApEvLl_ zE!N$C2BZ@h{!R(SY^8L>XQ-O8U!CTCkUyA4+W^5NfRvoeWRuxF3y^W7xJ;uuztX7Tq8D+WI3ICl1=L{)3(JJUC}P16z~~Il<0oghCc^C0XlM;s>v%D`>>t0d zX~DX`-!v`#$E4!Z(+MThOKr*Tr(Bcu5Pg|)M2_Rt_~L3$>gUwc$eD6YT6rr5wBYidHKdZU-PmY< zINQ=+LFHQD^mP4cp+u3&8ucMROqB}W17v~B`$vEI6x1YIDQq8pj8BFx&vuPMW$-^R z+0A2rfL%81#`7@T-x=dn0B1^|CZ0+;jnkn4Q+wO1W~W7MF9ra`w|fmv7a?#&v{um$b{XUi3m%63J#T5Ri&*cXn(po$a@g|z}*l(QPd3hS0rIY@pV`~(@pzTH-`+7o#k zv#OqXd-#QfDEbkJ6laQ%4$q*oqUDK(NnN#5%5Uc-JB`@j794nkuEXR>VdwXLw>j8= zn~;!DSj|-Ro8Rtf11-f2pxN%73rG+7IS(RarcMkQ-#=_rkFCZ%*PAvIi^)B2vx;sN zM=mA`wz6?o>0{kx(#j$EA1ei@)$P2ejEN_5%b4(Ln5Koz4(r$;jk4AP)CE={6?O>E6d`90n291Q{JqXU-7 z#WVNM5HJcQJvd1RS($!dnX_wb2?WQ(@PEQG6Y={=$GrGPC!BCTWoR@PkLL>lt;8Ja zb1T@rWV_QK99a5YlLIbp6>>*UXn7k6i51e$$K!sosk8$Z`is+efXJ|^YQ=u#QJ!+J z$Y4<%Pfy*<>`w*$F6>m~Vx^|$M&=qjo!bK@_aRbrU9b6RzS7tc^b2Zxc_#Wvq)wl_ zqnY6>hGav1ca<;9@qSGTt(paIgWN;#sSsr&MT$F9e(Q8&Dm!Hw89&E+pmjUoj1?2y zE|XGm*#_zOJzJO-VAWP~<@$&$rVj`N-;ggXX#jagPqx`m*%e?U*vPen5f25iDguH< zoql~_=n2Hql>(;nFp<7-|Au{i3WfYO$vUBcm0~+-`_?LAglEFgqo07@AR5f6Ia^p zVf!$l2l+@5=bHg zg#dw-pZK=?q-l+k)Qh~ALDP!g(oM}HKlO`J9<$boc4yckPllU!E#Q&0NpV+>mq$A5 z%;V*orkTy=FQb?-1}mD;5L#%Xd+wvr^m>t^H-nO(mjRiy=}ggop21|ZEpXl9ir91w zm7I%H1XS0aw9rojYsT6g;q*hv?tt0th-P7l>HN$^DZc4Zkwql8mVm+=qxnA{N`k=q z-pPuDr`eL1AK(|Db+awSmwH{`T7$cT0Q0j^k_HfQ*gYFOI%tY@OL%hrgG=*-dF zx~l{T#9p@Ek<0oyaG0@}yLMwk?DPdS<5v8Ty>K&2UFb*rr5vG41Ohjq#eyqkKsP=m z|C>%friwS`px$oK4s6Q?D~0${+2VFmpkh@BZ6+}PNdSxg{V zo)T^R5{(gua298Q@zkc(OG6s`3kS_`rX55p3#7YXDTzX%@tH7ro92gT{VzycD;DJM zV`w-n2S~}#|1SV;Dh*>gmE5DuUGiUCH{gHZ|`>7;JnDTCCNa z{LdE2>@uAbyYv(YlPFA`(*@(8{%%%tzTRjcgXZXEJ&K7zh+g0Cb+85L`ZQaSA+9 zqdqaXtE=l%nM>oph5C;mnzFzR*eO({Vv|X+7$)j4>meXN%pj`g^>&X9s_(ZO>HP_3 z)k5k=?m|`nzpsxQDvYpQi*V4{gM)*+%fBq7WMozZG(U{h;baP|yuAE)E?*bBo`2$> zQ~Db~mvgP6pgge2oU^56dG{J%zgxS-nrhT4nx6`W8v0Bg_(;E)Cn5zxRLJT+UibkmjG!lu9DuC*z)c7BR7zaURyA4jJ~h@^rDRDmTt2(@g;Ta)ja+{nrlxs0f{^$`i!~_G+>ZDh z9db>aM5Hk_ta88B<^)x~FY%qgzoYxhh!2SgFkl5cKNI8!{19a**o?tW|KadQ03#7n z1^>Y^(-`u~C#|MEMMXt-e^_Knoz`kYdD?-hWThWn5V|M@&|%YBCev#D!1c-VXSlGq zUJu9U0>>y9b$8A>XEU2+sRit;{$z4; zz_~a-vDxFJ=nv+b|E(+OY7DTs{=w^=PG<3#@>I(eg(jt+?)nzZE1^ZuJKd{d|AIo8 zNRcr3E|jN3h!MNbo=5*Fu&ck=awebe9Zo2cn14$tAZBo~n%nWTW}H*>BD=CH3HUQ8 zE-VaEtKUOS9xEP$9g!1xb$QvG1ZhL+8DwZj0mB#KRu%O$#7r@CTmu{gdW$ zq$~Yl%P@KALhtZP471abK^q|>ZeT`6%TED+CrUI?#0YJwE__oRbx9mbzuPnLN5`I?+HgKdh;(OEH+1JGf+aXNbQ3k-4|-g2G1T5ZkM$1Q&*$94B) z6RG%*868W^%zV2oA3$Hkj?yY434~Vgwvgh7eR( z@lRhAS|v`!w~{+A=U90PMDdi?aGgYm*QkCwYZ$2kV?3Pn9lXJj>J4QoqJb zRBF7-Tb>i)0gfdleh+Skb8(^!UfSAo20h-Pejm?9E7e+1aB#zgVo@QC>FU0%m2E#j zX17dcEz`lM$=#xv`)uDhMb;b$KXacMkQTQO}5_-S^53f!2QlEHn;T;j@`I$H%S z9Wbr-`UBp$YYx~}Q)}*z{8A5+%O2hU$g&H90&#spsZiLm630aCw5tmvNwDx6>?ogu z8a5&=ULFW^0|9S7yMG#}?k7BPvYM?lFbG_0V)-5>U>r|lTW415@=U_&L6XIryv;Cf~)${0m$1_R{t9Z8L{#FW?u=BsI*4f>xisjP;;(p&7^vy!Hmt#hmyLn@mXprr(Z!Mbj!_|Df>za$k}9n><@=Wf#5*Pi&D+F6|8|ehh}KjpT?y&c-PgYlV$SBD zo(YUM^QOPcGc$5faJp@h3B=mE`@^xuysT6zZMY%=a|rRa2$khS>5i&78DoN*6;@J! zwRki;ND7AjDXKDi0@`-wEetCnNoo%A2Au%@t;pNqmmx#}!=p+yN5^R@*5wZ8qtTLi zn)L5~FQ+?o1pMEhE{Ed@BwO!>a7?h+N#qLRGumz;j+00Gc^IQZV@~DTJ-^G$_}-6K5#mR*CXGwmfz7MDy{4G% zXkTDUooZ4%D6rPdER-FR(j#6YoqwAwOoqde8;Qf^aJd=Q|Axu=!WJTtOpcxKCcOk>~^sqvH38=Hf|(}eAAd}K5Y8|4pTwDxk2tku6JIi6f-I7m&*X z^?bFj-dFOT=#fJVB0dEoIRGSpuN&}YgoDZW8PMjIz%MuN8S$(;9L7>uy45^Sd}Jf! z_+AhNlV`){dOpm%A$43=&{mab$vWgGM>iFMLw`?9z06mV>WkI2j!LrJ9L><{p;LYD z8KhT(9^b&C$2kdIDnKJPc=ftaHt4|79abt_E*4VlklRnz<>^oIDcKJ|80;9EAe;Th z7DdbjcvH zI|j@fnBGM70R~fiaB5+JZh_a4uSY)F_l5Nsg8kRm>1EP3uOt1efT~o?-d)R1Megzn z>^|^C_&Bq^rAF>@=UdYgTJK%6Npv5e9t<9&cWB}C5wNXF zjebZV;vV{ToaL~4eoh_x(-5_Q5HjWD1->XAxZGadV1tu3HyQ7Apa!j-AWw-J0P``5 zE^gFE=p5d_x5(GrWK>BuyGHE#v#kO8@Ojc^ z2F;rXW|<};rJ(_3d+*A%dqsQPZwoH|NNPVTFRmN+O@#JIT?d%o=DIp~+|e(Gn2LUS zwLmjc%069C<*G3_Y0ti&gb!R97IpJORxIBJ6N7dwy7mF1z{|;}yzn_GA2@og9{OL_ zs*u{taeB8KO?UXB&C3o_`a?WYz0Y4#BFoo*^}nhhIG6#nKz!i3V>iRM^tt7#6R7`2 zV+qM+XXf<~w1hks5Ft;VB=Gi;ah}qnTR;W0_(o_@c_Ut06(o_VkLp;tM(hpH$+E`}^_B$)cos?mkv6&jf(I z#A!utw+#WGNKlLHo<`SuU4=5%RNk184QPIjG~%9i%~t|F;I7^LX0ifYk4n* zIKBFwTD-Cv#%tCl(?Ocis0zQ}^DTyDa4br>pH1fSg{>40jGTLU8eWzsH0KLqsS=5& z0#K4m#UNH{bSU)JuO+dud$atg6l)dozD{@Y07G|E3uejKzb}|NF9W1gBy-CgFjX}e z2lxPjuEZpl^tQ1n0l)mx`Te;0zg|tI^8^fVEvC~0ZB}cg#6rAueG0ORBS9|dEv>p? z)0#$m7}fA($_BBRw&$;Q3LW?Mh4<7dJ&j)dy6~8D)VX7(!PZ}!G+UDIJ?e({Bsb>B zU&c#LL={*ZQccu+Tb=+mhHs2;+0xoBd>6vruDXpNxH*FA0cQqA ztt&9`_%&zy-QE5u5cCu@((^l~iW5p4OXoBeVAEI%n%#`~!QLc$#bGa}o$%}4Xwsv( zedNB9Kl-iFOc=$dYARDMgZkpe0WR9V66r7V2Um*yHl3@`my{$WU07YMLXe*Lv;#HCtWEW9UtiKewVclyl~VjieE+NXOXo3dgQnxlH~lxIYa86Zy{pJ_9)hd z=4_9~w`WeHC)ftQR@+)In--qFkVgFH(N|Ri|9FX=TzCarAYY_jE`B3laISBuT84X> z0BN@ZVRUmDNUHWrVoz8sL`H)M67ZDdpnWdizfFKKpNR0lc-ym1saOcn>5nXmw-r1i zQCN)7*FZ96&Y9SyDx@8$3gVvPeSb*RTcjD@_r)K9*!2-kyG>GH&!^xkM9+j}wx`)> z3OyN5E)vv@wz@Ri1>gH+&g~9)Gf-zb((ZUym@F3s%ejYZ=jd@T3U8N52T;)G_bCaU z?Nt@av`!-08#R)>k-?~CMpyhzYgmNwuQmhmZ{`YaAdS2wOcO*UPG-`RjIkxX177HH zl6&OI!{}b#eA;;vdX4FXy=L=6x3(wI)JE|!8Izv{^HT0+=cjDwu9VuH-c8C{S33)F z^z7|DcPr0H%F!BK+}1kgD`0%pwqu&naJ8+!7j0_km*0nUpP;OEGpdqR@z?{6fXQ05 zpLfuqOZIvL%mD=aV7*gQz10qSj_;o$n%B1vDooM01M`}}3d;#6!mDJ%&}gDGwx2dF z$*dabwVBRpzPQm?vL?~*-!UKfAGMgRv{iQ%j%4Yh+_p#%@Hk;=1At$yqtq={7e#Vo zHu)}bb95p}{wxj0Yite7`&&3;ie}~luG)@^f@jfEk()2D_KTlLyj`@tf4!xaC`V9Z zi%u-F382MIpDdZ>OpZ8G<<;NDMKBjaCY`M=VpQMq-X)>k z>1XE{--=8h2UtIK#wQ?+C+X?o3!nF5Pr?7+KO?Axx8SMxvPrJ2w30!OfjWm}M-0XR zx9e1M5n^KijK=D;J%Vl}UEpB%@yZd-eD|JYEP>6`g1`( zcBxzrhd`TR%UiTNAHmQYK%;_$EGK8_z-M#&0U*A=KI)Q__cbeJwd&&&wHZYvsAA$+ zw}`GM{G6LSqsQV1b_ceq*53ZnW?E0w(A0tI3vfoqb$6N!ED74K{VxE*Ks~>`7h9K& z$Lgu{Y>wKA=dW|2O7(KsJmELo;AisrKiISUD8g2+Mc8A$?~k$n`_(|{639h(ytW9#OLM7>?UIU+&RpGPbl)Cz(_o3J!jFImR zWaVCb)x8=bw~xo5OPz6rmY_eowGGC0*@?t|5{gycooAGf6`X+l#!IEJO4YsFKUPc2sdShjO zwCS3{(zQd`#+X7@j0xVuu=CVaMBX@sMMJ#lo9Kn!Z7Pa>uqC8)K|AEDJ&%f-AX2n+C^HXW|S^^f1th>FWK z&W>nKm#SC) z%I|f`Hj5Q2j$n!pV7DDxf-nb@E8c8S%X311V5J8KN5bOpZuN_pNeH)qK|H7GXW3-Ew=I+2#iul;z8?p` zPwP_PhnA)Lq3y)&h)D259ZOt%pPzzXE)T4c=+ij|vPfhOF*{MMTo7*AcS70XwEAPoig2Rupi{dUI9BN&^Wkro&}m@JjG{`a+d04bOH3qX-@>E6po@JloZlS? zzj=+Zj~Mdw2K!vPR)BPC?^P7$`E;i*$pGwK-9H1A{lxERp%D82Z!ewloZ;LyL%K{@iHsX&_k(R+GkJ0NT~$r&nG<5AWYY9958{?t$Z0Q~7J6 zEna;>4Y|>v8~3F<7XNV`596r*)^E|#-yi2Bv{KOwKJvaMx#&I_f@s<(Y0n=avd zPh(ji&3FrzXyR|4Qi+@jP%|9ex)6R5qtVvO9Th89!}XMFPnUh71bKi?66gTF9|A=o#qQeAf>BV z5Gj@%kZVsX4N?r^OYPXyCy^mPph1&BoQ*Aih&G>ok4D7yagMeapEIgP?j(579u7I2 zP=Cqy7+WV}+>)r}R71j*^=LbK58BMwP0AoUz_~qk&!BMe+4L_!H9-)XRRijNMZwRO5%Cgo<(Tdi;BRr7f&GMejdxy_k@wHA1bCAhuEYMIhCq(R zxn4WcAumAuln=o32!mXATdBu%tc}fogW+gw|#0JVBH-CPjn9k(%8G zkdl&^y}w={bYC|t8xV|v{%zG-Z7)9r`nl4o4E|X8UMPmuF)ekg`vUZ$`cpN18L@0P zdN5=81|caaNxPDhem8j2HD>npfmaZ^b~OxLI(OF3viWtJHf<KiBdGf=N1T^)X%MEWoe-btZ z;_rwAvY9d5#vPj7)fO&#(jGpbG%vW6UoOGv9T-|oL+&d{uSB|f@|_pp7zk&NWvj0!w-&dkMC57=MbKy3g&_S(#=cJ{!`F<2i z0`qRR0Ans|mf*g1WaTU!rH^xmEP^WDQm0lN8?XQ?o&h>E7^35RG^eUaXvC0 zb*pHRq^xYi6l=z7xEuCxqR+za&^s7NZmtp}-XWy|Y4USf^(B+oZB)RhpTl)MY>fHWcR!Kgr&s% zxVUW|{8yeuV5d^Jx_tx=$5vJ&qK7p0@e`q-&R?oLaQHYX{X!NkM-{dYYJpn;o%9;C z{*q$`dG#?%`35eVVoCN_H}P%D;iP1rf^YrYwViVJn}jL*H)CRd_jza@F#}aJx*B{S1gKuodh>tzgDv}hr+43*(PZ+40L zhZsRazS{aYnTh3pvit&a-4r+-+^`}tGPylkf^@$88oAJYLnOLW33c6EXgX**A_q)D zLgFjfITC}&LJ9k^QQ6*mWw4kys%FpG52$vl*)+G``?})Lzp;^ASl}z=R~~i<7!9 zDaNR7E!BV1il;`68i=}mTWpM!H*Y@V(FFAKW^2cepGeV<+qZ5Z_CX9j`|LCL`}?QJ zw{-$9$J?dz``AKD=~brXcscl+VdrnZ;kVtp$wjXqobu!q8$oh9FOwU2`xbc3?Vy!g zIVn|Oh>qHSH0^7k_I;NSXDe7i6CnN)m70@)ioR$%v@~{q(FQs1kt+nR>)vJ#D(B*7 z0jSut3kk8k$^7ez^_BC&!J!`2pNQpqfTdHaiDx(Q)?Re!J_df%*JDV#DsaeYkADes zp&a%U>v0t``g}qW*GnYY}L%09(vB+z_OnNN8r1P8<$E9YzpHoc7)Lsqn&7W@AcEm&7G%|sG{2!{V}SszI@5zwi_xHQ@@9t zYG2ZoL|YQE5^NY1f{C#!Y!BV^|Zf9weu!VYn!N2^w6mlovfW{qXzQhbb6GW9+O*w|BwR z;P3H)cP$b*7}{dP-`&KsS*%t|EbUSY4=GkccAJfh)svqE#%>Hu(Lg^>QdBZ7-XYu+u%N*TO0J`S zgC|=VOd|e3yla|ox*AVG^ji^0lw?rP$$Vy$HW`r&a=G@VxurLyB)22Wwo#kJ%g}hZ z6{Datexs#Ch7Ju)7tPSzY(<;m+Ns_6b;~ZCJ#z-}g*sqO$Obg4Qc(B4XK1gK#%x6a zdutJ~h2jpm<1mv^o?-xuX)4&F!GZ>V3n%&;R9V{xk}`-%wHk{+zyeD$DiS(K&=5dU z_q1t4Fm1nD>W(?H77K~j9k*Fe>ZXkgg`8rW?pTe5g^iITzr-&aHqZu)iMVktf;P*G zM}Ar=^V-#L%B9 zdnjGH44G6TQLVZgZA9pZXfm%>tKy0|bLQyu+g5!v{86_jD+RDNe)h0T}Dm}4dP82$R z(F3c;s4Fs_r9Ir};tJx9h9Sa#n|*XLFWkI&6Q6$iDdcek%a<<)|2PgPqu?1eG-T;+ z_*Kt?=Nbz~o+71CET4rOq(vQljzhF@Vv~TS6wfdd=VOM$t%!R1baESnsAG9CYD_OQ z@c=rHosapS{|`g=zOb2P!=f%4DU|RulBCfmVq>jjwvL!>a--1~A9Ch@El#4w1)RD5 z2#xC&5E!4|JSp7Bd@|F-W@N0UlJk26;^4|BXi_iv*=#gyCAJ6BP0L_#bm>VeV(B+p z7=cpaw$<89r<#FST~mEI&`5e=kDfUApgUO$XhT_wy-+`yK=HP zv;c)8?VmuFZ91W{EwD|0YL`lS_|L|J-cu1z<(#NodI0YW6B`?g+oT9HxiTd+&dNy^ z6u6Ex@Ly@u8XCRnx{k%%&?A6;Z@ME&`!=V5)iVj3)mV6VK$F$kvu9DPSTPYWE-i`6 z!Ue}@ux5fM4KACWrZ}5ZNQ2O>STiG1ccJuZ(q?#FXoajog$kp8TaOO~PIjN#_XjQ4 zdOrqvbLYhAGpEU7@UPG?JtUW)Da8C|G_ZwZbbpljU;)DE?Kj7DUSFOiUtNPC|+%J5XtX-|vB#EIKy`*GexetKka zaPpWjV??0xi4!Mq;lc%s9z8lk1q~h->*9-6tN`b7T5-?D!=)IRah|mDS0SuD8HJv8 zrQi&8GxtvgVQ-sfjMAW*s%c`wAbdhDDTBmWuaDRcv@rfchI=z_b zH$xy24mc9r6xh=|qbXuf-)^Ho<;D??V5x_MXdDO0B4@WBJZQgEBB24`ud zDc`S^0I#CKRRq6{4NaolBL*yCi6^ zFp@dIP9_{!(<64-OD`tbntmCs%e&jMD;sYN$?)EPd+&+mS!d6ljj?0LqE)L_+KODx z{BF3~;?|ucN5iJTlXz_xKK*11IxhVlohzlD*3Tn0kf3n^y%+C=XZ|N7R6Qi400nB~ zF9WxVv>#9IJLu)n7Jsiih_Rh3;=<}t==UdC!WK73(U-I)SmLr~40nMVO-NK2g_dKM z;M&)JUGePrV)R-Ae7?J-aJ9LzX&k!$K>gh@4Q@`A(2G3yeAX%=Bp?yDYp|-ml#*H3-r4=-IT%}8w7QZ(=Mo&*qtXjEJSjoN| zK1>Kdzft@K3$2zsgKxV3Z+rU=4i0$q=#kC>4=iBFg$#)XT#n19HyCz(OKw$KGO-ye z>n(un4(b>Osc0hYx5BU{pk?yXxSZfNAF<~@LxCzE(x!^%(Xw9?e5ZC4$IRW=(6fqv z?YMKRT-KcG&!{h7Ro-g!>6 z7&H&BKmG=fo+i>tr3K)WM$TN`Kl!;OE^Ay~UPs=^l8p!9{Oga%r=QmAB9}dXCt8p| z0=Ge1@p_PSMaKelDK_mj##3M}*|5kpCyj%Vp)__X@2~va+VL7|&)Rf(ALY1=rOV5_ z?dPUwpr7|B;T`M?BNyIC2gE$jfp?4$hn9Ch(VQ<(r&JPJxIRaL+?=9-H5Aal7kted zYVx8n&z?OKF*N#RtZDDRR`-8@SKk#DeX}&=hhFnI=W~38%7tITy?7!j7E-;HBuoC{ z7#Ut_w8vXm3bj>~6YD9!g2o>ad61pRp396!+mly0sH}R?`>u6( zIS2)8NdXo#IIfmsS~$Mb+CY3;_AM*o+Vzn5Tp>NHMQ9;Yuuvfh7t&ESIMu(|5cViL zZa=a^`zi^jSorM|IBYV1!`_e2hCf1c;ppvLB&fYZKHQ`{Q_l^!M_P+J2{~{q@-@6l zKSS$k&rrnaUm2N|Q-uNw1uUh&Zdwjl0<)SEsbDIPrs6DkN!#MZiz6&7Osp*D?CdN) zPVB13F&ezW3~$K9R*f=c%4nCsO=TC9;zR*+O$1MpokKTR=O5|Sj^ocBSZBbLsr z?sB=TPVbBvZ$acOOv}B}myZ^JMU(f30n6gWF4|Uq3}rWm_nJ|_I0e{s%9KTe1&!{s zzCxX{*)jTmmzS_3VT0?W0M&C`+PVifdJl*HyZOYr4P54h#|spZxeBJJXF)>vx?X5E zts5@h9+YC=6AP+mnIbG~WaLuiS%xra>?kelNkEJ*2^=h62%cC77?egJeJh3ZLFtkV z!g=--H+SVO?TD1TM`|;`fu1H=`HW9}*jKR^P!;xRJX_~Co|Jl11fEv&L{~6s2A>=Z5A|gZ>F&RQF zmJqhwnYnEl#oujmncQbG6Pw(PFmqXGxeq_vkg_7Axg?iLcmCh+d(K<$Ih|9dI;A*Y zPVf7FKF|00KF{+#?|I+ndwnFQukkeODE3qxkFgyUQ&UQiO6{riJ1XfKvywbMDIdj~ zK~!*=0>^ zFCLZqC`s4aoUi8dI*ria^GGMlM)I?8{4jKX1*Y!$i^LAiKpkJzm1{=z?Z;B)k8Ihc zdfu;Jy+Ylpneb?5h69)42}$Of$ZeGApv-F_^|j}SaTwAt=eH=uPf4LYNW{Fqs=HPw zH8QJ98-kj_fPa??HTl2D$e`?;lm$(j0&V_BA!{M!36~@%CuPxsWg)+X zCm9qLCkPlUa1gv^D~J3%TeOfV=jhgA4E`f1>lp1xB5mv|s}RcHmOpvk`zKGH6z2Nj zhacvcGskGK>l6zSGUm!q_+jyiJ`8Ms0)0 z`qY#UE$Lqb1p@v2`a+Y8+?5R!_sNxwNPBeqwwIJ0n+DR|EyoegPUn z0A;yipHv;_I3RL>Go6X>CLZvbx~y?paduhb6yl=G8v9wZ%NkoXIGdcfYr8mqpEo@> zaU9ZPQO;M|kGgZtTy{KYGp;j2QW)4Nafr1gUuhNo{r6w3(kl(bwDD}^wL{r58Th=L z0pb(W;eYfQjLNHZXUJkpYA!DBk$(hW*08xa%h*;UuzkZcd?4SGC;H4T_zw2MQ8}fd zbGKmTh%UId%LhHYx%4O+*ABsd#&c^>@8V)CiT()drhFh18dAbB*LfK}*t`ZGReJ*e z@!z77r#s>|55~fyKDc^!91QROiB)smuvX~63O*axVBAMC&yDCaTd8kvdEXu3vu-9v z^|2{-frQ;(HG#VaXQGbFLJ}~hVE6GKP)q+Y4lZ}W5Qp^$-FgH59z3sqWE`GNf<}XR z*zNlvDkogV1QIkF%nQKEKC)EXn)FqgaoDmU6)#xOVA+A!zpd+(!SMEa*mNNS|BIFh z8C)-gSDJkt(k7+iJWpXGw^^{T!7&9`S7mdv2Ct{9iw za9ibo@oKh?=!xYBIunV1KJKy~#TO1pblkGzUeYX&kmhTgWW!3LXEb$qK z*430X8c7J6JQ8W+H^N=+ca;*k3!ZC$jjP;IHZlmFv;Ks$a|POzj1tTf44u0XuJ1>| zZ6y7e2s#d3gk|%GK$LlMdteC-it$fH+WosE0;f7<;6+eT!~Xq$`?I~A&sp|XWG8Q0zBhMbknI~qDg?XgGxLOOeYf=sO|5$=g`z2L?5B++%VYT zJ`Ua3fJXoAf&&Q}{Ybz#(X$TXFYbifq+w{-_69y_=Y}sk24eY>5m-0tBfL*bjEtmk z96eMUNhEAk5C)Tu@Q9(=4*mDKr8iZ5d-stGF5uwhFaOda>3>)7E2FGq-gnD0bp;vAH(MZXX5srl{ zXxPldos+X6+A-R9euQctR>kBY-Wc6)AKH)+D)kx3BLm&x=1gn2jH{qa40IocZcPfc z+|>58i;NzB--DvCAr&WV>%NDP9rW;D!fT8qfg_C&uSD}|I2#y0GZ(=*8?*GC<@xQa zvS^6Yq)9gV z%1lng*?rXGD*iH)$So_7K0~qn*a_fr00w)HL?HTM&mgwEtXKyb4Q7itZEb66gPl??gX3ov3G4$ti);Dm1-P1cm5 zr1ZWbLIU8u;W&mZmicL%z556W>8)Y!F&`(|jz_uoi+*1s`AGA1czWpo z)>DghnsSacH2hp(#S#(PAfknWT8+w^m3~eMIcOffa6l zv><%TftBns$QCu4*M1LUKhVSRo3F6#d05A<`=S$2^6N z+@{FsZN;opjK>d-9@dJM4z^_UZBYg*kFt4GmU@EA#MHQo^!3or#Rmvji2pqthmR`A zT&PBD>`Lay5E3+iFSqZ&h!5x{CYZZ_XAi<{+^{`lDs1{xQ6!~&mBYJ=tR)v0;sgH8 zH~bVmy#vuEXg)r&VVy-S_;s9%4XOMRO3L+tW%E%@<(_ocIt~;W2YUDJU1YRX5th2* zNb7lr=Y)g=g}m%6q;OUf4iYa{u3Qec9%*~sxsC%Rfddu|nUM(3PP)qZVGkcMMgSPCgr49pyJ3@6)8;k$W9`Rm{3(9DMSOMC?x!l+*7#= zLieo356dT^kAt^R-*M<%ESTPZP$PG7MS?|tb?eV_)X7kMV4c&e!nlbercmwK+X)!q z>5H*vU2wMJ=U6$U8Sv~199<@3?5f=u*j%=5EBevC*&fm}1%Ds8bwegNOzx_OGq+#i zr_+2ly(b*?%f5$+UCLs_X7altVC5mdL*Hu4hBh^%oU>UOWMw%m8LIk!E#IO$-O>y3 z>!oP4t$l`EsO%Bcwgyt}vD0Hu^lDQnJ9wsi3-q%GZR!uZhor_YV ztd6hDQHeGP65?<&(gjnWfxd{Jfixmy&a^WA%k_cv`n6^cL?Trv$evT7$Ow&Z-n=RJ zc(WS@0}F|q%Cv6Xx`JzehEVvH{!zt8Rb?e{`fp;K+^2HCDJdz!F5;Y$wN9Nnf?&aJ zJ$xUr0K#ri}L*(2}t% zKLfcnUzjiaSs(*FU3A6^btr$Dyakxp*hw+?}r>t`eR^oW+%wHBmnCKEl%* zVD|Pq@XbuZog3$Wu%gdMjIV8rV`E!UyP^Yed}0sE*J8Q!NIE2Pp|XLcN<&j6wCGC7 ze`o{H2JO4Uo@9y$+YivKvkggA=5VE^)*tpk`z9(IOS^e1&NDJ)0tO2e{EzRBPdBCu z*>J@P(gqP&cY=g!TCvJR4X%;lzskt@&K290=A+EiP{0{~SeD}-cy?ocaO}PCLZOW7 zcbtAE_!x_rT*hrxLfHoBGrPSx1#Y zY@=MR{@N7n-N=lvb}-flU&E8Ma`$iIQsAo?UST=)aWuf-Dn6|5RO7!gcB0kWTW4Z04Ynzfkn?S9-L z1x)Oe%8^S7Qw?6VY7^2uB;%!@d|jlxj#dvWzJq6EGvHB7#Z z6Cq-MSte5XG%Zb5ke((8VMt@&#diZpcMah~w*q_eXOde~8kf+ zxqz=`Xi62L0XD5lF;^^i^s#H$}laT zE!U6&6x>!FwEXxp`i=TvA^q}wcH2YnVyx4D33EwHF}Ke&R12C8+e$BR(AQP4eC+Po zfJpJayxdGR6Ff-$q)Px4gF)+E!r?~306(3U)=cbB>+M2H_+NH59F>D*^I!sa+ zy63`Qv3N{-iF=Mhb)FZ0|1b`rtrugWoosQPXMOUU5Mb%)?y#}JvuqcGHG00wvCU`|>d zjF^CaR%@|*q7mD*LgsTh;1Ai$Ht%D1j;Z&R&Y2 zNHFPfbS~9dVZ?}@h`268)6-)ug5slruM9YcuL{WRfu#by#1<`EwhWD%SPSE0EwojW zrV3-NOB(5&J9ko+E@xpusZgoA&~bn`zybuPS=9t8RjNcTDsd%N*x)&T^y$+_lc^L7 z&Y?qxRQ4mr$1v|xQ&Z`AEA#E;9kWvn`$gKIJ4=?z7D zoZmZ(Q62gs@WW_$HZm*Fbo5CPSJL##t!kzq_?Cf?HlGC!J$-%Dr1y_1U_pa5zO8Dj zn1x|;{6HQD>cJFU#;(MF9nU35qJ1{>%uH#aFT*ZdwHk1C0to?jdnwD?9L!0CDHe)XC~`Is49zA?qB1M z`&U$#Lh)@zFcb$Sr&y8>dbOPqy2KR@|t`)oiEEV4V^J4qi$Z@j_}zrPZy-lKK!=#R>vS5w;LdNtkLynbe3 zgW#2VJ-iH|l>QY~*SY!Zb?w?!n3^ga78p9zO2X-TW(s?4m{M>kf0Tg*4Sr~JdOt}J zHnN02WkgiRw4>2~m?rBvTSzS57?ajVV=TRJ*(Rk&PXvB$$i`*@kDbx*kYAT?HULMX zT#%HQ{eYRx^tjXd0}vfOfG=dU4VqznbTrqhqy?D3Vay6df3{fRfu)Kk0+Ay4Q`o-F zojZqnG5683RcnROvD*vh@MmBFq~`l|uxZmKczJm#;A#7RBIbxMY=?&9c=Q&ul)po> zG;mEKF>dJpusCRpl1NziQK;gha@oUchp~S3N(3B>kacM9fmL69fsfnO&|m;bI6QwU z?slK6_01)f$H_U(FCW=~y+If7#JDoL4;%}(_O&$_qvj~wr?g+*Eu8NeDFg=x!_Uu8 zxM#X|@19kE#dzZG;#q}~6DeIuaj~7g>Hd``s?2Mym&V6%Oce_j{5uunV_29|6(3X5 z=B7MXzSib^Rnb>pmWa)+b&)nN5@T8_DxK7~k=3ZM=&7u?E(Z(Re2)JaHEIn< zMv^Z;Vov=457K~#QIXU10IZqj0`rtG%p6U72z54pgqP1L9Etu7FV=a%eaRkr*}B0k z{xF(x>;l1q^PAz`*Gp(W*8ezs-CE+`Z8Nd#ejU7j&<95c96=}r%NGQ4} z7Lvk$2`9i{(0nZ1hs@PGXB(yd6?!U~3*|8=U#si2^Vi#OuF3**7(x4JOwY!evhFw* zj_amid21l>T86{FuyUq3GW28*rQsNpO4u&Hc3Q6Y8m{0{V3<=eo```pwY7GOK_XQ0BiI}4Ujj9 zvW76NpaEXqlw=sxr>Q3WYD%vd@xK55do*m^SfNKNtH$vDdKyNL`<&wIWWNy0>eX@d z*f9(rKD-F68_#gke}yoXU1vxD>RD4b*Uv~s8kyAJd#?;q<5@jW{1E%cDs=pe#%4c% z0qeFcL3O?V@cXjynC!j{H-9>dX0BYfStiXy5OuUN~@`#y+pjP8}iix*Supba=4h&PDp*|Vom&3L+)4Utp% zKQiw)?u9K$%5H07d<+Y89E5-G-aT-Cz`pXve);e9&9x}b`KHCwegJQ7s=4$`PB~!# znB#k&R9v(h^Tid|OqPyFYtqO(I00J{G#37P5$<(gU}JEK*O|uyV$d2 zJ;tuyhiyHY=Q1|!RaKL?X02aM5vxG!E0n?=v1M6$c-!HklC7%QwI z%`oodYm5^IV%!G%c=7iRL1tEfxH#$8xE%f(^XauYw{IEP)+&QK6@ht&UJ2zgtZZ@n zZMAHW0kd#W#q1SaTfQJ`MIv5*QOYlRKa$psrGD9m&xJCoV;siiHaaLi4*d1kUwHQX z1(}BBCIorcUAs8oz^{kU-oBl}VCvMZk1boaD3odQA|oagQ%`?`^QXSWdf&rx!>e)+ zS`-qMNvplSgCAMYu$qdqJEy^^qb+RPIbqt)vzTf{ZhZ?6LS_TXCXktbs#+*AH&A#2 zXE)H++0%2Fz=B4=KiJ~?HGH=m$2_7v{bZE3dQeG6ss-a1phb%oVbrKmShZ@EaAd(F zl45^Ekm8GFx}#Q0pOEbJ{^Hu*{S)&;V?<~N#?md;z=Ha)n zL_CYR47deiO#6B;w`>W2?<3Q(Xa8lvMT)=qz-zwfY+Va?Lyy99mls-En8Bi@8-AVI z3D3!;;92B(vS`%7-E%?MaqOC~)rjA3*D08nT6+e<*P}CPS*Xt*r+&P;nsZ$8$3d?~#v>!>Gdi4~@7?Fjh zJh^22^wSo6Iduw7oj#LQU$t5_!MZVN(j>uUBdbD7CpQiUz=0O0R?ST?BCIJ+Kk!5^ z%fc_tfByMrAzPS#s$p`9R%Q1eWxUj=zYsu$-b*~QQWeT@YEU4bH?E&3hZK5fR4AK? zh~S?wd(=E3dkN433&|D1qhlRql1P2{7yK7Z$BH1COID8wOEGuS0MsB^Dm7|9K6Ts% zkD~$j*ovKmHHW7W=V-H}q1ZLdMv&$+^r~Ruof~l1tED-AkwRiJPuH$p3u|j@fs%)Z z2W)L^!R|gfC_D!^Mx%D^+8Pn!_?X9!AD8I(n7k(PuFY39Khh|@Vte#=aS=9>%XHQys+|h@fXe?u-enVP@!r>T-{;q^Du1W|A#57|UZOIqMBNwSXmU63NMe z+WW6Y_qx@8kp4gFvT=2Ritf+5#{uO{T;DwoXm`en0p4V>p#QQ!4H7v1dX0~+&>})8 zqjE`|FbY!AbL!i-5%OH&g@l9%^A=+_a$^Du6FPw+Hx9j-x+_<%pp~7X^`gDKJsv!G zi24oclN*L1s*q;%G5LQpu#1L~kuk!;!qB|Aw$18)G5FQ{G^#JYjtgguU`*>&|D*q+ z*Jp~s>ILCcmo8nv0*5N#I=1lS1~J!8Qgsh}(3D={N>Hc!Sp3jkR(L1a7d=M>pvTm8 z__f#jh&r$ulRdiN@wN+?+)-*hO2RLbT(P2pH-7!Y8T$9npr^+)94p@l(PM4N;+ICk z$_2Q8DfOkvrEHTWV9T@*v2bOG(4^~>0Q|IcxF*fDg2OI5qM#uXRK6C=i~3l&I2*;$ zC5LZ=&jCv;{aWgWoPqEYyRhr{MZ~@|fql3B806dr#$watSRDK*5QqM{1>?%ra2_@c z-I|cCyb!>PZ)E{FxA+*wR}1+XAIact*j@93V~`OyN*q7~H%n!@L@qS2xeZi7Cg>tyT*5F7knO?@+Q($XsAK z9+JVTy&Hypy#>QgOoV0P-&i;AFj^m{lqi+!0jJNS;f`srHp;*O^0U7?-i0D035wZ& zr|fCcdkFd0RP&e(3Ml884R*iMfp$5-Zs{ENRkdnW?Gk=RsfnIFEX1*8UwRZ-A}i-B z8IEwq_#|jlGLip~MdY{SD7aDa#C4yN#{=m-CVoHCGEL4o`1{qXoDXPwa-F&t6N9Q` z4!wHq8rY>u3gsxP*zMc5rA1mfPYerx#xhvL^lk`t{&E<}HV!!bRS+I%fjVp2`J)Wd za#eg3%hKd8+%(F8EtcgxCgSu4vVVAdkMAe-LbJxr;NrC$-?{=TRs|!Ge@nsu4WSi#Rt^i)wTlgoSbaaEaW1mi`G1 zz>}3DP-of^xu#RZEZk9f{so~Xr6FxEEicS@OvozO_Z^Rb=Z^S(>t5{L^*uhvHj1<9 zh;Kt;a^Ev1u0^yqn8^;$PlUdQj$ps`wa=i?On@65?Zy9zB}XT#S#A(#Wbr z{>B%+?F%$@8i9k!HDq&jYJuUKu4a?d(wTIud|sIOYH3J$l97&CiYzVX^8$lDD=X%q zc`Zv}ubNs7JK#*u04#Q?2fcc(IO5k1?zXkaZLT3EQ7p$#pOUsl&jgl#D3{e`J=eML zvnCpr7O-gOh&@6Lg_{fQ0f$;tZefWL^v|W48BEM9!Mj)$7INc(a^1k8Iq$s-cLU7;}xlM6~R+-R2=dU=V zfUe1)!RN9gU(4%+RJpQ$`pm@l(7fKuxAH#E)3Tw7MML~v*o@EFQJy_}M(NyS*(OXW zW0bkMx!_aG0gO5*UJe)-7$B4HdI?k`H!02%6!J%?P|B8!Z|2RxZrXE01b!e%1A)cz z!X7Vf_aYan%UC(Qk(?AgRlv`bghJJ{$ci?cbsV-jSk1}IJDj?*yg z)d?#W9m1F{W02E-R;4t{OlJ0P)K2P_W?gY%>|Syb|S!oNWg#Q2!eqep|?)p$P~ zj*n?T-+RM`4FxnQzSxeB8TlIDV;oq#9vHe67yLcQazk2w@MIGV7_kpahTAB)7fO36 z{JC`eg_&>RNAl(4&(X3qVO0VMd7oWY7ryagrE2Jxh4{$6?S) zO2k6xRw=Pn7G$@l;9hx!rH4PMEs7WZiZ#wkd#kSJOb+%W;P;chUKwy34k}lM%tzO- zk)E-OwjGmyRay1GoM}@r%(02&8LiwZ_v`23hcS1`=Lm{$#ldSU(7bSu>)bng!?oo} zv3U3HU7S9B8jTt?0{o72CdC3DU9lF+%8iWJX` zT*^W67%KQoSg^Q%|Gp5Q$Tup#07dgZYu4FB$2T*7XI9~0MixMHP&^#qJp4w6l;K1I z&q)~ExM_1%38&Hg)^B-MN=>dvq+ru}^~mh5O`sHwKd%EOM^M^HafeaV!l0Sf=yCWu zLdhpZe0{>AU;*Ny6@zzsXArM7nMO^U4+w1&emryyZ9Sy!W0^R+{c9Wxnu>2$7{Y?Q z87@43ej*{6iRc^rqU)e!RY*egon-X+zx5d7n~CR-{>8pUPWarJw0e=gXpk+fNN8zx zTA?n-Nkl0i%bY0;i`?Bsq0={fkrMScePa}7v*@!dK|?mAn)q0VvoQn5@TWu{fM<7# zk2$;%E=^QDf2yF{k|k(c-Ut`RPeveHq@=)qU$=3kEZ&+*Jfxn+hEZi#ICqkZcxHAO zJB3n{?z@OY5;mlcbyAY~Ip_Phpz$&J8ej5V93~^iytN<6UBryxNP84esw4cDI2$#z zF&PaeUYPl6KptkK$}gBYLlf#nj6-`em}&6lHZoH4Wog*HC};5~nNrMVJ?wM##Da!@ zdk3I(9evE$kxrZal@U_p=Djg~fSP<8s z6#TJ*1dTdV@%=PAR4v4FI>&fRU;!&6Yt*PAtkce%IV0?)#A^Z_XwCs?+)H}63S|Ma zQ}82FqA4%0SUwfj^LDzZjgWIp== z)+g73`1p8SzkXf7iT$B%GVFR;*^e?q;Xlm6E`l;F#Tc_G%$V_KUP5d5T z^l3wW(+N1U?OROV2Dq;3gQ}z>w;$;WeC>((b+=+aEaga7ds%~a1-)+_$<>&=}mJ)RslP3hB&)Vg1X`pHWtbX>j=>^-B_QZAY_QyXy zy@ANzFlPEy*vwm5q}pfch}iAr=FOW5aT^@x)0k2$7gq|_``1s>kb0n_syG|RF<9>? z8*x&4Dn-X!z$elPNY9OHWBAu!3nk%(ClN@-l5D7muCqyc7~qJh)dNU>Ac@3~Ilz?N zeZVrun}M*(THEQNCRwm>Jexvc&k7SCb2lI3%Xl1%5E|^KRY>xeL%AyT=_~~Q z#3Z7PuyL1IQ*_6|%s1~*nZY9{E^jm)Mv-xV6}sx+HN6AsR?UP*J2M=(L^+D(Vy~(; zNs$*w&;Y(Yyb1&4i-1;tZJXkGkUhTNeHjxwI%O-c)ODz$JoPzQuU-1U$+3Zo+JY6O zP<9a`qmn1N@LG-6Z*}X|71C_8pdqy~7HqcfZmXZ${+qAKGymCoCtWw^i$Ezs7KDw$ z+*mQ>_s?!pc6N3`zIWw$Gb8!M!9oX{>n>fo1a8CTI<=4yh3#K|Z=$6E!J$v!;Mpn* zH9h_^E}XTH`?RIw?1iUSYK8y+KmbWZK~%HoOF=c##cLMwTXa&G?}+!z7(QYID$w_& z$s+J(_zisa>8HXEK-(^c`f+P@KKv0m1S1H`xb zbkmrGrij`6;b{r86PmL1Xu^aEkh=D4*suZok-GLs+erI=RCK*_mmOWWy`7|On`x(Q z+eX^9oi?j&q&scfwvDuH+fG~We$E+Z{Qi2!{s2|AYpr$HTK6^QRHq*tIpfu}a|9W` z;}{qni2IJ%eQWJ_kyG#~nzv=n0>$uDz`vyibs*>Rzbq20s?~nAHPDi2nRIR6l`+Nr zCY=Qo82`ySTKSEPt*@H?7RA8F=TEhgW7tSL0^`Y6A()3oNI7C-o)#shjDO-@c$C(l z&Y>^2iis|gJ-WAE zc_q6rCE0il`SnwE+Wx{Bn@mka^F>aS@Ci~TpWtSrAclF&L>j#7r1={GM^%vVf_ueh zA5tQ}i^$uQNbUY|vc|C^G=Ila%QQhC$&%6BC)du-%7zBO>dd_#qjjCqiL;r7h%BCj z8o9AGG5qh!wDEzkp2;nZvSPn0T`4!6Y0Rn1hR>J{-~U5D&p7j(OX^4;|7esq;b8=B zGtVJA=^>X#eae5m3-7*CT0$->DO%v;NhBql8sP?H))|z;KM6I7CvyN1)!$-Mw%3$M zqpr5HKavfEg4a{E${HQK=_9i>VBk_k%@dbrwk|%VOp?4WW`KHMa4ba%!}0drh3Co$ zN~Lwd2D)M7xeVmwI9E$mV2IEPpz7a^f>L9@gn3yI$1ss|>bqdWUvzx@479NQlUdc| zgGfM!#5m?peBle!V?s2>+FtytDM><2=9Srrl_ zg_;=neAD&d%Uve>g1q z?bC&FkVHT{DM!g+G_84@X41@4khcRXMl92&$y#1#z}p+qcnHeKric6q$(}SpZ-X6? zE(GA*jmDl+wrZTqhf0R5cN0dEt zLC$Kd=eLZctLkT}u$Ex8T}(j5k1G7)i36CBh3qWvJjRLkh1k4j$1wi9Rf$#zHV$^z z;ld0u{#SdO5|EhQp6k(Cblt*>o4htYG|&|thtr5h6rZyr{cY%q@09ps)($>nH$22u zeP;!KnXeG7h=`PYcCz0>^8?1$6&JSHmcik2k<29IWrtKjTBDX38Lr}=qt&}0{5x>X zkEnAGldXOW3~l$JP{Z14!cK*2^Yg)#vy>T z>YBrG#JqqWind!J4iqSu4W-7B^mL&#x+U~eDWZ|J#aH%HSec?fFP@9=-Hk~6#WUsO zp7m|(^F7;4RE9BWzD+5|@H7=x7!Yr?8Vv{u!hPnif7Vn&j+>W}kA_yDwva4?^`KrG zY-|BVysOluXF~IN{_~5CMIw=uJjieH;#^`O+`}TDx7dvPtKTCYQLhvPpRpm7_BTi6 zXAsrm{v-8GFM*ctA8j!xEr^lcp-myqNZQsA>j3ZOz6-^ z_lD?>jlZ7Sr2H!(|KwyrBDPnow2q-Fn0AQq?3I;?M7k95I5%D+%d-%*D34}bf*-W6fMKvN}4CrepJr1_2G&i`8OjHnSVbw zVA7{H<5=1LMl_?sLGXkfF959GbcpmR;8;-B^Y-^&wbGQ!49*abm&?Aw)2$iag=D61 z&3|>F*2p=1&1>WZ!>P?Bv-mA@Ag|xj&?rn$9&_FG1cy0Z6*-mKimllyQQUPLt{Q#Ol}C3S-H&&oxKCwa`jIQCyb*f%e|K{}~`YFn8$5<~P%)b0(` z?H(cEJ^h9yF9EC(4?bSLd*MgMKfdjgxj+#>N%KM7qO<=>|Ngq_gfH&vzgBWPXU@G8 zGY9MM+mVSk=8b!iF{16h$oL&k4;5PZ%V zqK@nbT$5(s0+PZy!yVZxiYaMihLknEW$QGmKT7PWB7xq&ebd%oy78cX?_UNWA{<0Q zrsr}x7^9?Jqs>?FErwKyB=ozp>Impr9CBZM>Dpm!(fTI0Ydr6oIQ%rb*XO_%gx>>B zSIxAJsT-gWM39jdKQLgx0&%3~guA{QC_JG)!KmEF4hQ7h^2%Cwxcqvkw<5e%*s2m)vHziv+}(~W9nB{7Ip6EVgNZdXRqu_+&aTqNsK44wl{M#wE?mZG!b zfk=eB$m_I)7lkdSqlKJlndv$G=JixfGMMIns0UV50=`$%2OWVM%(^q?`U)-zZ9OPjqo)9~b^Z=Q%2fM7_G`Xp-1@%@VS7>IRFPUre$E}T`rLbzd&!HeuB~zgBt-|M9+)2PwJ7G75KoSX9&%CD;XOk$~)2$8aU<& z*Skq@$rqBF4_1U+s!1QI__!>pfirA$76rrkV8f0%XXbJ7@~6)EMX{oJ1Bs)(EDZMj zYhaO0Up!huV>J-}7lKgs#-AA}vf5l%;ffgw+%P`}e%tQ~i$Sjh;h&mB@>&Tj74Wfi zMT{gdj>rpH3^~+yXyxfS!r4^-Wj67GQA=iXoU`v_080EN2Ywei2SFj?|HbuC>SX;D zS&z&zw$b7!64vesvWyMh5}-li6c0obSZ{YzsPU~?%K|7?rs^nEmjBdI?0d#J#r@Q% zn|<&cGHY!S$C>NXiO_9vV&WH9Id$-cw+?uJdkcEPEh{WV)M}dWmF`RzVWH#AB8Y0T0pf#Gh;8F1Uq$C3}h%289WVlc>WfN{qZ#T z=rnH_9C&w>Qr8Sc;Z3V-^58)Jm6${_Db{^@NUk@s=m^I?=YCrTOM@x>>bt`tm#WNwsRo<4=uM*=`hr>(=42?{S9Ks#Uu+uhrFrN5RVWM1ik1@g|39=m?Gau zeLt;Ll1^C4ZwYvJCQxLkTW$k8u)h-%=U{tz)$6j^%aXAVceFL!5l$4_l*Y)GtS)}5*$?e9KZt1O zIz!}z(>?N}k@B8?U&cA3dD6Vg;l#b)`3Vg{}QS`hD! zKESZEo=o%i^m8HB#nKe-$5rp)zv^s2rea^6ZwpzOPAtg&pcqws&q z9$xViPB@mWjw4fWtm@ztQT_+7)$p&opGKun5alYje@sY5Gvl2*e#*KW{LGkjt(xHa zF~`i|5gn@ybRhFT?~JW|WKAJ4z($n6>7pmZRAt71J?{wS(&DWvf!wujo^Fhp#X?~i zcw8_M|NDn}=>=ySQlD`u5Y>mj{tt#o0VVy*TM2YqAW2)Q$cl3OQPC+6?Ky}PNk~d< z#1C}xFFoF#1~=mEIQm!WK*E4~JNw@k9XBEX0@n8gQ5aKf)2S8gx153*v z;877j9J#PF-osa1BIt0Vv{!v1Bahps;}#r=)e&{tUFnuy^2%s`)RL@b>072G|MDJ} zxrM{pGhU_(I`aUNF~usIW#mxZG8Z~3k4P%36Yr!Tp||5j&5py1jpG`RQZYOkb;buk z1m%Cv&@kdJ42Q>yjY+8S*C3f15%&Q9#Iga8D$w8G9~pj<0mU_Q_J3{|Jp+sgcysK< z!^$b-zTj*Zy}ioB>VDHUpW`)0+uh<}2zYMRt4J+@Wo(|E4T1=F`vKaF9?9I`B@E>J z6C`LU|z?YlXqvq%N1)lXR}9Ir*!wgRU4^)JXatWN%|j4?lv&dUB@N6ZN= z0(0qqE}p=Rxc|c@C?o{-4=Skbnf{%D(fOO09scYBC^Gnk3*;9R0FqMYf)X6I-;tLi zMt*2&?oB3*x3qBbdOs=tl`f{L z6Pfz`qGf(uc;Ce6s@l_9WQ4I})hVU!GZD(ijir`jb54ptaU&jsF2^aTSyc~)rpZ(K znt)FzX-{eE%kZFd$B4&e!qAnlr#{9( zYXZltZ^6McU-In8MTfA5Q#_MJzogn}II4&=JiAx;)TtpS@`J26$pO1Ba`q0Q9w$b> zl%}$S=Nl{y7Ya>ZS z%ZZ$;AwTs+W@e!Q{mK4`((}WyH_WI>bymIoG zg08DqotOw(IizvDI135MH&BD0Qdn3x2r1hMXXzy8pM&6h0iQc^AofcTq)MRr*2VN{ z^V2>+f|=#1=!u<&SK9N{HFMX8$i2U7-R}%1_QnM?F-CR;N!Z)9wnMuQ;O^qtI1}@k za-xg9F(>+d>gzvEW`q;PtW$KrXK0zhRfmc=#?`SAB9%m=AhI~5V;)m>S;7&)26khL zOkGNaADg%PyGl(7zTG>NY*q@JHjAnKJ+TAsP+8Y`zC=Quj2R~o7yMPl{vAh-s~XvJ zcn=6Nc{sv;tn=Vu(PQ_ltK^EsL>6-d)PAn!;~%tr`=5DF|KGySdJ^;AM0#TA_W9xS z-C$;N5^-{JvM+RsOE2&YJJiudk(-m)YBowT-RxpI9g-lpxB_F0*j6iPaU81-aC3#E zx4oOF3wknp#xmc2Gh^^*rFlU9HF`mMyu*oPDC61NYmL+i?xLv0+0(rR3a+qb)ft+5 z-()jNL@Z6=`Ym3ry!xk7#a}scv8J}xA7mj=qMOMv=o4~Bmm4xLb$K##Pr7`) z;kJyA|DC3RDC$6YsCT6*#DT!YgzJsuqUI0|D*7(pTzSeP>Glm}7jz1iZ*`ge?ZD>w zA*qJq;^_pr!PiorM^r%MxGuLQs}1h{Z}-F7PbBwF0jwD$ZW3MxR(x~(UN8YTZ!SxS zZ=VrD>KS5mYmUb&H0Ulsb)}$wwN(rD`Hh$F2=R+Sgx|ZN`i9rP#a68ot$q+e+s$DrHJiG>>|@mpLHpV5JsHf?NRuMC14EN(ntlr}6mr!%Yy33#lvt4T)q=O3opyVI!LfU(2<`DkH#7sLl|LWkR zX{|M;skAA;vfWq&y^XlvVrTKk$~hENY;V4|8Dl(TcLwX(MF)EfembG{*7Ob8AxJVk zKtsJJZ;z=$1p(YN$s-z!KIk^(($9ZYr8u7!GzwyLk(!6a)aDeK}K z5rTUsl(3Fm0k^A79}&LfOFNLIxNaMzVpKksFXs838lY$p331ifiwUpVn?vgy_B_Y+ z``>J#Oh95Fn2f5B%`vVsK_g@hQRISv517n56la$eY8QS70g6D#Hccq5B=8~tPE;B- z0F#-Ea6|m-2>PG)X+R{0gmrLMnFmHw1>=^I|4R|V4$@~6M$zY9s4?n82IP?ZE`%FC zJw1#_F;E)EiR_ML38T_IOth3tE5_4@|1wDX6#ayKRP`Pr{;#gx`ILCNlydR{reGEP zrDFIBW%H>)-eXpB!LKkxDMpOzlXkUKDdp3jrfKfX`lBs-x9bm`9=?v?t1OTsN6EfofoNf#()?x=G}$05iqH0FxufE$Zxxnkgh4OaevLM%8vPPEnVRbw^hvWEcKKl_(p?1R2>7}O2!79Ft6*t`FtQb&- zQnthu?TaVB)7vm9`S$vyqmO&1MOE%??SvK6zC9?1$u*3p8?wpA|GH)788?Rgs30bZ zSSP_pYzjtm9E&pbcmvf!XX48rFuUBST!_s-Pud4L##$kO zRK$Ow(*KUSUAv*z)E+$#3}bxDB8DiGT|G5OnW*J z0>@Z@x!_Oag~9F&uBNAm=(c3AO;N5@ct6E?`Nk8rE=Y7gc(V|s*4|N7W0q&;2pw1 z-t3KR;OP0fN6a z-c+Er(K-MNires=;j=>u46N}|1ONkaB*8i=BWbaZ_ zXgbC1jo-{IUq2$2C;neL$#yfI1EIO{mxyP3R1A#Z|Io*O$1~U0*F8FR2{O8RV5O75F%|oYqUWVUAekcJR?=|cFUv@qVjW1?cRjT3P zuS`NjlJ^`gvY5u{mUU@4rUP}aEPD}h`AY^r24d-Y6$B-Fy#=}IhW;GFasjwB&{FcXR>TSNv$p9qWx2 zrX+%db{!?#(|n-2W@rp2x->&zQqS7qJ$xEjshf5nLw|B-J%&p~Vuhz^%75=n=kO46iQVs${#Tr54HTx!Qcqnv zp4kggk8{w@X(0N1nR)n}66CRXi(M6+qwlQmaXnigt0pLaR!`A4As*ba&tUdXp%R(u zPMaq#g=>wd)c}J-lPg926U4uI%cx)|%QM4(`DGc62M=Qn?X~I7<0ypTL9aO3J173( zIszWX;nY*xij%BYe4a_u^a|w>UV*5~{y-F|Z*&u%e}lfCalajsPM1fCJBP(zf!aS9 zH$;=1jjq6jmeBNe6)1wz+V#)8&<ilw1(9dp4{e z90$oE(x({FJs)gv$=PBJ*0w$N2zOu|pvHFrK!aw9llbH3{G@iGn26}%L6R9i`5TqZX>sj%{3_ZrwQ7GKY9q)fx>`00A3GMC+L>puLpkZ)6cSk0m z7U*-!T(9kVWj*I!M?3i0S5vV?HePcY6_{^3f{z<`Q7?d|V`@f+7mYbFYMl4(TH$dR zzA(oxO1FYbKfJuz_{~%Ze4%5jOvzb~kQqM--?jR*yJ_r9dmq!9SAd(Wx z&1l};++d9>s)m2;v{Gt0IpDUjLEbG(05L4JdlSf}t#19Y zD+}!4gaHTykc@$~5KW6VG*B!t z`F~s6{UP{8QOE!7I?VRXw8{86f4m;AsnKUtSB}9WHvEP}ya7 zp7yx^*)Bq;VKCohxU!nh46G|=e?)APJgy|@KDu7Su%(~viG(7yy3#cHzQ!`krSw<~_{E({sfyf{l5^Yxz zEXdvd3)X^%G#)I#SW1}AjwG%=*k5-{2%UXdwpngXN;vd{ch(kFAX^%+vMd;-!r z1V#k#;`eTZ87sgIk3!7dQBg^z!=gN+CRNM!v$Lwi!uP(wA*Ws9Po{Q@x|N}Fpddi0 zWZbclB5kT53>S*b@k0$*!2JIlg8N$21T2f!s<57{ z>(;MB{Qeu{6C41)rf_+8@V@hU6F>F@PF!g~?VBY&t-(MqXsMJ~RK}hjJX@l0CJbyP zsIWvyLD;xI@UL25>|!}hGkJ`Q6E_w85qMnVnokzMTrJ&)t!gzvC1;nE@g1iiD=u|a z0}>`}buKTXTk`cFU%Mq!@&{S_Jr=+IcMRAwi%yfgi2~^UBA+KZ|TT(TLpsc zvv05aHKx^GU#X*!4%vjB3H-^K$WS2x+<(p9osX0W7<;?e&L@@^CwWcWcShEbQQ_pj zALclzegMBWqxL7naV>8r3i!t2Di})|BdXBQdN`qd$ z@2AHT6DX(lGPJNRhRJb3?;o&545zQBa}MR$@qEE)bI15p;Gs0@pY&{7=J)xCw1>Rv z$waXl=bQ{@GJx-2c%k@25F1nsi`A!-hS_r3`%D^EwSaM99j-OAE`^bh+^X!uV|`Mr z=fKFys)FMchb6}T=%j60vY7$c#$wf+G@nVUg4oD8yk4lE1_|}4eq+1eL{2L^9dHjK zUC$6nqu9}+!l3he=zcPeRZ@IIrTd~P)SFCMR&p{bjR$2%j_V#J@%(xAPpBl6iZ^>wMxp zQ@Zx<{r-bK1h+l+53vPfChqZSJxz8;`fm?7o=y(srj*QOhkY%7kKfo{SwaqPt_g@&cPR0{_tn~=tT6-4tIw2B1~Rtp~UKSdS0nLSaS@{%iv z?wzPs*iH%(qL)Ir7}=!qH73py5dQR9FMV#uB7uDLr8EGNPr& zB@1~0t4ZJ6{SmZ-UEb=}=+W^Xs_omw;SbPRb3}8#yaC#uGap!=8-3Mdl!mwRv&al* znMV|SsW|(qq=L*@!vcMUom+kBviMWGgg-AG*$f0-QBb8Pb-Lm7xKFn?_67S16PQtW zZf33zI9=W`3FF{4E4yP2(&q4~?IR-IQ1g2LLCmn&4_}yAJ+nODVj<^F!nx$ni1vic zi|#X!rS>yRR5ukI_`WvWnLz)o{-^j`qy%TTG1KAnJLiK4O-)C<=NU9bi)>GI0m>B8 zyxo!LvD0?v3-l#_%-{mrhXWDOH_k;gR=ek1RYe`wV0bth&Ml;01z|UrQY?!mgo$tV9GXn0Tp2=&_ zewi<+t}=RA;(?5q=^T6GYtQB1tsR~;;~iw#OhUt z`=f7MeQj@c22|7VamjM5FWeJo{=lwcf{*;i{c}c**}}qBth2H*p=7nT&Qe)J|GA}L zoKHH8ds(3F)Ped8p;k7kS&1~_{Gm737Z86L6u!DHnxVlWuXpK3BwrgK3l8vcOZB4Y ztGB!mDt-4JFo;z6=9>A6A%CX6$Ka?b(fjCS)@Ejpia&%YE$ztbggxYeFoxS72h`*4 zFRN%^3ys>o{cdEc#gZQ^*nU9K=cMO~Cht7$vraEF&*yaAs3peVw(saMu(G0lf>E#5 zBRCknDWkTRl$1nXy{7Qv$^~dwft}dw(ds_)t_E{I3xMp;AuF>G;+3lYX3z^sv?Kem zIbDq`Zo5&UIU_~vRV-VSfdH~Gl$PQ9%gxiu4T&dXk+8Ow`gA}okGP@tXJ$(4BP{>K zPkoce93HP%E(6J~wqjShe%{Aw#xem0qJwE45?3D%+cH;RfpFxDyDyge|oPrG9_; zK({|#OHQCp_q_lEfB_2ypNj80m(4WF*TI>xfvKKn>QSz%5RZW$$LWRPDu-ei&f0b0 zwqtlZyH6v~=v&EAN#0nY)!*(GeZh@$QI$O1iz7*eV~F}gU*5~E9p*uQj~RUThexOw)eFv+v1d^0t7?yUo)trgmw$qBSvs; zQ>+nGV=p=&75!fN#+$!vbly;8)PL%JbNZw1Q0qbOy;#aIK_N9naEH-iePxU-}mPT?ZrZ;jqJpwg0W%ZV@`veQl zL^-b>M}GKZjOiHY;Pp$LO(EO4qx#d-NyG^yRlI)wn?k0E|$Xyzy;^ zIAXGx74jW+`!F(!&J9c;h1y?OQ@s6{s|(&{$nKIGIvXxFXlUUPf>e`oa)8h@wW^+* zjKDGLD%&&@l#vzAZ1UNgU&<#bcRc!XZSwGIQEiAq%Wk$v+}fj?s^P$=-%akrGILxa zm`9*<)K42wOBdheh|PLYMg3lU4335Jz~A~$60_}w%Lix9#?>y41z)URw|Gt#*L#sp zQCw%|_m7r~(8FYfUKR(ebAa|Z)o{l@2kum`(wza9$-9txDC>KJ`LhPQZ`R99vJ46YN;XJa3q=Ctwedshq6V5*YF(g z`6ngk@baKu;&o~;DHr_tfnRzC^NG8oY!OnJELp|cDZN!W8rtqLBv z6K@cwS_bt8c12xt@alS`y+~^8O5HX-w$s?8;e?Q-^mlzawBn{aDx`(IC)%I97N~oJ zidpFtC#qE{LoxsPW}r(VmauOV$=BES`sPLm#1+=J8G^7vs}|p1P%bkBnYgL2x{a4I zGtW-!+j;8x&Lm**QhOg{)Avj6*e9hw>mi>bizyYg@mMRw?U}ib7ivh<$)pog$z-sJ z(J8lji>isKAhZfrLw|zb1yr$q1Or@;knK734Za&Gy$ALiAix)~EWLluD1FKX< z%_b33_~8Ag11%sz)G}9;faLw-HQ5>V$5L&02Y3drz0qe(x{3(60@U^tl*mkF7G7R; z<3M(?g3;2r9)OL)o>+m8<|pl9khPGALam4vVv?8+YrajDm~PIOru;kQ8s1YA;+(n? z%+^V8hld{85o}dFEf{K3dYupvPOK<4a8>=mXS`+p!6);$1Q>o5p*9IqHs)0gCm!&;z&CcZ zk*^W7%JFf6i06^t6fO3T#u$bDWvH_mFB)Cm^6TsecXOO3P5hOPFft0BfmP6cu|k}s z3W^z9n;{%T5Xl~W*Lw+~PKPV0;g*9KM_~Yb&TrdzRHMJuXAqt45QBLcXH(#(ZT z3b`%3dC~yqLz5=~>NZD4U!Y}X+|%P%_h6SkN9O!A*787dxBy1pzi60_#naPGL=R#^ zxx6QKhwyk`6==M`7k-KQd65lC*2(d4w!?+;R085r*%C=!i6VIrYDBH!o{4Jtwk0&X zZ$mlSkC@AIH4KDBvPHCcp|$RF9_OjcSw_bXJ(S}xxeL(-~yb z`AW|E8ZO+?gKNh){6mP2M@v0T44MslMKc9|Cq5yDy{_++pjP(U+=6|Gs%ZWbEEHe(!Q^SIOC=dmb zujU}T2Sj&X!fT7R^4Rt@W}erLjm=5ma=gNf`dgY34PNW$@MsjFmUrL3_sxu+d7>2w zJ$jq{1@5HS0|roR>MuWo3_kOvtK*r!icip|C**tkx3NsXhrPROpLk{-vw=;-km%kB z3%d?haCFcx(n$wL8hc6D=LAJ_YO*Ww{l0@^hX3y7Sx{aT+b!1Xg zJuNVn+NO_I-0ZSF*lSN5&a5y9!IKg2=SnS?>g6GZzii-ktV(4WN58rA37iR;sBWe6 zZ|+7&TS%cddDOuB0)^YJZ>A2EvgQ$Z`sDbBz9A%Ow=Vo(a90)8y#z6@T-a?P{iNvA&RbK`;eO?+A!%f_w5*HVU7^# zi*)8@>Xk{gu%}=r?dF)a?76=Iu0-r4Z2voquF*Tk2SCK~!8TVK^rDN8& zbNI7CgsR9jo58)fj)Db4jcbnl~4}Od7mj^=4D7B%} zwXz>3ViW2K4`r3F&flywq64mK!k?@*u-`6a^U(=8zv26Pqtp-rO*l;d#t6=9GT4vb zlWcEgngU0Cn*NP5S-HW7P$=`3DoEYfQk;jdzFThEBGz49SeN`l%D~O!O?>9HjLrBl z($JQ-K6eJeWpomoC}0~x@Z2b^HpC*YYENBZekquaK1`hIzL;;H%8JbHlp=U9`*%Z> zP}u|=JZb@_Rnl@6sQt_K>szp}-(EHzyRBg!9d|3&ydC`B9VjMXhF%GwWaP&1l`CZy z@c`5}MpL0Y`=jrDc&oU2^gV?88VZS!n3)+>R@ZNEY;3H2j7Beuvipwobp&Q14M`~) z2N+{kx4h#IG2+7fbcOJF8H6S5Zlf?W*(0xhxknJi3#I)9V9Wp`V&h$=P|1g^(&o7f zCK8ZJ<|! z+GC6jr1YLOjytE3A~VFUR7#mR9N2yrK|#1>gI`-3Ise0=O1KZ|r zaAaF3zMot1;NWo&G)j$QDeM?(N}77AP%H)-{G{L4v*^`L*B0-D?e52E9`0J{xg>~*@COlAYKIH&f zr*?Fwax$BpEqDwby6P8@D1s6OsE^vxIaK>|mZ0mYY?Dat59KBnR?-l*qQ`f*{;FAr z4pOo(C7bnGl=Eq=M^@5xmxJ!;Fz@T)&7vGaUOqP_) zL6CF?5DaOJYZCj?lj>4do2Z>I&ZLyq%Hz3O2{>Cnb-RbZvIjQz46ezUx)P3{Y(pnN zfy*+UUSHn!9BWS)clCu(9FtK{z(Q`z_LQiWC)M=R;W^Y?$LoaEP0XbDbMlx&?u$3H zA|jb0e`S6{?JPOWV517`_?0A$;oq!k`m^!~VBj-LFX~*&^O@3z*i*38Zd{TjC%oRk{REbeJP!+gsk#q0LILzXnQ;$X$HqdK|m@Q~Z5+l5ZB1b2=YB|u|L z83j+DadvPJESAp%*R`W?t|6K`GjpVkJ}~qsR7FyCDdy{pxx$haygQs2)W3pRmeVr@ zmS^1zMb<9_81p&uIlz|mF_K2pbuJ-d=<_!?CdQ?PH}TC1FzYWx-E(pAePW^pEjZ-= zXY%HK@8R`eYGm~=(Chxsuwd*JYfSwut9w7g;=tZ(4MHaRb_xKCuAB3l|*bX^9K4EBQ7lIoT znY+HNWg2Iq^N$Di14bDJF?Jss9oL@(4$o#Vpj2{YZ4HjlDy24Wy_uiK+;Q9sVXXhQ zj+t6yl+XKB51^&wJBPq?+b!l>W9%FeagTjRKbz!J)g=4;iw<6y9z=RS1Q<^YbuliC zYRP{zCKcl+HzW3M7fv{^lW1YD2SL~t={Bqx>$~>`hfo%?@2NN|iT2+H;U9tQBD|q% z7D(kbypn>Bs&}nRC7*4rtHs?<*#|(a=H&fW`9dmWzzh4kHuXN&2lQNj5Hb)c=-$2k@ZWW^U5t?vEFl zoK;XjiOzg#JC9luh_4FhKG4DWCCZpRPRo!#V#D*R4N?{!4srxX!`mI_g%!nXda+3@ zjAu8f66&)zC58xw=i3o+`V{%a?i;Gb)*J*8H(No+I5bN(2`(8>Tu?A4n`fX@Ds-7= zuH+UQA)4u}V4voLyD8*lP`I2jJkZ7wQxz?YPnzM4<8-JuOnd7w!76HZo)!pa%g0n9 z#*8>l6g{IYuWX}kgSZ;wiqw?z`m;^X%Aazd+wQqXoU_q|{$+eq%tMg=EMWUY`f@+s z-eB@?qh#;b^IJ;b%K45XUwNHSR^J78@x8Ow{+%iqk2hB%3up)qZ#v!|DM>;F@mf{n z(h#J|I!z>n(O#BI*?07ezWcmPYuIK~6YSCp19$3ykO&C}2hP71mDQ>mS2p9Vl=WH; zF{%-|v>q~oYJ`N``D!0lH!!+Ikyeqx|o0xPz^d}=8#yYN9JZNV^yUJehtv?wlW z*v&qt+!i62sTM}3n=fKQT@>T0;n?Y^?SOJwEV$j%W{7@O=kjp|6S<=}jmOA#`l_b2 zM)Ym7)(0Rq+3KUZ-F}#8MPJ`)gd1Nu9p^LOIk72Bi^i`l3>3pe^H|WY+PF1is}`NQ z?W+?_rJ_uP=@U2fkRvvhYO-!I$uhc)B*EHw?689u&4hopXsVvbNftTbNVa zQKif6hyJ|asc8G;SBt)&;#QDqjlSyAh?U1n?gdH@oxBB1*~*YkBagg7jR$XFo(}H> zwlQS)1H5*}yvl3u&tk9l-@ell@k0%3nxgY(cVc7(whJG-D(5*^%%P62P!~0Qdb1zO z;zUuX4s`4kKN|E>*)zslaHI1q$%+oYte({jYDr()-^z&oshO^g(^=6$as|V<+(P|% zvkmlhOS3i2KS8;Rha|x)0Te>{5Eq*s*e^nnhI_|>)+qXhp%RRfZaQI_MB1b;14gK< zS=-Zvj2a-x6kR({o}mNT%aZ({%O}{ea92%#S1ZKQL!keG#7Lo)Ds62|=oB=E`>N8> zqzFCu%i~oxO%*38B0gtMJg<}7=q6Bv3Ov8uTO0l!Q)61m;*r&jZylPLA}^QjBgaow zf0a%_NL*lgW4(V<1udyM?#TyDrB)80`VeuLj%+?ZfI@#9YCXlfZSev>+%&xj`DrUE zC)0a3?NuUWJ|)uhCr1hFlaBztzddxucv`Ii8YeiU0rJ<*&QeW|Yc6(EXPiFG`ioO=L0Kssg8x~(b6B~@7%k_oyr7}O z?+ZSBvh?rnMx$u~hK`zJ_$Ya3H-5q<%B5D=^XWV1pPZRU@Tje}rDFLPfH=fGM%Z{Q z659p=|MonFYgnMCZX=*6BJz>n|>mIVZG3~5EwfK~hHj~wgJZ;Tvzy20dufx$W zr-LJ1#h7(>WpVX@zHhvESM8sX@C>Q|$pC#d#7^o8C#|p_`sqFIbA)6T%e_&|9E{~r zuP(TObn!uYNaCLaXFCS+KtP}efS=ilX+6m=3M{FpG-bsyZQ!E%D8pZ#ep_QW7t}l3 zX5WGUOjP@)Mv1?TnAnVD@YNupdnK=cf4dVMzVp|V ze#MkYpRW9r{{88~*uir-Z-X3$e6VdbwU)gse(BG9GSxCLK%%!6*l;-~#VFgm*T~K= z9loLB^uuJuzlr@cj41X&pjs+TH#QVlhKXbd-FshkGd$Z3x|Z1qv&Ib+ERLtsW;@C!=e<&-GMeeMR^c7_fY(L)99x=1`G$}_%l}O z;b7iRpqGC~CFiaKX5x)lvQ<_g*81JJ&zB{pY>0g`>u@CO27cG{g5&&8sn3Akr!n@_ z-uOQ=0-JqW;%<2b1+4Ye(LGi!b0Ty#c6COpfM<@$TsMO+@*h`ZnC{Xf;>zQjt&o8{ z5xzT?Q@1(<{?qo-T5=-ldtWLI!jhw>(+c9fCIFrs0-%}KM(FV!bz8>*9~1R?YEkMD4(G&j;)fbmuvqu^q?0ITTHTc{3T22`{~e^q|#Z zFMDPKxUC`_hhiuq;Wvma&y6TE9tl9ijQTs@H?Oz9tVV&Ehza@$VKzm4jm#@ z9P=coW#;ZTT=qN@}z4c$Xc!HCe?boe8o+Q(xeBa43xUf?nAdieji zdgtiKf-USjwv&!0HYT=h+qUg=Y-eKI#>6%zm}KIKZ9Dlg_ulu@pJ%OJ-E~f%T~+(3 z-+nd_9#7ToA?4|eU|?5n_NDvpfJ2f7?oOfob{{T>CvqNi)|Os5(XviN$MlXB6k_T) z8foyb8By>r3GNla@M8h^sglSEE$YI`@VFjg{SCgLT9a^7lbjTVk4M;Hw_uZKYv~P( z9P66vmHa=fxIN*WK^F`7u6!hjm11a#$e$&^x8b#Mj0XZUo8n4%5u2DSSl@a7Z>yrR zsAuej3>W=JzXLAaU1(5apML*D74xfKjE-KG)n+4%2OW49FY;4#7@{K#wI^&I0i9I1 zBJ)DBbHbmv#O9vU=&C#9xyT(K9@*)9(grI%Q^3szIYHtBS)^*oCnS5|ld1KD?j$ z+E&1BX6`XHx{LPq`D1^Bc{}{+;0&nP$j20xSL@S8w!mgWR$s{D;5Z`>Kr({QF%mAy8RMC{sKKo4 zvJp21#X(@-4EazWfe~Q*rb3`8q^Rsi5TB04sxp$gdhFxQM}kSz@;BO_=cwZ+<8`S4 z7lBOg?Qp_ik)ilz>%QsH+$)`m-K4+|Bup*e6!&+n?5n1quz@6UT+Hvbt$_wYK#o%r zGtHH3;x|c#wi?Ia&;93e2FKEHniictzlE>b@f#ky(h?XojI52uNex&}vfKsag zZAo+#ug5vTx#^7q2m(-0MLE>R{E2~g_3YhN4WjYvG$#Ah`A-OK$r*6_ zP|_28lS&mBysoIAf9aPmXb1IDWnvlqYh`*c0d>aWEd)-quP?)k!g zEyp^%ix`&7?qfux{S@#v$8O_GB8_{-IC%z zDXX7OxH^#mj{>fqA9I*dpsKPh!O1Cb^=>7>hVer?sIh+ z9I|`ikRw~&0}P#*?!0`c!o;W46hrEB#@>!z-V z{1Hll0wlkJOJ1WOvXJ`Y@%YhW=Bnt{D#6xeCu~H*LJop<^bAF>Nr3yjJ zmiY4qhLU&bIpgPxnI}chFPc1dD1BGzdea3Y1H!I2YSBC`fa>^28EQudF#I$alO*wB zWwwNs%jQP=*^5gwpcy?K_b--6Pmm6&RDkQC&jI>Y>z;=wSw}(3$*8)etu`(nlQ-0J zFHm(gfa2HzfvItjAX5DjPVrnrb|OEgNOv>MOG3NR6juDJO++9#wDD$-U(nWEo0EyA zwl*AK;?`zBD2si#w^j|U<2|!EP-8R1Wb--4677+rmF^jBEo8X0G`+(gc0DIEVkoJ|5$HLI zHU&VR`)h}3E=NFiww8qdfj4r;9q<9YRAiC7PV0Aa89?1ZuNU>8hJeazj`q-{nAb^F zA?@poVw5#zw_GojZfPhbyY;X3EHqTCHQOs?hL&Gv+qli}zO=X)2A%xIPdKW8MqU{l z;z7a#daa0j^KkncN$HUTt%jr+kTjW$705w=SV^(_-x^5YF-)b~+^+$}Up*+2jobje}RpVpN+ zt^ER+Qu!E3NA4A^&%*MJZyvohG>9SC#Cjrzxj08~^c)FK_bJ3n{cu!V{yAKBsd03Q z7mmI(lCNw{vjPvf`+I=3z}OEVk4c0I$J!CiM;#C*IX6+CBHLO>jm%ZIZ)LWhT~puq z5q0dqVYm7t8=tBR{|5jFwaLsMgf!R4j7~NrFkoPWCV}?7xCkMw838<`m$`4Z4erSP znn5dsIE_A$uJez4h6mffqyY3Q=JE|;FtnBp7n!yLVXfqaxrp(yvZUP6DRqYs~bPgt#vPqTDNT8rJi8OSOrV%_Lz9Ka6$%P?0!@ z(d#Q7qH~>^pnu~6*O@kSJwGF(gyeF$I!zKK;!7@u)n-#2!yT|@qIadzV1fW1xK2Z$ z5a%W>&m~|Iq63p-EiKNM>d_BdrIYORvA(3Yf6IhrgkaCWNCt}qgz}do;IA|?EUKH( za#iN9qQGe*3;A;K+PhF4785dB_T1{b@8>_{PNa>As^T8><^(J5hvdgf95_NnK*he_ zfh8H|&8cy8Es;#BW$54kaWr{ty;8Ju!K}M@cVxIZ4u+a*=rvq$oBJtZ0P}tI{P8Kp8-y+AB4DY;U$2 zho+$)!dN1Le!0Jt4N{g!Nz^P(!2)1F<*tA)cUFOxsgF}$$5u<#T1|p-$tIHsLsdGg z0a{=DW9rrouVE$zD~NG00iT}`Z$F_1rSK{R?ZYoGUHQu3$}pfx9D1AkB_NXn>$rsX z4V@)*bLfd2-6*9SZla3cbXUkvy{4p*d;fl7hOL6k!pkcoXg+De+|-ols~N0gRn&T>;$iOaVH>(?8NG^stY%FL@$o`sU z;3)%49q(mUuwV}@US_qWq$3$w0)x#9lN-&0kcE(Pf$_`S*{H}hNuRB;G_53ymswyq ziBW$2%4~@E;P%@b@hDy^R~Z3jBu}q z3d51h8JeO&;?kV31S-H`3EH%Li$O4HAVDUh#*|n3`QVo)a?^?(qXeq$@7_1w-++{s zySrwv_QjN?v|7!Eq|pj)pra`gZkso_eDbwRpL+Tik(iiLi@nzdDdgiYUz#$l3Mi7J zWhk--_kkF;7!aDF74{KSe!@}2Gz4{ya<~hsu>k+7#OG>YuYk=XRlw)@E=e8@Fu-)xP-K=VO9zw zJ3s`0T8Vh>6R1;B&k&4;L1HCvALXrHY5gZT(>bJkNRHqV$%RjugJEsz?v8X9@RR>* z)k>SbKmRKE>hn)JUE8VbTs|%h9ms;kt-;*+kYbR$eaXSkE&TJ!#$+{17jxzUb1quu zxw67kE&4H$Z752^zak8&1Yn@2M)U@#d30M@Nj2-LGa)~YTjdv)kLdz~4pA58%(HTo zvE*_eZ@$+>oppu{pQ>hzKP1%?V^P}D{q5Iy@QxrUIHyJ9)K?h+N^YSn35d#T`6uzP z!8JSzJCf3Xr!(W%`zt?T`cDimx-rkzdv zP)OLS2$|(BuLuXkHTEmTZnuJ_VDlL5-$gdGbHgRGNF_WkPDi^!bxzZ>78Dz_U(2q!7If4iHJqbsM-qH7h3Prh9C6-5(( z*;^QHwzDFf71Qe06-;RmMnD#?<5)Rgiy+Pv`%9cgMtGxzYu^Jf_o+Xf7jt4DYJ2+Y}ny?{A8#ou@aR_KyT3Vs4F)eL0-sLE07NTC4 z!?-PX<~pr}G>@6B86ZLOhZ=peI@6P;f1{&kaoql2>(IEx$! zx=RSe+QX52@~jkO=Oe|Tj#NNZSjA9FVX+A{Yy%NvWeZ7J2Qv37C0}jzgUdC-da>>c znFK|}KyDZ0H^b)|q~%_A>Fr?GBND;OH&3M)hIPmyO09~$6~*(TQDCMr7{skKS?mTQ z^8*!crfwp`x+kb=au9Hsn>E#1F7!BMx{$=NY@V4@$NY!QH<&WyXF>!-I>hk7>T1RF zX&JqaDeg}G0AB16ww_i9s-K?)j%JgJ5#XRG`cj!L(z`i8I5>_6Jz_|8#a)Ho#^)IQ z-NCx)I!R}(*ulR0gT6ZgX)dGaAN|F54uBt?zJ2KK!RjVAaUl54)lr+JYevdMvz^FX zL_|ir7pMx&?s~C*zkKS4`4OE?%N&@>JIQmQc!M;4(nR<;W8ZEdn{59jT5l%zfNJb; z6Y&^Gf{5)WGh9Ej3$-Zo=yOVdukIW&G3E)pH~vh{{H0DS=@w;eEP+YEb-Z17g#dhW z%!I|fgpu&u@L=5L(`&ml76z{gOQ=n`;V^mjZ11elC}#%x-LtLf#3aXnXOuBf@_NR zG}<#=`QG7F%X%ag#Cn#LG$4fr%Y`I-O)YB2l(6onX}%6QX+GLL;W0Ndg~FfaN`OGCPWr1aq2-rTdlQJLn)6Kki+4@5WklvS#yC~9ot;%= zEJ&(}YV7!eFz8^oZCg|eoxaEcd~R3CWrpD4rbvX5yle?BIk{g}A0evc+WoRAnHZHt zE$EI?;+6%B^>w5p%ccX7K=#11`8AyL5CV44DITY)P>TjnLrUVA5OR2?&0M)O5DlPK zxFDMC_b;l&-Il9Bk9Pern#3m&v8`bpryoxpyy?Bc+LMF$b12VYC(Pev9jzAa>QGwx z@d-!3=N^mVXsu;6_6KyzcF!2HN+%+e=7!A7fQ;D2%R$`LBfKyV5DQvWMn1rwR3?z7 z?@Z?A@;4wO+Er2}O`RgWygwvP7U7*=?JA5G)j!<(Nse;f%8Wvf0wdy?W!^NWMpbZ_ zDL94)LH4wt>VYYjTzg=h3J_07IWX18ufHy*s3h$6qw-K)E&F8N!M^&R-q_t9@nbsm z+DD1~ax&{z$`v(`&XzPIHY_p{_GXn$7ohibkZ1%xo;@J0EsOC{B7A?gN&|_Q7zUfE zwKO;>={MV!16EN{EV?^j1=L1Uz-U~sJ_x9#w}v~kx=w6!d>}b~iJCm`NU?XUh=`QT{fQ!pdkiv!@67}xpW5ml6Oy-X!~;T%Dlk@ zX$KS*@7`s93)Ku1w3K2T>LU|jPm6!ty{f+J_4PHlLY66op1q=9UB($VuPIja%Nf^% zkIO7awxbqmjaosbuz zBu?y^R?xZG1`Alz00R8U(f8Yl5V!nTQ*M-_Dj+92aWzOTw$+JX;lDS&c_YrwMXIY) zLEB|Tl?4W%*I1g~Ymd}l{=rLN_cnFosjStRsV4!V*5S4}F#0WO zci-+uk2d=8agL=7!-5)A6@tyDm9pp{cM0+&R98DK=PE&Eo#hTnwgG?TQcruHalsaM*yO%r56;(h<3*Y9S5XQoh;Zy~F#!w#|@PVw^x_q$k;I;XG z3;#SFUuvZj%U+xBZ&{dugO(zVtK%*ggWhtdXc+2Orq?T}0y>Na!(c0!WxplY*w&L~ zWvsQ>U_l{Z2OJ$);&VEJfI}l;ypW_)yleXZkpNJzelF)kwHpuS_RdK)%u@j8VBhVa zA7+PPchqmiYrCyukfqK6=HH>$wNj-c!w2f>oK)-+5* z(F!N4QM61aJS&iqBqH$r7H9Mg-{37#6*=VnH~W8O;sNacNJ2#o92dU~7dK%&f9lv2 zBQqDM@z8>{ag|@HD=k|cjqKT-En?(RwRXnAYsfQOTDoYkcu@8AK&wy+^VD)JCU7Yy z*a7XJ+_D^TiYJ z34fiWZtw4he)+F&?+izSIXLs6s_{hF3%(ZT;>DSqSzd2hOg$H}{9Tk8*z`Z$ zW;SQjPSpO5(t5qC23QEGco4+rb%kruJMSO4IuX8&FH;6K(qoJyzp@c1;3_7HC8%}NL9Q9WATScYw4>NiZ+W z5>o6TiHQw-EYP8##fK3bJi{EgIptmvfsRtbfw`~PcH139=wK!-(0F3D%j?#-usYXP z-gmhYO2^31T4rh+T&2tu@4TTc3P1~YQMVFBsZubZrLLdc!Rp1Yb{NC{g|H5UH8nNW zpY)&gkx4*TPGGS9G8*B}W_!ncxX3e_0ZvuVCv!md`M7cj*-2?^2B0}3e0jv}-uBlp znkSIP(RD}AvSbF`+sana=;Q-nG1CoikIs+~8a=`{a;1cItNLZe6MWn9Ll>=|gccLLicaJ#7%-yQr^6hAKAWT+oi630G>p@`s9`3(*-E1!THH81a^R4ef!LRS zed85pt!``)?Du1zYyGa2-f$pWcKG(xgT0||<4p|{tK#z6JI~`0V%{XN2z7dcz5H>w zbT^U)!4U1(T`dQWzZFFP3Dw$|@I*I1b@vTJyce5&)deG6}>&0@|pl3iwRA(|M zY$*?dP!CI)#;MF)B<4G=YD0a&zF(VfXExpXsNwnQAT75)c~%V4`Cgv9Ja{`glW`zH?X+q~JJ=%0e`h*NvFY0&>8EDJWT5q|`*n4`PwJjOl6*OA+ya@nNfU-`LU6u;a;t zEnZcV3}}6e`Rf>o@ z<3crl0ETqi;cjIo_7}a4%)%D02@7*st*|h&7aR*~>a`_8i`$Y@AMjvGl};hwh*oY3 zyJ@6kdYGbvmA&*KZ>pHs@jA@4B(P0Yf#L&cdWd5|?fa7`H2VR!rJ#I2=0_^=P;`5v zw~d?zd!^QDK~W)`$?cybyDohuDi={lRkfoQOm$m~?;KTX0Dj z*|?$Fc5o)YCB!I?eqda_n`29=pG&e8>0J8~lg+cB5NCIT4bu1K`=R>McqWTI?Mzpm z0KE^v&*!W;YJ23;I&Q?%kH5=5{V}GF-6itYAb%>91}i--;|C1Cul=Av>9YUQhPMz! z1w#SC59-Vgs!0-+XVg0vTMPz0Q#d)7Y_x+=uhwk#i6d^cLx2D zt(PxHCULs<96M_kY^A6*Vc>G<8?x@k=sxrrL*0lK~17hmB!e*MlJFE!LH(kfF zEEb&__H)H(5(milK;Q+xI4`UWg9*XbK;DO8>pmiP^RMAFtD+HA5=^1bS7@f|x~sQ- zHRr@<2l;u2MPN(+Zg=_h#|)$Aqh43l6HYfL^5bB))BfS~fS}WD<@D3`VgFUBACzTm zH19>Ta9@#V@jO2ua*zG#u=H>J=SUuuKW|qJ3?m!$!y6-j`oO(YsVHoKK)}H79$-F| zPF&q+3BXfMsTS9-m6dCP$JMS8Au6SWkzV20_+8|d48+6UUB&e)eS_xls1?hba3_mH z7T-j=fyE&a^koL9wKEpu#FL3CaS6>DLPBtp-KQx^QZD_JWl?`?_@Xg!o}wXG8ML>{ zC3daddHu9<6($sD$1^XQl!VWzZQ0}mh#Tw|Q5(q%P|$-yvBMO!v3C~W@MM9^*!@OE zFw07Wz>7EoQr*9xNulq-@SilVL;p}b3R&NhosLh?1zdud`Ypb;21nLki#gE|5lxPq zjClNM`igvIlC#T!EB!_h2z*gM36F3>7J{9?|4QempqWclzJ@gDvTlJjs+Qc7<2RM= zK9f(gLL#rofxR<3d9NHO7~==pnzNzpKsU-|wq)}>NzSnmE*DPPFu0a#qj!5&d)+S= zbWIsFCANji(r8MB+8yO$F5HIfl?mn<26e^`7aWZlNRry$l$ILd)O=$>@@}rrL$JV4 zx73F>P6+|(8s=&qH}NL!DQ7aD*$V5>3wKzUF6_8`fx%Ew(pBa3kts7~%Z^@gU}8ou z4Qwz;$*c*FRQo!3jp<{t|D%%S{R$_9fJ>?DWudj)s#3_HatKc;OyDx4b1!!7U}%bk%OV*Q|V3z_Bm2#UDY9Uf+9Wfr6gmtLhKqP#MjR@1*=eHznqldIl~nf>~pmSppwufR(D zm~3^|UrB`RZn5PCM57i`tp@pai*Hu(1F5E*^Umkz7NS4|wsQEm{g_Q`G83gy zwMRJXZ*bHtAY27&XU5YG_n&s}->Kk_x68f_M@JRRlHa)(fdfio#|<^C?quJqc)pT( zR&4&H52hw8quj>7Usd@1aUu6?bnr?q7kBva&J+UcB$AuLNP3c#@xJ zKVs$P+;6PbVzg5)=$A0jXdH8_(!@sQ%OjitN#MyNTVWaHa)#pm0JNHTrC{0fP6~9( zn|aA?Ceuuv?pLKe0h={PrWM8Ot9|I!9p!f8R_JIq8~V{r>k1W>I^=ZS24-cMI;JP> zcLLUeEIpX%fhe2`g=|ixBcDd&@zubXj%7Frd@qd&+WJT&^JV?qkl3!(8;T(d#w^5_ z86X7Gb;x}xnPdWr@J$GFE_w9Q9&XxBMnY2J6;kHna1xwE-3^98iCTC4B&cuB$6cj@cP*8xieaeVGpDlMZT&N(Cf3Ug&h3G)YK&jM!AOEroA6tbm8vCTXpisLDV8n1S_ z5^a>3J3h97_^_0kuLHi5+0u%*Np;gaa-^j!+AQNqq~!${wF`^2e>&^h5c_wgus*^5 zCnKOD0c-ck7e+B109O$(`VM4VfrCaYJ(+?59Qc;Tz%S7(Zf|POj|9)x5MijV4i9o^;5H z6N^A1+n6Z@{^1XtU}6$PRR$Bmf7)FRLw?BTr1S9K2g0K3<}1d}>EuXr_sh}~#hqEW zLLR;xkCD}xhBf;FKR4$Hjb{l~kgWE09(MYNk2op}*vDkER<}+pggn`$?3=z zD6q`yws~C2cP!A&7eF5;n1V*iXY{e9#JF|Bk^;wIs4C)A!KZiee z45aScep#@R%9*Xu84wiYYg%Or>~AYA1HD1A;vFQQna3bDVF+8$*~}3}!7mN! zmor@RLxDsk?;+;Bz`)_aD9hn~s~7!h{AFIB;wV}ve@uuGu>(PC; zmVG%9MnQ{PvWf6Z$V-r@B(5sIBPmN`P9>@Us03&{CFc0qoRPlP#)iG{LV>34O3OZ@ z(*CSSXrg#2V(Xq4JGV(7b|r1W%ijSuIcUi;fV|o_>w(nKF)iBrtEavOOce4wpVb5Z zH6ON;Cp!%OIQ{e_>BDv13*nfFK#m^3J%3U~r+6~#R!e4i*S8XpQ(tH`f#vaLXmtq# z94s&td%a_;K-VV^f^CGY=?Y#IbePdl2aD@H$|>dL;9d8{ z-bQW+0ywFV*=XMuz(0qLz~};a%2Wt0GiNN>8GH`!VEDXZ6_npkm8IEEVp#)^S<59q zVFSy_Xu*0gg#*?ar8elq^u2f1_&porKf(Neh6{jkG!lWN;;r06Wz4seR|lGhcOc^S zHMaA~yXyyMp_A>7Bpp)D;3Cp7dAyR@W^{w7NdhL?bN9}HVpwq|z<}QjyG+JIWmlI! zaq~DhCd3a87~tzUhrad3URJM%FzbXB>XP+}vU(L-=_p(&6cwxXib3Ced&>?%oag0n z1JQ|rB4%aA;Nh+wfG{|i34{L6Oa2d}_!pJK;etKZs>2#=WmEqExR3AkcgDQt&6D;J z&nLhX)9S>OpUpG+d_anNlxJS`<#UmWYlj6ml@At_ykDL%gzDVp=u~Kf{{2ME>zeOt z%nRS+pk{lRL7F0!zTH{c)GaOQU7eCyED(7WuVJw??20&+7N${ioTyC_`^r31>Oks3JwhM(=GQ997@ED z=KdPJF0o6k5t4&nb)0QP!cE=?V+Eb zNbs-!KQ7^|>j`!1vG9rMfNf7aph{_fBxLjl7}%6~(OJ0Y(=;}sr)_wZokffRABv55 zwP2g=wb=3!uk7C>&Zp^bA%bO)*o!3;%4q0`Nl6hy7{q0~CUd_KYnZHh*eF^J!g*i| z``@E^_V{deK&SFvl`@zb8MH}(URM9F|7rpc?733u8W4NqE;C8kJ3j9HbVhb-kwtuV zrmL=VbvA%R2ZIywY2N_QtUl+2bFs}~bkPua@{Vv44l1dJjEuJ|vv%(Wkw3?(M`v38 zCA9V6pTH0xDHY1MDt9#)*Jf1zQ_+@9Hl#G+bPd*h>Q>DjXmiz-QVTZ;$}sxBx8*;< z_mzQvF$XJ6w^cV`0i`^C;a{D`<$kjQg&e7nG9fDrbiCwvV#2{FAjfHre)2)w*g?nA zL6Zz=s23@@R8Q$krk0`-aT1B3T7BVc3xVQ|$v`1e1& z0r)?bDS$LzP!NT^4ar~yNbtlr|3>g1rtnhs z5~ZuyT#SMLx!wOlNB@&^`|x5xey(^9+B?|V+E)B5r@K--A##NJzX$r??{x0moQZ^e z6i-1kTTdRx>*_@n1St=aO`X zLRlUKZAaF?WC{6b(tKF3H!byev{4B@e)5coOEIa!>C+^XEo)UYw6~`}q>3%pi_FnN zS_d^#K_fW-#X|lw@caeTu_eK-1+G1W|Be3t{Pw@geY8N|(AY22mwDwNp}CS zkZkV2P3kL_o8}5cps5)Iod3VK{oj$qeu?6-(k9a62~I_$Al1B>sa2)RHqhJK4X8#8 zgZ1++q$JADWb=VAhq zTcK+SgY5S{WpJ|T^M7o(lD z@G)bN$}2lr$|U5BKlVZ}0Z4cXu#+apAbp+}CXEGYPT$kJ}E^3ra@ z;*u)XhQyAv3~V)>A~ZVaqy;4yq!E#c5>kX&wE;YFU~zDNej<*i$3^2w8129jHs?Kj zYdv3&yew@A|NPVLsD%mQl${s0m0(ClTkqvX3q<)a(#B+GPI6ikK=Fvl?EBmEZFOa> zNa~#OO6!r$TaFjTNi#bqo?{P+D)SomQT}DN2|L2!?YkMGC7=S;!ar2O5C)8)S2Pn7 zm%!f=%)1?5d8-mK$N?7?caOmZC&;ZAq)FX=;Fp~ZQ$GzFZ7EV8W=TFhkRZD1Q*va# z9*8nTf%Q>4s{b%r^wqkBN0sifw$eu-xUpLYwliK^kp{7{$7N{Dp|x;=is8h>-Q@RA zbd=*JFcJP2+$Cwn134cr9OC{NRVUrJ-KgHnG0A8#$t{BjRKgX( z=!XH9?B~UgZ#)R24Cy?LSnRm~$hfna7@+&+Et(Hu6US>!yY;m{Rd1E=$q!5B@Yd!D1(Iq1Q3yus0fuI&TBARPbmgX=;Uj zL>7>|*u#o%g0YkGS=w+Tn6fMv6U`O>}LPg#6IF|29`Qi`07x!>IjmZhS z$#N@~TZ4lyvK>yQSr-nYRWS&i?S^NW;LkP|s>&e*A z+9GM<76nPF*#K|%#cY6V0EU9%D->L35Pkm5!nBen-qz*@;hdl7K8VRMc}$uwFE(R#__JdPyy1kI`O&K>&Z%PTWSKHWTG%%D%hd1MX;GrvPo2)V|5m`KDwKa%7Rq&KPmFIIt`QBdM0{`!ILVcLRS~ zfQAw8ijag+78Em&*)N*f_e_S!858+5e07gZc@C*Nx#iVi66PZL(6N+52}tkBrzlG% z_&rB9iS+Rk@b19QDpj=J_-cldT-F(#sw9y31q!f%2`CoqiBn3iq6yk=vfWL)zX17# zmm;izlsEof_bC2|RL6^Xkc@GoD}t@qdX1=uV!q*PJN=0gwHZW-YgT%6D}~_g6@QSo z0sSaf{f(gsQ1JTgClSbvLry`N#w|rBrVlRjC zupCJfJ1H2p!{6Bok#RX-HtreISOu#G`6~uz+iPkCxOb}`l6Q@&8Wm#U(kBfunLC}$3-9*j z#XV#HG?#Mqz=hPC0zO+o>+{vDdr)bGhkS#w<4`zrQ%aPHAoOO{$Ab`xFrnLr;A#6w zu9zCgXyhllrA^pI_X0wJ;jzERzmtzV^59V5`>BaX%X$<=KBzle92SVJ;CG>y@{2nz-LTk))^^Ys4YEe74DUprcxg^;}*h-l7f+;uiSX2(Ky zNwzqzA>)NuRMU35fb*`fWKmpY8+boBSbc0(r)@X-%>TuMerxUj{aU`0m3BY9SbPo% z99KbmEF^lv`0mhHUXqwp?3?S{^I6^7{;b>OF_y2@onX+A<9DlRApH*g+S4=jkc~lj z5NflVH5pH2J4QIf>}PKpst+C@nAeL@srn^_QchbhKZs;m$K0x}BX`!#&dCflICvXl zk~6GqgXh&m2k70--U@(9ve?C>!VDGylOID4Mm9P@^6DASxZU-9)ARHO=ld8Jswh$D ze<#39;b`VBQR(ynG4Y{(^*!XpZSAylMpPMxH<NEjGYXRHvMmLc}Vr!~?xNfE&U(O<0! zl^I{Na&HhuksF@Ph{Yx-@Ks3S@-LUg$~oN-eczFcPYaDWo1M|#gwaFqLY4)ibRd3< z>1>~N0*Y+knT~aUJL$rp&uB2Ivw1WvwzD>s^u7-tDB)Z?Fo}XT!O9O3nV9^SjVhpv>Gg+T}a)Gx@^l$ z|8fs}zNhPAV^%JT*vvB>F4;Z$-wMEPPPt8Hc=Q0R*rOF%r-IYK>(T2jZkH}Aa;N2X zV^C0~`d>ZohnG0LsJ3fb$ArJ#Y$`TJ@6`oQ&$Uk%B@%hV^NcdS<_Z(u3mZ(F znpdglw0}c3fYNUBJJ4!R>jnoy`^}>JYaWYq!E8v8_~#tP)kyt%y3WtL@`t$4hFE%E z!jMeq4Q_ow;^m2+125f9c=kNI;*0oZkYW6;{z)hJH{p@*+Ma58k4qXmRCn17sk90gbc#&TC$g3c}cj}d089}|Bq`ZXQp;GK&< z4q4N<pzV|dXE*u-zI$nRf(6RxMN zEO|nr!y)%IkZ?!?+Rnl$0%o*LA#MQd#ago@OT_@N4$IqZ&&+APcpF=?Y_vF&@Bq-@ zjy@`AzlVlw3BS{Nz@X9Q7)Gfa{uWa_ly|tlxTiE5=P#Epf#QJ>`Bwu{wD1;==zQPl zO3H6nCb-rE)*xCeAuM-N_Q81m3zg2rk>QkR#y@@_-kfg0zL;~+AnW8xbJc=5_(3Zr zq89g4y1RNSgxeAKbWdAobNL#HATY|GuC3WdCfqf@klZf-)GH;1=79cM zNP$wiF244`{a=$B>+6{ASOYLCD92IVJ0fjNdLQ7HfDWv}@NcEmYcdLWtQcIAKcTzJ z4aNi=xZ*~~T~>}BE}C!5itZ})@WaeZe7L7;6^+3bSiC2EPRO`-39 zmXp?oHIrCj{EF0)bV2>2rhS14=@ zczq_uEUV)eVnUYi)WJFts^JwmtG?; zC7W^hV`Z?N`{eBxn0jzff64}FQ{H)4P!FRTw3`XI%3y<`Kg}rY81FRPji&+JVL$*^ zezqd}rkQqw_e8%C*;X+KTiFhZjFS*;q$Jg}z_h4YT}Z~yc;ok?MY6jw%pPuF@~lQ= zW;!=gGlY0~on;<`>D@pmw|5YxL?CnD7cN`1VQyf>w}u&>#C?-=^cXFPU}A*jhFGf* z7+}?DZ}dsbeM0acD9$JLTkkdOMO6VN2s;sf_%K=>(=FJagj0W0y=BptroIQ5Az_dY6OKqmW1EehsUU0=y+J05?uwtziuWgI8HXfxO>ePI+;8wiRv z_&#TXi+5KEv*5(D_D6%_NR3rJwv>ma?&Y6qnS(Mw`gvn`bh`3EmTM_& zzoYC~F?Mjx5+QgRH>I}t7c(4%0yoId~XWPLR;nQ;99hqG$eA+gQ=Z8?z!=d+*n zuRelVTp1y)$pf#w#g7D8mTk;};hQ)#PccoTY+hSWS#1zxSv)sn(D9=3G zZE_z%BkM?`AEnqDa~aqRHQ+SMHI6#-3VhZDxZp}lIezxpG)Nibrr#xn`8tzVI3T|Cg0jgEuJ^^=W^XnZP$ ze%xGZ$oPe~%yKLX6Z62?aoDXV#r0A<8V)i~zq*MPFng4n8VmFC1@5RM$M&|(l0N;R z#6-71p2p039e_PIdnc&`rYqOUUg|K%O5(`g$sT6J;fqjtE8M)9H~1KzCfK>vx0axz zOr2~MY{6jnW5-|VA^T)DPr}K=fhwg-PKJ7*Pdrh|ftc?fT95|^T$M8ZUjb$ene*MU zauakK;Dce7827Uu8aLPl(m8=;Wv1swEl{+BwWmT=QB?S5e-L_Dhy&g9*f4*bxt2h) z3KgNF+XhoDX)w5VFMawQv9MVSBoN(YzI#!HRz!M_un_bD%L*>)?osNaAPgP46jQ%H zj?Y_)ALa@bYoJr#-f$$nnOl!yC1`{;WzounjsY9;1mgO=S7@qOdPs>pfw^mL!DHbV z=v8<{>BI2f^JA1lsMxTJxR!rxhRTFs99mgirIex4aLPLR-eO*~h| z``?gQ?6n@tY=eN$*PxM3CJp$-!0Hs6^9WB!r`Uqp$-=AW&*`r%4VHf@BJ(kei9;r( zXI5b65`9sxQvnBbh!#r;Q-fzklLnN7>$RvC?WhsVyosRgJaQwb@5M~WE#D2Qx(mN%VE8f4- zvs3t5#OIKSl-lS!GU&Yq!n5@)&mY{TIAa0Zl78Qdj*n_&Yc*>}2|i?xauaR(Hj`ya zM=+_J2KtYL=YoGsg=%%~_gws@1meCZ_-4I|7oNikmBu6t2z3@Zss?}&(XO2n^%D(lGQ`?21^ zf+i@^@#~n*_$^gT7xBK0r*vP;6*Qhdil8&`9Z=pnC4GN>Qk)3r6escGqHXv$ldT;r00jT#Sf8Y)lybyJ`@oPd|YaVc=029f$To$o~BZb9@i= zD6T>K_YrnzKSC_WqeHn-p(5`YmhWRc2~I1&8jby@t|2mp_Fsq$#le+JLBm}1?AS2R zTVY_)2_t_gb?KLDMVz9qVfW%$2zp!{wW#m4=tNl4P-o$$V~C86MRe#X%pNoj)Bj;J zxOoJP*RC^(3{PYTntI#D*Xoqruip*Veh{ zH|#u+;`Zb7h5Hd28I6cbzhd^dZGdA>G|Dck zp^}>V_reIaZ1BBn9Cn`yMJ(-ia_QJ+d^LSKLYZuyGZbJJ&A_~a&~L5(itbZbH1%7d z*gk(_TuzF@wR#@azq=`q&%k5cmsoZ1BBJ9`U}&f>(5zA+4S#*Vi_}bAP(xO$<%jP0 zoUXk-pNxa&LJ`CIg0OS=Zsb=&AM<5*D+s)k5VrEmZ*byT1oc7Gm(2f?(rwZAJyOA9 zZBvt;RhEzw?{*a4HT|(HR>?QZKvo%m24`{h@6Y zar~nR2BOiHZ7^ihmIYm*f6OV`35#uU1YO0&3elFCjZ!AGST=)cD~*_25?5wGZ5(7Zq|m4}j`Vd-Y+VZ?~@F)W>x+DCELZ zk0oZ*^ukr-QhMWM@;;Tx_1|yehqHejoX3=r&6k=8umK6?W@qBYmIf&%$p#M}M=RB} zcPDPo9S6^*r3O)Xcv$GbFC+Mn>44`Y6dI{tc`oK7TL`G;0JBAQY3bOV&x0l*Xw#$z zJCc_hD6-9mw`Two@A**YjT>1vjt;&(KSE#dbSW*W8p4(rw(<^(?a61TTI_$rhBtR0 zX(51uYHoV+v9~7zbbNqLe+`Xa$K7@WPM$#po7vG^qqrXXFZAMW!vVsHtTS^?FM5yd z0XMblOK`3?fOiiBQ5oi;w7xrlb5+H{qk4+wuIivv5_rdK9qt72e z$ygt6I83Y4Qn_=NCSPhY%i@1`6rqY*Xg~c}3s-#9jEy)xEONJO+=&bQEoiA}g>OWZ zn$um6!Nv-{R3&C*(;3N#T979u>^Ol!>Ik~f0KabthX%&*x)jd{_I`E-_$WZ}S+kKQ zTWYN1kvCNClb19(cipZ%yx*Ceu;mu`G0b~a8xwn z_$1Ka_tBzG;cD9kP?2ho!eUh|$xO(ANNG(fWwKjcWVf1q@K+1HaJs#4Q>D4k$$5mN zOl_7T^tb$ln$|iDwF}Bj_Cn82po&DX_eg;e#K)r>F7Zn9l9_Q7Xzx<>q#H0$_sch>jPvs=j?7OIv#&AiT>(W=YmLvB0&^W zgEYQ%PAgnZi*MUmOM@e2oOkP=4>vY3IvOHJos!5rC4Fn#2P&8ZZ&X>{V{RT~B zgK3D476f>(&*MZm?8o5FQIzuZ+u^?RIlQ}Dxeu&Mv3pz(o&8gJA&AVn~l;GaBK!v+7Dr;?`2H@qfU;~EEqqq z*kPwL+q35wU20{}{T-Yx?Mi1}yInHutjIhwzB0j9k!@Bz>`Zpn>a}KkUqgZ&4LmKk zF?{+mHtpJjZ5su)e_!p!?z*4RKi17FRzV{(JQMlL|E+%%?$N0!zC3SU&g5(=LZx~^ z_hdw;X^#%+T2|G9IAHm*v*C^Cf|N(1qOH3^UM!@4{2m+9zsb9^$j{fdl`*n0LTBxo z@nY=$5IWo5s$qll!W9KTp4nJb+<~A)FAc2Jv@`Xulq@Ux)w3NWpHZ4A;&xk^Qut)D zkt)9Ncguf{4=o3rqFK5aeXb)v-;h2=Z=6M0_4kNe>7ecjt9$6qoFp033pb7i>GQ3t zIQ`Wf?5c7@ToV?DK_px?fZ6g-VCAe%xg*3w@Td7DL#ExSb?;*HW0$*f5#E*q|tKk zQ4}fg&KyspU%wK#+Z~z9u2e5rr+$fy3(ME2lk&(rELz{cP+q8=CUrKl1MDYrHo`^b z^umADX)QJyie?dLmesyReo~GRHBC&w#(uV zu)W|+kr$|(Ubu>!%xksIpsOp0t}EAYsI(9hVQi6c zm9~N8nK~M3w^H^&&Bt2y^UlWV-7s|T7hQk6qhXd&_RD&0Vfzp~C%(YuuP@@eYnL$^ zwc}vhr+B5Tcz%O<_7P4^ac$wA8Uyp~y@7x!%kpx}b$l%Ao4CYU?%D z ./help_resources.qrc -./HelpFiles/Annotations/Annotations.html +./HelpFiles/Annotations/Annotations_1.3.fld/filelist.xml +./HelpFiles/Annotations/Annotations_1.3.fld/header.html ./HelpFiles/Annotations/Annotations_1.3.fld/image001.png ./HelpFiles/Annotations/Annotations_1.3.fld/image002.png ./HelpFiles/Annotations/Annotations_1.3.fld/image003.png @@ -30,6 +31,17 @@ ./HelpFiles/Annotations/Annotations_1.3.fld/image026.png ./HelpFiles/Annotations/Annotations_1.3.fld/image027.png ./HelpFiles/Annotations/Annotations_1.3.fld/image028.png +./HelpFiles/Annotations/Annotations_1.3.fld/image029.png +./HelpFiles/Annotations/Annotations_1.3.fld/image030.png +./HelpFiles/Annotations/Annotations_1.3.fld/image031.png +./HelpFiles/Annotations/Annotations_1.3.fld/image032.png +./HelpFiles/Annotations/Annotations_1.3.fld/image033.png +./HelpFiles/Annotations/Annotations_1.3.fld/image034.png +./HelpFiles/Annotations/Annotations_1.3.fld/image035.png +./HelpFiles/Annotations/Annotations_1.3.fld/item0001.xml +./HelpFiles/Annotations/Annotations_1.3.fld/props002.xml +./HelpFiles/Annotations/Annotations_1.3.fld/themedata.thmx +./HelpFiles/Annotations/Annotations_1.3.html ./HelpFiles/Best_Practices_Guides/Annotation_and_Scenes_Best_Practices.html ./HelpFiles/ChartingOverview/ChartingOverview.html ./HelpFiles/ChartingOverview/HistogramChart.png @@ -37,7 +49,6 @@ ./HelpFiles/ChartingOverview/LineSeriesChart.png ./HelpFiles/ChartingOverview/LineSeriesHistory.png ./HelpFiles/ChartingOverview/MatrixChart.png -./HelpFiles/Edit_Menu.png ./HelpFiles/Features_Toolbox/Annotations/Annotations.fld/filelist.xml ./HelpFiles/Features_Toolbox/Annotations/Annotations.fld/image001.png ./HelpFiles/Features_Toolbox/Annotations/Annotations.fld/themedata.thmx -- GitLab From 1c359a378a43f035a73247dc9221e2db52da1d98 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 7 May 2018 12:05:25 -0500 Subject: [PATCH 754/755] Minor fix for help: QFileInfo::basename() chops off at first '.' but some files contain a '.' prior to the filenames's extension. Replace with FileInformation::getFileNameNoExtension() --- src/GuiQt/HelpViewerDialog.cxx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/HelpViewerDialog.cxx b/src/GuiQt/HelpViewerDialog.cxx index 7ed36edbd..eb4df8bf7 100644 --- a/src/GuiQt/HelpViewerDialog.cxx +++ b/src/GuiQt/HelpViewerDialog.cxx @@ -53,6 +53,7 @@ #include "CaretLogger.h" #include "CommandOperation.h" #include "CommandOperationManager.h" +#include "FileInformation.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -414,10 +415,15 @@ HelpViewerDialog::loadWorkbenchHelpInfoFromDirectory(QTreeWidgetItem* parent, */ QListIterator otherHtmlPageIter(otherHtmlPagesList); while (otherHtmlPageIter.hasNext()) { - const QFileInfo pageInfo = otherHtmlPageIter.next(); +// const QFileInfo pageInfo = otherHtmlPageIter.next(); +// createHelpTreeWidgetItemForHelpPage(treeItem, +// pageInfo.baseName(), +// pageInfo.absoluteFilePath()); + const QFileInfo qtPageInfo = otherHtmlPageIter.next(); + const FileInformation pageInfo(qtPageInfo.absoluteFilePath()); createHelpTreeWidgetItemForHelpPage(treeItem, - pageInfo.baseName(), - pageInfo.absoluteFilePath()); + pageInfo.getFileNameNoExtension(), + qtPageInfo.absoluteFilePath()); } /* -- GitLab From 3a9c975177525cd409952466381533c4cf0683b7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 7 May 2018 15:08:22 -0500 Subject: [PATCH 755/755] Fixed some help pages that contained myelin file links by changing them to relative paths --- .../Features_Toolbox/Borders/Borders.html | 25 +-- .../HelpFiles/Menus/Edit_Menu/Edit_Menu.html | 9 +- .../File_Menu/Preferences/Preferences.html | 9 +- src/Resources/Help/HelpFiles/Menus/Menus.html | 14 +- .../Help/HelpFiles/Toolbar/Toolbar.html | 170 ++++++------------ 5 files changed, 85 insertions(+), 142 deletions(-) diff --git a/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html index 31e23f3c5..42da41c5f 100644 --- a/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html +++ b/src/Resources/Help/HelpFiles/Features_Toolbox/Borders/Borders.html @@ -1,7 +1,6 @@ - + - Borders @@ -13,9 +12,9 @@ The Borders Tab in the Features - Toolbox contains options for display and selection - of loaded and newly created borders on brain surfaces. Features Toolbox + contains options for display and selection of loaded and newly + created borders on brain surfaces. 

    • Display + Borders toggles border display on and off. When - Border Mode + Border Mode is turned on, Display Borders is turned on by default.
    @@ -49,6 +48,7 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Mode/Mode.h mso-list:l9 level1 lfo3;tab-stops:list .5in">Borders + Attributes contains options for viewing borders. the color when Coloring is set to Standard Color. @@ -175,9 +176,8 @@ href="file:///Volumes/myelin1/shared/WB_Tutorial/WB_1.3_Help/Toolbar/Mode/Mode.h Border Attributes Image